Initial copy from dali-toolkit repository 37/231537/1
authorHeeyong Song <heeyong.song@samsung.com>
Wed, 22 Apr 2020 08:16:20 +0000 (17:16 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Wed, 22 Apr 2020 08:16:38 +0000 (17:16 +0900)
Change-Id: I0c3ed238c86b24b9c24e30b172cd67306923db88

1396 files changed:
CMakeLists.txt [new file with mode: 0755]
LICENSE [new file with mode: 0644]
LICENSE.BSD-3-Clause [new file with mode: 0644]
README.md [new file with mode: 0644]
automated-tests/.gitignore-with-autogenerated-files [new file with mode: 0644]
automated-tests/.gitignore-without-autogenerated-files [new file with mode: 0644]
automated-tests/CMakeLists.txt.in [new file with mode: 0644]
automated-tests/README.md [new file with mode: 0644]
automated-tests/build.sh [new file with mode: 0755]
automated-tests/coverage.sh [new file with mode: 0755]
automated-tests/execute.sh [new file with mode: 0755]
automated-tests/packaging/core-dali-toolkit-tests.spec [new file with mode: 0644]
automated-tests/patch-coverage.pl [new file with mode: 0755]
automated-tests/resources/AnimatedCube.bin [new file with mode: 0644]
automated-tests/resources/AnimatedCube.gltf [new file with mode: 0644]
automated-tests/resources/AnimatedCube_BaseColor.png [new file with mode: 0644]
automated-tests/resources/AnimatedCube_MetallicRoughness.png [new file with mode: 0644]
automated-tests/resources/Cube-Points-Only.obj [new file with mode: 0644]
automated-tests/resources/Cube.obj [new file with mode: 0644]
automated-tests/resources/TB-gloss.png [new file with mode: 0644]
automated-tests/resources/ToyRobot-Metal-Simple.mtl [new file with mode: 0644]
automated-tests/resources/ToyRobot-Metal.mtl [new file with mode: 0644]
automated-tests/resources/anim.gif [new file with mode: 0644]
automated-tests/resources/application-icon-20.png [new file with mode: 0644]
automated-tests/resources/application-icon-21.png [new file with mode: 0644]
automated-tests/resources/application-icon-22.png [new file with mode: 0644]
automated-tests/resources/application-icon-23.png [new file with mode: 0644]
automated-tests/resources/application-icon-24.png [new file with mode: 0644]
automated-tests/resources/application-icon-25.png [new file with mode: 0644]
automated-tests/resources/application-icon-26.png [new file with mode: 0644]
automated-tests/resources/application-icon-27.png [new file with mode: 0644]
automated-tests/resources/application-icon-28.png [new file with mode: 0644]
automated-tests/resources/application-icon-29.png [new file with mode: 0644]
automated-tests/resources/application-icon-30.png [new file with mode: 0644]
automated-tests/resources/broken.png [new file with mode: 0644]
automated-tests/resources/button-up.9.png [new file with mode: 0644]
automated-tests/resources/demo-tile-texture-focused.9.png [new file with mode: 0644]
automated-tests/resources/empty.bmp [new file with mode: 0644]
automated-tests/resources/folder_appicon_empty_bg.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0030.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0031.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0032.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0033.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0034.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0035.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0036.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0037.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0038.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u0039.png [new file with mode: 0644]
automated-tests/resources/fonts/bitmap/u003a.png [new file with mode: 0644]
automated-tests/resources/fonts/dejavu/DejaVuSans.ttf [new file with mode: 0644]
automated-tests/resources/fonts/dejavu/DejaVuSerif-Bold.ttf [new file with mode: 0644]
automated-tests/resources/fonts/dejavu/DejaVuSerif-Italic.ttf [new file with mode: 0644]
automated-tests/resources/fonts/dejavu/DejaVuSerif.ttf [new file with mode: 0644]
automated-tests/resources/fonts/dejavu/LICENSE [new file with mode: 0644]
automated-tests/resources/fonts/noto/LICENSE_OFL.txt [new file with mode: 0644]
automated-tests/resources/fonts/noto/NotoSansMalayalam-Regular.ttf [new file with mode: 0644]
automated-tests/resources/fonts/roboto/LICENSE [new file with mode: 0644]
automated-tests/resources/fonts/roboto/Roboto-Bold.ttf [new file with mode: 0644]
automated-tests/resources/fonts/roboto/Roboto-BoldItalic.ttf [new file with mode: 0644]
automated-tests/resources/fonts/roboto/Roboto-Italic.ttf [new file with mode: 0644]
automated-tests/resources/fonts/roboto/Roboto-Regular.ttf [new file with mode: 0644]
automated-tests/resources/fonts/tizen/BreezeColorEmoji.ttf [new file with mode: 0644]
automated-tests/resources/fonts/tizen/TizenSansArabicRegular.ttf [new file with mode: 0644]
automated-tests/resources/fonts/tizen/TizenSansHebrewRegular.ttf [new file with mode: 0644]
automated-tests/resources/fonts/tizen/TizenSansHindiRegular.ttf [new file with mode: 0644]
automated-tests/resources/fonts/tizen/TizenSansRegular.ttf [new file with mode: 0644]
automated-tests/resources/forest_diffuse_cubemap.png [new file with mode: 0644]
automated-tests/resources/forest_specular_cubemap.png [new file with mode: 0644]
automated-tests/resources/gallery-small-1.jpg [new file with mode: 0644]
automated-tests/resources/heartsframe.9.png [new file with mode: 0644]
automated-tests/resources/icon-delete.png [new file with mode: 0644]
automated-tests/resources/icon-edit.png [new file with mode: 0644]
automated-tests/resources/insta_camera.json [new file with mode: 0644]
automated-tests/resources/keyboard-Landscape.jpg [new file with mode: 0644]
automated-tests/resources/mask.png [new file with mode: 0644]
automated-tests/resources/po/ar.po [new file with mode: 0755]
automated-tests/resources/po/en.po [new file with mode: 0755]
automated-tests/resources/progress-bar-skin-indeterminate.png [new file with mode: 0644]
automated-tests/resources/progress-bar-skin-progress.png [new file with mode: 0644]
automated-tests/resources/progress-bar-skin-secondary-progress.png [new file with mode: 0644]
automated-tests/resources/progress-bar-skin-track.png [new file with mode: 0644]
automated-tests/resources/svg1.svg [new file with mode: 0644]
automated-tests/resources/tb-norm.png [new file with mode: 0644]
automated-tests/resources/tbcol.png [new file with mode: 0644]
automated-tests/resources/test-image-600.jpg [new file with mode: 0644]
automated-tests/scripts/add_all_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_style.pl [new file with mode: 0755]
automated-tests/scripts/all_smack.rule [new file with mode: 0644]
automated-tests/scripts/autocompletion.sh [new file with mode: 0755]
automated-tests/scripts/init.sh [new file with mode: 0755]
automated-tests/scripts/output_summary.pl [new file with mode: 0755]
automated-tests/scripts/retriever.sh [new file with mode: 0755]
automated-tests/scripts/summarize.pl [new file with mode: 0755]
automated-tests/scripts/tcbuild.sh [new file with mode: 0755]
automated-tests/scripts/tcheadgen.sh [new file with mode: 0755]
automated-tests/scripts/tcpackageslistsgen.sh [new file with mode: 0755]
automated-tests/scripts/tctestsgen.sh [new file with mode: 0755]
automated-tests/src/common/assert.h [new file with mode: 0644]
automated-tests/src/common/testcase.h [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.h [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/tct-dali-toolkit-internal-core.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Control-internal.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-FeedbackStyle.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-ItemView-internal.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Cursor.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-ViewModel.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-internal/utc-Dali-Visuals-internal.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-styling/default-theme.json [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/theme2.json [new file with mode: 0644]
automated-tests/src/dali-toolkit-styling/theme3.json [new file with mode: 0644]
automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp [new file with mode: 0755]
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-third-party/yoga/YGAbsolutePositionTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGAlignContentTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGAlignItemsTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGAlignSelfTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGAndroidNewsFeed.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGAspectRatioTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGBaselineFuncTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGBorderTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGComputedMarginTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGComputedPaddingTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGDefaultValuesTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGDimensionTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGDirtiedTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGDirtyMarkingTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGDisplayTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGEdgeTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGFlexDirectionTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGFlexTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGFlexWrapTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGHadOverflowTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGInfiniteHeightTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGJustifyContentTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGLayoutDiffingTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGLoggerTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGMarginTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureCacheTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureModeTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGMinMaxDimensionTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGNodeChildTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGPaddingTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGPercentageTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGPersistenceTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGRelayoutTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingFunctionTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingMeasureFuncTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGSizeOverflowTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGStyleTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGTraversalTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGTreeMutationTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/yoga/YGZeroOutLayoutRecursivlyTest.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-context-helper-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-intrusive-ptr.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-touch-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.h [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-environment-variable.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.h [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-input-method-context.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.h [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-options.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-native-image-source.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder.cpp [new file with mode: 0644]
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 [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-abstraction.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.h [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h [new file with mode: 0644]
automated-tests/src/dali-toolkit/tct-dali-toolkit-core.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-AccessibilityManager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Alignment.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ArcVisual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-BloomView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-BubbleEmitter.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Button.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-CubeTransitionEffect.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-DragAndDropDetector.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-FlexContainer.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-GaussianBlurView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ItemLayout.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-ItemView.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-JsonParser.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-KeyInputFocusManager.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-NavigationView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-PageTurnView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-ProgressBar.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ScrollBar.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ScrollView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ScrollViewEffect.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ShaderEffects.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ShadowView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Slider.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-SuperBlurView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringLTR.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringRTL.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-ToolBar.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Toolkit.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp [new file with mode: 0755]
automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-WebView.cpp [new file with mode: 0644]
automated-tests/tcbuild [new symlink]
automated-tests/templates/tct-package/README [new file with mode: 0644]
automated-tests/templates/tct-package/inst.sh [new file with mode: 0755]
build/tizen/CMakeLists.txt [new file with mode: 0644]
build/tizen/dali-toolkit.pc.in [new file with mode: 0644]
build/tizen/docs-internal/build.sh [new file with mode: 0755]
build/tizen/docs-internal/dali-internal.doxy.in [new file with mode: 0644]
build/tizen/docs/check_for_errors.cmake [new file with mode: 0644]
build/tizen/docs/dali.doxy.in [new file with mode: 0644]
build/tizen/rename-cov-data [new file with mode: 0755]
dali-toolkit-resources.manifest [new file with mode: 0644]
dali-toolkit.manifest [new file with mode: 0644]
dali-toolkit.manifest-smack [new file with mode: 0644]
dali-toolkit/dali-toolkit.h [new file with mode: 0644]
dali-toolkit/devel-api/asset-manager/asset-manager.cpp [new file with mode: 0644]
dali-toolkit/devel-api/asset-manager/asset-manager.h [new file with mode: 0644]
dali-toolkit/devel-api/builder/base64-encoding.cpp [new file with mode: 0644]
dali-toolkit/devel-api/builder/base64-encoding.h [new file with mode: 0644]
dali-toolkit/devel-api/builder/builder.cpp [new file with mode: 0644]
dali-toolkit/devel-api/builder/builder.h [new file with mode: 0755]
dali-toolkit/devel-api/builder/json-parser.cpp [new file with mode: 0644]
dali-toolkit/devel-api/builder/json-parser.h [new file with mode: 0644]
dali-toolkit/devel-api/builder/tree-node.cpp [new file with mode: 0644]
dali-toolkit/devel-api/builder/tree-node.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/bloom-view/bloom-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/bloom-view/bloom-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/buttons/button-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/buttons/toggle-button.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/buttons/toggle-button.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/control-depth-index-ranges.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/control-devel.cpp [new file with mode: 0755]
dali-toolkit/devel-api/controls/control-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/control-wrapper-impl.cpp [new file with mode: 0755]
dali-toolkit/devel-api/controls/control-wrapper-impl.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/control-wrapper.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/control-wrapper.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/effects-view/effects-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/effects-view/effects-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/magnifier/magnifier.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/magnifier/magnifier.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/navigation-view/navigation-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/navigation-view/navigation-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-factory.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/popup/confirmation-popup.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/popup/popup.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/popup/popup.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/shadow-view/shadow-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/shadow-view/shadow-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp [new file with mode: 0755]
dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/text-controls/text-field-devel.cpp [new file with mode: 0755]
dali-toolkit/devel-api/controls/text-controls/text-field-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/text-controls/text-label-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/tool-bar/tool-bar.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/tool-bar/tool-bar.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h [new file with mode: 0644]
dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp [new file with mode: 0755]
dali-toolkit/devel-api/controls/video-view/video-view-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/controls/web-view/web-view.cpp [new file with mode: 0644]
dali-toolkit/devel-api/controls/web-view/web-view.h [new file with mode: 0644]
dali-toolkit/devel-api/direction-enums.h [new file with mode: 0644]
dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.cpp [new file with mode: 0755]
dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h [new file with mode: 0755]
dali-toolkit/devel-api/file.list [new file with mode: 0755]
dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.cpp [new file with mode: 0644]
dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/async-image-loader-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/atlas-upload-observer.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/atlas-upload-observer.h [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/image-atlas.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/image-atlas.h [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/texture-manager.cpp [new file with mode: 0644]
dali-toolkit/devel-api/image-loader/texture-manager.h [new file with mode: 0755]
dali-toolkit/devel-api/layouting/flex-node.cpp [new file with mode: 0644]
dali-toolkit/devel-api/layouting/flex-node.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/alpha-discard-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/dissolve-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/distance-field-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/image-region-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/motion-blur-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/shader-effects/motion-stretch-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/styling/style-manager-devel.cpp [new file with mode: 0644]
dali-toolkit/devel-api/styling/style-manager-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/text/bitmap-font.cpp [new file with mode: 0755]
dali-toolkit/devel-api/text/bitmap-font.h [new file with mode: 0755]
dali-toolkit/devel-api/text/text-enumerations-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/text/text-utils-devel.cpp [new file with mode: 0755]
dali-toolkit/devel-api/text/text-utils-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/toolkit-property-index-ranges.h [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.cpp [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-effect.cpp [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-effect.h [new file with mode: 0755]
dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.cpp [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.cpp [new file with mode: 0644]
dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h [new file with mode: 0644]
dali-toolkit/devel-api/visual-factory/transition-data.cpp [new file with mode: 0644]
dali-toolkit/devel-api/visual-factory/transition-data.h [new file with mode: 0755]
dali-toolkit/devel-api/visual-factory/visual-base.cpp [new file with mode: 0644]
dali-toolkit/devel-api/visual-factory/visual-base.h [new file with mode: 0755]
dali-toolkit/devel-api/visual-factory/visual-factory.cpp [new file with mode: 0644]
dali-toolkit/devel-api/visual-factory/visual-factory.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h [new file with mode: 0755]
dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/color-visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/image-visual-actions-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/image-visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/text-visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/devel-api/visuals/visual-properties-devel.h [new file with mode: 0644]
dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/builder/builder-animations.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/builder-declarations.h [new file with mode: 0644]
dali-toolkit/internal/builder/builder-filesystem.h [new file with mode: 0755]
dali-toolkit/internal/builder/builder-get-is.inl.h [new file with mode: 0644]
dali-toolkit/internal/builder/builder-impl-debug.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/builder-impl-debug.h [new file with mode: 0644]
dali-toolkit/internal/builder/builder-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/builder-impl.h [new file with mode: 0755]
dali-toolkit/internal/builder/builder-set-property.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/builder-set-property.h [new file with mode: 0644]
dali-toolkit/internal/builder/builder-signals.cpp [new file with mode: 0755]
dali-toolkit/internal/builder/dictionary.h [new file with mode: 0644]
dali-toolkit/internal/builder/json-parser-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/json-parser-impl.h [new file with mode: 0644]
dali-toolkit/internal/builder/json-parser-state.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/json-parser-state.h [new file with mode: 0644]
dali-toolkit/internal/builder/optional-value.h [new file with mode: 0644]
dali-toolkit/internal/builder/replacement.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/replacement.h [new file with mode: 0644]
dali-toolkit/internal/builder/style.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/style.h [new file with mode: 0644]
dali-toolkit/internal/builder/tree-node-manipulator.cpp [new file with mode: 0644]
dali-toolkit/internal/builder/tree-node-manipulator.h [new file with mode: 0644]
dali-toolkit/internal/controls/alignment/alignment-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/alignment/alignment-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/bloom-view/bloom-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/bubble-effect.h [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/bubble-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h [new file with mode: 0644]
dali-toolkit/internal/controls/bubble-effect/color-adjuster.h [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/button-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/button-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/check-box-button-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/push-button-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/push-button-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/radio-button-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/radio-button-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/buttons/toggle-button-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-data-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/control/control-data-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/control/control-debug.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-debug.h [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-renderers.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/control/control-renderers.h [new file with mode: 0644]
dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/effects-view/effects-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/flex-container/flex-container-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/image-view/image-view-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/image-view/image-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/magnifier/magnifier-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/obj-loader.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/model3d-view/obj-loader.h [new file with mode: 0644]
dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/popup/confirmation-popup-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/popup/popup-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/popup/popup-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/scene3d-view/gltf-loader.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scene3d-view/gltf-loader.h [new file with mode: 0644]
dali-toolkit/internal/controls/scene3d-view/gltf-shader.h [new file with mode: 0644]
dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/item-view/depth-layout.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/grid-layout.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scrollable-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/slider/slider-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/slider/slider-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/table-view/array-2d.h [new file with mode: 0644]
dali-toolkit/internal/controls/table-view/table-view-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/table-view/table-view-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-editor-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-field-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-label-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/tool-bar/tool-bar-impl.h [new file with mode: 0644]
dali-toolkit/internal/controls/tooltip/tooltip.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/tooltip/tooltip.h [new file with mode: 0644]
dali-toolkit/internal/controls/video-view/video-view-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/video-view/video-view-impl.h [new file with mode: 0755]
dali-toolkit/internal/controls/web-view/web-view-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/web-view/web-view-impl.h [new file with mode: 0644]
dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h [new file with mode: 0755]
dali-toolkit/internal/feedback/feedback-ids.h [new file with mode: 0644]
dali-toolkit/internal/feedback/feedback-style.cpp [new file with mode: 0644]
dali-toolkit/internal/feedback/feedback-style.h [new file with mode: 0644]
dali-toolkit/internal/file.list [new file with mode: 0644]
dali-toolkit/internal/filters/blur-two-pass-filter.cpp [new file with mode: 0644]
dali-toolkit/internal/filters/blur-two-pass-filter.h [new file with mode: 0644]
dali-toolkit/internal/filters/emboss-filter.cpp [new file with mode: 0644]
dali-toolkit/internal/filters/emboss-filter.h [new file with mode: 0644]
dali-toolkit/internal/filters/image-filter.cpp [new file with mode: 0644]
dali-toolkit/internal/filters/image-filter.h [new file with mode: 0644]
dali-toolkit/internal/filters/spread-filter.cpp [new file with mode: 0644]
dali-toolkit/internal/filters/spread-filter.h [new file with mode: 0644]
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/helpers/color-conversion.cpp [new file with mode: 0644]
dali-toolkit/internal/helpers/color-conversion.h [new file with mode: 0644]
dali-toolkit/internal/helpers/property-helper.cpp [new file with mode: 0644]
dali-toolkit/internal/helpers/property-helper.h [new file with mode: 0644]
dali-toolkit/internal/helpers/round-robin-container-view.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/async-image-loader-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/async-image-loader-impl.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/atlas-packer.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/atlas-packer.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/image-atlas-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/image-atlas-impl.h [new file with mode: 0644]
dali-toolkit/internal/image-loader/image-load-thread.cpp [new file with mode: 0644]
dali-toolkit/internal/image-loader/image-load-thread.h [new file with mode: 0644]
dali-toolkit/internal/styling/style-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/styling/style-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/bidirectional-line-info-run.h [new file with mode: 0644]
dali-toolkit/internal/text/bidirectional-paragraph-info-run.h [new file with mode: 0644]
dali-toolkit/internal/text/bidirectional-support.cpp [new file with mode: 0755]
dali-toolkit/internal/text/bidirectional-support.h [new file with mode: 0755]
dali-toolkit/internal/text/character-run.h [new file with mode: 0644]
dali-toolkit/internal/text/character-set-conversion.cpp [new file with mode: 0644]
dali-toolkit/internal/text/character-set-conversion.h [new file with mode: 0644]
dali-toolkit/internal/text/color-run.h [new file with mode: 0644]
dali-toolkit/internal/text/color-segmentation.cpp [new file with mode: 0644]
dali-toolkit/internal/text/color-segmentation.h [new file with mode: 0644]
dali-toolkit/internal/text/cursor-helper-functions.cpp [new file with mode: 0644]
dali-toolkit/internal/text/cursor-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/decorator/text-decorator.cpp [new file with mode: 0644]
dali-toolkit/internal/text/decorator/text-decorator.h [new file with mode: 0644]
dali-toolkit/internal/text/embedded-item.h [new file with mode: 0755]
dali-toolkit/internal/text/font-description-run.h [new file with mode: 0644]
dali-toolkit/internal/text/font-run.h [new file with mode: 0644]
dali-toolkit/internal/text/glyph-metrics-helper.cpp [new file with mode: 0755]
dali-toolkit/internal/text/glyph-metrics-helper.h [new file with mode: 0644]
dali-toolkit/internal/text/glyph-run.h [new file with mode: 0644]
dali-toolkit/internal/text/hidden-text.cpp [new file with mode: 0644]
dali-toolkit/internal/text/hidden-text.h [new file with mode: 0644]
dali-toolkit/internal/text/input-style.h [new file with mode: 0644]
dali-toolkit/internal/text/layouts/layout-engine.cpp [new file with mode: 0755]
dali-toolkit/internal/text/layouts/layout-engine.h [new file with mode: 0755]
dali-toolkit/internal/text/layouts/layout-parameters.h [new file with mode: 0755]
dali-toolkit/internal/text/line-run.h [new file with mode: 0644]
dali-toolkit/internal/text/logical-model-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/text/logical-model-impl.h [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor-color.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-color.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-embedded-item.cpp [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor-embedded-item.h [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor-font.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-font.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-helper-functions.cpp [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor-helper-functions.h [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor.cpp [new file with mode: 0755]
dali-toolkit/internal/text/markup-processor.h [new file with mode: 0755]
dali-toolkit/internal/text/metrics.h [new file with mode: 0755]
dali-toolkit/internal/text/multi-language-helper-functions.cpp [new file with mode: 0644]
dali-toolkit/internal/text/multi-language-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/multi-language-support-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/text/multi-language-support-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/multi-language-support.cpp [new file with mode: 0644]
dali-toolkit/internal/text/multi-language-support.h [new file with mode: 0644]
dali-toolkit/internal/text/paragraph-run.h [new file with mode: 0644]
dali-toolkit/internal/text/property-string-parser.cpp [new file with mode: 0644]
dali-toolkit/internal/text/property-string-parser.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-manager.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp [new file with mode: 0755]
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-backend-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-backend-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-backend.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-backend.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-renderer.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-typesetter.cpp [new file with mode: 0755]
dali-toolkit/internal/text/rendering/text-typesetter.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/file.list [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/view-model.cpp [new file with mode: 0755]
dali-toolkit/internal/text/rendering/view-model.h [new file with mode: 0755]
dali-toolkit/internal/text/script-run.h [new file with mode: 0755]
dali-toolkit/internal/text/segmentation.cpp [new file with mode: 0644]
dali-toolkit/internal/text/segmentation.h [new file with mode: 0644]
dali-toolkit/internal/text/shaper.cpp [new file with mode: 0644]
dali-toolkit/internal/text/shaper.h [new file with mode: 0644]
dali-toolkit/internal/text/text-control-interface.h [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/text/text-controller-impl.h [new file with mode: 0755]
dali-toolkit/internal/text/text-controller.cpp [new file with mode: 0755]
dali-toolkit/internal/text/text-controller.h [new file with mode: 0755]
dali-toolkit/internal/text/text-definitions.h [new file with mode: 0755]
dali-toolkit/internal/text/text-editable-control-interface.h [new file with mode: 0644]
dali-toolkit/internal/text/text-effects-style.cpp [new file with mode: 0755]
dali-toolkit/internal/text/text-effects-style.h [new file with mode: 0755]
dali-toolkit/internal/text/text-enumerations-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-enumerations-impl.h [new file with mode: 0644]
dali-toolkit/internal/text/text-font-style.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-font-style.h [new file with mode: 0644]
dali-toolkit/internal/text/text-io.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-io.h [new file with mode: 0644]
dali-toolkit/internal/text/text-model-interface.h [new file with mode: 0755]
dali-toolkit/internal/text/text-model.cpp [new file with mode: 0755]
dali-toolkit/internal/text/text-model.h [new file with mode: 0755]
dali-toolkit/internal/text/text-run-container.h [new file with mode: 0644]
dali-toolkit/internal/text/text-scroller-interface.h [new file with mode: 0644]
dali-toolkit/internal/text/text-scroller.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-scroller.h [new file with mode: 0644]
dali-toolkit/internal/text/text-vertical-scroller.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-vertical-scroller.h [new file with mode: 0644]
dali-toolkit/internal/text/text-view-interface.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-view-interface.h [new file with mode: 0755]
dali-toolkit/internal/text/text-view.cpp [new file with mode: 0755]
dali-toolkit/internal/text/text-view.h [new file with mode: 0755]
dali-toolkit/internal/text/visual-model-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/text/visual-model-impl.h [new file with mode: 0755]
dali-toolkit/internal/text/xhtml-entities.cpp [new file with mode: 0755]
dali-toolkit/internal/text/xhtml-entities.h [new file with mode: 0755]
dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.cpp [new file with mode: 0755]
dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h [new file with mode: 0755]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp [new file with mode: 0755]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h [new file with mode: 0755]
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h [new file with mode: 0755]
dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h [new file with mode: 0644]
dali-toolkit/internal/visuals/arc/arc-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/arc/arc-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/border/border-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/border/border-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/color/color-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/color/color-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/gradient-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/gradient-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/gradient.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/gradient.h [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/linear-gradient.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/linear-gradient.h [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/radial-gradient.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/gradient/radial-gradient.h [new file with mode: 0644]
dali-toolkit/internal/visuals/image-atlas-manager.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/image-atlas-manager.h [new file with mode: 0644]
dali-toolkit/internal/visuals/image-visual-shader-factory.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/image-visual-shader-factory.h [new file with mode: 0644]
dali-toolkit/internal/visuals/image/image-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/image/image-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/mesh/mesh-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/mesh/mesh-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/npatch-loader.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/npatch-loader.h [new file with mode: 0644]
dali-toolkit/internal/visuals/npatch/npatch-visual.cpp [new file with mode: 0755]
dali-toolkit/internal/visuals/npatch/npatch-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/primitive/primitive-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/primitive/primitive-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h [new file with mode: 0644]
dali-toolkit/internal/visuals/svg/svg-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/svg/svg-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/text/text-visual.cpp [new file with mode: 0755]
dali-toolkit/internal/visuals/text/text-visual.h [new file with mode: 0644]
dali-toolkit/internal/visuals/texture-manager-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/texture-manager-impl.h [new file with mode: 0755]
dali-toolkit/internal/visuals/texture-upload-observer.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/texture-upload-observer.h [new file with mode: 0644]
dali-toolkit/internal/visuals/transition-data-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/transition-data-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-base-data-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-base-data-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-base-impl.cpp [new file with mode: 0755]
dali-toolkit/internal/visuals/visual-base-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-event-observer.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-factory-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-factory-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-factory-impl.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-factory-impl.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-string-constants.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-string-constants.h [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-url.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/visual-url.h [new file with mode: 0644]
dali-toolkit/internal/visuals/wireframe/wireframe-visual.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/wireframe/wireframe-visual.h [new file with mode: 0644]
dali-toolkit/po/ar.po [new file with mode: 0755]
dali-toolkit/po/as.po [new file with mode: 0644]
dali-toolkit/po/az.po [new file with mode: 0755]
dali-toolkit/po/be_BY.po [new file with mode: 0644]
dali-toolkit/po/bg.po [new file with mode: 0755]
dali-toolkit/po/bn.po [new file with mode: 0644]
dali-toolkit/po/bn_BD.po [new file with mode: 0644]
dali-toolkit/po/ca.po [new file with mode: 0755]
dali-toolkit/po/cs.po [new file with mode: 0755]
dali-toolkit/po/da.po [new file with mode: 0755]
dali-toolkit/po/de.po [new file with mode: 0755]
dali-toolkit/po/el_GR.po [new file with mode: 0755]
dali-toolkit/po/en.po [new file with mode: 0755]
dali-toolkit/po/en_PH.po [new file with mode: 0755]
dali-toolkit/po/en_US.po [new file with mode: 0755]
dali-toolkit/po/es_ES.po [new file with mode: 0755]
dali-toolkit/po/es_US.po [new file with mode: 0755]
dali-toolkit/po/et.po [new file with mode: 0755]
dali-toolkit/po/eu.po [new file with mode: 0755]
dali-toolkit/po/fa.po [new file with mode: 0644]
dali-toolkit/po/fi.po [new file with mode: 0755]
dali-toolkit/po/fr.po [new file with mode: 0755]
dali-toolkit/po/fr_CA.po [new file with mode: 0755]
dali-toolkit/po/ga.po [new file with mode: 0755]
dali-toolkit/po/gl.po [new file with mode: 0755]
dali-toolkit/po/gu.po [new file with mode: 0644]
dali-toolkit/po/hi.po [new file with mode: 0755]
dali-toolkit/po/hr.po [new file with mode: 0755]
dali-toolkit/po/hu.po [new file with mode: 0755]
dali-toolkit/po/hy.po [new file with mode: 0755]
dali-toolkit/po/id.po [new file with mode: 0644]
dali-toolkit/po/is.po [new file with mode: 0755]
dali-toolkit/po/it_IT.po [new file with mode: 0755]
dali-toolkit/po/ja_JP.po [new file with mode: 0755]
dali-toolkit/po/ka.po [new file with mode: 0755]
dali-toolkit/po/kk.po [new file with mode: 0755]
dali-toolkit/po/km.po [new file with mode: 0644]
dali-toolkit/po/kn.po [new file with mode: 0644]
dali-toolkit/po/ko_KR.po [new file with mode: 0755]
dali-toolkit/po/ky_KG.po [new file with mode: 0644]
dali-toolkit/po/lo.po [new file with mode: 0644]
dali-toolkit/po/lt.po [new file with mode: 0755]
dali-toolkit/po/lv.po [new file with mode: 0755]
dali-toolkit/po/mk.po [new file with mode: 0755]
dali-toolkit/po/ml.po [new file with mode: 0644]
dali-toolkit/po/mn_MN.po [new file with mode: 0644]
dali-toolkit/po/mr.po [new file with mode: 0644]
dali-toolkit/po/ms.po [new file with mode: 0644]
dali-toolkit/po/my_ZG.po [new file with mode: 0644]
dali-toolkit/po/nb.po [new file with mode: 0755]
dali-toolkit/po/ne.po [new file with mode: 0644]
dali-toolkit/po/nl.po [new file with mode: 0755]
dali-toolkit/po/or.po [new file with mode: 0644]
dali-toolkit/po/pa.po [new file with mode: 0644]
dali-toolkit/po/pl.po [new file with mode: 0755]
dali-toolkit/po/pt_BR.po [new file with mode: 0755]
dali-toolkit/po/pt_PT.po [new file with mode: 0755]
dali-toolkit/po/ro.po [new file with mode: 0755]
dali-toolkit/po/ru_RU.po [new file with mode: 0755]
dali-toolkit/po/si.po [new file with mode: 0644]
dali-toolkit/po/sk.po [new file with mode: 0755]
dali-toolkit/po/sl.po [new file with mode: 0755]
dali-toolkit/po/sr.po [new file with mode: 0755]
dali-toolkit/po/sv.po [new file with mode: 0755]
dali-toolkit/po/ta.po [new file with mode: 0644]
dali-toolkit/po/te.po [new file with mode: 0644]
dali-toolkit/po/tg_TJ.po [new file with mode: 0644]
dali-toolkit/po/th.po [new file with mode: 0644]
dali-toolkit/po/tk_TM.po [new file with mode: 0644]
dali-toolkit/po/tl.po [new file with mode: 0644]
dali-toolkit/po/tr_TR.po [new file with mode: 0755]
dali-toolkit/po/uk.po [new file with mode: 0755]
dali-toolkit/po/ur.po [new file with mode: 0644]
dali-toolkit/po/uz.po [new file with mode: 0755]
dali-toolkit/po/vi.po [new file with mode: 0644]
dali-toolkit/po/zh_CN.po [new file with mode: 0755]
dali-toolkit/po/zh_HK.po [new file with mode: 0755]
dali-toolkit/po/zh_TW.po [new file with mode: 0755]
dali-toolkit/public-api/accessibility-manager/accessibility-manager.cpp [new file with mode: 0644]
dali-toolkit/public-api/accessibility-manager/accessibility-manager.h [new file with mode: 0755]
dali-toolkit/public-api/align-enumerations.h [new file with mode: 0644]
dali-toolkit/public-api/controls/alignment/alignment.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/alignment/alignment.h [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/button.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/button.h [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/check-box-button.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/check-box-button.h [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/push-button.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/push-button.h [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/radio-button.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/buttons/radio-button.h [new file with mode: 0644]
dali-toolkit/public-api/controls/control-impl.cpp [new file with mode: 0755]
dali-toolkit/public-api/controls/control-impl.h [new file with mode: 0644]
dali-toolkit/public-api/controls/control.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/control.h [new file with mode: 0644]
dali-toolkit/public-api/controls/flex-container/flex-container.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/flex-container/flex-container.h [new file with mode: 0644]
dali-toolkit/public-api/controls/image-view/image-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/image-view/image-view.h [new file with mode: 0644]
dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/model3d-view/model3d-view.h [new file with mode: 0755]
dali-toolkit/public-api/controls/progress-bar/progress-bar.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/progress-bar/progress-bar.h [new file with mode: 0644]
dali-toolkit/public-api/controls/scroll-bar/scroll-bar.cpp [new file with mode: 0755]
dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/item-view/item-layout.cpp [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/item-view/item-view-declarations.h [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/item-view/item-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/item-view/item-view.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h [new file with mode: 0755]
dali-toolkit/public-api/controls/scrollable/scrollable.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/scrollable/scrollable.h [new file with mode: 0644]
dali-toolkit/public-api/controls/slider/slider.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/slider/slider.h [new file with mode: 0644]
dali-toolkit/public-api/controls/table-view/table-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/table-view/table-view.h [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/placeholder-properties.h [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-editor.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-editor.h [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-field.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-field.h [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-label.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/text-controls/text-label.h [new file with mode: 0644]
dali-toolkit/public-api/controls/video-view/video-view.cpp [new file with mode: 0644]
dali-toolkit/public-api/controls/video-view/video-view.h [new file with mode: 0755]
dali-toolkit/public-api/dali-toolkit-common.h [new file with mode: 0755]
dali-toolkit/public-api/dali-toolkit-version.cpp [new file with mode: 0644]
dali-toolkit/public-api/dali-toolkit-version.h [new file with mode: 0755]
dali-toolkit/public-api/enums.cpp [new file with mode: 0644]
dali-toolkit/public-api/enums.h [new file with mode: 0644]
dali-toolkit/public-api/file.list [new file with mode: 0644]
dali-toolkit/public-api/focus-manager/keyboard-focus-manager.cpp [new file with mode: 0644]
dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h [new file with mode: 0644]
dali-toolkit/public-api/image-loader/async-image-loader.cpp [new file with mode: 0644]
dali-toolkit/public-api/image-loader/async-image-loader.h [new file with mode: 0755]
dali-toolkit/public-api/image-loader/sync-image-loader.cpp [new file with mode: 0644]
dali-toolkit/public-api/image-loader/sync-image-loader.h [new file with mode: 0755]
dali-toolkit/public-api/styling/style-manager.cpp [new file with mode: 0644]
dali-toolkit/public-api/styling/style-manager.h [new file with mode: 0644]
dali-toolkit/public-api/text/rendering-backend.h [new file with mode: 0755]
dali-toolkit/public-api/text/text-enumerations.h [new file with mode: 0644]
dali-toolkit/public-api/toolkit-property-index-ranges.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/border-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/color-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/gradient-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/image-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/mesh-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/primitive-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/text-visual-properties.h [new file with mode: 0644]
dali-toolkit/public-api/visuals/visual-properties.h [new file with mode: 0644]
dali-toolkit/sounds/End_of_List.ogg [new file with mode: 0644]
dali-toolkit/sounds/Focus.ogg [new file with mode: 0644]
dali-toolkit/sounds/List_scroll.ogg [new file with mode: 0644]
dali-toolkit/sounds/file.list [new file with mode: 0644]
dali-toolkit/styles/1920x1080/dali-toolkit-default-theme.json [new file with mode: 0755]
dali-toolkit/styles/1920x1080/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/1920x1080/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/1920x1080/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/2048x1080/dali-toolkit-default-theme.json [new file with mode: 0755]
dali-toolkit/styles/2048x1080/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/2048x1080/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/2048x1080/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/360x360/dali-toolkit-default-theme.json [new file with mode: 0644]
dali-toolkit/styles/360x360/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/360x360/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/360x360/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/360x360/images/tw_bottom_btn_bg.png [new file with mode: 0755]
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json [new file with mode: 0644]
dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/480x800/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/480x800/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json [new file with mode: 0644]
dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png [new file with mode: 0644]
dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png [new file with mode: 0644]
dali-toolkit/styles/default-feedback-theme.json [new file with mode: 0644]
dali-toolkit/styles/file.list [new file with mode: 0644]
dali-toolkit/styles/images-common/00_popup_bg.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/00_popup_bg.png [new file with mode: 0644]
dali-toolkit/styles/images-common/00_popup_bottom_bg.png [new file with mode: 0755]
dali-toolkit/styles/images-common/00_popup_bubble_bg.png [new file with mode: 0755]
dali-toolkit/styles/images-common/00_popup_bubble_tail_bottom.png [new file with mode: 0755]
dali-toolkit/styles/images-common/00_popup_button_bg.png [new file with mode: 0644]
dali-toolkit/styles/images-common/00_popup_button_pressed.png [new file with mode: 0755]
dali-toolkit/styles/images-common/B16-8_TTS_focus.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/brdfLUT.png [new file with mode: 0644]
dali-toolkit/styles/images-common/broken.png [new file with mode: 0644]
dali-toolkit/styles/images-common/button-disabled.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/button-down-disabled.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/button-down.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/button-up.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/checkbox-selected-disabled.png [new file with mode: 0644]
dali-toolkit/styles/images-common/checkbox-selected.png [new file with mode: 0644]
dali-toolkit/styles/images-common/checkbox-unselected-disabled.png [new file with mode: 0644]
dali-toolkit/styles/images-common/checkbox-unselected.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_clipboard.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_copy.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_cut.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_paste.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_select.png [new file with mode: 0644]
dali-toolkit/styles/images-common/copy_paste_icon_select_all.png [new file with mode: 0644]
dali-toolkit/styles/images-common/cursor_handler_ball_center.png [new file with mode: 0755]
dali-toolkit/styles/images-common/file.list [new file with mode: 0644]
dali-toolkit/styles/images-common/insertpoint-icon-pressed.png [new file with mode: 0644]
dali-toolkit/styles/images-common/insertpoint-icon.png [new file with mode: 0644]
dali-toolkit/styles/images-common/keyboard_focus.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/magnifier.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bg.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_bg.#.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_bg_ef.#.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_bg_line.#.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom_ef.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_tail_bottom_line.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_bubble_tail_top.png [new file with mode: 0755]
dali-toolkit/styles/images-common/popup_bubble_tail_top_ef.png [new file with mode: 0755]
dali-toolkit/styles/images-common/popup_bubble_tail_top_line.png [new file with mode: 0755]
dali-toolkit/styles/images-common/popup_scroll.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_tail_down.png [new file with mode: 0755]
dali-toolkit/styles/images-common/popup_tail_left.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_tail_right.png [new file with mode: 0644]
dali-toolkit/styles/images-common/popup_tail_up.png [new file with mode: 0644]
dali-toolkit/styles/images-common/progress-bar-skin-indeterminate.png [new file with mode: 0644]
dali-toolkit/styles/images-common/progress-bar-skin-progress.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/progress-bar-skin-secondary-progress.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/progress-bar-skin-track.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/radio-button-selected-disabled.png [new file with mode: 0644]
dali-toolkit/styles/images-common/radio-button-selected.png [new file with mode: 0644]
dali-toolkit/styles/images-common/radio-button-unselected-disabled.png [new file with mode: 0644]
dali-toolkit/styles/images-common/radio-button-unselected.png [new file with mode: 0644]
dali-toolkit/styles/images-common/selection-popup-background.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/selection-popup-bg.9.png [new file with mode: 0755]
dali-toolkit/styles/images-common/selection-popup-border.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/selection_handle_ball_left.png [new file with mode: 0755]
dali-toolkit/styles/images-common/selection_handle_ball_right.png [new file with mode: 0755]
dali-toolkit/styles/images-common/selection_marker_left.png [new file with mode: 0644]
dali-toolkit/styles/images-common/selection_marker_right.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-popup-arrow.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-popup.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-popup.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-skin-handle.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-skin-progress.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-skin-progress.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-skin.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/slider-skin.png [new file with mode: 0644]
dali-toolkit/styles/images-common/text-input-selection-handle-left-press.png [new file with mode: 0644]
dali-toolkit/styles/images-common/text-input-selection-handle-left.png [new file with mode: 0644]
dali-toolkit/styles/images-common/text-input-selection-handle-right-press.png [new file with mode: 0644]
dali-toolkit/styles/images-common/text-input-selection-handle-right.png [new file with mode: 0644]
dali-toolkit/styles/images-common/text_selection_scroll_indicator.9.png [new file with mode: 0644]
dali-toolkit/styles/images-common/tooltip-tail-above.png [new file with mode: 0644]
dali-toolkit/styles/images-common/tooltip-tail-below.png [new file with mode: 0644]
dali-toolkit/styles/images-common/tooltip.9.png [new file with mode: 0644]
dali-toolkit/third-party/base-n/basen.hpp [new file with mode: 0644]
dali-toolkit/third-party/file.list [new file with mode: 0644]
dali-toolkit/third-party/nanosvg/nanosvg.cc [new file with mode: 0755]
dali-toolkit/third-party/nanosvg/nanosvg.h [new file with mode: 0644]
dali-toolkit/third-party/nanosvg/nanosvgrast.cc [new file with mode: 0644]
dali-toolkit/third-party/nanosvg/nanosvgrast.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/Utils.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/Utils.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGConfig.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGConfig.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGEnums.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGEnums.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGFloatOptional.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGFloatOptional.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGLayout.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGLayout.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGMacros.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGNode.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGNode.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGNodePrint.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGNodePrint.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGStyle.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/YGStyle.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/Yoga-internal.h [new file with mode: 0644]
dali-toolkit/third-party/yoga/Yoga.cpp [new file with mode: 0644]
dali-toolkit/third-party/yoga/Yoga.h [new file with mode: 0644]
doc/dali-toolkit-doc.h [new file with mode: 0755]
doc/file.list [new file with mode: 0644]
doc/images/dali-modules.png [new file with mode: 0755]
docs/DaliLayout.xml [new file with mode: 0644]
docs/README [new file with mode: 0644]
docs/api_footer.html [new file with mode: 0644]
docs/content/example-code/CMakeLists.txt [new file with mode: 0644]
docs/content/example-code/images/cards.jpg [new file with mode: 0644]
docs/content/example-code/properties.cpp [new file with mode: 0644]
docs/content/figures/image-scaling/cards.jpg [new file with mode: 0644]
docs/content/figures/image-scaling/concept-rectangles.svg [new file with mode: 0644]
docs/content/figures/image-scaling/dog.jpg [new file with mode: 0644]
docs/content/figures/image-scaling/door.jpg [new file with mode: 0644]
docs/content/figures/image-scaling/example-fitting-mode-options.svg [new file with mode: 0644]
docs/content/figures/image-scaling/example-scale-to-fill-problem.svg [new file with mode: 0644]
docs/content/figures/image-scaling/example-scale-to-fill-sequence.svg [new file with mode: 0644]
docs/content/figures/image-scaling/gallery-large-12.jpg [new file with mode: 0644]
docs/content/figures/image-scaling/liberty.jpg [new file with mode: 0644]
docs/content/figures/image-scaling/phone-transparent-screen.png [new file with mode: 0644]
docs/content/figures/image-scaling/phone.png [new file with mode: 0644]
docs/content/images/accessibility/accessibility-focus-group.png [new file with mode: 0644]
docs/content/images/accessibility/accessibility-focus-order.png [new file with mode: 0644]
docs/content/images/accessibility/accessibility-focus.png [new file with mode: 0644]
docs/content/images/actor-position.png [new file with mode: 0644]
docs/content/images/actors/Image-Actor.png [new file with mode: 0644]
docs/content/images/actors/Text-Label.png [new file with mode: 0644]
docs/content/images/actors/scale-none.png [new file with mode: 0644]
docs/content/images/actors/scale-to-fill-keep-aspect.png [new file with mode: 0644]
docs/content/images/actors/scale-to-fill.png [new file with mode: 0644]
docs/content/images/actors/scale-to-fit-keep-aspect.png [new file with mode: 0644]
docs/content/images/actors/shrink-to-fit-2.png [new file with mode: 0644]
docs/content/images/actors/shrink-to-fit-keep-aspect.png [new file with mode: 0644]
docs/content/images/actors/shrink-to-fit.png [new file with mode: 0644]
docs/content/images/anchor-point.png [new file with mode: 0644]
docs/content/images/animation/anim1.png [new file with mode: 0644]
docs/content/images/animation/anim2.png [new file with mode: 0644]
docs/content/images/animation/anim3.png [new file with mode: 0644]
docs/content/images/animation/animated-path.png [new file with mode: 0644]
docs/content/images/animation/keyframe-animation.png [new file with mode: 0644]
docs/content/images/animation/multi-threaded-animation-2.png [new file with mode: 0644]
docs/content/images/animation/multi-threaded-animation.png [new file with mode: 0644]
docs/content/images/animation/set-position-vs-animation.png [new file with mode: 0644]
docs/content/images/architecture.png [new file with mode: 0644]
docs/content/images/background/BackgroundBorder.png [new file with mode: 0644]
docs/content/images/background/BackgroundControlColor.png [new file with mode: 0644]
docs/content/images/background/BackgroundImage.png [new file with mode: 0644]
docs/content/images/background/BackgroundImageColor.png [new file with mode: 0644]
docs/content/images/background/BackgroundTextLabel.png [new file with mode: 0644]
docs/content/images/coordinate-system-and-stage.png [new file with mode: 0644]
docs/content/images/creating-custom-controls/control-handle-body.png [new file with mode: 0644]
docs/content/images/creating-custom-controls/popup-normal.png [new file with mode: 0644]
docs/content/images/creating-custom-controls/popup-styled.png [new file with mode: 0644]
docs/content/images/creating-custom-controls/rendering.png [new file with mode: 0644]
docs/content/images/dali-modules.png [new file with mode: 0644]
docs/content/images/dali-threads.png [new file with mode: 0644]
docs/content/images/debug-rendering/debug-blocks.png [new file with mode: 0644]
docs/content/images/dynamics/dynamics-joint.png [new file with mode: 0644]
docs/content/images/dynamics/dynamics-joint2.png [new file with mode: 0644]
docs/content/images/dynamics/dynamics-rigid.png [new file with mode: 0644]
docs/content/images/dynamics/dynamics-shapes.png [new file with mode: 0644]
docs/content/images/dynamics/dynamics-soft.png [new file with mode: 0644]
docs/content/images/emscripten/emscripten-dali-toy.png [new file with mode: 0644]
docs/content/images/emscripten/emscripten-live-doc.png [new file with mode: 0644]
docs/content/images/emscripten/emscripten-tests.png [new file with mode: 0644]
docs/content/images/flex-container/align-content.jpg [new file with mode: 0755]
docs/content/images/flex-container/align-items.jpg [new file with mode: 0755]
docs/content/images/flex-container/align-self.jpg [new file with mode: 0755]
docs/content/images/flex-container/content-direction-ltr.jpg [new file with mode: 0755]
docs/content/images/flex-container/content-direction-rtl.jpg [new file with mode: 0755]
docs/content/images/flex-container/flex-container.jpg [new file with mode: 0755]
docs/content/images/flex-container/flex-direction.jpg [new file with mode: 0755]
docs/content/images/flex-container/flex-margin.jpg [new file with mode: 0755]
docs/content/images/flex-container/flex-wrap.jpg [new file with mode: 0755]
docs/content/images/flex-container/flex.jpg [new file with mode: 0755]
docs/content/images/flex-container/flexbox-demo.jpg [new file with mode: 0644]
docs/content/images/flex-container/justify-content.jpg [new file with mode: 0755]
docs/content/images/focus-manager/focus-manager.png [new file with mode: 0644]
docs/content/images/image-scaling/demo-fitting-sampling.png [new file with mode: 0644]
docs/content/images/image-scaling/demo-sampling-modes.jpg [new file with mode: 0644]
docs/content/images/image-scaling/example-scale-to-fill-problem.jpg [new file with mode: 0644]
docs/content/images/image-scaling/example-scale-to-fill-sequence.jpg [new file with mode: 0644]
docs/content/images/image-scaling/fitting-mode-options.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_box.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_box_then_linear.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_box_then_nearest.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_linear.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_nearest.png [new file with mode: 0644]
docs/content/images/image-scaling/sampling_modes_no_filter.png [new file with mode: 0644]
docs/content/images/image-scaling/scaling-fitting-target-dimensions.png [new file with mode: 0644]
docs/content/images/image-scaling/workflow-1.png [new file with mode: 0644]
docs/content/images/image-scaling/workflow-2.png [new file with mode: 0644]
docs/content/images/image-scaling/workflow-3.png [new file with mode: 0644]
docs/content/images/image-scaling/workflow-4.png [new file with mode: 0644]
docs/content/images/image-scaling/workflow-main.png [new file with mode: 0644]
docs/content/images/item-view/depth.png [new file with mode: 0644]
docs/content/images/item-view/grid.png [new file with mode: 0644]
docs/content/images/item-view/list.png [new file with mode: 0755]
docs/content/images/item-view/spiral.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/adding-function.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/base-wrapped-types.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/constructors.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/folder-view.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/high-level-design.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/plugin-creation.png [new file with mode: 0644]
docs/content/images/javascript-wrapping-guide/plugin-execution.png [new file with mode: 0644]
docs/content/images/layer/layer2d.png [new file with mode: 0644]
docs/content/images/layer/layers.png [new file with mode: 0644]
docs/content/images/layer/layers3d.png [new file with mode: 0644]
docs/content/images/layer/transSort.png [new file with mode: 0644]
docs/content/images/list-view/coverflow.png [new file with mode: 0644]
docs/content/images/list-view/grid.png [new file with mode: 0644]
docs/content/images/list-view/list.png [new file with mode: 0644]
docs/content/images/list-view/tunnel.png [new file with mode: 0644]
docs/content/images/parent-origin.png [new file with mode: 0644]
docs/content/images/path/path.png [new file with mode: 0644]
docs/content/images/performance/update-render.png [new file with mode: 0644]
docs/content/images/popup/popup-example.png [new file with mode: 0644]
docs/content/images/popup/popup-fields.png [new file with mode: 0644]
docs/content/images/popup/popup-image-content.png [new file with mode: 0644]
docs/content/images/popup/popup-toast.png [new file with mode: 0644]
docs/content/images/resource/9-patch-full.png [new file with mode: 0644]
docs/content/images/resource/9-patch-zoomed.png [new file with mode: 0644]
docs/content/images/resource/9-patch.png [new file with mode: 0644]
docs/content/images/screen-shot.png [new file with mode: 0644]
docs/content/images/scroll-view/scroll-view.png [new file with mode: 0755]
docs/content/images/shaders/BendyEffect1.png [new file with mode: 0644]
docs/content/images/shaders/BendyEffect2.png [new file with mode: 0644]
docs/content/images/shaders/RippleEffect1.png [new file with mode: 0644]
docs/content/images/shaders/fragment-shader-color.png [new file with mode: 0644]
docs/content/images/shaders/fragment-shader-reveal.png [new file with mode: 0644]
docs/content/images/shaders/shader-animation.png [new file with mode: 0644]
docs/content/images/shaders/shader-effect-ripple.png [new file with mode: 0644]
docs/content/images/shaders/shader-grid-hint.png [new file with mode: 0644]
docs/content/images/shaders/vertex-shader.png [new file with mode: 0644]
docs/content/images/size-negotiation/Popup.png [new file with mode: 0644]
docs/content/images/size-negotiation/PopupExample.png [new file with mode: 0644]
docs/content/images/size-negotiation/ResizePolicies.png [new file with mode: 0644]
docs/content/images/size-negotiation/ResizePoliciesExample.png [new file with mode: 0644]
docs/content/images/size-negotiation/SizeNegotiationExample_After.png [new file with mode: 0644]
docs/content/images/size-negotiation/SizeNegotiationExample_Before.png [new file with mode: 0644]
docs/content/images/spinner.gif [new file with mode: 0644]
docs/content/images/stage-hand/blocks.png [new file with mode: 0644]
docs/content/images/stage-hand/inner-workings.png [new file with mode: 0644]
docs/content/images/stage-hand/netstat.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-logo.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-mainscreen.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-modify.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-netcat.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-performance.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-refesh.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-save.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-screenshot.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-settings.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-tizen-connection.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-ubuntu-connection.png [new file with mode: 0644]
docs/content/images/stage-hand/stagehand-zoom.png [new file with mode: 0644]
docs/content/images/stage/stage.png [new file with mode: 0644]
docs/content/images/text-controls/ArabicBegin.png [new file with mode: 0644]
docs/content/images/text-controls/ArabicCenter.png [new file with mode: 0644]
docs/content/images/text-controls/ArabicEnd.png [new file with mode: 0644]
docs/content/images/text-controls/AutoScroll.gif [new file with mode: 0644]
docs/content/images/text-controls/EmptyTextAndNoContentToPaste.png [new file with mode: 0644]
docs/content/images/text-controls/EmptyTextClipboardHasContent.png [new file with mode: 0644]
docs/content/images/text-controls/HelloWorld-Default-BEGIN.png [new file with mode: 0755]
docs/content/images/text-controls/HelloWorld-Default-CENTER.png [new file with mode: 0755]
docs/content/images/text-controls/HelloWorld-Default-END.png [new file with mode: 0755]
docs/content/images/text-controls/HelloWorld-HeightForWidth.png [new file with mode: 0644]
docs/content/images/text-controls/HelloWorld-NaturalSize.png [new file with mode: 0644]
docs/content/images/text-controls/HelloWorld-System-BEGIN.png [new file with mode: 0755]
docs/content/images/text-controls/HelloWorld-System-CENTER.png [new file with mode: 0755]
docs/content/images/text-controls/HelloWorld-System-END.png [new file with mode: 0755]
docs/content/images/text-controls/LTR_RTL.png [new file with mode: 0755]
docs/content/images/text-controls/LTR_order.png [new file with mode: 0755]
docs/content/images/text-controls/LatinBegin.png [new file with mode: 0644]
docs/content/images/text-controls/LatinCenter.png [new file with mode: 0644]
docs/content/images/text-controls/LatinEnd.png [new file with mode: 0644]
docs/content/images/text-controls/PlainText.png [new file with mode: 0644]
docs/content/images/text-controls/RTL_order.png [new file with mode: 0755]
docs/content/images/text-controls/RedText.png [new file with mode: 0644]
docs/content/images/text-controls/SelectAllWhitespace.png [new file with mode: 0644]
docs/content/images/text-controls/SelectWhitespaceAfterText.png [new file with mode: 0644]
docs/content/images/text-controls/SelectingText.png [new file with mode: 0644]
docs/content/images/text-controls/SpecialCharacter1.png [new file with mode: 0755]
docs/content/images/text-controls/SpecialCharacters.png [new file with mode: 0755]
docs/content/images/text-controls/TapAfterCopyingText.png [new file with mode: 0644]
docs/content/images/text-controls/TextLabelCenter.png [new file with mode: 0644]
docs/content/images/text-controls/TextLabelTopLeft.png [new file with mode: 0644]
docs/content/images/text-controls/TextWith1pxUnderline.png [new file with mode: 0644]
docs/content/images/text-controls/TextWithBiggerShadow.png [new file with mode: 0644]
docs/content/images/text-controls/TextWithColorShadow.png [new file with mode: 0644]
docs/content/images/text-controls/TextWithColorUnderline.png [new file with mode: 0644]
docs/content/images/text-controls/TextWithShadow.png [new file with mode: 0644]
docs/content/images/text-controls/TextWithUnderline.png [new file with mode: 0644]
docs/content/images/text-controls/XHTML_entity.png [new file with mode: 0755]
docs/content/images/viewing-modes/google-cardboard.png [new file with mode: 0644]
docs/content/images/viewing-modes/stereo-projection.png [new file with mode: 0755]
docs/content/images/visuals/HelloWorld.png [new file with mode: 0644]
docs/content/images/visuals/animated-image-visual.gif [new file with mode: 0644]
docs/content/images/visuals/bevelled-cube-high.png [new file with mode: 0644]
docs/content/images/visuals/bevelled-cube-low.png [new file with mode: 0644]
docs/content/images/visuals/border-visual.png [new file with mode: 0644]
docs/content/images/visuals/color-visual.png [new file with mode: 0644]
docs/content/images/visuals/cone.png [new file with mode: 0644]
docs/content/images/visuals/conical-frustrum.png [new file with mode: 0644]
docs/content/images/visuals/cube.png [new file with mode: 0644]
docs/content/images/visuals/cylinder.png [new file with mode: 0644]
docs/content/images/visuals/image-visual.png [new file with mode: 0644]
docs/content/images/visuals/linear-gradient-visual.png [new file with mode: 0644]
docs/content/images/visuals/mesh-visual.png [new file with mode: 0644]
docs/content/images/visuals/n-patch-visual.png [new file with mode: 0644]
docs/content/images/visuals/octahedron.png [new file with mode: 0644]
docs/content/images/visuals/radial-gradient-visual.png [new file with mode: 0644]
docs/content/images/visuals/slices.png [new file with mode: 0644]
docs/content/images/visuals/sphere.png [new file with mode: 0644]
docs/content/images/visuals/stacks.png [new file with mode: 0644]
docs/content/images/visuals/svg-visual.svg [new file with mode: 0755]
docs/content/images/visuals/wireframe-visual.png [new file with mode: 0644]
docs/content/main.md [new file with mode: 0644]
docs/content/programming-guide/accessibility.md [new file with mode: 0644]
docs/content/programming-guide/animation-multi-threading-notes.h [new file with mode: 0644]
docs/content/programming-guide/animation.md [new file with mode: 0644]
docs/content/programming-guide/background.h [new file with mode: 0644]
docs/content/programming-guide/build-guide.md [new file with mode: 0644]
docs/content/programming-guide/constraints.h [new file with mode: 0644]
docs/content/programming-guide/copy-and-paste.md [new file with mode: 0644]
docs/content/programming-guide/creating-custom-controls.md [new file with mode: 0644]
docs/content/programming-guide/dali-application.h [new file with mode: 0644]
docs/content/programming-guide/dali-introduction.md [new file with mode: 0644]
docs/content/programming-guide/debug-rendering.md [new file with mode: 0644]
docs/content/programming-guide/documentation-guide.md [new file with mode: 0644]
docs/content/programming-guide/event-system.h [new file with mode: 0644]
docs/content/programming-guide/flex-container.md [new file with mode: 0644]
docs/content/programming-guide/font-selection.md [new file with mode: 0644]
docs/content/programming-guide/fundamentals.md [new file with mode: 0644]
docs/content/programming-guide/handle-body-idiom.h [new file with mode: 0644]
docs/content/programming-guide/hello-world.h [new file with mode: 0644]
docs/content/programming-guide/high-level-design.md [new file with mode: 0644]
docs/content/programming-guide/image-view.h [new file with mode: 0644]
docs/content/programming-guide/input-style.md [new file with mode: 0644]
docs/content/programming-guide/item-view.md [new file with mode: 0644]
docs/content/programming-guide/layer.md [new file with mode: 0644]
docs/content/programming-guide/markup-style.md [new file with mode: 0644]
docs/content/programming-guide/multi-touch-guide.md [new file with mode: 0644]
docs/content/programming-guide/performance-profiling.md [new file with mode: 0644]
docs/content/programming-guide/performance-tips.md [new file with mode: 0644]
docs/content/programming-guide/popup.md [new file with mode: 0644]
docs/content/programming-guide/programming-languages.md [new file with mode: 0644]
docs/content/programming-guide/properties.h [new file with mode: 0644]
docs/content/programming-guide/resource-image-scaling.md [new file with mode: 0644]
docs/content/programming-guide/resource-tracking.md [new file with mode: 0644]
docs/content/programming-guide/resources.md [new file with mode: 0644]
docs/content/programming-guide/script-hello.md [new file with mode: 0644]
docs/content/programming-guide/script-json-specification.md [new file with mode: 0644]
docs/content/programming-guide/script-overview.md [new file with mode: 0644]
docs/content/programming-guide/scroll-view.h [new file with mode: 0644]
docs/content/programming-guide/shader-intro.h [new file with mode: 0644]
docs/content/programming-guide/signals-actions.md [new file with mode: 0644]
docs/content/programming-guide/size-negotiation-controls.h [new file with mode: 0644]
docs/content/programming-guide/size-negotiation.h [new file with mode: 0644]
docs/content/programming-guide/stage-hand.md [new file with mode: 0644]
docs/content/programming-guide/styling.h [new file with mode: 0644]
docs/content/programming-guide/text-auto-scrolling.md [new file with mode: 0644]
docs/content/programming-guide/text-editor.md [new file with mode: 0644]
docs/content/programming-guide/text-field.md [new file with mode: 0644]
docs/content/programming-guide/text-label.md [new file with mode: 0644]
docs/content/programming-guide/type-registration.h [new file with mode: 0644]
docs/content/programming-guide/visuals.md [new file with mode: 0644]
docs/dali_doxygen.css [new file with mode: 0644]
packaging/dali-toolkit.spec [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..ff17e64
--- /dev/null
@@ -0,0 +1,306 @@
+cmake_minimum_required(VERSION 3.11)\r
+\r
+PROJECT (dali-toolkit)\r
+\r
+ADD_DEFINITIONS(\r
+-DDALI_ENV="../../dali-env"\r
+-DDALI_DATA_READ_ONLY_DIR=DALI_ENV"/opt/share/dali"\r
+-DDALI_IMAGE_DIR=DALI_ENV"/opt/share/dali/toolkit/images/"\r
+-DDALI_STYLE_DIR=DALI_ENV"/opt/share/dali/toolkit/styles/"\r
+-DDALI_SOUND_DIR=DALI_ENV"/opt/share/dali/toolkit/sounds/"\r
+-DDALI_STYLE_IMAGE_DIR=DALI_ENV"/opt/share/dali/toolkit/styles/images/"\r
+-DCURL_STATICLIB=0\r
+/DBUILDING_DALI_TOOLKIT\r
+/vmg\r
+/NODEFAULTLIB:"libcmt.lib"\r
+/FI"../windows-dependencies/ExInclude/PreprocessorDefinitions.h"\r
+/FI"../windows-dependencies/ExInclude/ToolKitPreDefine.h"\r
+/MP\r
+/Gz\r
+)\r
+\r
+#head file path\r
+INCLUDE_DIRECTORIES(\r
+./\r
+../dali-core\r
+../dali-adaptor\r
+../windows-dependencies/ExInclude\r
+../dali-env/opt/include\r
+)\r
+\r
+#devel-api\r
+SET( devel_api_src_dir dali-toolkit/devel-api )\r
+\r
+SET ( SOURCES ${SOURCES}\r
+  ${devel_api_src_dir}/builder/builder.cpp\r
+  ${devel_api_src_dir}/builder/json-parser.cpp\r
+  ${devel_api_src_dir}/builder/tree-node.cpp\r
+  ${devel_api_src_dir}/controls/control-devel.cpp\r
+  ${devel_api_src_dir}/controls/control-wrapper.cpp\r
+  ${devel_api_src_dir}/controls/control-wrapper-impl.cpp\r
+  ${devel_api_src_dir}/controls/bloom-view/bloom-view.cpp\r
+  ${devel_api_src_dir}/controls/bubble-effect/bubble-emitter.cpp\r
+  ${devel_api_src_dir}/controls/buttons/toggle-button.cpp\r
+  ${devel_api_src_dir}/controls/effects-view/effects-view.cpp\r
+  ${devel_api_src_dir}/controls/magnifier/magnifier.cpp\r
+  ${devel_api_src_dir}/controls/navigation-view/navigation-view.cpp\r
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-landscape-view.cpp\r
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-portrait-view.cpp\r
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-view.cpp\r
+  ${devel_api_src_dir}/controls/popup/confirmation-popup.cpp\r
+  ${devel_api_src_dir}/controls/popup/popup.cpp\r
+  ${devel_api_src_dir}/controls/shadow-view/shadow-view.cpp\r
+  ${devel_api_src_dir}/controls/super-blur-view/super-blur-view.cpp\r
+  ${devel_api_src_dir}/controls/text-controls/text-editor-devel.cpp\r
+  ${devel_api_src_dir}/controls/text-controls/text-field-devel.cpp\r
+  ${devel_api_src_dir}/controls/text-controls/text-selection-popup.cpp\r
+  ${devel_api_src_dir}/controls/text-controls/text-selection-toolbar.cpp\r
+  ${devel_api_src_dir}/controls/tool-bar/tool-bar.cpp\r
+  ${devel_api_src_dir}/focus-manager/keyinput-focus-manager.cpp\r
+  ${devel_api_src_dir}/focus-manager/keyboard-focus-manager-devel.cpp\r
+  ${devel_api_src_dir}/image-loader/async-image-loader-devel.cpp\r
+  ${devel_api_src_dir}/image-loader/atlas-upload-observer.cpp\r
+  ${devel_api_src_dir}/image-loader/image-atlas.cpp\r
+  ${devel_api_src_dir}/image-loader/texture-manager.cpp\r
+  ${devel_api_src_dir}/styling/style-manager-devel.cpp\r
+  ${devel_api_src_dir}/transition-effects/cube-transition-cross-effect.cpp\r
+  ${devel_api_src_dir}/transition-effects/cube-transition-effect.cpp\r
+  ${devel_api_src_dir}/transition-effects/cube-transition-fold-effect.cpp\r
+  ${devel_api_src_dir}/transition-effects/cube-transition-wave-effect.cpp\r
+  ${devel_api_src_dir}/visual-factory/transition-data.cpp\r
+  ${devel_api_src_dir}/visual-factory/visual-factory.cpp\r
+  ${devel_api_src_dir}/visual-factory/visual-base.cpp\r
+  ${devel_api_src_dir}/controls/gaussian-blur-view/gaussian-blur-view.cpp\r
+)\r
+\r
+#internal\r
+SET(internal_src_dir dali-toolkit/internal )\r
+\r
+SET( SOURCES ${SOURCES}\r
+   ${internal_src_dir}/builder/builder-animations.cpp\r
+   ${internal_src_dir}/builder/builder-impl.cpp\r
+   ${internal_src_dir}/builder/builder-impl-debug.cpp\r
+   ${internal_src_dir}/builder/builder-set-property.cpp\r
+   ${internal_src_dir}/builder/builder-signals.cpp\r
+   ${internal_src_dir}/builder/json-parser-state.cpp\r
+   ${internal_src_dir}/builder/json-parser-impl.cpp\r
+   ${internal_src_dir}/builder/style.cpp\r
+   ${internal_src_dir}/builder/tree-node-manipulator.cpp\r
+   ${internal_src_dir}/builder/replacement.cpp\r
+   ${internal_src_dir}/visuals/animated-image/animated-image-visual.cpp\r
+   ${internal_src_dir}/visuals/animated-image/image-cache.cpp\r
+   ${internal_src_dir}/visuals/animated-image/fixed-image-cache.cpp\r
+   ${internal_src_dir}/visuals/animated-image/rolling-image-cache.cpp\r
+   ${internal_src_dir}/visuals/animated-image/rolling-gif-image-cache.cpp\r
+   ${internal_src_dir}/visuals/border/border-visual.cpp\r
+   ${internal_src_dir}/visuals/color/color-visual.cpp\r
+   ${internal_src_dir}/visuals/gradient/gradient-visual.cpp\r
+   ${internal_src_dir}/visuals/gradient/gradient.cpp\r
+   ${internal_src_dir}/visuals/gradient/linear-gradient.cpp\r
+   ${internal_src_dir}/visuals/gradient/radial-gradient.cpp\r
+   ${internal_src_dir}/visuals/animated-gradient/animated-gradient-visual.cpp\r
+   ${internal_src_dir}/visuals/image-atlas-manager.cpp\r
+   ${internal_src_dir}/visuals/image/image-visual.cpp\r
+   ${internal_src_dir}/visuals/mesh/mesh-visual.cpp\r
+   ${internal_src_dir}/visuals/npatch-loader.cpp\r
+   ${internal_src_dir}/visuals/npatch/npatch-visual.cpp\r
+   ${internal_src_dir}/visuals/primitive/primitive-visual.cpp\r
+   ${internal_src_dir}/visuals/svg/svg-rasterize-thread.cpp\r
+   ${internal_src_dir}/visuals/svg/svg-visual.cpp\r
+   ${internal_src_dir}/visuals/text/text-visual.cpp\r
+   ${internal_src_dir}/visuals/transition-data-impl.cpp\r
+   ${internal_src_dir}/visuals/texture-manager-impl.cpp\r
+   ${internal_src_dir}/visuals/texture-upload-observer.cpp\r
+   ${internal_src_dir}/visuals/image-visual-shader-factory.cpp\r
+   ${internal_src_dir}/visuals/visual-base-data-impl.cpp\r
+   ${internal_src_dir}/visuals/visual-base-impl.cpp\r
+   ${internal_src_dir}/visuals/visual-factory-cache.cpp\r
+   ${internal_src_dir}/visuals/visual-factory-impl.cpp\r
+   ${internal_src_dir}/visuals/visual-string-constants.cpp\r
+   ${internal_src_dir}/visuals/visual-url.cpp\r
+   ${internal_src_dir}/visuals/wireframe/wireframe-visual.cpp\r
+   ${internal_src_dir}/controls/alignment/alignment-impl.cpp\r
+   ${internal_src_dir}/controls/bloom-view/bloom-view-impl.cpp\r
+   ${internal_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp\r
+   ${internal_src_dir}/controls/bubble-effect/bubble-renderer.cpp\r
+   ${internal_src_dir}/controls/buttons/button-impl.cpp\r
+   ${internal_src_dir}/controls/buttons/check-box-button-impl.cpp\r
+   ${internal_src_dir}/controls/buttons/push-button-impl.cpp\r
+   ${internal_src_dir}/controls/buttons/radio-button-impl.cpp\r
+   ${internal_src_dir}/controls/buttons/toggle-button-impl.cpp\r
+   ${internal_src_dir}/controls/control/control-data-impl.cpp\r
+   ${internal_src_dir}/controls/control/control-debug.cpp\r
+   ${internal_src_dir}/controls/effects-view/effects-view-impl.cpp\r
+   ${internal_src_dir}/controls/flex-container/flex-container-impl.cpp\r
+   ${internal_src_dir}/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp\r
+   ${internal_src_dir}/controls/image-view/image-view-impl.cpp\r
+   ${internal_src_dir}/controls/magnifier/magnifier-impl.cpp\r
+   ${internal_src_dir}/controls/navigation-view/navigation-view-impl.cpp\r
+   ${internal_src_dir}/controls/popup/confirmation-popup-impl.cpp\r
+   ${internal_src_dir}/controls/model3d-view/model3d-view-impl.cpp\r
+   ${internal_src_dir}/controls/model3d-view/obj-loader.cpp\r
+   ${internal_src_dir}/controls/popup/popup-impl.cpp\r
+   ${internal_src_dir}/controls/page-turn-view/page-turn-portrait-view-impl.cpp\r
+   ${internal_src_dir}/controls/page-turn-view/page-turn-effect.cpp\r
+   ${internal_src_dir}/controls/page-turn-view/page-turn-landscape-view-impl.cpp\r
+   ${internal_src_dir}/controls/page-turn-view/page-turn-view-impl.cpp\r
+   ${internal_src_dir}/controls/progress-bar/progress-bar-impl.cpp\r
+   ${internal_src_dir}/controls/scroll-bar/scroll-bar-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/bouncing-effect-actor.cpp\r
+   ${internal_src_dir}/controls/scrollable/item-view/depth-layout.cpp\r
+   ${internal_src_dir}/controls/scrollable/item-view/grid-layout.cpp\r
+   ${internal_src_dir}/controls/scrollable/item-view/item-view-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/item-view/spiral-layout.cpp\r
+   ${internal_src_dir}/controls/scrollable/scrollable-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/scroll-view/scroll-base-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp\r
+   ${internal_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp\r
+   ${internal_src_dir}/controls/shadow-view/shadow-view-impl.cpp\r
+   ${internal_src_dir}/controls/slider/slider-impl.cpp\r
+   ${internal_src_dir}/controls/super-blur-view/super-blur-view-impl.cpp\r
+   ${internal_src_dir}/controls/table-view/table-view-impl.cpp\r
+   ${internal_src_dir}/controls/text-controls/text-editor-impl.cpp\r
+   ${internal_src_dir}/controls/text-controls/text-field-impl.cpp\r
+   ${internal_src_dir}/controls/text-controls/text-label-impl.cpp\r
+   ${internal_src_dir}/controls/text-controls/text-selection-popup-impl.cpp\r
+   ${internal_src_dir}/controls/text-controls/text-selection-toolbar-impl.cpp\r
+   ${internal_src_dir}/controls/tool-bar/tool-bar-impl.cpp\r
+   ${internal_src_dir}/controls/tooltip/tooltip.cpp\r
+   ${internal_src_dir}/controls/video-view/video-view-impl.cpp\r
+   ${internal_src_dir}/accessibility-manager/accessibility-manager-impl.cpp\r
+   ${internal_src_dir}/feedback/feedback-style.cpp\r
+   ${internal_src_dir}/focus-manager/keyboard-focus-manager-impl.cpp\r
+   ${internal_src_dir}/focus-manager/keyinput-focus-manager-impl.cpp\r
+   ${internal_src_dir}/helpers/color-conversion.cpp\r
+   ${internal_src_dir}/helpers/property-helper.cpp\r
+   ${internal_src_dir}/filters/blur-two-pass-filter.cpp\r
+   ${internal_src_dir}/filters/emboss-filter.cpp\r
+   ${internal_src_dir}/filters/image-filter.cpp\r
+   ${internal_src_dir}/filters/spread-filter.cpp\r
+   ${internal_src_dir}/image-loader/async-image-loader-impl.cpp\r
+   ${internal_src_dir}/image-loader/atlas-packer.cpp\r
+   ${internal_src_dir}/image-loader/image-atlas-impl.cpp\r
+   ${internal_src_dir}/image-loader/image-load-thread.cpp\r
+   ${internal_src_dir}/styling/style-manager-impl.cpp\r
+   ${internal_src_dir}/text/bidirectional-support.cpp\r
+   ${internal_src_dir}/text/character-set-conversion.cpp\r
+   ${internal_src_dir}/text/color-segmentation.cpp\r
+   ${internal_src_dir}/text/cursor-helper-functions.cpp\r
+   ${internal_src_dir}/text/glyph-metrics-helper.cpp\r
+   ${internal_src_dir}/text/logical-model-impl.cpp\r
+   ${internal_src_dir}/text/markup-processor.cpp\r
+   ${internal_src_dir}/text/markup-processor-color.cpp\r
+   ${internal_src_dir}/text/markup-processor-font.cpp\r
+   ${internal_src_dir}/text/markup-processor-helper-functions.cpp\r
+   ${internal_src_dir}/text/multi-language-support.cpp\r
+   ${internal_src_dir}/text/hidden-text.cpp\r
+   ${internal_src_dir}/text/property-string-parser.cpp\r
+   ${internal_src_dir}/text/segmentation.cpp\r
+   ${internal_src_dir}/text/shaper.cpp\r
+   ${internal_src_dir}/text/text-enumerations-impl.cpp\r
+   ${internal_src_dir}/text/text-controller.cpp\r
+   ${internal_src_dir}/text/text-controller-impl.cpp\r
+   ${internal_src_dir}/text/text-effects-style.cpp\r
+   ${internal_src_dir}/text/text-font-style.cpp\r
+   ${internal_src_dir}/text/text-io.cpp\r
+   ${internal_src_dir}/text/text-model.cpp\r
+   ${internal_src_dir}/text/text-scroller.cpp\r
+   ${internal_src_dir}/text/text-vertical-scroller.cpp\r
+   ${internal_src_dir}/text/text-view.cpp\r
+   ${internal_src_dir}/text/text-view-interface.cpp\r
+   ${internal_src_dir}/text/visual-model-impl.cpp\r
+   ${internal_src_dir}/text/decorator/text-decorator.cpp\r
+   ${internal_src_dir}/text/layouts/layout-engine.cpp\r
+   ${internal_src_dir}/text/multi-language-helper-functions.cpp\r
+   ${internal_src_dir}/text/multi-language-support-impl.cpp\r
+   ${internal_src_dir}/text/rendering/text-backend.cpp\r
+   ${internal_src_dir}/text/rendering/text-renderer.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/text-atlas-renderer.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/atlas-glyph-manager.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/atlas-glyph-manager-impl.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/atlas-manager.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/atlas-manager-impl.cpp\r
+   ${internal_src_dir}/text/rendering/atlas/atlas-mesh-factory.cpp\r
+   ${internal_src_dir}/text/rendering/text-backend-impl.cpp\r
+   ${internal_src_dir}/text/rendering/text-typesetter.cpp\r
+   ${internal_src_dir}/text/rendering/view-model.cpp\r
+   ${internal_src_dir}/transition-effects/cube-transition-effect-impl.cpp\r
+   ${internal_src_dir}/transition-effects/cube-transition-cross-effect-impl.cpp\r
+   ${internal_src_dir}/transition-effects/cube-transition-fold-effect-impl.cpp\r
+   ${internal_src_dir}/transition-effects/cube-transition-wave-effect-impl.cpp\r
+   ${internal_src_dir}/text/xhtml-entities.cpp\r
+)\r
+\r
+#public-api\r
+SET( public_api_src_dir dali-toolkit/public-api )\r
+\r
+SET( SOURCES ${SOURCES}\r
+  ${public_api_src_dir}/controls/control-impl.cpp\r
+  ${public_api_src_dir}/controls/control.cpp\r
+  ${public_api_src_dir}/controls/alignment/alignment.cpp\r
+  ${public_api_src_dir}/controls/buttons/button.cpp\r
+  ${public_api_src_dir}/controls/buttons/check-box-button.cpp\r
+  ${public_api_src_dir}/controls/buttons/push-button.cpp\r
+  ${public_api_src_dir}/controls/buttons/radio-button.cpp\r
+  ${public_api_src_dir}/controls/flex-container/flex-container.cpp\r
+  ${public_api_src_dir}/controls/image-view/image-view.cpp\r
+  ${public_api_src_dir}/controls/model3d-view/model3d-view.cpp\r
+  ${public_api_src_dir}/controls/progress-bar/progress-bar.cpp\r
+  ${public_api_src_dir}/controls/scroll-bar/scroll-bar.cpp\r
+  ${public_api_src_dir}/controls/scrollable/item-view/default-item-layout.cpp\r
+  ${public_api_src_dir}/controls/scrollable/item-view/item-layout.cpp\r
+  ${public_api_src_dir}/controls/scrollable/item-view/item-view.cpp\r
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-constraints.cpp\r
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-effect.cpp\r
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect.cpp\r
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view.cpp\r
+  ${public_api_src_dir}/controls/scrollable/scrollable.cpp\r
+  ${public_api_src_dir}/controls/slider/slider.cpp\r
+  ${public_api_src_dir}/controls/table-view/table-view.cpp\r
+  ${public_api_src_dir}/controls/text-controls/text-editor.cpp\r
+  ${public_api_src_dir}/controls/text-controls/text-label.cpp\r
+  ${public_api_src_dir}/controls/text-controls/text-field.cpp\r
+  ${public_api_src_dir}/controls/video-view/video-view.cpp\r
+  ${public_api_src_dir}/image-loader/async-image-loader.cpp\r
+  ${public_api_src_dir}/image-loader/sync-image-loader.cpp\r
+  ${public_api_src_dir}/styling/style-manager.cpp\r
+  ${public_api_src_dir}/accessibility-manager/accessibility-manager.cpp\r
+  ${public_api_src_dir}/focus-manager/keyboard-focus-manager.cpp\r
+  ${public_api_src_dir}/dali-toolkit-version.cpp\r
+  ${public_api_src_dir}/enums.cpp\r
+)\r
+\r
+link_directories(\r
+../windows-dependencies/ExLib\r
+../bin\r
+)\r
+\r
+SET( SOURCES ${SOURCES}\r
+  dali-toolkit/third-party/nanosvg/nanosvg.cc\r
+  dali-toolkit/third-party/nanosvg/nanosvgrast.cc\r
+  dali-toolkit/third-party/yoga/Yoga.cpp\r
+  dali-toolkit/third-party/yoga/YGStyle.cpp\r
+  dali-toolkit/third-party/yoga/YGNodePrint.cpp\r
+  dali-toolkit/third-party/yoga/YGNode.cpp\r
+  dali-toolkit/third-party/yoga/YGLayout.cpp\r
+  dali-toolkit/third-party/yoga/YGFloatOptional.cpp\r
+  dali-toolkit/third-party/yoga/YGEnums.cpp\r
+  dali-toolkit/third-party/yoga/YGConfig.cpp\r
+  dali-toolkit/third-party/yoga/Utils.cpp\r
+)\r
+set(LIBRARY_OUTPUT_PATH ../../../bin)\r
+\r
+ADD_LIBRARY(dali-toolkit SHARED ${SOURCES})\r
+\r
+target_link_libraries(dali-toolkit dali-core.lib)\r
+target_link_libraries(dali-toolkit dali-adaptor.lib)\r
+target_link_libraries(dali-toolkit dlfcn.lib)\r
+target_link_libraries(dali-toolkit WindowsPlatform.lib)\r
+\r
+add_dependencies(dali-toolkit dali-core)\r
+add_dependencies(dali-toolkit dali-adaptor)\r
+\r
+#add link library\r
+#TARGET_LINK_LIBRARIES(${FS_BUILD_BINARY_PREFIX}sqrt ${LIBRARIES})\r
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..dc0510e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,70 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
\ No newline at end of file
diff --git a/LICENSE.BSD-3-Clause b/LICENSE.BSD-3-Clause
new file mode 100644 (file)
index 0000000..bd25463
--- /dev/null
@@ -0,0 +1,12 @@
+
+Copyright (c) 2017 Samsung Electronics Co, Ltd. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..2bd6dd8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,114 @@
+<img src="https://dalihub.github.io/images/DaliLogo320x200.png">
+
+# Table of Contents
+
+   * [Build Instructions](#build-instructions)
+      * [1. Building for Ubuntu desktop](#1-building-for-ubuntu-desktop)
+         * [Minimum Requirements](#minimum-requirements)
+         * [Building the Repository](#building-the-repository)
+         * [Building and executing test cases](#building-and-executing-test-cases)
+      * [2. GBS Builds](#2-gbs-builds)
+         * [NON-SMACK Targets](#non-smack-targets)
+         * [SMACK enabled Targets](#smack-enabled-targets)
+         * [DEBUG Builds](#debug-builds)
+      * [3. Building for MS Windows](#3-building-for-ms-windows)
+         * Build with the Visual Studio project.
+         * Build with CMake.
+
+# Build Instructions
+
+## 1. Building for Ubuntu desktop
+
+### Requirements
+
+ - Ubuntu 14.04 or later
+ - Environment created using dali_env script in dali-core repository
+ - GCC version 6
+
+DALi requires a compiler supporting C++11 features.
+Ubuntu 16.04 is the first version to offer this by default (GCC v5.4.0).
+
+GCC version 6 is recommended since it has fixes for issues in version 5
+e.g. it avoids spurious 'defined but not used' warnings in header files.
+
+### Building the Repository
+
+To build the repository enter the 'build/tizen' folder:
+
+         $ cd dali-toolkit/build/tizen
+
+Then run the following command to set up the build:
+
+         $ cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX .
+
+If a Debug build is required, then add -DCMAKE_BUILD_TYPE=Debug
+
+To build run:
+
+         $ make install -j8
+
+### Building and executing test cases
+
+See the README.md in dali-toolkit/automated-tests.
+
+## 2. GBS Builds
+
+### NON-SMACK Targets
+
+         $ gbs build -A [TARGET_ARCH]
+
+### SMACK enabled Targets
+
+         $ gbs build -A [TARGET_ARCH] --define "%enable_dali_smack_rules 1"
+
+### DEBUG Builds
+
+         $ gbs build -A [TARGET_ARCH] --define "%enable_debug 1"
+
+
+## 3. Building for MS Windows
+
+Third party dependencies are built using vcpkg. Instructions on how to install vcpkg can be found in the
+vcpkg-script folder in the windows-dependencies repository.
+
+- Download the windows-dependencies repository from DaliHub
+
+         $ git clone https://github.com/dalihub/windows-dependencies.git
+
+- Read the windows-dependencies/vcpkg-script/Readme.md file for more instructions on how to build and install the third-party dependencies.
+
+### Build with the Visual Studio project
+  Read the windows-dependencies/README.md file for more instructions on how to build and run DALi for MS Windows.
+
+### Build with CMake
+
+  * Requirements
+    It's required the version 3.12.2 of CMake and a Git Bash Shell.
+
+  * Notes and troubleshoting:
+    It should be possible to use the MS Visual studio Developer Command Prompt (https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs) to build DALi from the command line.
+    However, the CMake version installed with MS Visual Studio 2017 is a bit out of date and some VCPKG modules require a higher version.
+    This instructions have been tested with CMake 3.12.2 on a Git Bash shell.
+
+  * Define an environment variable to set the path to the VCPKG folder
+
+    $ export VCPKG_FOLDER=C:/Users/username/Workspace/VCPKG_TOOL
+
+  * Define an environment variable to set the path where DALi is going to be installed.
+
+    $ export DALI_ENV_FOLDER=C:/Users/username/Workspace/dali-env
+
+  * Execute the following commands to create the makefiles, build and install DALi.
+
+    $ cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=$VCPKG_FOLDER/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DENABLE_LINK_TEST=OFF -DCMAKE_INSTALL_PREFIX=$DALI_ENV_FOLDER -DINSTALL_CMAKE_MODULES=ON -DUSE_DEFAULT_RESOURCE_DIR=OFF
+    $ cmake --build . --target install
+
+
+  * Options:
+    - CMAKE_TOOLCHAIN_FILE     ---> Needed to find packages installed by VCPKG.
+    - ENABLE_PKG_CONFIGURE     ---> Whether to install pkg configure files (not currently working on MS Windows. CMake modules used instead).
+    - ENABLE_LINK_TEST         ---> Whether to enable the link test (not currently working on MS Windows).
+    - CMAKE_INSTALL_PREFIX     ---> Were DALi is installed.
+    - INSTALL_CMAKE_MODULES    ---> Whether to install the CMake modules (Used by the CMake command find_package() to find previously installed libraries).
+    - ENABLE_DEBUG             ---> Whether to build with debug enabled.
+    - USE_DEFAULT_RESOURCE_DIR ---> Whether to use the default resource folders. Otherwise set environment variables for DALI_IMAGE_DIR, DALI_SOUND_DIR, DALI_STYLE_DIR, DALI_STYLE_IMAGE_DIR and DALI_DATA_READ_ONLY_DIR
diff --git a/automated-tests/.gitignore-with-autogenerated-files b/automated-tests/.gitignore-with-autogenerated-files
new file mode 100644 (file)
index 0000000..f039d8a
--- /dev/null
@@ -0,0 +1,4 @@
+*.xml
+build
+build.log
+tct*core.h
diff --git a/automated-tests/.gitignore-without-autogenerated-files b/automated-tests/.gitignore-without-autogenerated-files
new file mode 100644 (file)
index 0000000..8f3f9e2
--- /dev/null
@@ -0,0 +1,3 @@
+*.xml
+build
+build.log
diff --git a/automated-tests/CMakeLists.txt.in b/automated-tests/CMakeLists.txt.in
new file mode 100644 (file)
index 0000000..8851c15
--- /dev/null
@@ -0,0 +1,41 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(tct_coreapi_utc)
+
+INCLUDE(FindPkgConfig)
+SET(BIN_DIR "/opt/usr/bin")
+
+ADD_DEFINITIONS(-DDALI_STYLE_DIR="@dataReadOnlyDir@/toolkit/styles/")
+
+INCLUDE_DIRECTORIES(
+  src/common
+)
+
+ADD_SUBDIRECTORY(src)
+
+#Internationalization
+SET(PO_DIR ${CMAKE_SOURCE_DIR}/resources/po)
+MESSAGE("po dir: ${PO_DIR}")
+FILE(GLOB PO_FILES RELATIVE "${PO_DIR}" "${PO_DIR}/*.po")
+
+SET(MSGFMT "/usr/bin/msgfmt")
+SET(MO_FILES_DIR /tmp/locale)
+FILE(MAKE_DIRECTORY ${MO_FILES_DIR})
+
+FOREACH(PO_FILE ${PO_FILES})
+        SET(PO_FILE ${PO_DIR}/${PO_FILE})
+        MESSAGE("PO: ${PO_FILE}")
+        GET_FILENAME_COMPONENT(ABS_PO_FILE ${PO_FILE} ABSOLUTE)
+        MESSAGE("ABS_PO_FILE : ${ABS_PO_FILE}")
+        GET_FILENAME_COMPONENT(lang ${ABS_PO_FILE} NAME_WE)
+        MESSAGE("lang : ${lang}")
+        FILE(MAKE_DIRECTORY ${MO_FILES_DIR}/${lang}/LC_MESSAGES)
+        SET(MO_FILE ${MO_FILES_DIR}/${lang}/LC_MESSAGES/dali-toolkit.mo)
+        MESSAGE("MO_FILE : ${MO_FILE}")
+        ADD_CUSTOM_COMMAND(OUTPUT ${MO_FILE}
+                           COMMAND ${MSGFMT} -o ${MO_FILE} ${ABS_PO_FILE}
+                           DEPENDS ${ABS_PO_FILE})
+        SET(MO_FILES ${MO_FILES} ${MO_FILE})
+ENDFOREACH(PO_FILE)
+
+MESSAGE(".mo files: ${MO_FILES}")
+ADD_CUSTOM_TARGET(po ALL DEPENDS ${MO_FILES})
diff --git a/automated-tests/README.md b/automated-tests/README.md
new file mode 100644 (file)
index 0000000..c062b8a
--- /dev/null
@@ -0,0 +1,277 @@
+Testing environment   {#auto_testing}
+===================
+
+The new test environment from Tizen is the Web-TCT test suite. This was written for testing web components, but can easily be used for testing Dali.
+
+Each of the DALi repositories, **dali-core**, **dali-adaptor** and **dali-toolkit**, have their own test suites under the `automated-tests` folder. Within the src folder are a number of secondary folders - these correspond to 'API' tests  and internal (for desktop testing only)
+
+Installation
+------------
+
+There are usage instructions and installation instructions on the Tizen.org website [here](http://download.tizen.org/tct/2.2.1/Manual/Web_TCT_2.2.1_User_Guide_v1.0.pdf)
+
+These are device specific instructions, however, installing the test suite will also provide the relevant packages for running tests on Ubuntu ( follow the first block of quickstart instructions below ).
+
+If you are planning on running tests on device, then flash your handset with latest image, or turn off ssh: `set_usb_debug.sh --mtp-sdb` and plug it in, then follow the quickstart instructions repeated below.
+
+Multi-language locale environment
+---------------------------------
+
+Locales for English and Arabic must be installed to pass some test cases:
+
+$ sudo locale-gen en
+$ sudo locale-gen ar
+$ sudo update-locale
+
+Installing fonts required by tests
+----------------------------------
+
+The test suite requires certain fonts in the repository to be installed:
+
+$ mkdir -p ~/.fonts
+$ cp -r resources/fonts/* ~/.fonts/
+$ fc-cache
+
+Quickstart
+----------
+
+For target or desktop testing:
+
+    cd ~/Packages
+    wget http://download.tizen.org/tct/2.2.1/2.2.1_r1/web-tct_2.2.1_r1.tar.gz
+    sudo tar xzf web-tct_2.2.1_r1.tar.gz
+    cd web-tct_2.2.1_r1/tools
+    sudo -E ./tct-config-host.sh
+
+
+If you are planning on running tests on device, then plug in your freshly flashed device and run the following commands:
+
+    sudo apt-get install sdb
+    ./tct-config-device.sh
+
+**NOTE:** After flashing a handset, you will need to run this step of the installation again.
+
+Testing on desktop
+==================
+
+Building libraries with coverage options
+----------------------------------------
+
+Building dali toolkit:
+
+    cd dali-core  # the location of your dali-core repository
+    cd build/tizen
+    export CC=gcc
+    export CXX=g++
+    git clean -fxd . # Only do this in the build folder
+    CXXFLAGS='-g -O0 --coverage' LDFLAGS='--coverage' cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX -DCMAKE_BUILD_TYPE=Debug
+    make -j8 install
+
+Note, you __must__ use a local build and not a distributed build, and you __must__ also build with debug enabled to allow *DALI_ASSERT_DEBUG* to trigger on wrong behaviour ( Which should always be a test case failure! )
+
+Further note that, for the following, your gcov version must match the version of the compiler.
+
+Building the tests
+------------------
+
+Run the following commands:
+
+    cd automated-tests
+    ./build.sh
+
+This will build dali-toolkit and dali-toolkit-internal test sets.
+
+Test sets can be built individually:
+
+    ./build.sh dali-toolkit
+
+They can also be built without regenerating test case scripts (Useful for quicker rebuilds)
+
+    ./build.sh -n dali-toolkit-internal
+
+Or without cleaning down the build area (Useful for fast build/run/debug cycles)
+
+    ./build.sh -n -r dali-toolkit-internal
+
+
+Executing the tests
+-------------------
+
+To see a list of all of the options:
+
+    ./execute.sh -h
+
+To execute tests, cd into automated-tests and run
+
+    ./execute.sh
+
+This will execute dali and dali-internal test sets. Note that the output summary for the first will be printed before running the second.
+
+By default the tests execute in parallel, which is faster but does not produce any test case output files.  Use this to execute the tests in series and log test output to stdout/err
+
+    ./execute.sh -S
+
+To use test kit lite, (which is very slow),
+
+    ./execute.sh -s
+
+To see the test kit lite results, copy the style folder from web-tct_2.2.1_r1/tools/tct-mgr/style into automated-tests and run
+
+    firefox --new-window summary.xml
+
+To execute a subset of tests, you can run individual test sets, e.g.
+
+    ./execute.sh dali-toolkit
+
+To get coverage output (you need to first build dali libraries with
+--coverage), run
+
+    ./coverage.sh
+
+
+Testing on target
+=================
+
+To build for target, first build and install dali-core, dali-adaptor and dali-toolkit, then build dali-capi without --keep-packs option.
+
+You will need to install libconfig-tiny-perl:
+
+sudo apt-get install libconfig-tiny-perl
+
+If you use a non-standard `GBS_ROOT` then you will need to edit the tcbuild script to match your configuration - change line 96 and add a -B option with your GBS-ROOT path (line 96 = `gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs` ).
+To install on device from a non-standard GBS_ROOT, also modify line 28 (`RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"`).
+
+For core Dali cd into automated-tests, and use:
+
+sudo ./tcbuild build dali
+
+    sudo ./tcbuild build dali
+    ./tcbuild install dali
+
+For Dali Adaptor, cd into automated-tests, and use:
+
+    sudo ./tcbuild build dali-adaptor
+    sudo ./tcbuild build dali-platform-abstraction
+    ./tcbuild install dali-adaptor
+    ./tcbuild install dali-platform-abstraction
+
+Ensure your handset's filesystem is writable:
+
+    sdb shell su -c "change-booting-mode.sh --update"
+
+To execute tests, cd into automated-tests and run
+
+    tct-mgr
+
+This will bring up the java test suite program. You should see the Plan pane with a list of all tests in. Select the tct-dali-core-tests. and you will be offered a dialog to choose a test plan: either create a new one or use temp.
+Select dali test suite, and click Run, then "Create a new plan", and call it "Dali-Core" or some such. It will now run the dali-test suite.
+
+You can find the output files under /opt/tct/manager/result/
+
+
+Adding tests
+============
+
+To Managed API
+--------------
+
+If you are adding test cases for new or existing managed API (CAPI), you need to add your changes to the src/dali mirror, and copy your change to the managed test suite in core-api. You need to inform HQ of your update.
+
+For internal API
+----------------
+
+If you are adding tests for internal API, then this will only work on desktop, and you should add your tests to the src/dali-internal test suite.
+
+General
+-------
+
+If you are adding test cases to existing files, then all you need to do is create functions with the method signature
+
+    int UtcTestcase(void)
+    {
+      TestApplication application;
+      ...
+      END_TEST;
+    }
+
+Note that **the parentheses in the method signature must not be empty** (i.e., it must violate our coding convention and follow __exactly__ this pattern: `int UtcDaliMyTestcaseName(void)`), as it's parsed by an awk script to auto-generate the testcase arrays in the main header file. Neither may any comments on the same line contain empty parentheses.
+
+You can contine to use the TET api, e.g. `tet_infoline`, `tet_result` and our test check methods `DALI_TEST_CHECK`, `DALI_TEST_EQUALS`, etc.
+
+If you need any non-test methods or variables, ensure they are wrapped in an anonymous namespace.
+
+If you are adding new test files, then you need to add the filename to the SET(TC_SOURCES...
+section of CMakeLists.txt (this is also parsed by an awk script prior to building)
+
+Good Practices
+--------------
+Use DALI_TEST_EQUALS to test actual value against expected value, like this:
+
+    DALI_TEST_EQUALS( actor.GetProperty< float >( Actor::Property::COLOR_ALPHA ), 0.9f, TEST_LOCATION );
+
+This will speed up debugging in case the test some day fails. There is also a variant to test that value is greater than expected:
+
+    DALI_TEST_GREATER( textureBindIndex[1], textureBindIndex[2], TEST_LOCATION );
+
+When doing negative tests where your code uses DALI_ASSERT_ALWAYS, use the DALI_TEST_ASSERTION macro, like below:
+
+    DALI_TEST_ASSERTION(
+    {
+        animation.AnimateTo( Property( actor, Actor::Property::PARENT_ORIGIN ), targetParentOrigin );
+    }, "IsPropertyAnimatable( index )" );
+
+This macro will catch the DALi Exception and check that the correct assert message was included. It will also fail the test in case the assert did not occur. It also reduces the amount of false positive error logging whilst the  is being thrown making it easier to see the real errors.
+
+Note, DALI_ASSERT_DEBUG cannot be tested as tests execute against release version of the code.
+
+Use additional scope to control the life of stack allocated objects, such as DALi handles
+
+    // try reparenting an orphaned child
+    {
+        Actor temporaryParent = Actor::New();
+        temporaryParent.Add( child );
+        DALI_TEST_EQUALS( parent2.GetChildCount(), 0u, TEST_LOCATION );
+    }
+    // temporaryParent has now died, reparent the orphaned child
+    parent2.Add( child );
+    DALI_TEST_EQUALS( parent2.GetChildCount(), 1u, TEST_LOCATION );
+
+Always test the output of your test by making your code fail!!!
+
+Debugging
+=========
+
+On desktop, you can debug the tests by running gdb on the test program:
+
+    $ cd automated-tests
+    $ gdb build/src/dali-toolkit/tct-dali-toolkit-core
+    gdb> r <TestCase>
+
+replace `<TestCase>` with the name of the failing testcase.
+
+For example, using testcase UtcDaliControlBackgroundProperties from the dali-toolkit test suite:
+
+    $ gdb build/src/dali-toolkit/tct-dali-toolkit-core
+    gdb> r UtcDaliControlBackgroundProperties
+
+
+On target, you can re-install the test RPM and associated debug RPMs manually using
+
+    sdb push <test-package>.rpm /tmp
+
+After installing the rpm and it's debug RPMs, you can find the executable in /opt/usr/bin/tct-dali-core. First ensure you have smack permissions set:
+
+    chsmack -e "^" /usr/bin/gdb
+    chsmack -e "^" /opt/usr/bin/tct-dali-toolkit-core/tct-dali-toolkit-core
+
+then run it under gdb as above.
+
+
+Troubleshooting
+===============
+
+If when running tct-mgr tests, if "Health-Check get" fails and leaves a white screen on the device, you will need to run `tct-config-device.sh` from your `web-tct/tools` directory (wherever you untarred it) and power cycle your handset. If that still fails, you can work-around the issue by running "`mkdir –p /opt/usr/media/Documents/tct/`" on target – you may also need to kill the getCapabilities app from App Manager on the handset)
+
+If the test results show that the test cases fail with "Undefined reference to XXX", it means you have probably failed to update the dali packages on target.
+
+If all the tests are failing then make sure that you have enabled the engineering mode on the target with the 'change-booting-mode.sh --update' command in sdb shell, as the tests may not have installed correctly
diff --git a/automated-tests/build.sh b/automated-tests/build.sh
new file mode 100755 (executable)
index 0000000..2f92135
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+
+TEMP=`getopt -o rn --long rebuild,no-gen \
+     -n 'genmake' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+opt_rebuild=false
+opt_generate=true
+
+while true ; do
+    case "$1" in
+        -r|--rebuild) opt_rebuild=true ; shift ;;
+        -n|--no-gen)  opt_generate=false ; shift ;;
+        --) shift ; break ;;
+        *) shift ;;   # Ignore
+    esac
+done
+
+if [ false == $opt_rebuild -o ! -d "build" ] ; then
+    rm -rf build
+    mkdir build
+fi
+
+function build
+{
+    if [ $opt_generate == true -o $opt_rebuild == false ] ; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+    fi
+    (cd build ; cmake .. -DMODULE=$1 ; make -j7 )
+}
+
+if [ -n "$1" ] ; then
+  echo BUILDING ONLY $1
+  build $1
+else
+  for mod in `ls -1 src/ | grep -v CMakeList `
+  do
+    if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+        echo BUILDING $mod
+        build $mod
+        if [ $? -ne 0 ]; then echo "Build failed" ; exit 1; fi
+    fi
+  done
+fi
+
+echo "Build succeeded"
+exit 0
diff --git a/automated-tests/coverage.sh b/automated-tests/coverage.sh
new file mode 100755 (executable)
index 0000000..96c3740
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+opt_genhtml=true
+if [ $1 == -n ] ; then
+  opt_genhtml=false
+fi
+
+BUILD_DIR_NAME=tizen
+function MakeCovData()
+{
+    (  cd ../build/$BUILD_DIR_NAME ; make cov_data )
+}
+
+MakeCovData
+if [[ $? -ne 0 ]]
+then
+    BUILD_DIR_NAME=tizen-cmake
+    MakeCovData
+fi
+
+# From lcov version 1.10 onwards, branch coverage is off by default and earlier versions do not support the rc option
+LCOV_OPTS=`if [ \`printf "\\\`lcov --version | cut -d' ' -f4\\\`\n1.10\n" | sort -V | head -n 1\` = 1.10 ] ; then echo "--rc lcov_branch_coverage=1" ; fi`
+
+for i in `find . -name "*.dir"` ; do
+    (
+        cd $i
+        echo `pwd`
+        covs=( `ls *.gcda 2>/dev/null` )
+        if [[ $? -eq 0 ]]
+        then
+            lcov $LCOV_OPTS --directory . -c -o dali.info
+            lcov $LCOV_OPTS --remove dali.info "/usr/include/*" "*/automated-tests/*" "*/dali-env/*" -o dali.info
+            if [ ! -s dali.info ]
+            then
+              rm -f dali.info
+            fi
+        fi
+    )
+done
+
+(
+    if [ $opt_genhtml == true ] ; then
+        cd .. ;
+        genhtml $LCOV_OPTS -o build/$BUILD_DIR_NAME/doc/coverage `find . -name dali.info`
+        echo "Coverage output: ../build/$BUILD_DIR_NAME/doc/coverage/index.html"
+    fi
+)
diff --git a/automated-tests/execute.sh b/automated-tests/execute.sh
new file mode 100755 (executable)
index 0000000..7703340
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/bash
+
+TEMP=`getopt -o dhsSmf --long debug,help,failnorerun,serial,tct,modules -n 'execute.sh' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+function usage
+{
+    echo -e "Usage: execute.sh [-d][-s|-S|-r] [module|testcase]"
+    echo -e "       execute.sh\t\tExecute test cases from all modules in parallel"
+    echo -e "       execute.sh -f \tExecute test cases from all modules in parallel without rerunning failed test cases"
+    echo -e "       execute.sh -d <testcase>\tDebug testcase"
+    echo -e "       execute.sh [module]\tExecute test cases from the given module in parallel"
+    echo -e "       execute.sh -s [module]\t\tExecute test cases in serial using Testkit-Lite"
+    echo -e "       execute.sh -S [module]\t\tExecute test cases in serial"
+    echo -e "       execute.sh <testcase>\tFind and execute the given test case"
+    exit 2
+}
+
+opt_tct=0
+opt_serial=""
+opt_modules=0
+opt_debug=0
+opt_noFailedRerun="";
+while true ; do
+    case "$1" in
+        -h|--help)     usage ;;
+        -d|--debug)    opt_debug=1 ; shift ;;
+        -s|--tct)      opt_tct=1 ; shift ;;
+        -f|--nofailedrerun) opt_noFailedRerun="-f" ; shift ;;
+        -S|--serial)   opt_serial="-s" ; shift ;;
+        -m|--modules)  opt_modules=1 ; shift ;;
+        --) shift; break;;
+        *) echo "Internal error $1!" ; exit 1 ;;
+    esac
+done
+
+function execute_tct
+{
+    scripts/tctestsgen.sh $1 `pwd` desktop $2
+    testkit-lite -f `pwd`/tests.xml -o tct-${1}-core-tests.xml  -A --comm localhost
+    scripts/add_style.pl $1
+}
+
+function summary_start
+{
+    start=`date +"%Y-%m-%d_%H_%M_%S"`
+    cat > summary.xml <<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="./style/summary.xsl"?>
+<result_summary plan_name="Core">
+  <other xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" />
+  <summary test_plan_name="Dali">
+    <start_at>$start</start_at>
+    <end_at>$start</end_at>
+  </summary>
+EOF
+}
+
+function summary_end
+{
+    cat >> summary.xml <<EOF
+</result_summary>
+EOF
+}
+
+if [ $opt_modules == 1 ] ; then
+    modules= get_modules
+    echo $modules
+    exit 0
+fi
+
+# Clean up old test results
+rm -f tct*core-tests.xml
+
+# Clean up old coverage data
+[ -d ../build/tizen ] && rm -f ../build/tizen/dali/.libs/*.gcda
+[ -d ../build/tizen-cmake ] && find ../build/tizen-cmake/ -name \*.gcda -exec rm {} \;
+
+find build \( -name "*.gcda" \) -exec rm '{}' \;
+
+ASCII_BOLD="\e[1m"
+ASCII_RESET="\e[0m"
+
+modules=`ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
+if [ -f summary.xml ] ; then unlink summary.xml ; fi
+
+if [ $opt_tct == 1 ] ; then
+    # Use Test-kit lite
+    # Run all test case executables serially, create XML output
+    if [ -n "$1" ] ; then
+        execute_tct $1 $*
+    else
+        for mod in $modules
+        do
+            if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+                echo -ne "$ASCII_BOLD"
+                echo -e "Executing $mod$ASCII_RESET"
+                execute_tct $mod $*
+            fi
+        done
+    fi
+
+    scripts/summarize.pl
+
+else
+    # Execute test cases using own test harness
+
+    if [ -z "$1" ] ; then
+        # No arguments:
+        # Execute each test executable in turn (by default, runs tests in parallel)
+        summary_start
+        for mod in $modules
+        do
+            echo -e "$ASCII_BOLD"
+            echo -e "Executing $mod$ASCII_RESET"
+            build/src/$mod/tct-$mod-core $opt_serial $opt_noFailedRerun
+        done
+        summary_end
+
+    elif [ -f "build/src/$1/tct-$1-core" ] ; then
+        # First argument is an executable filename - execute only that with any
+        # remaining arguments
+        summary_start
+        module=$1
+        shift;
+        build/src/$module/tct-$module-core $opt_serial $opt_noFailedRerun $*
+        summary_end
+
+    else
+        # First argument is not an executable. Is it a test case name?
+        # Try executing each executable with the test case name until success/known failure
+        for mod in $modules
+        do
+            output=`build/src/$mod/tct-$mod-core $1`
+            ret=$?
+            if [ $ret -ne 6 ] ; then
+                if [ $opt_debug -ne 0 ] ; then
+                    echo DEBUGGING:
+                    gdb --args build/src/$mod/tct-$mod-core $1
+
+                else
+                    echo $output
+                    if [ $ret -eq 0 ] ; then echo -e "\nPassed" ; fi
+                fi
+                exit $ret
+            fi
+        done
+        echo $1 not found
+    fi
+fi
+
+if [ -f summary.xml ] ; then
+    scripts/output_summary.pl
+fi
+
+exit $?
diff --git a/automated-tests/packaging/core-dali-toolkit-tests.spec b/automated-tests/packaging/core-dali-toolkit-tests.spec
new file mode 100644 (file)
index 0000000..10fef06
--- /dev/null
@@ -0,0 +1,53 @@
+%define MODULE_NAME dali-toolkit
+%define MODULE_LIBNAME dali-toolkit
+Name:       core-%{MODULE_NAME}-tests
+Summary:    Core API unit TC (%{name})
+Version:    0.1
+Release:    0
+Group:      Development/Tools
+License:    Apache-2.0 and OFL-1.1
+Source0:    %{name}-%{version}.tar.gz
+Requires:       dali
+Requires:       dali-adaptor
+Requires:       dali-toolkit
+BuildRequires:  dali-integration-devel
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali)
+BuildRequires:  pkgconfig(dali-toolkit)
+BuildRequires:  libxml2-devel
+BuildRequires:  cmake
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
+%license LICENSE
diff --git a/automated-tests/patch-coverage.pl b/automated-tests/patch-coverage.pl
new file mode 100755 (executable)
index 0000000..c5d9083
--- /dev/null
@@ -0,0 +1,758 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 2020 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.
+#
+
+use strict;
+use Git;
+use Getopt::Long;
+use Error qw(:try);
+use HTML::Element;
+use Pod::Usage;
+use File::Basename;
+#use Data::Dumper;
+use File::stat;
+use Scalar::Util qw /looks_like_number/;
+use Cwd qw /getcwd/;
+use Term::ANSIColor qw(:constants);
+
+# Program to run gcov on files in patch (that are in source dirs - needs to be dali-aware).
+
+# A) Get patch
+# B) Remove uninteresting files
+# C) Find matching gcno/gcda files
+# D) Copy and rename them to match source prefix (i.e. strip library name off front)
+# E) Generate patch output with covered/uncovered lines marked in green/red
+# F) Generate coverage data for changed lines
+# G) Exit status should be 0 for high coverage (90% line coverage for all new/changed lines)
+#    or 1 for low coverage
+
+# Sources for conversion of gcno/gcda files:
+# ~/bin/lcov
+# Python git-coverage (From http://stef.thewalter.net/git-coverage-useful-code-coverage.html)
+
+our $repo = Git->repository();
+our $debug=0;
+our $pd_debug=0;
+our $opt_cached;
+our $opt_help;
+our $opt_output;
+our $opt_quiet;
+our $opt_verbose;
+
+my %options = (
+    "cached"       => { "optvar"=>\$opt_cached, "desc"=>"Use index" },
+    "output:s"     => { "optvar"=>\$opt_output, "desc"=>"Generate html output"},
+    "help"         => { "optvar"=>\$opt_help, "desc"=>""},
+    "quiet"        => { "optvar"=>\$opt_quiet, "desc"=>""},
+    "verbose"      => { "optvar"=>\$opt_verbose, "desc"=>"" });
+
+my %longOptions = map { $_ => $options{$_}->{"optvar"} } keys(%options);
+GetOptions( %longOptions ) or pod2usage(2);
+pod2usage(1) if $opt_help;
+
+
+## Format per file, repeated, no linebreak
+# <diffcmd>
+# index c1..c2 c3
+# --- a/<left-hand-side-file>
+# +++ b/<right-hand-side-file>
+# <diff hunks>
+
+# Format of each diff hunk, repeated, no linebreak
+# @@ <ranges> @@ line
+# 3 lines of context
+# [-|+]lines removed on left, added on right
+# 3 lines of context
+#
+# output:
+sub parse_diff
+{
+    my $patchref = shift;
+    my $file="";
+    my @checklines=();
+    my %b_lines=();
+    my $state = 0;
+    my $store_line=-1;
+    my %files=();
+
+    print "Patch size: ".scalar(@$patchref)."\n" if $pd_debug;
+    for my $line (@$patchref)
+    {
+        if($state == 0)
+        {
+            print "State: $state  $line  \n" if $pd_debug;
+            # Search for a line matching "+++ b/<filename>"
+            if( $line =~ m!^\+\+\+ b/([\w-_\./]*)!)
+            {
+                $file = $1;
+                $state = 1 ;
+                print "Found File: $file\n" if $pd_debug;
+            }
+        }
+        else #elsif($state == 1)
+        {
+            # If we find a line starting with diff, the previous
+            # file's diffs have finished, store them.
+            if( $line =~ /^diff/)
+            {
+                print "State: $state  $line  \n" if $pd_debug;
+                $state = 0;
+                # if the file had changes, store the new/modified line numbers
+                if( $file && scalar(@checklines))
+                {
+                    $files{$file}->{"patch"} = [@checklines];
+                    $files{$file}->{"b_lines"} = {%b_lines};
+                    @checklines=();
+                    %b_lines=();
+                }
+                print("\n\n") if $pd_debug;
+            }
+            # If we find a line starting with @@, it tells us the line numbers
+            # of the old file and new file for this hunk.
+            elsif( $line =~ /^@@/)
+            {
+                print "State: $state  $line  \n" if $pd_debug;
+
+                # Find the lines in the new file (of the form "+<start>[,<length>])
+                my($start,$space,$length) = ($line =~ /\+([0-9]+)(,| )([0-9]+)?/);
+                if($length || $space eq " ")
+                {
+                    if( $space eq " " )
+                    {
+                        $length=1;
+                    }
+                    push(@checklines, [$start, $length]);
+                    $store_line=$start;
+                }
+                else
+                {
+                    $store_line = -1;
+                }
+                if($pd_debug)
+                {
+                    my $last = scalar(@checklines)-1;
+                    if( $last >= 0 )
+                    {
+                        print "Checkline:" . $checklines[$last]->[0] . ", " . $checklines[$last]->[1] . "\n";
+                    }
+                }
+            }
+            # If we find a line starting with "+", it belongs to the new file's patch
+            elsif( $line =~ /^\+/)
+            {
+               if($store_line >= 0)
+               {
+                   chomp;
+                   $line = substr($line, 1); # Remove leading +
+                   $b_lines{$store_line} = $line;
+                   $store_line++;
+               }
+            }
+        }
+    }
+    # Store the final entry
+    $files{$file}->{"patch"} = [@checklines];
+    $files{$file}->{"b_lines"} = {%b_lines};
+
+    my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit)?/!} (keys(%files));;
+
+    if($pd_debug)
+    {
+        print("Filtered files:\n");
+        foreach my $file (keys(%filter))
+        {
+            print("$file: ");
+            $patchref = $filter{$file}->{"patch"};
+            foreach my $lineblock (@$patchref)
+            {
+                print "$lineblock->[0]($lineblock->[1]) "
+            }
+            print ( "\n");
+        }
+    }
+
+    return {%filter};
+}
+
+sub show_patch_lines
+{
+    my $filesref = shift;
+    print "\nNumber of files: " . scalar(keys(%$filesref)) . "\n";
+    for my $file (keys(%$filesref))
+    {
+        print("$file:");
+        my $clref = $filesref->{$file}->{"patch"};
+        for my $cl (@$clref)
+        {
+            print("($cl->[0],$cl->[1]) ");
+        }
+        print("\n");
+    }
+}
+
+sub get_gcno_file
+{
+    # Assumes test cases have been run, and "make rename_cov_data" has been executed
+
+    my $file = shift;
+    my ($name, $path, $suffix) = fileparse($file, (".c", ".cpp", ".h"));
+    my $gcno_file = $repo->wc_path() . "/build/tizen/.cov/$name.gcno";
+
+    # Note, will translate headers to their source's object, which
+    # may miss execution code in the headers (e.g. inlines are usually
+    # not all used in the implementation, and require getting coverage
+    # from test cases.
+
+    if( -f $gcno_file )
+    {
+        my $gcno_st = stat($gcno_file);
+        my $fq_file = $repo->wc_path() . $file;
+        my $src_st = stat($fq_file);
+        if($gcno_st->ctime < $src_st->mtime)
+        {
+            print "WARNING: GCNO $gcno_file older than SRC $fq_file\n";
+            $gcno_file="";
+        }
+
+    }
+    else
+    {
+        print("WARNING: No equivalent gcno file for $file\n");
+    }
+    return $gcno_file;
+}
+
+our %gcovfiles=();
+sub get_coverage
+{
+    my $file = shift;
+    my $filesref = shift;
+    print("get_coverage($file)\n") if $debug;
+
+    my $gcno_file = get_gcno_file($file);
+    my @gcov_files = ();
+    my $gcovfile;
+    if( $gcno_file )
+    {
+        print "Running gcov on $gcno_file:\n" if $debug;
+        open( my $fh,  "gcov --preserve-paths $gcno_file |") || die "Can't run gcov:$!\n";
+        while( <$fh> )
+        {
+            print $_ if $debug>=3;
+            chomp;
+            if( m!'(.*\.gcov)'$! )
+            {
+                my $coverage_file = $1; # File has / replaced with # and .. replaced with ^
+                my $source_file = $coverage_file;
+                $source_file =~ s!\^!..!g;  # Change ^ to ..
+                $source_file =~ s!\#!/!g;   # change #'s to /s
+                $source_file =~ s!.gcov$!!; # Strip off .gcov suffix
+
+                print "Matching $file against $source_file\n" if $debug >= 3;
+                # Only want the coverage files matching source file:
+                if(index( $source_file, $file ) > 0 )
+                {
+                    $gcovfile = $coverage_file;
+                    # Some header files do not produce an equivalent gcov file so we shouldn't parse them
+                    if(($source_file =~ /\.h$/) && (! -e $gcovfile))
+                    {
+                        print "Omitting Header: $source_file\n" if $debug;
+                        $gcovfile = ""
+                    }
+                    last;
+                }
+            }
+        }
+        close($fh);
+
+        if($gcovfile)
+        {
+            if($gcovfiles{$gcovfile} == undef)
+            {
+                # Only parse a gcov file once
+                $gcovfiles{$gcovfile}->{"seen"}=1;
+
+                print "Getting coverage data from $gcovfile\n" if $debug;
+
+                open( FH, "< $gcovfile" ) || die "Can't open $gcovfile for reading:$!\n";
+                while(<FH>)
+                {
+                    my ($cov, $line, @code ) = split( /:/, $_ );
+                    $cov =~ s/^\s+//; # Strip leading space
+                    $line =~ s/^\s+//;
+                    my $code=join(":", @code);
+                    if($cov =~ /\#/)
+                    {
+                        # There is no coverage data for these executable lines
+                        $gcovfiles{$gcovfile}->{"uncovered"}->{$line}++;
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                    elsif( $cov ne "-" && looks_like_number($cov) && $cov > 0 )
+                    {
+                        $gcovfiles{$gcovfile}->{"covered"}->{$line}=$cov;
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                    else
+                    {
+                        # All other lines are not executable.
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                }
+                close( FH );
+            }
+            $filesref->{$file}->{"coverage"} = $gcovfiles{$gcovfile}; # store hashref
+        }
+        else
+        {
+            # No gcov output - the gcno file produced no coverage of the source/header
+            # Probably means that there is no coverage for the file (with the given
+            # test case - there may be some somewhere, but for the sake of speed, don't
+            # check (yet).
+        }
+    }
+}
+
+# Run the git diff command to get the patch, then check the coverage
+# output for the patch.
+sub run_diff
+{
+    #print "run_diff(" . join(" ", @_) . ")\n";
+    my ($fh, $c) = $repo->command_output_pipe(@_);
+    our @patch=();
+    while(<$fh>)
+    {
+        chomp;
+        push @patch, $_;
+    }
+    $repo->command_close_pipe($fh, $c);
+
+    print "Patch size: " . scalar(@patch) . "\n" if $debug;
+
+    # @patch has slurped diff for all files...
+    my $filesref = parse_diff ( \@patch );
+    show_patch_lines($filesref) if $debug;
+
+    print "Checking coverage:\n" if $debug;
+
+    my $cwd=getcwd();
+    chdir ".cov" || die "Can't find $cwd/.cov:$!\n";
+
+    for my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+        if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+        {
+            get_coverage($file, $filesref);
+        }
+    }
+    chdir $cwd;
+    return $filesref;
+}
+
+sub calc_patch_coverage_percentage
+{
+    my $filesref = shift;
+    my $total_covered_lines = 0;
+    my $total_uncovered_lines = 0;
+
+    foreach my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $covered_lines = 0;
+        my $uncovered_lines = 0;
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+        if( $coverage_ref )
+        {
+            for my $patch (@$patchref)
+            {
+                for(my $i = 0; $i < $patch->[1]; $i++ )
+                {
+                    my $line = $i + $patch->[0];
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $covered_lines++;
+                        $total_covered_lines++;
+                    }
+                    if($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $uncovered_lines++;
+                        $total_uncovered_lines++;
+                    }
+                }
+            }
+            $coverage_ref->{"covered_lines"} = $covered_lines;
+            $coverage_ref->{"uncovered_lines"} = $uncovered_lines;
+            my $total = $covered_lines + $uncovered_lines;
+            my $percent = 0;
+            if($total > 0)
+            {
+                $percent = $covered_lines / $total;
+            }
+            $coverage_ref->{"percent_covered"} = 100 * $percent;
+        }
+    }
+    my $total_exec = $total_covered_lines + $total_uncovered_lines;
+    my $percent = 0;
+    if($total_exec > 0) { $percent = 100 * $total_covered_lines / $total_exec; }
+
+    return [ $total_exec, $percent ];
+}
+
+sub patch_output
+{
+    my $filesref = shift;
+    foreach my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $b_lines_ref = $filesref->{$file}->{"b_lines"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+        print BOLD, "$file  ";
+
+        if($coverage_ref)
+        {
+            if( $coverage_ref->{"covered_lines"} > 0
+                ||
+                $coverage_ref->{"uncovered_lines"} > 0 )
+            {
+                print GREEN, "Covered: " . $coverage_ref->{"covered_lines"}, RED, " Uncovered: " . $coverage_ref->{"uncovered_lines"}, RESET;
+            }
+        }
+        else
+        {
+            if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+            {
+                print RED;
+            }
+            print "No coverage found";
+        }
+        print RESET "\n";
+
+        for my $patch (@$patchref)
+        {
+            my $hunkstr="Hunk: " . $patch->[0];
+            if( $patch->[1] > 1 )
+            {
+                $hunkstr .= " - " . ($patch->[0]+$patch->[1]-1);
+            }
+            print BOLD, "$hunkstr\n",  RESET;
+            for(my $i = 0; $i < $patch->[1]; $i++ )
+            {
+                my $line = $i + $patch->[0];
+                printf "%-6s  ", $line;
+
+                if($coverage_ref)
+                {
+                    my $color;
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $color=GREEN;
+                    }
+                    elsif($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $color=BOLD . RED;
+                    }
+                    else
+                    {
+                        $color=BLACK;
+                    }
+                    my $src=$coverage_ref->{"src"}->{$line};
+                    chomp($src);
+                    print $color, "$src\n", RESET;
+                }
+                else
+                {
+                    # We don't have coverage data, so print it from the patch instead.
+                    my $src = $b_lines_ref->{$line};
+                    print "$src\n";
+                }
+            }
+        }
+    }
+}
+
+
+sub patch_html_output
+{
+    my $filesref = shift;
+
+    my $html = HTML::Element->new('html');
+    my $head = HTML::Element->new('head');
+    my $title = HTML::Element->new('title');
+    $title->push_content("Patch Coverage");
+    $head->push_content($title, "\n");
+    $html->push_content($head, "\n");
+
+    my $body = HTML::Element->new('body');
+    $body->attr('bgcolor', "white");
+
+    foreach my $file (sort(keys(%$filesref)))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $b_lines_ref = $filesref->{$file}->{"b_lines"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+
+        my $header = HTML::Element->new('h2');
+        $header->push_content($file);
+        $body->push_content($header);
+        $body->push_content("\n");
+        if($coverage_ref)
+        {
+            if( $coverage_ref->{"covered_lines"} > 0
+                ||
+                $coverage_ref->{"uncovered_lines"} > 0 )
+            {
+                my $para = HTML::Element->new('p');
+                my $covered = HTML::Element->new('span');
+                $covered->attr('style', "color:green;");
+                $covered->push_content("Covered: " . $coverage_ref->{"covered_lines"} );
+                $para->push_content($covered);
+
+                my $para2 = HTML::Element->new('p');
+                my $uncovered = HTML::Element->new('span');
+                $uncovered->attr('style', "color:red;");
+                $uncovered->push_content("Uncovered: " . $coverage_ref->{"uncovered_lines"} );
+                $para2->push_content($uncovered);
+                $body->push_content($para, $para2);
+            }
+            else
+            {
+                #print "coverage ref exists for $file:\n" . Data::Dumper::Dumper($coverage_ref) . "\n";
+            }
+        }
+        else
+        {
+            my $para = HTML::Element->new('p');
+            my $span = HTML::Element->new('span');
+            if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+            {
+                $span->attr('style', "color:red;");
+            }
+            $span->push_content("No coverage found");
+            $para->push_content($span);
+            $body->push_content($para);
+        }
+
+        for my $patch (@$patchref)
+        {
+            my $hunkstr="Hunk: " . $patch->[0];
+            if( $patch->[1] > 1 )
+            {
+                $hunkstr .= " - " . ($patch->[0]+$patch->[1]-1);
+            }
+
+            my $para = HTML::Element->new('p');
+            my $span = HTML::Element->new('span');
+            $span->attr('style', "font-weight:bold;");
+            $span->push_content($hunkstr);
+            $para->push_content($span);
+            $body->push_content($para);
+
+            my $codeHunk = HTML::Element->new('pre');
+            for(my $i = 0; $i < $patch->[1]; $i++ )
+            {
+                my $line = $i + $patch->[0];
+                my $num_line_digits=log($line)/log(10);
+                for $i (0..(6-$num_line_digits-1))
+                {
+                    $codeHunk->push_content(" ");
+                }
+
+                $codeHunk->push_content("$line  ");
+
+                my $srcLine = HTML::Element->new('span');
+                if($coverage_ref)
+                {
+                    my $color;
+
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $srcLine->attr('style', "color:green;");
+                    }
+                    elsif($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $srcLine->attr('style', "color:red;font-weight:bold;");
+                    }
+                    else
+                    {
+                        $srcLine->attr('style', "color:black;font-weight:normal;");
+                    }
+                    my $src=$coverage_ref->{"src"}->{$line};
+                    chomp($src);
+                    $srcLine->push_content($src);
+                }
+                else
+                {
+                    # We don't have coverage data, so print it from the patch instead.
+                    my $src = $b_lines_ref->{$line};
+                    $srcLine->attr('style', "color:black;font-weight:normal;");
+                    $srcLine->push_content($src);
+                }
+                $codeHunk->push_content($srcLine, "\n");
+            }
+            $body->push_content($codeHunk, "\n");
+        }
+    }
+    $body->push_content(HTML::Element->new('hr'));
+    $html->push_content($body, "\n");
+
+    open( my $filehandle, ">", $opt_output ) || die "Can't open $opt_output for writing:$!\n";
+
+    print $filehandle <<EOH;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+"http://www.w3.org/TR/REC-html40/loose.dtd">
+EOH
+;
+    print $filehandle $html->as_HTML();
+    close $filehandle;
+}
+
+
+################################################################################
+##                                    MAIN                                    ##
+################################################################################
+
+my $cwd = getcwd();
+chdir $repo->wc_path();
+chdir "build/tizen";
+`make rename_cov_data`;
+
+my @cmd=('--no-pager','diff','--no-ext-diff','-U0','--no-color');
+
+my $status = $repo->command("status", "-s");
+if( $status eq "" && !scalar(@ARGV))
+{
+    # There are no changes in the index or working tree, and
+    # no diff arguments to append. Use the last patch instead.
+    push @cmd, ('HEAD~1','HEAD');
+}
+else
+{
+    # detect if there are only cached changes or only working tree changes
+    my $cached = 0;
+    my $working = 0;
+    for my $fstat ( split(/\n/, $status) )
+    {
+        if(substr( $fstat, 0, 1 ) ne " "){ $cached++; }
+        if(substr( $fstat, 1, 1 ) ne " "){ $working++; }
+    }
+    if($cached > 0 )
+    {
+        if($working == 0)
+        {
+            push @cmd, "--cached";
+        }
+        else
+        {
+            die "Both cached & working files - cannot get correct patch from git\n";
+            # Would have to diff from separate clone.
+        }
+    }
+}
+
+push @cmd, @ARGV;
+my $filesref = run_diff(@cmd);
+
+chdir $cwd;
+
+# Check how many actual source files there are in the patch
+my $filecount = 0;
+foreach my $file (keys(%$filesref))
+{
+    my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+    next if($path !~ /^dali/);
+    next if($suffix ne ".cpp" && $suffix ne ".c" && $suffix ne ".h");
+    $filecount++;
+}
+if( $filecount == 0 )
+{
+    print "No source files found\n";
+    exit 0;    # Exit with no error.
+}
+
+my $percentref = calc_patch_coverage_percentage($filesref);
+if($percentref->[0] == 0)
+{
+    print "No coverable lines found\n";
+    exit 0;
+}
+my $percent = $percentref->[1];
+
+my $color=BOLD RED;
+if($opt_output)
+{
+    print "Outputing to $opt_output\n" if $debug;
+    patch_html_output($filesref);
+}
+elsif( ! $opt_quiet )
+{
+    patch_output($filesref);
+    if($percent>=90)
+    {
+        $color=GREEN;
+    }
+    print RESET;
+}
+
+printf("Percentage of change covered: %5.2f%\n", $percent);
+
+exit($percent<90);
+
+
+__END__
+
+=head1 NAME
+
+patch-coverage
+
+=head1 SYNOPSIS
+
+patch-coverage.pl - Determine if patch coverage is below 90%
+
+=head1 DESCRIPTION
+Calculates how well the most recent patch is covered (either the
+patch that is in the index+working directory, or HEAD).
+
+=head1 OPTIONS
+
+=over 28
+
+=item B<-c|--cached>
+Use index files if there is nothing in the working tree
+
+=item B<   --help>
+This help
+
+=item B<-q|--quiet>
+Don't generate any output
+
+=head1 RETURN STATUS
+0 if the coverage of source files is > 90%, otherwise 1
+
+=head1 EXAMPLES
+
+
+=cut
diff --git a/automated-tests/resources/AnimatedCube.bin b/automated-tests/resources/AnimatedCube.bin
new file mode 100644 (file)
index 0000000..72f7d2d
Binary files /dev/null and b/automated-tests/resources/AnimatedCube.bin differ
diff --git a/automated-tests/resources/AnimatedCube.gltf b/automated-tests/resources/AnimatedCube.gltf
new file mode 100644 (file)
index 0000000..2f78e20
--- /dev/null
@@ -0,0 +1,401 @@
+{
+   "accessors" : [
+      {
+         "bufferView" : 0,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 3,
+         "max" : [
+            2.000000
+         ],
+         "min" : [
+            0.000000
+         ],
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 1,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 3,
+         "max" : [
+            0.000000,
+            1.000000,
+            0.000000,
+            1.000000
+         ],
+         "min" : [
+            0.000000,
+            -8.742278e-008,
+            0.000000,
+            -1.000000
+         ],
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 2,
+         "byteOffset" : 0,
+         "componentType" : 5123,
+         "count" : 36,
+         "max" : [
+            35
+         ],
+         "min" : [
+            0
+         ],
+         "type" : "SCALAR"
+      },
+      {
+         "bufferView" : 3,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000001
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 4,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC3"
+      },
+      {
+         "bufferView" : 5,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            -0.000000,
+            -0.000000,
+            1.000000
+         ],
+         "min" : [
+            0.000000,
+            -0.000000,
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC4"
+      },
+      {
+         "bufferView" : 6,
+         "byteOffset" : 0,
+         "componentType" : 5126,
+         "count" : 36,
+         "max" : [
+            1.000000,
+            1.000000
+         ],
+         "min" : [
+            -1.000000,
+            -1.000000
+         ],
+         "type" : "VEC2"
+      }
+   ],
+   "animations" : [
+    {
+       "channels" : [
+          {
+             "sampler" : 0,
+             "target" : {
+                "node" : 0,
+                "path" : "rotation"
+             }
+          }
+       ],
+       "name" : "animation_AnimatedCube",
+       "samplers" : [
+          {
+             "input" : 0,
+             "interpolation" : "LINEAR",
+             "output" : 1
+          }
+       ]
+    }
+   ],
+   "asset" : {
+      "generator" : "VKTS glTF 2.0 exporter",
+      "version" : "2.0"
+   },
+   "bufferViews" : [
+      {
+         "buffer" : 0,
+         "byteLength" : 12,
+         "byteOffset" : 0
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 48,
+         "byteOffset" : 12
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 72,
+         "byteOffset" : 60,
+         "target" : 34963
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 432,
+         "byteOffset" : 132,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 432,
+         "byteOffset" : 564,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 576,
+         "byteOffset" : 996,
+         "target" : 34962
+      },
+      {
+         "buffer" : 0,
+         "byteLength" : 288,
+         "byteOffset" : 1572,
+         "target" : 34962
+      }
+   ],
+   "buffers" : [
+      {
+         "byteLength" : 1860,
+         "uri" : "AnimatedCube.bin"
+      }
+   ],
+   "images" : [
+      {
+         "uri" : "AnimatedCube_BaseColor.png"
+      },
+      {
+         "uri" : "AnimatedCube_MetallicRoughness.png"
+      }
+   ],
+   "materials" : [
+      {
+         "name" : "AnimatedCube",
+         "pbrMetallicRoughness" : {
+            "baseColorTexture" : {
+               "index" : 0
+            },
+            "metallicRoughnessTexture" : {
+               "index" : 1
+            },
+            "baseColorFactor": [ 1.000, 0.766, 0.336, 1.0 ],
+            "metallicFactor": 1.0,
+            "roughnessFactor": 0.0
+         },
+         "normalTexture": {
+          "scale": 1,
+          "index": 0
+         },
+         "occlusionTexture": {
+          "index": 0
+         },
+         "emissiveTexture": {
+          "index": 0
+         },
+         "emissiveFactor": [ 0.2, 0.1, 0.0 ],
+         "doubleSided": false,
+         "alphaMode": "MASK",
+         "alphaCutoff": 0.5
+      },
+      {
+         "name" : "AnimatedCube2",
+         "pbrMetallicRoughness" : {
+            "baseColorTexture" : {
+               "index" : 0
+            },
+            "metallicRoughnessTexture" : {
+               "index" : 1
+            },
+            "baseColorFactor": [ 1.000, 0.766, 0.336, 1.0 ],
+            "metallicFactor": 1.0,
+            "roughnessFactor": 0.0
+         },
+         "normalTexture": {
+          "scale": 1,
+          "index": 0
+         },
+         "occlusionTexture": {
+          "index": 0
+         },
+         "emissiveTexture": {
+          "index": 0
+         },
+         "emissiveFactor": [ 0.2, 0.1, 0.0 ],
+         "doubleSided": false,
+         "alphaMode": "OPAQUE"
+      }
+   ],
+   "meshes" : [
+      {
+         "name" : "AnimatedCube",
+         "primitives" : [
+            {
+               "attributes" : {
+                  "NORMAL" : 4,
+                  "POSITION" : 3,
+                  "TANGENT" : 5,
+                  "TEXCOORD_0" : 6,
+                  "COLOR_0" : 3
+               },
+               "indices" : 2,
+               "material" : 0,
+               "mode" : 4
+            }
+         ]
+      },
+      {
+         "name" : "AnimatedCube2",
+         "primitives" : [
+            {
+               "attributes" : {
+                  "NORMAL" : 4,
+                  "POSITION" : 3,
+                  "TANGENT" : 5,
+                  "TEXCOORD_0" : 6,
+                  "COLOR_0" : 3
+               },
+               "indices" : 2,
+               "material" : 1,
+               "mode" : 4
+            }
+         ]
+      }
+   ],
+   "nodes" : [
+      {
+         "mesh" : 0,
+         "name" : "AnimatedCube",
+         "rotation" : [
+            0.000000,
+            -1.000000,
+            0.000000,
+            0.000000
+         ]
+      },
+      {
+         "mesh" : 1,
+         "name" : "AnimatedCube2"
+      },
+      {
+
+        "camera" : 0,
+        "scale" : [ 0.5, 0.5, 3.0 ]
+      },
+      {
+        "camera" : 1,
+        "translation" : [ 0.5, 0.5, 3.0 ],
+        "children": [
+          4
+        ]
+      },
+      {
+        "camera" : 2,
+        "matrix": [
+            1.0,
+            0.0,
+            0.0,
+            0.0,
+            0.0,
+            0.0,
+            -1.0,
+            0.0,
+            0.0,
+            1.0,
+            0.0,
+            0.0,
+            0.0,
+            0.0,
+            0.0,
+            1.0
+        ]
+      }
+   ],
+   "scene" : 0,
+   "scenes" : [
+      {
+         "nodes" : [
+            0, 1, 2, 3
+         ]
+      }
+   ],
+   "textures" : [
+      {
+         "sampler" : 0,
+         "source" : 0
+      },
+      {
+         "sampler" : 1,
+         "source" : 1
+      }
+   ],
+   "cameras" : [
+    {
+      "type": "perspective",
+      "perspective": {
+        "aspectRatio": 1.0,
+        "yfov": 0.7,
+        "zfar": 100.0,
+        "znear": 0.01
+      }
+    },
+    {
+      "type": "orthographic",
+      "orthographic": {
+        "xmag": 1.0,
+        "ymag": 1.0,
+        "zfar": 100.0,
+        "znear": 0.01
+      }
+    },
+    {
+      "type": "orthographic",
+      "orthographic": {
+        "xmag": 1.0,
+        "ymag": 1.0,
+        "zfar": 100.0,
+        "znear": 0.01
+      }
+    }
+   ],
+   "samplers": [
+    {
+        "magFilter": 9729,
+        "minFilter": 9987,
+        "wrapS": 33071,
+        "wrapT": 10497
+    },
+    {
+        "magFilter": 9728,
+        "minFilter": 9986,
+        "wrapS": 33071,
+        "wrapT": 33648
+    }
+   ]
+}
\ No newline at end of file
diff --git a/automated-tests/resources/AnimatedCube_BaseColor.png b/automated-tests/resources/AnimatedCube_BaseColor.png
new file mode 100644 (file)
index 0000000..5e5cb20
Binary files /dev/null and b/automated-tests/resources/AnimatedCube_BaseColor.png differ
diff --git a/automated-tests/resources/AnimatedCube_MetallicRoughness.png b/automated-tests/resources/AnimatedCube_MetallicRoughness.png
new file mode 100644 (file)
index 0000000..efd2026
Binary files /dev/null and b/automated-tests/resources/AnimatedCube_MetallicRoughness.png differ
diff --git a/automated-tests/resources/Cube-Points-Only.obj b/automated-tests/resources/Cube-Points-Only.obj
new file mode 100644 (file)
index 0000000..b5fd755
--- /dev/null
@@ -0,0 +1,23 @@
+g cube
+
+v  0.0  0.0  0.0
+v  0.0  0.0  1.0
+v  0.0  1.0  0.0
+v  0.0  1.0  1.0
+v  1.0  0.0  0.0
+v  1.0  0.0  1.0
+v  1.0  1.0  0.0
+v  1.0  1.0  1.0
+
+f  1  7  5
+f  1  3  7
+f  1  4  3
+f  1  2  4
+f  3  8  7
+f  3  4  8
+f  5  7  8
+f  5  8  6
+f  1  5  6
+f  1  6  2
+f  2  6  8
+f  2  8  4
diff --git a/automated-tests/resources/Cube.obj b/automated-tests/resources/Cube.obj
new file mode 100644 (file)
index 0000000..e9bc9b4
--- /dev/null
@@ -0,0 +1,42 @@
+# cube.obj
+#
+
+g cube
+
+v  0.0  0.0  0.0
+v  0.0  0.0  1.0
+v  0.0  1.0  0.0
+v  0.0  1.0  1.0
+v  1.0  0.0  0.0
+v  1.0  0.0  1.0
+v  1.0  1.0  0.0
+v  1.0  1.0  1.0
+
+vt  0.0  0.0
+vt  0.3  0.3
+vt  0.0  1.0
+vt  0.3  0.7
+vt  1.0  0.0
+vt  0.7  0.3
+vt  1.0  1.0
+vt  0.7  0.7
+
+vn  0.0  0.0  1.0
+vn  0.0  0.0 -1.0
+vn  0.0  1.0  0.0
+vn  0.0 -1.0  0.0
+vn  1.0  0.0  0.0
+vn -1.0  0.0  0.0
+
+f  1/1/2  7/7/2  5/5/2
+f  1/1/2  3/3/2  7/7/2
+f  1/1/6  4/4/6  3/3/6
+f  1/1/6  2/2/6  4/4/6
+f  3/3/3  8/8/3  7/7/3
+f  3/3/3  4/4/3  8/8/3
+f  5/5/5  7/7/5  8/8/5
+f  5/5/5  8/8/5  6/6/5
+f  1/1/4  5/5/4  6/6/4
+f  1/1/4  6/6/4  2/2/4
+f  2/2/1  6/6/1  8/8/1
+f  2/2/1  8/8/1  4/4/1
diff --git a/automated-tests/resources/TB-gloss.png b/automated-tests/resources/TB-gloss.png
new file mode 100644 (file)
index 0000000..9ed4b6c
Binary files /dev/null and b/automated-tests/resources/TB-gloss.png differ
diff --git a/automated-tests/resources/ToyRobot-Metal-Simple.mtl b/automated-tests/resources/ToyRobot-Metal-Simple.mtl
new file mode 100644 (file)
index 0000000..f699daf
--- /dev/null
@@ -0,0 +1,9 @@
+newmtl lambert3SG
+illum 4
+Kd 0.00 0.00 0.00
+Ka 0.00 0.00 0.00
+Tf 1.00 1.00 1.00
+map_Kd tbcol.png
+Ni 1.00
+Ks 0.00 0.00 0.00
+Ns 3.66
diff --git a/automated-tests/resources/ToyRobot-Metal.mtl b/automated-tests/resources/ToyRobot-Metal.mtl
new file mode 100644 (file)
index 0000000..cab3ae2
--- /dev/null
@@ -0,0 +1,11 @@
+newmtl lambert3SG
+illum 4
+Kd 0.00 0.00 0.00
+Ka 0.00 0.00 0.00
+Tf 1.00 1.00 1.00
+map_Kd tbcol.png
+bump tb-norm.png -bm 0.05
+Ni 1.00
+Ks 0.00 0.00 0.00
+map_Ks TB-gloss.png
+Ns 3.66
diff --git a/automated-tests/resources/anim.gif b/automated-tests/resources/anim.gif
new file mode 100644 (file)
index 0000000..f66f076
Binary files /dev/null and b/automated-tests/resources/anim.gif differ
diff --git a/automated-tests/resources/application-icon-20.png b/automated-tests/resources/application-icon-20.png
new file mode 100644 (file)
index 0000000..aecb4a6
Binary files /dev/null and b/automated-tests/resources/application-icon-20.png differ
diff --git a/automated-tests/resources/application-icon-21.png b/automated-tests/resources/application-icon-21.png
new file mode 100644 (file)
index 0000000..f5b1418
Binary files /dev/null and b/automated-tests/resources/application-icon-21.png differ
diff --git a/automated-tests/resources/application-icon-22.png b/automated-tests/resources/application-icon-22.png
new file mode 100644 (file)
index 0000000..4221262
Binary files /dev/null and b/automated-tests/resources/application-icon-22.png differ
diff --git a/automated-tests/resources/application-icon-23.png b/automated-tests/resources/application-icon-23.png
new file mode 100644 (file)
index 0000000..4e7507b
Binary files /dev/null and b/automated-tests/resources/application-icon-23.png differ
diff --git a/automated-tests/resources/application-icon-24.png b/automated-tests/resources/application-icon-24.png
new file mode 100644 (file)
index 0000000..680257c
Binary files /dev/null and b/automated-tests/resources/application-icon-24.png differ
diff --git a/automated-tests/resources/application-icon-25.png b/automated-tests/resources/application-icon-25.png
new file mode 100644 (file)
index 0000000..a404573
Binary files /dev/null and b/automated-tests/resources/application-icon-25.png differ
diff --git a/automated-tests/resources/application-icon-26.png b/automated-tests/resources/application-icon-26.png
new file mode 100644 (file)
index 0000000..10138e5
Binary files /dev/null and b/automated-tests/resources/application-icon-26.png differ
diff --git a/automated-tests/resources/application-icon-27.png b/automated-tests/resources/application-icon-27.png
new file mode 100644 (file)
index 0000000..5dbb3b3
Binary files /dev/null and b/automated-tests/resources/application-icon-27.png differ
diff --git a/automated-tests/resources/application-icon-28.png b/automated-tests/resources/application-icon-28.png
new file mode 100644 (file)
index 0000000..1d71a31
Binary files /dev/null and b/automated-tests/resources/application-icon-28.png differ
diff --git a/automated-tests/resources/application-icon-29.png b/automated-tests/resources/application-icon-29.png
new file mode 100644 (file)
index 0000000..040c36b
Binary files /dev/null and b/automated-tests/resources/application-icon-29.png differ
diff --git a/automated-tests/resources/application-icon-30.png b/automated-tests/resources/application-icon-30.png
new file mode 100644 (file)
index 0000000..445590d
Binary files /dev/null and b/automated-tests/resources/application-icon-30.png differ
diff --git a/automated-tests/resources/broken.png b/automated-tests/resources/broken.png
new file mode 100644 (file)
index 0000000..2d1c272
Binary files /dev/null and b/automated-tests/resources/broken.png differ
diff --git a/automated-tests/resources/button-up.9.png b/automated-tests/resources/button-up.9.png
new file mode 100644 (file)
index 0000000..a2e2e01
Binary files /dev/null and b/automated-tests/resources/button-up.9.png differ
diff --git a/automated-tests/resources/demo-tile-texture-focused.9.png b/automated-tests/resources/demo-tile-texture-focused.9.png
new file mode 100644 (file)
index 0000000..3236edd
Binary files /dev/null and b/automated-tests/resources/demo-tile-texture-focused.9.png differ
diff --git a/automated-tests/resources/empty.bmp b/automated-tests/resources/empty.bmp
new file mode 100644 (file)
index 0000000..29df0c2
Binary files /dev/null and b/automated-tests/resources/empty.bmp differ
diff --git a/automated-tests/resources/folder_appicon_empty_bg.png b/automated-tests/resources/folder_appicon_empty_bg.png
new file mode 100644 (file)
index 0000000..32a47a5
Binary files /dev/null and b/automated-tests/resources/folder_appicon_empty_bg.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0030.png b/automated-tests/resources/fonts/bitmap/u0030.png
new file mode 100644 (file)
index 0000000..1b0cc3c
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0030.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0031.png b/automated-tests/resources/fonts/bitmap/u0031.png
new file mode 100644 (file)
index 0000000..2c70e9c
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0031.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0032.png b/automated-tests/resources/fonts/bitmap/u0032.png
new file mode 100644 (file)
index 0000000..2ed2d75
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0032.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0033.png b/automated-tests/resources/fonts/bitmap/u0033.png
new file mode 100644 (file)
index 0000000..2cb1673
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0033.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0034.png b/automated-tests/resources/fonts/bitmap/u0034.png
new file mode 100644 (file)
index 0000000..99d72e1
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0034.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0035.png b/automated-tests/resources/fonts/bitmap/u0035.png
new file mode 100644 (file)
index 0000000..2780eae
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0035.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0036.png b/automated-tests/resources/fonts/bitmap/u0036.png
new file mode 100644 (file)
index 0000000..62e240f
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0036.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0037.png b/automated-tests/resources/fonts/bitmap/u0037.png
new file mode 100644 (file)
index 0000000..ae3790a
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0037.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0038.png b/automated-tests/resources/fonts/bitmap/u0038.png
new file mode 100644 (file)
index 0000000..e2b0d13
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0038.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u0039.png b/automated-tests/resources/fonts/bitmap/u0039.png
new file mode 100644 (file)
index 0000000..2a3f481
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u0039.png differ
diff --git a/automated-tests/resources/fonts/bitmap/u003a.png b/automated-tests/resources/fonts/bitmap/u003a.png
new file mode 100644 (file)
index 0000000..a6ca724
Binary files /dev/null and b/automated-tests/resources/fonts/bitmap/u003a.png differ
diff --git a/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf b/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf
new file mode 100644 (file)
index 0000000..5267218
Binary files /dev/null and b/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf differ
diff --git a/automated-tests/resources/fonts/dejavu/DejaVuSerif-Bold.ttf b/automated-tests/resources/fonts/dejavu/DejaVuSerif-Bold.ttf
new file mode 100644 (file)
index 0000000..d683eb2
Binary files /dev/null and b/automated-tests/resources/fonts/dejavu/DejaVuSerif-Bold.ttf differ
diff --git a/automated-tests/resources/fonts/dejavu/DejaVuSerif-Italic.ttf b/automated-tests/resources/fonts/dejavu/DejaVuSerif-Italic.ttf
new file mode 100644 (file)
index 0000000..45b508b
Binary files /dev/null and b/automated-tests/resources/fonts/dejavu/DejaVuSerif-Italic.ttf differ
diff --git a/automated-tests/resources/fonts/dejavu/DejaVuSerif.ttf b/automated-tests/resources/fonts/dejavu/DejaVuSerif.ttf
new file mode 100644 (file)
index 0000000..39dd394
Binary files /dev/null and b/automated-tests/resources/fonts/dejavu/DejaVuSerif.ttf differ
diff --git a/automated-tests/resources/fonts/dejavu/LICENSE b/automated-tests/resources/fonts/dejavu/LICENSE
new file mode 100644 (file)
index 0000000..254e2cc
--- /dev/null
@@ -0,0 +1,99 @@
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot
+org. 
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the 
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
+$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
diff --git a/automated-tests/resources/fonts/noto/LICENSE_OFL.txt b/automated-tests/resources/fonts/noto/LICENSE_OFL.txt
new file mode 100644 (file)
index 0000000..d952d62
--- /dev/null
@@ -0,0 +1,92 @@
+This Font Software is licensed under the SIL Open Font License,
+Version 1.1.
+
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font
+creation efforts of academic and linguistic communities, and to
+provide a free and open framework in which fonts may be shared and
+improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply to
+any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software
+components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to,
+deleting, or substituting -- in part or in whole -- any of the
+components of the Original Version, by changing formats or by porting
+the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed,
+modify, redistribute, and sell modified and unmodified copies of the
+Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in
+Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the
+corresponding Copyright Holder. This restriction only applies to the
+primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created using
+the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/automated-tests/resources/fonts/noto/NotoSansMalayalam-Regular.ttf b/automated-tests/resources/fonts/noto/NotoSansMalayalam-Regular.ttf
new file mode 100644 (file)
index 0000000..be82967
Binary files /dev/null and b/automated-tests/resources/fonts/noto/NotoSansMalayalam-Regular.ttf differ
diff --git a/automated-tests/resources/fonts/roboto/LICENSE b/automated-tests/resources/fonts/roboto/LICENSE
new file mode 100644 (file)
index 0000000..261eeb9
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/automated-tests/resources/fonts/roboto/Roboto-Bold.ttf b/automated-tests/resources/fonts/roboto/Roboto-Bold.ttf
new file mode 100644 (file)
index 0000000..8869666
Binary files /dev/null and b/automated-tests/resources/fonts/roboto/Roboto-Bold.ttf differ
diff --git a/automated-tests/resources/fonts/roboto/Roboto-BoldItalic.ttf b/automated-tests/resources/fonts/roboto/Roboto-BoldItalic.ttf
new file mode 100644 (file)
index 0000000..f7f845a
Binary files /dev/null and b/automated-tests/resources/fonts/roboto/Roboto-BoldItalic.ttf differ
diff --git a/automated-tests/resources/fonts/roboto/Roboto-Italic.ttf b/automated-tests/resources/fonts/roboto/Roboto-Italic.ttf
new file mode 100644 (file)
index 0000000..a76d286
Binary files /dev/null and b/automated-tests/resources/fonts/roboto/Roboto-Italic.ttf differ
diff --git a/automated-tests/resources/fonts/roboto/Roboto-Regular.ttf b/automated-tests/resources/fonts/roboto/Roboto-Regular.ttf
new file mode 100644 (file)
index 0000000..ddee473
Binary files /dev/null and b/automated-tests/resources/fonts/roboto/Roboto-Regular.ttf differ
diff --git a/automated-tests/resources/fonts/tizen/BreezeColorEmoji.ttf b/automated-tests/resources/fonts/tizen/BreezeColorEmoji.ttf
new file mode 100644 (file)
index 0000000..2a6b046
Binary files /dev/null and b/automated-tests/resources/fonts/tizen/BreezeColorEmoji.ttf differ
diff --git a/automated-tests/resources/fonts/tizen/TizenSansArabicRegular.ttf b/automated-tests/resources/fonts/tizen/TizenSansArabicRegular.ttf
new file mode 100644 (file)
index 0000000..55fc232
Binary files /dev/null and b/automated-tests/resources/fonts/tizen/TizenSansArabicRegular.ttf differ
diff --git a/automated-tests/resources/fonts/tizen/TizenSansHebrewRegular.ttf b/automated-tests/resources/fonts/tizen/TizenSansHebrewRegular.ttf
new file mode 100644 (file)
index 0000000..b9a25d7
Binary files /dev/null and b/automated-tests/resources/fonts/tizen/TizenSansHebrewRegular.ttf differ
diff --git a/automated-tests/resources/fonts/tizen/TizenSansHindiRegular.ttf b/automated-tests/resources/fonts/tizen/TizenSansHindiRegular.ttf
new file mode 100644 (file)
index 0000000..d451f59
Binary files /dev/null and b/automated-tests/resources/fonts/tizen/TizenSansHindiRegular.ttf differ
diff --git a/automated-tests/resources/fonts/tizen/TizenSansRegular.ttf b/automated-tests/resources/fonts/tizen/TizenSansRegular.ttf
new file mode 100644 (file)
index 0000000..00863b6
Binary files /dev/null and b/automated-tests/resources/fonts/tizen/TizenSansRegular.ttf differ
diff --git a/automated-tests/resources/forest_diffuse_cubemap.png b/automated-tests/resources/forest_diffuse_cubemap.png
new file mode 100644 (file)
index 0000000..ff3e237
Binary files /dev/null and b/automated-tests/resources/forest_diffuse_cubemap.png differ
diff --git a/automated-tests/resources/forest_specular_cubemap.png b/automated-tests/resources/forest_specular_cubemap.png
new file mode 100644 (file)
index 0000000..d5cb909
Binary files /dev/null and b/automated-tests/resources/forest_specular_cubemap.png differ
diff --git a/automated-tests/resources/gallery-small-1.jpg b/automated-tests/resources/gallery-small-1.jpg
new file mode 100644 (file)
index 0000000..9292310
Binary files /dev/null and b/automated-tests/resources/gallery-small-1.jpg differ
diff --git a/automated-tests/resources/heartsframe.9.png b/automated-tests/resources/heartsframe.9.png
new file mode 100644 (file)
index 0000000..9313d47
Binary files /dev/null and b/automated-tests/resources/heartsframe.9.png differ
diff --git a/automated-tests/resources/icon-delete.png b/automated-tests/resources/icon-delete.png
new file mode 100644 (file)
index 0000000..f509cc0
Binary files /dev/null and b/automated-tests/resources/icon-delete.png differ
diff --git a/automated-tests/resources/icon-edit.png b/automated-tests/resources/icon-edit.png
new file mode 100644 (file)
index 0000000..ce3e327
Binary files /dev/null and b/automated-tests/resources/icon-edit.png differ
diff --git a/automated-tests/resources/insta_camera.json b/automated-tests/resources/insta_camera.json
new file mode 100644 (file)
index 0000000..945c3b2
--- /dev/null
@@ -0,0 +1 @@
+{"v":"5.0.1","fr":30.0000305175781,"ip":0,"op":124.000126139323,"w":800,"h":600,"nm":"Camera_003_render","ddd":0,"assets":[{"id":"comp_4","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"flash ring","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133,-67,0],"ix":2},"a":{"a":0,"k":[74,-135,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.09,0.09],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p09_1_0p167_0p167","0p09_1_0p167_0p167"],"t":73,"s":[0,0],"e":[148,148]},{"t":79.0000803629557}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0.09],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p09_1_0p167_0p167"],"t":73,"s":[23],"e":[0]},{"t":82.0000834147135}],"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[74,-135],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":73.0000742594401,"op":83.0000844319661,"st":73.0000742594401,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"button lines","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-35.5,-60.5,0],"ix":2},"a":{"a":0,"k":[72.5,-149.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[91,-152.25],[108,-160.75]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 5","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[60.25,-161.75],[49,-177.25]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[4.25,2.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 6","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[73.75,-162.5],[80.75,-179]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[4.25,2.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 4","np":3,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[53,-150.5],[34.25,-159.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.08],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p08_1_0p167_0p167"],"t":73.539,"s":[0],"e":[100]},{"t":80.0000813802083}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.08],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"n":["0p08_1_0p167_0p167"],"t":71,"s":[0],"e":[100]},{"t":80.0000813802083}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":5,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":71.0000722249349,"op":81.0000823974609,"st":71.0000722249349,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"flash light","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":71,"s":[35.264],"e":[102.264]},{"t":80.0000813802083}],"ix":10},"p":{"a":0,"k":[132,-68,0],"ix":2},"a":{"a":0,"k":[-340,-162,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"sr","sy":1,"d":1,"pt":{"a":0,"k":4,"ix":3},"p":{"a":0,"k":[0,0],"ix":4},"r":{"a":0,"k":143.286,"ix":5},"ir":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":71,"s":[0],"e":[25]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":76,"s":[25],"e":[0]},{"t":80.0000813802083}],"ix":6},"is":{"a":0,"k":193,"ix":8},"or":{"a":0,"k":73.6,"ix":7},"os":{"a":0,"k":0,"ix":9},"ix":1,"nm":"Polystar Path 1","mn":"ADBE Vector Shape - Star","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.992156862745,1,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-340,-162],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":71.0000722249349,"op":81.0000823974609,"st":71.0000722249349,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"face button mask","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-27,"s":[-2,-6.5,0],"e":[-2,-6.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":56,"s":[-2,-6.5,0],"h":1},{"t":66.0000671386719,"s":[-2,-6.5,0],"h":1}],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p14_1_0p167_0p167","0p14_1_0p167_0p167"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":17,"s":[216,302],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":101,"s":[216,302],"e":[0,302]},{"t":110.000111897786}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.204152006261,0.019608000213,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"face button","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":89.999,"ix":10},"p":{"a":0,"k":[34.724,96.498,0],"ix":2},"a":{"a":0,"k":[3,4,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.35,0.35],"y":[1,1]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p35_1_0p54_0","0p35_1_0p54_0"],"t":28,"s":[0,0],"e":[32,32]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0"],"t":48,"s":[32,32],"e":[32,32]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.53,0.53],"y":[0,0]},"n":["0p833_0p833_0p53_0","0p833_0p833_0p53_0"],"t":97,"s":[32,32],"e":[105,105]},{"t":135.000137329102}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":28.0000284830729,"op":124.000126139323,"st":28.0000284830729,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"line mask","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":0,"k":[-2,-6.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p14_1_0p54_0","0p14_1_0p54_0"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"t":17.0000172932943}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929412004059,0.929412004059,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"line","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90.084,"ix":10},"p":{"a":0,"k":[68.999,-5.896,0],"ix":2},"a":{"a":0,"k":[0.5,-56,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-171.5,-56],[165.5,-56]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.59],"y":[1]},"o":{"x":[0.29],"y":[0]},"n":["0p59_1_0p29_0"],"t":16,"s":[50],"e":[0]},{"t":33.0000335693359}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.59],"y":[1]},"o":{"x":[0.29],"y":[0]},"n":["0p59_1_0p29_0"],"t":16,"s":[50],"e":[100]},{"t":33.0000335693359}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929412004059,0.929412004059,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":16.0000162760417,"op":124.000126139323,"st":16.0000162760417,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"flash mask","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":0,"k":[-2,-6.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p14_1_0p54_0","0p14_1_0p54_0"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"t":17.0000172932943}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929412004059,0.929412004059,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"button","parent":20,"tt":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90.004,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":29,"s":[70.511],"e":[102.512]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[102.512],"e":[102.512]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":71,"s":[102.512],"e":[92.512]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":74,"s":[92.512],"e":[102.512]},{"i":{"x":[0.823],"y":[1]},"o":{"x":[0.167],"y":[0]},"n":["0p823_1_0p167_0"],"t":77,"s":[102.512],"e":[102.512]},{"i":{"x":[0.745],"y":[1]},"o":{"x":[1],"y":[-0.47]},"n":["0p745_1_1_-0p47"],"t":93,"s":[102.512],"e":[72.512]},{"t":105.000106811523}],"ix":3,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('X Position - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('X Position - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('X Position - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":29,"s":[-176.891],"e":[-176.421]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[-176.421],"e":[-176.421]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":71,"s":[-176.421],"e":[-176.421]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":74,"s":[-176.421],"e":[-176.421]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":77,"s":[-176.421],"e":[-176.421]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":93,"s":[-176.421],"e":[-176.421]},{"t":105.000106811523}],"ix":4}},"a":{"a":0,"k":[94,-107.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"X Position - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"X Position - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"X Position - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[26,86],"ix":2},"p":{"a":0,"k":[74,24],"ix":3},"r":{"a":0,"k":24,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[94,-107.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29.0000295003255,"op":106.000107828776,"st":29.0000295003255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"body mask","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":0,"k":[-2,-6.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p14_1_0p54_0","0p14_1_0p54_0"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"t":17.0000172932943}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929412004059,0.929412004059,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"flash","parent":20,"tt":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90.004,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":27,"s":[71.498],"e":[129.499]},{"i":{"x":[0.885],"y":[1]},"o":{"x":[0.167],"y":[0]},"n":["0p885_1_0p167_0"],"t":39,"s":[129.499],"e":[129.499]},{"i":{"x":[0.683],"y":[1]},"o":{"x":[0.688],"y":[-0.339]},"n":["0p683_1_0p688_-0p339"],"t":99,"s":[129.499],"e":[69.499]},{"t":110.000111897786}],"ix":3,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('X Position - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('X Position - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('X Position - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.59],"y":[0]},"n":["0p833_0p833_0p59_0"],"t":27,"s":[-6.965],"e":[-6.42]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":39,"s":[-6.42],"e":[-6.42]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":99,"s":[-6.42],"e":[-6.42]},{"t":110.000111897786}],"ix":4,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Y Position - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Y Position - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Y Position - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"}},"a":{"a":0,"k":[94,-107.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Y Position - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Y Position - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Y Position - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"X Position - Overshoot","np":3,"mn":"ADBE Slider Control","ix":4,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"X Position - Bounce","np":3,"mn":"ADBE Slider Control","ix":5,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"X Position - Friction","np":3,"mn":"ADBE Slider Control","ix":6,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[79,72.861],"ix":2},"p":{"a":0,"k":[72,22],"ix":3},"r":{"a":0,"k":9,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[94,-107.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":27.0000274658203,"op":107.000108846029,"st":27.0000274658203,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"lens mask 2","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-27,"s":[-2,-6.5,0],"e":[-2,-6.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":56,"s":[-2,-6.5,0],"h":1},{"t":66.0000671386719,"s":[-2,-6.5,0],"h":1}],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p14_1_0p167_0p167","0p14_1_0p167_0p167"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":17,"s":[216,302],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":101,"s":[216,302],"e":[0,302]},{"t":110.000111897786}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.204152006261,0.019608000213,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"lens","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-22,-28.5,0],"ix":2},"a":{"a":0,"k":[3,4,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Size - Ellipse Path 1 - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Size - Ellipse Path 1 - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Size - Ellipse Path 1 - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p833_0p833_0p54_0","0p833_0p833_0p54_0"],"t":21,"s":[0,0],"e":[94,94]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0"],"t":41,"s":[94,94],"e":[94,94]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.87,0.87],"y":[0,0]},"n":["0p833_0p833_0p87_0","0p833_0p833_0p87_0"],"t":97,"s":[94,94],"e":[183,183]},{"t":123.00012512207}],"ix":2,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Size - Ellipse Path 1 - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Size - Ellipse Path 1 - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Size - Ellipse Path 1 - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":21.0000213623047,"op":124.000126139323,"st":21.0000213623047,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"lens mask","parent":19,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-27,"s":[-2,-6.5,0],"e":[-2,-6.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":56,"s":[-2,-6.5,0],"h":1},{"t":66.0000671386719,"s":[-2,-6.5,0],"h":1}],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p14_1_0p167_0p167","0p14_1_0p167_0p167"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":17,"s":[216,302],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":101,"s":[216,302],"e":[0,302]},{"t":110.000111897786}],"ix":2,"x":"var $bm_rt;\n$bm_rt = thisComp.layer('body').content('Rectangle 1').content('Rectangle Path 1').size;"},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.204152006261,0.019608000213,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"lens","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-22,-28.5,0],"ix":2},"a":{"a":0,"k":[3,4,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Size - Ellipse Path 1 - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Size - Ellipse Path 1 - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Size - Ellipse Path 1 - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.54,0.54],"y":[0,0]},"n":["0p833_0p833_0p54_0","0p833_0p833_0p54_0"],"t":15,"s":[0,0],"e":[136,136]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0"],"t":35,"s":[136,136],"e":[136,136]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.87,0.87],"y":[0,0]},"n":["0p833_0p833_0p87_0","0p833_0p833_0p87_0"],"t":97,"s":[136,136],"e":[212,212]},{"t":123.00012512207}],"ix":2,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Size - Ellipse Path 1 - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Size - Ellipse Path 1 - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Size - Ellipse Path 1 - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":15.0000152587891,"op":124.000126139323,"st":15.0000152587891,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".gannon-gram","cl":"gannon-gram","parent":20,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90.004,"ix":10},"p":{"a":0,"k":[85.672,-6.451,0],"ix":2},"a":{"a":0,"k":[-0.257,-6.362,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-4.887],[-4.517,0],[-1.575,1.76],[0,0],[0,0],[0,0],[0,0],[0,0],[1.413,0],[0,2.919],[-2.803,0],[-0.718,-1.089],[0,0],[3.196,0]],"o":[[0,4.864],[2.803,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.672,0.602],[-2.803,0],[0,-2.919],[1.621,0],[0,0],[-1.181,-1.83],[-4.517,0]],"v":[[-101.849,-7.713],[-93.626,0.301],[-87.048,-2.617],[-87.048,-8.524],[-94.414,-8.524],[-94.414,-5.698],[-90.291,-5.698],[-90.291,-3.822],[-93.626,-2.641],[-98.467,-7.713],[-93.626,-12.786],[-89.966,-10.84],[-87.233,-12.323],[-93.626,-15.704]],"c":true},"ix":2},"nm":"G","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"G","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-69.614,0],[-66.024,0],[-71.976,-15.45],[-76.099,-15.45],[-82.075,0],[-78.462,0],[-77.489,-2.664],[-70.587,-2.664]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-74.038,-12.601],[-71.49,-5.513],[-76.609,-5.513]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"A","np":5,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-49.766,0],[-46.593,0],[-46.593,-15.45],[-49.882,-15.45],[-49.882,-5.443],[-57.039,-15.45],[-60.421,-15.45],[-60.421,0],[-57.132,0],[-57.132,-10.377]],"c":true},"ix":2},"nm":"N","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"N","np":3,"cix":2,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-28.721,0],[-25.548,0],[-25.548,-15.45],[-28.837,-15.45],[-28.837,-5.443],[-35.995,-15.45],[-39.376,-15.45],[-39.376,0],[-36.087,0],[-36.087,-10.377]],"c":true},"ix":2},"nm":"N","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"N","np":3,"cix":2,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-4.656],[-4.656,0],[0,4.656],[4.679,0]],"o":[[0,4.656],[4.679,0],[0,-4.656],[-4.656,0]],"v":[[-19.073,-7.713],[-11.012,0.278],[-2.928,-7.713],[-11.012,-15.704]],"c":true},"ix":2},"nm":"O","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-2.895],[2.849,0],[0,2.872],[-2.849,0]],"o":[[0,2.872],[-2.849,0],[0,-2.895],[2.849,0]],"v":[[-6.31,-7.713],[-11.012,-2.641],[-15.691,-7.713],[-11.012,-12.786]],"c":true},"ix":2},"nm":"O","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"O","np":5,"cix":2,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[14.196,0],[17.37,0],[17.37,-15.45],[14.081,-15.45],[14.081,-5.443],[6.923,-15.45],[3.541,-15.45],[3.541,0],[6.831,0],[6.831,-10.377]],"c":true},"ix":2},"nm":"N","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"N","np":3,"cix":2,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-4.887],[-4.517,0],[-1.575,1.76],[0,0],[0,0],[0,0],[0,0],[0,0],[1.413,0],[0,2.919],[-2.803,0],[-0.718,-1.089],[0,0],[3.196,0]],"o":[[0,4.864],[2.803,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.672,0.602],[-2.803,0],[0,-2.919],[1.621,0],[0,0],[-1.181,-1.83],[-4.517,0]],"v":[[23.845,-7.713],[32.068,0.301],[38.646,-2.617],[38.646,-8.524],[31.28,-8.524],[31.28,-5.698],[35.403,-5.698],[35.403,-3.822],[32.068,-2.641],[27.227,-7.713],[32.068,-12.786],[35.727,-10.84],[38.461,-12.323],[32.068,-15.704]],"c":true},"ix":2},"nm":"G","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"G","np":3,"cix":2,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,2.733],[3.22,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[1.668,-0.394],[0,-2.872],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[54.156,0],[57.932,0],[54.457,-5.883],[57.839,-10.47],[52.651,-15.45],[45.424,-15.45],[45.424,0],[48.713,0],[48.713,-5.536],[51.122,-5.536]],"c":true},"ix":2},"nm":"R","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-1.297],[1.32,0],[0,0],[0,0],[0,0]],"o":[[0,1.297],[0,0],[0,0],[0,0],[1.32,0]],"v":[[54.48,-10.493],[52.164,-8.362],[48.713,-8.362],[48.713,-12.624],[52.164,-12.624]],"c":true},"ix":2},"nm":"R","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"R","np":5,"cix":2,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[75.308,0],[78.898,0],[72.945,-15.45],[68.822,-15.45],[62.846,0],[66.459,0],[67.432,-2.664],[74.335,-2.664]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.884,-12.601],[73.431,-5.513],[68.312,-5.513]],"c":true},"ix":2},"nm":"A","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"A","np":5,"cix":2,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[97.935,0],[101.247,0],[101.247,-15.45],[96.615,-15.45],[92.862,-5.814],[89.11,-15.45],[84.5,-15.45],[84.5,0],[87.79,0],[87.79,-11.118],[92.144,0],[93.58,0],[97.935,-11.118]],"c":true},"ix":2},"nm":"M","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.988235294118,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"M","np":3,"cix":2,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":16.0000162760417,"op":110.000111897786,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":3,"nm":".chris-gannon-lottie-animation","cl":"chris-gannon-lottie-animation","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.45],"y":[1]},"o":{"x":[0.55],"y":[0]},"n":["0p45_1_0p55_0"],"t":72,"s":[0],"e":[-2]},{"i":{"x":[0.45],"y":[1]},"o":{"x":[0.55],"y":[0]},"n":["0p45_1_0p55_0"],"t":74,"s":[-2],"e":[0]},{"t":84.0000854492187}],"ix":10},"p":{"a":0,"k":[518,386,0],"ix":2},"a":{"a":0,"k":[178,146,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"body","parent":19,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.45],"y":[0]},"n":["0p833_0p833_0p45_0"],"t":0,"s":[0],"e":[-90]},{"t":17.0000172932943}],"ix":10,"x":"var $bm_rt;\nvar amp, freq, decay, n, t;\ntry {\n    amp = div(effect('Rotation - Overshoot')('ADBE Slider Control-0001'), 2.5), freq = div(effect('Rotation - Bounce')('ADBE Slider Control-0001'), 20), decay = div(effect('Rotation - Friction')('ADBE Slider Control-0001'), 20), n = 0, 0 < numKeys && (n = nearestKey(time).index, key(n).time > time && n--), t = 0 === n ? 0 : time - key(n).time, $bm_rt = 0 < n ? (v = velocityAtTime(sub(key(n).time, div(thisComp.frameDuration, 10))), sum(value, div(mul(mul(div(v, 100), amp), Math.sin(mul(mul(mul(freq, t), 2), Math.PI))), Math.exp(mul(decay, t))))) : value;\n} catch (e$$4) {\n    $bm_rt = value = value;\n}"},"p":{"a":0,"k":[60,60,0],"ix":2},"a":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":-27,"s":[-2,-6.5,0],"e":[-2,-6.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":56,"s":[-2,-6.5,0],"h":1},{"t":66.0000671386719,"s":[-2,-6.5,0],"h":1}],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Rotation - Overshoot","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":10,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Bounce","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":30,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]},{"ty":5,"nm":"Rotation - Friction","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":126,"ix":1,"x":"var $bm_rt;\n$bm_rt = clamp(value, 0, 100);"}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.14,0.14],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"n":["0p14_1_0p167_0p167","0p14_1_0p167_0p167"],"t":-27,"s":[0,0],"e":[200,1]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.45,0.45],"y":[0,0]},"n":["0p833_0p833_0p45_0","0p833_0p833_0p45_0"],"t":0,"s":[200,1],"e":[216,302]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"n":["0p833_1_0p167_0","0p833_1_0p167_0"],"t":17,"s":[216,302],"e":[216,302]},{"i":{"x":[0.197,0.45],"y":[1,1]},"o":{"x":[0.872,0.59],"y":[-0.522,0]},"n":["0p197_1_0p872_-0p522","0p45_1_0p59_0"],"t":97,"s":[216,302],"e":[0,200]},{"t":123.00012512207}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.992156982422,1,0.988234994926,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-2,-6.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":-27.0000274658203,"bm":0}]}],"layers":[{"ddd":0,"ind":3,"ty":0,"nm":".chris-gannon-instagram-lottie","cl":"chris-gannon-instagram-lottie","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,323,0],"ix":2},"a":{"a":0,"k":[400,300,0],"ix":1},"s":{"a":0,"k":[129,129,100],"ix":6}},"ao":0,"w":800,"h":600,"ip":0,"op":124.000126139323,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"blueToPurple","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,300,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[800,600],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"g":{"p":5,"k":{"a":0,"k":[0.007,0.298,0.404,0.851,0.307,0.431,0.308,0.735,0.6,0.565,0.212,0.62,0.8,0.565,0.212,0.62,1,0.565,0.212,0.62,0,1,0.199,1,0.397,1,0.592,0.5,0.788,0],"ix":9}},"s":{"a":0,"k":[-258,-522],"ix":5},"e":{"a":0,"k":[-943,-866],"ix":6},"t":2,"h":{"a":0,"k":18.494,"ix":7},"a":{"a":0,"k":-100.276,"ix":8},"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"yellowToOrange","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,300,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[800,600],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"g":{"p":7,"k":{"a":0,"k":[0.007,0.984,0.847,0.482,0.193,0.969,0.657,0.325,0.375,0.953,0.467,0.169,0.545,0.882,0.263,0.314,0.715,0.812,0.059,0.459,0.857,0.688,0.135,0.539,1,0.565,0.212,0.62,0,1,0.259,1,0.517,1,0.75,0.5,0.983,0],"ix":9}},"s":{"a":0,"k":[-140,330],"ix":5},"e":{"a":0,"k":[-637,989],"ix":6},"t":2,"h":{"a":0,"k":0,"ix":7},"a":{"a":0,"k":0,"ix":8},"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,300,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[800,600],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.811764705882,0.058823529412,0.458823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":124.000126139323,"st":0,"bm":0}]}
\ No newline at end of file
diff --git a/automated-tests/resources/keyboard-Landscape.jpg b/automated-tests/resources/keyboard-Landscape.jpg
new file mode 100644 (file)
index 0000000..5bc6f39
Binary files /dev/null and b/automated-tests/resources/keyboard-Landscape.jpg differ
diff --git a/automated-tests/resources/mask.png b/automated-tests/resources/mask.png
new file mode 100644 (file)
index 0000000..0032f29
Binary files /dev/null and b/automated-tests/resources/mask.png differ
diff --git a/automated-tests/resources/po/ar.po b/automated-tests/resources/po/ar.po
new file mode 100755 (executable)
index 0000000..b91b3a7
--- /dev/null
@@ -0,0 +1,3 @@
+#: Used to know if the language is using a right to left script
+msgid "IDS_LTR"
+msgstr "RTL"
diff --git a/automated-tests/resources/po/en.po b/automated-tests/resources/po/en.po
new file mode 100755 (executable)
index 0000000..566fbbd
--- /dev/null
@@ -0,0 +1,3 @@
+#: Used to know if the language is using a right to left script
+msgid "IDS_LTR"
+msgstr "LTR"
diff --git a/automated-tests/resources/progress-bar-skin-indeterminate.png b/automated-tests/resources/progress-bar-skin-indeterminate.png
new file mode 100644 (file)
index 0000000..df99c15
Binary files /dev/null and b/automated-tests/resources/progress-bar-skin-indeterminate.png differ
diff --git a/automated-tests/resources/progress-bar-skin-progress.png b/automated-tests/resources/progress-bar-skin-progress.png
new file mode 100644 (file)
index 0000000..f73b14f
Binary files /dev/null and b/automated-tests/resources/progress-bar-skin-progress.png differ
diff --git a/automated-tests/resources/progress-bar-skin-secondary-progress.png b/automated-tests/resources/progress-bar-skin-secondary-progress.png
new file mode 100644 (file)
index 0000000..f0ae311
Binary files /dev/null and b/automated-tests/resources/progress-bar-skin-secondary-progress.png differ
diff --git a/automated-tests/resources/progress-bar-skin-track.png b/automated-tests/resources/progress-bar-skin-track.png
new file mode 100644 (file)
index 0000000..a22e7c2
Binary files /dev/null and b/automated-tests/resources/progress-bar-skin-track.png differ
diff --git a/automated-tests/resources/svg1.svg b/automated-tests/resources/svg1.svg
new file mode 100644 (file)
index 0000000..4634fd8
--- /dev/null
@@ -0,0 +1,4 @@
+<svg width="100" height="100">
+   <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
+</svg> 
+
diff --git a/automated-tests/resources/tb-norm.png b/automated-tests/resources/tb-norm.png
new file mode 100644 (file)
index 0000000..884cc90
Binary files /dev/null and b/automated-tests/resources/tb-norm.png differ
diff --git a/automated-tests/resources/tbcol.png b/automated-tests/resources/tbcol.png
new file mode 100644 (file)
index 0000000..93d98cd
Binary files /dev/null and b/automated-tests/resources/tbcol.png differ
diff --git a/automated-tests/resources/test-image-600.jpg b/automated-tests/resources/test-image-600.jpg
new file mode 100644 (file)
index 0000000..c93db33
Binary files /dev/null and b/automated-tests/resources/test-image-600.jpg differ
diff --git a/automated-tests/scripts/add_all_smack_rule.sh b/automated-tests/scripts/add_all_smack_rule.sh
new file mode 100755 (executable)
index 0000000..8efb158
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+echo ""
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               echo "Comment"
+               continue
+       fi
+
+       echo "echo \"$rule\" > /smack/load2"
+       echo "$rule" > /smack/load2
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_smack_rule.sh b/automated-tests/scripts/add_smack_rule.sh
new file mode 100755 (executable)
index 0000000..22fe5ee
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+
+echo "sdb root on"
+sdb root on
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               #echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               #echo "Comment"
+               continue
+       fi
+
+       echo "sdb shell \"echo $rule > /smack/load2\""
+       sdb shell "echo $rule > /smack/load2"
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_style.pl b/automated-tests/scripts/add_style.pl
new file mode 100755 (executable)
index 0000000..e958842
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use strict;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $MOD_NAME = $ARGV[0];
+my $results_xml = "tct-$MOD_NAME-core-tests.xml";
+my $results_out = "results_xml.$$";
+
+# Copy $results_xml, writing new stylesheet line:
+# Write <?xml-stylesheet type="text/xsl" href="./style/testresult.xsl"?> as second line
+open RESULTS, "<$results_xml" || die "Can't open $results_xml for reading:$!\n";
+open RESULTS_OUT, ">$results_out" || die "Can't open $results_out for writing:$!\n";
+my $fline = readline RESULTS;
+print RESULTS_OUT $fline;
+print RESULTS_OUT "<?xml-stylesheet type=\"text/xsl\" href=\"./style/testresult.xsl\"?>\n";
+while(<RESULTS>)
+{
+    if( ! /xml-stylesheet/ )
+    {
+        print RESULTS_OUT $_;
+    }
+}
+close RESULTS_OUT;
+close RESULTS;
+unlink $results_xml;
+print `mv $results_out $results_xml`;
diff --git a/automated-tests/scripts/all_smack.rule b/automated-tests/scripts/all_smack.rule
new file mode 100644 (file)
index 0000000..93f2b67
--- /dev/null
@@ -0,0 +1,28 @@
+# calendar-service
+_ calendar-service::svc rwx
+
+# capi-appfw-application
+_ alarm-server::alarm rw
+_ aul::launch x
+_ aul::terminate x
+
+# capi-network-bluetooth
+_ bt-service::admin w
+_ bt-service::manager w
+_ bt-service::gap w
+_ bt-service::spp w
+_ bt:service::opp w
+
+# capi-network-nfc
+_ nfc-manager rwx
+_ nfc-manager::tag rwx
+_ nfc-manager::p2p rwx
+_ nfc-manager::admin rwx
+_ nfc-manager::common rwx
+
+# capi-location-*
+_ location::maps rw
+_ location::client rw
+
+# libmdm
+_ mdm-server::eas rw
diff --git a/automated-tests/scripts/autocompletion.sh b/automated-tests/scripts/autocompletion.sh
new file mode 100755 (executable)
index 0000000..d952c73
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+if [ -z "$TC_PROJECT_DIR" ]; then
+    echo "CoreAPI project directory can't be found. `basename $0` exitting..."
+    exit 1
+fi
+
+_tcbuild () {
+    local cur
+    cur=${COMP_WORDS[$COMP_CWORD]}
+    if [ $COMP_CWORD -eq 1 ]; then
+        COMPREPLY=( $( compgen -W "addmod build install rmmod" -- $cur ) )
+    else #if [ $COMP_CWORD -eq 2 ]; then
+        COMPREPLY=( $( cd $TC_PROJECT_DIR/src; compgen -d -X "common" -- $cur ) )
+    fi
+    return 0
+}
+
+complete -F _tcbuild tcbuild
diff --git a/automated-tests/scripts/init.sh b/automated-tests/scripts/init.sh
new file mode 100755 (executable)
index 0000000..1ccd9ea
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+PROJECT_DIR="$(cd "$(dirname $0)" && cd .. && pwd)"
+
+ln -s $PROJECT_DIR/scripts/tcbuild.sh $PROJECT_DIR/tcbuild
+
+echo "" >> $HOME/.bashrc
+echo "# CoreAPI-tests convenience helpers" >> $HOME/.bashrc
+echo "export TC_PROJECT_DIR=\"$PROJECT_DIR\"" >> $HOME/.bashrc
+echo "source $PROJECT_DIR/scripts/autocompletion.sh" >> $HOME/.bashrc
diff --git a/automated-tests/scripts/output_summary.pl b/automated-tests/scripts/output_summary.pl
new file mode 100755 (executable)
index 0000000..dec392d
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+
+# Reads summary.xml and produces human readable output
+
+use strict;
+use XML::Parser;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $text = "";
+my $module="";
+my %modules=();
+
+sub handle_start
+{
+    my ($p, $elt, %attrs) = @_;
+
+    if($elt =~ /suite/)
+    {
+        $module=$attrs{"name"};
+    }
+    if($elt =~ /_case/)
+    {
+        $text = "";
+    }
+}
+
+sub handle_end
+{
+  my ($p, $elt) = @_;
+  if($elt =~ /pass_case/)
+  {
+      $modules{$module}->{"pass"}=$text;
+      $text="";
+  }
+  elsif($elt =~ /fail_case/)
+  {
+      $modules{$module}->{"fail"}=$text;
+      $text="";
+  }
+}
+
+sub handle_char
+{
+  my ($p, $str) = @_;
+  $text .= $str;
+}
+
+my($parser) = new XML::Parser(Handlers => {Start => \&handle_start,
+                                           End   => \&handle_end,
+                                           Char  => \&handle_char});
+$parser->parsefile("summary.xml");
+
+my $RED_COLOR="\e[1;31m";
+my $GREEN_COLOR="\e[1;32m";
+my $ASCII_RESET="\e[0m";
+my $ASCII_BOLD="\e[1m";
+
+print "\n";
+my $totalFailures=0;
+foreach $module (keys(%modules))
+{
+    my $result_colour = $GREEN_COLOR;
+    if( $modules{$module}->{"fail"} )
+    {
+        $result_colour = $RED_COLOR;
+    }
+    my $numPasses = $modules{$module}->{"pass"};
+    my $numFailures = $modules{$module}->{"fail"};
+    $totalFailures += $numFailures;
+    print( "$ASCII_BOLD$module results:$ASCII_RESET\n" );
+    printf("Number of test passes:   %s%4d (%5.2f%%)%s\n", $ASCII_BOLD, $numPasses, 100.0 * $numPasses / ($numPasses+$numFailures),  $ASCII_RESET);
+    printf("%sNumber of test failures:%s %s%4d%s\n\n", $result_colour, $ASCII_RESET, $ASCII_BOLD, $numFailures, $ASCII_RESET);
+}
+
+exit $totalFailures == 0;
diff --git a/automated-tests/scripts/retriever.sh b/automated-tests/scripts/retriever.sh
new file mode 100755 (executable)
index 0000000..c1d466d
--- /dev/null
@@ -0,0 +1,212 @@
+#!/bin/bash
+
+USAGE=$(cat <<EOF
+Usage note: retriever.sh [option] [directory]
+Options:
+  none    retrieve TC names with corresponding startup and cleanup functions
+  -f      retrieveve TC name with corresponding "set" and "purpose" clauses
+  -anum   retrieve automatic TC number
+  -mnum   retrieve manual TC number
+
+In case of TC in form of "int tc_name()" script will abort.
+("int tc_name(void)" is a proper function signature)
+EOF
+)
+
+function get_tc_files {
+    CMAKE_FILE="$DIR/CMakeLists.txt"
+    if [ ! -e $CMAKE_FILE ]; then
+        echo "File $CMAKE_FILE not found. Aborting..."
+        exit 1
+    fi
+
+    TC_FILES=$(cat $CMAKE_FILE | awk -vDIR="$DIR" '
+    BEGIN {
+        flag = 0;
+        files = "";
+    }
+    /^SET\(TC_SOURCES/ {
+        flag = 1;
+        next;
+    }
+    /\)/ {
+        if (flag == 1)
+            exit;
+    }
+    !/^ *#/ {
+        if (flag == 1) {
+            if (files == "")
+                files = DIR "/" $1;
+            else
+                files = files " " DIR "/" $1;
+        }
+    }
+    END {
+        print files;
+    }')
+}
+
+function tc_names {
+    if [[ -z "$1" ]]; then
+        exit
+    fi
+
+    awk '
+    BEGIN {
+        OFS = ",";
+        start_fun = "NULL";
+        clean_fun = "NULL";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^void .*startup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        start_fun = $0
+    }
+    /^void .*cleanup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        clean_fun = $0
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)/ {
+        gsub(/^int /, "");
+        gsub(/\(void\).*/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS start_fun OFS clean_fun
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+function tc_anum {
+    awk '
+    BEGIN {
+        count = 0;
+        err_flag = 0;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        count++;
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print count
+        }
+    }
+    ' $*
+}
+
+function tc_mnum {
+    # TODO: fix this hardcoded value
+    echo 0
+}
+
+function tc_fullinfo {
+    awk '
+    BEGIN {
+        OFS=",";
+        purpose = "";
+        set = "default";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^\/\/& set:/ {
+        set = $3;
+        next;
+    }
+    /^\/\/& purpose:/ {
+        purpose = $3;
+        for (i = 4; i <= NF; i++) {
+            purpose = purpose " " $i;
+        }
+        next;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        gsub(/^int /, "");
+        gsub(/\(void\)$/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS set OFS purpose;
+        purpose = "";
+        next
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+
+# usage note and exit:
+# - argument begin with '-' but is not recognised or number of arguments is > 3,
+# - argument doesn't begin with '-' and number of arguments is > 2
+if [[ ( "$1" == -* && ( ! "$1" =~ ^-(anum|mnum|f)$ || $# > 3 ) ) || ( "$1" != -* && $# > 2 ) ]]; then
+    echo -e "$USAGE"
+    exit 1
+fi
+
+# get directory from last argument (or assume current one)
+if [[ ! "$1" =~ ^-(anum|mnum|f)$ ]]; then
+    DIR=${1:-.}
+else
+    DIR=${2:-.}
+fi
+
+# get filename from last argument
+if [[ $# == 3 && -f $DIR/$3 ]] ; then
+    FILE=$3
+elif [[ $# == 2 && -f $DIR/$2 ]] ; then
+    FILE=$2
+fi
+
+#echo "Dir: $DIR  File: $FILE" >& 2
+
+
+# populate $TC_FILES with files declared in CMakeLists.txt
+if [[ -z $FILE ]]; then
+    get_tc_files $DIR
+    if [ $? != 0 ]; then
+        exit 1
+    fi
+    echo "Got all files" >& 2
+else
+    TC_FILES="$DIR/$FILE"
+    echo "TC_FILES: $TC_FILES" >& 2
+fi
+
+
+
+# run appropriate subcommand
+case "$1" in
+    -anum)
+        tc_anum $TC_FILES ;;
+    -mnum)
+        tc_mnum $TC_FILES ;;
+    -f)
+        tc_fullinfo $TC_FILES ;;
+    *)
+        tc_names $TC_FILES ;;
+esac
diff --git a/automated-tests/scripts/summarize.pl b/automated-tests/scripts/summarize.pl
new file mode 100755 (executable)
index 0000000..8270376
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+
+# Generates an XML summary of test cases from Test-kit lite output XML.
+
+use strict;
+use XML::Parser;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $num_tests=0;
+my $num_passes=0;
+my $num_actual_passes=0;
+my $text = "";
+
+sub handle_start
+{
+    my ($p, $elt, %attrs) = @_;
+
+    if($elt =~ /testcase/)
+    {
+        $num_tests++;
+        if($attrs{"result"} eq "PASS")
+        {
+            $num_passes++;
+        }
+    }
+    if($elt =~ /actual_result/)
+    {
+        $text = "";
+    }
+}
+
+sub handle_end
+{
+  my ($p, $elt) = @_;
+  if($elt =~ /actual_result/)
+  {
+      if($text eq "PASS")
+      {
+          $num_actual_passes++;
+      }
+      $text = "";
+  }
+}
+
+sub handle_char
+{
+  my ($p, $str) = @_;
+  $text .= $str;
+}
+
+my($parser) = new XML::Parser(Handlers => {Start => \&handle_start,
+                                           End   => \&handle_end,
+                                           Char  => \&handle_char});
+
+
+# Write summary.xml:
+open SUMMARY, ">summary.xml" || die "Can't open summary.xml for writing:$!\n";
+print SUMMARY << "EOS";
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="./style/summary.xsl"?>
+<result_summary plan_name="Core">
+  <other xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" />
+  <summary test_plan_name="Empty test_plan_name">
+    <start_at>2014-03-21_18_52_41</start_at>
+    <end_at>2014-03-21_18_57_54</end_at>
+  </summary>
+EOS
+
+print "\n\nSummary of all tests:\n";
+my $output_files = `ls tct*core-tests.xml`;
+my $file;
+foreach $file (split /\s+/, $output_files )
+{
+    $num_tests=0;
+    $num_passes=0;
+    $num_actual_passes=0;
+    $text = "";
+
+    $parser->parsefile($file);
+
+    my $pass_rate = sprintf("%5.2f", $num_passes * 100.0 / $num_tests);
+    my $num_fails = $num_tests - $num_passes;
+    my $fail_rate = sprintf("%5.2f", $num_fails * 100.0 / $num_tests);
+
+    my $suite_name = $file;
+    $suite_name =~ s/\.xml$//;
+
+    print "$suite_name: $num_passes tests passed out of $num_tests ( $pass_rate% )\n";
+
+print SUMMARY << "EOS2";
+  <suite name="$suite_name">
+    <total_case>$num_tests</total_case>
+    <pass_case>$num_passes</pass_case>
+    <pass_rate>$pass_rate</pass_rate>
+    <fail_case>$num_fails</fail_case>
+    <fail_rate>$fail_rate</fail_rate>
+    <block_case>0</block_case>
+    <block_rate>0.00</block_rate>
+    <na_case>0</na_case>
+    <na_rate>0.00</na_rate>
+  </suite>
+EOS2
+}
+
+print SUMMARY "</result_summary>\n";
+close SUMMARY;
+
+print "Summary of results written to summary.xml\n";
diff --git a/automated-tests/scripts/tcbuild.sh b/automated-tests/scripts/tcbuild.sh
new file mode 100755 (executable)
index 0000000..b604675
--- /dev/null
@@ -0,0 +1,215 @@
+#!/bin/bash
+
+#---------- DEBUG_BEGIN ----------
+#ARG="-d" # debug-on flag, might be set as $1
+# keyprompt "introductory message" -- wait until any key pressed
+function keyprompt { echo -ne "\n\e[1;31m$1 -- " && read -n 1 && echo -e "\n\e[0m"; }
+# d_bp -- breakpoint at which user need to press any key to proceed
+function d_bp { if [[ "$ARG" == "-d" ]]; then keyprompt "d >> Press any key"; fi }
+# d_showVar VARNAME -- print bash variable name
+function d_showVar { if [ "$ARG" == "-d" -a -n "$1" ]; then echo "d >> ${1} = ${!1}"; fi }
+# d_print "message" -- print a debug message
+function d_print { if [ "$ARG" == "-d" -a -n "$1" ]; then echo -e "d >> $1"; fi }
+#----------  DEBUG_END  ----------
+
+PROJECT_DIR="$(cd "$(dirname $0)" && pwd)"
+d_showVar PROJECT_DIR
+
+function gbs_profile {
+perl -e "
+use Config::Tiny;
+my \$Config = Config::Tiny->read( \"\$ENV{HOME}/.gbs.conf\" );
+my \$profile = \$Config->{general}->{profile};
+\$profile =~ s/profile.//;
+print \$profile;"
+}
+
+PROFILE=`gbs_profile`
+RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"
+d_showVar RPM_DIR
+
+function add_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` addmod <module_name> [module_lib_name]"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+    MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+    d_showVar MODULE_NAME_C
+    MODULE_NAME_U=$(echo $MODULE_NAME | sed -e 's/-/_/')
+    d_showVar MODULE_NAME_U
+#    MODULE_LIBNAME=${2:-capi-$MODULE_NAME}
+    MODULE_LIBNAME=$1
+    d_showVar MODULE_LIBNAME
+
+    echo "Adding $MODULE_NAME module to project..."
+    d_bp
+    cd $PROJECT_DIR
+    # prepare .spec file
+    echo "-- Generating packaging/core-$MODULE_NAME-tests.spec file"
+    if [ ! -d packaging ]; then mkdir packaging; fi
+    sed -e "s:\[MODULE_NAME\]:$MODULE_NAME:g" -e "s:\[MODULE_LIBNAME\]:$MODULE_LIBNAME:g" \
+        templates/core-\[module_name\]-tests.spec > packaging/core-$MODULE_NAME-tests.spec
+    # prepare src directory
+    mkdir src/$MODULE_NAME
+    echo "-- Generating src/$MODULE_NAME/CMakeLists.txt file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" -e "s:%{MODULE_LIBNAME}:$MODULE_LIBNAME:g" \
+        templates/src-directory/CMakeLists.txt > src/$MODULE_NAME/CMakeLists.txt
+    echo "-- Generating src/$MODULE_NAME/tct-$MODULE_NAME-core.c file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" \
+        templates/src-directory/tct-\[module_name\]-core.c > src/$MODULE_NAME/tct-$MODULE_NAME-core.c
+    echo "-- Generating src/$MODULE_NAME/utc-$MODULE_NAME.c file"
+    sed -e "s:%{MODULE_NAME_U}:$MODULE_NAME_U:g" -e "s:%{MODULE_NAME_C}:$MODULE_NAME_C:g" \
+        templates/src-directory/utc-\[module_name\].c > src/$MODULE_NAME/utc-$MODULE_NAME.c
+    echo "Task finished successfully"
+}
+
+function rm_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` rmmod <module_name>"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+
+    echo "Removing $MODULE_NAME module from project..."
+    d_bp
+    echo "---- Updating /opt/tct/packages/package_list.xml"
+    scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/packages/package_list.xml 1
+    if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+   # echo "---- Updating test plans"
+   # scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/manager/plan/*.xml 1
+   # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+
+    cd $PROJECT_DIR
+    echo "-- Removing packaging/core-$MODULE_NAME-tests.spec file"
+    rm packaging/core-$MODULE_NAME-tests.spec
+    echo "-- Removing src/$MODULE_NAME directory"
+    rm -r src/$MODULE_NAME
+    echo "Task finished successfully"
+}
+
+function build {
+    if [ -n "$1" ]; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        cp packaging/core-$1-tests.spec ../packaging
+        cp .gitignore-without-autogenerated-files .gitignore
+        gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs | \
+            tee build.log | stdbuf -o0 sed -e 's/error:/\x1b[1;91m&\x1b[0m/' \
+                                           -e 's/warning:/\x1b[93m&\x1b[0m/'
+        rm ../packaging/core-$1-tests.spec
+        cp .gitignore-with-autogenerated-files .gitignore
+    else
+        echo "Build requires a module name"
+        exit 1
+    fi
+}
+
+function inst {
+    if [ -z "$1" ]
+    then
+        for mod in `ls -1 src/ | grep -v CMakeLists`
+        do
+
+       if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+            PKG_NAME="core-$mod-tests"
+            d_showVar PKG_NAME
+            VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+            d_showVar VER
+            PKG_VNAME="$PKG_NAME-$VER"
+            d_showVar PKG_VNAME
+            PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+            d_showVar PKG_FNAME
+
+            if [ -f "$RPM_DIR/$PKG_FNAME" ]
+            then
+                inst $mod
+                echo ""
+            fi
+       fi
+        done
+    else
+        cd $PROJECT_DIR
+        # setting variables
+        MOD_NAME="$1"
+        d_showVar MOD_NAME
+        PKG_NAME="core-$MOD_NAME-tests"
+        d_showVar PKG_NAME
+        VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+        d_showVar VER
+        PKG_VNAME="$PKG_NAME-$VER"
+        d_showVar PKG_VNAME
+        PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+        d_showVar PKG_FNAME
+        TCT_DIR="opt/tct-$MOD_NAME-core-tests"
+        d_showVar TCT_DIR
+
+        echo "Deploying $MOD_NAME suite to tct-mgr..."
+        d_bp
+        # prepare tct directory and files
+        echo "-- Preparing suite .zip file..."
+        echo "---- Creating /tmp/$TCT_DIR directory"
+        rm -r /tmp/opt > /dev/null 2>&1
+        mkdir -p /tmp/$TCT_DIR
+        # README
+        echo "---- Copying /tmp/$TCT_DIR"
+        cp templates/tct-package/README /tmp/$TCT_DIR
+        # rpm
+        echo "---- Copying /tmp/$TCT_DIR package"
+        cp $RPM_DIR/$PKG_FNAME /tmp/$TCT_DIR
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # inst.sh
+        echo "---- Generating /tmp/$TCT_DIR/inst.sh file"
+        sed -e "s:%{PKG_NAME}:\"$PKG_NAME\":g" -e "s:%{PKG_FULLNAME}:\"$PKG_FNAME\":g" \
+            -e "s:%{PKG_DIR}:\"/opt/usr/media/tct/$TCT_DIR\":g" \
+            templates/tct-package/inst.sh > /tmp/$TCT_DIR/inst.sh
+        chmod a+x /tmp/$TCT_DIR/inst.sh
+        # tests.xml
+        echo "---- Generating /tmp/$TCT_DIR"
+        scripts/tctestsgen.sh $MOD_NAME /tmp/$TCT_DIR target
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # zip
+        echo "---- Preparing /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip file"
+        # clear old zips
+        rm -r /tmp/tct/packages > /dev/null 2>&1
+        mkdir -p /tmp/tct/packages
+        # create new zip
+        ( cd /tmp; zip -r /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip opt > /dev/null 2>&1; )
+        # deployment
+        echo "-- Suite deployment..."
+        echo "---- Copying /opt/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip"
+        cp /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip /opt/tct/packages/
+        echo "---- Updating /opt/tct/packages/package_list.xml"
+        scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/packages/package_list.xml 0
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+       # echo "---- Updating test plans"
+       # for file in `grep -r tct-$MOD_NAME-core-tests /opt/tct/manager/plan/ | cut -d: -f1 | uniq`
+       # do
+       #     scripts/tcpackageslistsgen.sh $MOD_NAME $file
+       # done
+       # scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/manager/plan/Full_test.xml
+       # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        echo "Task finished successfully"
+    fi
+}
+
+if [ -z "$1" ]; then
+    # usage note
+    echo "Usage: `basename $0` <addmod|rmmod|build|install> <module_name> [module_lib_name]"
+    exit 1
+elif [ "addmod" == "$1" ]; then
+    # add new module
+    add_module $2 $3
+elif [ "rmmod" == "$1" ]; then
+    # remove module
+    rm_module $2
+elif [ "build" == "$1" ]; then
+    # build the binary
+    build $2
+elif [ "install" == "$1" ]; then
+    # install
+    inst $2
+else
+    echo "Invalid subcommand: $1"
+fi
diff --git a/automated-tests/scripts/tcheadgen.sh b/automated-tests/scripts/tcheadgen.sh
new file mode 100755 (executable)
index 0000000..c8cd679
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tcheadgen.sh <header_filename.h>"
+    exit 1
+fi
+
+FILE="$PWD/$1"
+TFILE="/tmp/retr.csv$$"
+HEADER_NAME=$(echo $1 | tr '[:lower:]' '[:upper:]' | sed -e 's/-/_/g' -e 's/\./_/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+
+$SCRIPT_DIR/retriever.sh > $TFILE
+if [ $? -ne 0 ]; then cat $TFILE; exit 1; fi
+awk -F',' -v HEADER_NAME="$HEADER_NAME" '
+    BEGIN {
+        OFS = ", ";
+
+        startup_counter = 0;
+        startup_list[0] = "";
+
+        cleanup_counter = 0;
+        cleanup_list[0] = "";
+
+        testcase_counter = 0;
+        testcase_list[0] = "";
+
+        tc_array_counter = 0;
+        tc_array_list[0] = "";
+
+print "#ifndef " HEADER_NAME
+print "#define " HEADER_NAME
+print ""
+print "#include \"testcase.h\""
+print ""
+    }
+    {
+        testcase_list[testcase_counter++] = $1;
+
+        if (startup_counter == 0 || startup_list[startup_counter-1] != $2)
+            startup_list[startup_counter++] = $2;
+
+        if (startup_counter == 0 || cleanup_list[cleanup_counter-1] != $3)
+            cleanup_list[cleanup_counter++] = $3;
+
+        tc_array_list[tc_array_counter++] = "\"" $1 "\", " $1 ", " $2 ", " $3;
+    }
+    END {
+        sc_count = (startup_counter > cleanup_counter) ? startup_counter : cleanup_counter;
+        for (i = 0; i < sc_count; i++) {
+            if (i < startup_counter && startup_list[i] != "NULL")
+print "extern void " startup_list[i] "(void);"
+            if (i < cleanup_counter && cleanup_list[i] != "NULL")
+print "extern void " cleanup_list[i] "(void);"
+        }
+
+print ""
+        for (i = 0; i < testcase_counter; i++)
+print "extern int " testcase_list[i] "(void);"
+
+print ""
+print "testcase tc_array[] = {"
+
+        for (i = 0; i < tc_array_counter; i++)
+print "    {" tc_array_list[i] "},"
+
+print "    {NULL, NULL}"
+print "};"
+print ""
+print "#endif // " HEADER_NAME
+}' $TFILE > $FILE
+unlink $TFILE
+
diff --git a/automated-tests/scripts/tcpackageslistsgen.sh b/automated-tests/scripts/tcpackageslistsgen.sh
new file mode 100755 (executable)
index 0000000..15ea51f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+if [ -z $1 -o -z $2 ]; then
+    echo "Usage note: tcpackageslistsgen.sh <module_name> <output_file.xml>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+FILE=$2
+if [ ! -f $FILE ]; then
+    echo "No such file: $2"
+    exit
+fi
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+AUTO_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -anum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $AUTO_NUM; exit 1; fi
+MAN_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -mnum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $MAN_NUM; exit 1; fi
+
+TFILE="/tmp/tempfile.xml"
+if [ -f $TFILE ]; then
+    rm $TFILE
+fi
+
+function regen {
+    awk -v RS='\r\n' -v ORS='\r\n' -v MODULE_NAME=$MODULE_NAME -v AUTO_NUM=$AUTO_NUM -v MAN_NUM=$MAN_NUM '    
+    BEGIN {
+        found = 0;
+        replaced = 0;
+    }
+    $0 ~ "<suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">" {
+        found = 1;
+        next
+    }
+    /<\/suite>/ {
+        if (found == 1) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+            found = 0;
+            replaced = 1;
+        } else {
+            print $0;
+        }
+        next
+    }
+    /<\/ns3:testplan>/ {
+        if (replaced == 0) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+print $0
+        } else {
+            print $0
+        }
+        next
+    }
+    {
+        if (found == 0) {
+            print $0;
+        }
+    }' $FILE > $TFILE
+    cat $TFILE > $FILE
+}
+
+regen
diff --git a/automated-tests/scripts/tctestsgen.sh b/automated-tests/scripts/tctestsgen.sh
new file mode 100755 (executable)
index 0000000..1881668
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tctestsgen.sh <module_name>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+TC_DIR="/opt/usr/bin/tct-$1-core"
+if [[ $3 == "desktop" ]] ; then
+  TC_DIR="build/src/$1"
+fi
+
+FILE="$2/tests.xml"
+if [ -a $FILE ]; then
+    rm $FILE
+fi
+TFILE="/tmp/tcs.csv"
+if [ -a $TFILE ]; then
+    rm $TFILE
+fi
+
+function gen {
+    awk -F',' -v MODULE_NAME=$MODULE_NAME -v MODULE_NAME_C=$MODULE_NAME_C -v TC_DIR=$TC_DIR '
+    BEGIN {
+        set = ""
+print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+print "    <?xml-stylesheet type=\"text/xsl\" href=\"./testcase.xsl\"?>";
+print "<test_definition>";
+print "  <suite name=\"tct-"MODULE_NAME"-core-tests\" category=\"Core APIs\">";
+    }
+    {
+        if (set != "" && set != $2) {
+print "    </set>"
+        }
+
+        if (set != $2) {
+            set = $2;
+print "    <set name=\"" set "\">";
+        }
+
+        tcname = $1;
+        tcpurpose = $3
+
+print "      <testcase component=\"CoreAPI/" MODULE_NAME_C "/" set "\" execution_type=\"auto\" id=\"" tcname "\" purpose=\"" tcpurpose "\">";
+print "        <description>";
+
+print "          <test_script_entry test_script_expected_result=\"0\">" TC_DIR "/tct-" MODULE_NAME "-core " tcname "</test_script_entry>";
+print "        </description>";
+print "      </testcase>";
+    }
+    END {
+        if (set != "") {
+print "    </set>"
+        }
+print "  </suite>"
+print "</test_definition>"
+    }' $TFILE > $FILE
+}
+
+(cd $SCRIPT_DIR/..; scripts/retriever.sh -f src/$MODULE_NAME $4 > ${TFILE}_pre)
+if [ $? -ne 0 ]; then cat ${TFILE}_pre; exit 1; fi
+cat ${TFILE}_pre | sort -t',' -k2,2 -s > $TFILE
+gen
diff --git a/automated-tests/src/common/assert.h b/automated-tests/src/common/assert.h
new file mode 100644 (file)
index 0000000..a5d6cff
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _ASSERT_H_
+#define _ASSERT_H_
+#include <stdio.h>
+#include <stdlib.h>
+
+#define assert(exp) \
+    if (!(exp)) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Following expression is not true:\n" \
+                "%s\n", #exp); \
+        return 1; \
+    }
+
+#define assert_eq(var, ref) \
+    if (var != ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are not equal:\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, (int)var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_neq(var, ref) \
+    if (var == ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are equal:\n" \
+                "%s == %s == %d\n", \
+            #var, #ref, #var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_gt(var, ref) \
+    if (var <= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_geq(var, ref) \
+    if (var < ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_lt(var, ref) \
+    if (var >= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_leq(var, ref) \
+    if (var > ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#endif //  _ASSERT_H_
diff --git a/automated-tests/src/common/testcase.h b/automated-tests/src/common/testcase.h
new file mode 100644 (file)
index 0000000..011a452
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _TESTCASE_H_
+#define _TESTCASE_H_
+
+/* pointer to startup/cleanup functions */
+typedef void (*void_fun_ptr)(void);
+
+/* pointer to testcase functions */
+typedef int (*tc_fun_ptr)(void);
+
+/* struct describing specific testcase */
+typedef struct testcase_s {
+    const char* name;
+    tc_fun_ptr function;
+    void_fun_ptr startup;
+    void_fun_ptr cleanup;
+} testcase;
+
+#endif // _TESTCASE_H_
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.cpp
new file mode 100644 (file)
index 0000000..c679479
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 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 "dummy-visual.h"
+
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+DummyVisualPtr DummyVisual::New( const Property::Map& properties )
+{
+  VisualFactoryCache* factoryCache = new VisualFactoryCache(false);
+
+  DummyVisualPtr dummyVisualPtr( new DummyVisual( *factoryCache ) );
+
+  return dummyVisualPtr;
+}
+
+DummyVisual::DummyVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mActionCounter( 0 )
+{
+}
+
+void DummyVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  // Implement if required
+}
+
+void DummyVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Implement if required
+}
+
+void DummyVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // Implement if required
+}
+
+void DummyVisual::OnSetTransform()
+{
+  // Implement if required
+}
+
+void DummyVisual::DoSetOnStage( Actor& actor )
+{
+  // Implement if required
+}
+
+void DummyVisual::OnDoAction( const Property::Index actionName, const Property::Value& attributes )
+{
+  if ( DummyVisual::TEST_ACTION == actionName )
+  {
+    mActionCounter++;  // GetActionCounter can be used to test for this.
+  }
+  // Further Actions can be added here
+}
+
+unsigned int DummyVisual::GetActionCounter() const
+{
+  return mActionCounter;
+}
+
+void DummyVisual::ResetActionCounter()
+{
+  mActionCounter = 0;
+}
+
+} // Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dummy-visual.h
new file mode 100644 (file)
index 0000000..05cae85
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef DALI_TOOLKIT_TEST_DUMMY_VISUAL_H
+#define DALI_TOOLKIT_TEST_DUMMY_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class DummyVisual;
+
+typedef IntrusivePtr< DummyVisual > DummyVisualPtr;
+
+/**
+ * Dummy Visual that can be used for testing
+ * Cannot create an instance of an existing Visual, so use this dummy class for the implementation.
+ */
+class DummyVisual : public Visual::Base
+{
+public:
+
+  // Actions that the dummy visual can perform.  These actions are called through the Visual::Base::DoAction API.
+  enum Type
+  {
+    TEST_ACTION = 0,  ///< Updates the action counter
+  };
+
+public:
+
+  // Constructor for DummyVisual
+  static DummyVisualPtr New( const Property::Map& properties );
+
+  // Prevent default methods being used.
+  DummyVisual( const DummyVisual& dummyVisual ) = delete;
+  DummyVisual( const DummyVisual&& dummyVisual ) = delete;
+  DummyVisual& operator=( const DummyVisual& dummyVisual ) = delete;
+  DummyVisual& operator=( const DummyVisual&& dummyVisual ) = delete;
+
+  // Get the Action counter, action counter incremented with every successful Action
+  unsigned int GetActionCounter() const;
+  // Reset the Action counter to 0;
+  void ResetActionCounter();
+
+protected:
+
+  DummyVisual( VisualFactoryCache& factoryCache );
+
+  virtual void DoCreatePropertyMap( Property::Map& map ) const override;
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+  virtual void DoSetProperties( const Property::Map& propertyMap ) override;
+  virtual void OnSetTransform() override;
+  virtual void DoSetOnStage( Actor& actor ) override;
+  virtual void OnDoAction( const Property::Index actionName, const Property::Value& attributes ) override;
+
+private:
+  unsigned int mActionCounter;
+
+};
+
+
+} // Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEST_DUMMY_VISUAL_H
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
new file mode 100755 (executable)
index 0000000..b7a1122
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// FILE HEADER
+#include "toolkit-text-utils.h"
+
+// EXTERNAL INCLUDES
+#include <limits>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/markup-processor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Frees previously allocated bidirectional resources.
+ *
+ * @param[in] bidirectionalLineInfo Bidirectional info per line.
+ * @param[in] index Index to the first line with bidirectional info to be freed.
+ */
+void FreeBidirectionalLineInfoResources( Vector<BidirectionalLineInfoRun> bidirectionalLineInfo,
+                                         uint32_t index )
+{
+  // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+  for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfo.Begin() + index,
+         endIt = bidirectionalLineInfo.End();
+       it != endIt;
+       ++it )
+  {
+    BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+    free( bidiLineInfo.visualToLogicalMap );
+  }
+}
+
+/**
+ * @brief Clear all the model data except for LogicalModel::mText.
+ *
+ * @param[in] characterIndex Clear data starting from the index.
+ */
+void ClearModelData( CharacterIndex characterIndex,
+                     LogicalModelPtr logicalModel,
+                     VisualModelPtr visualModel )
+{
+  // n.b. This does not Clear the mText from mLogicalModel
+
+  // Frees previously allocated resources.
+  FreeBidirectionalLineInfoResources( logicalModel->mBidirectionalLineInfo, 0u );
+
+  logicalModel->mScriptRuns.Clear();
+  logicalModel->mFontRuns.Clear();
+  logicalModel->mBidirectionalParagraphInfo.Clear();
+  logicalModel->mCharacterDirections.Clear();
+  logicalModel->mBidirectionalLineInfo.Clear();
+  visualModel->mGlyphs.Clear();
+  visualModel->mGlyphsToCharacters.Clear();
+  visualModel->mCharactersToGlyph.Clear();
+  visualModel->mCharactersPerGlyph.Clear();
+  visualModel->mGlyphsPerCharacter.Clear();
+  visualModel->mGlyphPositions.Clear();
+  visualModel->mLines.Clear();
+
+  visualModel->ClearCaches();
+}
+
+void CreateTextModel( const std::string& text,
+                      const Size& textArea,
+                      const Vector<FontDescriptionRun>& fontDescriptions,
+                      const LayoutOptions& options,
+                      Size& layoutSize,
+                      ModelPtr& textModel,
+                      MetricsPtr& metrics,
+                      bool markupProcessorEnabled )
+{
+  textModel = Model::New(); ///< Pointer to the text's model.
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  MarkupProcessData markupProcessData( logicalModel->mColorRuns,
+                                       logicalModel->mFontDescriptionRuns,
+                                       logicalModel->mEmbeddedItems );
+
+  Length textSize = 0u;
+  const uint8_t* utf8 = NULL;
+  if( markupProcessorEnabled )
+  {
+    ProcessMarkupString( text, markupProcessData );
+    textSize = markupProcessData.markupProcessedText.size();
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
+  }
+  else
+  {
+    textSize = text.size();
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+  }
+
+  // 1) Convert to utf32
+  Vector<Character>& utf32Characters = logicalModel->mText;
+  utf32Characters.Resize( textSize );
+
+  // Transform a text array encoded in utf8 into an array encoded in utf32.
+  // It returns the actual number of characters.
+  Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
+  utf32Characters.Resize( characterCount );
+
+  // 2) Set the break and paragraph info.
+  Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
+  lineBreakInfo.Resize( characterCount );
+
+  SetLineBreakInfo( utf32Characters,
+                    0u,
+                    characterCount,
+                    lineBreakInfo );
+
+  if( 0u == characterCount )
+  {
+    // Nothing else to do if the number of characters is zero.
+    return;
+  }
+
+  // 3) Set the script info.
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+  Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
+  multilanguageSupport.SetScripts( utf32Characters,
+                                   0u,
+                                   characterCount,
+                                   scripts );
+
+  // 4) Set the font info
+  Vector<FontDescriptionRun>& fontDescriptionRuns = logicalModel->mFontDescriptionRuns;
+  fontDescriptionRuns = fontDescriptions;
+  Vector<FontRun>& validFonts = logicalModel->mFontRuns;
+
+  // The default font description.
+  TextAbstraction::FontDescription fontDescription;
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  // Validates the fonts. If there is a character with no assigned font it sets a default one.
+  // After this call, fonts are validated.
+  multilanguageSupport.ValidateFonts( utf32Characters,
+                                      scripts,
+                                      fontDescriptionRuns,
+                                      fontDescription,
+                                      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+                                      0u,
+                                      characterCount,
+                                      validFonts );
+
+  // 5) Set the bidirectional info per paragraph.
+  Vector<Character> mirroredUtf32Characters;
+  bool textMirrored = false;
+
+  // Reserve some space for the vector of paragraph's bidirectional info.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+  // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+  SetBidirectionalInfo( utf32Characters,
+                        scripts,
+                        lineBreakInfo,
+                        0u,
+                        characterCount,
+                        bidirectionalInfo );
+
+  // Create the paragraph info.
+  logicalModel->CreateParagraphInfo( 0u,
+                                     characterCount );
+
+  // 6) Set character directions.
+  Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
+  if( 0u != bidirectionalInfo.Count() )
+  {
+    // Only set the character directions if there is right to left characters.
+    GetCharactersDirection( bidirectionalInfo,
+                            characterCount,
+                            0u,
+                            characterCount,
+                            characterDirections );
+
+
+    // This paragraph has right to left text. Some characters may need to be mirrored.
+    textMirrored = GetMirroredText( utf32Characters,
+                                    characterDirections,
+                                    bidirectionalInfo,
+                                    0u,
+                                    characterCount,
+                                    mirroredUtf32Characters );
+  }
+  else
+  {
+    // There is no right to left characters. Clear the directions vector.
+    characterDirections.Clear();
+  }
+
+  // 7) Shape the text.
+
+  Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphsToCharactersMap = visualModel->mGlyphsToCharacters;
+  Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex> newParagraphGlyphs;
+
+  const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+
+  ShapeText( textToShape,
+             lineBreakInfo,
+             scripts,
+             validFonts,
+             0u,
+             0u,
+             characterCount,
+             glyphs,
+             glyphsToCharactersMap,
+             charactersPerGlyph,
+             newParagraphGlyphs );
+
+  // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+  visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, characterCount );
+  visualModel->CreateCharacterToGlyphTable( 0u, 0u, characterCount );
+
+  const Length numberOfGlyphs = glyphs.Count();
+
+  // 8) Get the glyph metrics
+  metrics = Metrics::New( fontClient );
+
+  GlyphInfo* glyphsBuffer = glyphs.Begin();
+  metrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+
+  // Update the width and advance of all new paragraph characters.
+  for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(),
+         endIt = newParagraphGlyphs.End();
+       it != endIt;
+       ++it )
+  {
+    const GlyphIndex index = *it;
+    GlyphInfo& glyph = *( glyphsBuffer + index );
+
+    glyph.xBearing = 0.f;
+    glyph.width = 0.f;
+    glyph.advance = 0.f;
+  }
+
+  // 9) Layout the text
+  Layout::Engine layoutEngine;
+  layoutEngine.SetMetrics( metrics );
+  layoutEngine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
+
+  // Set the layout parameters.
+  textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
+  textModel->mLineWrapMode = LineWrap::WORD;
+  textModel->mIgnoreSpacesAfterText = true;
+  textModel->mMatchSystemLanguageDirection = false;
+  Layout::Parameters layoutParameters( textArea,
+                                       textModel );
+
+  Vector<LineRun>& lines = visualModel->mLines;
+
+  Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+  glyphPositions.Resize( numberOfGlyphs );
+
+  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
+
+  // The initial glyph and the number of glyphs to layout.
+  layoutParameters.startGlyphIndex = 0u;
+  layoutParameters.numberOfGlyphs = numberOfGlyphs;
+  layoutParameters.startLineIndex = 0u;
+  layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
+
+  bool isAutoScroll = false;
+  layoutEngine.LayoutText( layoutParameters,
+                           layoutSize,
+                           false,
+                           isAutoScroll );
+
+  if( options.align )
+  {
+    float alignmentOffset = 0.f;
+    layoutEngine.Align( textArea,
+                        0u,
+                        characterCount,
+                        Text::HorizontalAlignment::BEGIN,
+                        lines,
+                        alignmentOffset,
+                        Dali::LayoutDirection::LEFT_TO_RIGHT,
+                        false );
+  }
+}
+
+void ConfigureTextLabel( ControllerPtr controller )
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  // Set the text layout as multi-line.
+  controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
+
+  // Set cursor's width to zero.
+  controller->GetLayoutEngine().SetCursorWidth( 0 );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Disables the text input.
+  controller->EnableTextInput( NULL, inputMethodContext );
+
+  // Disables the vertical scrolling.
+  controller->SetVerticalScrollEnabled( false );
+
+  // Disables the horizontal scrolling.
+  controller->SetHorizontalScrollEnabled( false );
+
+  // Enable the text elide.
+  controller->SetTextElideEnabled( true );
+}
+
+void ConfigureTextField( ControllerPtr controller )
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+
+  // Set the text layout as multi-line.
+  controller->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Enables the vertical scrolling after the text input has been enabled.
+  controller->SetVerticalScrollEnabled( false );
+
+  // Disables the horizontal scrolling.
+  controller->SetHorizontalScrollEnabled( true );
+
+  // No maximum number of characters.
+  controller->SetMaximumNumberOfCharacters( 50u );
+
+  // Disable the text elide.
+  controller->SetTextElideEnabled( false );
+}
+
+void ConfigureTextEditor( ControllerPtr controller )
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+
+  // Set the text layout as multi-line.
+  controller->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Enables the vertical scrolling after the text input has been enabled.
+  controller->SetVerticalScrollEnabled( true );
+
+  // Disables the horizontal scrolling.
+  controller->SetHorizontalScrollEnabled( false );
+
+  // No maximum number of characters.
+  controller->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
+
+  // Disable the text elide.
+  controller->SetTextElideEnabled( false );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.h
new file mode 100644 (file)
index 0000000..eb0dd40
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef DALI_TOOLKIT_TEXT_UTILS_H
+#define DALI_TOOLKIT_TEXT_UTILS_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/metrics.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-model.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Some layout options.
+ */
+struct LayoutOptions
+{
+  LayoutOptions()
+  : align{ true }
+  {}
+
+  bool align   : 1; ///< Whether to align the lines.
+};
+
+/**
+ * @brief Creates and fills all the vectors of a text model: characters in utf32, segmentation info,
+ * scripts, fonts, bidi info, glyphs, conversion tables, etc.
+ *
+ * @param[in] text The given text.
+ * @param[in] textArea The area where to layout the text.
+ * @param[in] fontDescriptions The fonts to be used.
+ * @param[in] options Layout options.
+ * @param[out] layoutSize The laid-out size.
+ * @param[out] textModel Pointer to a text model instance.
+ * @param[out] metrics Pointer to a wrapper around FontClient used to get metrics.
+ * @param[in] markupProcessorEnabled Enable markup processor to use markup text.
+ */
+void CreateTextModel( const std::string& text,
+                      const Size& textArea,
+                      const Vector<FontDescriptionRun>& fontDescriptions,
+                      const LayoutOptions& options,
+                      Size& layoutSize,
+                      ModelPtr& textModel,
+                      MetricsPtr& metrics,
+                      bool markupProcessorEnabled );
+
+/**
+ * @brief Configures the text @p controller similarly to the one configured by the text-label.
+ *
+ * @param[in,out] The text controller to configure.
+ */
+void ConfigureTextLabel( ControllerPtr controller );
+
+/**
+ * @brief Configures the text @p controller similarly to the one configured by the text-field.
+ *
+ * @param[in,out] The text controller to configure.
+ */
+void ConfigureTextField( ControllerPtr controller );
+
+/**
+ * @brief Configures the text @p controller similarly to the one configured by the text-editor.
+ *
+ * @param[in,out] The text controller to configure.
+ */
+void ConfigureTextEditor( ControllerPtr controller );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UTILS_H
diff --git a/automated-tests/src/dali-toolkit-internal/tct-dali-toolkit-internal-core.cpp b/automated-tests/src/dali-toolkit-internal/tct-dali-toolkit-internal-core.cpp
new file mode 100644 (file)
index 0000000..39ed044
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-toolkit-internal-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        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-internal/utc-Dali-BidirectionalSupport.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-BidirectionalSupport.cpp
new file mode 100644 (file)
index 0000000..e056f73
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2018 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/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void SetBidirectionalInfo( const Vector<Character>& text,
+//                            const Vector<ScriptRun>& scripts,
+//                            const Vector<LineBreakInfo>& lineBreakInfo,
+//                            CharacterIndex startIndex,
+//                            Length numberOfCharacters,
+//                            Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo )
+// bool GetMirroredText( const Vector<Character>& text,
+//                       Vector<CharacterDirection>& directions,
+//                       const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+//                       CharacterIndex startIndex,
+//                       Length numberOfCharacters,
+//                       Vector<Character>& mirroredText )
+// void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+//                              Length totalNumberOfCharacters,
+//                              CharacterIndex startIndex,
+//                              Length numberOfCharacters,
+//                              Vector<CharacterDirection>& directions )
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetBidirectionalInfoData
+{
+  std::string   description;                 ///< Description of the test.
+  std::string   text;                        ///< Input text.
+  unsigned int  startIndex;                  ///< The index from where the model is updated.
+  unsigned int  numberOfCharacters;          ///< The number of characters to update.
+  unsigned int  numberOfParagraphs;          ///< The expected number of bidirectional paragraphs.
+  unsigned int* indices;                     ///< The expected indices to the first character of each paragraph.
+  unsigned int* numberOfParagraphCharacters; ///< The expected number of characters of each paragraph.
+  bool*         directions;                  ///< The expected direction of each paragraph.
+};
+
+struct BidiLineData
+{
+  unsigned int  characterIndex;
+  unsigned int  numberOfCharacters;
+  unsigned int* visualToLogical;
+};
+
+struct GetMirroredTextData
+{
+  std::string  description;        ///< Description of the test.
+  std::string  text;               ///< Input text.
+  unsigned int startIndex;         ///< The index from where the model is updated.
+  unsigned int numberOfCharacters; ///< The number of the characters.
+  std::string  mirroredText;       ///< The expected result.
+};
+
+struct GetCharactersDirectionData
+{
+  std::string  description;            ///< Description of the test.
+  std::string  text;                   ///< Input text.
+  unsigned int startIndex;             ///< The index from where the model is updated.
+  unsigned int numberOfCharacters;     ///< The number of characters.
+  bool*        directions;             ///< The expected directions.
+  bool         markupProcessorEnabled; ///< Enable markup processor to use markup text.
+};
+
+bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Clear the bidirectional paragraph info data.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+  if( 0u != data.numberOfCharacters )
+  {
+    ClearCharacterRuns( data.startIndex,
+                        data.startIndex + data.numberOfCharacters - 1u,
+                        bidirectionalInfo );
+  }
+
+  // 3) Call the SetBidirectionalInfo() function.
+  SetBidirectionalInfo( logicalModel->mText,
+                        logicalModel->mScriptRuns,
+                        logicalModel->mLineBreakInfo,
+                        data.startIndex,
+                        data.numberOfCharacters,
+                        bidirectionalInfo );
+
+  // 4) Compare with the expected results.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  if( data.numberOfParagraphs != bidirectionalInfo.Count() )
+  {
+    // Different number of expected bidirectional paragraphs.
+    std::cout << "  Different number of bidi paragraphs : " << bidirectionalInfo.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.numberOfParagraphs; ++index )
+  {
+    const BidirectionalParagraphInfoRun& run = bidirectionalInfo[index];
+
+    const CharacterDirection direction = bidirectionalSupport.GetParagraphDirection( run.bidirectionalInfoIndex );
+    if( direction != data.directions[index] )
+    {
+      std::cout << "  Different direction" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+
+    if( run.characterRun.characterIndex != data.indices[index] )
+    {
+      std::cout << "  Different index" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+    if( run.characterRun.numberOfCharacters != data.numberOfParagraphCharacters[index] )
+    {
+      std::cout << "  Different number of characters" << std::endl;
+      std::cout << "        paragraph : " << index << std::endl;
+      std::cout << "            index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", direction : " << direction << std::endl;
+      std::cout << "  expected, index : " << data.indices[index] << ", num chars : " << data.numberOfParagraphCharacters[index] << ", direction : " << data.directions[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool GetMirroredTextTest( const GetMirroredTextData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Call the GetMirroredText() function for the whole text
+  Vector<Character> mirroredText;
+  bool mirrored = false;
+  mirrored = GetMirroredText( logicalModel->mText,
+                              logicalModel->mCharacterDirections,
+                              logicalModel->mBidirectionalParagraphInfo,
+                              0u,
+                              logicalModel->mText.Count(),
+                              mirroredText );
+
+  // 3) Call the GetMirroredText() function for the given index + number of characters
+  mirrored = GetMirroredText( logicalModel->mText,
+                              logicalModel->mCharacterDirections,
+                              logicalModel->mBidirectionalParagraphInfo,
+                              data.startIndex,
+                              data.numberOfCharacters,
+                              mirroredText );
+
+  // 4) Compare the results.
+
+  // Convert to utf8
+  std::string mirroredString;
+  Utf32ToUtf8( mirroredText.Begin(),
+               mirroredText.Count(),
+               mirroredString );
+
+  if( !mirrored && ( mirroredString != data.text ) )
+  {
+    std::cout << "  No mirrored text and mirroredString != data.text." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.text << "]" << std::endl;
+    return false;
+  }
+
+  if( mirrored && ( mirroredString == data.text ) )
+  {
+    std::cout << "  Mirrored text and mirroredString == data.text." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.text << "]" << std::endl;
+    return false;
+  }
+
+  if( mirrored && ( mirroredString != data.mirroredText ) )
+  {
+    std::cout << "  Mirrored text and mirroredString != data.mirroredText." << std::endl;
+    std::cout << "  mirrored string : [" << mirroredString << "]" << std::endl;
+    std::cout << "             text : [" << data.mirroredText << "]" << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool GetCharactersDirectionTest( const GetCharactersDirectionData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  // Create the model.
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   data.markupProcessorEnabled );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
+
+  // 2) Clear the direction info data.
+  Vector<CharacterDirection>& directions = logicalModel->mCharacterDirections;
+
+  if( directions.Count() >= data.startIndex + data.numberOfCharacters )
+  {
+    directions.Erase( directions.Begin() + data.startIndex,
+                      directions.Begin() + data.startIndex + data.numberOfCharacters );
+  }
+
+  // 3) Call GetCharactersDirection() function.
+
+  GetCharactersDirection( bidirectionalInfo,
+                          logicalModel->mText.Count(),
+                          data.startIndex,
+                          data.numberOfCharacters,
+                          directions );
+
+  for( unsigned int index = 0u; index < logicalModel->mText.Count(); ++index )
+  {
+    if( data.directions[index] != directions[index] )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetBidirectionalInfo(void)
+{
+  tet_infoline(" UtcDaliSetBidirectionalInfo");
+
+  unsigned int indices01[] = {};
+  unsigned int numberOfCharacters01[] = {};
+  bool         direction01[] = {};
+  unsigned int indices02[] = {};
+  unsigned int numberOfCharacters02[] = {};
+  bool         direction02[] = {};
+  unsigned int indices03[] = { 17u, 48u };
+  unsigned int numberOfCharacters03[] = { 14u, 14u };
+  bool         direction03[] = { true, true };
+  unsigned int indices04[] = { 17u, 31u, 79u };
+  unsigned int numberOfCharacters04[] = { 14u, 48u, 31u };
+  bool         direction04[] = { true, false, true };
+  unsigned int indices05[] = { 17u, 41u, 117u };
+  unsigned int numberOfCharacters05[] = { 24u, 76u, 49u };
+  bool         direction05[] = { true, false, true };
+  unsigned int indices06[] = { 17u, 48u };
+  unsigned int numberOfCharacters06[] = { 14u, 14u };
+  bool         direction06[] = { true, true };
+  unsigned int indices07[] = { 17u, 31u, 79u };
+  unsigned int numberOfCharacters07[] = { 14u, 48u, 31u };
+  bool         direction07[] = { true, false, true };
+  unsigned int indices08[] = { 17u, 41u, 117u };
+  unsigned int numberOfCharacters08[] = { 24u, 76u, 49u };
+  bool         direction08[] = { true, false, true };
+
+  struct SetBidirectionalInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      0u,
+      indices01,
+      numberOfCharacters01,
+      direction01
+    },
+    {
+      "Some left to right paragraphs",
+      "Hello world\ndemo\n\n",
+      0u,
+      18u,
+      0u,
+      indices02,
+      numberOfCharacters02,
+      direction02
+    },
+    {
+      "A mix of left to right and right to left paragraphs.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+      0u,
+      78u,
+      2u,
+      indices03,
+      numberOfCharacters03,
+      direction03
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+      0u,
+      126u,
+      3u,
+      indices04,
+      numberOfCharacters04,
+      direction04
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      0u,
+      182u,
+      3u,
+      indices05,
+      numberOfCharacters05,
+      direction05
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Updates a left to right paragraph.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo\nمرحبا بالعالم\nhello world demo",
+      31u,
+      17u,
+      2u,
+      indices06,
+      numberOfCharacters06,
+      direction06
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text.",
+      "Hello world demo\nمرحبا بالعالم\nhello world demo مرحبا بالعالم hello world demo\nمرحبا hello world demo بالعالم\nhello world demo",
+      0u,
+      126u,
+      3u,
+      indices07,
+      numberOfCharacters07,
+      direction07
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates initial paragraphs.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      0u,
+      41u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates mid paragraphs.",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      41u,
+      76u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+    {
+      "A mix of left to right and right to left paragraphs. Paragraphs also contain a mix of bidirectional text and a mix of right to left scripts. Updates from character 85",
+      "Hello world demo\nمرحبا שלום עולם بالعالم\nhello world שלום بالعالم עולם demo مرحبا שלום עולם بالعالم hello world demo\nمرحبا hello שלום بالعالم עולם world demo بالعالم\nhello world demo",
+      117u,
+      65u,
+      3u,
+      indices08,
+      numberOfCharacters08,
+      direction08
+    },
+  };
+  const unsigned int numberOfTests = 10u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !SetBidirectionalInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetMirroredText(void)
+{
+  tet_infoline(" UtcDaliGetMirroredText");
+
+  struct GetMirroredTextData data[] =
+  {
+    {
+      "Zero characters.",
+      "",
+      0u,
+      0u,
+      ""
+    },
+    {
+      "Left to right characters only.",
+      "Hello world\nhello world demo.",
+      0u,
+      29u,
+      "Hello world\nhello world demo."
+    },
+    {
+      "Right to left characters but with no characters to mirror.",
+      "שלום עולם\nمرحبا بالعالم",
+      0u,
+      23u,
+      "שלום עולם\nمرحبا بالعالم"
+    },
+    {
+      "Right to left characters with some characters to mirror.",
+      "שלום עולם\n(مرحبا بالعالم)",
+      0u,
+      25u,
+      "שלום עולם\n)مرحبا بالعالم("
+    },
+    {
+      "Right to left characters with some characters to mirror. Update last paragraph.",
+      "שלום עולם\n(مرحبا بالعالم)",
+      10u,
+      15u,
+      "שלום עולם\n)مرحبا بالعالم("
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs.",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      0u,
+      239u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום )hello) world demo )עולם(\nשלום )مرحبا بالعالم עולם( )hello("
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update middle paragraphs.",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      29u,
+      38u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום( עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update middle paragraphs (2).",
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם (hello) مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)",
+      67u,
+      100u,
+      "Hello world demo\nhello world\nhello world (مرحبا بالعالم שלום) עולם\nשלום مرحبا بالعالم עולם )hello( مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום (hello) world demo (עולם)\nשלום (مرحبا بالعالم עולם) (hello)"
+    },
+  };
+  const unsigned int numberOfTests = 8u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetMirroredTextTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetCharactersDirection(void)
+{
+  tet_infoline(" UtcDaliGetCharactersDirection");
+
+  bool directions01[] = {};
+  bool directions02[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false };
+  bool directions03[] = {
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true };
+  bool directions04[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  false, false, false, false, false, false,
+    false, false, false, false, false };
+  bool directions05[] = {
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  false, true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  false, false, false, false,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  true,  true,  true,  true,  true,  true,  true,  true,
+    true,  true,  false, false, false, false, false };
+
+    bool directions06[] = {
+    true,  true,  true,  true,  true,  true,  true,  true,  true, true,
+    false, false, false, false, false, false, false, false, false, false,
+    false, false, false, false, false, false };
+
+  struct GetCharactersDirectionData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      directions01,
+      false
+    },
+    {
+      "Left to right characters only",
+      "Hello world\nhello world demo",
+      0u,
+      28u,
+      directions02,
+      false
+    },
+    {
+      "Right to left characters only",
+      "שלום עולם\nשלום עולם",
+      0u,
+      19u,
+      directions03,
+      false
+    },
+    {
+      "Mix of bidirectional text",
+      "Hello world\nhello world שלום עולם\nשלום עולם hello world",
+      0u,
+      55u,
+      directions04,
+      false
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs.",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      0u,
+      227u,
+      directions05,
+      false
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update first paragraph.",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      0u,
+      17u,
+      directions05,
+      false
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update from character 29",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      29u,
+      134u,
+      directions05,
+      false
+    },
+    {
+      "Mix of bidirectional text. With more paragraphs. Update from character 163",
+      "Hello world demo\nhello world\nhello world مرحبا بالعالم שלום עולם\nשלום مرحبا بالعالم עולם hello مرحبا بالعالم world"
+      " مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
+      163u,
+      35u,
+      directions05,
+      false
+    },
+    {
+      "Mix of bidirectional text. With brackets and LRM",
+      "שלום עולם &lrm;(hello)[world]&lrm;",
+      0u,
+      26u,
+      directions06,
+      true
+    }
+  };
+  const unsigned int numberOfTests = 9u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetCharactersDirectionTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp
new file mode 100644 (file)
index 0000000..14cef1c
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017 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>
+#include <dali-toolkit/internal/helpers/color-conversion.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_color_conversion_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_color_conversion_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliPropertyHelperConvertHtmlStringToColor(void)
+{
+  tet_infoline( "Test to check whether An HTML style hex string can be converted" );
+
+  const std::string stringColor( "#FF0000" );
+
+  Vector4 result;
+  DALI_TEST_CHECK( Toolkit::Internal::ConvertStringToColor( stringColor, result ) );
+
+  DALI_TEST_EQUALS( result, Color::RED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperConvertStringPropertyToColor(void)
+{
+  tet_infoline( "Test to check whether A Property value containing a string can be converted" );
+
+  const std::string stringColor( "#00FF00" );
+  Property::Value colorProperty( stringColor );
+
+  Vector4 result;
+  DALI_TEST_CHECK( Toolkit::Internal::ConvertPropertyToColor( colorProperty, result ) );
+
+  DALI_TEST_EQUALS( result, Color::GREEN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperConvertVector4PropertyToColor(void)
+{
+  tet_infoline( "Test to check whether A Property value containing a string can be converted" );
+
+  const Vector4 color( 0.0, 0.0, 1.0, 1.0 );
+  Property::Value colorProperty( color );
+
+  Vector4 result;
+  DALI_TEST_CHECK( Toolkit::Internal::ConvertPropertyToColor( colorProperty, result ) );
+
+  DALI_TEST_EQUALS( result, Color::BLUE, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Control-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Control-internal.cpp
new file mode 100644 (file)
index 0000000..c7e8c39
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 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 <toolkit-text-utils.h>
+#include <dummy-visual.h>
+#include <../dali-toolkit/dali-toolkit-test-utils/dummy-control.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/control/control-debug.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+
+
+int UtcDaliControlActionOnVisual(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Register an ImageVisual and perform image reload Action on it. Tests Actions are completed." );
+  Vector2 controlSize( 20.f, 30.f );
+
+  //Created DummyVisual
+  Property::Map settings;
+  Toolkit::Internal::DummyVisualPtr dummyVisualPtr = Toolkit::Internal::DummyVisual::New( settings );
+
+  DummyControl dummyControl = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  tet_infoline( "Register test visual and stage control" );
+
+  Toolkit::Visual::Base visualBaseHandle = Toolkit::Visual::Base( dummyVisualPtr.Get() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visualBaseHandle );
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Check action counter is 0 before DoAction" );
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 0, TEST_LOCATION );
+
+  tet_infoline( "Perform TEST_ACTION action on registered test visual. Should increase the action counter" );
+
+  Property::Map attributes;
+  DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::Internal::DummyVisual::TEST_ACTION, attributes );
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlDebugHierarchy(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Create a control hierarchy, and test that the debug produces output" );
+
+  auto tableView = Toolkit::TableView::New(1, 2);
+  tableView.AddChild( ImageView::New( TEST_RESOURCE_DIR "/gallery-small-1.jpg" ), TableView::CellPosition( 1, 1 ) );
+  tableView.AddChild( TextLabel::New("Stuff"), TableView::CellPosition( 1, 2 ) );
+
+  Stage::GetCurrent().Add( tableView );
+
+  Property::Value v(Matrix3::IDENTITY);
+  tableView.RegisterProperty( "SomeMatrix3", v);
+
+  std::ostringstream oss;
+  Dali::Toolkit::Internal::DumpControlHierarchy( oss, Stage::GetCurrent().GetRootLayer() );
+  DALI_TEST_CHECK( oss.str().length() != 0 );
+  tet_printf("Control hierarchy: \n%s\n", oss.str().c_str() );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp
new file mode 100755 (executable)
index 0000000..8b119d4
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/text/text-visual.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <toolkit-environment-variable.h> // for setting environment variable: DALI_DEBUG_RENDERING
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* TEST_IMAGE_FILE_NAME =  "image_01.jpg";
+const char* TEST_NPATCH_FILE_NAME =  "image_01.9.jpg";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+void TestDebugVisual( Visual::Base& visual, Visual::Type actualType, Vector2 expectedNaturalSize )
+{
+  {
+    auto& impl = GetImplementation( visual );
+    DALI_TEST_CHECK( &typeid( Toolkit::Internal::WireframeVisual ) == &typeid( impl ) );
+  }
+
+  Vector2 naturalSize;
+  visual.GetNaturalSize( naturalSize );
+  DALI_TEST_EQUALS( naturalSize, expectedNaturalSize, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  Property::Map propertyMap;
+  visual.CreatePropertyMap( propertyMap );
+  Property::Value* typeValue = propertyMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  if ( typeValue )
+  {
+    DALI_TEST_CHECK( typeValue->Get<int>() == actualType );
+  }
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  Stage::GetCurrent().Add( actor );
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1, TEST_LOCATION );
+  if( actor.GetRendererCount() > 0 )
+  {
+    Geometry geometry = actor.GetRendererAt( 0 ).GetGeometry();
+    DALI_TEST_CHECK( geometry.GetType() == Geometry::LINES );
+  }
+}
+}
+
+void dali_debug_rendering_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_debug_rendering_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliDebugRenderingGetVisual1(void)
+{
+  EnvironmentVariable::SetTestingEnvironmentVariable(true);
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliDebugRenderingGetVisual1:  Request visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test that color visual is replaced with debug visual
+  Property::Map propertyMap1;
+  propertyMap1.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap1.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base colorVisual = factory.CreateVisual(propertyMap1);
+  DALI_TEST_CHECK( colorVisual );
+  TestDebugVisual( colorVisual, Visual::COLOR, Vector2::ZERO );
+
+  // Test that border visual is replaced with debug visual
+  Property::Map propertyMap2;
+  propertyMap2.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  propertyMap2.Insert(BorderVisual::Property::COLOR,  Color::BLUE);
+  propertyMap2.Insert(BorderVisual::Property::SIZE,  2.f);
+  Visual::Base borderVisual = factory.CreateVisual(propertyMap2);
+  DALI_TEST_CHECK( borderVisual );
+  TestDebugVisual( borderVisual, Visual::BORDER, Vector2::ZERO );
+
+  // Test that gradient visual is replaced with debug visual
+  Property::Map propertyMap3;
+  propertyMap3.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+  Vector2 start(-1.f, -1.f);
+  Vector2 end(1.f, 1.f);
+  propertyMap3.Insert(GradientVisual::Property::START_POSITION, start);
+  propertyMap3.Insert(GradientVisual::Property::END_POSITION, end);
+  propertyMap3.Insert(GradientVisual::Property::SPREAD_METHOD, GradientVisual::SpreadMethod::REPEAT);
+  Property::Array stopOffsets;
+  stopOffsets.PushBack( 0.2f );
+  stopOffsets.PushBack( 0.8f );
+  propertyMap3.Insert(GradientVisual::Property::STOP_OFFSET, stopOffsets);
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap3.Insert(GradientVisual::Property::STOP_COLOR, stopColors);
+  Visual::Base gradientVisual = factory.CreateVisual(propertyMap3);
+  DALI_TEST_CHECK( gradientVisual );
+  TestDebugVisual( gradientVisual, Visual::GRADIENT, Vector2::ZERO );
+
+  // Test that image visual is replaced with debug visual
+  Property::Map propertyMap4;
+  propertyMap4.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap4.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap4.Insert( ImageVisual::Property::DESIRED_WIDTH,  50.f );
+  propertyMap4.Insert( ImageVisual::Property::DESIRED_HEIGHT,  100.f );
+  Visual::Base imageVisual = factory.CreateVisual( propertyMap4 );
+  DALI_TEST_CHECK( imageVisual );
+  TestDebugVisual( imageVisual, Visual::IMAGE, Vector2( 50.f, 100.f ) );
+
+  // Test that SVG visual is replaced with debug visual
+  // TEST_SVG_FILE:
+  //  <svg width="100" height="100">
+  //  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
+  //  </svg>
+  Property::Map propertyMap5;
+  propertyMap5.Insert( Toolkit::Visual::Property::TYPE, Visual::SVG );
+  propertyMap5.Insert( ImageVisual::Property::URL,  TEST_SVG_FILE_NAME );
+  Visual::Base svgVisual = factory.CreateVisual( propertyMap5 );
+  DALI_TEST_CHECK( svgVisual );
+  TestDebugVisual( svgVisual, Visual::SVG, Vector2(100.f, 100.f) );
+
+  // Test that AnimatedImageVisual is replaced with debug visual
+  // TEST_GIF_FILE: anim.gif
+  // resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+  Property::Map propertyMap6;
+  propertyMap6.Insert( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE );
+  propertyMap6.Insert( ImageVisual::Property::URL,  TEST_GIF_FILE_NAME );
+  Visual::Base animatedImageVisual = factory.CreateVisual( propertyMap6 );
+  DALI_TEST_CHECK( animatedImageVisual );
+  TestDebugVisual( animatedImageVisual, Visual::ANIMATED_IMAGE, Vector2(50.f, 50.f) );
+
+  // Test that text visual is replaced with debug visual
+
+  // Load some fonts to get the same metrics on different platforms.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+  Property::Map propertyMap7;
+  propertyMap7.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap7.Insert( TextVisual::Property::ENABLE_MARKUP, true );
+  propertyMap7.Insert( TextVisual::Property::TEXT, "<font family='TizenSans' size='12'>Hello world</font>" );
+  propertyMap7.Insert( TextVisual::Property::MULTI_LINE, true );
+
+  Visual::Base textVisual = factory.CreateVisual( propertyMap7 );
+  DALI_TEST_CHECK( textVisual );
+  {
+    auto&& impl = GetImplementation( textVisual );
+    DALI_TEST_CHECK( &typeid( Toolkit::Internal::WireframeVisual ) == &typeid( impl ) );
+  }
+
+  Vector2 naturalSize;
+  textVisual.GetNaturalSize( naturalSize );
+  DALI_TEST_EQUALS( naturalSize, Vector2( 78.f, 20.f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  const float height = textVisual.GetHeightForWidth( 40.f );
+  DALI_TEST_EQUALS( height, 38.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Test that NPatchVisual is replaced with debug visual
+  // TEST_NPATCH_FILE_NAME: image_01.9.jpg
+  Property::Map propertyMap8;
+  propertyMap8.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap8.Insert( ImageVisual::Property::URL,  TEST_NPATCH_FILE_NAME );
+  Visual::Base nPatchVisual = factory.CreateVisual( propertyMap8 );
+  DALI_TEST_CHECK( nPatchVisual );
+  TestDebugVisual( nPatchVisual, Visual::N_PATCH, Vector2::ZERO );
+
+  EnvironmentVariable::SetTestingEnvironmentVariable(false);
+  END_TEST;
+}
+
+int UtcDaliDebugRenderingGetVisual2(void)
+{
+  EnvironmentVariable::SetTestingEnvironmentVariable(true);
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliDebugRenderingGetVisual2: Request visual with various parameters" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test that color visual is replaced with debug visual
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::COLOR;
+  map[ ColorVisual::Property::MIX_COLOR ] = Color::CYAN;
+
+  Visual::Base colorVisual = factory.CreateVisual( map);
+  DALI_TEST_CHECK( colorVisual );
+  TestDebugVisual( colorVisual, Visual::COLOR, Vector2::ZERO );
+
+  // Test that border visual is replaced with debug visual
+  map.Clear();
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::BORDER;
+  map[ BorderVisual::Property::COLOR  ] = Color::GREEN;
+  map[ BorderVisual::Property::SIZE   ] = 2.f;
+  Visual::Base borderVisual = factory.CreateVisual( map );
+  DALI_TEST_CHECK( borderVisual );
+  TestDebugVisual( borderVisual, Visual::BORDER, Vector2::ZERO );
+
+  // Test that image visual is replaced with debug visual
+  Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME);
+  Visual::Base imageVisual = factory.CreateVisual( image );
+  DALI_TEST_CHECK( imageVisual );
+  TestDebugVisual( imageVisual, Visual::IMAGE, Vector2::ZERO);
+
+  // Test that n patch visual is replaced with debug visual
+  Visual::Base nPatchVisual = factory.CreateVisual( TEST_NPATCH_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( nPatchVisual );
+  TestDebugVisual( nPatchVisual, Visual::N_PATCH, Vector2::ZERO );
+
+  EnvironmentVariable::SetTestingEnvironmentVariable(false);
+  END_TEST;
+}
+
+int UtcDaliDebugRenderingGetVisualObject01(void)
+{
+  EnvironmentVariable::SetTestingEnvironmentVariable( true );
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  tet_infoline( "Create a TextVisual when debugging is enabled, thus creating a proxy Wireframe Visual" );
+
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::TEXT;
+  map[ TextVisual::Property::TEXT ] = "Hello";
+
+  Visual::Base textVisual = factory.CreateVisual( map);
+  DALI_TEST_CHECK( textVisual );
+
+  tet_infoline( "Check that GetVisualObject returns the actual TextVisual" );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( textVisual ).GetVisualObject();
+  DALI_TEST_CHECK( dynamic_cast< Toolkit::Internal::TextVisual* >( &visualImpl ) );
+
+  tet_infoline( "Compare the returned TextVisual with the visual implementation, should differ" );
+  DALI_TEST_CHECK( textVisual.GetObjectPtr() != &visualImpl );
+
+  END_TEST;
+}
+
+int UtcDaliDebugRenderingGetVisualObject02(void)
+{
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  tet_infoline( "Create a TextVisual without debugging enabled, thus no proxy Wireframe Visual" );
+
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::TEXT;
+  map[ TextVisual::Property::TEXT ] = "Hello";
+
+  Visual::Base textVisual = factory.CreateVisual( map);
+  DALI_TEST_CHECK( textVisual );
+
+  tet_infoline( "Check that GetVisualObject returns the actual TextVisual" );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( textVisual ).GetVisualObject();
+  DALI_TEST_CHECK( dynamic_cast< Toolkit::Internal::TextVisual* >( &visualImpl ) );
+
+  tet_infoline( "Compare the returned TextVisual with the visual implementation, should be the same" );
+  DALI_TEST_CHECK( textVisual.GetObjectPtr() == &visualImpl );
+
+  END_TEST;
+}
+
+int UtcDaliDebugRenderingGetVisualObject03(void)
+{
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  tet_infoline( "Create a WireframeVisual without debugging enabled, thus no proxy Wireframe Visual either" );
+
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::WIREFRAME;
+
+  Visual::Base textVisual = factory.CreateVisual( map);
+  DALI_TEST_CHECK( textVisual );
+
+  tet_infoline( "Check that GetVisualObject returns the WireframeVisual" );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( textVisual ).GetVisualObject();
+  DALI_TEST_CHECK( dynamic_cast< Toolkit::Internal::WireframeVisual* >( &visualImpl ) );
+
+  tet_infoline( "Compare the returned Visual with the visual implementation, should be the same" );
+  DALI_TEST_CHECK( textVisual.GetObjectPtr() == &visualImpl );
+
+  END_TEST;
+}
+
+int UtcDaliDebugRenderingRenderText(void)
+{
+  EnvironmentVariable::SetTestingEnvironmentVariable( true );
+  ToolkitTestApplication application;
+  tet_infoline( "Ensure we can render text when in debug mode" );
+
+  try
+  {
+    Toolkit::TextLabel label = TextLabel::New( "Hello" );
+    Stage::GetCurrent().Add( label );
+    DALI_TEST_CHECK( true );
+  } catch( ... )
+  {
+    DALI_TEST_CHECK( false );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-FeedbackStyle.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-FeedbackStyle.cpp
new file mode 100644 (file)
index 0000000..202c87f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020 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/internal/feedback/feedback-style.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/adaptor-framework/feedback-player.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Sets the return value of the FeedbackPlayer::LoadFile() method of the stub implementation.
+ *
+ * Used to improve the line coverage.
+ *
+ * @param[in] feedbackPlayer The FeedbackPlayer singleton.
+ * @param[in] returnValue The desired return value for the FeedbackPlayer::LoadFile() method. Either true or false.
+ */
+void SetLoadFileReturnValue( Dali::FeedbackPlayer feedbackPlayer, bool returnValue );
+
+}
+
+}
+
+}
+
+int UtcDaliFeedbackStyle(void)
+{
+  // Not too much to test. Just to improve coverage.
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliFeedbackStyle");
+
+  try
+  {
+    Toolkit::Internal::FeedbackStyle feedbackStyle;
+
+    Dali::FeedbackPlayer feedbackPlayer = Dali::FeedbackPlayer::Get();
+    Dali::Internal::Adaptor::SetLoadFileReturnValue(feedbackPlayer, false);
+
+    Toolkit::Internal::FeedbackStyle feedbackStyle2;
+
+    Dali::Internal::Adaptor::SetLoadFileReturnValue(feedbackPlayer, true);
+  }
+  catch(...)
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-ItemView-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-ItemView-internal.cpp
new file mode 100755 (executable)
index 0000000..3ca8d0a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+const unsigned int TOTAL_ITEM_NUMBER = 200;
+const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
+
+
+// Implementation of ItemFactory for providing actors to ItemView
+class TestItemFactory : public ItemFactory
+{
+public:
+
+  /**
+   * Constructor
+   * @param application class, stored as reference
+   */
+  TestItemFactory()
+  {
+  }
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~TestItemFactory()
+  {
+  }
+
+public: // From ItemFactory
+
+  /**
+   * Query the number of items available from the factory.
+   * The maximum available item has an ID of GetNumberOfItems() - 1.
+   */
+  virtual unsigned int GetNumberOfItems()
+  {
+    return TOTAL_ITEM_NUMBER;
+  }
+
+  /**
+   * Create an Actor to represent a visible item.
+   * @param itemId
+   * @return the created actor.
+   */
+  virtual Actor NewItem(unsigned int itemId)
+  {
+    // Create a renderable actor for this item
+    Image image = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+    Actor actor = CreateRenderableActor(image);
+
+    return actor;
+  }
+};
+
+}
+
+int UtcDaliItemLayoutCheckPropertiesSetBeforeActivateLayout(void)
+{
+  ToolkitTestApplication application;
+
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  Property::Map gridLayoutProperty;
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::GRID) );
+
+  //Set the column of grid-layout.
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_COLUMN_NUMBER, Dali::Property::Value(6) );
+
+  Property::Array layoutArray;
+
+  layoutArray.PushBack(gridLayoutProperty);
+
+  view.SetProperty( ItemView::Property::LAYOUT, layoutArray );
+
+  Dali::Toolkit::Internal::GridLayout* gridLayout = dynamic_cast<Dali::Toolkit::Internal::GridLayout*>(view.GetLayout(0).Get());
+
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Vector3 stageSize(stage.GetSize());
+
+  //Check if the number of columns is equals to 6 which is set before.
+  DALI_TEST_EQUALS(gridLayout->GetNumberOfColumns(), 6, TEST_LOCATION );
+  view.ActivateLayout(0, stageSize, 0.0f);
+  END_TEST;
+
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-LogicalModel.cpp
new file mode 100755 (executable)
index 0000000..7cbbe90
--- /dev/null
@@ -0,0 +1,1189 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void CreateParagraphInfo( CharacterIndex startIndex,
+//                           Length numberOfCharacters );
+// void FindParagraphs( CharacterIndex index,
+//                      Length numberOfCharacters,
+//                      Vector<ParagraphRunIndex>& paragraphs );
+// bool FetchBidirectionalLineInfo( CharacterIndex characterIndex )
+// CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
+// CharacterIndex GetLogicalCursorIndex( CharacterIndex visualCursorIndex ) const;
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct CreateParagraphData
+{
+  std::string    description;                    ///< Description of the test.
+  std::string    text;                           ///< Input text.
+  CharacterIndex index;                          ///< The first character index.
+  Length         numberOfCharacters;             ///< The number of characters.
+  unsigned int   numberOfParagraphs;             ///< The expected number of paragraphs.
+  unsigned int*  indices;                        ///< The expected paragraph info indices.
+  unsigned int*  numberOfCharactersPerParagraph; ///< The expected number of characters of each paragraph.
+};
+
+struct FindParagraphData
+{
+  std::string    description;        ///< Description of the test.
+  std::string    text;               ///< Input text.
+  CharacterIndex index;              ///< The first character index.
+  Length         numberOfCharacters; ///< The number of characters.
+  unsigned int   numberOfParagraphs; ///< The expected number of paragraphs.
+  unsigned int*  paragraphs;         ///< The expected paragraph info.
+};
+
+struct FetchBidirectionalLineInfoData
+{
+  std::string   description;    ///< Description of the test.
+  std::string   text;           ///< Input text.
+  unsigned int  numberOfTests;  ///< The number of tests.
+  unsigned int* characterIndex; ///< The logical character index.
+  bool*         fetched;        ///< Whether the expected bidi line exists.
+  unsigned int* bidiLineIndex;  ///< Index to the expected bidi line.
+};
+
+struct GetLogicalCharacterIndexData
+{
+  std::string   description;        ///< Description of the test.
+  std::string   text;               ///< Input text.
+  Size          textArea;           ///< The text area.
+  unsigned int  numberOfIndices;    ///< The number of characters to set.
+  unsigned int* visualToLogical;    ///< The expected visual to logical conversion table.
+  unsigned int* cachedBidiLine;     ///< The cached bidi line index for each character.
+};
+
+struct GetLogicalCursorIndexData
+{
+  std::string         description;        ///< Description of the test.
+  std::string         text;               ///< Input text.
+  Size                textArea;           ///< The text area.
+  unsigned int        numberOfFonts;      ///< The number of fonts.
+  FontDescriptionRun* fontDescriptions;   ///< The font descriptions.
+  unsigned int        numberOfIndices;    ///< The number of characters to set.
+  unsigned int*       visualCursorIndex;  ///< The given cursor visual index.
+  unsigned int*       characterIndex;     ///< Index to the first logical character of the line.
+  unsigned int*       logicalCursorIndex; ///< The expected cursor logical index.
+  unsigned int*       cachedBidiLine;     ///< The cached bidi line index for each character.
+};
+
+bool CreateParagraphTest( const CreateParagraphData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Clear the paragraphs.
+  Vector<ParagraphRun>& paragraphs = logicalModel->mParagraphInfo;
+  ClearCharacterRuns( data.index,
+                      data.index + data.numberOfCharacters - 1u,
+                      paragraphs );
+
+  // 3) Call the LogicalModel::CreateParagraphInfo() method
+  logicalModel->CreateParagraphInfo( data.index,
+                                     data.numberOfCharacters );
+
+  // 4) Compare the results.
+  if( data.numberOfParagraphs != paragraphs.Count() )
+  {
+    std::cout << "  Different number of paragraphs : " << paragraphs.Count() << ", expected : " << data.numberOfParagraphs << std::endl;
+    return false;
+  }
+
+  unsigned int index = 0u;
+  for( Vector<ParagraphRun>::ConstIterator it = paragraphs.Begin(),
+         endIt = paragraphs.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const ParagraphRun& paragraph( *it );
+
+    if( data.indices[index] != paragraph.characterRun.characterIndex )
+    {
+      std::cout << "  Different character index for paragraph : " << index << ", " << paragraph.characterRun.characterIndex << ", expected : " << data.indices[index] << std::endl;
+      return false;
+    }
+    if( data.numberOfCharactersPerParagraph[index] != paragraph.characterRun.numberOfCharacters )
+    {
+      std::cout << "  Different number of characters for paragraph : " << index << ", " << paragraph.characterRun.numberOfCharacters << ", expected : " << data.numberOfCharactersPerParagraph[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool FindParagraphTest( const FindParagraphData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Find the paragraphs.
+  Vector<ParagraphRunIndex> paragraphs;
+  logicalModel->FindParagraphs( data.index, data.numberOfCharacters, paragraphs );
+
+  // 3) compare the results.
+  if( data.numberOfParagraphs != paragraphs.Count() )
+  {
+    return false;
+  }
+
+  unsigned int index = 0u;
+  for( Vector<ParagraphRunIndex>::ConstIterator it = paragraphs.Begin(),
+         endIt = paragraphs.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const ParagraphRunIndex paragraphIndex = *it;
+
+    if( paragraphIndex != data.paragraphs[index] )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool FetchBidirectionalLineInfoTest( const FetchBidirectionalLineInfoData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+  // Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea( 100.f, 300.f );
+  Size layoutSize;
+
+  // Create the model with the whole text.
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    const bool fetched = logicalModel->FetchBidirectionalLineInfo( data.characterIndex[index] );
+
+    if( fetched != data.fetched[index] )
+    {
+      std::cout << "  Different fetched result : " << fetched << ", expected : " << data.fetched[index] << std::endl;
+      return false;
+    }
+
+    if( fetched )
+    {
+      if( logicalModel->mBidirectionalLineIndex != data.bidiLineIndex[index] )
+      {
+        std::cout << "  Different bidi line index : " << logicalModel->mBidirectionalLineIndex << ", expected : " << data.bidiLineIndex << std::endl;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool GetLogicalCharacterIndexTest( const GetLogicalCharacterIndexData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+  // Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size layoutSize;
+
+  // Create the model with the whole text.
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   data.textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0u; index < data.numberOfIndices; ++index )
+  {
+    // Check the current cached bidi line index. (Check it before call the GetLogicalCharacterIndex() method )
+    if( data.cachedBidiLine[index] != logicalModel->mBidirectionalLineIndex )
+    {
+      std::cout << "  index : " << index << ", different cached bidi index : " << logicalModel->mBidirectionalLineIndex << ", expected : " << data.cachedBidiLine[index] << std::endl;
+      return false;
+    }
+
+    const bool fetched = logicalModel->FetchBidirectionalLineInfo( index );
+    const Character logicalIndex = fetched ? logicalModel->GetLogicalCharacterIndex( index ) : index;
+
+    if( data.visualToLogical[index] != logicalIndex )
+    {
+      std::cout << "  visual index : " << index << ", different logical index : " << logicalIndex << ", expected : " << data.visualToLogical[index] << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+bool GetLogicalCursorIndexTest( const GetLogicalCursorIndexData& data )
+{
+  tet_printf( "  testing : %s\n", data.description.c_str() );
+
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+
+  // Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size layoutSize;
+
+  // Create the model with the whole text.
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  if( 0u != data.numberOfFonts )
+  {
+    fontDescriptionRuns.Insert( fontDescriptionRuns.End(),
+                                data.fontDescriptions,
+                                data.fontDescriptions + data.numberOfFonts );
+  }
+
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   data.textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0u; index < data.numberOfIndices; ++index )
+  {
+    const bool fetched = logicalModel->FetchBidirectionalLineInfo( data.characterIndex[index] );
+    tet_printf("  fetched %d, line index %d, expected line index %d\n", fetched, logicalModel->mBidirectionalLineIndex, data.cachedBidiLine[index] );
+
+    if( logicalModel->mBidirectionalLineIndex != data.cachedBidiLine[index] )
+    {
+      tet_printf( "  test : %d, different cached line index : %d, expected : %d\n", index, logicalModel->mBidirectionalLineIndex, data.cachedBidiLine[index] );
+      return false;
+    }
+
+    const CharacterIndex visualCharacterIndex = data.visualCursorIndex[index];
+    const CharacterIndex logicalCursorIndex = fetched ? logicalModel->GetLogicalCursorIndex( visualCharacterIndex ) : visualCharacterIndex;
+    tet_printf("  visual index %d, logical index %d\n", visualCharacterIndex, logicalCursorIndex);
+
+    if( logicalCursorIndex != data.logicalCursorIndex[index] )
+    {
+      tet_printf( "  test : %d, visual index : %d, different logical cursor index :%d, expected : %d\n", index, visualCharacterIndex, logicalCursorIndex, data.logicalCursorIndex[index] );
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+//
+// UtcDaliCreateParagraph
+// UtcDaliFindParagraph
+// UtcDaliFetchBidirectionalLineInfo
+// UtcDaliGetLogicalCharacterIndex
+// UtcDaliGetLogicalCursorIndex
+//
+//////////////////////////////////////////////////////////
+
+int UtcDaliCreateParagraph(void)
+{
+  tet_infoline(" UtcDaliCreateParagraph");
+
+  unsigned int paragraphsIndices01[] = { 0u };
+  unsigned int paragraphsNumberOfCharacters01[] = { 0u };
+  unsigned int paragraphsIndices02[] = { 0u, 12u, 17u };
+  unsigned int paragraphsNumberOfCharacters02[] = { 12u, 5u, 1u };
+  unsigned int paragraphsIndices03[] = { 0u, 12u, 17u, 34u };
+  unsigned int paragraphsNumberOfCharacters03[] = { 12u, 5u, 17u ,1u };
+
+  struct CreateParagraphData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      0u,
+      paragraphsIndices01,
+      paragraphsNumberOfCharacters01,
+    },
+    {
+      "Some paragraphs",
+      "Hello world\ndemo\n\n",
+      0u,
+      18u,
+      3u,
+      paragraphsIndices02,
+      paragraphsNumberOfCharacters02,
+    },
+    {
+      "Some paragraphs. Update the initial paragraphs.",
+      "Hello world\ndemo\nhello world demo\n\n",
+      0u,
+      17u,
+      4u,
+      paragraphsIndices03,
+      paragraphsNumberOfCharacters03,
+    },
+    {
+      "Some paragraphs. Update the mid paragraphs.",
+      "Hello world\ndemo\nhello world demo\n\n",
+      12u,
+      5u,
+      4u,
+      paragraphsIndices03,
+      paragraphsNumberOfCharacters03,
+    },
+    {
+      "Some paragraphs. Update the final paragraphs.",
+      "Hello world\ndemo\nhello world demo\n\n",
+      17u,
+      18u,
+      4u,
+      paragraphsIndices03,
+      paragraphsNumberOfCharacters03,
+    },
+  };
+  const unsigned int numberOfTests = 5u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !CreateParagraphTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliFindParagraph(void)
+{
+  tet_infoline(" UtcDaliFindParagraph");
+
+  unsigned int paragraphs01[] = {};
+  unsigned int paragraphs02[] = { 0u, 1u, 2u };
+  unsigned int paragraphs03[] = { 0u };
+  unsigned int paragraphs04[] = { 1u };
+  unsigned int paragraphs05[] = { 0u, 1u, 2u };
+
+  struct FindParagraphData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      100u,
+      0u,
+      paragraphs01,
+    },
+    {
+      "Some paragraphs",
+      "Hello world\ndemo\n\n",
+      0u,
+      18u,
+      3u,
+      paragraphs02
+    },
+    {
+      "Some paragraphs",
+      "Hello world\ndemo\n\n",
+      0u,
+      12u,
+      1u,
+      paragraphs03
+    },
+    {
+      "Some paragraphs",
+      "Hello world\ndemo\n\n",
+      12u,
+      5u,
+      1u,
+      paragraphs04
+    },
+    {
+      "Some paragraphs",
+      "Hello world\ndemo\n\n",
+      3u,
+      15u,
+      3u,
+      paragraphs05
+    },
+  };
+  const unsigned int numberOfTests = 5u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !FindParagraphTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliFetchBidirectionalLineInfo(void)
+{
+  tet_infoline(" UtcDaliFetchBidirectionalLineInfo");
+
+  unsigned int logicalIndex01[] = { 0u };
+  bool fetched01[] = { false };
+  unsigned int bidiLine01[] = { 0u };
+
+  unsigned int logicalIndex02[] = { 3u };
+  bool fetched02[] = { false };
+  unsigned int bidiLine02[] = { 0u };
+
+  unsigned int logicalIndex03[] = { 0u, 11u, 12u, 21u, 22u, 33u, 34u, 43u, 44u, 54u};
+  bool fetched03[] = { false, false, true, true, false, false, true, true, false, false };
+  unsigned int bidiLine03[] = { 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 0u, 0u };
+
+  struct FetchBidirectionalLineInfoData data[] =
+  {
+    {
+      "Void text",
+      "",
+      1u,
+      logicalIndex01,
+      fetched01,
+      bidiLine01
+    },
+    {
+      "LTR text",
+      "Hello world",
+      1u,
+      logicalIndex02,
+      fetched02,
+      bidiLine02
+    },
+    {
+      "Bidi text",
+      "Hello world\nשלום עולם\nhello world\nשלום עולם\nhello world",
+      10u,
+      logicalIndex03,
+      fetched03,
+      bidiLine03
+    }
+  };
+  const unsigned int numberOfTests = 3u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !FetchBidirectionalLineInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetLogicalCharacterIndex(void)
+{
+  tet_infoline(" UtcDaliSetVisualToLogicalMap");
+
+  unsigned int visualToLogical01[] = {};
+  unsigned int  cachedBidiLine01[] = {};
+  unsigned int visualToLogical02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  unsigned int  cachedBidiLine02[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,  0u };
+  unsigned int visualToLogical03[] = { 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u };
+  unsigned int  cachedBidiLine03[] = {  0u,  0u,  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u };
+
+  unsigned int visualToLogical04[] = { 0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  cachedBidiLine04[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                       0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                       1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u };
+
+// size 300, 300
+// LO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _  h  e  l  l  o  _  w  o  r  l  d \n
+//      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
+// VO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _  h  e  l  l  o  _  w  o  r  l  d \n
+//      0  1  2  3  4  5  6  7  8  9 10 11 12 25 24 23 22 21 20 19 18 17 16 15 14 13 26 27 28 29 30 31 32 33 34 35 36 37 38 39
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _  h  e  l  l  o  _  w  o  r  l  d   ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
+// VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م  _  ,  h  e  l  l  o  _  w  o  r  l  d   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
+//     81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 55 56 57 58 59 60 61 62 63 64 65 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     82 83 84 85 86 87 88 89 90 91 92 93 94 95
+// VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
+//     95 94 93 92 91 90 89 88 87 86 85 84 83 82
+
+
+// LO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+// VO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+
+  unsigned int visualToLogical05[] = { 0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  cachedBidiLine05[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u };
+
+// size 300, 300
+// LO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _
+//      0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
+// VO   H  e  l  l  o  _  w  o  r  l  d  ,  _  م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _
+//      0  1  2  3  4  5  6  7  8  9 10 11 12 25 24 23 22 21 20 19 18 17 16 15 14 13 26 27
+
+// LO    h  e  l  l  o  _  w  o  r  l  d \n
+//      28 29 30 31 32 33 34 35 36 37 38 39
+// VO    h  e  l  l  o  _  w  o  r  l  d \n
+//      28 29 30 31 32 33 34 35 36 37 38 39
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _  h  e  l  l  o  _  w  o  r  l  d   ,  _
+//     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
+// VO  _  ,  h  e  l  l  o  _  w  o  r  l  d   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
+//     67 66 55 56 57 58 59 60 61 62 63 64 65 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     68 69 70 71 72 73 74 75 76 77 78 79 80 81
+// VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
+//     81 80 79 78 77 76 75 74 73 72 71 70 69 68
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     82 83 84 85 86 87 88 89 90 91 92 93 94 95
+// VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
+//     95 94 93 92 91 90 89 88 87 86 85 84 83 82
+
+
+// LO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+// VO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+
+  unsigned int visualToLogical06[] = { 0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u, 12u, 25u, 24u, 23u, 22u, 21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u, 43u, 42u, 41u, 40u, 67u, 66u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 81u, 80u, 79u, 78u, 77u, 76u, 75u, 74u, 73u, 72u, 71u, 70u, 69u, 68u, 95u, 94u, 93u, 92u, 91u, 90u, 89u, 88u, 87u, 86u, 85u, 84u, 83u, 82u, 96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u, 104u, 105u, 106u };
+  unsigned int  cachedBidiLine06[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                       0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                       1u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u,
+                                       2u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u, 3u,
+                                       3u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u,
+                                       4u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u, 5u,
+                                       5u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u,
+                                       6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u, 6u };
+
+// size 100, 600
+// LO   H  e  l  l  o  _  w  o  r  l  d  ,  _
+//      0  1  2  3  4  5  6  7  8  9 10 11 12
+// VO   H  e  l  l  o  _  w  o  r  l  d  ,  _
+//      0  1  2  3  4  5  6  7  8  9 10 11 12
+
+// LO    م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,   _
+//      13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
+// VO    م  ل  ا  ع   ل  ا  ب  _  ا   ب  ح  ر  م  ,   _
+//      25 24 23 22 21 20 19 18 17 16 15 14 13 26 27
+
+// LO    h  e  l  l  o  _  w  o  r  l  d \n
+//      28 29 30 31 32 33 34 35 36 37 38 39
+// VO    h  e  l  l  o  _  w  o  r  l  d \n
+//      28 29 30 31 32 33 34 35 36 37 38 39
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  ,  _
+//     40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
+// VO   _  ,  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
+//     54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
+
+// LO   h  e  l  l  o  _  w  o  r  l  d   ,  _
+//     55 56 57 58 59 60 61 62 63 64 65 66 67
+// VO   _  ,  h  e  l  l  o  _  w  o  r  l  d
+//     67 66 55 56 57 58 59 60 61 62 63 64 65
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     68 69 70 71 72 73 74 75 76 77 78 79 80 81
+// VO  \n  م  ل  ا   ع  ل  ا  ب  _  ا   ب  ح  ر  م
+//     81 80 79 78 77 76 75 74 73 72 71 70 69 68
+
+// LO   م  ر  ح  ب   ا  _  ب  ا  ل  ع   ا  ل  م  \n
+//     82 83 84 85 86 87 88 89 90 91 92 93 94 95
+// VO  \n  م  ل  ا  ع  ل   ا  ب  _  ا   ب  ح  ر  م
+//     95 94 93 92 91 90 89 88 87 86 85 84 83 82
+
+
+// LO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+// VO   h   e   l   l   o   _   w   o   r   l   d
+//     96  97  98  99 100 101 102 103 104 105 106
+
+  struct GetLogicalCharacterIndexData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      Size( 300.f, 300.f ),
+      0u,
+      visualToLogical01,
+      cachedBidiLine01
+    },
+    {
+      "Left to right text only",
+      "Hello world",
+      Size( 300.f, 300.f ),
+      11u,
+      visualToLogical02,
+      cachedBidiLine02
+    },
+    {
+      "Right to left text only",
+      "مرحبا بالعالم",
+      Size( 300.f, 300.f ),
+      13u,
+      visualToLogical03,
+      cachedBidiLine03
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      Size( 300.f, 300.f ),
+      107u,
+      visualToLogical04,
+      cachedBidiLine04
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      Size( 200.f, 400.f ),
+      107u,
+      visualToLogical05,
+      cachedBidiLine05
+    },
+    {
+      "Mix of left to right and right to left text.",
+      "Hello world, مرحبا بالعالم, hello world\nمرحبا بالعالم, hello world, مرحبا بالعالم\nمرحبا بالعالم\nhello world",
+      Size( 100.f, 600.f ),
+      107u,
+      visualToLogical06,
+      cachedBidiLine06
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetLogicalCharacterIndexTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetLogicalCursorIndex(void)
+{
+  tet_infoline(" UtcDaliGetLogicalCursorIndex");
+
+  const std::string fontFamily( "TizenSans" );
+  const std::string fontFamilyHebrew( "TizenSansHebrew" );
+
+
+
+  unsigned int visualIndex01[] = { 10u };
+  unsigned int characterIndex01[] = { 0u };
+  unsigned int logicalIndex01[] = { 10u };
+  unsigned int bidirectionalLineIndex01[] = { 0u };
+
+  //  0           11
+  //   Hello world  \n
+  // 12    16
+  //   demo
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 0u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 11u;
+  fontDescriptionRun02.familyLength = fontFamily.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns02;
+  fontDescriptionRuns02.PushBack( fontDescriptionRun02 );
+
+  unsigned int visualIndex02[] = { 0u, 16u, 11u, 12u };
+  unsigned int characterIndex02[] = { 0u, 0u, 0u, 0u };
+  unsigned int logicalIndex02[] = { 0u, 16u, 11u, 12u };
+  unsigned int bidirectionalLineIndex02[] = { 0u, 0u, 0u, 0u };
+
+// LO     H  e  l  l  o  _  w  o  r  l  d  \n
+//       0  1  2  3  4  5  6  7  8  9 10 11  12
+// VO     H  e  l  l  o  _  w  o  r  l  d  \n
+
+// LO         ש  ל  ו  ם  _  ע  ו  ל  ם \n
+//          12 13 14 15 16 17 18 19 20 21  22
+// VO     \n  ם  ל  ו  ע _  ם  ו  ל  ש
+
+// LO      h  e  l  l  o  _  w  o  r  l  d  _  ש  ל  ו  ם  _  ע ו  ל  ם  \n
+//       22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43  44
+// VO      h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש  \n
+
+// LO      ש  ל  ו  ם  _  ע  ו  ל  ם  _  h  e  l  l  o  _  w  o  r   l  d \n
+//       44 45 46 47 48 49 50 51  52 52 54 55 56 57 58 59 60 61 62 63  64 65 66
+// VO      \n h  e  l  l  o  _  w   o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש
+
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0301;
+  fontDescriptionRun0301.characterRun.characterIndex = 0u;
+  fontDescriptionRun0301.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun0301.familyLength = fontFamily.size();
+  fontDescriptionRun0301.familyName = new char[fontDescriptionRun0301.familyLength];
+  memcpy( fontDescriptionRun0301.familyName, fontFamily.c_str(), fontDescriptionRun0301.familyLength );
+  fontDescriptionRun0301.familyDefined = true;
+  fontDescriptionRun0301.weightDefined = false;
+  fontDescriptionRun0301.widthDefined = false;
+  fontDescriptionRun0301.slantDefined = false;
+  fontDescriptionRun0301.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0302;
+  fontDescriptionRun0302.characterRun.characterIndex = 12u;
+  fontDescriptionRun0302.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun0302.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0302.familyName = new char[fontDescriptionRun0302.familyLength];
+  memcpy( fontDescriptionRun0302.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0302.familyLength );
+  fontDescriptionRun0302.familyDefined = true;
+  fontDescriptionRun0302.weightDefined = false;
+  fontDescriptionRun0302.widthDefined = false;
+  fontDescriptionRun0302.slantDefined = false;
+  fontDescriptionRun0302.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0303;
+  fontDescriptionRun0303.characterRun.characterIndex = 22u;
+  fontDescriptionRun0303.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun0303.familyLength = fontFamily.size();
+  fontDescriptionRun0303.familyName = new char[fontDescriptionRun0303.familyLength];
+  memcpy( fontDescriptionRun0303.familyName, fontFamily.c_str(), fontDescriptionRun0303.familyLength );
+  fontDescriptionRun0303.familyDefined = true;
+  fontDescriptionRun0303.weightDefined = false;
+  fontDescriptionRun0303.widthDefined = false;
+  fontDescriptionRun0303.slantDefined = false;
+  fontDescriptionRun0303.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0304;
+  fontDescriptionRun0304.characterRun.characterIndex = 34u;
+  fontDescriptionRun0304.characterRun.numberOfCharacters = 20u;
+  fontDescriptionRun0304.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0304.familyName = new char[fontDescriptionRun0304.familyLength];
+  memcpy( fontDescriptionRun0304.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0304.familyLength );
+  fontDescriptionRun0304.familyDefined = true;
+  fontDescriptionRun0304.weightDefined = false;
+  fontDescriptionRun0304.widthDefined = false;
+  fontDescriptionRun0304.slantDefined = false;
+  fontDescriptionRun0304.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0305;
+  fontDescriptionRun0305.characterRun.characterIndex = 54u;
+  fontDescriptionRun0305.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun0305.familyLength = fontFamily.size();
+  fontDescriptionRun0305.familyName = new char[fontDescriptionRun0305.familyLength];
+  memcpy( fontDescriptionRun0305.familyName, fontFamily.c_str(), fontDescriptionRun0305.familyLength );
+  fontDescriptionRun0305.familyDefined = true;
+  fontDescriptionRun0305.weightDefined = false;
+  fontDescriptionRun0305.widthDefined = false;
+  fontDescriptionRun0305.slantDefined = false;
+  fontDescriptionRun0305.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns03;
+  fontDescriptionRuns03.PushBack( fontDescriptionRun0301 );
+  fontDescriptionRuns03.PushBack( fontDescriptionRun0302 );
+  fontDescriptionRuns03.PushBack( fontDescriptionRun0303 );
+  fontDescriptionRuns03.PushBack( fontDescriptionRun0304 );
+  fontDescriptionRuns03.PushBack( fontDescriptionRun0305 );
+
+  unsigned int visualIndex03[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u,
+                                   13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u,
+                                   22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 43u,
+                                   45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u, 66u };
+
+  unsigned int characterIndex03[] = {  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,
+                                      12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u, 12u,
+                                      22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u,
+                                      44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u};
+
+  unsigned int logicalIndex03[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u,
+                                    21u, 20u, 19u, 18u, 17u, 16u, 15u, 14u, 13u, 12u,
+                                    22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 42u, 41u, 40u, 39u, 38u, 37u, 36u, 35u, 43u,
+                                    65u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 54u, 53u, 52u, 51u, 50u, 49u, 48u, 47u, 46u, 45u, 44u };
+
+  unsigned int bidirectionalLineIndex03[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                              2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u };
+
+
+// LO     ש  ל  ו  ם  _  ע  ו  ל  ם \n
+//       0  1  2  3  4  5  6  7  8  9 10
+// VO  \n ם  ל  ו  ע  _  ם  ו  ל  ש
+
+//      h  e  l  l  o  _  w  o  r  l  d  \n
+// LO 10 11 12 13 14 15 16 17 18 19 20 21 22
+//      h  e  l  l  o  _  w  o  r  l  d  \n
+
+//         ש  ל  ו  ם  _  ע  ו  ל  ם _  h  e  l  l  o  _  w  o  r  l  d  \n
+// LO    22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
+//     \n  h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש
+
+//      h  e  l  l  o  _  w  o  r  l  d  _  ש  ל  ו  ם  _  ע  ו  ל  ם \n
+// LO 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
+//      h  e  l  l  o  _  w  o  r  l  d  _  ם  ל  ו  ע  _  ם  ו  ל  ש \n
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0401;
+  fontDescriptionRun0401.characterRun.characterIndex = 0u;
+  fontDescriptionRun0401.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun0401.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0401.familyName = new char[fontDescriptionRun0401.familyLength];
+  memcpy( fontDescriptionRun0401.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0401.familyLength );
+  fontDescriptionRun0401.familyDefined = true;
+  fontDescriptionRun0401.weightDefined = false;
+  fontDescriptionRun0401.widthDefined = false;
+  fontDescriptionRun0401.slantDefined = false;
+  fontDescriptionRun0401.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun0402;
+  fontDescriptionRun0402.characterRun.characterIndex = 10u;
+  fontDescriptionRun0402.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun0402.familyLength = fontFamily.size();
+  fontDescriptionRun0402.familyName = new char[fontDescriptionRun0402.familyLength];
+  memcpy( fontDescriptionRun0402.familyName, fontFamily.c_str(), fontDescriptionRun0402.familyLength );
+  fontDescriptionRun0402.familyDefined = true;
+  fontDescriptionRun0402.weightDefined = false;
+  fontDescriptionRun0402.widthDefined = false;
+  fontDescriptionRun0402.slantDefined = false;
+  fontDescriptionRun0402.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun0403;
+  fontDescriptionRun0403.characterRun.characterIndex = 22u;
+  fontDescriptionRun0403.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun0403.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0403.familyName = new char[fontDescriptionRun0403.familyLength];
+  memcpy( fontDescriptionRun0403.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0403.familyLength );
+  fontDescriptionRun0403.familyDefined = true;
+  fontDescriptionRun0403.weightDefined = false;
+  fontDescriptionRun0403.widthDefined = false;
+  fontDescriptionRun0403.slantDefined = false;
+  fontDescriptionRun0403.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun0404;
+  fontDescriptionRun0404.characterRun.characterIndex = 32u;
+  fontDescriptionRun0404.characterRun.numberOfCharacters = 24u;
+  fontDescriptionRun0404.familyLength = fontFamily.size();
+  fontDescriptionRun0404.familyName = new char[fontDescriptionRun0404.familyLength];
+  memcpy( fontDescriptionRun0404.familyName, fontFamily.c_str(), fontDescriptionRun0404.familyLength );
+  fontDescriptionRun0404.familyDefined = true;
+  fontDescriptionRun0404.weightDefined = false;
+  fontDescriptionRun0404.widthDefined = false;
+  fontDescriptionRun0404.slantDefined = false;
+  fontDescriptionRun0404.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun0405;
+  fontDescriptionRun0405.characterRun.characterIndex = 56u;
+  fontDescriptionRun0405.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun0405.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0405.familyName = new char[fontDescriptionRun0405.familyLength];
+  memcpy( fontDescriptionRun0405.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0405.familyLength );
+  fontDescriptionRun0405.familyDefined = true;
+  fontDescriptionRun0405.weightDefined = false;
+  fontDescriptionRun0405.widthDefined = false;
+  fontDescriptionRun0405.slantDefined = false;
+  fontDescriptionRun0405.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns04;
+  fontDescriptionRuns04.PushBack( fontDescriptionRun0401 );
+  fontDescriptionRuns04.PushBack( fontDescriptionRun0402 );
+  fontDescriptionRuns04.PushBack( fontDescriptionRun0403 );
+  fontDescriptionRuns04.PushBack( fontDescriptionRun0404 );
+  fontDescriptionRuns04.PushBack( fontDescriptionRun0405 );
+
+  unsigned int  visualIndex04[] = {  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u,
+                                    10u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u,
+                                    23u, 24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 43u, 44u,
+                                    44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u, 64u, 65u };
+
+  unsigned int characterIndex04[] = {  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,
+                                      10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 10u,
+                                      22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u, 22u,
+                                      44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u, 44u };
+
+  unsigned int logicalIndex04[] = {  9u,  8u,  7u,  6u,  5u,  4u,  3u,  2u,  1u,  0u,
+                                    10u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u,
+                                    43u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, 41u, 42u, 32u, 31u, 30u, 29u, 28u, 27u, 26u, 25u, 24u, 23u, 22u,
+                                    44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u, 56u, 64u, 63u, 62u, 61u, 60u, 59u, 58u, 57u, 65u };
+
+  unsigned int bidirectionalLineIndex04[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                              2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u, 2u };
+
+// LO   A  B  C  D  E  F  G  H  I  J  K
+//     0  1  2  3  4  5  6  7  8  9 10 11
+// LO   L  M  N
+//    11 12 13 14
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0501;
+  fontDescriptionRun0501.characterRun.characterIndex = 0u;
+  fontDescriptionRun0501.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun0501.familyLength = fontFamily.size();
+  fontDescriptionRun0501.familyName = new char[fontDescriptionRun0501.familyLength];
+  memcpy( fontDescriptionRun0501.familyName, fontFamily.c_str(), fontDescriptionRun0501.familyLength );
+  fontDescriptionRun0501.familyDefined = true;
+  fontDescriptionRun0501.weightDefined = false;
+  fontDescriptionRun0501.widthDefined = false;
+  fontDescriptionRun0501.slantDefined = false;
+  fontDescriptionRun0501.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns05;
+  fontDescriptionRuns05.PushBack( fontDescriptionRun0501 );
+
+  unsigned int  visualIndex05[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u,
+                                    11u, 12u, 13u, 14u };
+
+  unsigned int characterIndex05[] = { 0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,
+                                      11u, 11u, 11u, 11u };
+
+  unsigned int logicalIndex05[] = { 0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u,
+                                    11u, 12u, 13u, 14u };
+
+  unsigned int bidirectionalLineIndex05[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              0u, 0u, 0u, 0u };
+
+// LO      ק  ר  א  ט  ו  ן  ם  פ  ש  ד  ג  כ
+//        0  1  2  3  4  5  6  7  8  9  10 11 12
+// VO      כ  ג  ד  ש  פ  ם  ן  ו  ט  א  ר  ק
+
+// LO      ע  י  ח  ל
+//       12 13 14 15 16
+// VO      ל  ח  י  ע
+
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun0601;
+  fontDescriptionRun0601.characterRun.characterIndex = 0u;
+  fontDescriptionRun0601.characterRun.numberOfCharacters = 16u;
+  fontDescriptionRun0601.familyLength = fontFamilyHebrew.size();
+  fontDescriptionRun0601.familyName = new char[fontDescriptionRun0601.familyLength];
+  memcpy( fontDescriptionRun0601.familyName, fontFamilyHebrew.c_str(), fontDescriptionRun0601.familyLength );
+  fontDescriptionRun0601.familyDefined = true;
+  fontDescriptionRun0601.weightDefined = false;
+  fontDescriptionRun0601.widthDefined = false;
+  fontDescriptionRun0601.slantDefined = false;
+  fontDescriptionRun0601.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns06;
+  fontDescriptionRuns06.PushBack( fontDescriptionRun0601 );
+
+  unsigned int  visualIndex06[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u, 10u, 11u, 12u,
+                                    12u, 13u, 14u, 15u, 16u };
+
+  unsigned int characterIndex06[] = {  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,  0u,
+                                      12u, 12u, 12u, 12u, 12u };
+
+  unsigned int logicalIndex06[] = { 12u, 11u, 10u,  9u,  8u,  7u,  6u,  5u,  4u,  3u,  2u,  1u, 0u,
+                                    16u, 15u, 14u, 13u, 12u };
+
+  unsigned int bidirectionalLineIndex06[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+                                              1u, 1u, 1u, 1u, 1u, };
+
+  struct GetLogicalCursorIndexData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      Size( 300.f, 300.f ),
+      0u,
+      nullptr,
+      1u,
+      visualIndex01,
+      characterIndex01,
+      logicalIndex01,
+      bidirectionalLineIndex01,
+    },
+    {
+      "All left to right text 01.",
+      "Hello world\ndemo",
+      Size( 300.f, 300.f ),
+      1u,
+      fontDescriptionRuns02.Begin(),
+      4u,
+      visualIndex02,
+      characterIndex02,
+      logicalIndex02,
+      bidirectionalLineIndex02,
+    },
+    {
+      "bidirectional text 01.",
+      "Hello world\nשלום עולם\nhello world שלום עולם\nשלום עולם hello world\n",
+      Size( 300.f, 300.f ),
+      5u,
+      fontDescriptionRuns03.Begin(),
+      65u,
+      visualIndex03,
+      characterIndex03,
+      logicalIndex03,
+      bidirectionalLineIndex03,
+    },
+    {
+      "bidirectional text 02.",
+      "שלום עולם\nhello world\nשלום עולם hello world\nhello world שלום עולם\n",
+      Size( 300.f, 300.f ),
+      5u,
+      fontDescriptionRuns04.Begin(),
+      65u,
+      visualIndex04,
+      characterIndex04,
+      logicalIndex04,
+      bidirectionalLineIndex04,
+    },
+    {
+      "long line 01.",
+      "ABCDEFGHIJKLMN",
+      Size( 100.f, 300.f ),
+      1u,
+      fontDescriptionRuns05.Begin(),
+      13u,
+      visualIndex05,
+      characterIndex05,
+      logicalIndex05,
+      bidirectionalLineIndex05,
+    },
+    {
+      "bidirectional text 03.",
+      "קראטוןםפשדגכעיחל",
+      Size( 100.f, 300.f ),
+      1u,
+      fontDescriptionRuns06.Begin(),
+      18u,
+      visualIndex06,
+      characterIndex06,
+      logicalIndex06,
+      bidirectionalLineIndex06,
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetLogicalCursorIndexTest( data[index] ) )
+    {
+      tet_printf("Test %d failed : [%s]\n", index, data[index].description.c_str());
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp
new file mode 100644 (file)
index 0000000..58fc510
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017 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>
+#include <dali-toolkit/internal/helpers/property-helper.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_property_helper_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_property_helper_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliPropertyHelperGetStringFromPropertyWithString(void)
+{
+  tet_infoline( "Test to check if a simple string is parsed correctly" );
+
+  const std::string inputString = "Hello World";
+  Property::Value value( inputString );
+
+  std::string output;
+  DALI_TEST_CHECK( Toolkit::Internal::GetStringFromProperty( value, output ) );
+  DALI_TEST_EQUALS( output, inputString, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperGetStringFromPropertyWithEmptyValue(void)
+{
+  tet_infoline( "Test to ensure if an empty value returns false" );
+
+  std::string output;
+  DALI_TEST_CHECK( ! Toolkit::Internal::GetStringFromProperty( Property::Value(), output ) );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperGetStringFromPropertyWithStringArray(void)
+{
+  tet_infoline( "Test to check if a string array is parsed correctly and adds new line characters too" );
+
+  Property::Value value( Property::Array().Add( "Hello World" )
+                                          .Add( "The Quick Brown Fox" )
+                                          .Add( "Jumps over the lazy dog" ) );
+
+  std::string output;
+  DALI_TEST_CHECK( Toolkit::Internal::GetStringFromProperty( value, output ) );
+  DALI_TEST_CHECK( output.find( "Hello World\n" ) != std::string::npos );
+  DALI_TEST_CHECK( output.find( "The Quick Brown Fox\n" ) != std::string::npos );
+  DALI_TEST_CHECK( output.find( "Jumps over the lazy dog\n" ) != std::string::npos );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperGetStringFromPropertyWithEmptyArray(void)
+{
+  tet_infoline( "Test to check if an empty array returns false" );
+
+  Property::Array array;
+
+  std::string output;
+  DALI_TEST_CHECK( ! Toolkit::Internal::GetStringFromProperty( Property::Value( array ), output ) );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyHelperGetStringFromPropertyWithMultipleTypesInArray(void)
+{
+  tet_infoline( "Test to ensure an array with multiple types returns false" );
+
+  Property::Value value( Property::Array().Add( "Hello World" )
+                                          .Add( "The Quick Brown Fox" )
+                                          .Add( 1 )
+                                          .Add( "Jumps" )
+                                          .Add( 25 )
+                                          .Add( "Over" ) );
+
+  std::string output;
+  DALI_TEST_CHECK( ! Toolkit::Internal::GetStringFromProperty( value, output ) );
+  DALI_TEST_CHECK( output.empty() );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSetConversion.cpp
new file mode 100755 (executable)
index 0000000..f3725d2
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * 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 <iostream>
+
+#include <stdlib.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions for scripts with different number of bytes per character.
+// Latin 1 byte per character, Arabic 2 bytes per character, Devanagari 3 bytes per character and emojis 4 bytes per character.
+//
+// uint8_t GetUtf8Length( uint8_t utf8LeadByte );
+// uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length );
+// uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters );
+// uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 );
+// uint32_t Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 );
+//     void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std::string& utf8 );
+//
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct GetNumberOfUtf8CharactersData
+{
+  std::string  description;        ///< Description of the test.
+  std::string  text;               ///< input text.
+  unsigned int numberOfCharacters; ///< The expected number of characters.
+};
+
+bool GetNumberOfUtf8CharactersTest( const GetNumberOfUtf8CharactersData& data )
+{
+  return GetNumberOfUtf8Characters( reinterpret_cast<const uint8_t*>( data.text.c_str() ), data.text.size() ) == data.numberOfCharacters;
+}
+
+//////////////////////////////////////////////////////////
+
+struct GetNumberOfUtf8BytesData
+{
+  std::string   description;        ///< Description of the test.
+  unsigned int* utf32;              ///< input text in utf32.
+  unsigned int  numberOfCharacters; ///< The number of characters.
+  unsigned int  numberOfBytes;      ///< The expected number of bytes in utf8.
+};
+
+bool GetNumberOfUtf8BytesTest( const GetNumberOfUtf8BytesData& data )
+{
+  return GetNumberOfUtf8Bytes( data.utf32, data.numberOfCharacters ) == data.numberOfBytes;
+}
+
+//////////////////////////////////////////////////////////
+
+struct Utf8ToUtf32Data
+{
+  std::string   description; ///< Description of the test.
+  std::string   text;        ///< input text.
+  unsigned int* utf32;       ///< The expected text (array of bytes with text encoded in utf32).
+};
+
+
+bool Utf8ToUtf32Test( const Utf8ToUtf32Data& data )
+{
+  Vector<uint32_t> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   utf32.Begin() );
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    if( data.utf32[index] != utf32[index] )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+struct Utf32ToUtf8Data
+{
+  std::string   description;        ///< Description of the test.
+  unsigned int* utf32;              ///< The input text (array of bytes with text encoded in utf32).
+  unsigned int  numberOfCharacters; ///< The number of characters.
+  std::string   text;               ///< The expected text.
+};
+
+bool Utf32ToUtf8Test( const Utf32ToUtf8Data& data )
+{
+  std::string text;
+
+  Utf32ToUtf8( data.utf32, data.numberOfCharacters, text );
+
+  return text == data.text;
+}
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextCharacterSetConversionGetUtf8Length(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetUtf8Length");
+
+  // Copy of the table used to get the size in bytes of a character encoded with utf8.
+  // If the table used by the GetUtf8Length() function is updated, this one needs to be updated as well.
+  const static uint8_t U1 = 1u;
+  const static uint8_t U2 = 2u;
+  const static uint8_t U3 = 3u;
+  const static uint8_t U4 = 4u;
+  const static uint8_t U5 = 5u;
+  const static uint8_t U6 = 6u;
+  const static uint8_t U0 = 0u;
+  const static uint8_t UTF8_LENGTH[256] = {
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, // lead byte = 0xxx xxxx (U+0000 - U+007F + some extended ascii characters)
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1,                                 //
+
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, // lead byte = 110x xxxx (U+0080 - U+07FF)
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
+    U2, U2,                                 //
+
+    U3, U3, U3, U3, U3, U3, U3, U3, U3, U3, // lead byte = 1110 xxxx (U+0800 - U+FFFF)
+    U3, U3, U3, U3, U3, U3,                 //
+
+    U4, U4, U4, U4, U4, U4, U4, U4,         // lead byte = 1111 0xxx (U+10000 - U+1FFFFF)
+
+    U5, U5, U5, U5,                         // lead byte = 1111 10xx (U+200000 - U+3FFFFFF)
+
+    U6, U6,                                 // lead byte = 1111 110x (U+4000000 - U+7FFFFFFF)
+
+    U0, U0,                                 // Non valid.
+  };
+
+  for( unsigned int index = 0; index < 256u; ++index )
+  {
+    if( GetUtf8Length( index ) != UTF8_LENGTH[static_cast<uint8_t>(index)] )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+
+int UtcDaliTextCharacterSetConversionGetNumberOfUtf8Characters(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Characters");
+
+  const GetNumberOfUtf8CharactersData data[] =
+  {
+    {
+      "Latin script",
+      "Hello World",
+      11u,
+    },
+    {
+      "Arabic script",
+      "مرحبا بالعالم",
+      13u,
+    },
+    {
+      "Devanagari script",
+      "हैलो वर्ल्ड",
+      11u,
+    },
+    {
+      "Emojis",
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+      7u,
+    },
+    {
+      "5 bytes test",
+      "\xF8\xA0\x80\x80\x80",
+      1u,
+    },
+    {
+      "6 bytes test",
+      "\xFC\x84\x80\x80\x80\x80",
+      1u,
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetNumberOfUtf8CharactersTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes");
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_03[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_04[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+  unsigned int utf32_05[] = { 0x800000 };
+  unsigned int utf32_06[] = { 0x4000000 };
+
+  const GetNumberOfUtf8BytesData data[] =
+  {
+    {
+      "Latin script",
+      utf32_01,
+      11u,
+      11u,
+    },
+    {
+      "Arabic script",
+      utf32_02,
+      13u,
+      25u,
+    },
+    {
+      "Devanagari script",
+      utf32_03,
+      11u,
+      31u,
+    },
+    {
+      "Emojis",
+      utf32_04,
+      7u,
+      19u,
+    },
+    {
+      "5 bytes test",
+      utf32_05,
+      1u,
+      5u,
+    },
+    {
+      "6 bytes test",
+      utf32_06,
+      1u,
+      6u
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !GetNumberOfUtf8BytesTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionUtf8ToUtf32(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionGetNumberOfUtf8Bytes");
+
+  char utf8_06[] = { -2, -1 }; // Invalid string
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0xA, 0x20, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0xA, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World + CR and CR+LF
+  unsigned int utf32_03[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_04[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_05[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+  unsigned int utf32_06[] = { 0x800000 };
+  unsigned int utf32_07[] = { 0x4000000 };
+  unsigned int utf32_08[] = { 0x20, 0x20 }; // Invalid string
+
+  const Utf8ToUtf32Data data[] =
+  {
+    {
+      "Latin script",
+      "Hello World",
+      utf32_01,
+    },
+    {
+      "Latin script with 'CR' and 'CR'+'LF'",
+      "\xd Hello\xd\xa World",
+      utf32_02,
+    },
+    {
+      "Arabic script",
+      "مرحبا بالعالم",
+      utf32_03,
+    },
+    {
+      "Devanagari script",
+      "हैलो वर्ल्ड",
+      utf32_04,
+    },
+    {
+      "Emojis",
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+      utf32_05,
+    },
+    {
+      "5 bytes test",
+      "\xF8\xA0\x80\x80\x80",
+      utf32_06,
+    },
+    {
+      "6 bytes test",
+      "\xFC\x84\x80\x80\x80\x80",
+      utf32_07,
+    },
+    {
+      "Invalid text",
+      utf8_06,
+      utf32_08,
+    },
+  };
+  const unsigned int numberOfTests = 8u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !Utf8ToUtf32Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCharacterSetConversionUtf32ToUtf8(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCharacterSetConversionUtf32ToUtf8");
+
+  unsigned int utf32_01[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 }; // Hello World
+  unsigned int utf32_02[] = { 0x645, 0x631, 0x62D, 0x628, 0x627, 0x20, 0x628, 0x627, 0x644, 0x639, 0x627, 0x644, 0x645 }; // مرحبا بالعالم
+  unsigned int utf32_03[] = { 0x939, 0x948, 0x932, 0x94B, 0x20, 0x935, 0x930, 0x94D, 0x932, 0x94D, 0x921 }; // हैलो वर्ल्ड
+  unsigned int utf32_04[] = { 0x1F601, 0x20, 0x1F602, 0x20, 0x1F603, 0x20, 0x1F604 }; // Emojis
+  unsigned int utf32_05[] = { 0x800000 };
+  unsigned int utf32_06[] = { 0x4000000 };
+
+  struct Utf32ToUtf8Data data[] =
+  {
+    {
+      "Latin script",
+      utf32_01,
+      11u,
+      "Hello World",
+    },
+    {
+      "Arabic script",
+      utf32_02,
+      13u,
+      "مرحبا بالعالم",
+    },
+    {
+      "Devanagari script",
+      utf32_03,
+      11u,
+      "हैलो वर्ल्ड",
+    },
+    {
+      "Emojis",
+      utf32_04,
+      7u,
+      "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84",
+    },
+    {
+      "5 bytes test",
+      utf32_05,
+      1u,
+      "\xF8\xA0\x80\x80\x80",
+    },
+    {
+      "6 bytes test",
+      utf32_06,
+      1u,
+      "\xFC\x84\x80\x80\x80\x80",
+    },
+  };
+
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !Utf32ToUtf8Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp
new file mode 100755 (executable)
index 0000000..ae3afd2
--- /dev/null
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2019 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 <fstream>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali-toolkit/devel-api/text/text-utils-devel.h>
+#include <devel-api/adaptor-framework/image-loading.h>
+
+
+
+using namespace std;
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+namespace
+{
+const std::string TEST_IMAGE_FILE_NAME1 =  TEST_RESOURCE_DIR  "/application-icon-20.png";
+const std::string TEST_IMAGE_FILE_NAME2 =  TEST_RESOURCE_DIR  "/application-icon-26.png";
+
+const std::vector<std::string> embeddedItems = { TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2 };
+
+struct CircularTextData
+{
+  std::string                      description;
+  std::string                      text;
+  DevelText::RendererParameters&   textParameters;
+  const std::vector<std::string>&  embeddedItems;
+  bool                             blend:1;
+};
+
+
+bool CircularRenderTest( const CircularTextData& data )
+{
+  bool ret = true;
+
+  Dali::Vector<Dali::Toolkit::DevelText::EmbeddedItemInfo> embeddedItemLayout;
+
+  Devel::PixelBuffer pixelBuffer = Toolkit::DevelText::Render( data.textParameters, embeddedItemLayout );
+
+   const int dstWidth = static_cast<int>( pixelBuffer.GetWidth() );
+   const int dstHeight = static_cast<int>( pixelBuffer.GetHeight() );
+
+   unsigned int index = 0u;
+   for( const auto& itemLayout : embeddedItemLayout )
+   {
+     int width = static_cast<int>( itemLayout.size.width );
+     int height = static_cast<int>( itemLayout.size.height );
+     int x = static_cast<int>( itemLayout.position.x );
+     int y = static_cast<int>( itemLayout.position.y );
+
+     Dali::Devel::PixelBuffer itemPixelBuffer = Dali::LoadImageFromFile( data.embeddedItems[index++] );
+     itemPixelBuffer.Resize( width, height );
+     itemPixelBuffer.Rotate( itemLayout.angle );
+
+     width = static_cast<int>( itemPixelBuffer.GetWidth() );
+     height = static_cast<int>( itemPixelBuffer.GetHeight() );
+
+     Dali::Pixel::Format itemPixelFormat = itemPixelBuffer.GetPixelFormat();
+
+     // Check if the item is out of the buffer.
+     if( ( x + width < 0 ) ||
+         ( x > dstWidth ) ||
+         ( y < 0 ) ||
+         ( y - height > dstHeight ) )
+     {
+       // The embedded item is completely out of the buffer.
+       continue;
+     }
+
+     // Crop if it exceeds the boundaries of the destination buffer.
+     int layoutX = 0;
+     int layoutY = 0;
+     int cropX = 0;
+     int cropY = 0;
+     int newWidth = width;
+     int newHeight = height;
+
+     bool crop = false;
+
+     if( 0 > x )
+     {
+       newWidth += x;
+       cropX = std::abs( x );
+       crop = true;
+     }
+     else
+     {
+       layoutX = x;
+     }
+
+     if( cropX + newWidth > dstWidth )
+     {
+       crop = true;
+       newWidth -= ( ( cropX + newWidth ) - dstWidth );
+     }
+
+     layoutY = y;
+     if( 0.f > layoutY )
+     {
+       newHeight += layoutY;
+       cropY = std::abs(layoutY);
+       crop = true;
+     }
+
+     if( cropY + newHeight > dstHeight )
+     {
+       crop = true;
+       newHeight -= ( ( cropY + newHeight ) - dstHeight );
+     }
+
+     uint16_t uiCropX = static_cast<uint16_t>(cropX);
+     uint16_t uiCropY = static_cast<uint16_t>(cropY);
+     uint16_t uiNewWidth = static_cast<uint16_t>(newWidth);
+     uint16_t uiNewHeight = static_cast<uint16_t>(newHeight);
+
+     if( crop )
+     {
+       itemPixelBuffer.Crop( uiCropX, uiCropY, uiNewWidth, uiNewHeight );
+     }
+
+     // Blend the item pixel buffer with the text's color according its blending mode.
+     if( Dali::TextAbstraction::ColorBlendingMode::MULTIPLY == itemLayout.colorBlendingMode )
+     {
+       Dali::Devel::PixelBuffer buffer = Dali::Devel::PixelBuffer::New( uiNewWidth,
+                                                                        uiNewHeight,
+                                                                        itemPixelFormat );
+
+       unsigned char* bufferPtr = buffer.GetBuffer();
+       const unsigned char* itemBufferPtr = itemPixelBuffer.GetBuffer();
+       const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(itemPixelFormat);
+       const unsigned int size = uiNewWidth * uiNewHeight * bytesPerPixel;
+
+       for (unsigned int i = 0u; i < size; i += bytesPerPixel)
+       {
+         *(bufferPtr + 0u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 0u) ) * data.textParameters.textColor.r );
+         *(bufferPtr + 1u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 1u) ) * data.textParameters.textColor.g );
+         *(bufferPtr + 2u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 2u) ) * data.textParameters.textColor.b );
+         *(bufferPtr + 3u) = static_cast<unsigned char>( static_cast<float>( *(itemBufferPtr + 3u) ) * data.textParameters.textColor.a );
+
+         itemBufferPtr += bytesPerPixel;
+         bufferPtr += bytesPerPixel;
+       }
+
+       itemPixelBuffer = buffer;
+     }
+
+     Dali::Toolkit::DevelText::UpdateBuffer(itemPixelBuffer, pixelBuffer, layoutX, layoutY, data.blend);
+   }
+
+  return  ret;
+}
+
+} // namespace
+
+int UtcDaliTextCircularBitmapFont(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularBitmapFont");
+
+  Dali::Toolkit::DevelText::BitmapFontDescription description;
+  Dali::Toolkit::DevelText::Glyph glyph;
+  glyph.url = "BitmapFontUrl";
+  glyph.utf8[0u] = 0u;
+  glyph.utf8[1u] = 0u;
+  glyph.utf8[2u] = 0u;
+  glyph.utf8[3u] = 0u;
+  glyph.ascender = 1.f;
+  glyph.descender = 1.f;
+  description.glyphs.push_back( glyph );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  Dali::Toolkit::DevelText::CreateBitmapFont( description, bitmapFont );
+
+  for( const auto& bitmapGlyph : bitmapFont.glyphs )
+  {
+    if( glyph.url != bitmapGlyph.url )
+    {
+      std::cout << "  different output string : " << bitmapGlyph.url << ", expected : " << glyph.url << " " << std::endl;
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularShadowText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularShadowText");
+
+  Dali::Toolkit::DevelText::ShadowParameters shadowParameters;
+  Devel::PixelBuffer outPixelBuffer;
+  shadowParameters.input = Devel::PixelBuffer::New( 100, 100, Pixel::RGBA8888 );
+  shadowParameters.textColor = Color::BLACK;
+  shadowParameters.color =  Color::BLACK;
+  shadowParameters.offset.x = 10u;
+  shadowParameters.offset.y = 10u;
+  shadowParameters.blendShadow = true;
+  outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters );
+  DALI_TEST_CHECK( outPixelBuffer );
+  DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  shadowParameters.blendShadow = false;
+  outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters );
+  DALI_TEST_CHECK( outPixelBuffer );
+  DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  shadowParameters.input = Devel::PixelBuffer::New( 100, 100, Pixel::A8 );
+  outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters );
+  DALI_TEST_CHECK( outPixelBuffer );
+  DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularPixelBufferText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularPixelBufferText");
+
+  Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::A8 );
+  Vector4 color;
+  Devel::PixelBuffer pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, true );
+  pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, false );
+  DALI_TEST_CHECK( pixelBufferRgba );
+  DALI_TEST_EQUALS( pixelBufferRgba.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 );
+  pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, false );
+  DALI_TEST_CHECK( pixelBufferRgba );
+  DALI_TEST_EQUALS( pixelBufferRgba.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularNoText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularNoText");
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "";
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+
+  CircularTextData data =
+  {
+      "No text",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.text = "<item 'width'=26 'height'=26/>";
+  textParameters.markupEnabled = true;
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularIncrementAngle(void)
+{
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularIncrementAngle");
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 0.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+
+  CircularTextData data =
+  {
+      "IncrementAngle",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+
+
+int UtcDaliTextCircularMarkup(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularMarkup");
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = false;
+
+  CircularTextData data =
+  {
+      "Markup",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularFont(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularFont");
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "thin";
+  textParameters.fontWidth = "condensed";
+  textParameters.fontSlant = "normal";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "Font",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularAlignment(void)
+{
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularAlignment");
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "Alignment",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.horizontalAlignment = "begin";
+  textParameters.verticalAlignment = "top";
+  textParameters.circularAlignment = "begin";
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.horizontalAlignment = "end";
+  textParameters.verticalAlignment = "bottom";
+  textParameters.circularAlignment = "end";
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularRTL(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularRTL");
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "مرحبا بالعالم" + image1 + " hello world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "RTL",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.circularAlignment = "begin";
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.circularAlignment = "end";
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.text = "שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم";
+  textParameters.layout = "singleLine";
+  textParameters.horizontalAlignment = "end";
+  textParameters.fontSize = 90.f;
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularN(void)
+{
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextCircularN");
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "singleLine";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "singleLine",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.verticalAlignment = "top";
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.verticalAlignment = "bottom";
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.textWidth = 90u;
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularBlend(void)
+{
+  tet_infoline(" UtcDaliTextCircularN");
+
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+  stage.SetBackgroundColor( Color::WHITE );
+  stage.SetBackgroundColor( Vector4( 0.04f, 0.345f, 0.392f, 1.0f ) );
+
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "blend",
+      "",
+      textParameters,
+      embeddedItems,
+      false
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularEllipsis(void)
+{
+  tet_infoline(" UtcDaliTextCircularEllipsis");
+
+  ToolkitTestApplication application;
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = false;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "ellipsis",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  textParameters.layout = "singleLine";
+  textParameters.textHeight = 50u;
+  textParameters.ellipsisEnabled = true;
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularEmoji(void)
+{
+  tet_infoline(" UtcDaliTextCircularEmoji");
+
+  ToolkitTestApplication application;
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "<font family='BreezeColorEmoji' size='60'>\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84</font>";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "Emoji",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextUpdateBufferFormatCheck(void)
+{
+  tet_infoline(" UtcDaliTextUpdateBufferFormatCheck");
+  ToolkitTestApplication application;
+
+  Devel::PixelBuffer srcBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 );
+  Devel::PixelBuffer dstBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::A8 );
+
+  Dali::Toolkit::DevelText::UpdateBuffer(srcBuffer, dstBuffer, 0, 0, true);
+
+  Devel::PixelBuffer compressedSrcBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::COMPRESSED_R11_EAC );
+  Devel::PixelBuffer compressedDstBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::COMPRESSED_R11_EAC );
+  Dali::Toolkit::DevelText::UpdateBuffer(compressedSrcBuffer, compressedDstBuffer, 0, 0, true);
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularTextColor(void)
+{
+  tet_infoline(" UtcDaliTextCircularTextColor");
+
+  ToolkitTestApplication application;
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 + "'/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "hello " + image1 + " <color value='blue'>world</color> " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "textColor",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextCircularColorBlend(void)
+{
+  tet_infoline(" UtcDaliTextCircularColorBlend");
+
+  ToolkitTestApplication application;
+
+  const std::string image1 = "<item 'width'=26 'height'=26 'url'='" + TEST_IMAGE_FILE_NAME1 +  "' 'color-blending'=multiply/>";
+  const std::string image2 = "<item 'width'=26 'height'=26/>";
+
+  Dali::Toolkit::DevelText::RendererParameters textParameters;
+  textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons.";
+  textParameters.horizontalAlignment = "center";
+  textParameters.verticalAlignment = "center";
+  textParameters.circularAlignment = "center";
+  textParameters.fontFamily = "SamsungUI";
+  textParameters.fontWeight = "";
+  textParameters.fontWidth = "";
+  textParameters.fontSlant = "";
+  textParameters.layout = "circular";
+  textParameters.textColor = Color::BLACK;
+  textParameters.fontSize = 25.f;
+  textParameters.textWidth = 360u;
+  textParameters.textHeight = 360u;
+  textParameters.radius = 180u;
+  textParameters.beginAngle = 15.f;
+  textParameters.incrementAngle = 360.f;
+  textParameters.ellipsisEnabled = true;
+  textParameters.markupEnabled = true;
+
+  CircularTextData data =
+  {
+      "colorBlend",
+      "",
+      textParameters,
+      embeddedItems,
+      true
+  };
+
+  if( !CircularRenderTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp
new file mode 100755 (executable)
index 0000000..7275618
--- /dev/null
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2019 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 <limits>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+namespace
+{
+
+const char* const OPTION_SELECT_ALL("option-select_all");   // "Select All" popup option.
+const char* const OPTION_CUT("optionCut");                  // "Cut" popup option.
+const char* const OPTION_COPY("optionCopy");                // "Copy" popup option.
+const char* const OPTION_PASTE("optionPaste");              // "Paste" popup option.
+const char* const OPTION_CLIPBOARD("optionClipboard");      // "Clipboard" popup option.
+
+const Size CONTROL_SIZE( 300.f, 60.f );
+
+std::string gClipboardText;
+void ContentSelectedCallback( ClipboardEventNotifier& notifier )
+{
+  gClipboardText = notifier.GetContent();
+}
+
+// Generate a KeyEvent to send to Core.
+Dali::KeyEvent GenerateKey( const std::string& keyName,
+                            const std::string& keyString,
+                            int keyCode,
+                            int keyModifier,
+                            unsigned long timeStamp,
+                            const Dali::KeyEvent::State& keyState )
+{
+  return Dali::KeyEvent( keyName,
+                         keyString,
+                         keyCode,
+                         keyModifier,
+                         timeStamp,
+                         keyState );
+}
+
+} // namespace
+
+int UtcDaliTextController(void)
+{
+  tet_infoline(" UtcDaliTextController");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+  DALI_TEST_CHECK( controller );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetGetScrollEnabled(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetGetScrollEnabled");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+  DALI_TEST_CHECK( controller );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  DALI_TEST_CHECK( !controller->IsHorizontalScrollEnabled() );
+  DALI_TEST_CHECK( controller->IsVerticalScrollEnabled() );
+
+  // Configures the text controller similarly to the text-field.
+  ConfigureTextField( controller );
+
+  DALI_TEST_CHECK( controller->IsHorizontalScrollEnabled() );
+  DALI_TEST_CHECK( !controller->IsVerticalScrollEnabled() );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  DALI_TEST_CHECK( !controller->IsHorizontalScrollEnabled() );
+  DALI_TEST_CHECK( !controller->IsVerticalScrollEnabled() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetIsTextElide(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetIsTextElide");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+  DALI_TEST_CHECK( controller );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+  DALI_TEST_EQUALS( false, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  controller->SetTextElideEnabled( true );
+  DALI_TEST_EQUALS( true, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  // Configures the text controller similarly to the text-field.
+  ConfigureTextField( controller );
+  DALI_TEST_EQUALS( false, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  controller->SetTextElideEnabled( true );
+  DALI_TEST_EQUALS( true, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+  DALI_TEST_EQUALS( true, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  controller->SetTextElideEnabled( false );
+  DALI_TEST_EQUALS( false, controller->IsTextElideEnabled(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerEnableCursorBlinking(void)
+{
+  tet_infoline(" UtcDaliTextControllerEnableCursorBlinking");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+  DALI_TEST_CHECK( controller );
+
+  // There is no text input enabled.
+  DALI_TEST_CHECK( !controller->GetEnableCursorBlink() );
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Enables the cursor blink.
+  controller->SetEnableCursorBlink( true );
+
+  DALI_TEST_CHECK( controller->GetEnableCursorBlink() );
+
+  // Disables the cursor blink.
+  controller->SetEnableCursorBlink( false );
+
+  DALI_TEST_CHECK( !controller->GetEnableCursorBlink() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerImfEvent(void)
+{
+  tet_infoline(" UtcDaliTextController");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  std::string text;
+  InputMethodContext::EventData imfEvent;
+
+  DALI_TEST_CHECK( controller );
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the placeholder text.
+  controller->SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, "Hello Dali" );
+
+  // For coverage.
+  imfEvent = InputMethodContext::EventData( InputMethodContext::GET_SURROUNDING, "", 0, 0 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Send VOID event.
+  imfEvent = InputMethodContext::EventData( InputMethodContext::VOID, "", 0, 0 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  controller->GetText( text );
+  DALI_TEST_CHECK( text.empty() );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::COMMIT, "Hello ", 0, 6 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+  controller->GetNaturalSize();
+
+  // Check 'Delete All' key which means the input panel send a big range
+  imfEvent = InputMethodContext::EventData( InputMethodContext::DELETE_SURROUNDING, "", -100, 100 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "", text, TEST_LOCATION );
+
+  // Send COMMIT event.
+  imfEvent = InputMethodContext::EventData( InputMethodContext::COMMIT, "Hello ", 0, 6 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello ", text, TEST_LOCATION );
+
+  // Send PRE_EDIT event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  // Send DELETE_SURROUNDING event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::DELETE_SURROUNDING, "", -1, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello ", text, TEST_LOCATION );
+
+  // for coverage
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::UNDERLINE );
+
+  // Send PRE_EDIT event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "wo", 6, 2 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello wo", text, TEST_LOCATION );
+
+  // Send GET_SURROUNDING event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::GET_SURROUNDING, "", 0, 0 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello wo", text, TEST_LOCATION );
+
+  // Send PRIVATE_COMMAND event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRIVATE_COMMAND, "", 0, 0 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello wo", text, TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerImfPreeditStyle(void)
+{
+  tet_infoline(" UtcDaliTextControllerImfPreeditStyle");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  std::string text;
+  InputMethodContext::EventData imfEvent;
+
+  DALI_TEST_CHECK( controller );
+
+  // Configures the text controller similarly to the text-field.
+  ConfigureTextField( controller );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+
+  // Send COMMIT event.
+  imfEvent = InputMethodContext::EventData( InputMethodContext::COMMIT, "Hello ", 0, 6 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello ", text, TEST_LOCATION );
+
+  // Send PRE_EDIT event
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::NONE );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as REVERSE
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::REVERSE );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as HIGHLIGHT
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::HIGHLIGHT );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as CUSTOM_PLATFORM_STYLE_1
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1 );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as CUSTOM_PLATFORM_STYLE_2
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2 );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as CUSTOM_PLATFORM_STYLE_3
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3 );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  imfEvent = InputMethodContext::EventData( InputMethodContext::PRE_EDIT, "w", 6, 1 );
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Set the preedit style as CUSTOM_PLATFORM_STYLE_4
+  inputMethodContext.SetPreeditStyle( InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4 );
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_EQUALS( "Hello w", text, TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerTextPopupButtonTouched(void)
+{
+  tet_infoline(" UtcDaliTextControllerTextPopupButtonTouched");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  std::string text;
+  PushButton button;
+  Property::Map attributes;
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Creates the text's popup.
+  TextSelectionPopupCallbackInterface& callbackInterface = *controller;
+  TextSelectionPopup textPopup = TextSelectionPopup::New( &callbackInterface );
+
+  Toolkit::TextSelectionPopup::Buttons buttonsToEnable = static_cast<Toolkit::TextSelectionPopup::Buttons>( TextSelectionPopup::CUT        |
+                                                                                                            TextSelectionPopup::COPY       |
+                                                                                                            TextSelectionPopup::PASTE      |
+                                                                                                            TextSelectionPopup::SELECT     |
+                                                                                                            TextSelectionPopup::SELECT_ALL |
+                                                                                                            TextSelectionPopup::CLIPBOARD );
+
+  textPopup.EnableButtons( buttonsToEnable );
+  Stage::GetCurrent().Add( textPopup );
+  textPopup.ShowPopup();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Sets some text.
+  controller->SetText( "Hello world" );
+
+  // Select the whole text.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_SELECT_ALL ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Call relayout to process the input events.
+  controller->Relayout( CONTROL_SIZE );
+
+  // Cut the text.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_CUT ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_CHECK( text.empty() );
+
+  // Set text again.
+  controller->SetText( "Hello world" );
+
+  // Select the whole text.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_SELECT_ALL ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Call relayout to process the input events.
+  controller->Relayout( CONTROL_SIZE );
+
+  // Copy to the clipboard.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_COPY ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Call relayout to process the input events.
+  controller->Relayout( CONTROL_SIZE );
+
+  // Cut the text.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_CUT ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  controller->GetText( text );
+  DALI_TEST_CHECK( text.empty() );
+
+  ClipboardEventNotifier clipboardEventNotifier = ClipboardEventNotifier::Get();
+  clipboardEventNotifier.ContentSelectedSignal().Connect( &ContentSelectedCallback );
+
+  // Paste the text.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_PASTE ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  // Call relayout to process the input events.
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( "Hello world", gClipboardText, TEST_LOCATION );
+
+  // Show the clipboard.
+  button = PushButton::DownCast( textPopup.FindChildByName( OPTION_CLIPBOARD ) );
+  DALI_TEST_CHECK( button );
+
+  button.DoAction( "buttonClick", attributes );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerGetInputShadowProperty(void)
+{
+  tet_infoline(" UtcDaliTextControllerGetInputShadowProperty");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  const std::string& shadowProperties = controller->GetInputShadowProperties();
+
+  DALI_TEST_CHECK( shadowProperties.empty() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerGetInputUnderlineProperty(void)
+{
+  tet_infoline(" UtcDaliTextControllerGetInputUnderlineProperty");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  const std::string& underlineProperties = controller->GetInputUnderlineProperties();
+
+  DALI_TEST_CHECK( underlineProperties.empty() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetGetAutoScrollEnabled(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetGetAutoScrollEnabled");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  DALI_TEST_CHECK( !controller->IsAutoScrollEnabled() );
+
+  // The auto scrolling shouldn't be enabled if the multi-line is enabled.
+
+  // Enable multi-line.
+  controller->SetMultiLineEnabled( true );
+
+  // Enable text scrolling.
+  controller->SetAutoScrollEnabled( true );
+
+  DALI_TEST_CHECK( !controller->IsAutoScrollEnabled() );
+
+  // Disable multi-line.
+  controller->SetMultiLineEnabled( false );
+
+  // Enable text scrolling.
+  controller->SetAutoScrollEnabled( true );
+
+  // Should be ebabled now.
+  DALI_TEST_CHECK( controller->IsAutoScrollEnabled() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetGetCheckProperty(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetGetCheckProperty");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller, *controller );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  DALI_TEST_CHECK( !controller->IsInputModePassword() );
+
+  // Set the text input to password.
+  controller->SetInputModePassword( true );
+
+  DALI_TEST_CHECK( controller->IsInputModePassword() );
+
+  // Unset the text input to password.
+  controller->SetInputModePassword( false );
+
+  DALI_TEST_CHECK( !controller->IsInputModePassword() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetGetTapLongPressAction(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetGetTapLongPressAction");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  DALI_TEST_CHECK( controller );
+
+  // Test first with no decorator.
+
+  DALI_TEST_EQUALS( Controller::NoTextTap::NO_ACTION, controller->GetNoTextDoubleTapAction(), TEST_LOCATION );
+  controller->SetNoTextDoubleTapAction( Controller::NoTextTap::HIGHLIGHT );
+  DALI_TEST_EQUALS( Controller::NoTextTap::NO_ACTION, controller->GetNoTextDoubleTapAction(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Controller::NoTextTap::NO_ACTION, controller->GetNoTextLongPressAction(), TEST_LOCATION );
+  controller->SetNoTextLongPressAction( Controller::NoTextTap::HIGHLIGHT );
+  DALI_TEST_EQUALS( Controller::NoTextTap::NO_ACTION, controller->GetNoTextLongPressAction(), TEST_LOCATION );
+
+  // Add a decorator and re-test.
+
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller, *controller );
+
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  DALI_TEST_EQUALS( Controller::NoTextTap::NO_ACTION, controller->GetNoTextDoubleTapAction(), TEST_LOCATION );
+  controller->SetNoTextDoubleTapAction( Controller::NoTextTap::HIGHLIGHT );
+  DALI_TEST_EQUALS( Controller::NoTextTap::HIGHLIGHT, controller->GetNoTextDoubleTapAction(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Controller::NoTextTap::SHOW_SELECTION_POPUP, controller->GetNoTextLongPressAction(), TEST_LOCATION ); // The default is SHOW_SELECTION_POPUP
+  controller->SetNoTextLongPressAction( Controller::NoTextTap::HIGHLIGHT );
+  DALI_TEST_EQUALS( Controller::NoTextTap::HIGHLIGHT, controller->GetNoTextLongPressAction(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerSetGetLineSpacingProperty(void)
+{
+  tet_infoline(" UtcDaliTextControllerSetGetLineSpacingProperty");
+  ToolkitTestApplication application;
+
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+
+  // single line text
+  const std::string textSingle("A Quick Brown Fox Jumps Over The Lazy Dog");
+
+  // multi-line text
+  const std::string textMulti("A Quick Brown\nFox Jumps Over\nThe Lazy Dog");
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // single line, line spacing = 0px
+  {
+    const float EXPECTED_SPACING = 0.0f;
+    const Vector2 EXPECTED_LAYOUT_SIZE( 342.0f, 19.0f);
+    const Vector3 EXPECTED_NATURAL_SIZE( 342.0f, 20.0f, 0.0f );
+
+    controller->SetText(textSingle);
+    controller->Relayout(size);
+    controller->SetMultiLineEnabled( false );
+
+    Vector3 naturalSize  = controller->GetNaturalSize();
+    Vector2 layoutSize   = controller->GetTextModel()->GetLayoutSize();
+    float lineSpacing0 = controller->GetDefaultLineSpacing();
+
+    DALI_TEST_EQUALS( EXPECTED_SPACING, lineSpacing0, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_LAYOUT_SIZE, layoutSize, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, naturalSize, TEST_LOCATION );
+  }
+
+  // single line, line spacing = 20px
+  {
+    const float EXPECTED_SPACING = 20.0f;
+    const Vector2 EXPECTED_LAYOUT_SIZE( 342.0f, 19.0f );
+    const Vector3 EXPECTED_NATURAL_SIZE( 342.0f, 40.0f, 0.0f );
+
+    controller->SetText(textSingle);
+    controller->Relayout(size);
+    controller->SetDefaultLineSpacing( 20 );
+    controller->SetMultiLineEnabled( false );
+
+    Vector3 naturalSize  = controller->GetNaturalSize();
+    Vector2 layoutSize   = controller->GetTextModel()->GetLayoutSize();
+    float lineSpacing0 = controller->GetDefaultLineSpacing();
+
+    DALI_TEST_EQUALS( EXPECTED_SPACING, lineSpacing0, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_LAYOUT_SIZE, layoutSize, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, naturalSize, TEST_LOCATION );
+  }
+
+  // multi-line, line spacing = 0px
+  {
+    const float EXPECTED_SPACING = 0.0f;
+    const Vector2 EXPECTED_LAYOUT_SIZE( 332.0f, 39.0f );
+    const Vector3 EXPECTED_NATURAL_SIZE( 118.0f, 58.0f, 0.0f );
+
+    controller->SetText(textMulti);
+    controller->Relayout(size);
+    controller->SetMultiLineEnabled( true );
+    controller->SetDefaultLineSpacing( 0 );
+
+    Vector3 naturalSize  = controller->GetNaturalSize();
+    Vector2 layoutSize   = controller->GetTextModel()->GetLayoutSize();
+    float lineSpacing0 = controller->GetDefaultLineSpacing();
+
+    DALI_TEST_EQUALS( EXPECTED_SPACING, lineSpacing0, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_LAYOUT_SIZE, layoutSize, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, naturalSize, TEST_LOCATION );
+  }
+
+  // multi-line, line spacing = 20px
+  {
+    const float EXPECTED_SPACING = 20.0f;
+    const Vector2 EXPECTED_LAYOUT_SIZE( 118.0f, 57.0f );
+    const Vector3 EXPECTED_NATURAL_SIZE( 118.0f, 118.0f, 0.0f );
+
+    controller->SetText(textMulti);
+    controller->Relayout(size);
+    controller->SetMultiLineEnabled( true );
+    controller->SetDefaultLineSpacing( 20 );
+
+    Vector3 naturalSize  = controller->GetNaturalSize();
+    Vector2 layoutSize   = controller->GetTextModel()->GetLayoutSize();
+    float lineSpacing0 = controller->GetDefaultLineSpacing();
+
+    DALI_TEST_EQUALS( EXPECTED_SPACING, lineSpacing0, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_LAYOUT_SIZE, layoutSize, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, naturalSize, TEST_LOCATION );
+  }
+
+  // multi-line, line spacing = 30px
+  {
+    const float EXPECTED_SPACING = 30.0f;
+    const Vector2 EXPECTED_LAYOUT_SIZE( 118.0f, 117.0f );
+    const Vector3 EXPECTED_NATURAL_SIZE( 118.0f, 148.0f, 0.0f );
+
+    controller->SetText(textMulti);
+    controller->Relayout(size);
+    controller->SetMultiLineEnabled( true );
+    controller->SetDefaultLineSpacing( 30 );
+
+    Vector3 naturalSize  = controller->GetNaturalSize();
+    Vector2 layoutSize   = controller->GetTextModel()->GetLayoutSize();
+    float lineSpacing0 = controller->GetDefaultLineSpacing();
+
+    DALI_TEST_EQUALS( EXPECTED_SPACING, lineSpacing0, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_LAYOUT_SIZE, layoutSize, TEST_LOCATION );
+    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, naturalSize, TEST_LOCATION );
+  }
+
+
+  END_TEST;
+
+}
+
+int UtcDaliTextControllerCheckBufferIndices(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckBufferIndices");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Set the text
+  const std::string text("A Quick Brown Fox Jumps Over The Lazy Dog");
+  controller->SetText(text);
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Tweak some parameters to make the indices to access the text buffer invalid
+  mImpl.mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl.mModel->mLogicalModel->mText.Count() * 10u;
+  mImpl.mTextUpdateInfo.mNumberOfCharactersToRemove = 0u;
+  mImpl.mTextUpdateInfo.mPreviousNumberOfCharacters = 0u;
+  mImpl.mOperationsPending = Controller::ALL_OPERATIONS;
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputColorChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputColorChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText(text);
+
+  const Vector4 inputColor( 0.0f, 0.0f, 0.0f, 1.0f );
+  controller->SetInputColor( inputColor );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  //  Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input color
+  const Vector4 newInputColor( 1.0f, 0.0f, 0.0f, 1.0f );
+  controller->SetInputColor( newInputColor );
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::COLOR, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::COLOR ), TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputFontFamilyChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputFontFamilyChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text and font family
+  const std::string text("Hello World!");
+  controller->SetText(text);
+  controller->SetInputFontFamily("SamsungOneUI_200");
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  //  Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input font family
+  controller->SetInputFontFamily("SamsungOneUI_300");
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::VALIDATE_FONTS, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::VALIDATE_FONTS ),
+                    TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputFontWeightChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputFontWeightChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText(text);
+  controller->SetInputFontWeight( TextAbstraction::FontWeight::NORMAL );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input font weight
+  controller->SetInputFontWeight( TextAbstraction::FontWeight::BOLD );
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::VALIDATE_FONTS, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::VALIDATE_FONTS ),
+                    TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputFontWidthChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputFontWidthChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText(text);
+  controller->SetInputFontWidth( TextAbstraction::FontWidth::NORMAL );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input font width
+  controller->SetInputFontWidth( TextAbstraction::FontWidth::EXPANDED );
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::VALIDATE_FONTS, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::VALIDATE_FONTS ),
+                    TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputFontSlantChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputFontSlantChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText(text);
+  controller->SetInputFontSlant( TextAbstraction::FontSlant::NORMAL );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  //  Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input font slant
+  controller->SetInputFontSlant( TextAbstraction::FontSlant::ROMAN );
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::VALIDATE_FONTS, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::VALIDATE_FONTS ),
+                    TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerCheckInputFontPointSizeChanged(void)
+{
+  tet_infoline(" UtcDaliTextControllerCheckInputFontPointSizeChanged");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel(controller);
+
+  // Enable the text input.
+  // Creates a decorator.
+  Text::DecoratorPtr decorator = Text::Decorator::New( *controller,
+                                                       *controller );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  // Enables the text input.
+  controller->EnableTextInput( decorator, inputMethodContext );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText(text);
+  controller->SetInputFontPointSize( 1.0f );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  //  Reset operation
+  mImpl.mOperationsPending = Controller::NO_OPERATION;
+
+  // simulate a key event.
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Dali::KeyEvent::Down ) );
+
+  // change the input font point size
+  controller->SetInputFontPointSize( 1.2f );
+
+  // Check if relayout is requested or not when event state is INACTIVE.
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+  DALI_TEST_EQUALS( Controller::VALIDATE_FONTS, static_cast<Controller::OperationsMask>( mImpl.mOperationsPending & Controller::VALIDATE_FONTS ),
+                    TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerSelectEvent(void)
+{
+  tet_infoline(" UtcDaliTextControllerSelectEvent");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Configures the text controller similarly to the text-field.
+  ConfigureTextField( controller );
+
+  // Set the text
+  const std::string text("Hello World!");
+  controller->SetText( text );
+
+  // Select the whole text.
+  controller->SelectEvent( 0.f, 0.f, false );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout(size);
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Check if the whole text is selected or not.
+  std::string retrieved_text;
+  mImpl.RetrieveSelection( retrieved_text, false );
+  DALI_TEST_EQUALS( "Hello", retrieved_text, TEST_LOCATION );
+
+  // Select the whole text.
+  controller->SelectEvent( 0.f, 0.f, true );
+
+  // Perform a relayout
+  controller->Relayout( size );
+
+  mImpl.RetrieveSelection( retrieved_text, false );
+  DALI_TEST_EQUALS( text, retrieved_text, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTextControllerMaxLengthSetText(void)
+{
+  tet_infoline(" UtcDaliTextControllerMaxLengthSetText");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextLabel( controller );
+
+  const Length MAX_TEXT_LENGTH = 1024u * 32u;
+
+  // make over length world
+  int maxLength = ( 1024u * 32u ) + 10u;
+  char world[maxLength] = { 'a' };
+
+  // Set the text
+  std::string text( world, maxLength );
+  controller->SetText( text );
+
+  // check text length
+  controller->GetText( text );
+  Length textSize = text.size();
+
+  DALI_TEST_EQUALS( MAX_TEXT_LENGTH, textSize, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextControllerRemoveTextChangeEventData(void)
+{
+  tet_infoline(" UtcDaliTextControllerRemoveTextChangeEventData");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  ConfigureTextField( controller );
+
+  // Set the text
+  const std::string text( "Hello World!" );
+  controller->SetText( text );
+  controller->SetInputFontPointSize( 1.0f );
+
+  // Get the implementation of the text controller
+  Controller::Impl& mImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  DALI_TEST_EQUALS( EventData::INACTIVE, mImpl.mEventData->mState, TEST_LOCATION );
+
+  // Send DELETE_SURROUNDING event
+  InputMethodContext::EventData imfEvent = InputMethodContext::EventData( InputMethodContext::DELETE_SURROUNDING, "", -1, 1 );
+  InputMethodContext inputMethodContext = InputMethodContext::New();
+  controller->OnInputMethodContextEvent( inputMethodContext, imfEvent );
+
+  // Force to update the model.
+  controller->GetNaturalSize();
+
+  // Simulate a key event to delete text
+  controller->KeyEvent( GenerateKey( "", "", DALI_KEY_BACKSPACE, 0, 0, Dali::KeyEvent::Down ) );
+
+  DALI_TEST_EQUALS( EventData::EDITING, mImpl.mEventData->mState, TEST_LOCATION );
+
+  // Perform a relayout
+  const Size size( Dali::Stage::GetCurrent().GetSize() );
+  controller->Relayout( size );
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Cursor.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Cursor.cpp
new file mode 100755 (executable)
index 0000000..9c0842e
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+ * Copyright (c) 2017 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/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// LineIndex GetClosestLine( VisualModelPtr visualModel,
+//                           float visualY,
+//                           bool& isLineHit )
+// CharacterIndex GetClosestCursorIndex( VisualModelPtr visualModel,
+//                                       LogicalModelPtr logicalModel,
+//                                       MetricsPtr metrics,
+//                                       float visualX,
+//                                       float visualY,
+//                                       CharacterHitTest::Mode mode,
+//                                       bool& isCharacterHit )
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct GetClosestLineData
+{
+  std::string    description;                    ///< Description of the test.
+  std::string    text;                           ///< Input text.
+  unsigned int   numberOfTests;                  ///< The number of tests.
+  float*         visualY;                        ///< The visual 'y' position for each test.
+  LineIndex*     lineIndex;                      ///< The expected line index for each test.
+  bool*          isLineHit;                      ///< The expected line hit value for each test.
+};
+
+struct GetClosestCursorIndexData
+{
+  std::string             description;           ///< Description of the test.
+  std::string             text;                  ///< Input text.
+  unsigned int            numberOfTests;         ///< The number of tests.
+  float*                  visualX;               ///< The visual 'x' position for each test.
+  float*                  visualY;               ///< The visual 'y' position for each test.
+  CharacterHitTest::Mode* mode;                  ///< The type of hit test.
+  CharacterIndex*         logicalIndex;          ///< The expected logical cursor index for each test.
+  bool*                   isCharacterHit;        ///< The expected character hit value for each test.
+};
+
+struct GetCursorPositionData
+{
+  std::string     description;                    ///< Description of the test.
+  std::string     text;                           ///< Input text.
+  unsigned int    numberOfTests;                  ///< The number of tests.
+  CharacterIndex* logicalIndex;                   ///< The logical cursor index for each test.
+  float*          visualX;                        ///< The expected visual 'x' position for each test.
+  float*          visualY;                        ///< The expected visual 'y' position for each test.
+};
+
+struct FindSelectionIndicesData
+{
+  std::string     description;                    ///< Description of the test.
+  std::string     text;                           ///< Input text.
+  unsigned int    numberOfTests;                  ///< The number of tests.
+  float*          visualX;                        ///< The visual 'x' position for each test.
+  float*          visualY;                        ///< The visual 'y' position for each test.
+  bool*           found;                          ///< Whether selection indices are found.
+  CharacterIndex* startIndex;                     ///< The expected start cursor index for each test.
+  CharacterIndex* endIndex;                       ///< The expected end cursor index for each test.
+  CharacterIndex* noTextHitIndex;                 ///< The expected character index when there is no hit.
+};
+
+bool GetClosestLineTest( const GetClosestLineData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(400.f, 600.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    bool isLineHit = false;
+    const LineIndex lineIndex = GetClosestLine( visualModel,
+                                                data.visualY[index],
+                                                isLineHit );
+
+    if( lineIndex != data.lineIndex[index] )
+    {
+      std::cout << "  test " << index << " failed. Different line index : " << lineIndex << ", expected : " << data.lineIndex[index] << std::endl;
+      return false;
+    }
+    if( isLineHit != data.isLineHit[index] )
+    {
+      std::cout << "  test " << index << " failed. Different line hit value : " << isLineHit << ", expected : " << data.isLineHit[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool GetClosestCursorIndexTest( const GetClosestCursorIndexData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(400.f, 600.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    bool isCharacterHit = false;
+    const CharacterIndex logicalCursorIndex = GetClosestCursorIndex( visualModel,
+                                                                     logicalModel,
+                                                                     metrics,
+                                                                     data.visualX[index],
+                                                                     data.visualY[index],
+                                                                     data.mode[index],
+                                                                     isCharacterHit );
+
+    if( logicalCursorIndex != data.logicalIndex[index] )
+    {
+      std::cout << "  test " << index << " failed. Different logical cursor index : " << logicalCursorIndex << ", expected : " << data.logicalIndex[index] << std::endl;
+      return false;
+    }
+    if( isCharacterHit != data.isCharacterHit[index] )
+    {
+      std::cout << "  test " << index << " failed. Different character hit value : " << isCharacterHit << ", expected : " << data.isCharacterHit[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool GetCursorPositionTest( const GetCursorPositionData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(400.f, 600.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  GetCursorPositionParameters parameters;
+  parameters.visualModel = visualModel;
+  parameters.logicalModel = logicalModel;
+  parameters.metrics = metrics;
+  parameters.isMultiline = true;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    CursorInfo cursorInfo;
+    parameters.logical = data.logicalIndex[index];
+
+    GetCursorPosition( parameters,
+                       cursorInfo );
+
+    if( cursorInfo.primaryPosition.x != data.visualX[index] )
+    {
+      std::cout << "  test " << index << " failed. Different 'x' cursor position : " << cursorInfo.primaryPosition.x << ", expected : " << data.visualX[index] << std::endl;
+      return false;
+    }
+    if( cursorInfo.primaryPosition.y != data.visualY[index] )
+    {
+      std::cout << "  test " << index << " failed. Different 'y' cursor position : " << cursorInfo.primaryPosition.y << ", expected : " << data.visualY[index] << std::endl;
+       return false;
+    }
+  }
+
+  return true;
+}
+
+bool FindSelectionIndicesTest( const FindSelectionIndicesData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(400.f, 600.f);
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  for( unsigned int index = 0; index < data.numberOfTests; ++index )
+  {
+    CharacterIndex startIndex = 0;
+    CharacterIndex endIndex = 0;
+    CharacterIndex noTextHitIndex = 0;
+    const bool found = FindSelectionIndices( visualModel,
+                                             logicalModel,
+                                             metrics,
+                                             data.visualX[index],
+                                             data.visualY[index],
+                                             startIndex,
+                                             endIndex,
+                                             noTextHitIndex );
+
+    if( found != data.found[index] )
+    {
+      std::cout << "  test " << index << " failed. Different found value : " << found << ", expected : " <<  data.found[index] << std::endl;
+      return false;
+    }
+    if( startIndex != data.startIndex[index] )
+    {
+      std::cout << "  test " << index << " failed. Different start index : " << startIndex << ", expected : " << data.startIndex[index] << std::endl;
+      return false;
+    }
+    if( endIndex != data.endIndex[index] )
+    {
+      std::cout << "  test " << index << " failed. Different end index : " << endIndex << ", expected : " << data.endIndex[index] << std::endl;
+      return false;
+    }
+    if( noTextHitIndex != data.noTextHitIndex[index] )
+    {
+      std::cout << "  test " << index << " failed. Different no text hit index : " << noTextHitIndex << ", expected : " << data.noTextHitIndex[index] << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+//
+// UtcDaliGetClosestLine
+// UtcDaliGetClosestCursorIndex
+//
+//////////////////////////////////////////////////////////
+
+int UtcDaliGetClosestLine(void)
+{
+  tet_infoline(" UtcDaliGetClosestLine");
+
+  float visualY01[] = { -4.f, 3.f, 1000.f };
+  LineIndex lineIndices01[] = { 0, 0, 0 };
+  bool isLineHit01[] = { false, false, false };
+
+  float visualY02[] = { -4.f, 3.f, 1000.f };
+  LineIndex lineIndices02[] = { 0, 0, 0 };
+  bool isLineHit02[] = { false, true, false };
+
+  float visualY03[] = { -4.f, 11.f, 30.f, 51.f, 68.f, 87.f, 109.f, 130.f };
+  LineIndex lineIndices03[] = { 0, 0, 1u, 2u, 3u, 4u, 5u, 5u };
+  bool isLineHit03[] = { false, true, true, true, true, true, true, false };
+
+  struct GetClosestLineData data[] =
+  {
+    {
+      "void text.",
+      "",
+      3u,
+      visualY01,
+      lineIndices01,
+      isLineHit01
+    },
+    {
+      "Single line text.",
+      "hello world",
+      3u,
+      visualY02,
+      lineIndices02,
+      isLineHit02
+    },
+    {
+      "Multi-line text.",
+      "abcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuדאוvwxה"
+      "סתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuד"
+      "אוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqr"
+      "פרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmno"
+      "צמםpqrפרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjkl"
+      "חלךmnoצמםpqrפרףstuדאוvwxהסתyzטזץ",
+      8u,
+      visualY03,
+      lineIndices03,
+      isLineHit03
+    }
+  };
+  const unsigned int numberOfTests = 3u;
+
+  for( unsigned int index = 0; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetClosestLineTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetClosestCursorIndex(void)
+{
+  tet_infoline(" UtcDaliGetClosestCursorIndex");
+
+  float visualX01[] = { -100.f };
+  float visualY01[] = { -100.f };
+  CharacterHitTest::Mode mode01[] = { CharacterHitTest::TAP };
+  CharacterIndex logicalIndex01[] = { 0 };
+  bool isCharacterHit01[] = { false };
+
+  float visualX02[] = { -100.f, 1000.f, 60.f, 79.f, 83.f, 148.f, 99.f };
+  float visualY02[] = { -100.f, 1000.f, 12.f, 12.f, 12.f, 12.f, 12.f };
+  CharacterHitTest::Mode mode02[] = { CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP };
+  CharacterIndex logicalIndex02[] = { 0, 21u, 8u, 11u, 11u, 13u, 20u };
+  bool isCharacterHit02[] = { false, false, true, true, true, true, true  };
+
+  float visualX03[] = { 19.f, 104.f, -2.f, 127.f };
+  float visualY03[] = { 12.f, 12.f, 12.f, 12.f };
+  CharacterHitTest::Mode mode03[] = { CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP };
+  CharacterIndex logicalIndex03[] = { 3u, 12u, 0, 18u };
+  bool isCharacterHit03[] = { true, true, false, false };
+
+  //  0     5 _ 6     11  12
+  //   Hello     world  \n
+  // 12    16 _ 17    21   22
+  //   שלום       עולם  \n
+  // 22         31_32      40  41
+  //   different     الأربعاء  \n
+  float visualX04[] = { -100.f, 40.f, 44.f, 85.f, 500.f,
+                         500.f, 367.f, 359.f, 329.f, -100.f,
+                        -100.f, 19.f, 64.f, 72.f, 104.f, 111.f, 500.f};
+  float visualY04[] = { -100.f, 12.f, 12.f, 12.f, 12.f,
+                          30.f, 30.f, 30.f, 30.f, 30.f,
+                          50.f, 50.f, 50.f, 50.f, 50.f, 50.f, 50.f };
+  CharacterHitTest::Mode mode04[] = { CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP };
+  CharacterIndex logicalIndex04[] = {    0,  6u,  6u, 11u, 11u,
+                                       12u, 16u, 17u, 21u, 21u,
+                                       22u, 25u, 31u, 32u, 34u, 40u, 40u,
+                                       41u };
+  bool isCharacterHit04[] = { false, true, true, false, false,
+                              false, true, true, false, false,
+                              false, true, true, true, true, false, false };
+
+  //   0           10           20            30           40      46
+  //    abcשנבdefג   קכghiעיןjk   lחלךmnoצמם   pqrפרףstuד   אוvwxה
+  //  46     50            60            70           80               93
+  //    סתyz   טזץabcשנבd    efגקכghiעי    ןjklחלךmno   צמםpqrפרףstuד
+  //  93       100           110          120         130          139
+  //    אוvwxהס   תyzטזץabcש   נבdefגקכgh   iעיןjklחלך   mnoצמםpqr
+  // 139           150           160           170          180       186
+  //    פרףstuדאוvw   xהסתyzטזץa   bcשנבdefגק    כghiעיןjkl    חלךmno
+  // 186     190           200           210          220            233
+  //    צמםp   qrפרףstuדא    וvwxהסתyzט   זץabcשנבde   fגקכghiעיןjkl
+  // 233        240            250           260     265
+  //    חלךmnoצ    מםpqrפרףst   uדאוvwxהסת    yzטזץ
+
+  float visualX05[] = { -100.f, 96.f, 155.f, 250.f, 344.f, 500.f,
+                        -100.f, 36.f, 124.f, 190.f, 280.f, 500.f,
+                        -100.f, 56.f, 158.f, 237.f, 303.f, 500.f,
+                        -100.f, 98.f, 184.f, 261.f, 337.f, 500.f,
+                        -100.f, 40.f, 113.f, 223.f, 302.f, 500.f,
+                        -100.f, 82.f, 160.f, 253.f, 500.f };
+  float visualY05[] = { -100.f, 12.f, 12.f, 12.f, 12.f, 12.f,
+                        30.f, 30.f, 30.f, 30.f, 30.f, 30.f,
+                        50.f, 50.f, 50.f, 50.f, 50.f, 50.f,
+                        67.f, 67.f, 67.f, 67.f, 67.f, 67.f,
+                        87.f, 87.f, 87.f, 87.f, 87.f, 87.f,
+                        107.f, 107.f, 107.f, 107.f, 107.f };
+  CharacterHitTest::Mode mode05[] = { CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP };
+  CharacterIndex logicalIndex05[] = {    0,  10u,  20u,  30u,  40u,  46u,
+                                       47u,  52u,  62u,  71u,  82u,  93u,
+                                       94u,  99u, 112u, 122u, 131u, 140u,
+                                      141u, 153u, 162u, 171u, 181u, 187u,
+                                      188u, 194u, 201u, 213u, 222u, 234u,
+                                      236u, 244u, 254u, 263u, 265u };
+  bool isCharacterHit05[] = { false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, false };
+
+  //   0            10           20           30           40        46
+  //    שנבabcגקכd    efעיןghiחל   ךjklצמםmno   פרףpqrדאוs   tuהסתv
+  //  46     50           60          70            80              93
+  //    wxטז   ץyzשנבabcג   קכdefעיןgh   iחלךjklצמם   mnoפרףpqrדאוs
+  //  93        100          110          120           130           139
+  //    tuהסתvw   xטזץyzשנבa   bcגקכdefעי    ןghiחלךjkl    צמםmnoפרף
+  // 139           150           160          170         180       186
+  //    pqrדאוstuהס   תvwxטזץyzש   נבabcגקכde   fעיןghiחלך   jklצמם
+  // 186    190          200           210           220            232
+  //    mnoפ   רףpqrדאוst   uהסתvwxטזץ   yzשנבabcגק    כdefעיןghiחל
+  // 232         240           250           260     265
+  //    ךjklצמםm   noפרףpqrדא    וstuהסתvwx   טזץyz
+
+  float visualX06[] = { 500.f, 307.f, 237.f, 148.f, 55.f, -100.f,
+                        500.f, 362.f, 276.f, 213.f, 121.f, -100.f,
+                        500.f, 344.f, 238.f, 167.f, 93.f, -100.f,
+                        500.f, 306.f, 216.f, 142.f, 58.f, -100.f,
+                        500.f, 355.f, 279.f, 182.f, 92.f, -100.f,
+                        500.f, 326.f, 238.f, 150.f, -100.f };
+  float visualY06[] = { -100.f, 12.f, 12.f, 12.f, 12.f, 12.f,
+                        30.f, 30.f, 30.f, 30.f, 30.f, 30.f,
+                        50.f, 50.f, 50.f, 50.f, 50.f, 50.f,
+                        67.f, 67.f, 67.f, 67.f, 67.f, 67.f,
+                        87.f, 87.f, 87.f, 87.f, 87.f, 87.f,
+                        107.f, 107.f, 107.f, 107.f, 107.f };
+  CharacterHitTest::Mode mode06[] = { CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP,
+                                      CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP, CharacterHitTest::TAP };
+  CharacterIndex logicalIndex06[] = {    0,  10u,  20u,  30u,  40u,  45u,
+                                       46u,  50u,  60u,  70u,  80u,  92u,
+                                       93u, 100u, 110u, 120u, 130u, 138u,
+                                      139u, 150u, 160u, 170u, 180u, 185u,
+                                      186u, 190u, 200u, 210u, 220u, 231u,
+                                      232u, 240u, 250u, 260u, 265u  };
+  bool isCharacterHit06[] = { false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, true, false,
+                              false, true, true, true, false };
+
+  float visualX07[] = { 395.f };
+  float visualY07[] = { 12.f };
+  CharacterHitTest::Mode mode07[] = { CharacterHitTest::TAP };
+  CharacterIndex logicalIndex07[] = { 1u };
+  bool isCharacterHit07[] = { true };
+
+  float visualX08[] = { 7.f };
+  float visualY08[] = { 12.f };
+  CharacterHitTest::Mode mode08[] = { CharacterHitTest::TAP };
+  CharacterIndex logicalIndex08[] = { 2u };
+  bool isCharacterHit08[] = { true };
+
+  struct GetClosestCursorIndexData data[] =
+  {
+    {
+      "Void text.",
+      "",
+      1u,
+      visualX01,
+      visualY01,
+      mode01,
+      logicalIndex01,
+      isCharacterHit01
+    },
+    {
+      "Single line text.",
+      "Hello world שלום עולם",
+      7u,
+      visualX02,
+      visualY02,
+      mode02,
+      logicalIndex02,
+      isCharacterHit02
+    },
+    {
+      "Single line with ligatures",
+      "different الأربعاء",
+      4u,
+      visualX03,
+      visualY03,
+      mode03,
+      logicalIndex03,
+      isCharacterHit03
+    },
+    {
+      "Multiline. Single line paragraphs",
+      "Hello world\n"
+      "שלום עולם\n"
+      "different الأربعاء\n",
+      17u,
+      visualX04,
+      visualY04,
+      mode04,
+      logicalIndex04,
+      isCharacterHit04
+    },
+    {
+      "Multiline. Single bidirectional paragraph, starts LTR, wrapped lines",
+      "abcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuדאוvwxה"
+      "סתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqrפרףstuד"
+      "אוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmnoצמםpqr"
+      "פרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjklחלךmno"
+      "צמםpqrפרףstuדאוvwxהסתyzטזץabcשנבdefגקכghiעיןjkl"
+      "חלךmnoצמםpqrפרףstuדאוvwxהסתyzטזץ",
+      35u,
+      visualX05,
+      visualY05,
+      mode05,
+      logicalIndex05,
+      isCharacterHit05
+    },
+    {
+      "Multiline. Single bidirectional paragraph, starts RTL, wrapped lines",
+      "שנבabcגקכdefעיןghiחלךjklצמםmnoפרףpqrדאוstuהסתv"
+      "wxטזץyzשנבabcגקכdefעיןghiחלךjklצמםmnoפרףpqrדאוs"
+      "tuהסתvwxטזץyzשנבabcגקכdefעיןghiחלךjklצמםmnoפרף"
+      "pqrדאוstuהסתvwxטזץyzשנבabcגקכdefעיןghiחלךjklצמם"
+      "mnoפרףpqrדאוstuהסתvwxטזץyzשנבabcגקכdefעיןghiחל"
+      "ךjklצמםmnoפרףpqrדאוstuהסתvwxטזץyz",
+      35u,
+      visualX06,
+      visualY06,
+      mode06,
+      logicalIndex06,
+      isCharacterHit06
+    },
+    {
+      "Testing complex characters. Arabic ligatures",
+      "الأَبْجَدِيَّة العَرَبِيَّة",
+      1u,
+      visualX07,
+      visualY07,
+      mode07,
+      logicalIndex07,
+      isCharacterHit07
+    },
+    {
+      "Testing complex characters. Latin ligatures",
+      "fi ligature",
+      1u,
+      visualX08,
+      visualY08,
+      mode08,
+      logicalIndex08,
+      isCharacterHit08
+    }
+  };
+  const unsigned int numberOfTests = 8u;
+
+  for( unsigned int index = 0; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetClosestCursorIndexTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliGetCursorPosition(void)
+{
+  tet_infoline(" UtcDaliGetCursorPosition");
+
+  float visualX08[] = { 4.f };
+  float visualY08[] = { 0.f };
+  CharacterIndex logicalIndex08[] = { 1u };
+
+  struct GetCursorPositionData data[] =
+  {
+    {
+      "Testing complex characters. Latin ligatures",
+      "fi ligature",
+      1u,
+      logicalIndex08,
+      visualX08,
+      visualY08,
+    }
+  };
+  const unsigned int numberOfTests = 1u;
+
+  for( unsigned int index = 0; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !GetCursorPositionTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliFindSelectionIndices(void)
+{
+  tet_infoline(" UtcDaliFindSelectionIndices");
+
+  float visualX01[] = { -100.f };
+  float visualY01[] = { -100.f };
+  bool found01[] = { false };
+  CharacterIndex startIndex01[] = { 0 };
+  CharacterIndex endIndex01[] = { 0 };
+  CharacterIndex noHitText01[] = { 0 };
+
+  float visualX02[] = { -100.f, 1000.f, 1000.f };
+  float visualY02[] = { -100.f, 12.f, 1000.f };
+  bool found02[] = { false, false, false };
+  CharacterIndex startIndex02[] = { 0, 6u, 6u };
+  CharacterIndex endIndex02[] = { 5u, 11u, 11u };
+  CharacterIndex noHitText02[] = { 0, 11u, 11u };
+
+  float visualX03[] = { 70.f };
+  float visualY03[] = { 12.f };
+  bool found03[] = { true };
+  CharacterIndex startIndex03[] = { 6u };
+  CharacterIndex endIndex03[] = { 11u };
+  CharacterIndex noHitText03[] = { 0u };
+
+  float visualX04[] = { 131.f };
+  float visualY04[] = { 12.f };
+  bool found04[] = { true };
+  CharacterIndex startIndex04[] = { 12u };
+  CharacterIndex endIndex04[] = { 16u };
+  CharacterIndex noHitText04[] = { 0u };
+
+  float visualX05[] = { 0.f };
+  float visualY05[] = { 12.f };
+  bool found05[] = { true };
+  CharacterIndex startIndex05[] = { 0 };
+  CharacterIndex endIndex05[] = { 1u };
+  CharacterIndex noHitText05[] = { 0 };
+
+  float visualX06[] = { 10.f };
+  float visualY06[] = { 12.f };
+  bool found06[] = { true };
+  CharacterIndex startIndex06[] = { 0 };
+  CharacterIndex endIndex06[] = { 1u };
+  CharacterIndex noHitText06[] = { 0u };
+
+  struct FindSelectionIndicesData data[] =
+  {
+    {
+      "void text",
+      "",
+      1u,
+      visualX01,
+      visualY01,
+      found01,
+      startIndex01,
+      endIndex01,
+      noHitText01
+    },
+    {
+      "touch out of text's boundaries",
+      "Hello world",
+      3u,
+      visualX02,
+      visualY02,
+      found02,
+      startIndex02,
+      endIndex02,
+      noHitText02
+    },
+    {
+      "touch on the text",
+      "Hello world demo",
+      1u,
+      visualX03,
+      visualY03,
+      found03,
+      startIndex03,
+      endIndex03,
+      noHitText03
+    },
+    {
+      "touch on the new paragraph character at the end of line",
+      "Hello world demo\n",
+      1u,
+      visualX04,
+      visualY04,
+      found04,
+      startIndex04,
+      endIndex04,
+      noHitText04
+    },
+    {
+      "touch on a white space character. is the unique character of the line",
+      " ",
+      1u,
+      visualX05,
+      visualY05,
+      found05,
+      startIndex05,
+      endIndex05,
+      noHitText05
+    },
+    {
+      "touch on a white space character. is between two words",
+      "h ello",
+      1u,
+      visualX06,
+      visualY06,
+      found06,
+      startIndex06,
+      endIndex06,
+      noHitText06
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !FindSelectionIndicesTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp
new file mode 100755 (executable)
index 0000000..04ef6f0
--- /dev/null
@@ -0,0 +1,5429 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the LayoutEngine methods.
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct LayoutTextData
+{
+  std::string          description;
+  std::string          text;
+  Size                 textArea;
+  unsigned int         numberOfFonts;
+  FontDescriptionRun*  fontDescriptions;
+  Size                 layoutSize;
+  unsigned int         totalNumberOfGlyphs;
+  float*               positions;
+  unsigned int         numberOfLines;
+  LineRun*             lines;
+  Layout::Engine::Type layout;
+  unsigned int         startIndex;
+  unsigned int         numberOfGlyphs;
+  bool                 ellipsis:1;
+  bool                 updated:1;
+};
+
+void Print( const LineRun& line )
+{
+  std::cout << "        glyph run, index : " << line.glyphRun.glyphIndex << ", num glyphs : " << line.glyphRun.numberOfGlyphs << std::endl;
+  std::cout << "    character run, index : " << line.characterRun.characterIndex << ", num chars : " << line.characterRun.numberOfCharacters << std::endl;
+  std::cout << "                   width : " << line.width << std::endl;
+  std::cout << "                ascender : " << line.ascender << std::endl;
+  std::cout << "               descender : " << line.descender << std::endl;
+  std::cout << "             extraLength : " << line.extraLength << std::endl;
+  std::cout << "         alignmentOffset : " << line.alignmentOffset << std::endl;
+  std::cout << "               direction : " << line.direction << std::endl;
+  std::cout << "                ellipsis : " << line.ellipsis << std::endl;
+}
+
+bool LayoutTextTest( const LayoutTextData& data )
+{
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHindiRegular.ttf" );
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  if( 0u != data.numberOfFonts )
+  {
+    fontDescriptionRuns.Insert( fontDescriptionRuns.End(),
+                                data.fontDescriptions,
+                                data.fontDescriptions + data.numberOfFonts );
+  }
+
+  LayoutOptions options;
+  options.align = false;
+  CreateTextModel( data.text,
+                   data.textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Clear the layout.
+  Vector<LineRun>& lines = visualModel->mLines;
+
+  const Length numberOfCharacters = logicalModel->mText.Count();
+  const bool isLastNewParagraph = ( 0u == numberOfCharacters ) ? false : TextAbstraction::IsNewParagraph( *( logicalModel->mText.Begin() + ( numberOfCharacters - 1u ) ) );
+  const GlyphIndex lastGlyphIndex = data.startIndex + data.numberOfGlyphs - 1u;
+  const bool removeLastLine = isLastNewParagraph && ( lastGlyphIndex + 1u == visualModel->mGlyphs.Count() );
+
+  LineIndex startRemoveIndex = 0u;
+
+  if( 0u != lines.Count() )
+  {
+    startRemoveIndex = lines.Count();
+    LineIndex endRemoveIndex = startRemoveIndex;
+    ClearGlyphRuns( data.startIndex,
+                    lastGlyphIndex + ( removeLastLine ? 1u : 0u ),
+                    lines,
+                    startRemoveIndex,
+                    endRemoveIndex );
+
+    // Update the character runs of the lines.
+    const CharacterIndex* const glyphsToCharactersBuffer = visualModel->mGlyphsToCharacters.Begin();
+    const Length* const charactersPerGlyph = visualModel->mCharactersPerGlyph.Begin();
+    const CharacterIndex startCharacterIndex = *( glyphsToCharactersBuffer + data.startIndex );
+    const CharacterIndex lastCharacterIndex = *( glyphsToCharactersBuffer + lastGlyphIndex ) + *( charactersPerGlyph + lastGlyphIndex ) - 1u;
+    ClearCharacterRuns( startCharacterIndex,
+                        lastCharacterIndex + ( removeLastLine ? 1u : 0u ),
+                        lines,
+                        startRemoveIndex,
+                        endRemoveIndex );
+
+    lines.Erase( lines.Begin() + startRemoveIndex,
+                 lines.Begin() + endRemoveIndex );
+  }
+
+  Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
+
+  glyphPositions.Erase( glyphPositions.Begin() + data.startIndex,
+                        glyphPositions.Begin() + data.startIndex + data.numberOfGlyphs );
+
+  // 3) Layout
+  Layout::Engine engine;
+  engine.SetMetrics( metrics );
+  engine.SetLayout( data.layout );
+
+  textModel->mHorizontalAlignment = Text::HorizontalAlignment::BEGIN;
+  textModel->mLineWrapMode = LineWrap::WORD;
+  textModel->mIgnoreSpacesAfterText = true;
+  textModel->mMatchSystemLanguageDirection = false;
+  Layout::Parameters layoutParameters( data.textArea,
+                                       textModel );
+
+  layoutParameters.isLastNewParagraph = isLastNewParagraph;
+
+  // The initial glyph and the number of glyphs to layout.
+  layoutParameters.startGlyphIndex = data.startIndex;
+  layoutParameters.numberOfGlyphs = data.numberOfGlyphs;
+  layoutParameters.startLineIndex = startRemoveIndex;
+  layoutParameters.estimatedNumberOfLines = logicalModel->mParagraphInfo.Count();
+
+  layoutSize = Vector2::ZERO;
+
+  bool isAutoScroll = false;
+  const bool updated = engine.LayoutText( layoutParameters,
+                                          layoutSize,
+                                          data.ellipsis,
+                                          isAutoScroll );
+
+  // 4) Compare the results.
+
+  if( updated != data.updated )
+  {
+    std::cout << "  Different updated bool : " << updated << ", expected : " << data.updated << std::endl;
+    return false;
+  }
+
+  if( layoutSize != data.layoutSize )
+  {
+    std::cout << "  Different layout size : " << layoutSize << ", expected : " << data.layoutSize << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.totalNumberOfGlyphs; ++index )
+  {
+    const Vector2& position = *( glyphPositions.Begin() + index );
+
+    if( fabsf( position.x - *( data.positions + 2u * index ) ) > Math::MACHINE_EPSILON_1000 )
+    {
+      std::cout << "  Different position for glyph " << index << " x : " << position.x << ", expected : " << *( data.positions + 2u * index ) << std::endl;
+      return false;
+    }
+    if( fabsf( position.y - *( data.positions + 2u * index + 1u ) ) > Math::MACHINE_EPSILON_1000 )
+    {
+      std::cout << "  Different position for glyph " << index << " y : " << position.y << ", expected : " << *( data.positions + 2u * index + 1u ) << std::endl;
+      return false;
+    }
+  }
+
+  if( lines.Count() != data.numberOfLines )
+  {
+    std::cout << "  Different number of lines : " << lines.Count() << ", expected : " << data.numberOfLines << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.numberOfLines; ++index )
+  {
+    const LineRun& line = *( lines.Begin() + index );
+    const LineRun& expectedLine = *( data.lines + index );
+
+    if( line.glyphRun.glyphIndex != expectedLine.glyphRun.glyphIndex )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+    if( line.glyphRun.numberOfGlyphs != expectedLine.glyphRun.numberOfGlyphs )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( line.characterRun.characterIndex != expectedLine.characterRun.characterIndex )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+    if( line.characterRun.numberOfCharacters != expectedLine.characterRun.numberOfCharacters )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( fabsf( line.width - expectedLine.width ) > Math::MACHINE_EPSILON_1 )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( fabsf( line.ascender - expectedLine.ascender ) > Math::MACHINE_EPSILON_1 )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( fabsf( line.descender - expectedLine.descender ) > Math::MACHINE_EPSILON_1 )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( fabsf( line.extraLength - expectedLine.extraLength ) > Math::MACHINE_EPSILON_1 )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    if( line.ellipsis != expectedLine.ellipsis )
+    {
+      std::cout << "  Different line info for line : " << index << std::endl;
+      Print( line );
+      std::cout << "  expected" << std::endl;
+      Print( expectedLine );
+      return false;
+    }
+
+    // Do not compare the alignment offset as it's not calculated in the layout.
+    // Do not compare the line direction as it's not set in the layout.
+  }
+
+  return true;
+}
+
+//////////////////////////////////////////////////////////
+
+struct AlignData
+{
+  std::string                       description;
+  std::string                       text;
+  Size                              textArea;
+  unsigned int                      numberOfFonts;
+  FontDescriptionRun*               fontDescriptions;
+  Text::HorizontalAlignment::Type   horizontalAlignment;
+  Text::VerticalAlignment::Type     verticalAlignment;
+  unsigned int                      startIndex;
+  unsigned int                      numberOfCharacters;
+  unsigned int                      numberOfLines;
+  float*                            lineOffsets;
+  Dali::LayoutDirection::Type       layoutDirection;
+  bool                              matchSystemLanguageDirection;
+};
+
+bool AlignTest( const AlignData& data )
+{
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size layoutSize;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  if( 0u != data.numberOfFonts )
+  {
+    fontDescriptionRuns.Insert( fontDescriptionRuns.End(),
+                                data.fontDescriptions,
+                                data.fontDescriptions + data.numberOfFonts );
+  }
+
+  LayoutOptions options;
+  options.align = false;
+  CreateTextModel( data.text,
+                   data.textArea,
+                   fontDescriptionRuns,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // Call the Align method.
+  Layout::Engine engine;
+  engine.SetMetrics( metrics );
+
+  float alignmentOffset = 0.f;
+  engine.Align( data.textArea,
+                data.startIndex,
+                data.numberOfCharacters,
+                data.horizontalAlignment,
+                visualModel->mLines,
+                alignmentOffset,
+                data.layoutDirection,
+                data.matchSystemLanguageDirection );
+
+  // Compare results.
+  if( data.numberOfLines != visualModel->mLines.Count() )
+  {
+    std::cout << "  Different number of lines : " << visualModel->mLines.Count() << ", expected : " << data.numberOfLines << std::endl;
+    return false;
+  }
+
+  const LineRun* const linesBuffer = visualModel->mLines.Begin();
+  for( unsigned int index = 0u; index < data.numberOfLines; ++index )
+  {
+    const LineRun& line = *( linesBuffer + index );
+
+    if( line.alignmentOffset != *( data.lineOffsets + index ) )
+    {
+      std::cout << "  different line offset for index " << index << " : " << line.alignmentOffset << ", expected : " << *( data.lineOffsets + index ) << std::endl;
+      return false;
+    }
+  }
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+//
+// UtcDaliTextLayoutSetGetLayout
+// UtcDaliTextLayoutSetGetTextEllipsisEnabled
+// UtcDaliTextLayoutSetGetHorizontalAlignment
+// UtcDaliTextLayoutSetGetVerticalAlignment
+// UtcDaliTextLayoutSetGetCursorWidth
+// UtcDaliTextLayoutNoText
+// UtcDaliTextLayoutSmallTextArea01
+// UtcDaliTextLayoutSmallTextArea02
+// UtcDaliTextLayoutMultilineText01
+// UtcDaliTextLayoutMultilineText02
+// UtcDaliTextLayoutMultilineText03
+// UtcDaliTextLayoutMultilineText04
+// UtcDaliTextLayoutMultilineText05
+// UtcDaliTextLayoutMultilineText06
+// UtcDaliTextUpdateLayout01
+// UtcDaliTextUpdateLayout02
+// UtcDaliTextUpdateLayout03
+// UtcDaliTextLayoutEllipsis01
+// UtcDaliTextLayoutEllipsis02
+// UtcDaliTextLayoutEllipsis03
+// UtcDaliTextLayoutEllipsis04
+// UtcDaliTextLayoutEllipsis04
+// UtcDaliTextReorderLayout01
+// UtcDaliTextReorderLayout02
+// UtcDaliTextReorderLayout03
+// UtcDaliTextReorderLayout04
+// UtcDaliTextAlign01
+// UtcDaliTextAlign02
+// UtcDaliTextAlign03
+// UtcDaliTextAlign04
+// UtcDaliTextAlign05
+// UtcDaliTextAlign06
+// UtcDaliTextAlign07
+// UtcDaliTextAlign08
+// UtcDaliTextAlign09
+//
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextLayoutSetGetLayout(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutSetGetLayout");
+
+  Layout::Engine engine;
+
+  DALI_TEST_CHECK( Layout::Engine::SINGLE_LINE_BOX == engine.GetLayout() );
+
+  engine.SetLayout( Layout::Engine::MULTI_LINE_BOX );
+  DALI_TEST_CHECK( Layout::Engine::MULTI_LINE_BOX == engine.GetLayout() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutSetGetCursorWidth(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" ");
+
+  Layout::Engine engine;
+
+  DALI_TEST_EQUALS( 0, engine.GetCursorWidth(), TEST_LOCATION );
+
+  engine.SetCursorWidth( 2 );
+  DALI_TEST_EQUALS( 2, engine.GetCursorWidth(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutNoText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutNoText");
+
+  Size textArea(100.f, 60.f);
+  Size layoutSize = Vector2::ZERO;
+  LayoutTextData data =
+  {
+    "No text",
+    "",
+    textArea,
+    0u,
+    NULL,
+    layoutSize,
+    0u,
+    NULL,
+    0u,
+    NULL,
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    0u,
+    false,
+    false
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutSmallTextArea01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutSmallTextArea01");
+
+  // Won't layout the text in multi-line if the width is too small.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 11u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+  Size textArea(1.f, 1.f);
+  Size layoutSize = Vector2::ZERO;
+  LayoutTextData data =
+  {
+    "Layout text in a small area",
+    "Hello world",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    0u,
+    NULL,
+    0u,
+    NULL,
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    11u,
+    false,
+    false
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutSmallTextArea02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutSmallTextArea02");
+
+  // Will layout the text in single line as it can be scrolled.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 11u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+  Size textArea(1.f, 1.f);
+  Size layoutSize(78.f, 19.f);
+  float positions[] = { 0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f };
+  struct LineRun line =
+  {
+    { 0u, 11u },
+    { 0u, 11u },
+    78.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line );
+
+  LayoutTextData data =
+  {
+    "Layout text in a small area",
+    "Hello world",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    11u,
+    positions,
+    1u,
+    lines.Begin(),
+    Layout::Engine::SINGLE_LINE_BOX,
+    0u,
+    11u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText01");
+
+  // Layout some lines of left to right text.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun1;
+  fontDescriptionRun1.characterRun.characterIndex = 0u;
+  fontDescriptionRun1.characterRun.numberOfCharacters = 18u;
+  fontDescriptionRun1.familyLength = fontFamily.size();
+  fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+  memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+  fontDescriptionRun1.familyDefined = true;
+  fontDescriptionRun1.weightDefined = false;
+  fontDescriptionRun1.widthDefined = false;
+  fontDescriptionRun1.slantDefined = false;
+  fontDescriptionRun1.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun2;
+  fontDescriptionRun2.characterRun.characterIndex = 18u;
+  fontDescriptionRun2.characterRun.numberOfCharacters = 31u;
+  fontDescriptionRun2.familyLength = fontFamily.size();
+  fontDescriptionRun2.familyName = new char[fontDescriptionRun2.familyLength];
+  memcpy( fontDescriptionRun2.familyName, fontFamily.c_str(), fontDescriptionRun2.familyLength );
+  fontDescriptionRun2.familyDefined = true;
+  fontDescriptionRun2.weightDefined = false;
+  fontDescriptionRun2.widthDefined = false;
+  fontDescriptionRun2.slantDefined = false;
+  fontDescriptionRun2.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun2 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(91.f, 95.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f,  -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f,  -0.f, 39.f, -9.f, 50.f,  -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,
+    0.f, -13.f,  9.f,  -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -2.f, 42.f, -12.f,
+    0.f, -12.f,  8.f,  -9.f, 16.f,  -9.f, 26.f,  -9.f, 35.f, -9.f, 44.f, -11.f, 50.f, -0.f,
+    0.f, -12.f, 10.f, -12.f, 14.f, -12.f, 25.f,  -9.f, 34.f, -9.f, 40.f,  -9.f, 49.f, -9.f, 58.f, -11.f, 64.f, -0.f,
+    0.f, -12.f,  4.f, -12.f,  8.f,  -9.f, 18.f,  -9.f, 27.f, -9.f, 34.f,  -0.f, 40.f, -9.f, 49.f, -12.f, 53.f, -0.f, 58.f, -11.f, 65.f,  -9.f, 74.f, -9.f, 82.f, -11.f, 90.f, -2.f
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 12u, 6u },
+    { 12u, 6u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line2 =
+  {
+    { 18u, 7u },
+    { 18u, 7u },
+    49.f,
+    15.f,
+    -4.f,
+    5.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line3 =
+  {
+    { 25u, 9u },
+    { 25u, 10u },
+    63.f,
+    15.f,
+    -4.f,
+    5.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line4 =
+  {
+    { 34u, 14u },
+    { 35u, 14u },
+    91.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+  lines.PushBack( line3 );
+  lines.PushBack( line4 );
+
+  LayoutTextData data =
+  {
+    "Layout simple multi-line text",
+    "Hello world demo.\n"
+    "Layout different lines of text.",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    48u,
+    positions,
+    5u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    48u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText02");
+
+  // Layout some lines of bidirectional text.
+
+  const std::string fontFamily1( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun1;
+  fontDescriptionRun1.characterRun.characterIndex = 0u;
+  fontDescriptionRun1.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun1.familyLength = fontFamily1.size();
+  fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+  memcpy( fontDescriptionRun1.familyName, fontFamily1.c_str(), fontDescriptionRun1.familyLength );
+  fontDescriptionRun1.familyDefined = true;
+  fontDescriptionRun1.weightDefined = false;
+  fontDescriptionRun1.widthDefined = false;
+  fontDescriptionRun1.slantDefined = false;
+  fontDescriptionRun1.sizeDefined = false;
+
+  const std::string fontFamily2( "TizenSansHebrew" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun2;
+  fontDescriptionRun2.characterRun.characterIndex = 17u;
+  fontDescriptionRun2.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun2.familyLength = fontFamily2.size();
+  fontDescriptionRun2.familyName = new char[fontDescriptionRun2.familyLength];
+  memcpy( fontDescriptionRun2.familyName, fontFamily2.c_str(), fontDescriptionRun2.familyLength );
+  fontDescriptionRun2.familyDefined = true;
+  fontDescriptionRun2.weightDefined = false;
+  fontDescriptionRun2.widthDefined = false;
+  fontDescriptionRun2.slantDefined = false;
+  fontDescriptionRun2.sizeDefined = false;
+
+  const std::string fontFamily3( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun3;
+  fontDescriptionRun3.characterRun.characterIndex = 26u;
+  fontDescriptionRun3.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun3.familyLength = fontFamily3.size();
+  fontDescriptionRun3.familyName = new char[fontDescriptionRun3.familyLength];
+  memcpy( fontDescriptionRun3.familyName, fontFamily3.c_str(), fontDescriptionRun3.familyLength );
+  fontDescriptionRun3.familyDefined = true;
+  fontDescriptionRun3.weightDefined = false;
+  fontDescriptionRun3.widthDefined = false;
+  fontDescriptionRun3.slantDefined = false;
+  fontDescriptionRun3.sizeDefined = false;
+
+  const std::string fontFamily4( "TizenSansHebrew" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun4;
+  fontDescriptionRun4.characterRun.characterIndex = 28u;
+  fontDescriptionRun4.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun4.familyLength = fontFamily4.size();
+  fontDescriptionRun4.familyName = new char[fontDescriptionRun4.familyLength];
+  memcpy( fontDescriptionRun4.familyName, fontFamily4.c_str(), fontDescriptionRun4.familyLength );
+  fontDescriptionRun4.familyDefined = true;
+  fontDescriptionRun4.weightDefined = false;
+  fontDescriptionRun4.widthDefined = false;
+  fontDescriptionRun4.slantDefined = false;
+  fontDescriptionRun4.sizeDefined = false;
+
+  const std::string fontFamily5( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun5;
+  fontDescriptionRun5.characterRun.characterIndex = 38u;
+  fontDescriptionRun5.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun5.familyLength = fontFamily5.size();
+  fontDescriptionRun5.familyName = new char[fontDescriptionRun5.familyLength];
+  memcpy( fontDescriptionRun5.familyName, fontFamily5.c_str(), fontDescriptionRun5.familyLength );
+  fontDescriptionRun5.familyDefined = true;
+  fontDescriptionRun5.weightDefined = false;
+  fontDescriptionRun5.widthDefined = false;
+  fontDescriptionRun5.slantDefined = false;
+  fontDescriptionRun5.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun2 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun3 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun4 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun5 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(78.f, 114.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f,  -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f,  -0.f, 39.f,  -9.f, 50.f,  -9.f, 60.f,  -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,  //  0 .. 11
+    0.f, -13.f,  9.f,  -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f,  -0.f,                           // 12 .. 21
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                // 22 .. 27
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f,  -0.f,                            // 28 .. 37
+    4.f, -13.f,  12.f,  -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f,  -0.f, 41.f,  -9.f, 52.f,  -9.f, 62.f,  -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,  // 38 .. 49
+    3.f, -13.f,  12.f,  -9.f, 21.f,  -9.f, 33.f,  -9.f, 0.f, -2.f,                                                                                            // 50 .. 54
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 12u, 10u },
+    { 12u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line2 =
+  {
+    { 22u, 6u },
+    { 22u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line3 =
+  {
+    { 28u, 10u },
+    { 28u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line4 =
+  {
+    { 38u, 12u },
+    { 38u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line5 =
+  {
+    { 50u, 5u },
+    { 50u, 5u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+  lines.PushBack( line3 );
+  lines.PushBack( line4 );
+  lines.PushBack( line5 );
+
+  LayoutTextData data =
+  {
+    "Layout bidirectional text.",
+    "Hello world demo שלום עולם.\n"
+    "שלום עולם hello world demo.",
+    textArea,
+    5u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    55u,
+    positions,
+    6u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    55u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText03");
+
+  // Layout a long word which doesn't fit in the width of the text area.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 29u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(94.f, 57.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f,  -9.f, 35.f,  -9.f, 46.f, -9.f, 56.f, -9.f, 62.f, -13.f, 65.f, -13.f, 74.f, -13.f, 83.f,  -9.f,
+    0.f,  -9.f, 12.f, -9.f, 22.f, -13.f, 30.f,  -9.f, 39.f, -13.f, 43.f, -13.f, 46.f, -9.f, 55.f, -9.f, 66.f,  -9.f, 76.f,  -9.f, 82.f, -13.f, 85.f, -13.f,
+    0.f, -13.f,  9.f, -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f,  -2.f,
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    91.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 12u, 12u },
+    { 12u, 12u },
+    94.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line2 =
+  {
+    { 24u, 5u },
+    { 24u, 5u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+
+  LayoutTextData data =
+  {
+    "Layout a long word which doesn't fit in the width of the text area.",
+    "Helloworlddemohelloworlddemo.",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    29u,
+    positions,
+    3u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    29u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText04");
+
+  // Layout simple text ending with a \n. It has to add a void line at the end.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 13u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(81.f, 38.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -2.f, 81.f, -12.f
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 13u },
+    { 0u, 13u },
+    81.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 13u, 0u },
+    { 13u, 0u },
+    0.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+
+  LayoutTextData data =
+  {
+    "Layout simple text ending with a \n.",
+    "Hello world.\n",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    13u,
+    positions,
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    13u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText05");
+
+  // Layout simple text with one character with a different font size.
+
+  const std::string fontFamily( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun1;
+  fontDescriptionRun1.characterRun.characterIndex = 0u;
+  fontDescriptionRun1.characterRun.numberOfCharacters = 6u;
+  fontDescriptionRun1.familyLength = fontFamily.size();
+  fontDescriptionRun1.familyName = new char[fontDescriptionRun1.familyLength];
+  memcpy( fontDescriptionRun1.familyName, fontFamily.c_str(), fontDescriptionRun1.familyLength );
+  fontDescriptionRun1.familyDefined = true;
+  fontDescriptionRun1.weightDefined = false;
+  fontDescriptionRun1.widthDefined = false;
+  fontDescriptionRun1.slantDefined = false;
+  fontDescriptionRun1.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun2;
+  fontDescriptionRun2.characterRun.characterIndex = 6u;
+  fontDescriptionRun2.characterRun.numberOfCharacters = 1u;
+  fontDescriptionRun2.familyLength = fontFamily.size();
+  fontDescriptionRun2.familyName = new char[fontDescriptionRun2.familyLength];
+  memcpy( fontDescriptionRun2.familyName, fontFamily.c_str(), fontDescriptionRun2.familyLength );
+  fontDescriptionRun2.size = 1280u;
+  fontDescriptionRun2.familyDefined = true;
+  fontDescriptionRun2.weightDefined = false;
+  fontDescriptionRun2.widthDefined = false;
+  fontDescriptionRun2.slantDefined = false;
+  fontDescriptionRun2.sizeDefined = true;
+
+  FontDescriptionRun fontDescriptionRun3;
+  fontDescriptionRun3.characterRun.characterIndex = 7u;
+  fontDescriptionRun3.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun3.familyLength = fontFamily.size();
+  fontDescriptionRun3.familyName = new char[fontDescriptionRun3.familyLength];
+  memcpy( fontDescriptionRun3.familyName, fontFamily.c_str(), fontDescriptionRun3.familyLength );
+  fontDescriptionRun3.familyDefined = true;
+  fontDescriptionRun3.weightDefined = false;
+  fontDescriptionRun3.widthDefined = false;
+  fontDescriptionRun3.slantDefined = false;
+  fontDescriptionRun3.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun1 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun2 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun3 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(87.f, 51.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -14.f, 59.f, -9.f, 69.f, -9.f, 75.f, -13.f, 78.f, -13.f, 87.f, -0.f,
+    0.f, -13.f,  9.f, -9.f, 18.f,  -9.f, 30.f,  -9.f, 39.f, -2.f
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    87.f,
+    25.f,
+    -7.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 12u, 5u },
+    { 12u, 5u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+
+  LayoutTextData data =
+  {
+    "Layout simple text with one character with a different font size.",
+    "Hello world demo.",
+    textArea,
+    3u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    17u,
+    positions,
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    17u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText06");
+
+  const std::string fontFamily( "TizenSansHebrew" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+
+  Size textArea(64.f, 100.f);
+  Size layoutSize(31.f, 38.f);
+  float positions[] =
+  {
+    26.f, -13.f, 17.f, -10.f, 8.f, -10.f, 4.f, -10.f, 0.f, -0.f,
+    22.f, -10.f, 17.f, -10.f, 12.f, -10.f, 4.f, -10.f, 0.f, -10.f
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 5u },
+    { 0u, 5u },
+    30.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 5u, 5u },
+    { 5u, 5u },
+    31.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+
+  LayoutTextData data =
+  {
+    "Layout right to left text that doesn't fit in the text area after reordering.",
+    "לכאן שנורו", // If this text is laid-out ltr the width is 64. When reordered, the length is 66. This might cause alignment issues.
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    10u,
+    positions,
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    10u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutMultilineText07(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutMultilineText07");
+
+  const std::string fontFamily( "TizenSansHebrew" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun.familyLength = fontFamily.size();
+  fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+  memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+  fontDescriptionRun.familyDefined = true;
+  fontDescriptionRun.weightDefined = false;
+  fontDescriptionRun.widthDefined = false;
+  fontDescriptionRun.slantDefined = false;
+  fontDescriptionRun.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+
+  Size textArea(26.f, 100.f);
+  Size layoutSize(21.f, 57.f);
+  float positions[] =
+  {
+    10.f, -10.f, 5.f, -10.f, 0.f, -10.f,
+    11.f, -10.f, 7.f, -10.f, 0.f, -13.f,
+    13.f, -10.f, 4.f, -10.f, 0.f, -10.f
+  };
+  struct LineRun line0 =
+  {
+    { 0u, 3u },
+    { 0u, 3u },
+    19.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line1 =
+  {
+    { 3u, 3u },
+    { 3u, 3u },
+    21.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line2 =
+  {
+    { 6u, 3u },
+    { 6u, 3u },
+    21.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line0 );
+  lines.PushBack( line1 );
+  lines.PushBack( line2 );
+
+  LayoutTextData data =
+  {
+    "Layout a single word of right to left text that doesn't fit in one single line. When layouting ltr a piece of word fits in the line but it doesn't after reordering.",
+    "שנורולכאן", // If a piece of this text is laid-out ltr the width is 26. When reordered, the length is 27. This might cause alignment issues.
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    9u,
+    positions,
+    3u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    9u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextUpdateLayout01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextUpdateLayout01");
+
+  // Layout some lines of bidirectional text. Update the paragraphs at the beginning.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 17u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 26u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun03.familyLength = fontLatin.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontLatin.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 28u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun04.familyLength = fontArabic.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontArabic.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 42u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 54u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun06.familyLength = fontHebrew.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontHebrew.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun07;
+  fontDescriptionRun07.characterRun.characterIndex = 64u;
+  fontDescriptionRun07.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun07.familyLength = fontHebrew.size();
+  fontDescriptionRun07.familyName = new char[fontDescriptionRun07.familyLength];
+  memcpy( fontDescriptionRun07.familyName, fontHebrew.c_str(), fontDescriptionRun07.familyLength );
+  fontDescriptionRun07.familyDefined = true;
+  fontDescriptionRun07.weightDefined = false;
+  fontDescriptionRun07.widthDefined = false;
+  fontDescriptionRun07.slantDefined = false;
+  fontDescriptionRun07.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun08;
+  fontDescriptionRun08.characterRun.characterIndex = 74u;
+  fontDescriptionRun08.characterRun.numberOfCharacters = 18u;
+  fontDescriptionRun08.familyLength = fontLatin.size();
+  fontDescriptionRun08.familyName = new char[fontDescriptionRun08.familyLength];
+  memcpy( fontDescriptionRun08.familyName, fontLatin.c_str(), fontDescriptionRun08.familyLength );
+  fontDescriptionRun08.familyDefined = true;
+  fontDescriptionRun08.weightDefined = false;
+  fontDescriptionRun08.widthDefined = false;
+  fontDescriptionRun08.slantDefined = false;
+  fontDescriptionRun08.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun09;
+  fontDescriptionRun09.characterRun.characterIndex = 92u;
+  fontDescriptionRun09.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun09.familyLength = fontLatin.size();
+  fontDescriptionRun09.familyName = new char[fontDescriptionRun09.familyLength];
+  memcpy( fontDescriptionRun09.familyName, fontLatin.c_str(), fontDescriptionRun09.familyLength );
+  fontDescriptionRun09.familyDefined = true;
+  fontDescriptionRun09.weightDefined = false;
+  fontDescriptionRun09.widthDefined = false;
+  fontDescriptionRun09.slantDefined = false;
+  fontDescriptionRun09.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun10;
+  fontDescriptionRun10.characterRun.characterIndex = 104u;
+  fontDescriptionRun10.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun10.familyLength = fontArabic.size();
+  fontDescriptionRun10.familyName = new char[fontDescriptionRun10.familyLength];
+  memcpy( fontDescriptionRun10.familyName, fontArabic.c_str(), fontDescriptionRun10.familyLength );
+  fontDescriptionRun10.familyDefined = true;
+  fontDescriptionRun10.weightDefined = false;
+  fontDescriptionRun10.widthDefined = false;
+  fontDescriptionRun10.slantDefined = false;
+  fontDescriptionRun10.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun11;
+  fontDescriptionRun11.characterRun.characterIndex = 118u;
+  fontDescriptionRun11.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun11.familyLength = fontHebrew.size();
+  fontDescriptionRun11.familyName = new char[fontDescriptionRun11.familyLength];
+  memcpy( fontDescriptionRun11.familyName, fontHebrew.c_str(), fontDescriptionRun11.familyLength );
+  fontDescriptionRun11.familyDefined = true;
+  fontDescriptionRun11.weightDefined = false;
+  fontDescriptionRun11.widthDefined = false;
+  fontDescriptionRun11.slantDefined = false;
+  fontDescriptionRun11.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun12;
+  fontDescriptionRun12.characterRun.characterIndex = 128u;
+  fontDescriptionRun12.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun12.familyLength = fontLatin.size();
+  fontDescriptionRun12.familyName = new char[fontDescriptionRun12.familyLength];
+  memcpy( fontDescriptionRun12.familyName, fontLatin.c_str(), fontDescriptionRun12.familyLength );
+  fontDescriptionRun12.familyDefined = true;
+  fontDescriptionRun12.weightDefined = false;
+  fontDescriptionRun12.widthDefined = false;
+  fontDescriptionRun12.slantDefined = false;
+  fontDescriptionRun12.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun13;
+  fontDescriptionRun13.characterRun.characterIndex = 145u;
+  fontDescriptionRun13.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun13.familyLength = fontHebrew.size();
+  fontDescriptionRun13.familyName = new char[fontDescriptionRun13.familyLength];
+  memcpy( fontDescriptionRun13.familyName, fontHebrew.c_str(), fontDescriptionRun13.familyLength );
+  fontDescriptionRun13.familyDefined = true;
+  fontDescriptionRun13.weightDefined = false;
+  fontDescriptionRun13.widthDefined = false;
+  fontDescriptionRun13.slantDefined = false;
+  fontDescriptionRun13.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun14;
+  fontDescriptionRun14.characterRun.characterIndex = 154u;
+  fontDescriptionRun14.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun14.familyLength = fontLatin.size();
+  fontDescriptionRun14.familyName = new char[fontDescriptionRun14.familyLength];
+  memcpy( fontDescriptionRun14.familyName, fontLatin.c_str(), fontDescriptionRun14.familyLength );
+  fontDescriptionRun14.familyDefined = true;
+  fontDescriptionRun14.weightDefined = false;
+  fontDescriptionRun14.widthDefined = false;
+  fontDescriptionRun14.slantDefined = false;
+  fontDescriptionRun14.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun15;
+  fontDescriptionRun15.characterRun.characterIndex = 156u;
+  fontDescriptionRun15.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun15.familyLength = fontHebrew.size();
+  fontDescriptionRun15.familyName = new char[fontDescriptionRun15.familyLength];
+  memcpy( fontDescriptionRun15.familyName, fontHebrew.c_str(), fontDescriptionRun15.familyLength );
+  fontDescriptionRun15.familyDefined = true;
+  fontDescriptionRun15.weightDefined = false;
+  fontDescriptionRun15.widthDefined = false;
+  fontDescriptionRun15.slantDefined = false;
+  fontDescriptionRun15.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun16;
+  fontDescriptionRun16.characterRun.characterIndex = 166u;
+  fontDescriptionRun16.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun16.familyLength = fontLatin.size();
+  fontDescriptionRun16.familyName = new char[fontDescriptionRun16.familyLength];
+  memcpy( fontDescriptionRun16.familyName, fontLatin.c_str(), fontDescriptionRun16.familyLength );
+  fontDescriptionRun16.familyDefined = true;
+  fontDescriptionRun16.weightDefined = false;
+  fontDescriptionRun16.widthDefined = false;
+  fontDescriptionRun16.slantDefined = false;
+  fontDescriptionRun16.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun17;
+  fontDescriptionRun17.characterRun.characterIndex = 178u;
+  fontDescriptionRun17.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun17.familyLength = fontArabic.size();
+  fontDescriptionRun17.familyName = new char[fontDescriptionRun17.familyLength];
+  memcpy( fontDescriptionRun17.familyName, fontArabic.c_str(), fontDescriptionRun17.familyLength );
+  fontDescriptionRun17.familyDefined = true;
+  fontDescriptionRun17.weightDefined = false;
+  fontDescriptionRun17.widthDefined = false;
+  fontDescriptionRun17.slantDefined = false;
+  fontDescriptionRun17.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun07 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun08 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun09 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun10 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun11 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun12 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun13 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun14 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun15 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun16 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun17 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(92.f, 361.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     //   0 ..  11
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             //  12 ..  21
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              //  22 ..  27
+    87.f, -8.f, 82.f, -6.f, 75.f, -8.f, 72.f, -7.f, 71.f, -11.f, 67.f, -0.f, 63.f, -7.f, 62.f, -11.f, 57.f, -11.f, 51.f, -8.f, 50.f, -11.f, 45.f, -11.f, 40.f, -8.f, 37.f, -0.f, 4.f, -13.f, 12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 0.f, -0.f,   //  28 ..  47
+    39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 35.f, -0.f, 25.f, -10.f, 17.f, -13.f, 12.f, -10.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                 //  48 ..  58
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 0.f, -0.f,                                                                                                                                                                                            //  59 ..  63
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           //  64 ..  73
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     //  74 ..  85
+    3.f, -13.f,  12.f, -9.f, 21.f, -9.f, 33.f, -9.f, 0.f, -2.f, 0.f, -12.f,                                                                                                                                                                                 //  86 ..  91
+    0.f, -13.f,  8.f, -9.f, 17.f, -13.f, 21.f, -13.f, 24.f, -9.f, 33.f, -0.f, 37.f, -9.f, 48.f, -9.f, 58.f, -9.f, 64.f, -13.f, 67.f, -13.f, 76.f, -0.f,                                                                                                     //  92 .. 103
+    81.f, -8.f, 76.f, -6.f, 69.f, -8.f, 66.f, -7.f, 65.f, -11.f, 61.f, -0.f, 57.f, -7.f, 56.f, -11.f, 51.f, -11.f, 45.f, -8.f, 44.f, -11.f, 39.f, -11.f, 34.f, -8.f, 31.f, -0.f, 21.f, -10.f, 13.f, -13.f, 8.f, -10.f, 0.f, -10.f, 88.f, -0.f,              // 104 .. 122
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -0.f,                                                                                                                                                                                           // 123 .. 127
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     // 128 .. 139
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             // 140 .. 149
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              // 150 .. 155
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           // 156 .. 165
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     // 166 .. 177
+    47.f, -8.f, 42.f, -6.f, 35.f, -8.f, 32.f, -7.f, 31.f, -11.f, 27.f, -0.f, 23.f, -7.f, 22.f, -11.f, 17.f, -11.f, 11.f, -8.f, 10.f, -11.f, 5.f, -11.f, 0.f, -8.f, 0.f, -0.f,                                                                               // 178 .. 191
+  };
+
+  struct LineRun line01 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line02 =
+  {
+    { 12u, 10u },
+    { 12u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line03 =
+  {
+    { 22u, 6u },
+    { 22u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line04 =
+  {
+    { 28u, 20u },
+    { 28u, 20u },
+    92.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line05 =
+  {
+    { 48u, 11u },
+    { 48u, 11u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line06 =
+  {
+    { 59u, 5u },
+    { 59u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line07 =
+  {
+    { 64u, 10u },
+    { 64u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line08 =
+  {
+    { 74u, 12u },
+    { 74u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line09 =
+  {
+    { 86u, 6u },
+    { 86u, 6u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line10 =
+  {
+    { 92u, 12u },
+    { 92u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line11 =
+  {
+    { 104u, 19u },
+    { 104u, 19u },
+    90.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line12 =
+  {
+    { 123u, 5u },
+    { 123u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line13 =
+  {
+    { 128u, 12u },
+    { 128u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line14 =
+  {
+    { 140u, 10u },
+    { 140u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line15 =
+  {
+    { 150u, 6u },
+    { 150u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line16 =
+  {
+    { 156u, 10u },
+    { 156u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line17 =
+  {
+    { 166u, 12u },
+    { 166u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line18 =
+  {
+    { 178u, 14u },
+    { 178u, 14u },
+    56.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line19 =
+  {
+    { 192u, 0u },
+    { 192u, 0u },
+    0.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+  lines.PushBack( line02 );
+  lines.PushBack( line03 );
+  lines.PushBack( line04 );
+  lines.PushBack( line05 );
+  lines.PushBack( line06 );
+  lines.PushBack( line07 );
+  lines.PushBack( line08 );
+  lines.PushBack( line09 );
+  lines.PushBack( line10 );
+  lines.PushBack( line11 );
+  lines.PushBack( line12 );
+  lines.PushBack( line13 );
+  lines.PushBack( line14 );
+  lines.PushBack( line15 );
+  lines.PushBack( line16 );
+  lines.PushBack( line17 );
+  lines.PushBack( line18 );
+  lines.PushBack( line19 );
+
+  LayoutTextData data =
+  {
+    "Layout bidirectional text.",
+    "Hello world demo שלום עולם.\n"
+    "مرحبا بالعالم hello world שלום עולם\n"
+    "שלום עולם hello world demo.\n"
+    "hello world مرحبا بالعالم שלום עולם\n"
+    "Hello world demo שלום עולם.\n"
+    "שלום עולם hello world مرحبا بالعالم\n",
+    textArea,
+    17u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    192u,
+    positions,
+    19u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    64u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextUpdateLayout02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextUpdateLayout02");
+
+  // Layout some lines of bidirectional text. Update the paragraphs at the middle.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 17u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 26u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun03.familyLength = fontLatin.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontLatin.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 28u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun04.familyLength = fontArabic.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontArabic.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 42u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 54u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun06.familyLength = fontHebrew.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontHebrew.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun07;
+  fontDescriptionRun07.characterRun.characterIndex = 64u;
+  fontDescriptionRun07.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun07.familyLength = fontHebrew.size();
+  fontDescriptionRun07.familyName = new char[fontDescriptionRun07.familyLength];
+  memcpy( fontDescriptionRun07.familyName, fontHebrew.c_str(), fontDescriptionRun07.familyLength );
+  fontDescriptionRun07.familyDefined = true;
+  fontDescriptionRun07.weightDefined = false;
+  fontDescriptionRun07.widthDefined = false;
+  fontDescriptionRun07.slantDefined = false;
+  fontDescriptionRun07.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun08;
+  fontDescriptionRun08.characterRun.characterIndex = 74u;
+  fontDescriptionRun08.characterRun.numberOfCharacters = 18u;
+  fontDescriptionRun08.familyLength = fontLatin.size();
+  fontDescriptionRun08.familyName = new char[fontDescriptionRun08.familyLength];
+  memcpy( fontDescriptionRun08.familyName, fontLatin.c_str(), fontDescriptionRun08.familyLength );
+  fontDescriptionRun08.familyDefined = true;
+  fontDescriptionRun08.weightDefined = false;
+  fontDescriptionRun08.widthDefined = false;
+  fontDescriptionRun08.slantDefined = false;
+  fontDescriptionRun08.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun09;
+  fontDescriptionRun09.characterRun.characterIndex = 92u;
+  fontDescriptionRun09.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun09.familyLength = fontLatin.size();
+  fontDescriptionRun09.familyName = new char[fontDescriptionRun09.familyLength];
+  memcpy( fontDescriptionRun09.familyName, fontLatin.c_str(), fontDescriptionRun09.familyLength );
+  fontDescriptionRun09.familyDefined = true;
+  fontDescriptionRun09.weightDefined = false;
+  fontDescriptionRun09.widthDefined = false;
+  fontDescriptionRun09.slantDefined = false;
+  fontDescriptionRun09.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun10;
+  fontDescriptionRun10.characterRun.characterIndex = 104u;
+  fontDescriptionRun10.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun10.familyLength = fontArabic.size();
+  fontDescriptionRun10.familyName = new char[fontDescriptionRun10.familyLength];
+  memcpy( fontDescriptionRun10.familyName, fontArabic.c_str(), fontDescriptionRun10.familyLength );
+  fontDescriptionRun10.familyDefined = true;
+  fontDescriptionRun10.weightDefined = false;
+  fontDescriptionRun10.widthDefined = false;
+  fontDescriptionRun10.slantDefined = false;
+  fontDescriptionRun10.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun11;
+  fontDescriptionRun11.characterRun.characterIndex = 118u;
+  fontDescriptionRun11.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun11.familyLength = fontHebrew.size();
+  fontDescriptionRun11.familyName = new char[fontDescriptionRun11.familyLength];
+  memcpy( fontDescriptionRun11.familyName, fontHebrew.c_str(), fontDescriptionRun11.familyLength );
+  fontDescriptionRun11.familyDefined = true;
+  fontDescriptionRun11.weightDefined = false;
+  fontDescriptionRun11.widthDefined = false;
+  fontDescriptionRun11.slantDefined = false;
+  fontDescriptionRun11.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun12;
+  fontDescriptionRun12.characterRun.characterIndex = 128u;
+  fontDescriptionRun12.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun12.familyLength = fontLatin.size();
+  fontDescriptionRun12.familyName = new char[fontDescriptionRun12.familyLength];
+  memcpy( fontDescriptionRun12.familyName, fontLatin.c_str(), fontDescriptionRun12.familyLength );
+  fontDescriptionRun12.familyDefined = true;
+  fontDescriptionRun12.weightDefined = false;
+  fontDescriptionRun12.widthDefined = false;
+  fontDescriptionRun12.slantDefined = false;
+  fontDescriptionRun12.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun13;
+  fontDescriptionRun13.characterRun.characterIndex = 145u;
+  fontDescriptionRun13.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun13.familyLength = fontHebrew.size();
+  fontDescriptionRun13.familyName = new char[fontDescriptionRun13.familyLength];
+  memcpy( fontDescriptionRun13.familyName, fontHebrew.c_str(), fontDescriptionRun13.familyLength );
+  fontDescriptionRun13.familyDefined = true;
+  fontDescriptionRun13.weightDefined = false;
+  fontDescriptionRun13.widthDefined = false;
+  fontDescriptionRun13.slantDefined = false;
+  fontDescriptionRun13.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun14;
+  fontDescriptionRun14.characterRun.characterIndex = 154u;
+  fontDescriptionRun14.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun14.familyLength = fontLatin.size();
+  fontDescriptionRun14.familyName = new char[fontDescriptionRun14.familyLength];
+  memcpy( fontDescriptionRun14.familyName, fontLatin.c_str(), fontDescriptionRun14.familyLength );
+  fontDescriptionRun14.familyDefined = true;
+  fontDescriptionRun14.weightDefined = false;
+  fontDescriptionRun14.widthDefined = false;
+  fontDescriptionRun14.slantDefined = false;
+  fontDescriptionRun14.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun15;
+  fontDescriptionRun15.characterRun.characterIndex = 156u;
+  fontDescriptionRun15.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun15.familyLength = fontHebrew.size();
+  fontDescriptionRun15.familyName = new char[fontDescriptionRun15.familyLength];
+  memcpy( fontDescriptionRun15.familyName, fontHebrew.c_str(), fontDescriptionRun15.familyLength );
+  fontDescriptionRun15.familyDefined = true;
+  fontDescriptionRun15.weightDefined = false;
+  fontDescriptionRun15.widthDefined = false;
+  fontDescriptionRun15.slantDefined = false;
+  fontDescriptionRun15.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun16;
+  fontDescriptionRun16.characterRun.characterIndex = 166u;
+  fontDescriptionRun16.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun16.familyLength = fontLatin.size();
+  fontDescriptionRun16.familyName = new char[fontDescriptionRun16.familyLength];
+  memcpy( fontDescriptionRun16.familyName, fontLatin.c_str(), fontDescriptionRun16.familyLength );
+  fontDescriptionRun16.familyDefined = true;
+  fontDescriptionRun16.weightDefined = false;
+  fontDescriptionRun16.widthDefined = false;
+  fontDescriptionRun16.slantDefined = false;
+  fontDescriptionRun16.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun17;
+  fontDescriptionRun17.characterRun.characterIndex = 178u;
+  fontDescriptionRun17.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun17.familyLength = fontArabic.size();
+  fontDescriptionRun17.familyName = new char[fontDescriptionRun17.familyLength];
+  memcpy( fontDescriptionRun17.familyName, fontArabic.c_str(), fontDescriptionRun17.familyLength );
+  fontDescriptionRun17.familyDefined = true;
+  fontDescriptionRun17.weightDefined = false;
+  fontDescriptionRun17.widthDefined = false;
+  fontDescriptionRun17.slantDefined = false;
+  fontDescriptionRun17.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun07 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun08 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun09 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun10 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun11 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun12 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun13 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun14 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun15 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun16 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun17 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(92.f, 361.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     //   0 ..  11
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             //  12 ..  21
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              //  22 ..  27
+    87.f, -8.f, 82.f, -6.f, 75.f, -8.f, 72.f, -7.f, 71.f, -11.f, 67.f, -0.f, 63.f, -7.f, 62.f, -11.f, 57.f, -11.f, 51.f, -8.f, 50.f, -11.f, 45.f, -11.f, 40.f, -8.f, 37.f, -0.f, 4.f, -13.f, 12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 0.f, -0.f,   //  28 ..  47
+    39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 35.f, -0.f, 25.f, -10.f, 17.f, -13.f, 12.f, -10.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                 //  48 ..  58
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 0.f, -0.f,                                                                                                                                                                                            //  59 ..  63
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           //  64 ..  73
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     //  74 ..  85
+    3.f, -13.f,  12.f, -9.f, 21.f, -9.f, 33.f, -9.f, 0.f, -2.f, 0.f, -12.f,                                                                                                                                                                                 //  86 ..  91
+    0.f, -13.f,  8.f, -9.f, 17.f, -13.f, 21.f, -13.f, 24.f, -9.f, 33.f, -0.f, 37.f, -9.f, 48.f, -9.f, 58.f, -9.f, 64.f, -13.f, 67.f, -13.f, 76.f, -0.f,                                                                                                     //  92 .. 103
+    81.f, -8.f, 76.f, -6.f, 69.f, -8.f, 66.f, -7.f, 65.f, -11.f, 61.f, -0.f, 57.f, -7.f, 56.f, -11.f, 51.f, -11.f, 45.f, -8.f, 44.f, -11.f, 39.f, -11.f, 34.f, -8.f, 31.f, -0.f, 21.f, -10.f, 13.f, -13.f, 8.f, -10.f, 0.f, -10.f, 88.f, -0.f,              // 104 .. 122
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -0.f,                                                                                                                                                                                           // 123 .. 127
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     // 128 .. 139
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             // 140 .. 149
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              // 150 .. 155
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           // 156 .. 165
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     // 166 .. 177
+    47.f, -8.f, 42.f, -6.f, 35.f, -8.f, 32.f, -7.f, 31.f, -11.f, 27.f, -0.f, 23.f, -7.f, 22.f, -11.f, 17.f, -11.f, 11.f, -8.f, 10.f, -11.f, 5.f, -11.f, 0.f, -8.f, 0.f, -0.f,                                                                               // 178 .. 191
+  };
+
+  struct LineRun line01 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line02 =
+  {
+    { 12u, 10u },
+    { 12u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line03 =
+  {
+    { 22u, 6u },
+    { 22u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line04 =
+  {
+    { 28u, 20u },
+    { 28u, 20u },
+    92.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    true,
+    false
+  };
+  struct LineRun line05 =
+  {
+    { 48u, 11u },
+    { 48u, 11u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line06 =
+  {
+    { 59u, 5u },
+    { 59u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line07 =
+  {
+    { 64u, 10u },
+    { 64u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line08 =
+  {
+    { 74u, 12u },
+    { 74u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    1.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line09 =
+  {
+    { 86u, 6u },
+    { 86u, 6u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line10 =
+  {
+    { 92u, 12u },
+    { 92u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line11 =
+  {
+    { 104u, 19u },
+    { 104u, 19u },
+    90.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line12 =
+  {
+    { 123u, 5u },
+    { 123u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line13 =
+  {
+    { 128u, 12u },
+    { 128u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line14 =
+  {
+    { 140u, 10u },
+    { 140u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line15 =
+  {
+    { 150u, 6u },
+    { 150u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line16 =
+  {
+    { 156u, 10u },
+    { 156u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line17 =
+  {
+    { 166u, 12u },
+    { 166u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line18 =
+  {
+    { 178u, 14u },
+    { 178u, 14u },
+    56.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line19 =
+  {
+    { 192u, 0u },
+    { 192u, 0u },
+    0.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+  lines.PushBack( line02 );
+  lines.PushBack( line03 );
+  lines.PushBack( line04 );
+  lines.PushBack( line05 );
+  lines.PushBack( line06 );
+  lines.PushBack( line07 );
+  lines.PushBack( line08 );
+  lines.PushBack( line09 );
+  lines.PushBack( line10 );
+  lines.PushBack( line11 );
+  lines.PushBack( line12 );
+  lines.PushBack( line13 );
+  lines.PushBack( line14 );
+  lines.PushBack( line15 );
+  lines.PushBack( line16 );
+  lines.PushBack( line17 );
+  lines.PushBack( line18 );
+  lines.PushBack( line19 );
+
+  LayoutTextData data =
+  {
+    "Layout bidirectional text.",
+    "Hello world demo שלום עולם.\n"
+    "مرحبا بالعالم hello world שלום עולם\n"
+    "שלום עולם hello world demo.\n"
+    "hello world مرحبا بالعالم שלום עולם\n"
+    "Hello world demo שלום עולם.\n"
+    "שלום עולם hello world مرحبا بالعالم\n",
+    textArea,
+    17u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    192u,
+    positions,
+    19u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    64u,
+    64u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextUpdateLayout03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextUpdateLayout03");
+
+  // Layout some lines of bidirectional text. Update the paragraphs at the middle.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 17u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 26u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun03.familyLength = fontLatin.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontLatin.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 28u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun04.familyLength = fontArabic.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontArabic.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 42u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 54u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun06.familyLength = fontHebrew.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontHebrew.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun07;
+  fontDescriptionRun07.characterRun.characterIndex = 64u;
+  fontDescriptionRun07.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun07.familyLength = fontHebrew.size();
+  fontDescriptionRun07.familyName = new char[fontDescriptionRun07.familyLength];
+  memcpy( fontDescriptionRun07.familyName, fontHebrew.c_str(), fontDescriptionRun07.familyLength );
+  fontDescriptionRun07.familyDefined = true;
+  fontDescriptionRun07.weightDefined = false;
+  fontDescriptionRun07.widthDefined = false;
+  fontDescriptionRun07.slantDefined = false;
+  fontDescriptionRun07.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun08;
+  fontDescriptionRun08.characterRun.characterIndex = 74u;
+  fontDescriptionRun08.characterRun.numberOfCharacters = 18u;
+  fontDescriptionRun08.familyLength = fontLatin.size();
+  fontDescriptionRun08.familyName = new char[fontDescriptionRun08.familyLength];
+  memcpy( fontDescriptionRun08.familyName, fontLatin.c_str(), fontDescriptionRun08.familyLength );
+  fontDescriptionRun08.familyDefined = true;
+  fontDescriptionRun08.weightDefined = false;
+  fontDescriptionRun08.widthDefined = false;
+  fontDescriptionRun08.slantDefined = false;
+  fontDescriptionRun08.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun09;
+  fontDescriptionRun09.characterRun.characterIndex = 92u;
+  fontDescriptionRun09.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun09.familyLength = fontLatin.size();
+  fontDescriptionRun09.familyName = new char[fontDescriptionRun09.familyLength];
+  memcpy( fontDescriptionRun09.familyName, fontLatin.c_str(), fontDescriptionRun09.familyLength );
+  fontDescriptionRun09.familyDefined = true;
+  fontDescriptionRun09.weightDefined = false;
+  fontDescriptionRun09.widthDefined = false;
+  fontDescriptionRun09.slantDefined = false;
+  fontDescriptionRun09.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun10;
+  fontDescriptionRun10.characterRun.characterIndex = 104u;
+  fontDescriptionRun10.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun10.familyLength = fontArabic.size();
+  fontDescriptionRun10.familyName = new char[fontDescriptionRun10.familyLength];
+  memcpy( fontDescriptionRun10.familyName, fontArabic.c_str(), fontDescriptionRun10.familyLength );
+  fontDescriptionRun10.familyDefined = true;
+  fontDescriptionRun10.weightDefined = false;
+  fontDescriptionRun10.widthDefined = false;
+  fontDescriptionRun10.slantDefined = false;
+  fontDescriptionRun10.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun11;
+  fontDescriptionRun11.characterRun.characterIndex = 118u;
+  fontDescriptionRun11.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun11.familyLength = fontHebrew.size();
+  fontDescriptionRun11.familyName = new char[fontDescriptionRun11.familyLength];
+  memcpy( fontDescriptionRun11.familyName, fontHebrew.c_str(), fontDescriptionRun11.familyLength );
+  fontDescriptionRun11.familyDefined = true;
+  fontDescriptionRun11.weightDefined = false;
+  fontDescriptionRun11.widthDefined = false;
+  fontDescriptionRun11.slantDefined = false;
+  fontDescriptionRun11.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun12;
+  fontDescriptionRun12.characterRun.characterIndex = 128u;
+  fontDescriptionRun12.characterRun.numberOfCharacters = 17u;
+  fontDescriptionRun12.familyLength = fontLatin.size();
+  fontDescriptionRun12.familyName = new char[fontDescriptionRun12.familyLength];
+  memcpy( fontDescriptionRun12.familyName, fontLatin.c_str(), fontDescriptionRun12.familyLength );
+  fontDescriptionRun12.familyDefined = true;
+  fontDescriptionRun12.weightDefined = false;
+  fontDescriptionRun12.widthDefined = false;
+  fontDescriptionRun12.slantDefined = false;
+  fontDescriptionRun12.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun13;
+  fontDescriptionRun13.characterRun.characterIndex = 145u;
+  fontDescriptionRun13.characterRun.numberOfCharacters = 9u;
+  fontDescriptionRun13.familyLength = fontHebrew.size();
+  fontDescriptionRun13.familyName = new char[fontDescriptionRun13.familyLength];
+  memcpy( fontDescriptionRun13.familyName, fontHebrew.c_str(), fontDescriptionRun13.familyLength );
+  fontDescriptionRun13.familyDefined = true;
+  fontDescriptionRun13.weightDefined = false;
+  fontDescriptionRun13.widthDefined = false;
+  fontDescriptionRun13.slantDefined = false;
+  fontDescriptionRun13.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun14;
+  fontDescriptionRun14.characterRun.characterIndex = 154u;
+  fontDescriptionRun14.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun14.familyLength = fontLatin.size();
+  fontDescriptionRun14.familyName = new char[fontDescriptionRun14.familyLength];
+  memcpy( fontDescriptionRun14.familyName, fontLatin.c_str(), fontDescriptionRun14.familyLength );
+  fontDescriptionRun14.familyDefined = true;
+  fontDescriptionRun14.weightDefined = false;
+  fontDescriptionRun14.widthDefined = false;
+  fontDescriptionRun14.slantDefined = false;
+  fontDescriptionRun14.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun15;
+  fontDescriptionRun15.characterRun.characterIndex = 156u;
+  fontDescriptionRun15.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun15.familyLength = fontHebrew.size();
+  fontDescriptionRun15.familyName = new char[fontDescriptionRun15.familyLength];
+  memcpy( fontDescriptionRun15.familyName, fontHebrew.c_str(), fontDescriptionRun15.familyLength );
+  fontDescriptionRun15.familyDefined = true;
+  fontDescriptionRun15.weightDefined = false;
+  fontDescriptionRun15.widthDefined = false;
+  fontDescriptionRun15.slantDefined = false;
+  fontDescriptionRun15.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun16;
+  fontDescriptionRun16.characterRun.characterIndex = 166u;
+  fontDescriptionRun16.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun16.familyLength = fontLatin.size();
+  fontDescriptionRun16.familyName = new char[fontDescriptionRun16.familyLength];
+  memcpy( fontDescriptionRun16.familyName, fontLatin.c_str(), fontDescriptionRun16.familyLength );
+  fontDescriptionRun16.familyDefined = true;
+  fontDescriptionRun16.weightDefined = false;
+  fontDescriptionRun16.widthDefined = false;
+  fontDescriptionRun16.slantDefined = false;
+  fontDescriptionRun16.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun17;
+  fontDescriptionRun17.characterRun.characterIndex = 178u;
+  fontDescriptionRun17.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun17.familyLength = fontArabic.size();
+  fontDescriptionRun17.familyName = new char[fontDescriptionRun17.familyLength];
+  memcpy( fontDescriptionRun17.familyName, fontArabic.c_str(), fontDescriptionRun17.familyLength );
+  fontDescriptionRun17.familyDefined = true;
+  fontDescriptionRun17.weightDefined = false;
+  fontDescriptionRun17.widthDefined = false;
+  fontDescriptionRun17.slantDefined = false;
+  fontDescriptionRun17.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun07 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun08 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun09 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun10 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun11 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun12 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun13 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun14 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun15 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun16 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun17 );
+  Size textArea(100.f, 300.f);
+  Size layoutSize(92.f, 361.f);
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     //   0 ..  11
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             //  12 ..  21
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              //  22 ..  27
+    87.f, -8.f, 82.f, -6.f, 75.f, -8.f, 72.f, -7.f, 71.f, -11.f, 67.f, -0.f, 63.f, -7.f, 62.f, -11.f, 57.f, -11.f, 51.f, -8.f, 50.f, -11.f, 45.f, -11.f, 40.f, -8.f, 37.f, -0.f, 4.f, -13.f, 12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 0.f, -0.f,   //  28 ..  47
+    39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 35.f, -0.f, 25.f, -10.f, 17.f, -13.f, 12.f, -10.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                 //  48 ..  58
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 0.f, -0.f,                                                                                                                                                                                            //  59 ..  63
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           //  64 ..  73
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     //  74 ..  85
+    3.f, -13.f,  12.f, -9.f, 21.f, -9.f, 33.f, -9.f, 0.f, -2.f, 0.f, -12.f,                                                                                                                                                                                 //  86 ..  91
+    0.f, -13.f,  8.f, -9.f, 17.f, -13.f, 21.f, -13.f, 24.f, -9.f, 33.f, -0.f, 37.f, -9.f, 48.f, -9.f, 58.f, -9.f, 64.f, -13.f, 67.f, -13.f, 76.f, -0.f,                                                                                                     //  92 .. 103
+    81.f, -8.f, 76.f, -6.f, 69.f, -8.f, 66.f, -7.f, 65.f, -11.f, 61.f, -0.f, 57.f, -7.f, 56.f, -11.f, 51.f, -11.f, 45.f, -8.f, 44.f, -11.f, 39.f, -11.f, 34.f, -8.f, 31.f, -0.f, 21.f, -10.f, 13.f, -13.f, 8.f, -10.f, 0.f, -10.f, 88.f, -0.f,              // 104 .. 122
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -0.f,                                                                                                                                                                                           // 123 .. 127
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,                                                                                                     // 128 .. 139
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 65.f, -10.f, 57.f, -13.f, 52.f, -10.f, 44.f, -10.f, 75.f, -0.f,                                                                                                                             // 140 .. 149
+    21.f, -10.f, 16.f, -10.f, 9.f, -13.f, 0.f, -10.f, 29.f, -2.f, 32.f, -12.f,                                                                                                                                                                              // 150 .. 155
+    59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,                                                                                                                           // 156 .. 165
+    4.f, -13.f,  12.f, -9.f, 21.f, -13.f, 25.f, -13.f, 28.f, -9.f, 37.f, -0.f, 41.f, -9.f, 52.f, -9.f, 62.f, -9.f, 68.f, -13.f, 71.f, -13.f, 0.f, -0.f,                                                                                                     // 166 .. 177
+    47.f, -8.f, 42.f, -6.f, 35.f, -8.f, 32.f, -7.f, 31.f, -11.f, 27.f, -0.f, 23.f, -7.f, 22.f, -11.f, 17.f, -11.f, 11.f, -8.f, 10.f, -11.f, 5.f, -11.f, 0.f, -8.f, 0.f, -0.f,                                                                               // 178 .. 191
+  };
+
+  struct LineRun line01 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line02 =
+  {
+    { 12u, 10u },
+    { 12u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line03 =
+  {
+    { 22u, 6u },
+    { 22u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line04 =
+  {
+    { 28u, 20u },
+    { 28u, 20u },
+    92.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line05 =
+  {
+    { 48u, 11u },
+    { 48u, 11u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line06 =
+  {
+    { 59u, 5u },
+    { 59u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line07 =
+  {
+    { 64u, 10u },
+    { 64u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line08 =
+  {
+    { 74u, 12u },
+    { 74u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    1.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line09 =
+  {
+    { 86u, 6u },
+    { 86u, 6u },
+    42.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line10 =
+  {
+    { 92u, 12u },
+    { 92u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line11 =
+  {
+    { 104u, 19u },
+    { 104u, 19u },
+    90.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line12 =
+  {
+    { 123u, 5u },
+    { 123u, 5u },
+    29.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line13 =
+  {
+    { 128u, 12u },
+    { 128u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line14 =
+  {
+    { 140u, 10u },
+    { 140u, 10u },
+    75.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line15 =
+  {
+    { 150u, 6u },
+    { 150u, 6u },
+    32.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line16 =
+  {
+    { 156u, 10u },
+    { 156u, 10u },
+    65.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line17 =
+  {
+    { 166u, 12u },
+    { 166u, 12u },
+    76.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line18 =
+  {
+    { 178u, 14u },
+    { 178u, 14u },
+    56.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line19 =
+  {
+    { 192u, 0u },
+    { 192u, 0u },
+    0.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+  lines.PushBack( line02 );
+  lines.PushBack( line03 );
+  lines.PushBack( line04 );
+  lines.PushBack( line05 );
+  lines.PushBack( line06 );
+  lines.PushBack( line07 );
+  lines.PushBack( line08 );
+  lines.PushBack( line09 );
+  lines.PushBack( line10 );
+  lines.PushBack( line11 );
+  lines.PushBack( line12 );
+  lines.PushBack( line13 );
+  lines.PushBack( line14 );
+  lines.PushBack( line15 );
+  lines.PushBack( line16 );
+  lines.PushBack( line17 );
+  lines.PushBack( line18 );
+  lines.PushBack( line19 );
+
+  LayoutTextData data =
+  {
+    "Layout bidirectional text.",
+    "Hello world demo שלום עולם.\n"
+    "مرحبا بالعالم hello world שלום עולם\n"
+    "שלום עולם hello world demo.\n"
+    "hello world مرحبا بالعالم שלום עולם\n"
+    "Hello world demo שלום עולם.\n"
+    "שלום עולם hello world مرحبا بالعالم\n",
+    textArea,
+    17u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    192u,
+    positions,
+    19u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    128u,
+    64u,
+    false,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutEllipsis01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutEllipsis01");
+
+  // Layout single-line LTR text with ellipsis.
+
+  const std::string fontLatin( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 51u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+
+  struct LineRun line01 =
+  {
+    { 0u, 14u },
+    { 0u, 14u },
+    99.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    true
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f, 82.f, -13.f,
+  };
+
+  Size textArea( 100.f, 50.f );
+  Size layoutSize( 100.f, 19.f );
+
+  LayoutTextData data =
+  {
+    "Layout single-line LTR text with ellipsis.",
+    "Hello world demo hello world demo hello world demo.",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    13u,
+    positions,
+    1u,
+    lines.Begin(),
+    Layout::Engine::SINGLE_LINE_BOX,
+    0u,
+    51u,
+    true,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutEllipsis02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutEllipsis02");
+
+  // Layout multi-line LTR text with ellipsis.
+
+  const std::string fontLatin( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 51u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+
+  struct LineRun line01 =
+  {
+    { 0u, 12u },
+    { 0u, 12u },
+    78.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line02 =
+  {
+    { 12u, 12u },
+    { 12u, 12u },
+    93.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    true
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+  lines.PushBack( line02 );
+
+  float positions[] =
+  {
+    0.f, -12.f, 10.f, -9.f, 19.f, -13.f, 23.f, -13.f, 26.f, -9.f, 35.f, -0.f, 39.f, -9.f, 50.f, -9.f, 60.f, -9.f, 66.f, -13.f, 69.f, -13.f, 78.f, -0.f,
+    0.f, -13.f,  9.f, -9.f, 18.f, -9.f, 30.f, -9.f, 39.f, -0.f, 44.f, -13.f, 52.f, -9.f, 61.f, -13.f, 65.f, -13.f, 68.f, -9.f, 77.f, -0.f, 81.f, -9.f,
+  };
+
+  Size textArea( 100.f, 50.f );
+  Size layoutSize( 100.f, 38.f );
+
+  LayoutTextData data =
+  {
+    "Layout multi-line LTR text with ellipsis.",
+    "Hello world demo hello world demo hello world demo.",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    24u,
+    positions,
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    51u,
+    true,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutEllipsis03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutEllipsis03");
+
+  // Layout single-line RTL text with ellipsis.
+
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun01.familyLength = fontHebrew.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontHebrew.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 10u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun02.familyLength = fontArabic.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontArabic.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 24u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun03.familyLength = fontHebrew.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontHebrew.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 34u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun04.familyLength = fontArabic.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontArabic.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun05.familyLength = fontHebrew.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontHebrew.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 58u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 15u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  struct LineRun line01 =
+  {
+    { 0u, 17u },
+    { 0u, 17u },
+    100.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    true
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+
+  float positions[] =
+  {
+    91.f, -10.f, 83.f, -13.f, 78.f, -10.f, 70.f, -10.f, 65.f, -0.f, 57.f, -10.f, 52.f, -10.f, 45.f, -13.f, 36.f, -10.f, 31.f, -0.f, 24.f, -8.f, 19.f, -6.f, 12.f, -8.f, 9.f, -7.f, 8.f, -11.f, 4.f, -0.f,
+  };
+
+  Size textArea( 100.f, 50.f );
+  Size layoutSize( 100.f, 19.f );
+
+  LayoutTextData data =
+  {
+    "Layout single-line RTL text with ellipsis.",
+    "שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    16u,
+    positions,
+    1u,
+    lines.Begin(),
+    Layout::Engine::SINGLE_LINE_BOX,
+    0u,
+    72u,
+    true,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutEllipsis04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutEllipsis04");
+
+  // Layout multi-line RTL text with ellipsis.
+
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun01.familyLength = fontHebrew.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontHebrew.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 10u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun02.familyLength = fontArabic.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontArabic.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 24u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun03.familyLength = fontHebrew.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontHebrew.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 34u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun04.familyLength = fontArabic.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontArabic.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun05.familyLength = fontHebrew.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontHebrew.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 58u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 15u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  struct LineRun line01 =
+  {
+    { 0u, 16u },
+    { 0u, 16u },
+    94.f,
+    15.f,
+    -4.f,
+    3.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  struct LineRun line02 =
+  {
+    { 16u, 18u },
+    { 16u, 18u },
+    97.f,
+    15.f,
+    -4.f,
+    4.f,
+    0.f,
+    0.f,
+    false,
+    true
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+  lines.PushBack( line02 );
+
+  float positions[] =
+  {
+    86.f, -10.f, 78.f, -13.f, 73.f, -10.f, 65.f, -10.f, 60.f, -0.f, 52.f, -10.f, 47.f, -10.f, 40.f, -13.f, 31.f, -10.f, 26.f, -0.f, 19.f, -8.f, 14.f, -6.f, 7.f, -8.f, 4.f, -7.f, 3.f, -11.f, 0.f, -0.f,
+    95.f, -7.f, 94.f, -11.f, 89.f, -11.f, 83.f, -8.f, 82.f, -11.f, 77.f, -11.f, 72.f, -8.f, 69.f, -0.f, 59.f, -10.f, 51.f, -13.f, 46.f, -10.f, 38.f, -10.f, 33.f, -0.f, 25.f, -10.f, 20.f, -10.f, 13.f, -13.f, 4.f, -10.f, 0.f, -0.f,
+  };
+
+  Size textArea( 100.f, 50.f );
+  Size layoutSize( 100.f, 38.f );
+
+  LayoutTextData data =
+  {
+    "Layout multi-line RTL text with ellipsis.",
+    "שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    34u,
+    positions,
+    2u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    72u,
+    true,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutEllipsis05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutEllipsis05");
+
+  const std::string fontLatin( "TizenSans" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 51u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+
+  struct LineRun line01 =
+  {
+    { 0u, 11u },
+    { 0u, 11u },
+    78.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines;
+  lines.PushBack( line01 );
+
+  float positions[] =
+  {
+    0.f, -12.f
+  };
+
+  Size textArea( 100.f, 19.f );
+  Size layoutSize( 78.f, 19.f );
+
+  LayoutTextData data =
+  {
+    "Not enough height.",
+    "Hello world",
+    textArea,
+    1u,
+    fontDescriptionRuns.Begin(),
+    layoutSize,
+    1u,
+    positions,
+    1u,
+    lines.Begin(),
+    Layout::Engine::MULTI_LINE_BOX,
+    0u,
+    11u,
+    true,
+    true
+  };
+
+  if( !LayoutTextTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign01");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Begin alignment for the first paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::BEGIN,
+    Text::VerticalAlignment::TOP,
+    0u,
+    22u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign02");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 2.f, 61.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Begin alignment for the mid paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::BEGIN,
+    Text::VerticalAlignment::TOP,
+    22u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign03");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Begin alignment for the last paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::BEGIN,
+    Text::VerticalAlignment::TOP,
+    48u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign04");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 11.f, 17.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Center alignment for the first paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::CENTER,
+    Text::VerticalAlignment::TOP,
+    0u,
+    22u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign05");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, -1.f, 30.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Center alignment for the mid paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::CENTER,
+    Text::VerticalAlignment::TOP,
+    22u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign06");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 11.f, 21.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Center alignment for the last paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::CENTER,
+    Text::VerticalAlignment::TOP,
+    48u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign07(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign07");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 22.f, 35.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "End alignment for the first paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::END,
+    Text::VerticalAlignment::TOP,
+    0u,
+    22u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign08(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign08");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, -4.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "End alignment for the mid paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::END,
+    Text::VerticalAlignment::TOP,
+    22u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign09(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign09");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 22.f, 42.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "End alignment for the last paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::END,
+    Text::VerticalAlignment::TOP,
+    48u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    false
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign10(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign10");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Begin alignment for the first paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::END,
+    Text::VerticalAlignment::TOP,
+    0u,
+    22u,
+    6u,
+    positions,
+    Dali::LayoutDirection::RIGHT_TO_LEFT,
+    true
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign11(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign11");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 22.f, 35.f, 2.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "End alignment for the last paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::END,
+    Text::VerticalAlignment::TOP,
+    0u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    true
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextAlign12(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextAlign12");
+
+  // Calculate text alignment.
+
+  const std::string fontLatin( "TizenSans" );
+  const std::string fontHebrew( "TizenSansHebrew" );
+  const std::string fontArabic( "TizenSansArabic" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun01.familyLength = fontLatin.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontLatin.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 12u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 10u;
+  fontDescriptionRun02.familyLength = fontHebrew.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontHebrew.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 22u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun03.familyLength = fontArabic.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontArabic.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun04;
+  fontDescriptionRun04.characterRun.characterIndex = 36u;
+  fontDescriptionRun04.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun04.familyLength = fontLatin.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontLatin.c_str(), fontDescriptionRun04.familyLength );
+  fontDescriptionRun04.familyDefined = true;
+  fontDescriptionRun04.weightDefined = false;
+  fontDescriptionRun04.widthDefined = false;
+  fontDescriptionRun04.slantDefined = false;
+  fontDescriptionRun04.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun05;
+  fontDescriptionRun05.characterRun.characterIndex = 48u;
+  fontDescriptionRun05.characterRun.numberOfCharacters = 12u;
+  fontDescriptionRun05.familyLength = fontLatin.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontLatin.c_str(), fontDescriptionRun05.familyLength );
+  fontDescriptionRun05.familyDefined = true;
+  fontDescriptionRun05.weightDefined = false;
+  fontDescriptionRun05.widthDefined = false;
+  fontDescriptionRun05.slantDefined = false;
+  fontDescriptionRun05.sizeDefined = false;
+
+  FontDescriptionRun fontDescriptionRun06;
+  fontDescriptionRun06.characterRun.characterIndex = 60u;
+  fontDescriptionRun06.characterRun.numberOfCharacters = 14u;
+  fontDescriptionRun06.familyLength = fontArabic.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontArabic.c_str(), fontDescriptionRun06.familyLength );
+  fontDescriptionRun06.familyDefined = true;
+  fontDescriptionRun06.weightDefined = false;
+  fontDescriptionRun06.widthDefined = false;
+  fontDescriptionRun06.slantDefined = false;
+  fontDescriptionRun06.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns;
+  fontDescriptionRuns.PushBack( fontDescriptionRun01 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun02 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun03 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun04 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun05 );
+  fontDescriptionRuns.PushBack( fontDescriptionRun06 );
+
+  float positions[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
+
+  Size textArea( 100.f, 300.f );
+  AlignData data =
+  {
+    "Begin alignment for the first paragraph.",
+    "Hello world שלום עולם\nمرحبا بالعالم Hello world\nHello world مرحبا بالعالم.",
+    textArea,
+    6u,
+    fontDescriptionRuns.Begin(),
+    Text::HorizontalAlignment::BEGIN,
+    Text::VerticalAlignment::TOP,
+    48u,
+    26u,
+    6u,
+    positions,
+    Dali::LayoutDirection::LEFT_TO_RIGHT,
+    true
+  };
+
+  if( !AlignTest( data ) )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutSetGetDefaultLineSpacing(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLayoutSetGetDefaultLineSpacing");
+
+  Layout::Engine engine;
+  DALI_TEST_EQUALS( 0.f, engine.GetDefaultLineSpacing(), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  engine.SetDefaultLineSpacing( 10.f );
+  DALI_TEST_EQUALS( 10.f, engine.GetDefaultLineSpacing(), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextLayoutGetGlyphMetrics(void)
+{
+  tet_infoline(" UtcDaliTextLayoutGetGlyphMetrics");
+
+  // Test retrieving metrics from group of characters
+
+  const std::string fontFamily( "TizenSansHindi" );
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun01;
+  fontDescriptionRun01.characterRun.characterIndex = 0u;
+  fontDescriptionRun01.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun01.familyLength = fontFamily.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontFamily.c_str(), fontDescriptionRun01.familyLength );
+  fontDescriptionRun01.familyDefined = true;
+  fontDescriptionRun01.weightDefined = false;
+  fontDescriptionRun01.widthDefined = false;
+  fontDescriptionRun01.slantDefined = false;
+  fontDescriptionRun01.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun02;
+  fontDescriptionRun02.characterRun.characterIndex = 0u;
+  fontDescriptionRun02.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun02.familyLength = fontFamily.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength );
+  fontDescriptionRun02.familyDefined = true;
+  fontDescriptionRun02.weightDefined = false;
+  fontDescriptionRun02.widthDefined = false;
+  fontDescriptionRun02.slantDefined = false;
+  fontDescriptionRun02.sizeDefined = false;
+
+  // Set a known font description
+  FontDescriptionRun fontDescriptionRun03;
+  fontDescriptionRun03.characterRun.characterIndex = 0u;
+  fontDescriptionRun03.characterRun.numberOfCharacters = 2u;
+  fontDescriptionRun03.familyLength = fontFamily.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontFamily.c_str(), fontDescriptionRun03.familyLength );
+  fontDescriptionRun03.familyDefined = true;
+  fontDescriptionRun03.weightDefined = false;
+  fontDescriptionRun03.widthDefined = false;
+  fontDescriptionRun03.slantDefined = false;
+  fontDescriptionRun03.sizeDefined = false;
+
+  Vector<FontDescriptionRun> fontDescriptionRuns01;
+  fontDescriptionRuns01.PushBack( fontDescriptionRun01 );
+
+  Vector<FontDescriptionRun> fontDescriptionRuns02;
+  fontDescriptionRuns02.PushBack( fontDescriptionRun02 );
+
+  Vector<FontDescriptionRun> fontDescriptionRuns03;
+  fontDescriptionRuns03.PushBack( fontDescriptionRun03 );
+
+  // Set a text area.
+  Size textArea(100.f, 100.f);
+
+
+  // Group: second glyph doesn't exceed the width of the first glyph
+  float positions01[] = { 0.f, -11.f };
+
+  struct LineRun line01 =
+  {
+    { 0u, 1u },
+    { 0u, 1u },
+    11.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines01;
+  lines01.PushBack( line01 );
+
+  Size layoutSize01 = Vector2(11.f, 19.f);
+
+  // Group: second glyph doesn't exceed the width of the first glyph
+  float positions02[] = { 0.f, -11.f , 7.f, -15.f };
+
+  struct LineRun line02 =
+  {
+    { 0u, 2u },
+    { 0u, 2u },
+    15.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines02;
+  lines02.PushBack( line02 );
+
+  Size layoutSize02 = Vector2(15.f, 19.f);
+
+  // Group: second glyph doesn't exceed the width of the first glyph
+  float positions03[] = { 0.f, -11.f , 2.f, -15.f };
+
+  struct LineRun line03 =
+  {
+    { 0u, 2u },
+    { 0u, 2u },
+    11.f,
+    15.f,
+    -4.f,
+    0.f,
+    0.f,
+    0.f,
+    false,
+    false
+  };
+  Vector<LineRun> lines03;
+  lines03.PushBack( line03 );
+
+  Size layoutSize03 = Vector2(11.f, 19.f);
+
+ /////////////////////////////
+
+  struct LayoutTextData data[] =
+  {
+    {
+      "Single glyph",
+      "प",
+      textArea,
+      1u,
+      fontDescriptionRuns01.Begin(),
+      layoutSize01,
+      1u,
+      positions01,
+      1u,
+      lines01.Begin(),
+      Layout::Engine::SINGLE_LINE_BOX,
+      0u,
+      1u,
+      false,
+      true
+    },
+    {
+      "Group: second glyph exceeds the width of the first glyph",
+      "पो",
+      textArea,
+      1u,
+      fontDescriptionRuns02.Begin(),
+      layoutSize02,
+      2u,
+      positions02,
+      1u,
+      lines02.Begin(),
+      Layout::Engine::SINGLE_LINE_BOX,
+      0u,
+      2u,
+      false,
+      true
+    },
+   {
+      "Group: second glyph doesn't exceed the width of the first glyph",
+      "पे",
+      textArea,
+      1u,
+      fontDescriptionRuns03.Begin(),
+      layoutSize03,
+      2u,
+      positions03,
+      1u,
+      lines03.Begin(),
+      Layout::Engine::SINGLE_LINE_BOX,
+      0u,
+      2u,
+      false,
+      true
+    }
+  };
+  const unsigned int numberOfTests = sizeof(data)/sizeof(LayoutTextData);
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !LayoutTextTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp
new file mode 100755 (executable)
index 0000000..779eb56
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * 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 <iostream>
+
+#include <stdlib.h>
+#include <limits>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/internal/text/text-io.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+namespace
+{
+
+  ///////////////////////////////////////////////////////////
+
+  struct TokenComparisonData
+  {
+    std::string description;
+    std::string string1; ///< must be in lower case!!!!
+    std::string string2;
+    bool expectedResult;
+  };
+
+  bool TokenComparisonTest( const TokenComparisonData& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    const bool result = TokenComparison( data.string1,
+                                         data.string2.c_str(),
+                                         data.string2.size() );
+
+    if( result != data.expectedResult )
+    {
+      std::cout << "  different conparison result : " << result << ", expected : " << data.expectedResult << std::endl;
+      std::cout << "  comparing : [" << data.string1 << "] and [" << data.string2 << "]" << std::endl;
+
+      return false;
+    }
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////
+
+  struct ColorStringToVector4Data
+  {
+    std::string description;
+    std::string colorStr;
+    Vector4 expectedColor;
+  };
+
+  bool ColorStringToVector4Test( const ColorStringToVector4Data& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    Vector4 color;
+    ColorStringToVector4( data.colorStr.c_str(), data.colorStr.size(), color );
+
+    if( color != data.expectedColor )
+    {
+      std::cout << "  different color : " << color << ", expected : " << data.expectedColor << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////
+
+  struct Vector4ToColorStringData
+  {
+    std::string description;
+    Vector4 color;
+    std::string expectedColorStr;
+  };
+
+  bool Vector4ToColorStringTest( const Vector4ToColorStringData& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    std::string colorStr;
+    Vector4ToColorString( data.color, colorStr );
+
+    if( colorStr != data.expectedColorStr )
+    {
+      std::cout << "  different color : [" << colorStr << "], expected : [" << data.expectedColorStr << "]" << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////
+
+  struct StringToVector2Data
+  {
+    std::string description;
+    std::string vector2Str;
+    Vector2 expectedVector2;
+  };
+
+  bool StringToVector2Test( const StringToVector2Data& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    Vector2 vector2;
+    StringToVector2( data.vector2Str.c_str(), data.vector2Str.size(), vector2 );
+
+    if( vector2 != data.expectedVector2 )
+    {
+      std::cout << "  different vector2 : " << vector2 << ", expected : " << data.expectedVector2 << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////
+
+
+  struct Vector2ToStringData
+  {
+    std::string description;
+    Vector2 vector2;
+    std::string expectedVector2Str;
+  };
+
+  bool Vector2ToStringTest( const Vector2ToStringData& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    std::string vector2Str;
+    Vector2ToString( data.vector2, vector2Str );
+
+    if( vector2Str != data.expectedVector2Str )
+    {
+      std::cout << "  different vector2 : [" << vector2Str << "], expected : [" << data.expectedVector2Str << "]" << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////////
+
+
+  struct XHTMLEntityToUTF8Data
+  {
+    std::string description;
+    std::string xHTMLEntityString;
+    std::string expectedString;
+  };
+
+  bool XHTMLEntityToUTF8Test( const XHTMLEntityToUTF8Data& data )
+  {
+    std::cout << "  testing " << data.description << std::endl;
+
+    Vector<ColorRun> colorRuns;
+    Vector<FontDescriptionRun> fontRuns;
+    Vector<EmbeddedItem> items;
+    MarkupProcessData markupProcessData( colorRuns, fontRuns, items );
+    ProcessMarkupString( data.xHTMLEntityString, markupProcessData );
+
+    for( Vector<EmbeddedItem>::Iterator it = items.Begin(),
+           endIt = items.End();
+         it != endIt;
+         ++it )
+    {
+      EmbeddedItem& item = *it;
+      delete[] item.url;
+    }
+    items.Clear();
+
+    if( markupProcessData.markupProcessedText != data.expectedString )
+    {
+      std::cout << "  different output string : " << markupProcessData.markupProcessedText << ", expected : " << data.expectedString << " " << std::endl;
+      return false;
+    }
+
+    return true;
+  }
+
+} // namespace
+
+int UtcDaliTextTokenComparison(void)
+{
+  tet_infoline(" UtcDaliTextTokenComparison");
+
+  const TokenComparisonData data[] =
+  {
+    {
+      "void texts",
+      "",
+      "",
+      true
+    },
+    {
+      "different size text",
+      "hello",
+      "world!",
+      false
+    },
+    {
+      "different texts",
+      "hello",
+      "world",
+      false
+    },
+    {
+      "same texts",
+      "world",
+      "wOrLD",
+      true
+    },
+    {
+      "some punctuation characters, numbers, ...",
+      "hello0123456789.![?]",
+      "Hello0123456789.![?]",
+      true
+    }
+
+  };
+  const unsigned int numberOfTests = 5u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !TokenComparisonTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextColorStringToVector4(void)
+{
+  tet_infoline(" UtcDaliTextColorStringToVector4");
+
+  const ColorStringToVector4Data data[] =
+  {
+    {
+      "black string",
+      "bLack",
+      Color::BLACK
+    },
+    {
+      "white string",
+      "White",
+      Color::WHITE
+    },
+    {
+      "red string",
+      "reD",
+      Color::RED
+    },
+    {
+      "green string",
+      "green",
+      Color::GREEN
+    },
+    {
+      "blue string",
+      "blue",
+      Color::BLUE
+    },
+    {
+      "yellow string",
+      "yeLloW",
+      Color::YELLOW
+    },
+    {
+      "magenta string",
+      "MagEnta",
+      Color::MAGENTA
+    },
+    {
+      "cyan string",
+      "CyaN",
+      Color::CYAN
+    },
+    {
+      "transparent string",
+      "transparent",
+      Color::TRANSPARENT
+    },
+    {
+      "3 component web color",
+      "#F00",
+      Color::RED
+    },
+    {
+      "6 component web color",
+      "#fF0000",
+      Color::RED
+    },
+    {
+      "hex color red (ARGB)",
+      "0xffff0000",
+      Color::RED
+    },
+    {
+      "hex color green (ARGB)",
+      "0xFf00FF00",
+      Color::GREEN
+    },
+    {
+      "undefined color",
+      "undefined",
+      Vector4::ZERO
+    },
+  };
+  const unsigned int numberOfTests = 14u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !ColorStringToVector4Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextVector4ToColorString(void)
+{
+  tet_infoline(" UtcDaliTextVector4ToColorString");
+
+  const Vector4ToColorStringData data[] =
+  {
+    {
+      "black color",
+      Color::BLACK,
+      "black"
+    },
+    {
+      "white string",
+      Color::WHITE,
+      "white"
+    },
+    {
+      "red string",
+      Color::RED,
+      "red"
+    },
+    {
+      "green string",
+      Color::GREEN,
+      "green"
+    },
+    {
+      "blue string",
+      Color::BLUE,
+      "blue"
+    },
+    {
+      "yellow string",
+      Color::YELLOW,
+      "yellow"
+    },
+    {
+      "magenta string",
+      Color::MAGENTA,
+      "magenta",
+    },
+    {
+      "cyan string",
+      Color::CYAN,
+      "cyan"
+    },
+    {
+      "transparent string",
+      Color::TRANSPARENT,
+      "transparent"
+    },
+    {
+      "hex color",
+      Vector4( 0.4f, 0.5f, 0.6f, 1.f ),
+      "0xff667f99"
+    },
+  };
+  const unsigned int numberOfTests = 10u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !Vector4ToColorStringTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextStringToVector2(void)
+{
+  tet_infoline(" UtcDaliTextStringToVector2");
+  const StringToVector2Data data[] =
+  {
+    {
+      "void text",
+      "",
+      Vector2::ZERO
+    },
+    {
+      "zero zero",
+      "0 0",
+      Vector2::ZERO
+    },
+    {
+      "five four",
+      "5 4",
+      Vector2(5.f, 4.f)
+    }
+  };
+  const unsigned int numberOfTests = 3u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !StringToVector2Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextVector2ToString(void)
+{
+  tet_infoline(" UtcDaliTextVector2ToString");
+  const Vector2ToStringData data[] =
+  {
+    {
+      "zero zero",
+      Vector2::ZERO,
+      "0 0",
+    },
+    {
+      "five four",
+      Vector2(5.f, 4.f),
+      "5 4",
+    }
+  };
+  const unsigned int numberOfTests = 2u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !Vector2ToStringTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextXHTMLEntityToUTF8(void)
+{
+  tet_infoline(" UtcDaliTextXHTMLEntityToUTF8");
+  const XHTMLEntityToUTF8Data data[] =
+  {
+    {
+      "Text Without XHTML Entity",
+      "Checking XHTML Entitities",
+      "Checking XHTML Entitities"
+    },
+    {
+      "Text With XHTML Entity in Numeric form",
+      "Checking Numeric Entitities &#x26; &#x27; &#x3C; &#x3E; &#xA1; &#xA2; &#xA3; &#xA4; &#xA5; &#xA6; &#xA7; &#xA8; &#xA9; &#xAA; &#xAB; &#xAC; &#xAD; &#xAE; &#xAF; &#xB0; &#xB1; &#xB2; &#xB3; &#xB4; &#xB5; &#xB6; &#xB7; &#xB8; &#xB9; &#xBA; &#xBB; &#xBC; &#xBD; &#xBE; &#xBF; &#xC0; &#xC1; &#xC2; &#xC3; &#xC4; &#xC5; &#xE6; &#xC7; &#xC8; &#xC9; &#xCA; &#xCB; &#xCC; &#xCD; &#xCE; &#xCF; &#xF0; &#xD1; &#xD2; &#xD3; &#xD4; &#xD5; &#xD6; &#xD7; &#xD8; &#xD9; &#xDA; &#xDB; &#xDD; &#xFE; &#xDF; &#xE0; &#xE1; &#xE2; &#xE3; &#xE4; &#xE5; &#xE6; &#xE7; &#xE8; &#xE9; &#xEA; &#xEB; &#xEC; &#xED; &#xEE; &#xEF; &#xF0; &#xF1; &#xF2; &#xF3; &#xF4; &#xF5; &#xF6; &#xF7; &#xF8; &#xF9; &#xFA; &#xFB; &#xFC; &#xFD; &#xFE; &#xFF; &#x3B1; &#x3B2; &#x3B3; &#x3B4; &#x3B5; &#x3B6; &#x3B7; &#x3B8; &#x3B9; &#x3BA; &#x3BB; &#x3BC; &#x3BD; &#x3BE; &#x3BF; &#x3C0; &#x3C1; &#x3C3; &#x3C4; &#x3C5; &#x3C6; &#x3C7; &#x3C8; &#x3C9; &#x2026; &#x20AC; &#x2190; &#x2191; &#x2192; &#x2193; &#x2194; &#x2190; &#x2192; &#x2200; &#x2203; &#x2207; &#x220F; &#x2211; &#x2227; &#x2228; &#x222B; &#x2260; &#x2261; &#x2295; &#x22A5; &#x2020; &#x2021; &#x2022; ",
+      "Checking Numeric Entitities & ' < > ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å æ Ç È É Ê Ë Ì Í Î Ï ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ý þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω … € ← ↑ → ↓ ↔ ← → ∀ ∃ ∇ ∏ ∑ ∧ ∨ ∫ ≠ ≡ ⊕ ⊥ † ‡ • "
+    },
+    {
+      "Text With XHTML Named Entities",
+      "Checking Named Entitities &amp; &apos; &lt; &gt; &iexcl; &cent; &pound; &curren; &yen; &brvbar; &sect; &uml; &copy; &ordf; &laquo; &not; &shy; &reg; &macr; &deg; &plusmn; &sup2; &sup3; &acute; &micro; &para; &middot; &cedil; &sup1; &ordm; &raquo; &frac14; &frac12; &frac34; &iquest; &Agrave; &Aacute; &Acirc; &Atilde; &Auml; &Aring; &aelig; &Ccedil; &Egrave; &Eacute; &Ecirc; &Euml; &Igrave; &Iacute; &Icirc; &Iuml; &eth; &Ntilde; &Ograve; &Oacute; &Ocirc; &Otilde; &Ouml; &times; &Oslash; &Ugrave; &Uacute; &Ucirc; &Yacute; &thorn; &szlig; &agrave; &aacute; &acirc; &atilde; &auml; &aring; &aelig; &ccedil; &egrave; &eacute; &ecirc; &euml; &igrave; &iacute; &icirc; &iuml; &eth; &ntilde; &ograve; &oacute; &ocirc; &otilde; &ouml; &divide; &oslash; &ugrave; &uacute; &ucirc; &uuml; &yacute; &thorn; &yuml; &alpha; &beta; &gamma; &delta; &epsilon; &zeta; &eta; &theta; &iota; &kappa; &lambda; &mu; &nu; &xi; &omicron; &pi; &rho; &sigma; &tau; &upsilon; &phi; &chi; &psi; &omega; &hellip; &euro; &larr; &uarr; &rarr; &darr; &harr; &larr; &rarr; &forall; &exist; &nabla; &prod; &sum; &and; &or; &int; &ne; &equiv; &oplus; &perp; &dagger; &Dagger; &bull; ",
+      "Checking Named Entitities & ' < > ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å æ Ç È É Ê Ë Ì Í Î Ï ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ý þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω … € ← ↑ → ↓ ↔ ← → ∀ ∃ ∇ ∏ ∑ ∧ ∨ ∫ ≠ ≡ ⊕ ⊥ † ‡ • "
+    },
+    {
+      "Testing of < special character",
+      "Testing of < special character",
+      "Testing of "
+    },
+    {
+      "Testing of & special character",
+      "Testing of & special character",
+      "Testing of "
+    },
+    {
+      "Testing of & < > special character",
+      "Testing of \\& \\< \\> special character",
+      "Testing of & < > special character"
+    }
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !XHTMLEntityToUTF8Test( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-MultiLanguage.cpp
new file mode 100755 (executable)
index 0000000..559e34e
--- /dev/null
@@ -0,0 +1,1875 @@
+/*
+ * Copyright (c) 2018 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 <unistd.h>
+
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/multi-language-helper-functions.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions with different scripts.
+//
+// void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
+//                             const TextAbstraction::FontDescription& defaultFontDescription,
+//                             TextAbstraction::PointSize26Dot6 defaultPointSize,
+//                             CharacterIndex characterIndex,
+//                             TextAbstraction::FontDescription& fontDescription,
+//                             TextAbstraction::PointSize26Dot6& fontPointSize,
+//                             bool& isDefaultFont );
+//
+// Script GetScript( Length index,
+//                   Vector<ScriptRun>::ConstIterator& scriptRunIt,
+//                   const Vector<ScriptRun>::ConstIterator& scriptRunEndIt );
+//
+// Constructor, destructor and MultilanguageSupport::Get()
+//
+// void MultilanguageSupport::SetScripts( const Vector<Character>& text,
+//                                        CharacterIndex startIndex,
+//                                        Length numberOfCharacters,
+//                                        Vector<ScriptRun>& scripts );
+//
+// void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
+//                                           const Vector<ScriptRun>& scripts,
+//                                           const Vector<FontDescriptionRun>& fontDescriptions,
+//                                           const TextAbstraction::FontDescription& defaultFontDescription,
+//                                           TextAbstraction::PointSize26Dot6 defaultFontPointSize,
+//                                           CharacterIndex startIndex,
+//                                           Length numberOfCharacters,
+//                                           Vector<FontRun>& fonts );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
+const unsigned int NON_DEFAULT_FONT_SIZE = 40u;
+
+struct MergeFontDescriptionsData
+{
+  std::string description;                                 ///< Description of the experiment.
+  Vector<FontDescriptionRun> fontDescriptionRuns;          ///< The font description runs.
+  TextAbstraction::FontDescription defaultFontDescription; ///< The default font description.
+  TextAbstraction::PointSize26Dot6 defaultPointSize;       ///< The default point size.
+  unsigned int startIndex;                                 ///< The start index.
+  unsigned int numberOfCharacters;                         ///< The number of characters.
+  Vector<FontId> expectedFontIds;                          ///< The expected font ids.
+  Vector<bool> expectedIsDefault;                          ///< The expected font ids.
+};
+
+struct ScriptsData
+{
+  std::string description;         ///< Description of the experiment.
+  std::string text;                ///< Input text.
+  unsigned int index;              ///< The index of the first character to update the script.
+  unsigned int numberOfCharacters; ///< The numbers of characters to update the script.
+  Vector<ScriptRun> scriptRuns;    ///< Expected script runs.
+};
+
+struct ValidateFontsData
+{
+  std::string                description;         ///< Description of the experiment.
+  std::string                text;                ///< Input text.
+  std::string                defaultFont;         ///< The default font.
+  unsigned int               defaultFontSize;     ///< The default font size.
+  unsigned int               index;               ///< The index of the first character to update the script.
+  unsigned int               numberOfCharacters;  ///< The numbers of characters to update the script.
+  Vector<FontDescriptionRun> fontDescriptionRuns; ///< The font description runs.
+  Vector<FontRun>            fontRuns;            ///< The expected font runs.
+};
+
+//////////////////////////////////////////////////////////
+bool MergeFontDescriptionsTest( const MergeFontDescriptionsData& data )
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  Vector<FontId> fontIds;
+  fontIds.Resize( data.startIndex + data.numberOfCharacters, 0u );
+  Vector<bool> isDefaultFont;
+  isDefaultFont.Resize( data.startIndex + data.numberOfCharacters, true );
+
+  for( unsigned int index = data.startIndex; index < data.startIndex + data.numberOfCharacters; ++index )
+  {
+    TextAbstraction::FontDescription fontDescription;
+    TextAbstraction::PointSize26Dot6 fontPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+
+    MergeFontDescriptions( data.fontDescriptionRuns,
+                           data.defaultFontDescription,
+                           data.defaultPointSize,
+                           index,
+                           fontDescription,
+                           fontPointSize,
+                           isDefaultFont[index] );
+
+    if( !isDefaultFont[index] )
+    {
+      fontIds[index] = fontClient.GetFontId( fontDescription, fontPointSize );
+    }
+  }
+
+  if( fontIds.Count() != data.expectedFontIds.Count() )
+  {
+    std::cout << data.description << " Different number of font ids : " << fontIds.Count() << ", expected : " << data.expectedFontIds.Count() << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < fontIds.Count(); ++index )
+  {
+    if( fontIds[index] != data.expectedFontIds[index] )
+    {
+      std::cout << data.description << " Different font id at index : " << index << ", font id : " << fontIds[index] << ", expected : " << data.expectedFontIds[index] << std::endl;
+      std::cout << "           font ids : ";
+      for( unsigned int i=0;i<fontIds.Count();++i)
+      {
+        std::cout << fontIds[i] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "  expected font ids : ";
+      for( unsigned int i=0;i<data.expectedFontIds.Count();++i)
+      {
+        std::cout << data.expectedFontIds[i] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+
+    if( isDefaultFont[index] != data.expectedIsDefault[index] )
+    {
+      std::cout << data.description << " Different 'is font default' at index : " << index << ", is font default : " << isDefaultFont[index] << ", expected : " << data.expectedIsDefault[index] << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ScriptsTest( const ScriptsData& data )
+{
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = ( data.text.size() == 0 ) ? 0 :
+    Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                 data.text.size(),
+                 &utf32[0u] );
+
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the script info.
+  Vector<ScriptRun> scripts;
+  multilanguageSupport.SetScripts( utf32,
+                                   0u,
+                                   numberOfCharacters,
+                                   scripts );
+
+  if( ( 0u != data.index ) ||
+      ( numberOfCharacters != data.numberOfCharacters ) )
+  {
+    // 3) Clear the scripts.
+    ClearCharacterRuns( data.index,
+                        data.index + data.numberOfCharacters - 1u,
+                        scripts );
+
+    multilanguageSupport.SetScripts( utf32,
+                                     data.index,
+                                     data.numberOfCharacters,
+                                     scripts );
+  }
+
+  // 4) Compare the results.
+
+  tet_printf( "Testing %s\n", data.description.c_str() );
+  if( scripts.Count() != data.scriptRuns.Count() )
+  {
+    tet_printf("ScriptsTest FAIL: different number of scripts. %d, should be %d\n", scripts.Count(), data.scriptRuns.Count() );
+    for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(); it != scripts.End(); ++it)
+    {
+      const ScriptRun& run = *it;
+
+      std::cout << "  index : " << run.characterRun.characterIndex << ", num chars : " << run.characterRun.numberOfCharacters << ", script : [" << TextAbstraction::ScriptName[run.script] << "]" << std::endl;
+    }
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < scripts.Count(); ++index )
+  {
+    const ScriptRun& scriptRun1 = scripts[index];
+    const ScriptRun& scriptRun2 = data.scriptRuns[index];
+
+    if( scriptRun1.characterRun.characterIndex != scriptRun2.characterRun.characterIndex )
+    {
+      tet_printf("ScriptsTest FAIL: different character index. %d, should be %d\n", scriptRun1.characterRun.characterIndex, scriptRun2.characterRun.characterIndex );
+      return false;
+    }
+
+    if( scriptRun1.characterRun.numberOfCharacters != scriptRun2.characterRun.numberOfCharacters )
+    {
+      tet_printf("ScriptsTest FAIL: different number of characters. %d, should be %d\n", scriptRun1.characterRun.numberOfCharacters, scriptRun2.characterRun.numberOfCharacters );
+      return false;
+    }
+
+    if( scriptRun1.script != scriptRun2.script )
+    {
+      tet_printf("ScriptsTest FAIL: script index: %u, different script. %s, should be %s\n", index, TextAbstraction::ScriptName[scriptRun1.script], TextAbstraction::ScriptName[scriptRun2.script] );
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool ValidateFontTest( const ValidateFontsData& data )
+{
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = (data.text.size() == 0 ) ? 0 :
+    Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                                                   data.text.size(),
+                                                   &utf32[0u] );
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the script info.
+  Vector<ScriptRun> scripts;
+  multilanguageSupport.SetScripts( utf32,
+                                   0u,
+                                   numberOfCharacters,
+                                   scripts );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  // Get the default font id.
+  const FontId defaultFontId = fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + data.defaultFont,
+                                                     data.defaultFontSize );
+  TextAbstraction::FontDescription defaultFontDescription;
+  fontClient.GetDescription( defaultFontId, defaultFontDescription );
+
+  const TextAbstraction::PointSize26Dot6 defaultPointSize = fontClient.GetPointSize( defaultFontId );
+
+  Vector<FontRun> fontRuns;
+
+  // 3) Validate the fonts.
+  multilanguageSupport.ValidateFonts( utf32,
+                                      scripts,
+                                      data.fontDescriptionRuns,
+                                      defaultFontDescription,
+                                      defaultPointSize,
+                                      0u,
+                                      numberOfCharacters,
+                                      fontRuns );
+
+  if( ( 0u != data.index ) ||
+      ( numberOfCharacters != data.numberOfCharacters ) )
+  {
+    // 4) Clear the fonts.
+    ClearCharacterRuns( data.index,
+                        data.index + data.numberOfCharacters - 1u,
+                        fontRuns );
+
+    multilanguageSupport.ValidateFonts( utf32,
+                                        scripts,
+                                        data.fontDescriptionRuns,
+                                        defaultFontDescription,
+                                        defaultPointSize,
+                                        data.index,
+                                        data.numberOfCharacters,
+                                        fontRuns );
+  }
+
+  // 5) Compare the results.
+  if( data.fontRuns.Count() != fontRuns.Count() )
+  {
+    std::cout << "  Different number of font runs : " << fontRuns.Count() << ", expected : " << data.fontRuns.Count() << std::endl;
+    return false;
+  }
+
+
+  for( unsigned int index = 0; index < data.fontRuns.Count(); ++index )
+  {
+    const FontRun& run = fontRuns[index];
+    const FontRun& expectedRun = data.fontRuns[index];
+
+    if( run.characterRun.characterIndex != expectedRun.characterRun.characterIndex )
+    {
+      std::cout << "  character run : " << index << ", index : " << run.characterRun.characterIndex << ", expected : " << expectedRun.characterRun.characterIndex << std::endl;
+      return false;
+    }
+    if( run.characterRun.numberOfCharacters != expectedRun.characterRun.numberOfCharacters )
+    {
+      std::cout << "  character run : " << index << ", num chars : " << run.characterRun.numberOfCharacters << ", expected : " << expectedRun.characterRun.numberOfCharacters << std::endl;
+      return false;
+    }
+    if( run.fontId != expectedRun.fontId )
+    {
+      std::cout << "  character run : " << index << ", font : " << run.fontId << ", expected : " << expectedRun.fontId << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+int UtcDaliTextGetScript(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextGetScript");
+
+  Script script = TextAbstraction::LATIN;
+
+  // Text with no scripts.
+  Vector<ScriptRun> scriptRuns;
+  Vector<ScriptRun>::ConstIterator scriptRunIt = scriptRuns.Begin();
+  script = GetScript( 0u,
+                      scriptRunIt,
+                      scriptRuns.End() );
+
+  DALI_TEST_CHECK( TextAbstraction::UNKNOWN == script );
+
+  const unsigned int numberOfCharacters = 7u;
+  // Add scripts.
+  ScriptRun scriptRun01 =
+  {
+    {
+      0u,
+      2u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun02 =
+  {
+    {
+      2u,
+      2u,
+    },
+    TextAbstraction::HEBREW
+  };
+  ScriptRun scriptRun03 =
+  {
+    {
+      4u,
+      2u,
+    },
+    TextAbstraction::ARABIC
+  };
+  scriptRuns.PushBack( scriptRun01 );
+  scriptRuns.PushBack( scriptRun02 );
+  scriptRuns.PushBack( scriptRun03 );
+
+  // Expected results
+  TextAbstraction::Script expectedScripts[]=
+  {
+    TextAbstraction::LATIN,
+    TextAbstraction::LATIN,
+    TextAbstraction::HEBREW,
+    TextAbstraction::HEBREW,
+    TextAbstraction::ARABIC,
+    TextAbstraction::ARABIC,
+    TextAbstraction::UNKNOWN
+  };
+
+  scriptRunIt = scriptRuns.Begin();
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    script = GetScript( index,
+                        scriptRunIt,
+                        scriptRuns.End() );
+
+    DALI_TEST_CHECK( expectedScripts[index] == script );
+  }
+  DALI_TEST_CHECK( scriptRunIt == scriptRuns.End() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMergeFontDescriptions(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMergeFontDescriptions");
+
+  // Load some fonts.
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", NON_DEFAULT_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Italic.ttf" );
+
+  // To test the font width as GetFontId() with the font file path can't cache the width property.
+  TextAbstraction::FontDescription widthDescription;
+  widthDescription.path = "";
+  widthDescription.family = "DejaVu Serif";
+  widthDescription.weight = TextAbstraction::FontWeight::NORMAL;
+  widthDescription.width = TextAbstraction::FontWidth::EXPANDED;
+  widthDescription.slant = TextAbstraction::FontSlant::NORMAL;
+  fontClient.GetFontId( widthDescription );
+
+  // Test.
+
+  TextAbstraction::FontDescription defaultFontDescription01;
+  Vector<FontDescriptionRun> fontDescriptionRuns01;
+  Vector<FontId> expectedFontIds01;
+  Vector<bool> expectedIsFontDefault01;
+
+  TextAbstraction::FontDescription defaultFontDescription02;
+  Vector<FontDescriptionRun> fontDescriptionRuns02;
+  Vector<FontId> expectedFontIds02;
+  expectedFontIds02.PushBack( 0u );
+  expectedFontIds02.PushBack( 0u );
+  Vector<bool> expectedIsFontDefault02;
+  expectedIsFontDefault02.PushBack( true );
+  expectedIsFontDefault02.PushBack( true );
+
+  TextAbstraction::FontDescription defaultFontDescription03;
+  defaultFontDescription03.family = "DejaVu Serif";
+  Vector<FontDescriptionRun> fontDescriptionRuns03;
+
+  FontDescriptionRun fontDescription0301 =
+  {
+    {
+      0u,
+      2u
+    },
+    const_cast<char*>( "DejaVu Sans" ),
+    11u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  FontDescriptionRun fontDescription0302 =
+  {
+    {
+      2u,
+      2u
+    },
+    NULL,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::ITALIC,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    false,
+    false,
+    false,
+    true,
+    false
+  };
+  FontDescriptionRun fontDescription0303 =
+  {
+    {
+      4u,
+      2u
+    },
+    NULL,
+    0u,
+    TextAbstraction::FontWeight::BOLD,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    false,
+    true,
+    false,
+    false,
+    false
+  };
+  FontDescriptionRun fontDescription0304 =
+  {
+    {
+      6u,
+      2u
+    },
+    NULL,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    NON_DEFAULT_FONT_SIZE,
+    false,
+    false,
+    false,
+    false,
+    true
+  };
+  FontDescriptionRun fontDescription0305 =
+  {
+    {
+      8u,
+      2u
+    },
+    NULL,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::EXPANDED,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    false,
+    false,
+    true,
+    false,
+    false
+  };
+
+  fontDescriptionRuns03.PushBack( fontDescription0301 );
+  fontDescriptionRuns03.PushBack( fontDescription0302 );
+  fontDescriptionRuns03.PushBack( fontDescription0303 );
+  fontDescriptionRuns03.PushBack( fontDescription0304 );
+  fontDescriptionRuns03.PushBack( fontDescription0305 );
+
+  Vector<FontId> expectedFontIds03;
+  expectedFontIds03.PushBack( 1u );
+  expectedFontIds03.PushBack( 1u );
+  expectedFontIds03.PushBack( 5u );
+  expectedFontIds03.PushBack( 5u );
+  expectedFontIds03.PushBack( 4u );
+  expectedFontIds03.PushBack( 4u );
+  expectedFontIds03.PushBack( 3u );
+  expectedFontIds03.PushBack( 3u );
+  expectedFontIds03.PushBack( 6u );
+  expectedFontIds03.PushBack( 6u );
+  Vector<bool> expectedIsFontDefault03;
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+  expectedIsFontDefault03.PushBack( false );
+
+  const MergeFontDescriptionsData data[] =
+  {
+    {
+      "void text.",
+      fontDescriptionRuns01,
+      defaultFontDescription01,
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      0u,
+      expectedFontIds01,
+      expectedIsFontDefault01
+    },
+    {
+      "No description runs.",
+      fontDescriptionRuns02,
+      defaultFontDescription02,
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      2u,
+      expectedFontIds02,
+      expectedIsFontDefault02
+    },
+    {
+      "Some description runs.",
+      fontDescriptionRuns03,
+      defaultFontDescription03,
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      10u,
+      expectedFontIds03,
+      expectedIsFontDefault03
+    }
+  };
+  const unsigned int numberOfTests = 3u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !MergeFontDescriptionsTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMultiLanguageConstructor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageConstructor");
+
+  MultilanguageSupport multilanguageSupport;
+  DALI_TEST_CHECK( !multilanguageSupport );
+
+  MultilanguageSupport multilanguageSupport1 = MultilanguageSupport::Get();
+  DALI_TEST_CHECK( multilanguageSupport1 );
+
+  // To increase coverage.
+  MultilanguageSupport multilanguageSupport2 = MultilanguageSupport::Get();
+  DALI_TEST_CHECK( multilanguageSupport2 );
+
+  DALI_TEST_CHECK( multilanguageSupport1 == multilanguageSupport2 );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMultiLanguageSetScripts(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageSetScripts" );
+
+  // Void text.
+  Vector<ScriptRun> scriptRuns00;
+
+  // Hello world.
+  Vector<ScriptRun> scriptRuns01;
+  ScriptRun scriptRun0100 =
+  {
+    {
+      0u,
+      11u,
+    },
+    TextAbstraction::LATIN
+  };
+  scriptRuns01.PushBack( scriptRun0100 );
+
+  // Mix of LTR '\n'and RTL
+  Vector<ScriptRun> scriptRuns02;
+  ScriptRun scriptRun0200 =
+  {
+    {
+      0u,
+      12u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun0201 =
+  {
+    {
+      12u,
+      13u,
+    },
+    TextAbstraction::ARABIC
+  };
+  scriptRuns02.PushBack( scriptRun0200 );
+  scriptRuns02.PushBack( scriptRun0201 );
+
+  // Mix of RTL '\n'and LTR
+  Vector<ScriptRun> scriptRuns03;
+  ScriptRun scriptRun0300 =
+  {
+    {
+      0u,
+      14u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun0301 =
+  {
+    {
+      14u,
+      11u,
+    },
+    TextAbstraction::LATIN
+  };
+  scriptRuns03.PushBack( scriptRun0300 );
+  scriptRuns03.PushBack( scriptRun0301 );
+
+  // White spaces. At the beginning of the text.
+  Vector<ScriptRun> scriptRuns04;
+  ScriptRun scriptRun0400 =
+  {
+    {
+      0u,
+      15u,
+    },
+    TextAbstraction::LATIN
+  };
+  scriptRuns04.PushBack( scriptRun0400 );
+
+  // White spaces. At the end of the text.
+  Vector<ScriptRun> scriptRuns05;
+  ScriptRun scriptRun0500 =
+  {
+    {
+      0u,
+      15u,
+    },
+    TextAbstraction::LATIN
+  };
+  scriptRuns05.PushBack( scriptRun0500 );
+
+  // White spaces. At the middle of the text.
+  Vector<ScriptRun> scriptRuns06;
+  ScriptRun scriptRun0600 =
+  {
+    {
+      0u,
+      15u,
+    },
+    TextAbstraction::LATIN
+  };
+  scriptRuns06.PushBack( scriptRun0600 );
+
+  // White spaces between different scripts.
+  Vector<ScriptRun> scriptRuns07;
+  ScriptRun scriptRun0700 =
+  {
+    {
+      0u,
+      8u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun0701 =
+  {
+    {
+      8u,
+      5u,
+    },
+    TextAbstraction::HANGUL
+  };
+  scriptRuns07.PushBack( scriptRun0700 );
+  scriptRuns07.PushBack( scriptRun0701 );
+
+  // White spaces between different scripts and differetn directions. Starting LTR.
+  Vector<ScriptRun> scriptRuns08;
+  ScriptRun scriptRun0800 =
+  {
+    {
+      0u,
+      18u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun0801 =
+  {
+    {
+      18u,
+      14u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun0802 =
+  {
+    {
+      32u,
+      18u,
+    },
+    TextAbstraction::HANGUL
+  };
+  scriptRuns08.PushBack( scriptRun0800 );
+  scriptRuns08.PushBack( scriptRun0801 );
+  scriptRuns08.PushBack( scriptRun0802 );
+
+  // White spaces between different scripts and differetn directions. Starting RTL.
+  Vector<ScriptRun> scriptRuns09;
+  ScriptRun scriptRun0900 =
+  {
+    {
+      0u,
+      21u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun0901 =
+  {
+    {
+      21u,
+      16u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun0902 =
+  {
+    {
+      37u,
+      10u,
+    },
+    TextAbstraction::HANGUL
+  };
+  ScriptRun scriptRun0903 =
+  {
+    {
+      47u,
+      20u,
+    },
+    TextAbstraction::ARABIC
+  };
+  scriptRuns09.PushBack( scriptRun0900 );
+  scriptRuns09.PushBack( scriptRun0901 );
+  scriptRuns09.PushBack( scriptRun0902 );
+  scriptRuns09.PushBack( scriptRun0903 );
+
+  // Paragraphs with different directions.
+  Vector<ScriptRun> scriptRuns10;
+  ScriptRun scriptRun1000 =
+  {
+    {
+      0u,
+      20u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun1001 =
+  {
+    {
+      20u,
+      12u,
+    },
+    TextAbstraction::HEBREW
+  };
+  ScriptRun scriptRun1002 =
+  {
+    {
+      32u,
+      17u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun1003 =
+  {
+    {
+      49u,
+      18u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun1004 =
+  {
+    {
+      67u,
+      14u,
+    },
+    TextAbstraction::HANGUL
+  };
+  ScriptRun scriptRun1005 =
+  {
+    {
+      81u,
+      19u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun1006 =
+  {
+    {
+      100u,
+      13u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun1007 =
+  {
+    {
+      113u,
+      16u,
+    },
+    TextAbstraction::HEBREW
+  };
+  ScriptRun scriptRun1008 =
+  {
+    {
+      129u,
+      20u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun1009 =
+  {
+    {
+      149u,
+      14u,
+    },
+    TextAbstraction::ARABIC
+  };
+  ScriptRun scriptRun1010 =
+  {
+    {
+      163u,
+      18u,
+    },
+    TextAbstraction::HANGUL
+  };
+  ScriptRun scriptRun1011 =
+  {
+    {
+      181u,
+      17u,
+    },
+    TextAbstraction::HANGUL
+  };
+  scriptRuns10.PushBack( scriptRun1000 );
+  scriptRuns10.PushBack( scriptRun1001 );
+  scriptRuns10.PushBack( scriptRun1002 );
+  scriptRuns10.PushBack( scriptRun1003 );
+  scriptRuns10.PushBack( scriptRun1004 );
+  scriptRuns10.PushBack( scriptRun1005 );
+  scriptRuns10.PushBack( scriptRun1006 );
+  scriptRuns10.PushBack( scriptRun1007 );
+  scriptRuns10.PushBack( scriptRun1008 );
+  scriptRuns10.PushBack( scriptRun1009 );
+  scriptRuns10.PushBack( scriptRun1010 );
+  scriptRuns10.PushBack( scriptRun1011 );
+
+  // Paragraphs with no scripts mixed with paragraphs with scripts.
+  Vector<ScriptRun> scriptRuns11;
+  ScriptRun scriptRun1100 =
+  {
+    {
+      0u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1101 =
+  {
+    {
+      3u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1102 =
+  {
+    {
+      6u,
+      19u,
+    },
+    TextAbstraction::LATIN
+  };
+  ScriptRun scriptRun1103 =
+  {
+    {
+      25u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1104 =
+  {
+    {
+      28u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1105 =
+  {
+    {
+      31u,
+      15u,
+    },
+    TextAbstraction::HEBREW
+  };
+  ScriptRun scriptRun1106 =
+  {
+    {
+      46u,
+      2u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1107 =
+  {
+    {
+      48u,
+      2u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1108 =
+  {
+    {
+      50u,
+      2u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  scriptRuns11.PushBack( scriptRun1100 );
+  scriptRuns11.PushBack( scriptRun1101 );
+  scriptRuns11.PushBack( scriptRun1102 );
+  scriptRuns11.PushBack( scriptRun1103 );
+  scriptRuns11.PushBack( scriptRun1104 );
+  scriptRuns11.PushBack( scriptRun1105 );
+  scriptRuns11.PushBack( scriptRun1106 );
+  scriptRuns11.PushBack( scriptRun1107 );
+  scriptRuns11.PushBack( scriptRun1108 );
+
+  // Paragraphs with no scripts.
+  Vector<ScriptRun> scriptRuns12;
+  ScriptRun scriptRun1200 =
+  {
+    {
+      0u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1201 =
+  {
+    {
+      3u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1202 =
+  {
+    {
+      6u,
+      3u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  ScriptRun scriptRun1203 =
+  {
+    {
+      9u,
+      2u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  scriptRuns12.PushBack( scriptRun1200 );
+  scriptRuns12.PushBack( scriptRun1201 );
+  scriptRuns12.PushBack( scriptRun1202 );
+  scriptRuns12.PushBack( scriptRun1203 );
+
+  Vector<ScriptRun> scriptRuns13;
+  ScriptRun scriptRun1301 =
+  {
+    {
+      0u,
+      4u,
+    },
+    TextAbstraction::UNKNOWN
+  };
+  scriptRuns13.PushBack( scriptRun1301 );
+
+  const ScriptsData data[] =
+  {
+    {
+      "void text",
+      "",
+      0u,
+      0u,
+      scriptRuns00,
+    },
+    {
+      "Easy latin script",
+      "Hello world",
+      0u,
+      11u,
+      scriptRuns01,
+    },
+    {
+      "Mix of LTR '\\n'and RTL",
+      "Hello world\nمرحبا بالعالم",
+      0u,
+      25u,
+      scriptRuns02,
+    },
+    {
+      "Update mix of LTR '\\n'and RTL. Update LTR",
+      "Hello world\nمرحبا بالعالم",
+      0u,
+      12u,
+      scriptRuns02,
+    },
+    {
+      "Update mix of LTR '\\n'and RTL. Update RTL",
+      "Hello world\nمرحبا بالعالم",
+      12u,
+      13u,
+      scriptRuns02,
+    },
+    {
+      "Mix of RTL '\\n'and LTR",
+      "مرحبا بالعالم\nHello world",
+      0u,
+      25u,
+      scriptRuns03,
+    },
+    {
+      "Update mix of RTL '\\n'and LTR. Update RTL",
+      "مرحبا بالعالم\nHello world",
+      0u,
+      14u,
+      scriptRuns03,
+    },
+    {
+      "Update mix of RTL '\\n'and LTR. Update LTR",
+      "مرحبا بالعالم\nHello world",
+      14u,
+      11u,
+      scriptRuns03,
+    },
+    {
+      "White spaces. At the beginning of the text.",
+      "    Hello world",
+      0u,
+      15u,
+      scriptRuns04,
+    },
+    {
+      "White spaces. At the end of the text.",
+      "Hello world    ",
+      0u,
+      15u,
+      scriptRuns05,
+    },
+    {
+      "White spaces. At the middle of the text.",
+      "Hello     world",
+      0u,
+      15u,
+      scriptRuns06,
+    },
+    {
+      "White spaces between different scripts.",
+      "  Hel   세계   ",
+      0u,
+      13u,
+      scriptRuns07,
+    },
+    {
+      "White spaces between different scripts and differetn directions. Starting LTR.",
+      "  Hello   world   مرحبا  بالعالم     안녕하세요   세계   ",
+      0u,
+      50u,
+      scriptRuns08,
+    },
+    {
+      "White spaces between different scripts and differetn directions. Starting RTL.",
+      "   مرحبا  بالعالم    Hello   world   안녕하세요   세계   مرحبا  بالعالم   ",
+      0u,
+      67u,
+      scriptRuns09
+    },
+    {
+      "Paragraphs with different directions.",
+      "   مرحبا  بالعالم   שלום עולם   مرحبا  بالعالم  \n "
+      " Hello   world   안녕하세요   세계   \n "
+      "  مرحبا  بالعالم  Hello   world    שלום עולם  \n  "
+      " Hello   world    مرحبا  بالعالم    안녕하세요   세계   \n "
+      "   안녕하세요   세계   ",
+      0u,
+      198u,
+      scriptRuns10
+    },
+    {
+      "Update paragraphs with different directions. Update initial paragraphs.",
+      "   مرحبا  بالعالم   שלום עולם   مرحبا  بالعالم  \n "
+      " Hello   world   안녕하세요   세계   \n "
+      "  مرحبا  بالعالم  Hello   world    שלום עולם  \n  "
+      " Hello   world    مرحبا  بالعالم    안녕하세요   세계   \n "
+      "   안녕하세요   세계   ",
+      0u,
+      81u,
+      scriptRuns10
+    },
+    {
+      "Update paragraphs with different directions. Update middle paragraphs.",
+      "   مرحبا  بالعالم   שלום עולם   مرحبا  بالعالم  \n "
+      " Hello   world   안녕하세요   세계   \n "
+      "  مرحبا  بالعالم  Hello   world    שלום עולם  \n  "
+      " Hello   world    مرحبا  بالعالم    안녕하세요   세계   \n "
+      "   안녕하세요   세계   ",
+      49u,
+      80u,
+      scriptRuns10
+    },
+    {
+      "Update paragraphs with different directions. Update final paragraphs.",
+      "   مرحبا  بالعالم   שלום עולם   مرحبا  بالعالم  \n "
+      " Hello   world   안녕하세요   세계   \n "
+      "  مرحبا  بالعالم  Hello   world    שלום עולם  \n  "
+      " Hello   world    مرحبا  بالعالم    안녕하세요   세계   \n "
+      "   안녕하세요   세계   ",
+      129u,
+      69u,
+      scriptRuns10
+    },
+    {
+      "Paragraphs with no scripts mixed with paragraphs with scripts.",
+      "  \n  \n   Hello   world  \n  \n  \n   שלום עולם  \n \n \n  ",
+      0u,
+      52u,
+      scriptRuns11
+    },
+    {
+      "Paragraphs with no scripts.",
+      "  \n  \n  \n  ",
+      0u,
+      11u,
+      scriptRuns12
+    },
+    {
+      "Update paragraphs with no scripts. Update initial paragraphs.",
+      "  \n  \n  \n  ",
+      0u,
+      3u,
+      scriptRuns12
+    },
+    {
+      "Update paragraphs with no scripts. Update middle paragraphs.",
+      "  \n  \n  \n  ",
+      3u,
+      6u,
+      scriptRuns12
+    },
+    {
+      "Update paragraphs with no scripts. Update final paragraphs.",
+      "  \n  \n  \n  ",
+      9u,
+      2u,
+      scriptRuns12
+    },
+    {
+      "Unknown scripts.",
+      "ᚩᚯᚱᚸ", // Runic script not currentlu supported.
+      0u,
+      4u,
+      scriptRuns13
+    }
+  };
+  const unsigned int numberOfTests = 24u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ScriptsTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextMultiLanguageValidateFonts01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextMultiLanguageValidateFonts");
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  const PointSize26Dot6 pointSize01 = static_cast<PointSize26Dot6>( 21.f * 64.f );
+  const PointSize26Dot6 pointSize02 = static_cast<PointSize26Dot6>( 35.f * 64.f );
+
+  // Load some fonts.
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/BreezeColorEmoji.ttf", EMOJI_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf", pointSize01 );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf", pointSize02 );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf", pointSize01 );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf", pointSize02 );
+
+  // Font id 1 --> TizenSansArabicRegular.ttf
+  // Font id 2 --> TizenSansHebrewRegular.ttf
+  // Font id 3 --> BreezeColorEmoji.ttf
+  // Font id 4 --> TizenSansRegular.ttf, size 8
+  // Font id 5 --> TizenSansRegular.ttf, size 16
+  // Font id 6 --> TizenSansHebrewRegular.ttf, size 8
+  // Font id 7 --> TizenSansHebrewRegular.ttf, size 16
+  // Font id 8 --> (default)
+
+  Vector<FontRun> fontRuns01;
+  Vector<FontDescriptionRun> fontDescriptions01;
+
+  FontRun fontRun0201 =
+  {
+    {
+      0u,
+      11u
+    },
+    8u
+  };
+  Vector<FontRun> fontRuns02;
+  fontRuns02.PushBack( fontRun0201 );
+
+  FontDescriptionRun fontDescription0201 =
+  {
+    {
+      0u,
+      11u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  Vector<FontDescriptionRun> fontDescriptions02;
+  fontDescriptions02.PushBack( fontDescription0201 );
+
+  FontRun fontRun0301 =
+  {
+    {
+      0u,
+      12u
+    },
+    8u
+  };
+  FontRun fontRun0302 =
+  {
+    {
+      12u,
+      12u
+    },
+    8u
+  };
+  FontRun fontRun0303 =
+  {
+    {
+      24u,
+      4u
+    },
+    8u
+  };
+  Vector<FontRun> fontRuns03;
+  fontRuns03.PushBack( fontRun0301 );
+  fontRuns03.PushBack( fontRun0302 );
+  fontRuns03.PushBack( fontRun0303 );
+
+  Vector<FontDescriptionRun> fontDescriptions03;
+
+  FontRun fontRun0701 =
+  {
+    {
+      0u,
+      4u
+    },
+    2u
+  };
+  FontRun fontRun0702 =
+  {
+    {
+      4u,
+      1u
+    },
+    8u
+  };
+  FontRun fontRun0703 =
+  {
+    {
+      5u,
+      4u
+    },
+    2u
+  };
+  Vector<FontRun> fontRuns07;
+  fontRuns07.PushBack( fontRun0701 );
+  fontRuns07.PushBack( fontRun0702 );
+  fontRuns07.PushBack( fontRun0703 );
+
+  FontDescriptionRun fontDescription0701 =
+  {
+    {
+      0u,
+      4u
+    },
+    const_cast<char*>( "TizenSansHebrew" ),
+    15u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  FontDescriptionRun fontDescription0702 =
+  {
+    {
+      5u,
+      4u
+    },
+    const_cast<char*>( "TizenSansHebrew" ),
+    15u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  Vector<FontDescriptionRun> fontDescriptions07;
+  fontDescriptions07.PushBack( fontDescription0701 );
+  fontDescriptions07.PushBack( fontDescription0702 );
+
+  FontRun fontRun0801 =
+  {
+    {
+      0u,
+      9u
+    },
+    2u
+  };
+  Vector<FontRun> fontRuns08;
+  fontRuns08.PushBack( fontRun0801 );
+
+  Vector<FontDescriptionRun> fontDescriptions08;
+
+  FontRun fontRun0901 =
+  {
+    {
+      0u,
+      4u
+    },
+    3u
+  };
+  Vector<FontRun> fontRuns09;
+  fontRuns09.PushBack( fontRun0901 );
+
+  Vector<FontDescriptionRun> fontDescriptions09;
+  FontDescriptionRun fontDescription0901 =
+  {
+    {
+      0u,
+      4u
+    },
+    const_cast<char*>( "BreezeColorEmoji" ),
+    16u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    EMOJI_FONT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  fontDescriptions09.PushBack( fontDescription0901 );
+
+  FontRun fontRun1001 =
+  {
+    {
+      0u,
+      13u
+    },
+    4u
+  };
+  FontRun fontRun1002 =
+  {
+    {
+      13u,
+      9u
+    },
+    6u
+  };
+  FontRun fontRun1003 =
+  {
+    {
+      22u,
+      15u
+    },
+    5u
+  };
+  FontRun fontRun1004 =
+  {
+    {
+      37u,
+      9u
+    },
+    7u
+  };
+  Vector<FontRun> fontRuns10;
+  fontRuns10.PushBack( fontRun1001 );
+  fontRuns10.PushBack( fontRun1002 );
+  fontRuns10.PushBack( fontRun1003 );
+  fontRuns10.PushBack( fontRun1004 );
+
+  FontDescriptionRun fontDescription1001 =
+  {
+    {
+      0u,
+      13u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    pointSize01,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  FontDescriptionRun fontDescription1002 =
+  {
+    {
+      13u,
+      9u
+    },
+    const_cast<char*>( "TizenSansHebrew" ),
+    15u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    pointSize01,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  FontDescriptionRun fontDescription1003 =
+  {
+    {
+      22u,
+      15u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    pointSize02,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  FontDescriptionRun fontDescription1004 =
+  {
+    {
+      37u,
+      9u
+    },
+    const_cast<char*>( "TizenSansHebrew" ),
+    15u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    pointSize02,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  Vector<FontDescriptionRun> fontDescriptions10;
+  fontDescriptions10.PushBack( fontDescription1001 );
+  fontDescriptions10.PushBack( fontDescription1002 );
+  fontDescriptions10.PushBack( fontDescription1003 );
+  fontDescriptions10.PushBack( fontDescription1004 );
+
+  FontRun fontRun1101 =
+  {
+    {
+      0u,
+      22u
+    },
+    5u
+  };
+  Vector<FontRun> fontRuns11;
+  fontRuns11.PushBack( fontRun1101 );
+
+  FontDescriptionRun fontDescription1101 =
+  {
+    {
+      0,
+      22u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    pointSize02,
+    true,
+    false,
+    false,
+    false,
+    true
+  };
+  Vector<FontDescriptionRun> fontDescriptions11;
+  fontDescriptions11.PushBack( fontDescription1101 );
+
+  FontRun fontRun1201 =
+  {
+    {
+      0u,
+      6u
+    },
+    8u
+  };
+  FontRun fontRun1202 =
+  {
+    {
+      6u,
+      1u
+    },
+    9u
+  };
+  FontRun fontRun1203 =
+  {
+    {
+      7u,
+      5u
+    },
+    8u
+  };
+  Vector<FontRun> fontRuns12;
+  fontRuns12.PushBack( fontRun1201 );
+  fontRuns12.PushBack( fontRun1202 );
+  fontRuns12.PushBack( fontRun1203 );
+
+  FontDescriptionRun fontDescription1201 =
+  {
+    {
+      0u,
+      6u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  FontDescriptionRun fontDescription1202 =
+  {
+    {
+      6u,
+      1u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  FontDescriptionRun fontDescription1203 =
+  {
+    {
+      7u,
+      5u
+    },
+    const_cast<char*>( "TizenSans" ),
+    9u,
+    TextAbstraction::FontWeight::NORMAL,
+    TextAbstraction::FontWidth::NORMAL,
+    TextAbstraction::FontSlant::NORMAL,
+    0u,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  Vector<FontDescriptionRun> fontDescriptions12;
+  fontDescriptions12.PushBack( fontDescription1201 );
+  fontDescriptions12.PushBack( fontDescription1202 );
+  fontDescriptions12.PushBack( fontDescription1203 );
+
+  const ValidateFontsData data[] =
+  {
+    {
+      "void text.",
+      "",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      0u,
+      fontDescriptions01,
+      fontRuns01
+    },
+    {
+      "Easy latin script.",
+      "Hello world",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      11u,
+      fontDescriptions02,
+      fontRuns02
+    },
+    {
+      "Different paragraphs.",
+      "Hello world\nhello world\ndemo",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      28u,
+      fontDescriptions03,
+      fontRuns03
+    },
+    {
+      "Different paragraphs. Update the initial paragraph.",
+      "Hello world\nhello world\ndemo",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      12u,
+      fontDescriptions03,
+      fontRuns03
+    },
+    {
+      "Different paragraphs. Update the middle paragraph.",
+      "Hello world\nhello world\ndemo",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      12u,
+      12u,
+      fontDescriptions03,
+      fontRuns03
+    },
+    {
+      "Different paragraphs. Update the final paragraph.",
+      "Hello world\nhello world\ndemo",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      24u,
+      4u,
+      fontDescriptions03,
+      fontRuns03
+    },
+    {
+      "Hebrew text. Default font: latin",
+      "שלום עולם",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      9u,
+      fontDescriptions07,
+      fontRuns07
+    },
+    {
+      "Hebrew text. Default font: hebrew",
+      "שלום עולם",
+      "/tizen/TizenSansHebrewRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      9u,
+      fontDescriptions08,
+      fontRuns08
+    },
+    {
+      "Emojis",
+      "\xF0\x9F\x98\x81\xF0\x9F\x98\x82\xF0\x9F\x98\x83\xF0\x9F\x98\x84",
+      "/tizen/BreezeColorEmoji.ttf",
+      EMOJI_FONT_SIZE,
+      0u,
+      4u,
+      fontDescriptions09,
+      fontRuns09
+    },
+    {
+      "Mix text. Default font: latin. Different font sizes",
+      "Hello world, שלום עולם, hello world, שלום עולם",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      46u,
+      fontDescriptions10,
+      fontRuns10
+    },
+    {
+      "Unknown script -> changed to LATIN",
+      "WRC – The Official App",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      22u,
+      fontDescriptions11,
+      fontRuns11
+    },
+    {
+      "Common script.",
+      "Hello \tworld",
+      "/tizen/TizenSansRegular.ttf",
+      TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+      0u,
+      12u,
+      fontDescriptions12,
+      fontRuns12
+    },
+  };
+  const unsigned int numberOfTests = 12u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    if( !ValidateFontTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Segmentation.cpp
new file mode 100644 (file)
index 0000000..cfbf325
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2018 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/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions with different scripts.
+// void SetLineBreakInfo( const Vector<Character>& text,
+//                        Vector<LineBreakInfo>& lineBreakInfo );
+// void SetWordBreakInfo( const Vector<Character>& text,
+//                        CharacterIndex startIndex,
+//                        Length numberOfCharacters,
+//                        Vector<WordBreakInfo>& wordBreakInfo );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct BreakInfoData
+{
+  std::string description;        ///< Description of the test.
+  std::string text;               ///< input text.
+  uint32_t    index;              ///< The index from where to start to query the break info.
+  uint32_t    numberOfCharacters; ///< The requested number of characters.
+  std::string breakInfo;          ///< The expected break info.
+};
+
+bool LineBreakInfoTest( const BreakInfoData& data )
+{
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = ( data.text.size() == 0 ) ? 0 :
+    Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                 data.text.size(),
+                 &utf32[0u] );
+
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the line break info for the whole text.
+  Vector<LineBreakInfo> lineBreakInfo;
+  lineBreakInfo.Resize( numberOfCharacters );
+
+  SetLineBreakInfo( utf32,
+                    0u,
+                    numberOfCharacters,
+                    lineBreakInfo );
+
+  // 3) Update the word text info if it's requested for part of the text.
+  if( ( 0u != data.index ) &&
+      ( numberOfCharacters != data.numberOfCharacters ) )
+  {
+    // Clear part of the line break info.
+    lineBreakInfo.Erase( lineBreakInfo.Begin() + data.index,
+                         lineBreakInfo.Begin() + data.index + data.numberOfCharacters );
+
+    // Update the word line info.
+    SetLineBreakInfo( utf32,
+                      data.index,
+                      data.numberOfCharacters,
+                      lineBreakInfo );
+  }
+
+  // 4) compare the results
+  std::ostringstream breakInfo;
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    breakInfo << static_cast<unsigned int>( lineBreakInfo[index] );
+  }
+
+  if( data.breakInfo != breakInfo.str() )
+  {
+    std::cout << "                text : [" << data.text << "]" << std::endl;
+    std::cout << "               index : " <<  data.index << std::endl;
+    std::cout << "  numberOfCharacters : " <<  data.numberOfCharacters << std::endl;
+    std::cout << "            expected : [" << data.breakInfo << "]" << std::endl;
+    std::cout << "                 got : [" << breakInfo.str() << "]" << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+bool WordBreakInfoTest( const BreakInfoData& data )
+{
+  // 1) Convert to utf32
+  Vector<Character> utf32;
+  utf32.Resize( data.text.size() );
+
+  const uint32_t numberOfCharacters = ( data.text.size() == 0 ) ? 0 :
+    Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( data.text.c_str() ),
+                 data.text.size(),
+                 &utf32[0u] );
+
+  utf32.Resize( numberOfCharacters );
+
+  // 2) Set the word break info for the whole text.
+  Vector<WordBreakInfo> wordBreakInfo;
+  wordBreakInfo.Resize( numberOfCharacters );
+
+  SetWordBreakInfo( utf32,
+                    0u,
+                    numberOfCharacters,
+                    wordBreakInfo );
+
+  // 3) Update the word text info if it's requested for part of the text.
+  if( ( 0u != data.index ) &&
+      ( numberOfCharacters != data.numberOfCharacters ) )
+  {
+    // Clear part of the word break info.
+    wordBreakInfo.Erase( wordBreakInfo.Begin() + data.index,
+                         wordBreakInfo.Begin() + data.index + data.numberOfCharacters );
+
+    // Update the word break info.
+    SetWordBreakInfo( utf32,
+                      data.index,
+                      data.numberOfCharacters,
+                      wordBreakInfo );
+  }
+
+  // 4) compare the results
+  std::ostringstream breakInfo;
+
+  for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+  {
+    breakInfo << static_cast<unsigned int>( wordBreakInfo[index] );
+  }
+
+  if( data.breakInfo != breakInfo.str() )
+  {
+    std::cout << "                text : [" << data.text << "]" << std::endl;
+    std::cout << "               index : " <<  data.index << std::endl;
+    std::cout << "  numberOfCharacters : " <<  data.numberOfCharacters << std::endl;
+    std::cout << "            expected : [" << data.breakInfo << "]" << std::endl;
+    std::cout << "                 got : [" << breakInfo.str() << "]" << std::endl;
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextSegnemtationSetLineBreakInfo(void)
+{
+  tet_infoline(" UtcDaliTextSegnemtationSetLineBreakInfo");
+
+  struct BreakInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      "",
+    },
+    {
+      "Latin script",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      0u,
+      317u,
+      "22222122222122222122212222212222212222222222122122221222221222222222122122220"
+      "2221221222212222222122222222221222222122222222122222222122212220"
+      "221222122222122222221222222222122212222221222222212220"
+      "22122222212222222122222222222122221222122222122222222222122222222222212220"
+      "222222122222221221222212212221222222122222222220",
+    },
+    {
+      "Latin script. Update initial paragraphs.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      0u,
+      141u,
+      "22222122222122222122212222212222212222222222122122221222221222222222122122220"
+      "2221221222212222222122222222221222222122222222122222222122212220"
+      "221222122222122222221222222222122212222221222222212220"
+      "22122222212222222122222222222122221222122222122222222222122222222222212220"
+      "222222122222221221222212212221222222122222222220",
+    },
+    {
+      "Latin script. Update mid paragraphs.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      141u,
+      128u,
+      "22222122222122222122212222212222212222222222122122221222221222222222122122220"
+      "2221221222212222222122222222221222222122222222122222222122212220"
+      "221222122222122222221222222222122212222221222222212220"
+      "22122222212222222122222222222122221222122222122222222222122222222222212220"
+      "222222122222221221222212212221222222122222222220",
+    },
+    {
+      "Latin script. Update final paragraphs.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      195u,
+      122u,
+      "22222122222122222122212222212222212222222222122122221222221222222222122122220"
+      "2221221222212222222122222222221222222122222222122222222122212220"
+      "221222122222122222221222222222122212222221222222212220"
+      "22122222212222222122222222222122221222122222122222222222122222222222212220"
+      "222222122222221221222212212221222222122222222220",
+    },
+    {
+      "Japanese script",
+      "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n"
+      "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n"
+      "韓国統一省によると15年だけで1320億ウォン(約130億円)が同工業団地を通じ北朝鮮に支払われたという。",
+      0u,
+      132u,
+      "1111111111111111111111220"
+      "111111211111111111111111111111111111111111111111111220"
+      "11111111121111122211111212211211111111111111111111120",
+    },
+    {
+      "Chinese script",
+      "在被捕的64人中,警方落案起訴了35名男子和3名女子,他們年齡介乎15到70歲。\n"
+      "38人中有1人獲准保釋。\n"
+      "16名年齡介乎14到33歲的被捕人士獲准保釋候查,另有10人仍被拘留作進一步調查。",
+      0u,
+      95u,
+      "11112112111111112111111112111111121121220"
+      "2111111111220"
+      "21111112112111111111111211121111111111120",
+    }
+  };
+  const unsigned int numberOfTests = 7u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !LineBreakInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextSegnemtationSetWordBreakInfo(void)
+{
+  tet_infoline(" UtcDaliTextSegnemtationSetWordBreakInfo");
+
+  struct BreakInfoData data[] =
+  {
+    {
+      "Zero characters.",
+      "",
+      0u,
+      0u,
+      "",
+    },
+    {
+      "Latin script, full text.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      0u,
+      317u,
+      "11110011110011110011001110001111001111111110010011000111100111111110010011000"
+      "1100100111001111110011111111000111110011111110011111110011001000"
+      "100110011110011111100111111100011001111100111111001000"
+      "10011111001111110011111111110011000110011110011111111110011111111111001000"
+      "111110011111100100110001001100111110011111111100",
+    },
+    {
+      "Latin script, update first paragraph.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      0u,
+      77u,
+      "11110011110011110011001110001111001111111110010011000111100111111110010011000"
+      "1100100111001111110011111111000111110011111110011111110011001000"
+      "100110011110011111100111111100011001111100111111001000"
+      "10011111001111110011111111110011000110011110011111111110011111111111001000"
+      "111110011111100100110001001100111110011111111100",
+    },
+    {
+      "Latin script, update middle paragraphs.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      77u,
+      118u,
+      "11110011110011110011001110001111001111111110010011000111100111111110010011000"
+      "1100100111001111110011111111000111110011111110011111110011001000"
+      "100110011110011111100111111100011001111100111111001000"
+      "10011111001111110011111111110011000110011110011111111110011111111111001000"
+      "111110011111100100110001001100111110011111111100",
+    },
+    {
+      "Latin script, update last paragraph.",
+      "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+      "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+      "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+      "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+      "Quidam corpora at duo. An eos possim scripserit?",
+      269u,
+      48u,
+      "11110011110011110011001110001111001111111110010011000111100111111110010011000"
+      "1100100111001111110011111111000111110011111110011111110011001000"
+      "100110011110011111100111111100011001111100111111001000"
+      "10011111001111110011111111110011000110011110011111111110011111111111001000"
+      "111110011111100100110001001100111110011111111100",
+    },
+    {
+      "Japanese script, full text.",
+      "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n"
+      "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n"
+      "韓国統一省によると15年だけで1320億ウォン(約130億円)が同工業団地を通じ北朝鮮に支払われたという。",
+      0u,
+      132u,
+      "0000000000000010000000000"
+      "000000000000000000000000000000000000000000000000000000"
+      "00000000010000011100110001100000000000000000000000000",
+    },
+    {
+      "Japanese script, update first paragraph.",
+      "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n"
+      "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n"
+      "韓国統一省によると15年だけで1320億ウォン(約130億円)が同工業団地を通じ北朝鮮に支払われたという。",
+      0u,
+      25u,
+      "0000000000000010000000000"
+      "000000000000000000000000000000000000000000000000000000"
+      "00000000010000011100110001100000000000000000000000000",
+    },
+    {
+      "Japanese script, update middle paragraph.",
+      "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n"
+      "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n"
+      "韓国統一省によると15年だけで1320億ウォン(約130億円)が同工業団地を通じ北朝鮮に支払われたという。",
+      25u,
+      54u,
+      "0000000000000010000000000"
+      "000000000000000000000000000000000000000000000000000000"
+      "00000000010000011100110001100000000000000000000000000",
+    },
+    {
+      "Japanese script, update last paragraph.",
+      "韓国側は北朝鮮当局を通じて米ドルで賃金を支払う。\n"
+      "国際社会から様々な経済制裁を受ける北朝鮮にとっては出稼ぎ労働などと並んで重要な外貨稼ぎの手段となっている。\n"
+      "韓国統一省によると15年だけで1320億ウォン(約130億円)が同工業団地を通じ北朝鮮に支払われたという。",
+      79u,
+      53u,
+      "0000000000000010000000000"
+      "000000000000000000000000000000000000000000000000000000"
+      "00000000010000011100110001100000000000000000000000000",
+    },
+    {
+      "Chinese script, full text.",
+      "在被捕的64人中,警方落案起訴了35名男子和3名女子,他們年齡介乎15到70歲。\n"
+      "38人中有1人獲准保釋。\n"
+      "16名年齡介乎14到33歲的被捕人士獲准保釋候查,另有10人仍被拘留作進一步調查。",
+      0u,
+      95u,
+      "00001000000000001000000000000000010010000"
+      "1000000000000"
+      "10000001001000000000000000010000000000000",
+    },
+    {
+      "Chinese script, update first paragraph.",
+      "在被捕的64人中,警方落案起訴了35名男子和3名女子,他們年齡介乎15到70歲。\n"
+      "38人中有1人獲准保釋。\n"
+      "16名年齡介乎14到33歲的被捕人士獲准保釋候查,另有10人仍被拘留作進一步調查。",
+      0u,
+      41u,
+      "00001000000000001000000000000000010010000"
+      "1000000000000"
+      "10000001001000000000000000010000000000000",
+    },
+    {
+      "Chinese script, update middle paragraph.",
+      "在被捕的64人中,警方落案起訴了35名男子和3名女子,他們年齡介乎15到70歲。\n"
+      "38人中有1人獲准保釋。\n"
+      "16名年齡介乎14到33歲的被捕人士獲准保釋候查,另有10人仍被拘留作進一步調查。",
+      41u,
+      13u,
+      "00001000000000001000000000000000010010000"
+      "1000000000000"
+      "10000001001000000000000000010000000000000",
+    },
+    {
+      "Chinese script, update last paragraph.",
+      "在被捕的64人中,警方落案起訴了35名男子和3名女子,他們年齡介乎15到70歲。\n"
+      "38人中有1人獲准保釋。\n"
+      "16名年齡介乎14到33歲的被捕人士獲准保釋候查,另有10人仍被拘留作進一步調查。",
+      54u,
+      41u,
+      "00001000000000001000000000000000010010000"
+      "1000000000000"
+      "10000001001000000000000000010000000000000",
+    }
+  };
+  const unsigned int numberOfTests = 13u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !WordBreakInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp
new file mode 100755 (executable)
index 0000000..9dd7d57
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following function.
+// void ShapeText( const Vector<Character>& text,
+//                 const Vector<LineBreakInfo>& lineBreakInfo,
+//                 const Vector<ScriptRun>& scripts,
+//                 const Vector<FontRun>& fonts,
+//                 CharacterIndex startCharacterIndex,
+//                 GlyphIndex startGlyphIndex,
+//                 Length numberOfCharacters,
+//                 Vector<GlyphInfo>& glyphs,
+//                 Vector<CharacterIndex>& glyphToCharacterMap,
+//                 Vector<Length>& charactersPerGlyph,
+//                 Vector<GlyphIndex>& newParagraphGlyphs );
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+struct GlyphInfoData
+{
+  FontId fontId;     ///< Identifies the font containing the glyph
+  GlyphIndex index;  ///< Uniquely identifies a glyph for a given FontId
+  float width;       ///< The width of the glyph
+  float height;      ///< The height of the glyph
+  float xBearing;    ///< The distance from the cursor position to the leftmost border of the glyph
+  float yBearing;    ///< The distance from the baseline to the topmost border of the glyph
+  float advance;     ///< The distance to move the cursor for this glyph
+  float scaleFactor; ///< The scaling applied (fixed-size fonts only)
+  bool isItalicRequired; ///< Whether the italic style is required.
+  bool isBoldRequired;   ///< Whether the bold style is required.
+};
+
+bool IsEqualGlyph ( const GlyphInfoData& glyphData, const GlyphInfo& glyph )
+{
+  if( glyphData.fontId != glyph.fontId )
+  {
+    return false;
+  }
+  if( glyphData.index != glyph.index )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.width - glyph.width ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.height - glyph.height ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.xBearing - glyph.xBearing ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.yBearing - glyph.yBearing ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.advance - glyph.advance ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( fabsf( glyphData.scaleFactor - glyph.scaleFactor ) > Math::MACHINE_EPSILON_1000 )
+  {
+    return false;
+  }
+  if( glyphData.isItalicRequired != glyph.isItalicRequired )
+  {
+    return false;
+  }
+  if( glyphData.isBoldRequired != glyph.isBoldRequired )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+struct ShapeInfoData
+{
+  std::string     description;                        ///< Description of the test.
+  std::string     text;                               ///< input text.
+  uint32_t        index;                              ///< The index from where to start to query the break info.
+  uint32_t        numberOfCharacters;                 ///< The requested number of characters.
+  uint32_t        expectedNumberOfGlyphs;             ///< The expected number of glyphs.
+  GlyphInfoData*  glyphs;                             ///< The glyphs.
+  CharacterIndex* characterIndices;                   ///< The character index for each glyph.
+  Length*         charactersPerGlyph;                 ///< The characters per glyph.
+  uint32_t        expectedNumberOfNewParagraphGlyphs; ///< The expected number of glyphs.
+  GlyphIndex*     newParagraphGlyphs;                 ///< Indices to the new paragraphs glyphs.
+  Vector<FontDescriptionRun> fontDescriptions;        ///< Fonts which is used for text.
+};
+
+bool ShapeInfoTest( const ShapeInfoData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+
+  CreateTextModel( data.text,
+                   textArea,
+                   data.fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  // 2) Clear the model.
+
+  Vector<GlyphInfo>& glyphs = visualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphToCharacter = visualModel->mGlyphsToCharacters;
+  Vector<Length>& charactersPerGlyph = visualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  // Get the glyph index.
+  GlyphIndex glyphIndex = 0u;
+  if( 0u != visualModel->mCharactersToGlyph.Count() )
+  {
+    glyphIndex = *( visualModel->mCharactersToGlyph.Begin() + data.index );
+
+    const CharacterIndex lastCharacterIndex = data.index + data.numberOfCharacters - 1u;
+    const Length numberOfGlyphs = *( visualModel->mCharactersToGlyph.Begin() + lastCharacterIndex ) + *( visualModel->mGlyphsPerCharacter.Begin() + lastCharacterIndex ) - glyphIndex;
+
+    // Erase the glyph info from the text model.
+    // Got from the ShapeText() function.
+    glyphs.Erase( glyphs.Begin() + glyphIndex, glyphs.Begin() + glyphIndex + numberOfGlyphs );
+    glyphToCharacter.Erase( glyphToCharacter.Begin() + glyphIndex, glyphToCharacter.Begin() + glyphIndex + numberOfGlyphs );
+    charactersPerGlyph.Erase( charactersPerGlyph.Begin() + glyphIndex, charactersPerGlyph.Begin() + glyphIndex + numberOfGlyphs );
+
+    // Got from the VisualModel::CreateCharacterToGlyphTable() and the VisualModel::CreateGlyphsPerCharacterTable() methods.
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.index,
+                             charactersToGlyph.Begin() + data.index + data.numberOfCharacters );
+    glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.index,
+                              glyphsPerCharacter.Begin() + data.index + data.numberOfCharacters );
+
+    // Update the glyph to character indices.
+    for( Vector<CharacterIndex>::Iterator it = glyphToCharacter.Begin() + glyphIndex,
+           endIt = glyphToCharacter.End();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= data.numberOfCharacters;
+    }
+
+  }
+
+  // Reset the metrics got from the model as the ShapeText() function doesn't retrieve them.
+  for( Vector<GlyphInfo>::Iterator it = glyphs.Begin(),
+         endIt = glyphs.End();
+       it != endIt;
+       ++it )
+  {
+    GlyphInfo& info = *it;
+    info.width = 0.f;
+    info.height = 0.f;
+    info.xBearing = 0.f;
+    info.yBearing = 0.f;
+    info.scaleFactor = 0.f;
+  }
+
+  // 3) Call the ShapeText() function.
+
+  Vector<GlyphIndex> newParagraphGlyphs;
+
+  ShapeText( logicalModel->mText,
+             logicalModel->mLineBreakInfo,
+             logicalModel->mScriptRuns,
+             logicalModel->mFontRuns,
+             data.index,
+             glyphIndex,
+             data.numberOfCharacters,
+             glyphs,
+             glyphToCharacter,
+             charactersPerGlyph,
+             newParagraphGlyphs );
+
+  // Clear the advance of the new paragraph glyphs.
+  for( Vector<GlyphIndex>::Iterator it = newParagraphGlyphs.Begin(),
+         endIt = newParagraphGlyphs.End();
+       it != endIt;
+       ++it )
+  {
+    GlyphInfo& info = *( glyphs.Begin() + *it );
+    info.advance = 0.f;
+  }
+
+  // 4) Compare the results.
+
+  if( data.expectedNumberOfGlyphs != glyphs.Count() )
+  {
+    std::cout << "  Different number of glyphs : " << glyphs.Count() << ", expected : " << data.expectedNumberOfGlyphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( !IsEqualGlyph( data.glyphs[index], glyphs[index] ) )
+    {
+      std::cout << "  different glyph info, index : " << index << std::endl;
+
+      const GlyphInfo& glyphInfo = glyphs[index];
+      std::cout << "            fontId : " << glyphInfo.fontId << std::endl;
+      std::cout << "             index : " << glyphInfo.index << std::endl;
+      std::cout << "             width : " << glyphInfo.width << std::endl;
+      std::cout << "            height : " << glyphInfo.height << std::endl;
+      std::cout << "          xBearing : " << glyphInfo.xBearing << std::endl;
+      std::cout << "          yBearing : " << glyphInfo.yBearing << std::endl;
+      std::cout << "           advance : " << glyphInfo.advance << std::endl;
+      std::cout << "       scaleFactor : " << glyphInfo.scaleFactor << std::endl;
+      std::cout << "  isItalicRequired : " << glyphInfo.isItalicRequired << std::endl;
+      std::cout << "    isBoldRequired : " << glyphInfo.isBoldRequired << std::endl;
+
+      std::cout << "  Expected : " << std::endl;
+      const GlyphInfoData& expectedGlyphInfo = data.glyphs[index];
+      std::cout << "            fontId : " << expectedGlyphInfo.fontId << std::endl;
+      std::cout << "             index : " << expectedGlyphInfo.index << std::endl;
+      std::cout << "             width : " << expectedGlyphInfo.width << std::endl;
+      std::cout << "            height : " << expectedGlyphInfo.height << std::endl;
+      std::cout << "          xBearing : " << expectedGlyphInfo.xBearing << std::endl;
+      std::cout << "          yBearing : " << expectedGlyphInfo.yBearing << std::endl;
+      std::cout << "           advance : " << expectedGlyphInfo.advance << std::endl;
+      std::cout << "       scaleFactor : " << expectedGlyphInfo.scaleFactor << std::endl;
+      std::cout << "  isItalicRequired : " << expectedGlyphInfo.isItalicRequired << std::endl;
+      std::cout << "    isBoldRequired : " << expectedGlyphInfo.isBoldRequired << std::endl;
+
+
+      return false;
+    }
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( data.characterIndices[index] != glyphToCharacter[index] )
+    {
+      std::cout << "  different character index, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfGlyphs; ++index )
+  {
+    if( data.charactersPerGlyph[index] != charactersPerGlyph[index] )
+    {
+      std::cout << "  different character per glyph, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  if( data.expectedNumberOfNewParagraphGlyphs != newParagraphGlyphs.Count() )
+  {
+    std::cout << "  Different number of new paragraph glyphs : " << newParagraphGlyphs.Count() << ", expected : " << data.expectedNumberOfNewParagraphGlyphs << std::endl;
+    return false;
+  }
+
+  for( unsigned int index = 0u; index < data.expectedNumberOfNewParagraphGlyphs; ++index )
+  {
+    if( data.newParagraphGlyphs[index] != newParagraphGlyphs[index] )
+    {
+      std::cout << "  different new paragraph glyph, index : " << index << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void LoadTextShapeFonts()
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/noto/NotoSansMalayalam-Regular.ttf" );
+}
+
+void LoadSoftwareStylingFonts()
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Regular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Bold.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-Italic.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/roboto/Roboto-BoldItalic.ttf" );
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliTextShape(void)
+{
+  tet_infoline(" UtcDaliTextShape");
+
+  struct GlyphInfoData glyphs02[] =
+  {
+    { 1u, 276u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,   3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 317u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 312u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+  };
+
+  CharacterIndex characterIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  Length charactersPerGlyph02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+
+  struct GlyphInfoData glyphs03[] =
+  {
+    { 1u, 276u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,   3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 317u, 0.f, 0.f, 0.f, 0.f, 11.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 312u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,   0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u,   0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+  };
+
+  CharacterIndex characterIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u };
+  Length charactersPerGlyph03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  CharacterIndex newParagraphGlyphs03[] = { 11u, 16u };
+
+  struct GlyphInfoData glyphs04[] =
+  {
+    { 2u, 67u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 27u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 2u, 59u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 2u, 67u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 55u, 0.f, 0.f, 0.f, 0.f, 19.f, 0.f },
+    { 2u, 59u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 2u, 67u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 56u, 0.f, 0.f, 0.f, 0.f, 19.f, 0.f },
+    { 2u, 59u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 2u, 67u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 2u, 52u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f },
+    { 2u, 59u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+  };
+
+  CharacterIndex characterIndices04[] = { 0u, 0u, 0u, 2u, 2u, 2u, 4u, 4u, 4u, 6u, 6u, 6u };
+  Length charactersPerGlyph04[] = { 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u, 0u, 0u, 2u };
+
+  struct GlyphInfoData glyphs05[] =
+  {
+    { 1u, 280u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 312u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 310u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 313u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 315u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 306u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 312u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 313u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 314u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 314u, 0.f, 0.f, 0.f, 0.f,  6.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 311u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 315u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 403u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 308u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 296u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 313u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+    { 1u, 310u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 309u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 313u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 313u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 312u, 0.f, 0.f, 0.f, 0.f,  5.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 297u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 315u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 308u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 298u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 303u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 295u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 308u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f },
+    { 1u, 299u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u,  3u, 0.f, 0.f, 0.f, 0.f,  4.f, 0.f },
+    { 1u, 297u, 0.f, 0.f, 0.f, 0.f,  7.f, 0.f },
+    { 1u, 315u, 0.f, 0.f, 0.f, 0.f,  8.f, 0.f },
+    { 1u, 307u, 0.f, 0.f, 0.f, 0.f, 13.f, 0.f },
+    { 1u,  4u, 0.f, 0.f, 0.f, 0.f,  3.f, 0.f },
+    { 1u,  0u, 0.f, 0.f, 0.f, 0.f,  0.f, 0.f },
+  };
+
+  CharacterIndex characterIndices05[] = {  0u,  1u,  2u,  3u,  4u,  5u,  6u,  7u,  8u,  9u,
+                                          10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u,
+                                          20u, 21u, 22u, 23u, 24u, 25u, 26u, 27u, 28u, 29u,
+                                          30u, 31u, 32u, 33u, 34u, 35u, 37u, 38u, 39u, 40u,
+                                          41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u,
+                                          51u, 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u,
+                                          61u, 62u, 63u, 64u, 65u, 66u, 67u, 68u, 69u, 70u,
+                                          71u, 72u, 73u, 74u };
+  Length charactersPerGlyph05[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 2u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u };
+  CharacterIndex newParagraphGlyphs05[] = { 26u };
+  CharacterIndex newParagraphGlyphs06[] = { 49u };
+  CharacterIndex newParagraphGlyphs07[] = { 73u };
+
+  Vector<FontDescriptionRun> fontDescriptions01;
+  Vector<FontDescriptionRun> fontDescriptions02;
+  Vector<FontDescriptionRun> fontDescriptions03;
+  Vector<FontDescriptionRun> fontDescriptions04;
+  Vector<FontDescriptionRun> fontDescriptions05;
+  Vector<FontDescriptionRun> fontDescriptions06;
+
+  const std::string fontFamily( "TizenSans" );
+  const std::string fontFamilyMalayalam( "Noto Sans Malayalam" );
+
+  FontDescriptionRun fontDescriptionRun01 =
+  {
+    {
+      0u,
+      11u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun01.familyLength = fontFamily.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontFamily.c_str(), fontDescriptionRun01.familyLength );
+
+  fontDescriptions01.PushBack( fontDescriptionRun01 );
+
+  FontDescriptionRun fontDescriptionRun02 =
+  {
+    {
+      0u,
+      17u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun02.familyLength = fontFamily.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength );
+
+  fontDescriptions02.PushBack( fontDescriptionRun02 );
+
+  FontDescriptionRun fontDescriptionRun03 =
+  {
+    {
+      0u,
+      8u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun03.familyLength = fontFamilyMalayalam.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontFamilyMalayalam.c_str(), fontDescriptionRun03.familyLength );
+
+  fontDescriptions03.PushBack( fontDescriptionRun03 );
+
+  FontDescriptionRun fontDescriptionRun04 =
+  {
+    {
+      0u,
+      75u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun04.familyLength = fontFamily.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontFamily.c_str(), fontDescriptionRun04.familyLength );
+
+  fontDescriptions04.PushBack( fontDescriptionRun04 );
+
+  FontDescriptionRun fontDescriptionRun05 =
+  {
+    {
+      0u,
+      75u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun05.familyLength = fontFamily.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontFamily.c_str(), fontDescriptionRun05.familyLength );
+
+  fontDescriptions05.PushBack( fontDescriptionRun05 );
+
+  FontDescriptionRun fontDescriptionRun06 =
+  {
+    {
+      0u,
+      75u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun06.familyLength = fontFamily.size();
+  fontDescriptionRun06.familyName = new char[fontDescriptionRun06.familyLength];
+  memcpy( fontDescriptionRun06.familyName, fontFamily.c_str(), fontDescriptionRun06.familyLength );
+
+  fontDescriptions06.PushBack( fontDescriptionRun06 );
+
+  struct ShapeInfoData data[] =
+  {
+    {
+      "Zero characters",
+      "",
+      0u,
+      0u,
+      0u,
+      nullptr,
+      nullptr,
+      nullptr,
+      0u,
+      nullptr
+    },
+    {
+      "Latin script",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphs02,
+      characterIndices02,
+      charactersPerGlyph02,
+      0u,
+      nullptr,
+      fontDescriptions01
+    },
+    {
+      "Latin script. Some paragraphs.",
+      "Hello world\ndemo\n",
+      0u,
+      17u,
+      17u,
+      glyphs03,
+      characterIndices03,
+      charactersPerGlyph03,
+      2u,
+      newParagraphGlyphs03,
+      fontDescriptions02
+    },
+    {
+      "Malayalam script. More glyphs than characters.",
+      "ജോസോഹോവോ",
+      0u,
+      8u,
+      12u,
+      glyphs04,
+      characterIndices04,
+      charactersPerGlyph04,
+      0u,
+      nullptr,
+      fontDescriptions03
+    },
+    {
+      "Latin script with some paragraphs. Update initial paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      0u,
+      27u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs05,
+      fontDescriptions04
+    },
+    {
+      "Latin script with some paragraphs. Update mid paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      27u,
+      24u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs06,
+      fontDescriptions05
+    },
+    {
+      "Latin script with some paragraphs. Update final paragraph.",
+      "Lorem ipsum dolor sit amet\naeque definiebas ea mei\nposse iracundia ne cum.\n",
+      51u,
+      24u,
+      74u,
+      glyphs05,
+      characterIndices05,
+      charactersPerGlyph05,
+      1u,
+      newParagraphGlyphs07,
+      fontDescriptions06
+    },
+  };
+  const unsigned int numberOfTests = 7u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    LoadTextShapeFonts();
+
+    if( !ShapeInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextSoftwareStyling(void)
+{
+  tet_infoline(" UtcDaliTextSoftwareStyling");
+
+  struct GlyphInfoData glyphs01[] =
+  {
+    { 4u, 38u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true },
+    { 4u, 39u, 0.f, 0.f, 0.f, 0.f,  9.f, 0.f, true, true },
+    { 4u, 40u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true },
+    { 4u, 41u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true, true },
+  };
+  struct GlyphInfoData glyphs02[] =
+  {
+    { 1u, 38u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, false, false },
+    { 2u, 39u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, false,  true },
+    { 3u, 40u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true,  false },
+    { 4u, 41u, 0.f, 0.f, 0.f, 0.f, 10.f, 0.f, true,   true },
+  };
+
+  CharacterIndex characterIndices[] = { 0u, 1u, 2u, 3u };
+  Length charactersPerGlyph[] = { 1u, 1u, 1u, 1u };
+
+  Vector<FontDescriptionRun> fontDescriptions01;
+  Vector<FontDescriptionRun> fontDescriptions02;
+
+  const std::string fontFamily( "Roboto" );
+
+  FontDescriptionRun fontDescriptionRun01 =
+  {
+    {
+      0u,
+      4u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::BOLD,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::ITALIC,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    true,
+    false,
+    true,
+    false
+  };
+  fontDescriptionRun01.familyLength = fontFamily.size();
+  fontDescriptionRun01.familyName = new char[fontDescriptionRun01.familyLength];
+  memcpy( fontDescriptionRun01.familyName, fontFamily.c_str(), fontDescriptionRun01.familyLength );
+
+  fontDescriptions01.PushBack(fontDescriptionRun01);
+
+  FontDescriptionRun fontDescriptionRun02 =
+  {
+    {
+      0u,
+      1u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun02.familyLength = fontFamily.size();
+  fontDescriptionRun02.familyName = new char[fontDescriptionRun02.familyLength];
+  memcpy( fontDescriptionRun02.familyName, fontFamily.c_str(), fontDescriptionRun02.familyLength );
+
+  FontDescriptionRun fontDescriptionRun03 =
+  {
+    {
+      1u,
+      1u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::BOLD,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::NONE,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    true,
+    false,
+    false,
+    false
+  };
+  fontDescriptionRun03.familyLength = fontFamily.size();
+  fontDescriptionRun03.familyName = new char[fontDescriptionRun03.familyLength];
+  memcpy( fontDescriptionRun03.familyName, fontFamily.c_str(), fontDescriptionRun03.familyLength );
+
+  FontDescriptionRun fontDescriptionRun04 =
+  {
+    {
+      2u,
+      1u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::NONE,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::ITALIC,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    false,
+    false,
+    true,
+    false
+  };
+  fontDescriptionRun04.familyLength = fontFamily.size();
+  fontDescriptionRun04.familyName = new char[fontDescriptionRun04.familyLength];
+  memcpy( fontDescriptionRun04.familyName, fontFamily.c_str(), fontDescriptionRun04.familyLength );
+
+  FontDescriptionRun fontDescriptionRun05 =
+  {
+    {
+      3u,
+      1u
+    },
+    nullptr,
+    0u,
+    TextAbstraction::FontWeight::BOLD,
+    TextAbstraction::FontWidth::NONE,
+    TextAbstraction::FontSlant::ITALIC,
+    TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
+    true,
+    true,
+    false,
+    true,
+    false
+  };
+  fontDescriptionRun05.familyLength = fontFamily.size();
+  fontDescriptionRun05.familyName = new char[fontDescriptionRun05.familyLength];
+  memcpy( fontDescriptionRun05.familyName, fontFamily.c_str(), fontDescriptionRun05.familyLength );
+
+  fontDescriptions02.PushBack(fontDescriptionRun02);
+  fontDescriptions02.PushBack(fontDescriptionRun03);
+  fontDescriptions02.PushBack(fontDescriptionRun04);
+  fontDescriptions02.PushBack(fontDescriptionRun05);
+
+
+  struct ShapeInfoData data[] =
+  {
+    {
+      "Latin script. Characters have same font description",
+      "ABCD",
+      0u,
+      4u,
+      4u,
+      glyphs01,
+      characterIndices,
+      charactersPerGlyph,
+      0u,
+      nullptr,
+      fontDescriptions01
+    },
+    {
+      "Latin script. Each character has different font description.",
+      "ABCD",
+      0u,
+      4u,
+      4u,
+      glyphs02,
+      characterIndices,
+      charactersPerGlyph,
+      0u,
+      nullptr,
+      fontDescriptions02
+    }
+  };
+
+  const unsigned int numberOfTests = 2u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    LoadSoftwareStylingFonts();
+
+    if( !ShapeInfoTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Typesetter.cpp
new file mode 100644 (file)
index 0000000..8ec03d6
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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 <iostream>
+
+#include <stdlib.h>
+#include <limits>
+#include <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
+#include <dali-toolkit/internal/text/rendering/view-model.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+namespace
+{
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+const PointSize26Dot6 EMOJI_FONT_SIZE = 3840u; // 60 * 64
+} // namespace
+
+int UtcDaliTextTypesetter(void)
+{
+  tet_infoline(" UtcDaliTextTypesetter");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextTypesetterGetViewModel(void)
+{
+  tet_infoline(" UtcDaliTextTypesetter");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextRenderingControllerRender(void)
+{
+  tet_infoline(" UtcDaliTextRenderingControllerRender");
+  ToolkitTestApplication application;
+
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/BreezeColorEmoji.ttf", EMOJI_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets the text.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "<font family='TizenSansRegular'>Hello world </font><font family='BreezeColorEmoji'>\xF0\x9F\x98\x81</font>" );
+
+  // Creates the text's model and relais-out the text.
+  const Size relayoutSize( 120.f, 60.f );
+  controller->Relayout( relayoutSize );
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr renderingController = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( renderingController );
+
+  // Renders the text and creates the final bitmap.
+  PixelData bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+  DALI_TEST_CHECK( bitmap );
+
+  DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  DALI_TEST_EQUALS( Pixel::RGBA8888, bitmap.GetPixelFormat(), TEST_LOCATION );
+
+  // Changes vertical alignment.
+  controller->SetVerticalAlignment( Text::VerticalAlignment::CENTER );
+  controller->Relayout( relayoutSize );
+
+  // Renders the text and creates the final bitmap.
+  bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+  DALI_TEST_CHECK( bitmap );
+
+  DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  DALI_TEST_EQUALS( Pixel::RGBA8888, bitmap.GetPixelFormat(), TEST_LOCATION );
+
+  controller->SetVerticalAlignment( Text::VerticalAlignment::BOTTOM );
+  controller->Relayout( relayoutSize );
+
+  // Renders the text and creates the final bitmap.
+  bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+  DALI_TEST_CHECK( bitmap );
+
+  DALI_TEST_EQUALS( 120u, bitmap.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  DALI_TEST_EQUALS( Pixel::RGBA8888, bitmap.GetPixelFormat(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextTypesetterVerticalLineAlignment(void)
+{
+  tet_infoline(" UtcDaliTextTypesetter");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets the text.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "<font family='TizenSansRegular'>Hello world</font>" );
+
+  // Creates the text's model and relais-out the text.
+  const Size relayoutSize( 120.f, 60.f );
+  controller->Relayout( relayoutSize );
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr renderingController = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( renderingController );
+
+  {
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::TOP );
+    controller->Relayout( relayoutSize );
+
+    // Renders the text and creates the final bitmap.
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+    DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  }
+
+  {
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::MIDDLE );
+    controller->Relayout( relayoutSize );
+
+    // Renders the text and creates the final bitmap.
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+    DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  }
+
+  {
+    controller->SetVerticalLineAlignment( Dali::Toolkit::DevelText::VerticalLineAlignment::BOTTOM );
+    controller->Relayout( relayoutSize );
+
+    // Renders the text and creates the final bitmap.
+    auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+    DALI_TEST_EQUALS( 60u, bitmap.GetHeight(), TEST_LOCATION );
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextTypesetterBitmapFont(void)
+{
+  tet_infoline("UtcDaliTextTypesetterBitmapFont ");
+  ToolkitTestApplication application;
+
+  DevelText::BitmapFontDescription fontDescription;
+  fontDescription.name = "Digits";
+  fontDescription.underlinePosition = 0.f;
+  fontDescription.underlineThickness = 0.f;
+  fontDescription.isColorFont = true;
+
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0031.png", "0", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0032.png", "1", 34.f, 0.f } );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  DevelText::CreateBitmapFont( fontDescription, bitmapFont );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( bitmapFont );
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets the text.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "<font family='Digits'><color 'value'='red'>0</color></font>" );
+
+  // Creates the text's model and relais-out the text.
+  const Size relayoutSize( 31.f, 34.f );
+  controller->Relayout( relayoutSize );
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr renderingController = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( renderingController );
+
+  controller->Relayout( relayoutSize );
+
+  // Renders the text and creates the final bitmap.
+  auto bitmap = renderingController->Render( relayoutSize, Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT );
+
+  DALI_TEST_EQUALS( 31u, bitmap.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 34u, bitmap.GetHeight(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-ViewModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-ViewModel.cpp
new file mode 100755 (executable)
index 0000000..74be44b
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
+#include <dali-toolkit/internal/text/rendering/view-model.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+namespace
+{
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+const Size CONTROL_SIZE( 200.f, 400.f );
+const Size CONTROL_SMALL_SIZE( 50.f, 100.f );
+const char* LOREM_IPSUM = "Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.\n"
+  "Usu ne nisl maiorum iudicabit, veniam epicurei oporteat eos an.\n"
+  "Ne nec nulla regione albucius, mea doctus delenit ad!\n"
+  "Et everti blandit adversarium mei, eam porro neglegentur suscipiantur an.\n"
+  "Quidam corpora at duo. An eos possim scripserit?\n\n"
+  "Aťqui dicant sěnťenťíae aň vel!\n"
+  "Vis viris médiocrem elaboraret ét, verear civibus moderatius ex duo!\n"
+  "Án veri laborě iňtěgré quó, mei aď poššit lobortis, mei prompťa čonsťitůťó eů.\n"
+  "Aliquip sanctůs delicáta quí ěá, et natum aliquam est?\n"
+  "Asšúm sapěret usu ůť.\n"
+  "Síť ut apeirián laboramúš percipitur, sůas hařum ín éos?\n";
+const Vector2 LOREM_SCROLL_POSITION( 0.f, -265.f );
+const Length LOREM_NUMBER_OF_LINES = 35u;
+const Length LOREM_NUMBER_OF_LINES_ELIDED = 21u;
+const Length LOREM_NUMBER_OF_GLYPHS = 632;
+const Length LOREM_NUMBER_OF_GLYPHS_ELIDED = 395u;
+
+// The expected layout size for UtcDaliTextViewModelGetLayoutSize
+const Size LAYOUT_SIZE( 194.f, 45.f );
+
+// The expected color indices for UtcDaliTextViewModelGetColors
+const ColorIndex COLOR_INDICES[] = { 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 2u, 2u, 2u, 2u, 2u, 1u, 1u, 1u, 1u, 1u, 3u, 1u, 1u, 1u, 0u, 0u, 0u, 0u };
+const Length NUMBER_OF_COLORS = 3u;
+const Vector4 COLORS[] = { Color::RED, Color::BLUE, Color::GREEN };
+
+struct ElideData
+{
+  std::string  description;
+  std::string  text;
+  Vector2      size;
+  unsigned int numberOfLines;
+  unsigned int numberOfGlyphs;
+  float*       positions;
+};
+
+bool ElideTest( const ElideData& data )
+{
+  std::cout << "  testing : " << data.description << std::endl;
+
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansHebrewRegular.ttf" );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansArabicRegular.ttf" );
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets a text and relais-out.
+  controller->SetMarkupProcessorEnabled( true );
+
+  controller->SetText( data.text );
+  controller->Relayout( data.size );
+
+  // Elide the glyphs.
+  model->ElideGlyphs();
+
+  if( data.numberOfLines != model->GetNumberOfLines() )
+  {
+    std::cout << "  different number of lines : " << model->GetNumberOfLines() << ", expected : " << data.numberOfLines << std::endl;
+    return false;
+  }
+
+  if( data.numberOfGlyphs != model->GetNumberOfGlyphs() )
+  {
+    std::cout << "  different number of glyphs : " << model->GetNumberOfGlyphs() << ", expected : " << data.numberOfGlyphs << std::endl;
+    return false;
+  }
+
+  const Vector2* const layoutBuffer = model->GetLayout();
+  const Length numberOfLines = model->GetNumberOfLines();
+
+  if( numberOfLines != 0u )
+  {
+    const LineRun& lastLine = *( model->GetLines() + numberOfLines - 1u );
+    const Length numberOfLastLineGlyphs = data.numberOfGlyphs - lastLine.glyphRun.glyphIndex;
+
+    std::cout << "  last line alignment offset : " << lastLine.alignmentOffset << std::endl;
+
+    for( unsigned int index = 0u; index < numberOfLastLineGlyphs; ++index )
+    {
+      if( *( data.positions + index ) != ( lastLine.alignmentOffset + ( *( layoutBuffer + lastLine.glyphRun.glyphIndex + index ) ).x ) )
+      {
+        std::cout << "  different layout :";
+        for( unsigned int i = 0; i < numberOfLastLineGlyphs; ++i )
+        {
+          std::cout << " " << ( lastLine.alignmentOffset + ( *( layoutBuffer + lastLine.glyphRun.glyphIndex + i ) ).x );
+        }
+        std::cout << std::endl;
+        std::cout << "          expected :";
+        for( unsigned int i = 0; i < numberOfLastLineGlyphs; ++i )
+        {
+          std::cout << " " << *( data.positions + i );
+        }
+        std::cout << std::endl;
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+int UtcDaliTextViewModel(void)
+{
+  tet_infoline(" UtcDaliTextViewModel");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetControlSize(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetControlSize");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // The text has not been laid-out. The stored control's size should be zero.
+  DALI_TEST_EQUALS( Size::ZERO, model->GetControlSize(), TEST_LOCATION );
+
+  // Sets a text and relais-out.
+  controller->SetText( "Hello world" );
+  controller->Relayout( CONTROL_SIZE );
+
+  // The control's size should be stored now.
+  DALI_TEST_EQUALS( CONTROL_SIZE, model->GetControlSize(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetLayoutSize(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetLayoutSize");
+  ToolkitTestApplication application;
+
+  // Load some fonts.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // The text has not been laid-out. The stored control's size should be zero.
+  DALI_TEST_EQUALS( Size::ZERO, model->GetLayoutSize(), TEST_LOCATION );
+
+  // Sets a text and relais-out.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "<font family='TizenSansRegular' size='10'>Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.</font>" );
+  controller->Relayout( CONTROL_SIZE );
+
+  // The control's size should be stored now.
+  DALI_TEST_EQUALS( LAYOUT_SIZE, model->GetLayoutSize(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetScrollPosition(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetScrollPosition");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // No text has been set. The scroll position should be zero.
+  DALI_TEST_EQUALS( Vector2::ZERO, model->GetScrollPosition(), TEST_LOCATION );
+
+  // Gains the keyboard focus, sets a big text and relais-out.
+  controller->KeyboardFocusGainEvent();
+  controller->SetText( LOREM_IPSUM );
+  controller->Relayout( CONTROL_SIZE );
+
+  // The text should be scrolled to the end.
+  DALI_TEST_EQUALS( LOREM_SCROLL_POSITION, model->GetScrollPosition(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetAlignment(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetAlignment");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  DALI_TEST_EQUALS( Text::HorizontalAlignment::BEGIN, model->GetHorizontalAlignment(), TEST_LOCATION );
+  DALI_TEST_EQUALS( Text::VerticalAlignment::TOP, model->GetVerticalAlignment(), TEST_LOCATION );
+
+  controller->SetHorizontalAlignment( Text::HorizontalAlignment::CENTER );
+  controller->SetVerticalAlignment( Text::VerticalAlignment::CENTER );
+
+  DALI_TEST_EQUALS( Text::HorizontalAlignment::CENTER, model->GetHorizontalAlignment(), TEST_LOCATION );
+  DALI_TEST_EQUALS( Text::VerticalAlignment::CENTER, model->GetVerticalAlignment(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelIsTextElideEnabled(void)
+{
+  tet_infoline(" UtcDaliTextViewModelIsTextElideEnabled");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // Elide text should be disabled.
+  DALI_TEST_CHECK( !model->IsTextElideEnabled() );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Elide text should be enabled.
+  DALI_TEST_CHECK( model->IsTextElideEnabled() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetLines(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetLines");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // The number of lines should be zero.
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfLines(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL == model->GetLines() );
+
+  // Sets a text and relais-out.
+  controller->SetText( LOREM_IPSUM );
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_LINES, model->GetNumberOfLines(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL != model->GetLines() );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Relais-out for the text-label configuration.
+  controller->Relayout( Size( 100.f, 100.f) ); // Change the size to force a relayout.
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_LINES_ELIDED, model->GetNumberOfLines(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL != model->GetLines() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetGlyphsLayout(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetGlyphsLayout");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // The number of glyphs should be zero.
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL == model->GetGlyphs() );
+  DALI_TEST_CHECK( NULL == model->GetLayout() );
+
+  // Sets a text and relais-out.
+  controller->SetText( LOREM_IPSUM );
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_GLYPHS, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL != model->GetGlyphs() );
+  DALI_TEST_CHECK( NULL != model->GetLayout() );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Relais-out for the text-label configuration.
+  controller->Relayout( Size( 100.f, 100.f) ); // Change the size to force a relayout.
+  controller->Relayout( CONTROL_SIZE );
+
+  // Elide the glyphs.
+  model->ElideGlyphs();
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_GLYPHS_ELIDED, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL != model->GetGlyphs() );
+  DALI_TEST_CHECK( NULL != model->GetLayout() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelGetColors(void)
+{
+  tet_infoline(" UtcDaliTextViewModelGetColors");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Sets a text and relais-out.
+  controller->SetMarkupProcessorEnabled( true );
+  controller->SetText( "Lorem <color value='red'>ips<color value='blue'>um do</color>lor s<color value='green'>i</color>t a</color>met." );
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( Color::BLACK, model->GetDefaultColor(), TEST_LOCATION );
+
+  const ColorIndex* const colorIndicesBuffer = model->GetColorIndices();
+
+  const Length numberOfGlyphs = model->GetNumberOfGlyphs();
+  for( ColorIndex index = 0u; index < numberOfGlyphs; ++index )
+  {
+    DALI_TEST_EQUALS( COLOR_INDICES[index], *( colorIndicesBuffer + index ), TEST_LOCATION );
+  }
+
+  const Vector4* const colors = model->GetColors();
+  for( unsigned int index = 0u; index < NUMBER_OF_COLORS; ++index )
+  {
+    DALI_TEST_EQUALS( COLORS[index], *( colors + index ), TEST_LOCATION );
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelElideText01(void)
+{
+  tet_infoline(" UtcDaliTextViewModelElideText01");
+  ToolkitTestApplication application;
+
+  // Creates a text controller.
+  ControllerPtr controller = Controller::New();
+
+  // Tests the rendering controller has been created.
+  TypesetterPtr typesetter = Typesetter::New( controller->GetTextModel() );
+  DALI_TEST_CHECK( typesetter );
+
+  // Tests the view model has been created.
+  ViewModel* model = typesetter->GetViewModel();
+  DALI_TEST_CHECK( NULL != model );
+
+  // Configures the text controller similarly to the text-editor.
+  ConfigureTextEditor( controller );
+
+  // The number of glyphs should be zero.
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfLines(), TEST_LOCATION );
+  DALI_TEST_CHECK( NULL == model->GetGlyphs() );
+  DALI_TEST_CHECK( NULL == model->GetLayout() );
+
+  // Sets a text and relais-out.
+  controller->SetText( LOREM_IPSUM );
+  controller->Relayout( CONTROL_SIZE );
+
+  // Keep the pointers to the glyphs and layout.
+  // As the text is not elided with this configuration, the pointers shoud be the same after calling the ElideGlyphs() method.
+  const GlyphInfo* const glyphsModel = model->GetGlyphs();
+  const Vector2* layoutsModel = model->GetLayout();
+
+  // Elide the glyphs. Text shouldn't be elided with this configuration.
+  model->ElideGlyphs();
+
+  DALI_TEST_CHECK( glyphsModel == model->GetGlyphs() );
+  DALI_TEST_CHECK( layoutsModel == model->GetLayout() );
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_GLYPHS, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_LINES, model->GetNumberOfLines(), TEST_LOCATION );
+
+  // Configures the text controller similarly to the text-label.
+  ConfigureTextLabel( controller );
+
+  // Clear the text and relais-out.
+  controller->SetText( "" );
+  controller->Relayout( CONTROL_SIZE );
+
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfLines(), TEST_LOCATION );
+
+  // Elide the glyphs. Should not add the ellipsis glyph.
+  model->ElideGlyphs();
+
+  DALI_TEST_EQUALS( 0u, model->GetNumberOfGlyphs(), TEST_LOCATION );
+
+  // Sets a text that doesn't need to be elided.
+  controller->SetText( "Hello\n" );
+  controller->Relayout( CONTROL_SIZE );
+
+  // Elide the glyphs.
+  model->ElideGlyphs();
+
+  DALI_TEST_EQUALS( 6u, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 2u, model->GetNumberOfLines(), TEST_LOCATION );
+
+  // Sets a text and relais-out.
+  controller->SetText( LOREM_IPSUM );
+  controller->Relayout( CONTROL_SIZE );
+
+  // Elide the glyphs.
+  model->ElideGlyphs();
+
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_GLYPHS_ELIDED, model->GetNumberOfGlyphs(), TEST_LOCATION );
+  DALI_TEST_EQUALS( LOREM_NUMBER_OF_LINES_ELIDED, model->GetNumberOfLines(), TEST_LOCATION );
+  const GlyphInfo* const glyphs = model->GetGlyphs();
+  const Vector2* layouts = model->GetLayout();
+  DALI_TEST_CHECK( NULL != glyphs );
+  DALI_TEST_CHECK( NULL != layouts );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliTextViewModelElideText02(void)
+{
+  tet_infoline(" UtcDaliTextViewModelElideText02");
+
+  Size textSize00( 100.f, 100.f );
+
+  Size textSize01( 80.f, 100.f );
+  float positions01[] = { 0.f, 8.f, 16.f, 26.f, 33.f, 41.f, 45.f, 54.f, 64.0f };
+
+  Size textSize02( 80.f, 100.f );
+  float positions02[] = { 72.f, 63.f, 54.f, 50.f, 43.f, 38.f, 30.f, 13.0f };
+
+  Size textSize03( 80.f, 100.f );
+  float positions03[] = { 74.f, 69.f, 66.f, 61.f, 53.f, 51.f, 47.f, 46.f, 41.f, 31.f, 28.f, 14.f, 7.f };
+
+  Size textSize04( 80.f, 10.f );
+  float positions04[] = { 2.f };
+
+  struct ElideData data[] =
+  {
+    {
+      "void text",
+      "",
+      textSize00,
+      0u,
+      0u,
+      NULL
+    },
+    {
+      "Latin script",
+      "<font family='TizenSans'>Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.</font>",
+      textSize01,
+      5u,
+      37u,
+      positions01
+    },
+    {
+      "Hebrew script",
+      "<font family='TizenSansHebrew'>צעד על לשון המלצת לאחרונה, אם לכאן שנורו סרבול מדע, קרן דת שפות להפוך.</font>",
+      textSize02,
+      5u,
+      49u,
+      positions02
+    },
+    {
+      "Arabic script",
+      "<font family='TizenSansArabic'>عل النفط ديسمبر الإمداد بال, بين وترك شعار هو. لمّ من المبرمة النفط بالسيطرة, أم يتم تحرّك وبغطاء, عدم في لإعادة وإقامة رجوعهم.</font>",
+      textSize03,
+      5u,
+      73u,
+      positions03
+    },
+    {
+      "Small control size, no line fits.",
+      "<font family='TizenSans'>Lorem ipsum dolor sit amet, aeque definiebas ea mei, posse iracundia ne cum.</font>",
+      textSize04,
+      1u,
+      1u,
+      positions04
+    }
+  };
+  const unsigned int numberOfTests = 5u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !ElideTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
new file mode 100755 (executable)
index 0000000..5ac4ab1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019 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-toolkit/internal/controls/text-controls/text-field-impl.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+int UtcDaliTextFieldMultipleBackgroundText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextFieldMultipleBackgroundText" );
+
+  // Create a text field
+  TextField textField = TextField::New();
+  textField.SetSize( 400.f, 60.f );
+  textField.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  textField.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Add the text field to the stage
+  Stage::GetCurrent().Add( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField );
+  ControllerPtr controller = textFieldImpl.GetTextController();
+  Controller::Impl& controllerImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Add multiple background colors for the text.
+  ColorRun backgroundColorRun1;
+  backgroundColorRun1.characterRun.characterIndex = 0u;
+  backgroundColorRun1.characterRun.numberOfCharacters = 1u;
+  backgroundColorRun1.color = Color::RED;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun1 );
+
+  ColorRun backgroundColorRun2;
+  backgroundColorRun2.characterRun.characterIndex = 5u;
+  backgroundColorRun2.characterRun.numberOfCharacters = 8u;
+  backgroundColorRun2.color = Color::CYAN;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun2 );
+
+  ColorRun backgroundColorRun3;
+  backgroundColorRun3.characterRun.characterIndex = 23u;
+  backgroundColorRun3.characterRun.numberOfCharacters = 6u;
+  backgroundColorRun3.color = Color::GREEN;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun3 );
+
+  // Check the case where there is only one character in the text
+  controller->SetText( "S" );
+
+  application.SendNotification();
+  application.Render();
+
+  // The offscreen root actor should have one child: the renderable.
+  Actor stencil = textField.GetChildAt( 0u );
+  DALI_TEST_CHECK( stencil.GetChildCount() == 1u );
+
+  // The renderable actor should have two children: the text and the background.
+  Actor renderableActor = stencil.GetChildAt( 0u );
+  DALI_TEST_CHECK( renderableActor.GetChildCount() == 2u );
+
+  // Check that the background is created
+  Actor backgroundActor = renderableActor.GetChildAt( 0u );
+  DALI_TEST_CHECK( backgroundActor );
+  DALI_TEST_CHECK( backgroundActor.GetName() == "TextBackgroundColorActor" );
+
+  // Change the text to contain more characters
+  controller->SetText( "Text Multiple Background Test" );
+
+  application.SendNotification();
+  application.Render();
+
+  // Highlight the whole text
+  textFieldImpl.SelectWholeText();
+
+  application.SendNotification();
+  application.Render();
+
+  // Now the offscreen root actor should have three children: the renderable, the highlight, and the background.
+  DALI_TEST_CHECK( stencil.GetChildCount() == 3u );
+  // The renderable actor should have one child only: the text
+  DALI_TEST_CHECK( renderableActor.GetChildCount() == 1u );
+
+  // The background should now be lowered below the highlight
+  backgroundActor = stencil.GetChildAt( 0u );
+  DALI_TEST_CHECK( backgroundActor );
+  DALI_TEST_CHECK( backgroundActor.GetName() == "TextBackgroundColorActor" );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp
new file mode 100644 (file)
index 0000000..21f6f7c
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2020 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/internal/visuals/texture-manager-impl.h>
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
+
+using namespace Dali::Toolkit::Internal;
+
+
+void utc_dali_toolkit_texture_manager_startup(void)
+{
+  setenv( "LOG_TEXTURE_MANAGER", "3", 1 );
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_texture_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+class TestObserver : public Dali::Toolkit::TextureUploadObserver
+{
+public:
+  TestObserver()
+  : mLoaded(false),
+    mObserverCalled(false)
+  {
+  }
+
+  virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet,
+                               bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override
+  {
+    mLoaded = loadSuccess;
+    mObserverCalled = true;
+  }
+
+  virtual void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override
+  {
+    mLoaded = loadSuccess;
+    mObserverCalled = true;
+  }
+
+  bool mLoaded;
+  bool mObserverCalled;
+};
+
+
+int UtcTextureManagerRequestLoad(void)
+{
+  ToolkitTestApplication application;
+
+  TextureManager textureManager; // Create new texture manager
+
+  TestObserver observer;
+  std::string filename("image.png");
+  auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  TextureManager::TextureId textureId = textureManager.RequestLoad(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    TextureManager::NO_ATLAS,
+    &observer,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  VisualUrl url = textureManager.GetVisualUrl( textureId );
+
+  DALI_TEST_EQUALS( url.GetUrl().compare( filename ), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcTextureManagerGenerateHash(void)
+{
+  ToolkitTestApplication application;
+
+  TextureManager textureManager; // Create new texture manager
+
+  TestObserver observer;
+  std::string filename( "image.png" );
+  auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  TextureManager::TextureId textureId = textureManager.RequestLoad(
+    filename,
+    ImageDimensions(),
+    FittingMode::SCALE_TO_FILL,
+    SamplingMode::BOX_THEN_LINEAR,
+    TextureManager::USE_ATLAS,
+    &observer,
+    true,
+    TextureManager::ReloadPolicy::CACHED,
+    preMultiply);
+
+  VisualUrl url = textureManager.GetVisualUrl( textureId );
+
+  DALI_TEST_EQUALS( url.GetUrl().compare( filename ), 0, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualModel.cpp
new file mode 100644 (file)
index 0000000..df247e0
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * 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 <iostream>
+
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <toolkit-text-utils.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+// Tests the following functions.
+//
+// void CreateCharacterToGlyphTable( CharacterIndex startIndex,
+//                                   Length numberOfCharacters )
+//
+// void CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+//                                     Length numberOfCharacters )
+
+
+//////////////////////////////////////////////////////////
+
+namespace
+{
+
+struct SetGlyphsPerCharacterData
+{
+  std::string   description;             ///< Description of the test.
+  std::string   text;                    ///< Input text.
+  unsigned int  startIndex;              ///< The start index from where the glyphs per character table is set.
+  unsigned int  numberOfCharacters;      ///< The number of characters to set.
+  unsigned int  totalNumberOfCharacters; ///< The total number of characters.
+  unsigned int* glyphsPerCharacter;      ///< The number of glyphs per character.
+};
+
+struct SetCharacterToGlyphData
+{
+  std::string   description;             ///< Description of the test.
+  std::string   text;                    ///< Input text.
+  unsigned int  startIndex;              ///< The start index from where the character to glyph table is set.
+  unsigned int  numberOfCharacters;      ///< The number of characters to set.
+  unsigned int  totalNumberOfCharacters; ///< The total number of characters.
+  unsigned int* glyphsIndices;           ///< The glyph indices.
+};
+
+bool SetGlyphsPerCharacterTest( const SetGlyphsPerCharacterData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  // 2) Clear the model.
+
+  GlyphIndex startGlyphIndex = 0u;
+  if( 0u != charactersToGlyph.Count() )
+  {
+    // The number of glyphs to be removed.
+    const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex];
+    startGlyphIndex = charactersToGlyph[data.startIndex];
+
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex,
+                             charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters );
+    glyphsPerCharacter.Erase( glyphsPerCharacter.Begin() + data.startIndex,
+                              glyphsPerCharacter.Begin() + data.startIndex + data.numberOfCharacters );
+
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it = charactersToGlyph.Begin() + data.startIndex,
+           endIt = charactersToGlyph.End();
+         it != endIt;
+         ++it )
+    {
+      *it -= numberOfGlyphs;
+    }
+  }
+
+  // 3) Call the CreateGlyphsPerCharacterTable() function
+  visualModel->CreateGlyphsPerCharacterTable( data.startIndex,
+                                              startGlyphIndex,
+                                              data.numberOfCharacters );
+
+  // 4) Compare the results.
+  if( data.totalNumberOfCharacters != glyphsPerCharacter.Count() )
+  {
+    std::cout << "  Different number of characters : " << glyphsPerCharacter.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl;
+    return false;
+  }
+
+  for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i )
+  {
+    if( data.glyphsPerCharacter[i] != glyphsPerCharacter[i] )
+    {
+      std::cout << "  Different number of glyphs for index " << i << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << glyphsPerCharacter[j] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "  expected" << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << data.glyphsPerCharacter[j] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SetCharacterToGlyphTest( const SetCharacterToGlyphData& data )
+{
+  // 1) Create the model.
+  ModelPtr textModel;
+  MetricsPtr metrics;
+  Size textArea(100.f, 60.f);
+  Size layoutSize;
+
+  const Vector<FontDescriptionRun> fontDescriptions;
+  const LayoutOptions options;
+  CreateTextModel( data.text,
+                   textArea,
+                   fontDescriptions,
+                   options,
+                   layoutSize,
+                   textModel,
+                   metrics,
+                   false );
+
+  LogicalModelPtr logicalModel = textModel->mLogicalModel;
+  VisualModelPtr visualModel = textModel->mVisualModel;
+
+  Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
+  Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
+
+  // 2) Clear the model.
+
+  GlyphIndex startGlyphIndex = 0u;
+  if( 0u != charactersToGlyph.Count() )
+  {
+    // The number of glyphs to be removed.
+    const Length numberOfGlyphs = charactersToGlyph[data.startIndex + data.numberOfCharacters - 1u] + glyphsPerCharacter[data.startIndex + data.numberOfCharacters - 1u] - charactersToGlyph[data.startIndex];
+    startGlyphIndex = charactersToGlyph[data.startIndex];
+
+    charactersToGlyph.Erase( charactersToGlyph.Begin() + data.startIndex,
+                             charactersToGlyph.Begin() + data.startIndex + data.numberOfCharacters );
+
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it = charactersToGlyph.Begin() + data.startIndex,
+           endIt = charactersToGlyph.End();
+         it != endIt;
+         ++it )
+    {
+      *it -= numberOfGlyphs;
+    }
+  }
+
+  // 3) Call the CreateCharacterToGlyphTable() function
+  visualModel->CreateCharacterToGlyphTable( data.startIndex,
+                                            startGlyphIndex,
+                                            data.numberOfCharacters );
+
+  // 4) Compare the results.
+  if( data.totalNumberOfCharacters != charactersToGlyph.Count() )
+  {
+    std::cout << "  Different number of character : " << charactersToGlyph.Count() << ", expected : " << data.totalNumberOfCharacters << std::endl;
+    return false;
+  }
+
+  for( unsigned int i = 0u; i < data.totalNumberOfCharacters; ++i )
+  {
+    if( data.glyphsIndices[i] != charactersToGlyph[i] )
+    {
+      std::cout << "  Different number of character to glyph index " << i << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << charactersToGlyph[j] << " ";
+      }
+      std::cout << std::endl;
+      std::cout << "  expected" << std::endl;
+      for( unsigned int j = 0; j < data.totalNumberOfCharacters; ++j )
+      {
+        std::cout << data.glyphsIndices[j] << " ";
+      }
+      std::cout << std::endl;
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliSetGlyphsPerCharacter(void)
+{
+  tet_infoline(" UtcDaliSetGlyphsPerCharacter");
+
+  Length glyphsPerCharacter02[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  Length glyphsPerCharacter03[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u };
+  Length glyphsPerCharacter04[] = { 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 0u, 1u,
+                                    1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u,
+                                    1u, 1u, 1u, 1u, 0u, 1u, 0u, 2u, 1u, 0u,
+                                    2u, 0u, 2u, 0u, 2u, 1u, 1u, 0u, 0u, 0u,
+                                    2u, 1u, 1u, 1u, 1u, 1u, 0u, 0u, 2u, 1u,
+                                    0u, 2u, 1u, 1u };
+
+  struct SetGlyphsPerCharacterData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      0u,
+      0u,
+      0u,
+      NULL
+    },
+    {
+      "Simple 1 to 1 text",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphsPerCharacter02,
+    },
+    {
+      "Text with different number of glyphs and characters.",
+      "Hello different world",
+      0u,
+      21u,
+      21u,
+      glyphsPerCharacter03,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      0u,
+      22u,
+      54u,
+      glyphsPerCharacter04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      22u,
+      14u,
+      54u,
+      glyphsPerCharacter04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update final paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      36u,
+      18u,
+      54u,
+      glyphsPerCharacter04,
+    },
+  };
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !SetGlyphsPerCharacterTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliSetCharacterToGlyph(void)
+{
+  tet_infoline(" UtcDaliSetGlyphsPerCharacter");
+
+  GlyphIndex glyphIndices02[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u };
+  GlyphIndex glyphIndices03[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u };
+  GlyphIndex glyphIndices04[] = { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u,
+                                  21u, 22u, 23u, 23u, 24u, 24u, 26u, 27u, 27u, 29u, 29u, 31u, 31u, 33u,
+                                  34u, 35u, 35u, 35u, 35u, 37u, 38u, 39u, 40u, 41u, 42u, 42u, 42u, 44u, 45u, 45u, 47u, 48u };
+
+  struct SetCharacterToGlyphData data[] =
+  {
+    {
+      "Zero characters text",
+      "",
+      0u,
+      0u,
+      0u,
+      NULL
+    },
+    {
+      "Simple 1 to 1 text",
+      "Hello world",
+      0u,
+      11u,
+      11u,
+      glyphIndices02,
+    },
+    {
+      "Text with different number of glyphs and characters.",
+      "Hello different world",
+      0u,
+      21u,
+      21u,
+      glyphIndices03,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update initial paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      0u,
+      22u,
+      54u,
+      glyphIndices04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update mid paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      22u,
+      14u,
+      54u,
+      glyphIndices04,
+    },
+    {
+      "Text paragraphs with different number of glyphs and characters. Update final paragraphs.",
+      "Hello different world\nनमस्ते दुनिया\nမင်္ဂလာပါကမ္ဘာလောက",
+      36u,
+      18u,
+      54u,
+      glyphIndices04,
+    },
+  };
+
+  const unsigned int numberOfTests = 6u;
+
+  for( unsigned int index = 0u; index < numberOfTests; ++index )
+  {
+    ToolkitTestApplication application;
+    if( !SetCharacterToGlyphTest( data[index] ) )
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-VisualUrl.cpp
new file mode 100644 (file)
index 0000000..962ad8e
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2017 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/internal/visuals/visual-url.h>
+
+using namespace Dali::Toolkit::Internal;
+
+int UtcDaliVisualUrlConstructor(void)
+{
+  const char* url="file://bar.org/foobar.gif";
+  VisualUrl visualUrl(url);
+  DALI_TEST_EQUALS( true, visualUrl.IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl.GetType(), VisualUrl::GIF, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
+
+  VisualUrl visualUrl2("foobar.jpeg");
+  visualUrl2 = visualUrl;
+  DALI_TEST_EQUALS( true, visualUrl2.IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl2.GetType(), VisualUrl::GIF, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl2.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
+
+  VisualUrl visualUrl3( visualUrl );
+  DALI_TEST_EQUALS( true, visualUrl3.IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl3.GetType(), VisualUrl::GIF, TEST_LOCATION );
+  DALI_TEST_EQUALS( visualUrl3.GetProtocolType(), VisualUrl::LOCAL, TEST_LOCATION );
+  END_TEST;
+}
+
+
+int UtcDaliVisualUrlRegularImage(void)
+{
+  tet_infoline( "UtcDaliVisualUrl REGULAR_IMAGE" );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.jpeg").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.PNG").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.Png123").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("foobar.Png1.23").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl(" ").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl(".").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("9").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("dali://bar.org/foobar.gif").GetType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlSvg(void)
+{
+  tet_infoline( "UtcDaliVisualUrl SVG" );
+
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svg").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svg.svg").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.svG").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.SVG").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl(".SvG").GetType(), TEST_LOCATION );
+
+  // SVGs aren't N-patch
+  DALI_TEST_EQUALS( VisualUrl::SVG, VisualUrl("foobar.9.svg").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.png").GetType(), TEST_LOCATION );
+
+  // maybe controversial, but for now we expect the suffix to be exactly .svg
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.svg1").GetType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlNPatch(void)
+{
+  tet_infoline( "UtcDaliVisualUrl N_PATCH" );
+
+  DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.#.png").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.9.bmp").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.9.jpg[]=$$").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::N_PATCH, VisualUrl("foobar.9.#.#.9.wbpm123").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.##.png").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("svg.99.jpeg").GetType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGif(void)
+{
+  tet_infoline( "UtcDaliVisualUrl GIF" );
+
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.gif").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.gif.gif").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.giF").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.GIF").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl(".GiF").GetType(), TEST_LOCATION );
+
+  // GIFs aren't N-patch
+  DALI_TEST_EQUALS( VisualUrl::GIF, VisualUrl("foobar.9.gif").GetType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.png").GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("gif.gif1").GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REGULAR_IMAGE, VisualUrl("dali://.gif").GetType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualUrlLocationP(void)
+{
+  tet_infoline( "UtcDaliVisualUrl Location" );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.jpeg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ftp://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("ssh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("http://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("https://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("FTP://BAR.ORG/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("SSH://BAR.ORG/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTP://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.GIF").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::REMOTE, VisualUrl("HTTPS://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://1234").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("DALI://1234").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::TEXTURE, VisualUrl("dali://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualUrlLocationN(void)
+{
+  tet_infoline( "UtcDaliVisualUrl Location negative tests" );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("h://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ht://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htp://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htpp://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("httt://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http;//bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:x/bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/xbar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sshttp://bar.org/foobar.svg").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:https://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:http://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("HPPT://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftp:/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftp:a/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("fpp://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ftt://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh;//bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ssh:a/bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("shh://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("sss://bar.org/foobar.9.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http:/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("h1tps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("ht2ps://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("htt3s://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("http4://bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https5/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:6/bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("https:/7bar.org/foobar.gif").GetProtocolType(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("file://bar.org/foobar.png").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dal://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("d1li://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("da2i://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dal3://1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali4//1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:5/1").GetProtocolType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( VisualUrl::LOCAL, VisualUrl("dali:/61").GetProtocolType(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlIsValid(void)
+{
+  tet_infoline( "UtcDaliVisualUrl IsValid" );
+
+  DALI_TEST_EQUALS( false, VisualUrl().IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("").IsValid(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.gif").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.png").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.svg").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.GIF").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.9.png").IsValid(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.gif").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.png").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.svg").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.GIF").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("http://bar.org/foobar.9.png").IsValid(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.gif").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.png").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.svg").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.GIF").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("https://bar.org/foobar.9.png").IsValid(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.gif").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.png").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.svg").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.GIF").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTP://bar.org/foobar.9.png").IsValid(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.gif").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.png").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.svg").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.GIF").IsValid(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("HTTPS://bar.org/foobar.9.png").IsValid(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualUrlIsLocalResource(void)
+{
+  tet_infoline( "UtcDaliVisualUrl IsLocalResource" );
+
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, VisualUrl("foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("http://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("https://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTP://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.gif").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.png").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.svg").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.GIF").IsLocalResource(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, VisualUrl("HTTPS://bar.org/foobar.9.png").IsLocalResource(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGetLocationP(void)
+{
+  tet_infoline( "UtcDaliVisualUrl GetLocation Positive" );
+
+  DALI_TEST_EQUAL( "a", VisualUrl("http://a").GetLocation() );
+  DALI_TEST_EQUAL( "1", VisualUrl("dali://1").GetLocation() );
+  DALI_TEST_EQUAL( "", VisualUrl("ftp://").GetLocation() );
+  DALI_TEST_EQUAL( "http://", VisualUrl("http://http://").GetLocation() );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlGetLocationN(void)
+{
+  tet_infoline( "UtcDaliVisualUrl GetLocation Negative" );
+
+  DALI_TEST_EQUAL( "", VisualUrl("").GetLocation() );
+  DALI_TEST_EQUAL( "a", VisualUrl("a").GetLocation() );
+  DALI_TEST_EQUAL( "dali:/1", VisualUrl("dali:/1").GetLocation() );
+  DALI_TEST_EQUAL( "dali//1", VisualUrl("dali//1").GetLocation() );
+  DALI_TEST_EQUAL( "", VisualUrl("http:/http://").GetLocation() );
+
+  END_TEST;
+}
+
+int UtcDaliVisualUrlCreateTextureUrl(void)
+{
+  tet_infoline( "UtcDaliVisualUrl CreateTextureUrl" );
+
+  DALI_TEST_EQUAL( "dali://a", VisualUrl::CreateTextureUrl( "a" ) );
+  DALI_TEST_EQUAL( "dali://1234", VisualUrl::CreateTextureUrl( "1234" ) );
+  DALI_TEST_EQUAL( "dali://", VisualUrl::CreateTextureUrl( "" ) );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Visuals-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Visuals-internal.cpp
new file mode 100644 (file)
index 0000000..d20cbcf
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2018 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 <toolkit-text-utils.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dummy-visual.h>
+#include <../dali-toolkit/dali-toolkit-test-utils/dummy-control.h>
+#include <dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+const char* TEST_VECTOR_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/insta_camera.json";
+
+}
+
+int UtcDaliVisualAction(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register an ImageVisual and and perform an Action on Visual directly" );
+  Vector2 controlSize( 20.f, 30.f );
+
+  //Created DummyVisual
+  Property::Map settings;
+  Toolkit::Internal::DummyVisualPtr dummyVisualPtr = Toolkit::Internal::DummyVisual::New( settings );
+
+  DummyControl dummyControl = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  tet_infoline( "Register visual and stage control" );
+
+  Toolkit::Visual::Base visualBaseHandle = Toolkit::Visual::Base( dummyVisualPtr.Get() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visualBaseHandle );
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Check action counter is 0 before DoAction" );
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 0, TEST_LOCATION );
+
+  tet_infoline( "Perform TEST_ACTION action on Visual. Should increase the action counter" );
+
+  Property::Map attributes;
+  Toolkit::Internal::Visual::Base& internalVisualBase =  GetImplementation( visualBaseHandle );
+  internalVisualBase.DoAction( Dali::Toolkit::Internal::DummyVisual::TEST_ACTION, attributes );
+  application.SendNotification();
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualActionNotImplemented(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register an ImageVisual and and perform an Action on a Visual which does not support any Actions" );
+  Vector2 controlSize( 20.f, 30.f );
+
+  //Created DummyVisual
+  Property::Map settings;
+  Toolkit::Internal::DummyVisualPtr dummyVisualPtr = Toolkit::Internal::DummyVisual::New( settings );
+
+  DummyControl dummyControl = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  tet_infoline( "Register visual and stage control" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Check action counter is 0 before DoAction" );
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 0, TEST_LOCATION );
+
+  tet_infoline( "Perform TEST_ACTION action on Color Visual which does not support it.. Should not increment the action counter" );
+  Property::Map attributes;
+  GetImplementation( visual ).DoAction( Dali::Toolkit::Internal::DummyVisual::TEST_ACTION, attributes );
+  application.SendNotification();
+  DALI_TEST_EQUALS( dummyVisualPtr->GetActionCounter() , 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetProperties(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register a visual and SetProperties" );
+
+  Toolkit::Internal::VisualFactoryCache* factoryCache = new Toolkit::Internal::VisualFactoryCache(false);
+
+  //Created ColorVisual
+  Property::Map propertyMap1;
+  propertyMap1.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap1.Insert(ColorVisual::Property::MIX_COLOR,  Color::RED);
+  Toolkit::Internal::ColorVisualPtr colorVisualPtr = Toolkit::Internal::ColorVisual::New( *factoryCache, propertyMap1 );
+
+  DummyControl dummyControl = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummyControl.GetImplementation() );
+
+  Toolkit::Visual::Base visualBaseHandle = Toolkit::Visual::Base( colorVisualPtr.Get() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visualBaseHandle );
+  dummyControl.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::MIX_COLOR,  Color::BLUE );
+
+  colorVisualPtr->SetProperties( propertyMap );
+  application.SendNotification();
+  application.Render();
+
+  Property::Map resultMap;
+  visualBaseHandle.CreatePropertyMap( resultMap );
+
+  Property::Value* colorValue = resultMap.Find( Visual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get< Vector4 >() == Color::BLUE );
+
+  delete factoryCache;
+
+  END_TEST;
+}
+
+int UtcDaliNPatchBufferGetRedOffsetAndMask(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliNPatchBufferGetRedOffsetAndMask");
+
+  int byteOffset = 0;
+  int bitMask = 0;
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::A8, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::L8, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::LA88, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGB888, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xff );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGB8888, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xff );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGBA8888, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xff );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::BGR8888, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 2 && bitMask == 0xff );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::BGRA8888, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 2 && bitMask == 0xff );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGB565, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xf8 );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::BGR565, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 1 && bitMask == 0x1f );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGBA4444, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xf0 );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::BGRA4444, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 1 && bitMask == 0xf0 );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGBA5551, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0xf8 );
+
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::BGRA5551, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 1 && bitMask == 0x1e );
+
+  // Compressed formats are not supported
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::INVALID, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_R11_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SIGNED_R11_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RG11_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SIGNED_RG11_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGB8_ETC2, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ETC2, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGB8_ETC1, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGB_PVRTC_4BPPV1, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA8_ETC2_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+
+  // Not supported
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGB16F, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+  Toolkit::Internal::NPatchBuffer::GetRedOffsetAndMask( Pixel::RGB32F, byteOffset, bitMask );
+  DALI_TEST_CHECK( byteOffset == 0 && bitMask == 0 );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualCreateInstancePropertyMap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualCreateInstancePropertyMap" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE,  DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  );
+
+  // request AnimatedVectorImageVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( visual );
+
+  Property::Map resultMap;
+  visualImpl.CreateInstancePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  DALI_TEST_CHECK( resultMap.Empty() );   // Now the map is empty
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualSetProperties(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualSetProperties" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3  )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, Vector2( 0.2f, 0.8f )  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( visual );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Map propertyMap1;
+  propertyMap1.Add( DevelImageVisual::Property::LOOP_COUNT, 1  )
+              .Add( DevelImageVisual::Property::PLAY_RANGE, Vector2( 0.4f, 0.6f )  );
+
+  visualImpl.SetProperties( propertyMap1 );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliArcVisualCreateInstancePropertyMap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliArcVisualCreateInstancePropertyMap" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ARC )
+             .Add( DevelArcVisual::Property::THICKNESS, 20.0f );
+
+  // request ArcVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation( visual );
+
+  Property::Map resultMap;
+  visualImpl.CreateInstancePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  DALI_TEST_CHECK( resultMap.Empty() );   // Now the map is empty
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-styling/default-theme.json b/automated-tests/src/dali-toolkit-styling/default-theme.json
new file mode 100644 (file)
index 0000000..7630242
--- /dev/null
@@ -0,0 +1,430 @@
+{
+  "config":
+  {
+    "alwaysShowFocus":false,
+    "clearFocusOnEscape":true,
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png"
+  },
+  "constants":
+  {
+    "CONFIG_SCRIPT_LOG_LEVEL":"NoLogging"
+  },
+  "styles":
+  {
+    "textlabel":
+    {
+      "pointSize":18
+    },
+
+    "textlabelFontSize0":
+    {
+      "pointSize":8
+    },
+    "textlabelFontSize1":
+    {
+      "pointSize":10
+    },
+    "textlabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "textlabelFontSize3":
+    {
+      "pointSize":19
+    },
+    "textlabelFontSize4":
+    {
+      "pointSize":25
+    },
+
+    "textfield":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
+    },
+
+    "textfieldFontSize0":
+    {
+      "pointSize":10
+    },
+    "textfieldFontSize1":
+    {
+      "pointSize":10
+    },
+    "textfieldFontSize2":
+    {
+      "pointSize":10
+    },
+    "textfieldFontSize3":
+    {
+      "pointSize":10
+    },
+    "textfieldFontSize4":
+    {
+      "pointSize":10
+    },
+    "textselectionpopup":
+    {
+      "popupMaxSize":[656,72],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "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"
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "textselectionpopupbutton":
+    {
+      "label":
+      {
+        "pointSize":8,
+        "fontStyle": { "weight":"light" }
+      }
+    },
+    "textselectiontoolbar":
+    {
+      "enableOvershoot":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[720.0,130.0]
+      }
+    },
+    "scrollview":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "itemview":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "texteditor":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
+    },
+    "ComplexControl":
+    {
+      "states":
+      {
+        "NORMAL":
+        {
+          "states":
+          {
+            "SELECTED":
+            {
+              "visuals":
+              {
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0001.png",
+                  "atlasing":true
+                },
+                "testVisual2":
+                {
+                  "visualType":"GRADIENT",
+                  "startPosition": [-1, -1],
+                  "endPosition": [1, 1],
+                  "spreadMethod": "REPEAT",
+                  "stopOffset": [0.2, 0.8],
+                  "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+                },
+                "foregroundVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"theSameImage.png",
+                  "atlasing":true
+                },
+                "labelVisual":
+                {
+                  "visualType":"TEXT",
+                  "pointSize":8,
+                  "text":"Some text"
+                }
+              }
+            },
+            "UNSELECTED":
+            {
+              "visuals":
+              {
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0002.png",
+                  "atlasing":true
+                },
+                "testVisual2":
+                {
+                  "visualType":"COLOR",
+                  "mixColor": [ 1,0,0,1]
+                },
+                "foregroundVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"theSameImage.png",
+                  "atlasing":true
+                },
+                "labelVisual":
+                {
+                  "visualType":"TEXT",
+                  "pointSize":8,
+                  "text":"Some different text"
+                }
+              }
+            }
+          },
+          "transitions":
+          {
+            "visualName":"*",
+            "effect":"CROSSFADE",
+            "animator":
+            {
+              "alphaFunction":"EASE_IN_OUT",
+              "duration":0.3
+            }
+          }
+        },
+        "FOCUSED":
+        {
+          "visuals":
+          {
+            "foregroundVisual":
+            {
+              "visualType":"GRADIENT",
+              "startPosition": [-1, -1],
+              "endPosition": [1, 1],
+              "spreadMethod": "REPEAT",
+              "stopOffset": [0.3, 0.9],
+              "stopColor": [ [ 0,0,1,1], [0,1,1,1] ]
+            },
+            "focusVisual":
+            {
+              "visualType":"NPATCH",
+              "url": "focus.9.png"
+            }
+          },
+          "entryTransition":
+          {
+            "target":"focusVisual",
+            "property":"mixColor",
+            "initialValue":[0,0,0,0],
+            "targetValue":[1,1,1,1],
+            "animator":
+            {
+              "alphaFunction":"EASE_IN_OUT_SINE",
+              "timePeriod":
+              {
+                "duration":0.5,
+                "delay":0
+              }
+            }
+          },
+          "exitTransition":
+          {
+            "target":"focusVisual",
+            "property":"mixColor",
+            "initialValue":[1,1,1,1],
+            "targetValue":[0,0,0,0],
+            "animator":
+            {
+              "alphaFunction":"EASE_IN_OUT_SINE",
+              "timePeriod":
+              {
+                "duration":0.5,
+                "delay":0
+              }
+            }
+          }
+        },
+        "DISABLED":
+        {
+          "states":
+          {
+            "SELECTED":
+            {
+              "visuals":
+              {
+                "testVisual":
+                {
+                  "visualType":"IMAGE",
+                  "url":"0001.png",
+                  "atlasing":true
+                },
+                "testVisual2":
+                {
+                  "visualType":"GRADIENT",
+                  "startPosition": [-1, -1],
+                  "endPosition": [1, 1],
+                  "spreadMethod": "REPEAT",
+                  "stopOffset": [0.2, 0.8],
+                  "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+                }
+              }
+            }
+          },
+          "visuals":
+          {
+            "foregroundVisual":
+            {
+              "visualType":"COLOR",
+              "mixColor": [1,0,0,1]
+            }
+          }
+        }
+      },
+      "transitions":
+      [
+        {
+          "effect":"CROSSFADE",
+          "animator":
+          {
+            "alphaFunction":"EASE_IN_OUT",
+            "duration":0.3
+          }
+        }
+      ]
+    },
+    "BasicControl":
+    {
+      "states":
+      {
+        "NORMAL":
+        {
+          "visuals":
+          {
+            "foregroundVisual":
+            {
+              "visualType":"GRADIENT",
+              "startPosition": [-1, -1],
+              "endPosition": [1, 1],
+              "spreadMethod": "REPEAT",
+              "stopOffset": [0.2, 0.8],
+              "stopColor": [ [ 1,0,0,1], [0,1,0,1] ]
+            },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":8,
+              "textColor":[1,0,1,1]
+            }
+          }
+        },
+        "FOCUSED":
+        {
+          "visuals":
+          {
+            "foregroundVisual":
+            {
+              "visualType":"GRADIENT",
+              "startPosition": [-1, -1],
+              "endPosition": [1, 1],
+              "spreadMethod": "REPEAT",
+              "stopOffset": [0.3, 0.9],
+              "stopColor": [ [ 0,0,1,1], [0,1,1,1] ]
+            },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":10
+            },
+            "focusVisual":
+            {
+              "visualType":"IMAGE",
+              "url": "focus.png",
+              "atlasing":true
+            }
+          },
+          "entryTransition":
+          {
+            "target":"focusVisual",
+            "property":"mixColor",
+            "initialValue":[0,0,0,0],
+            "targetValue":[1,1,1,1],
+            "animator":
+            {
+              "alphaFunction":"EASE_IN_OUT_SINE",
+              "timePeriod":
+              {
+                "duration":0.5,
+                "delay":0
+              }
+            }
+          },
+          "exitTransition":
+          {
+            "target":"focusVisual",
+            "property":"mixColor",
+            "initialValue":[1,1,1,1],
+            "targetValue":[0,0,0,0],
+            "animator":
+            {
+              "alphaFunction":"EASE_IN_OUT_SINE",
+              "timePeriod":
+              {
+                "duration":0.5,
+                "delay":0
+              }
+            }
+          }
+        },
+        "DISABLED":
+        {
+          "visuals":
+          {
+            "foregroundVisual":
+            {
+              "visualType":"COLOR",
+              "mixColor": [1,0,0,1]
+            },
+            "labelVisual":
+            {
+              "visualType":"TEXT",
+              "pointSize":9,
+              "textColor":[1,1,1,1]
+            }
+          }
+        }
+      },
+      "transitions":
+      [
+        {
+          "effect":"CROSSFADE",
+          "animator":
+          {
+            "alphaFunction":"EASE_IN_OUT",
+            "duration":0.3
+          }
+        }
+      ]
+    },
+    "NoStateStyle":
+    {
+      "testVisual2":
+      {
+        "visualType":"COLOR",
+        "mixColor":[1,1,1,1]
+      }
+    }
+  }
+}
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..ef04d46
--- /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 = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        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/theme2.json b/automated-tests/src/dali-toolkit-styling/theme2.json
new file mode 100644 (file)
index 0000000..8ca44cd
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "styles":
+  {
+    "testbutton":
+    {
+      "backgroundColor":[1.0,1.0,0.0,1.0]
+    }
+  }
+}
diff --git a/automated-tests/src/dali-toolkit-styling/theme3.json b/automated-tests/src/dali-toolkit-styling/theme3.json
new file mode 100644 (file)
index 0000000..68a292e
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "styles":
+  {
+    "testbutton":
+    {
+      "backgroundColor":[1.0,1.0,0.0,1.0]
+// Deliberate Error: trailing comma
+    },
+  },
+}
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 100755 (executable)
index 0000000..94d625d
--- /dev/null
@@ -0,0 +1,1356 @@
+ /*
+ * Copyright (c) 2019 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/style-monitor.h>
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#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>
+#include <dummy-control.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+#include <dali/integration-api/events/key-event-integ.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+std::string defaultTheme;
+
+} // anonymous namespace
+
+
+
+
+void dali_style_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+
+  std::ifstream t("src/dali-toolkit-styling/default-theme.json");
+  defaultTheme = std::string((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
+}
+
+void dali_style_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+Visual::Base CheckVisual( Impl::DummyControl& dummyImpl, Property::Index visualId, int type, const char* location )
+{
+    DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(visualId), true, location);
+    Visual::Base visual = dummyImpl.GetVisual(visualId);
+    DALI_TEST_EQUALS( (bool)visual, true, location );
+    Property::Map map;
+    visual.CreatePropertyMap( map );
+    Property::Value* value = map.Find( Toolkit::Visual::Property::TYPE );
+    DALI_TEST_EQUALS( value != NULL, true, location );
+
+    int visualType;
+    value->Get( visualType );
+    DALI_TEST_EQUALS( visualType, type, location );
+    return visual;
+}
+
+
+Integration::Bitmap* CreateBitmap( unsigned int imageWidth, unsigned int imageHeight, unsigned int initialColor, Pixel::Format pixelFormat )
+{
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
+  Integration::PixelBuffer* pixbuffer = bitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, imageWidth, imageHeight, imageWidth, imageHeight );
+  unsigned int bytesPerPixel = GetBytesPerPixel( pixelFormat );
+
+  memset( pixbuffer, initialColor, imageHeight * imageWidth * bytesPerPixel );
+
+  return bitmap;
+}
+
+Integration::ResourcePointer CustomizeNinePatch( ToolkitTestApplication& application,
+                                                 unsigned int ninePatchImageWidth,
+                                                 unsigned int ninePatchImageHeight)
+{
+  TestPlatformAbstraction& platform = application.GetPlatform();
+
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+
+  tet_infoline("Create Bitmap");
+  platform.SetClosestImageSize(Vector2( ninePatchImageWidth, ninePatchImageHeight));
+  Integration::Bitmap* bitmap = CreateBitmap( ninePatchImageWidth, ninePatchImageHeight, 0xFF, pixelFormat );
+
+  tet_infoline("Getting resource");
+  Integration::ResourcePointer resourcePtr(bitmap);
+  platform.SetSynchronouslyLoadedResource( resourcePtr);
+
+  return resourcePtr;
+}
+
+int UtcDaliStyleManagerConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliStyleManagerConstructorP");
+  StyleManager styleManager;
+  DALI_TEST_CHECK( !styleManager);
+  END_TEST;
+}
+
+int UtcDaliStyleManagerCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  StyleManager styleManager = StyleManager::Get();
+  StyleManager copyOfStyleManager( styleManager );
+
+  DALI_TEST_CHECK( copyOfStyleManager );
+  END_TEST;
+}
+
+int UtcDaliStyleManagerAssignmentOperatorP(void)
+{
+  ToolkitTestApplication 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"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"CONFIG_SCRIPT_LOG_LEVEL\":\"Verbose\"\n"
+    "  },\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);
+
+  // To ensure we make VisualFactory
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  Visual::Base textVisual = factory.CreateVisual( propertyMap );
+
+  // 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"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"CONFIG_SCRIPT_LOG_LEVEL\":\"Concise\"\n"
+    "  },\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"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"CONFIG_SCRIPT_LOG_LEVEL\":\"General\"\n"
+    "  },\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 UtcDaliStyleManagerIncludeStyleP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works" );
+
+  const char* json1 =
+    "{\n"
+    "  \"includes\":\n"
+    "  [\n"
+    "     \"src/dali-toolkit-styling/theme2.json\"\n"
+    "  ],\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"foregroundColor\":[0.0,0.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) );
+
+  DALI_TEST_EQUALS( themedBgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( themedFgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerIncludeStyleN(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliStyleManagerIncludeStyle - test that style sheet inclusion works, but included stylesheet is bad json" );
+
+  const char* json1 =
+    "{\n"
+    "  \"includes\":\n"
+    "  [\n"
+    "     \"src/dali-toolkit-styling/theme3.json\"\n"
+    "  ],\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"foregroundColor\":[0.0,0.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);
+
+  try
+  {
+    styleManager.ApplyTheme(themeFile);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "!\"Cannot parse JSON\"", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerStyleChangedSignalFontFamily(void)
+{
+  tet_infoline("Test that the StyleChange signal is fired when the font family 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::TextField field = Toolkit::TextField::New();
+  Stage::GetCurrent().Add( field );
+
+  Toolkit::TextEditor editor = Toolkit::TextEditor::New();
+  Stage::GetCurrent().Add( editor );
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::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);
+
+  // Check that the field's font style has been altered
+  family = field.GetProperty(TextField::Property::FONT_FAMILY);
+  family.Get( familyStr );
+
+  DALI_TEST_EQUALS( familyStr, "Times New Roman", TEST_LOCATION);
+
+  // Check that the editor's font style has been altered
+  family = editor.GetProperty(TextEditor::Property::FONT_FAMILY);
+  family.Get( familyStr );
+
+  DALI_TEST_EQUALS( familyStr, "Times New Roman", TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerStyleChangedSignalFontSize(void)
+{
+  tet_infoline("Test that the StyleChange signal is fired when the font size is altered" );
+
+  const char* defaultTheme =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"textlabelFontSize0\":\n"
+    "    {\n"
+    "      \"pointSize\":10\n"
+    "    },\n"
+    "    \"textlabelFontSize1\":\n"
+    "    {\n"
+    "      \"pointSize\":10\n"
+    "    },\n"
+    "    \"textlabelFontSize2\":\n"
+    "    {\n"
+    "      \"pointSize\":12\n"
+    "    },\n"
+    "    \"textlabelFontSize3\":\n"
+    "    {\n"
+    "      \"pointSize\":14\n"
+    "    },\n"
+    "    \"textlabelFontSize4\":\n"
+    "    {\n"
+    "      \"pointSize\":16\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  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();
+
+  label.SetProperty(TextLabel::Property::POINT_SIZE, 10.0f);
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  Test::StyleMonitor::SetDefaultFontSize(2);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor,  StyleChange::DEFAULT_FONT_SIZE_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  tet_infoline("Test that the label's font size has been altered\n");
+  Property::Value pointSizeValue = label.GetProperty(TextLabel::Property::POINT_SIZE);
+  float pointSize;
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 12.0f, 0.001, TEST_LOCATION );
+
+  styleChangedSignalHandler.signalCount = 0;
+
+  Test::StyleMonitor::SetDefaultFontSize(4);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor, StyleChange::DEFAULT_FONT_SIZE_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
+  pointSizeValue = label.GetProperty(TextLabel::Property::POINT_SIZE);
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 16.0f, 0.001, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerStyleChangedSignalFontSizeTextField(void)
+{
+  tet_infoline("Test that the StyleChange signal is fired when the font size is altered" );
+
+  const char* defaultTheme =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"textfieldFontSize0\":\n"
+    "    {\n"
+    "      \"pointSize\":8\n"
+    "    },\n"
+    "    \"textfieldFontSize1\":\n"
+    "    {\n"
+    "      \"pointSize\":10\n"
+    "    },\n"
+    "    \"textfieldFontSize2\":\n"
+    "    {\n"
+    "      \"pointSize\":12\n"
+    "    },\n"
+    "    \"textfieldFontSize3\":\n"
+    "    {\n"
+    "      \"pointSize\":14\n"
+    "    },\n"
+    "    \"textfieldFontSize4\":\n"
+    "    {\n"
+    "      \"pointSize\":16\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json", defaultTheme );
+
+  ToolkitTestApplication application;
+
+  std::string fieldStr("Field");
+  Toolkit::TextField field = Toolkit::TextField::New();
+  field.SetProperty( Toolkit::TextField::Property::TEXT, fieldStr );
+  Stage::GetCurrent().Add( field );
+
+  Toolkit::TextField field2 = Toolkit::TextField::New();
+  Stage::GetCurrent().Add( field2 );
+  field2.SetProperty( Toolkit::TextField::Property::TEXT, fieldStr );
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleMonitor styleMonitor = StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  field.SetProperty(TextField::Property::POINT_SIZE, 10.0f);
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  Test::StyleMonitor::SetDefaultFontSize(2);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor,  StyleChange::DEFAULT_FONT_SIZE_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  tet_infoline("Test that the field's font size has been altered\n");
+  Property::Value pointSizeValue = field.GetProperty(TextField::Property::POINT_SIZE);
+  float pointSize;
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 12.0f, 0.001, TEST_LOCATION );
+
+  styleChangedSignalHandler.signalCount = 0;
+
+  Test::StyleMonitor::SetDefaultFontSize(4);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor, StyleChange::DEFAULT_FONT_SIZE_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  // Check that the field's font style has been altered
+  pointSizeValue = field.GetProperty(TextField::Property::POINT_SIZE);
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 16.0f, 0.001, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerStyleChangedSignalFontSizeTextEditor(void)
+{
+  tet_infoline("Test that the StyleChange signal is fired when the font size is altered" );
+
+  const char* defaultTheme =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"texteditorFontSize0\":\n"
+    "    {\n"
+    "      \"pointSize\":10\n"
+    "    },\n"
+    "    \"texteditorFontSize1\":\n"
+    "    {\n"
+    "      \"pointSize\":12\n"
+    "    },\n"
+    "    \"texteditorFontSize2\":\n"
+    "    {\n"
+    "      \"pointSize\":14\n"
+    "    },\n"
+    "    \"texteditorFontSize3\":\n"
+    "    {\n"
+    "      \"pointSize\":18\n"
+    "    },\n"
+    "    \"texteditorFontSize4\":\n"
+    "    {\n"
+    "      \"pointSize\":25\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json", defaultTheme );
+
+  ToolkitTestApplication application;
+
+  std::string editorStr("Editor");
+  Toolkit::TextEditor editor = Toolkit::TextEditor::New();
+  editor.SetProperty( Toolkit::TextEditor::Property::TEXT, editorStr );
+  Stage::GetCurrent().Add( editor );
+
+  Toolkit::TextEditor editor2 = Toolkit::TextEditor::New();
+  Stage::GetCurrent().Add( editor2 );
+  editor2.SetProperty( Toolkit::TextEditor::Property::TEXT, editorStr );
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleMonitor styleMonitor = StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  editor.SetProperty(TextEditor::Property::POINT_SIZE, 10.0f);
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  Test::StyleMonitor::SetDefaultFontSize(2);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor,  StyleChange::DEFAULT_FONT_SIZE_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  tet_infoline("Test that the editor's font size has been altered\n");
+  Property::Value pointSizeValue = editor.GetProperty(TextEditor::Property::POINT_SIZE);
+  float pointSize;
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 14.0f, 0.001, TEST_LOCATION );
+
+  styleChangedSignalHandler.signalCount = 0;
+
+  Test::StyleMonitor::SetDefaultFontSize(4);
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor, StyleChange::DEFAULT_FONT_SIZE_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  // Check that the editor's font style has been altered
+  pointSizeValue = editor.GetProperty(TextEditor::Property::POINT_SIZE);
+  pointSizeValue.Get( pointSize );
+
+  DALI_TEST_EQUALS( pointSize, 25.0f, 0.001, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetState01(void)
+{
+  tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetStyleName("BasicControl");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+  Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  Visual::Base labelVisual1 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  Property::Map labelMap;
+  labelVisual1.CreatePropertyMap( labelMap );
+  labelMap[TextVisual::Property::TEXT] = "New text";
+  VisualFactory factory = VisualFactory::Get();
+  labelVisual1 = factory.CreateVisual(labelMap);
+  dummyImpl.UnregisterVisual(DummyControl::Property::LABEL_VISUAL );
+  dummyImpl.RegisterVisual(DummyControl::Property::LABEL_VISUAL, labelVisual1 );
+
+  actor.SetProperty( DevelControl::Property::STATE, DevelControl::FOCUSED );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::LABEL_VISUAL), true, TEST_LOCATION);
+
+  Visual::Base visual2 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  Visual::Base labelVisual2 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( visual1 != visual2 );
+  DALI_TEST_CHECK( labelVisual1 != labelVisual2 );
+  labelMap.Clear();
+  labelVisual2.CreatePropertyMap( labelMap );
+  Property::Value* textValue = labelMap.Find( Toolkit::TextVisual::Property::TEXT, "text");
+  DALI_TEST_CHECK( textValue );
+  Property::Value* pointSizeValue = labelMap.Find( Toolkit::TextVisual::Property::POINT_SIZE, "pointSize");
+  tet_infoline( "Check that the instance data has been copied to the new text visual\n");
+  DALI_TEST_EQUALS( textValue->Get<std::string>(), "New text", TEST_LOCATION );
+  DALI_TEST_EQUALS( pointSizeValue->Get<int>(), 10, TEST_LOCATION );
+
+
+  actor.SetProperty( DevelControl::Property::STATE, DevelControl::DISABLED );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+
+  Visual::Base visual3 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( !focusVisual );
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), false, TEST_LOCATION);
+
+  DALI_TEST_CHECK( visual1 != visual3 );
+  DALI_TEST_CHECK( visual2 != visual3 );
+
+  Visual::Base labelVisual3 = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( labelVisual2 != labelVisual3 );
+
+  labelVisual2.CreatePropertyMap( labelMap );
+  textValue = labelMap.Find(Toolkit::TextVisual::Property::TEXT, "text");
+  DALI_TEST_CHECK( textValue );
+  pointSizeValue = labelMap.Find(Toolkit::TextVisual::Property::POINT_SIZE, "pointSize");
+  tet_infoline( "Check that the instance data has been copied to the new text visual\n");
+  DALI_TEST_EQUALS( textValue->Get<std::string>(), "New text", TEST_LOCATION );
+  DALI_TEST_EQUALS( pointSizeValue->Get<int>(), 10, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerSetState02(void)
+{
+  tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetStyleName("BasicControl");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
+  int state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+  Visual::Base visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "FOCUSED" ).Add("withTransitions", false));
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::FOCUSED, TEST_LOCATION );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), true, TEST_LOCATION);
+
+  Visual::Base visual2 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  DALI_TEST_CHECK( visual1 != visual2 );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "DISABLED" ).Add("withTransitions", false));
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::DISABLED, TEST_LOCATION );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+
+  Visual::Base visual3 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL2);
+  DALI_TEST_CHECK( !testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( testVisual );
+
+
+  DALI_TEST_CHECK( visual1 != visual3 );
+  DALI_TEST_CHECK( visual2 != visual3 );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "NORMAL" ).Add("withTransitions", false));
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOREGROUND_VISUAL), true, TEST_LOCATION);
+
+  visual1 = dummyImpl.GetVisual(DummyControl::Property::FOREGROUND_VISUAL);
+  DALI_TEST_CHECK( visual1 );
+
+  Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( !focusVisual );
+  DALI_TEST_EQUALS(dummyImpl.IsVisualEnabled(DummyControl::Property::FOCUS_VISUAL), false, TEST_LOCATION);
+
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetState03N(void)
+{
+  tet_infoline("Instantiate dummy control and test state transition without state style" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetStyleName("NoStyles");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  int state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "FOCUSED" ).Add("withTransitions", false));
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::FOCUSED, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "DISABLED" ).Add("withTransitions", false));
+
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::DISABLED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetState04N(void)
+{
+  tet_infoline("Instantiate dummy control and test state transition with style without state" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetStyleName("NoStateStyle");
+  Stage::GetCurrent().Add(actor);
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  int state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::NORMAL, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "FOCUSED" ).Add("withTransitions", false));
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::FOCUSED, TEST_LOCATION );
+
+  actor.SetProperty( DevelControl::Property::STATE,
+                     Property::Map().Add( "state", "DISABLED" ).Add("withTransitions", false));
+
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_CHECK( testVisual = visual );
+
+  state = actor.GetProperty<int>( DevelControl::Property::STATE );
+  DALI_TEST_EQUALS( state, (int) DevelControl::DISABLED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerSetSubState01(void)
+{
+  tet_infoline("Instantiate dummy control and test state/visual/transition capture" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetProperty(DevelControl::Property::STATE, "NORMAL");
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+  actor.SetStyleName("ComplexControl");
+  Stage::GetCurrent().Add(actor);
+
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "UNSELECTED");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::COLOR, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetSubState02(void)
+{
+  tet_infoline("Instantiate complex control and test state/substate change" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  Dali::StyleMonitor styleMonitor = Dali::StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  DummyControl actor = DummyControl::New(true);
+  actor.SetProperty(DevelControl::Property::STATE, "NORMAL");
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+  tet_infoline( "Setting state to NORMAL/SELECTED before re-styling\n");
+
+  actor.SetStyleName("ComplexControl");
+  Stage::GetCurrent().Add(actor);
+
+  Integration::ResourcePointer ninePatch = CustomizeNinePatch( application, 30, 30 );
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "UNSELECTED");
+  tet_infoline( "Changing substate to UNSELECTED - check visual changes\n");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::COLOR, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::STATE, "FOCUSED");
+  tet_infoline( "Changing state to FOCUSED - check visual changes\n");
+
+  Visual::Base fgVisual1 = CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+  Visual::Base focusVisual1 = CheckVisual( dummyImpl, DummyControl::Property::FOCUS_VISUAL, Toolkit::Visual::N_PATCH, TEST_LOCATION);
+
+  actor.SetProperty(DevelControl::Property::SUB_STATE, "SELECTED");
+  tet_infoline( "Changing  substate to SELECTED - Expect no change\n");
+
+  Visual::Base fgVisual2 = CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+  Visual::Base focusVisual2 = CheckVisual( dummyImpl, DummyControl::Property::FOCUS_VISUAL, Toolkit::Visual::N_PATCH, TEST_LOCATION);
+
+  DALI_TEST_CHECK( fgVisual1 == fgVisual2 );
+  DALI_TEST_CHECK( focusVisual1 == focusVisual2 );
+
+  actor.SetProperty(DevelControl::Property::STATE, "NORMAL");
+  tet_infoline( "Changing state to NORMAL - Expect to change to NORMAL/SELECTED \n");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, Toolkit::Visual::GRADIENT, TEST_LOCATION);
+
+  Visual::Base focusVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( ! focusVisual );
+
+  actor.SetProperty(DevelControl::Property::STATE, "DISABLED");
+  tet_infoline( "Changing state to DISABLED - Expect to change to DISABLED/SELECTED \n");
+
+  CheckVisual( dummyImpl, DummyControl::Property::FOREGROUND_VISUAL, Toolkit::Visual::COLOR, TEST_LOCATION);
+  CheckVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, Toolkit::Visual::IMAGE, TEST_LOCATION);
+
+  Visual::Base testVisual = dummyImpl.GetVisual(DummyControl::Property::FOCUS_VISUAL);
+  DALI_TEST_CHECK( ! testVisual );
+  testVisual = dummyImpl.GetVisual(DummyControl::Property::LABEL_VISUAL);
+  DALI_TEST_CHECK( ! testVisual );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerConfigSectionTest(void)
+{
+  tet_infoline("Test that the properties in config section are works" );
+
+  const char* defaultTheme =
+    "{\n"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"TEST\":\"broken\"\n"
+    "  },\n"
+    "  \"config\":\n"
+    "  {\n"
+    "    \"brokenImageUrl\":\"{TEST}|{TEST}|{TEST|TEST.png\",\n"
+    "    \"alwaysShowFocus\":false,\n"
+    "    \"clearFocusOnEscape\":false\n"
+    "  },\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "  }\n"
+    "}\n";
+
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json", defaultTheme );
+
+  ToolkitTestApplication application;
+
+  Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+
+  Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
+  bool alwaysShowFocus = config["alwaysShowFocus"].Get<bool>();
+  DALI_TEST_CHECK( !alwaysShowFocus );
+  bool clearFocusOnEscape = config["clearFocusOnEscape"].Get<bool>();
+  DALI_TEST_CHECK( !clearFocusOnEscape );
+  std::string brokenImageUrl = config["brokenImageUrl"].Get<std::string>();
+  DALI_TEST_CHECK( brokenImageUrl.compare( "broken|broken|{TEST|TEST.png" ) == 0 );
+
+  // For coverage
+  Toolkit::TextEditor editor = Toolkit::TextEditor::New();
+  editor.SetKeyboardFocusable( true );
+  Stage::GetCurrent().Add( editor );
+
+  Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( editor );
+
+  application.ProcessEvent( Integration::KeyEvent( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Down, "", "", Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
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..d188f08
--- /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 = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        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..0ae564f
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2019 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 <cstdlib>
+
+#include <dali-test-suite-utils.h>
+// GTest fails to compile with "error: return-statement with a value, in function returning 'void'" error
+// if using dali assert function so define new assert with returning void.
+#define _ASSERT_H_
+#define assert(exp) \
+    if (!(exp)) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Following expression is not true:\n" \
+                "%s\n", #exp); \
+        std::abort(); \
+    }
+#include <gtest/gtest.h>
+#undef GTEST_HAS_DEATH_TEST
+#include "yoga/YGFlexTest.cpp"
+#include "yoga/YGAlignContentTest.cpp"
+#include "yoga/YGComputedMarginTest.cpp"
+#include "yoga/YGZeroOutLayoutRecursivlyTest.cpp"
+#include "yoga/YGRoundingTest.cpp"
+#include "yoga/YGTreeMutationTest.cpp"
+#include "yoga/YGMeasureCacheTest.cpp"
+#include "yoga/YGTraversalTest.cpp"
+#include "yoga/YGAlignItemsTest.cpp"
+#include "yoga/YGComputedPaddingTest.cpp"
+#include "yoga/YGDimensionTest.cpp"
+#include "yoga/YGDefaultValuesTest.cpp"
+#include "yoga/YGMinMaxDimensionTest.cpp"
+#include "yoga/YGPaddingTest.cpp"
+#include "yoga/YGLoggerTest.cpp"
+#include "yoga/YGAbsolutePositionTest.cpp"
+#include "yoga/YGBorderTest.cpp"
+#include "yoga/YGDirtiedTest.cpp"
+#include "yoga/YGRoundingMeasureFuncTest.cpp"
+#include "yoga/YGEdgeTest.cpp"
+#include "yoga/YGAlignSelfTest.cpp"
+#include "yoga/YGMeasureTest.cpp"
+#include "yoga/YGFlexDirectionTest.cpp"
+#include "yoga/YGHadOverflowTest.cpp"
+#include "yoga/YGNodeChildTest.cpp"
+#include "yoga/YGRoundingFunctionTest.cpp"
+#include "yoga/YGPersistenceTest.cpp"
+#include "yoga/YGPercentageTest.cpp"
+#include "yoga/YGStyleTest.cpp"
+#include "yoga/YGMarginTest.cpp"
+#include "yoga/YGLayoutDiffingTest.cpp"
+#include "yoga/YGBaselineFuncTest.cpp"
+#include "yoga/YGAspectRatioTest.cpp"
+#include "yoga/YGSizeOverflowTest.cpp"
+#include "yoga/YGDirtyMarkingTest.cpp"
+#include "yoga/YGMeasureModeTest.cpp"
+#include "yoga/YGJustifyContentTest.cpp"
+#include "yoga/YGInfiniteHeightTest.cpp"
+#include "yoga/YGRelayoutTest.cpp"
+#include "yoga/YGDisplayTest.cpp"
+#include "yoga/YGFlexWrapTest.cpp"
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliFlexboxLayoutTest(void)
+{
+  tet_infoline("UtcDaliFlexboxLayoutTest");
+  int argc = 1;
+  const char* argv = "yoga-gtest";
+  testing::InitGoogleTest( &argc,  const_cast< char** >( &argv ) );
+
+  // The test function is a 3rd party function that should return true if the test passes
+  if( !RUN_ALL_TESTS() )
+  {
+    tet_result(TET_PASS);
+  }
+  else
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAbsolutePositionTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAbsolutePositionTest.cpp
new file mode 100644 (file)
index 0000000..a319cf1
--- /dev/null
@@ -0,0 +1,1031 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGAbsolutePositionTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, absolute_layout_width_height_start_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_width_height_end_bottom) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeEnd, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_start_top_end_bottom) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeEnd, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_width_height_start_top_end_bottom) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeEnd, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, do_not_clamp_height_of_absolute_node_to_height_of_its_overflow_hidden_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetOverflow(root, YGOverflowHidden);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeStart, 0);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 0);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 100);
+  YGNodeStyleSetHeight(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_within_border) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root, YGEdgeBottom, 10);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 10);
+  YGNodeStyleSetBorder(root, YGEdgeLeft, 10);
+  YGNodeStyleSetBorder(root, YGEdgeTop, 10);
+  YGNodeStyleSetBorder(root, YGEdgeRight, 10);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 0);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 0);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child1, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child1, YGEdgeRight, 0);
+  YGNodeStyleSetPosition(root_child1, YGEdgeBottom, 0);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child2, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child2, YGEdgeLeft, 0);
+  YGNodeStyleSetPosition(root_child2, YGEdgeTop, 0);
+  YGNodeStyleSetMargin(root_child2, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child2, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child2, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child2, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child3, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child3, YGEdgeRight, 0);
+  YGNodeStyleSetPosition(root_child3, YGEdgeBottom, 0);
+  YGNodeStyleSetMargin(root_child3, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexEnd);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_justify_content_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_center_on_child_only) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignCenter);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_center_and_top_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_center_and_bottom_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_center_and_left_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 5);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_align_items_and_justify_content_center_and_right_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 110);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeRight, 5);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, position_root_with_rtl_should_position_withoutdirection) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root, YGEdgeLeft, 72);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_percentage_bottom_based_on_parent_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeTop, 50);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child1, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child1, YGEdgeBottom, 50);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child2, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child2, YGEdgeTop, 10);
+  YGNodeStyleSetPositionPercent(root_child2, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_in_wrap_reverse_column_container) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_in_wrap_reverse_row_container) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_in_wrap_reverse_column_container_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexEnd);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, absolute_layout_in_wrap_reverse_row_container_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexEnd);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignContentTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignContentTest.cpp
new file mode 100644 (file)
index 0000000..7cd5c09
--- /dev/null
@@ -0,0 +1,1878 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGAlignContentTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, align_content_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 130);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 10);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeStyleSetHeight(root_child4, 10);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(130, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(130, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_flex_start_without_height_on_children) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 10);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_flex_start_with_flex) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 120);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 0);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child3, 1);
+  YGNodeStyleSetFlexShrink(root_child3, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child3, 0);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root, YGAlignFlexEnd);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 10);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeStyleSetHeight(root_child4, 10);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_spacebetween) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignSpaceBetween);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 130);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 10);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeStyleSetHeight(root_child4, 10);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(130, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(130, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_spacearound) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignSpaceAround);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 140);
+  YGNodeStyleSetHeight(root, 120);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 10);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeStyleSetHeight(root_child4, 10);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(95, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(95, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_children) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0_child0, 0);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_flex) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child3, 1);
+  YGNodeStyleSetFlexShrink(root_child3, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child3, 0);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_flex_no_shrink) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child3, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child3, 0);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child1, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child1, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child1, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child1, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child3, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child3, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root_child1, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root_child1, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root_child1, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root_child1, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root_child3, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root_child3, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root_child3, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root_child3, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_single_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_fixed_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 60);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetMaxHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_row_with_min_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetMinHeight(root_child1, 80);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 150);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0_child0, 0);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_content_stretch_is_not_overriding_align_items) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root_child0, YGAlignStretch);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignCenter);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root_child0_child0, YGAlignStretch);
+  YGNodeStyleSetWidth(root_child0_child0, 10);
+  YGNodeStyleSetHeight(root_child0_child0, 10);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignItemsTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignItemsTest.cpp
new file mode 100644 (file)
index 0000000..fd5e424
--- /dev/null
@@ -0,0 +1,2158 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGAlignItemsTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, align_items_stretch) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexEnd);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_multiline) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child1, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child1, YGWrapWrap);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 25);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child1_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child1, 25);
+  YGNodeStyleSetHeight(root_child1_child1, 10);
+  YGNodeInsertChild(root_child1, root_child1_child1, 1);
+
+  const YGNodeRef root_child1_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child2, 25);
+  YGNodeStyleSetHeight(root_child1_child2, 20);
+  YGNodeInsertChild(root_child1, root_child1_child2, 2);
+
+  const YGNodeRef root_child1_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child3, 25);
+  YGNodeStyleSetHeight(root_child1_child3, 10);
+  YGNodeInsertChild(root_child1, root_child1_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_multiline_override) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child1, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child1, YGWrapWrap);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 25);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child1_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child1_child1, YGAlignBaseline);
+  YGNodeStyleSetWidth(root_child1_child1, 25);
+  YGNodeStyleSetHeight(root_child1_child1, 10);
+  YGNodeInsertChild(root_child1, root_child1_child1, 1);
+
+  const YGNodeRef root_child1_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child2, 25);
+  YGNodeStyleSetHeight(root_child1_child2, 20);
+  YGNodeInsertChild(root_child1, root_child1_child2, 2);
+
+  const YGNodeRef root_child1_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child1_child3, YGAlignBaseline);
+  YGNodeStyleSetWidth(root_child1_child3, 25);
+  YGNodeStyleSetHeight(root_child1_child3, 10);
+  YGNodeInsertChild(root_child1, root_child1_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_multiline_no_override_on_secondline) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child1, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child1, YGWrapWrap);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 25);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child1_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child1, 25);
+  YGNodeStyleSetHeight(root_child1_child1, 10);
+  YGNodeInsertChild(root_child1, root_child1_child1, 1);
+
+  const YGNodeRef root_child1_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child2, 25);
+  YGNodeStyleSetHeight(root_child1_child2, 20);
+  YGNodeInsertChild(root_child1, root_child1_child2, 2);
+
+  const YGNodeRef root_child1_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child1_child3, YGAlignBaseline);
+  YGNodeStyleSetWidth(root_child1_child3, 25);
+  YGNodeStyleSetHeight(root_child1_child3, 10);
+  YGNodeInsertChild(root_child1, root_child1_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child1_child3));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_top2) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root_child1, YGEdgeTop, 5);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_double_nested_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 50);
+  YGNodeStyleSetHeight(root_child0_child0, 20);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 15);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 5);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child1_child0, YGEdgeLeft, 1);
+  YGNodeStyleSetMargin(root_child1_child0, YGEdgeTop, 1);
+  YGNodeStyleSetMargin(root_child1_child0, YGEdgeRight, 1);
+  YGNodeStyleSetMargin(root_child1_child0, YGEdgeBottom, 1);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(44, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(1, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(1, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(44, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(-1, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(1, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_child_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 5);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 5);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 5);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 5);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root_child1, YGEdgeLeft, 5);
+  YGNodeStyleSetPadding(root_child1, YGEdgeTop, 5);
+  YGNodeStyleSetPadding(root_child1, YGEdgeRight, 5);
+  YGNodeStyleSetPadding(root_child1, YGEdgeBottom, 5);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(-5, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(-5, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_multiline) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 20);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child2_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2_child0, 50);
+  YGNodeStyleSetHeight(root_child2_child0, 10);
+  YGNodeInsertChild(root_child2, root_child2_child0, 0);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 50);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_multiline_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 20);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 40);
+  YGNodeStyleSetHeight(root_child2, 70);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child2_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2_child0, 10);
+  YGNodeStyleSetHeight(root_child2_child0, 10);
+  YGNodeInsertChild(root_child2, root_child2_child0, 0);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 20);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_multiline_column2) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 20);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 40);
+  YGNodeStyleSetHeight(root_child2, 70);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child2_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2_child0, 10);
+  YGNodeStyleSetHeight(root_child2_child0, 10);
+  YGNodeInsertChild(root_child2, root_child2_child0, 0);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 20);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_baseline_multiline_row_and_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 20);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child2_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2_child0, 50);
+  YGNodeStyleSetHeight(root_child2_child0, 10);
+  YGNodeInsertChild(root_child2, root_child2_child0, 0);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 50);
+  YGNodeStyleSetHeight(root_child3, 20);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_center_child_with_margin_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignCenter);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeRight, 10);
+  YGNodeStyleSetWidth(root_child0_child0, 52);
+  YGNodeStyleSetHeight(root_child0_child0, 52);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_flex_end_child_with_margin_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexEnd);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeRight, 10);
+  YGNodeStyleSetWidth(root_child0_child0, 52);
+  YGNodeStyleSetHeight(root_child0_child0, 52);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_center_child_without_margin_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignCenter);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 72);
+  YGNodeStyleSetHeight(root_child0_child0, 72);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_flex_end_child_without_margin_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexEnd);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 72);
+  YGNodeStyleSetHeight(root_child0_child0, 72);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_center_should_size_based_on_content) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root_child0, YGJustifyCenter);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 20);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 20);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_strech_should_size_based_on_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root_child0, YGJustifyCenter);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 20);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 20);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_flex_start_with_shrinking_children) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexStart);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0, 1);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_flex_start_with_stretching_children) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0, 1);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_flex_start_with_shrinking_children_with_stretch) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexStart);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0, 1);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignSelfTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAlignSelfTest.cpp
new file mode 100644 (file)
index 0000000..00bb7b9
--- /dev/null
@@ -0,0 +1,249 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGAlignSelfTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, align_self_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignCenter);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_self_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexEnd);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_self_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_self_flex_end_override_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexEnd);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_self_baseline) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignBaseline);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignSelf(root_child1, YGAlignBaseline);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAndroidNewsFeed.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAndroidNewsFeed.cpp
new file mode 100644 (file)
index 0000000..fb3f073
--- /dev/null
@@ -0,0 +1,445 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGAndroidNewsFeed.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, android_news_feed) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetWidth(root, 1080);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root_child0_child0, YGAlignStretch);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root_child0_child0_child0, YGAlignStretch);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child0_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root_child0_child0_child0_child0, YGAlignStretch);
+  YGNodeStyleSetAlignItems(root_child0_child0_child0_child0, YGAlignFlexStart);
+  YGNodeStyleSetMargin(root_child0_child0_child0_child0, YGEdgeStart, 36);
+  YGNodeStyleSetMargin(root_child0_child0_child0_child0, YGEdgeTop, 24);
+  YGNodeInsertChild(
+      root_child0_child0_child0, root_child0_child0_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0_child0_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child0_child0_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child0_child0_child0, YGAlignStretch);
+  YGNodeInsertChild(
+      root_child0_child0_child0_child0,
+      root_child0_child0_child0_child0_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child0_child0_child0_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child0_child0_child0_child0, YGAlignStretch);
+  YGNodeStyleSetWidth(root_child0_child0_child0_child0_child0_child0, 120);
+  YGNodeStyleSetHeight(root_child0_child0_child0_child0_child0_child0, 120);
+  YGNodeInsertChild(
+      root_child0_child0_child0_child0_child0,
+      root_child0_child0_child0_child0_child0_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child0_child0_child1 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child0_child0_child1, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0_child0_child1, 1);
+  YGNodeStyleSetMargin(
+      root_child0_child0_child0_child0_child1, YGEdgeRight, 36);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child0_child0_child1, YGEdgeLeft, 36);
+  YGNodeStyleSetPadding(root_child0_child0_child0_child0_child1, YGEdgeTop, 21);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child0_child0_child1, YGEdgeRight, 36);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child0_child0_child1, YGEdgeBottom, 18);
+  YGNodeInsertChild(
+      root_child0_child0_child0_child0,
+      root_child0_child0_child0_child0_child1,
+      1);
+
+  const YGNodeRef root_child0_child0_child0_child0_child1_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child0_child0_child1_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child0_child0_child1_child0, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0_child0_child1_child0, 1);
+  YGNodeInsertChild(
+      root_child0_child0_child0_child0_child1,
+      root_child0_child0_child0_child0_child1_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child0_child0_child1_child1 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child0_child0_child1_child1, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0_child0_child1_child1, 1);
+  YGNodeInsertChild(
+      root_child0_child0_child0_child0_child1,
+      root_child0_child0_child0_child0_child1_child1,
+      1);
+
+  const YGNodeRef root_child0_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(root_child0_child0_child1, YGAlignStretch);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child1, 1);
+
+  const YGNodeRef root_child0_child0_child1_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child1_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root_child0_child0_child1_child0, YGAlignStretch);
+  YGNodeStyleSetAlignItems(root_child0_child0_child1_child0, YGAlignFlexStart);
+  YGNodeStyleSetMargin(root_child0_child0_child1_child0, YGEdgeStart, 174);
+  YGNodeStyleSetMargin(root_child0_child0_child1_child0, YGEdgeTop, 24);
+  YGNodeInsertChild(
+      root_child0_child0_child1, root_child0_child0_child1_child0, 0);
+
+  const YGNodeRef root_child0_child0_child1_child0_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child1_child0_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child1_child0_child0, YGAlignStretch);
+  YGNodeInsertChild(
+      root_child0_child0_child1_child0,
+      root_child0_child0_child1_child0_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child1_child0_child0_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child1_child0_child0_child0, YGAlignStretch);
+  YGNodeStyleSetWidth(root_child0_child0_child1_child0_child0_child0, 72);
+  YGNodeStyleSetHeight(root_child0_child0_child1_child0_child0_child0, 72);
+  YGNodeInsertChild(
+      root_child0_child0_child1_child0_child0,
+      root_child0_child0_child1_child0_child0_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child1_child0_child1 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child1_child0_child1, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child1_child0_child1, 1);
+  YGNodeStyleSetMargin(
+      root_child0_child0_child1_child0_child1, YGEdgeRight, 36);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child1_child0_child1, YGEdgeLeft, 36);
+  YGNodeStyleSetPadding(root_child0_child0_child1_child0_child1, YGEdgeTop, 21);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child1_child0_child1, YGEdgeRight, 36);
+  YGNodeStyleSetPadding(
+      root_child0_child0_child1_child0_child1, YGEdgeBottom, 18);
+  YGNodeInsertChild(
+      root_child0_child0_child1_child0,
+      root_child0_child0_child1_child0_child1,
+      1);
+
+  const YGNodeRef root_child0_child0_child1_child0_child1_child0 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(
+      root_child0_child0_child1_child0_child1_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child1_child0_child1_child0, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child1_child0_child1_child0, 1);
+  YGNodeInsertChild(
+      root_child0_child0_child1_child0_child1,
+      root_child0_child0_child1_child0_child1_child0,
+      0);
+
+  const YGNodeRef root_child0_child0_child1_child0_child1_child1 =
+      YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignContent(
+      root_child0_child0_child1_child0_child1_child1, YGAlignStretch);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child1_child0_child1_child1, 1);
+  YGNodeInsertChild(
+      root_child0_child0_child1_child0_child1,
+      root_child0_child0_child1_child0_child1_child1,
+      1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(144, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetLeft(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetTop(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(1044, YGNodeLayoutGetWidth(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120,
+      YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120,
+      YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      120, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      39, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(144, YGNodeLayoutGetTop(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(96, YGNodeLayoutGetHeight(root_child0_child0_child1));
+
+  ASSERT_FLOAT_EQ(174, YGNodeLayoutGetLeft(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetTop(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(906, YGNodeLayoutGetWidth(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72,
+      YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      39, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(144, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetTop(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(1044, YGNodeLayoutGetWidth(root_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      924, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120,
+      YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      120,
+      YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      816, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1));
+  ASSERT_FLOAT_EQ(
+      39, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child0_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child0_child0_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(144, YGNodeLayoutGetTop(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(96, YGNodeLayoutGetHeight(root_child0_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetTop(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(906, YGNodeLayoutGetWidth(root_child0_child0_child1_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      834, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child0_child0));
+  ASSERT_FLOAT_EQ(
+      72,
+      YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(
+      726, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      72, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1));
+  ASSERT_FLOAT_EQ(
+      39, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1_child0));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1_child0));
+
+  ASSERT_FLOAT_EQ(
+      36, YGNodeLayoutGetLeft(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      21, YGNodeLayoutGetTop(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetWidth(root_child0_child0_child1_child0_child1_child1));
+  ASSERT_FLOAT_EQ(
+      0, YGNodeLayoutGetHeight(root_child0_child0_child1_child0_child1_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGAspectRatioTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGAspectRatioTest.cpp
new file mode 100644 (file)
index 0000000..c49133e
--- /dev/null
@@ -0,0 +1,898 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+static YGSize _measure_for_aspect_ratio(YGNodeRef node,
+                                                               float width,
+                                                               YGMeasureMode widthMode,
+                                                               float height,
+                                                               YGMeasureMode heightMode) {
+  return YGSize{
+      .width = widthMode == YGMeasureModeExactly ? width : 50,
+      .height = heightMode == YGMeasureModeExactly ? height : 50,
+  };
+}
+
+TEST(YogaTest, aspect_ratio_cross_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_main_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_both_dimensions_defined_row) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_both_dimensions_defined_column) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_align_stretch) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_flex_grow) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_flex_shrink) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 150);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_flex_shrink_2) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeightPercent(root_child0, 100);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetHeightPercent(root_child1, 100);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetAspectRatio(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_basis) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_absolute_layout_width_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 0);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 0);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_absolute_layout_height_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 0);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 0);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_with_max_cross_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetMaxWidth(root_child0, 40);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_with_max_main_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetMaxHeight(root_child0, 40);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_with_min_cross_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 30);
+  YGNodeStyleSetMinWidth(root_child0, 40);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(30, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_with_min_main_defined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetMinHeight(root_child0, 40);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_double_cross) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 2);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_half_cross) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeStyleSetAspectRatio(root_child0, 0.5);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_double_main) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 0.5);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_half_main) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetAspectRatio(root_child0, 2);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_with_measure_func) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setMeasureFunc(_measure_for_aspect_ratio);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_width_height_flex_grow_row) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_width_height_flex_grow_column) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_height_as_flex_basis) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child1, 100);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetAspectRatio(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(75, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_EQ(125, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_EQ(125, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_width_as_flex_basis) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 100);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetAspectRatio(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(75, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_EQ(125, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_EQ(125, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_overrides_flex_grow_row) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 0.5);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_overrides_flex_grow_column) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetAspectRatio(root_child0, 2);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_left_right_absolute) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_top_bottom_absolute) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetPosition(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_width_overrides_align_stretch_row) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_height_overrides_align_stretch_column) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_allow_child_overflow_parent_size) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 4);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_defined_main_with_margin) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_defined_cross_with_margin) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_defined_cross_with_main_margin) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetAspectRatio(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_should_prefer_explicit_height) {
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetUseWebDefaults(config, true);
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionColumn);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionColumn);
+  YGNodeStyleSetHeight(root_child0_child0, 100);
+  YGNodeStyleSetAspectRatio(root_child0_child0, 2);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, 200, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_should_prefer_explicit_width) {
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetUseWebDefaults(config, true);
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root_child0_child0, 100);
+  YGNodeStyleSetAspectRatio(root_child0_child0, 0.5);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, aspect_ratio_should_prefer_flexed_dimension) {
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetUseWebDefaults(config, true);
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionColumn);
+  YGNodeStyleSetAspectRatio(root_child0, 2);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAspectRatio(root_child0_child0, 4);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGBaselineFuncTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGBaselineFuncTest.cpp
new file mode 100644 (file)
index 0000000..c8d1ff1
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+static float _baseline(YGNodeRef node, const float width, const float height) {
+  float* baseline = (float*)node->getContext();
+  return *baseline;
+}
+
+TEST(YogaTest, align_baseline_customer_func) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignBaseline);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  float baselineValue = 10;
+  const YGNodeRef root_child1_child0 = YGNodeNew();
+  root_child1_child0->setContext(&baselineValue);
+  YGNodeStyleSetWidth(root_child1_child0, 50);
+  root_child1_child0->setBaseLineFunc(_baseline);
+  YGNodeStyleSetHeight(root_child1_child0, 20);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1_child0));
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGBorderTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGBorderTest.cpp
new file mode 100644 (file)
index 0000000..d4e6376
--- /dev/null
@@ -0,0 +1,212 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGBorderTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, border_no_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetBorder(root, YGEdgeLeft, 10);
+  YGNodeStyleSetBorder(root, YGEdgeTop, 10);
+  YGNodeStyleSetBorder(root, YGEdgeRight, 10);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 10);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, border_container_match_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetBorder(root, YGEdgeLeft, 10);
+  YGNodeStyleSetBorder(root, YGEdgeTop, 10);
+  YGNodeStyleSetBorder(root, YGEdgeRight, 10);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 10);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, border_flex_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetBorder(root, YGEdgeLeft, 10);
+  YGNodeStyleSetBorder(root, YGEdgeTop, 10);
+  YGNodeStyleSetBorder(root, YGEdgeRight, 10);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, border_stretch_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetBorder(root, YGEdgeLeft, 10);
+  YGNodeStyleSetBorder(root, YGEdgeTop, 10);
+  YGNodeStyleSetBorder(root, YGEdgeRight, 10);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, border_center_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetBorder(root, YGEdgeStart, 10);
+  YGNodeStyleSetBorder(root, YGEdgeEnd, 20);
+  YGNodeStyleSetBorder(root, YGEdgeBottom, 20);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGComputedMarginTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGComputedMarginTest.cpp
new file mode 100644 (file)
index 0000000..9cbbe4e
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, computed_layout_margin) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+  YGNodeStyleSetMarginPercent(root, YGEdgeStart, 10);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetMargin(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeRight));
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetMargin(root, YGEdgeRight));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGComputedPaddingTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGComputedPaddingTest.cpp
new file mode 100644 (file)
index 0000000..bf31fe7
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, computed_layout_padding) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+  YGNodeStyleSetPaddingPercent(root, YGEdgeStart, 10);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetPadding(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeRight));
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetPadding(root, YGEdgeRight));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGDefaultValuesTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGDefaultValuesTest.cpp
new file mode 100644 (file)
index 0000000..ca14386
--- /dev/null
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, assert_default_values) {
+  const YGNodeRef root = YGNodeNew();
+
+  ASSERT_EQ(0, YGNodeGetChildCount(root));
+  ASSERT_EQ(NULL, YGNodeGetChild(root, 1));
+
+  ASSERT_EQ(YGDirectionInherit, YGNodeStyleGetDirection(root));
+  ASSERT_EQ(YGFlexDirectionColumn, YGNodeStyleGetFlexDirection(root));
+  ASSERT_EQ(YGJustifyFlexStart, YGNodeStyleGetJustifyContent(root));
+  ASSERT_EQ(YGAlignFlexStart, YGNodeStyleGetAlignContent(root));
+  ASSERT_EQ(YGAlignStretch, YGNodeStyleGetAlignItems(root));
+  ASSERT_EQ(YGAlignAuto, YGNodeStyleGetAlignSelf(root));
+  ASSERT_EQ(YGPositionTypeRelative, YGNodeStyleGetPositionType(root));
+  ASSERT_EQ(YGWrapNoWrap, YGNodeStyleGetFlexWrap(root));
+  ASSERT_EQ(YGOverflowVisible, YGNodeStyleGetOverflow(root));
+  ASSERT_FLOAT_EQ(0, YGNodeStyleGetFlexGrow(root));
+  ASSERT_FLOAT_EQ(0, YGNodeStyleGetFlexShrink(root));
+  ASSERT_EQ(YGNodeStyleGetFlexBasis(root).unit, YGUnitAuto);
+
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeLeft).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeTop).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeRight).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeBottom).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeStart).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPosition(root, YGEdgeEnd).unit, YGUnitUndefined);
+
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeLeft).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeTop).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeRight).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeBottom).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeStart).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMargin(root, YGEdgeEnd).unit, YGUnitUndefined);
+
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeLeft).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeTop).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeRight).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeBottom).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeStart).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetPadding(root, YGEdgeEnd).unit, YGUnitUndefined);
+
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeLeft)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeTop)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeRight)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeBottom)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeStart)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeStyleGetBorder(root, YGEdgeEnd)));
+
+  ASSERT_EQ(YGNodeStyleGetWidth(root).unit, YGUnitAuto);
+  ASSERT_EQ(YGNodeStyleGetHeight(root).unit, YGUnitAuto);
+  ASSERT_EQ(YGNodeStyleGetMinWidth(root).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMinHeight(root).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMaxWidth(root).unit, YGUnitUndefined);
+  ASSERT_EQ(YGNodeStyleGetMaxHeight(root).unit, YGUnitUndefined);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetRight(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetBottom(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeTop));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeRight));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(root, YGEdgeBottom));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeTop));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeRight));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(root, YGEdgeBottom));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetBorder(root, YGEdgeLeft));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetBorder(root, YGEdgeTop));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetBorder(root, YGEdgeRight));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetBorder(root, YGEdgeBottom));
+
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeLayoutGetWidth(root)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeLayoutGetHeight(root)));
+  ASSERT_EQ(YGDirectionInherit, YGNodeLayoutGetDirection(root));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, assert_webdefault_values) {
+  YGConfig *config = YGConfigNew();
+  YGConfigSetUseWebDefaults(config, true);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  ASSERT_EQ(YGFlexDirectionRow, YGNodeStyleGetFlexDirection(root));
+  ASSERT_EQ(YGAlignStretch, YGNodeStyleGetAlignContent(root));
+  ASSERT_FLOAT_EQ(1.0f, YGNodeStyleGetFlexShrink(root));
+
+  YGNodeFreeRecursive(root);
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, assert_webdefault_values_reset) {
+  YGConfig *config = YGConfigNew();
+  YGConfigSetUseWebDefaults(config, true);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeReset(root);
+
+  ASSERT_EQ(YGFlexDirectionRow, YGNodeStyleGetFlexDirection(root));
+  ASSERT_EQ(YGAlignStretch, YGNodeStyleGetAlignContent(root));
+  ASSERT_FLOAT_EQ(1.0f, YGNodeStyleGetFlexShrink(root));
+
+  YGNodeFreeRecursive(root);
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, assert_legacy_stretch_behaviour) {
+  YGConfig *config = YGConfigNew();
+  YGConfigSetUseLegacyStretchBehaviour(config, true);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexStart);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0_child0, 1);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGDimensionTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGDimensionTest.cpp
new file mode 100644 (file)
index 0000000..42fc123
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGDimensionTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, wrap_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_grandchild) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 100);
+  YGNodeStyleSetHeight(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGDirtiedTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGDirtiedTest.cpp
new file mode 100644 (file)
index 0000000..bb0c05d
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+
+static void _dirtied(YGNodeRef node) {
+  int* dirtiedCount = (int*)node->getContext();
+  (*dirtiedCount)++;
+}
+
+TEST(YogaTest, dirtied) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  int dirtiedCount = 0;
+  root->setContext(&dirtiedCount);
+  root->setDirtiedFunc(_dirtied);
+
+  ASSERT_EQ(0, dirtiedCount);
+
+  // `_dirtied` MUST be called in case of explicit dirtying.
+  root->setDirty(true);
+  ASSERT_EQ(1, dirtiedCount);
+
+  // `_dirtied` MUST be called ONCE.
+  root->setDirty(true);
+  ASSERT_EQ(1, dirtiedCount);
+}
+
+TEST(YogaTest, dirtied_propagation) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  int dirtiedCount = 0;
+  root->setContext(&dirtiedCount);
+  root->setDirtiedFunc(_dirtied);
+
+  ASSERT_EQ(0, dirtiedCount);
+
+  // `_dirtied` MUST be called for the first time.
+  root_child0->markDirtyAndPropogate();
+  ASSERT_EQ(1, dirtiedCount);
+
+  // `_dirtied` must NOT be called for the second time.
+  root_child0->markDirtyAndPropogate();
+  ASSERT_EQ(1, dirtiedCount);
+}
+
+TEST(YogaTest, dirtied_hierarchy) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  int dirtiedCount = 0;
+  root_child0->setContext(&dirtiedCount);
+  root_child0->setDirtiedFunc(_dirtied);
+
+  ASSERT_EQ(0, dirtiedCount);
+
+  // `_dirtied` must NOT be called for descendants.
+  root->markDirtyAndPropogate();
+  ASSERT_EQ(0, dirtiedCount);
+
+  // `_dirtied` must NOT be called for the sibling node.
+  root_child1->markDirtyAndPropogate();
+  ASSERT_EQ(0, dirtiedCount);
+
+  // `_dirtied` MUST be called in case of explicit dirtying.
+  root_child0->markDirtyAndPropogate();
+  ASSERT_EQ(1, dirtiedCount);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGDirtyMarkingTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGDirtyMarkingTest.cpp
new file mode 100644 (file)
index 0000000..d951f53
--- /dev/null
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+
+TEST(YogaTest, dirty_propagation) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeStyleSetWidth(root_child0, 20);
+
+  EXPECT_TRUE(root_child0->isDirty());
+  EXPECT_FALSE(root_child1->isDirty());
+  EXPECT_TRUE(root->isDirty());
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  EXPECT_FALSE(root_child0->isDirty());
+  EXPECT_FALSE(root_child1->isDirty());
+  EXPECT_FALSE(root->isDirty());
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dirty_propagation_only_if_prop_changed) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeStyleSetWidth(root_child0, 50);
+
+  EXPECT_FALSE(root_child0->isDirty());
+  EXPECT_FALSE(root_child1->isDirty());
+  EXPECT_FALSE(root->isDirty());
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dirty_mark_all_children_as_dirty_when_display_changes) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(child0, 1);
+  const YGNodeRef child1 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(child1, 1);
+
+  const YGNodeRef child1_child0 = YGNodeNew();
+  const YGNodeRef child1_child0_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(child1_child0_child0, 8);
+  YGNodeStyleSetHeight(child1_child0_child0, 16);
+
+  YGNodeInsertChild(child1_child0, child1_child0_child0, 0);
+
+  YGNodeInsertChild(child1, child1_child0, 0);
+  YGNodeInsertChild(root, child0, 0);
+  YGNodeInsertChild(root, child1, 0);
+
+  YGNodeStyleSetDisplay(child0, YGDisplayFlex);
+  YGNodeStyleSetDisplay(child1, YGDisplayNone);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(child1_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(child1_child0_child0));
+
+  YGNodeStyleSetDisplay(child0, YGDisplayNone);
+  YGNodeStyleSetDisplay(child1, YGDisplayFlex);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(8, YGNodeLayoutGetWidth(child1_child0_child0));
+  ASSERT_FLOAT_EQ(16, YGNodeLayoutGetHeight(child1_child0_child0));
+
+  YGNodeStyleSetDisplay(child0, YGDisplayFlex);
+  YGNodeStyleSetDisplay(child1, YGDisplayNone);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(child1_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(child1_child0_child0));
+
+  YGNodeStyleSetDisplay(child0, YGDisplayNone);
+  YGNodeStyleSetDisplay(child1, YGDisplayFlex);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(8, YGNodeLayoutGetWidth(child1_child0_child0));
+  ASSERT_FLOAT_EQ(16, YGNodeLayoutGetHeight(child1_child0_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dirty_node_only_if_children_are_actually_removed) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef child0 = YGNodeNew();
+  YGNodeStyleSetWidth(child0, 50);
+  YGNodeStyleSetHeight(child0, 25);
+  YGNodeInsertChild(root, child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  const YGNodeRef child1 = YGNodeNew();
+  YGNodeRemoveChild(root, child1);
+  EXPECT_FALSE(root->isDirty());
+  YGNodeFree(child1);
+
+  YGNodeRemoveChild(root, child0);
+  EXPECT_TRUE(root->isDirty());
+  YGNodeFree(child0);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dirty_node_only_if_undefined_values_gets_set_to_undefined) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+  YGNodeStyleSetMinWidth(root, YGUndefined);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  EXPECT_FALSE(root->isDirty());
+
+  YGNodeStyleSetMinWidth(root, YGUndefined);
+
+  EXPECT_FALSE(root->isDirty());
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGDisplayTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGDisplayTest.cpp
new file mode 100644 (file)
index 0000000..45256ac
--- /dev/null
@@ -0,0 +1,332 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGDisplayTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, display_none) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetDisplay(root_child1, YGDisplayNone);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, display_none_fixed_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 20);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeStyleSetDisplay(root_child1, YGDisplayNone);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, display_none_with_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeStyleSetDisplay(root_child0, YGDisplayNone);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, display_none_with_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 0);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetDisplay(root_child1, YGDisplayNone);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child1_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1_child0, 0);
+  YGNodeStyleSetWidth(root_child1_child0, 20);
+  YGNodeStyleSetMinWidth(root_child1_child0, 0);
+  YGNodeStyleSetMinHeight(root_child1_child0, 0);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetFlexShrink(root_child2, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child2, 0);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, display_none_with_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetPosition(root_child1, YGEdgeTop, 10);
+  YGNodeStyleSetDisplay(root_child1, YGDisplayNone);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGEdgeTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGEdgeTest.cpp
new file mode 100644 (file)
index 0000000..02de146
--- /dev/null
@@ -0,0 +1,161 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, start_overrides) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 20);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetRight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetRight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, end_overrides) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeEnd, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 20);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetRight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetRight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, horizontal_overridden) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeHorizontal, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetRight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, vertical_overridden) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeVertical, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetBottom(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, horizontal_overrides_all) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeHorizontal, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeAll, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetRight(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetBottom(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, vertical_overrides_all) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeVertical, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeAll, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetRight(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetBottom(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, all_overridden) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeAll, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetRight(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetBottom(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexDirectionTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexDirectionTest.cpp
new file mode 100644 (file)
index 0000000..93e0942
--- /dev/null
@@ -0,0 +1,415 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGFlexDirectionTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, flex_direction_column_no_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_direction_row_no_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_direction_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_direction_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_direction_column_reverse) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumnReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_direction_row_reverse) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRowReverse);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexTest.cpp
new file mode 100644 (file)
index 0000000..e1a8ba8
--- /dev/null
@@ -0,0 +1,491 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGFlexTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, flex_basis_flex_grow_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_basis_flex_grow_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_basis_flex_shrink_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_basis_flex_shrink_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_shrink_to_zero) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root, 75);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_basis_overrides_main_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_shrink_at_most) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_less_than_factor_one) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 0.2f);
+  YGNodeStyleSetFlexBasis(root_child0, 40);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 0.2f);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 0.4f);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(132, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(132, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(224, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(184, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(132, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(132, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(224, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(184, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexWrapTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGFlexWrapTest.cpp
new file mode 100644 (file)
index 0000000..e8e5458
--- /dev/null
@@ -0,0 +1,1735 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGFlexWrapTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, wrap_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 30);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 30);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 30);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 30);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 30);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 30);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_row_align_items_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexEnd);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 30);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_row_align_items_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 30);
+  YGNodeInsertChild(root, root_child3, 3);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child3));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_wrap_children_with_min_main_overriding_flex_basis) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetMinWidth(root_child0, 55);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1, 50);
+  YGNodeStyleSetMinWidth(root_child1, 55);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_wrap_wrap_to_child_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root_child0, YGAlignFlexStart);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 100);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 100);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 100);
+  YGNodeStyleSetHeight(root_child1, 100);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_wrap_align_stretch_fits_one_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 150);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_row_align_content_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_row_align_content_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignCenter);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_row_single_line_different_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 300);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(270, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(240, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(210, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_row_align_content_stretch) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignStretch);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_row_align_content_space_around) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignContent(root, YGAlignSpaceAround);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_reverse_column_fixed_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrapReverse);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 30);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 30);
+  YGNodeStyleSetHeight(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 30);
+  YGNodeStyleSetHeight(root_child2, 30);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child3, 30);
+  YGNodeStyleSetHeight(root_child3, 40);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child4, 30);
+  YGNodeStyleSetHeight(root_child4, 50);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(170, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(170, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(170, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(170, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrapped_row_within_align_items_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 150);
+  YGNodeStyleSetHeight(root_child0_child0, 80);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1, 80);
+  YGNodeStyleSetHeight(root_child0_child1, 80);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrapped_row_within_align_items_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 150);
+  YGNodeStyleSetHeight(root_child0_child0, 80);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1, 80);
+  YGNodeStyleSetHeight(root_child0_child1, 80);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrapped_row_within_align_items_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexEnd);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 150);
+  YGNodeStyleSetHeight(root_child0_child0, 80);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1, 80);
+  YGNodeStyleSetHeight(root_child0_child1, 80);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrapped_column_max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignContent(root, YGAlignCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 700);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 500);
+  YGNodeStyleSetMaxHeight(root_child0, 200);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child1, YGEdgeLeft, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeTop, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeRight, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeBottom, 20);
+  YGNodeStyleSetWidth(root_child1, 200);
+  YGNodeStyleSetHeight(root_child1, 200);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 100);
+  YGNodeStyleSetHeight(root_child2, 100);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(700, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(420, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(700, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(350, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrapped_column_max_height_flex) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignContent(root, YGAlignCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetFlexWrap(root, YGWrapWrap);
+  YGNodeStyleSetWidth(root, 700);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 0);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 500);
+  YGNodeStyleSetMaxHeight(root_child0, 200);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexShrink(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 0);
+  YGNodeStyleSetMargin(root_child1, YGEdgeLeft, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeTop, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeRight, 20);
+  YGNodeStyleSetMargin(root_child1, YGEdgeBottom, 20);
+  YGNodeStyleSetWidth(root_child1, 200);
+  YGNodeStyleSetHeight(root_child1, 200);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 100);
+  YGNodeStyleSetHeight(root_child2, 100);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(700, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(700, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_nodes_with_content_sizing_overflowing_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeStyleSetWidth(root_child0, 85);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 40);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 40);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0_child1, YGEdgeRight, 10);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+
+  const YGNodeRef root_child0_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1_child0, 40);
+  YGNodeStyleSetHeight(root_child0_child1_child0, 40);
+  YGNodeInsertChild(root_child0_child1, root_child0_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(85, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(415, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(85, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, wrap_nodes_with_content_sizing_margin_cross) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
+  YGNodeStyleSetWidth(root_child0, 70);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 40);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 40);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0_child1, YGEdgeTop, 10);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+
+  const YGNodeRef root_child0_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1_child0, 40);
+  YGNodeStyleSetHeight(root_child0_child1_child0, 40);
+  YGNodeInsertChild(root_child0_child1, root_child0_child1_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(430, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(70, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child0_child1_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0_child1_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGHadOverflowTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGHadOverflowTest.cpp
new file mode 100644 (file)
index 0000000..39cb20a
--- /dev/null
@@ -0,0 +1,127 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+using namespace ::testing;
+
+class YogaTest_HadOverflowTests : public testing::Test {
+protected:
+  YogaTest_HadOverflowTests() {
+    config = YGConfigNew();
+    root = YGNodeNewWithConfig(config);
+    YGNodeStyleSetWidth(root, 200);
+    YGNodeStyleSetHeight(root, 100);
+    YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+    YGNodeStyleSetFlexWrap(root, YGWrapNoWrap);
+  }
+
+  ~YogaTest_HadOverflowTests() {
+    YGNodeFreeRecursive(root);
+    YGConfigFree(config);
+  }
+
+  YGNodeRef root;
+  YGConfigRef config;
+};
+
+TEST_F(YogaTest_HadOverflowTests, children_overflow_no_wrap_and_no_flex_children) {
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child0, 80);
+  YGNodeStyleSetHeight(child0, 40);
+  YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(child0, YGEdgeBottom, 15);
+  YGNodeInsertChild(root, child0, 0);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1, 80);
+  YGNodeStyleSetHeight(child1, 40);
+  YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
+  YGNodeInsertChild(root, child1, 1);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
+}
+
+TEST_F(YogaTest_HadOverflowTests, spacing_overflow_no_wrap_and_no_flex_children) {
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child0, 80);
+  YGNodeStyleSetHeight(child0, 40);
+  YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, child0, 0);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1, 80);
+  YGNodeStyleSetHeight(child1, 40);
+  YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
+  YGNodeInsertChild(root, child1, 1);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
+}
+
+TEST_F(YogaTest_HadOverflowTests, no_overflow_no_wrap_and_flex_children) {
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child0, 80);
+  YGNodeStyleSetHeight(child0, 40);
+  YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, child0, 0);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1, 80);
+  YGNodeStyleSetHeight(child1, 40);
+  YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
+  YGNodeStyleSetFlexShrink(child1, 1);
+  YGNodeInsertChild(root, child1, 1);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_FALSE(YGNodeLayoutGetHadOverflow(root));
+}
+
+TEST_F(YogaTest_HadOverflowTests, hadOverflow_gets_reset_if_not_logger_valid) {
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child0, 80);
+  YGNodeStyleSetHeight(child0, 40);
+  YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, child0, 0);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1, 80);
+  YGNodeStyleSetHeight(child1, 40);
+  YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
+  YGNodeInsertChild(root, child1, 1);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
+
+  YGNodeStyleSetFlexShrink(child1, 1);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_FALSE(YGNodeLayoutGetHadOverflow(root));
+}
+
+TEST_F(YogaTest_HadOverflowTests, spacing_overflow_in_nested_nodes) {
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child0, 80);
+  YGNodeStyleSetHeight(child0, 40);
+  YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, child0, 0);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1, 80);
+  YGNodeStyleSetHeight(child1, 40);
+  YGNodeInsertChild(root, child1, 1);
+  const YGNodeRef child1_1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(child1_1, 80);
+  YGNodeStyleSetHeight(child1_1, 40);
+  YGNodeStyleSetMargin(child1_1, YGEdgeBottom, 5);
+  YGNodeInsertChild(child1, child1_1, 0);
+
+  YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
+
+  ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGInfiniteHeightTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGInfiniteHeightTest.cpp
new file mode 100644 (file)
index 0000000..a557b3d
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+// This test isn't correct from the Flexbox standard standpoint,
+// because percentages are calculated with parent constraints.
+// However, we need to make sure we fail gracefully in this case, not returning NaN
+TEST(YogaTest, percent_absolute_position_infinite_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 300);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 300);
+  YGNodeStyleSetHeight(root_child0, 300);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child1, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child1, YGEdgeLeft, 20);
+  YGNodeStyleSetPositionPercent(root_child1, YGEdgeTop, 20);
+  YGNodeStyleSetWidthPercent(root_child1, 20);
+  YGNodeStyleSetHeightPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGJustifyContentTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGJustifyContentTest.cpp
new file mode 100644 (file)
index 0000000..e5d4216
--- /dev/null
@@ -0,0 +1,999 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGJustifyContentTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, justify_content_row_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(82, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(82, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(56, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(56, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_space_between) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceBetween);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_space_around) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceAround);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_flex_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_flex_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(82, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(82, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(56, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(56, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_space_between) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceBetween);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_space_around) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceAround);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_min_width_and_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetMargin(root, YGEdgeLeft, 100);
+  YGNodeStyleSetMinWidth(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_max_width_and_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetMargin(root, YGEdgeLeft, 100);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMaxWidth(root, 80);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_min_height_and_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 100);
+  YGNodeStyleSetMinHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_colunn_max_height_and_margin) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 100);
+  YGNodeStyleSetHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 80);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 20);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_column_space_evenly) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceEvenly);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(18, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(74, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(18, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(74, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_row_space_evenly) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceEvenly);
+  YGNodeStyleSetWidth(root, 102);
+  YGNodeStyleSetHeight(root, 102);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(26, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(51, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(77, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(102, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(77, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(51, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(26, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGLayoutDiffingTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGLayoutDiffingTest.cpp
new file mode 100644 (file)
index 0000000..a04e87d
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, assert_layout_trees_are_same) {
+  YGConfig* config = YGConfigNew();
+  YGConfigSetUseLegacyStretchBehaviour(config, true);
+  const YGNodeRef root1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root1, 500);
+  YGNodeStyleSetHeight(root1, 500);
+
+  const YGNodeRef root1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root1_child0, YGAlignFlexStart);
+  YGNodeInsertChild(root1, root1_child0, 0);
+
+  const YGNodeRef root1_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root1_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root1_child0_child0, 1);
+  YGNodeInsertChild(root1_child0, root1_child0_child0, 0);
+
+  const YGNodeRef root1_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root1_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root1_child0_child0_child0, 1);
+  YGNodeInsertChild(root1_child0_child0, root1_child0_child0_child0, 0);
+
+  const int32_t cal1_configInstanceCount = YGConfigGetInstanceCount();
+  const int32_t cal1_nodeInstanceCount = YGNodeGetInstanceCount();
+
+  YGNodeCalculateLayout(root1, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(YGConfigGetInstanceCount(), cal1_configInstanceCount);
+  ASSERT_EQ(YGNodeGetInstanceCount(), cal1_nodeInstanceCount);
+
+  const YGNodeRef root2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root2, 500);
+  YGNodeStyleSetHeight(root2, 500);
+
+  const YGNodeRef root2_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root2_child0, YGAlignFlexStart);
+  YGNodeInsertChild(root2, root2_child0, 0);
+
+  const YGNodeRef root2_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root2_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root2_child0_child0, 1);
+  YGNodeInsertChild(root2_child0, root2_child0_child0, 0);
+
+  const YGNodeRef root2_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root2_child0_child0_child0, 1);
+  YGNodeStyleSetFlexShrink(root2_child0_child0_child0, 1);
+  YGNodeInsertChild(root2_child0_child0, root2_child0_child0_child0, 0);
+
+  const int32_t cal2_configInstanceCount = YGConfigGetInstanceCount();
+  const int32_t cal2_nodeInstanceCount = YGNodeGetInstanceCount();
+
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(YGConfigGetInstanceCount(), cal2_configInstanceCount);
+  ASSERT_EQ(YGNodeGetInstanceCount(), cal2_nodeInstanceCount);
+
+  ASSERT_TRUE(YGNodeLayoutGetDidUseLegacyFlag(root1));
+  ASSERT_TRUE(YGNodeLayoutGetDidUseLegacyFlag(root2));
+  ASSERT_TRUE(root1->isLayoutTreeEqualToNode(*root2));
+
+  YGNodeStyleSetAlignItems(root2, YGAlignFlexEnd);
+
+  const int32_t cal3_configInstanceCount = YGConfigGetInstanceCount();
+  const int32_t cal3_nodeInstanceCount = YGNodeGetInstanceCount();
+
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(YGConfigGetInstanceCount(), cal3_configInstanceCount);
+  ASSERT_EQ(YGNodeGetInstanceCount(), cal3_nodeInstanceCount);
+
+  ASSERT_FALSE(root1->isLayoutTreeEqualToNode(*root2));
+
+  YGNodeFreeRecursive(root1);
+  YGNodeFreeRecursive(root2);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGLoggerTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGLoggerTest.cpp
new file mode 100644 (file)
index 0000000..1b84ee6
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <stdarg.h>
+#include <yoga/Yoga.h>
+
+namespace {
+char writeBuffer[4096];
+int _unmanagedLogger(const YGConfigRef config,
+                     const YGNodeRef node,
+                     YGLogLevel level,
+                     const char *format,
+                     va_list args) {
+  return vsnprintf(writeBuffer + strlen(writeBuffer),
+                   sizeof(writeBuffer) - strlen(writeBuffer),
+                   format,
+                   args);
+}
+}
+
+TEST(YogaTest, logger_default_node_should_print_no_style_info) {
+  writeBuffer[0] = '\0';
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetLogger(config, _unmanagedLogger);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR);
+  YGNodePrint(root,
+              (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren |
+                               YGPrintOptionsStyle));
+  YGConfigSetLogger(config, NULL);
+  YGNodeFree(root);
+
+  const char *expected = "<div layout=\"width: 0; height: 0; top: 0; left: 0;\" style=\"\" ></div>";
+  ASSERT_STREQ(expected, writeBuffer);
+}
+
+TEST(YogaTest, logger_node_with_percentage_absolute_position_and_margin) {
+  writeBuffer[0] = '\0';
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetLogger(config, _unmanagedLogger);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root, YGPositionTypeAbsolute);
+  YGNodeStyleSetWidthPercent(root, 50);
+  YGNodeStyleSetHeightPercent(root, 75);
+  YGNodeStyleSetFlex(root, 1);
+  YGNodeStyleSetMargin(root, YGEdgeRight, 10);
+  YGNodeStyleSetMarginAuto(root, YGEdgeLeft);
+  YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR);
+  YGNodePrint(root,
+              (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren |
+                               YGPrintOptionsStyle));
+  YGConfigSetLogger(config, NULL);
+  YGNodeFree(root);
+
+  const char *expected = "<div layout=\"width: 0; height: 0; top: 0; left: 0;\" style=\"flex: 1; "
+                         "margin-left: auto; margin-right: 10px; width: 50%; height: 75%; "
+                         "position: absolute; \" ></div>";
+  ASSERT_STREQ(expected, writeBuffer);
+}
+
+TEST(YogaTest, logger_node_with_children_should_print_indented) {
+  writeBuffer[0] = '\0';
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetLogger(config, _unmanagedLogger);
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  const YGNodeRef child0 = YGNodeNewWithConfig(config);
+  const YGNodeRef child1 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, child0, 0);
+  YGNodeInsertChild(root, child1, 1);
+  YGNodeCalculateLayout(root, YGUnitUndefined, YGUnitUndefined, YGDirectionLTR);
+  YGNodePrint(root,
+              (YGPrintOptions)(YGPrintOptionsLayout | YGPrintOptionsChildren |
+                               YGPrintOptionsStyle));
+  YGConfigSetLogger(config, NULL);
+  YGNodeFreeRecursive(root);
+
+  const char *expected = "<div layout=\"width: 0; height: 0; top: 0; left: 0;\" style=\"\" >\n  "
+                         "<div layout=\"width: 0; height: 0; top: 0; left: 0;\" style=\"\" "
+                         "></div>\n  <div layout=\"width: 0; height: 0; top: 0; left: 0;\" "
+                         "style=\"\" ></div>\n</div>";
+  ASSERT_STREQ(expected, writeBuffer);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGMarginTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGMarginTest.cpp
new file mode 100644 (file)
index 0000000..593cd2f
--- /dev/null
@@ -0,0 +1,1717 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGMarginTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, margin_start) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeEnd, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_bottom) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_and_flex_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeEnd, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_and_flex_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_and_stretch_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_and_stretch_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeStart, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeEnd, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_with_sibling_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeEnd, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_with_sibling_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(55, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_bottom) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeBottom);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_bottom_and_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeBottom);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_bottom_and_top_justify_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeBottom);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_mutiple_children_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child1, YGEdgeTop);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_mutiple_children_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child1, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_and_right_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_and_right) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_start_and_end_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeStart);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeEnd);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_start_and_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeStart);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeEnd);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_and_right_column_and_center) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_right) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_and_right_strech) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_top_and_bottom_strech) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeBottom);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_should_not_be_part_of_max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 250);
+  YGNodeStyleSetHeight(root, 250);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeStyleSetMaxHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_should_not_be_part_of_max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 250);
+  YGNodeStyleSetHeight(root, 250);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 20);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetMaxWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_right_child_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 72);
+  YGNodeStyleSetHeight(root_child0, 72);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_child_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetWidth(root_child0, 72);
+  YGNodeStyleSetHeight(root_child0, 72);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_fix_left_auto_right_child_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeRight);
+  YGNodeStyleSetWidth(root_child0, 72);
+  YGNodeStyleSetHeight(root_child0, 72);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_fix_right_child_bigger_than_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 52);
+  YGNodeStyleSetHeight(root, 52);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetWidth(root_child0, 72);
+  YGNodeStyleSetHeight(root_child0, 72);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(72, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_top_stretching_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 0);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeTop);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, margin_auto_left_stretching_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 0);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureCacheTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureCacheTest.cpp
new file mode 100644 (file)
index 0000000..91f1891
--- /dev/null
@@ -0,0 +1,176 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+static YGSize _measureMax(YGNodeRef node,
+                          float width,
+                          YGMeasureMode widthMode,
+                          float height,
+                          YGMeasureMode heightMode) {
+  int* measureCount = (int*)node->getContext();
+  (*measureCount)++;
+
+  return YGSize{
+      .width = widthMode == YGMeasureModeUndefined ? 10 : width,
+      .height = heightMode == YGMeasureModeUndefined ? 10 : height,
+  };
+}
+
+static YGSize _measureMin(YGNodeRef node,
+                          float width,
+                          YGMeasureMode widthMode,
+                          float height,
+                          YGMeasureMode heightMode) {
+  int* measureCount = (int*)node->getContext();
+  *measureCount = *measureCount + 1;
+  return YGSize{
+      .width =
+          widthMode == YGMeasureModeUndefined || (widthMode == YGMeasureModeAtMost && width > 10)
+              ? 10
+              : width,
+      .height =
+          heightMode == YGMeasureModeUndefined || (heightMode == YGMeasureModeAtMost && height > 10)
+              ? 10
+              : height,
+  };
+}
+
+static YGSize _measure_84_49(YGNodeRef node,
+                             float width,
+                             YGMeasureMode widthMode,
+                             float height,
+                             YGMeasureMode heightMode) {
+  int* measureCount = (int*)node->getContext();
+  if (measureCount) {
+    (*measureCount)++;
+  }
+
+  return YGSize{
+      .width = 84.f, .height = 49.f,
+  };
+}
+
+TEST(YogaTest, measure_once_single_flexible_child) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  int measureCount = 0;
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measureMax);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, remeasure_with_same_exact_width_larger_than_needed_height) {
+  const YGNodeRef root = YGNodeNew();
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  int measureCount = 0;
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measureMin);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+  YGNodeCalculateLayout(root, 100, 50, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, remeasure_with_same_atmost_width_larger_than_needed_height) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  int measureCount = 0;
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measureMin);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+  YGNodeCalculateLayout(root, 100, 50, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, remeasure_with_computed_width_larger_than_needed_height) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  int measureCount = 0;
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measureMin);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+  YGNodeStyleSetAlignItems(root, YGAlignStretch);
+  YGNodeCalculateLayout(root, 10, 50, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, remeasure_with_atmost_computed_width_undefined_height) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  int measureCount = 0;
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measureMin);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, YGUndefined, YGDirectionLTR);
+  YGNodeCalculateLayout(root, 10, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, remeasure_with_already_measured_value_smaller_but_still_float_equal) {
+  int measureCount = 0;
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 288.f);
+  YGNodeStyleSetHeight(root, 288.f);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetPadding(root_child0, YGEdgeAll, 2.88f);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNew();
+  root_child0_child0->setContext(&measureCount);
+  root_child0_child0->setMeasureFunc(_measure_84_49);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeFreeRecursive(root);
+
+  ASSERT_EQ(1, measureCount);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureModeTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureModeTest.cpp
new file mode 100644 (file)
index 0000000..8e52894
--- /dev/null
@@ -0,0 +1,326 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+struct _MeasureConstraint {
+  float width;
+  YGMeasureMode widthMode;
+  float height;
+  YGMeasureMode heightMode;
+};
+
+struct _MeasureConstraintList {
+  uint32_t length;
+  struct _MeasureConstraint *constraints;
+};
+
+static YGSize _measure_for_mode_test(YGNodeRef node,
+                                                        float width,
+                                                        YGMeasureMode widthMode,
+                                                        float height,
+                                                        YGMeasureMode heightMode) {
+  struct _MeasureConstraintList* constraintList =
+      (struct _MeasureConstraintList*)node->getContext();
+  struct _MeasureConstraint *constraints = constraintList->constraints;
+  uint32_t currentIndex = constraintList->length;
+  (&constraints[currentIndex])->width = width;
+  (&constraints[currentIndex])->widthMode = widthMode;
+  (&constraints[currentIndex])->height = height;
+  (&constraints[currentIndex])->heightMode = heightMode;
+  constraintList->length = currentIndex + 1;
+
+  return YGSize{
+      .width = widthMode == YGMeasureModeUndefined ? 10 : width,
+      .height = heightMode == YGMeasureModeUndefined ? 10 : width,
+  };
+}
+
+TEST(YogaTest, exactly_measure_stretched_child_column) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  //  root_child0->setContext(&constraintList);
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  //  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].width);
+  ASSERT_EQ(YGMeasureModeExactly, constraintList.constraints[0].widthMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, exactly_measure_stretched_child_row) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  //  root_child0->setContext(&constraintList);
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeExactly, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, at_most_main_axis_column) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, at_most_cross_axis_column) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].width);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].widthMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, at_most_main_axis_row) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].width);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].widthMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, at_most_cross_axis_row) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, flex_child) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(2, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].heightMode);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[1].height);
+  ASSERT_EQ(YGMeasureModeExactly, constraintList.constraints[1].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, flex_child_with_flex_basis) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 0);
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeExactly, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, overflow_scroll_column) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetOverflow(root, YGOverflowScroll);
+  YGNodeStyleSetHeight(root, 100);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].width);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].widthMode);
+
+  ASSERT_TRUE(YGFloatIsUndefined(constraintList.constraints[0].height));
+  ASSERT_EQ(YGMeasureModeUndefined, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, overflow_scroll_row) {
+  struct _MeasureConstraintList constraintList = _MeasureConstraintList{
+      .length = 0,
+      .constraints = (struct _MeasureConstraint *) malloc(10 * sizeof(struct _MeasureConstraint)),
+  };
+
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetOverflow(root, YGOverflowScroll);
+  YGNodeStyleSetHeight(root, 100);
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&constraintList);
+  root_child0->setMeasureFunc(_measure_for_mode_test);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, constraintList.length);
+
+  ASSERT_TRUE(YGFloatIsUndefined(constraintList.constraints[0].width));
+  ASSERT_EQ(YGMeasureModeUndefined, constraintList.constraints[0].widthMode);
+
+  ASSERT_FLOAT_EQ(100, constraintList.constraints[0].height);
+  ASSERT_EQ(YGMeasureModeAtMost, constraintList.constraints[0].heightMode);
+
+  free(constraintList.constraints);
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGMeasureTest.cpp
new file mode 100644 (file)
index 0000000..aea2cd5
--- /dev/null
@@ -0,0 +1,689 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+static YGSize _measure(YGNodeRef node,
+                       float width,
+                       YGMeasureMode widthMode,
+                       float height,
+                       YGMeasureMode heightMode) {
+  int* measureCount = (int*)node->getContext();
+  if (measureCount) {
+    (*measureCount)++;
+  }
+
+  return YGSize{
+      .width = 10, .height = 10,
+  };
+}
+
+static YGSize _simulate_wrapping_text(YGNodeRef node,
+                                      float width,
+                                      YGMeasureMode widthMode,
+                                      float height,
+                                      YGMeasureMode heightMode) {
+  if (widthMode == YGMeasureModeUndefined || width >= 68) {
+    return YGSize{.width = 68, .height = 16};
+  }
+
+  return YGSize{
+      .width = 50, .height = 32,
+  };
+}
+
+static YGSize _measure_assert_negative(YGNodeRef node,
+                                       float width,
+                                       YGMeasureMode widthMode,
+                                       float height,
+                                       YGMeasureMode heightMode) {
+  EXPECT_GE(width, 0);
+  EXPECT_GE(height, 0);
+
+  return YGSize{
+    .width = 0, .height = 0,
+  };
+}
+
+TEST(YogaTest, dont_measure_single_grow_shrink_child) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, measure_absolute_child_with_no_constraints) {
+  const YGNodeRef root = YGNodeNew();
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeInsertChild(root, root_child0, 0);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0_child0 = YGNodeNew();
+  YGNodeStyleSetPositionType(root_child0_child0, YGPositionTypeAbsolute);
+  root_child0_child0->setContext(&measureCount);
+  root_child0_child0->setMeasureFunc(_measure);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(1, measureCount);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dont_measure_when_min_equals_max) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetMinWidth(root_child0, 10);
+  YGNodeStyleSetMaxWidth(root_child0, 10);
+  YGNodeStyleSetMinHeight(root_child0, 10);
+  YGNodeStyleSetMaxHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, measureCount);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dont_measure_when_min_equals_max_percentages) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetMinWidthPercent(root_child0, 10);
+  YGNodeStyleSetMaxWidthPercent(root_child0, 10);
+  YGNodeStyleSetMinHeightPercent(root_child0, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, measureCount);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+
+TEST(YogaTest, measure_nodes_with_margin_auto_and_stretch) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetMarginAuto(root_child0, YGEdgeLeft);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  EXPECT_EQ(490, YGNodeLayoutGetLeft(root_child0));
+  EXPECT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  EXPECT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  EXPECT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dont_measure_when_min_equals_max_mixed_width_percent) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetMinWidthPercent(root_child0, 10);
+  YGNodeStyleSetMaxWidthPercent(root_child0, 10);
+  YGNodeStyleSetMinHeight(root_child0, 10);
+  YGNodeStyleSetMaxHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, measureCount);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, dont_measure_when_min_equals_max_mixed_height_percent) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+  YGNodeStyleSetMinWidth(root_child0, 10);
+  YGNodeStyleSetMaxWidth(root_child0, 10);
+  YGNodeStyleSetMinHeightPercent(root_child0, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, measureCount);
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, measure_enough_size_should_be_in_single_line) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexStart);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(68, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(16, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, measure_not_enough_size_should_wrap) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetWidth(root, 55);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetAlignSelf(root_child0, YGAlignFlexStart);
+  //  YGNodeSetMeasureFunc(root_child0, _simulate_wrapping_text);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(32, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, measure_zero_space_should_grow) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetHeight(root, 200);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetFlexGrow(root, 0);
+
+  int measureCount = 0;
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionColumn);
+  YGNodeStyleSetPadding(root_child0, YGEdgeAll, 100);
+  root_child0->setContext(&measureCount);
+  root_child0->setMeasureFunc(_measure);
+
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 282, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(282, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, measure_flex_direction_row_and_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 25);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 25);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 25);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 25);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  //  YGNodeSetMeasureFunc(root_child0, _simulate_wrapping_text);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_flex_direction_column_and_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetPadding(root, YGEdgeAll, 25);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  //  YGNodeSetMeasureFunc(root_child0, _simulate_wrapping_text);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(32, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(57, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_flex_direction_row_no_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  //  YGNodeSetMeasureFunc(root_child0, _simulate_wrapping_text);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_flex_direction_row_no_padding_align_items_flexstart) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(32, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_with_fixed_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetPadding(root, YGEdgeAll, 25);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_with_flex_shrink) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetPadding(root, YGEdgeAll, 25);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, measure_no_padding) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root, YGEdgeTop, 20);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_simulate_wrapping_text);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 5);
+  YGNodeStyleSetHeight(root_child1, 5);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(32, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(32, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(YogaDeathTest, cannot_add_child_to_node_with_measure_func) {
+  const YGNodeRef root = YGNodeNew();
+  root->setMeasureFunc(_measure);
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  ASSERT_DEATH(YGNodeInsertChild(root, root_child0, 0), "Cannot add child.*");
+  YGNodeFree(root_child0);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaDeathTest, cannot_add_nonnull_measure_func_to_non_leaf_node) {
+  const YGNodeRef root = YGNodeNew();
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeInsertChild(root, root_child0, 0);
+  ASSERT_DEATH(root->setMeasureFunc(_measure), "Cannot set measure function.*");
+  YGNodeFreeRecursive(root);
+}
+
+#endif
+
+TEST(YogaTest, can_nullify_measure_func_on_any_node) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeInsertChild(root, YGNodeNew(), 0);
+  root->setMeasureFunc(nullptr);
+  ASSERT_TRUE(root->getMeasure() == NULL);
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, cant_call_negative_measure) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetHeight(root, 10);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_measure_assert_negative);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeFreeRecursive(root);
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, cant_call_negative_measure_horizontal) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 10);
+  YGNodeStyleSetHeight(root, 20);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_measure_assert_negative);
+  YGNodeStyleSetMargin(root_child0, YGEdgeStart, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeFreeRecursive(root);
+  YGConfigFree(config);
+}
+
+static YGSize _measure_90_10(YGNodeRef node,
+  float width,
+  YGMeasureMode widthMode,
+  float height,
+  YGMeasureMode heightMode) {
+
+  return YGSize{
+    .width = 90, .height = 10,
+  };
+}
+
+TEST(YogaTest, percent_with_text_node) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root, YGJustifySpaceBetween);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 80);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  root_child1->setMeasureFunc(_measure_90_10);
+  YGNodeStyleSetMaxWidthPercent(root_child1, 50);
+  YGNodeStyleSetPaddingPercent(root_child1, YGEdgeTop, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(15, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGMinMaxDimensionTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGMinMaxDimensionTest.cpp
new file mode 100644 (file)
index 0000000..515bdfd
--- /dev/null
@@ -0,0 +1,1297 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGMinMaxDimensionTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMaxWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetMaxHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, min_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMinHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, min_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMinWidth(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_min_max) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, align_items_min_max) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetMinWidth(root, 100);
+  YGNodeStyleSetMaxWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 60);
+  YGNodeStyleSetHeight(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, justify_content_overflow_min_max) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 110);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 50);
+  YGNodeStyleSetHeight(root_child2, 50);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(110, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_to_min) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_in_at_most_container) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0_child0, 0);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 0);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_min_max_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetMaxWidth(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetHeight(root_child0_child0, 20);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetMaxWidth(root_child0, 300);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetHeight(root_child0_child0, 20);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_root_ignored) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root, 1);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 200);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 100);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_root_minimized) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeStyleSetMaxHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMinHeight(root_child0, 100);
+  YGNodeStyleSetMaxHeight(root_child0, 500);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0_child0, 200);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0_child1, 100);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(300, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_height_maximized) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMinHeight(root_child0, 100);
+  YGNodeStyleSetMaxHeight(root_child0, 500);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0_child0, 200);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0_child1, 100);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_min_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetMinWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_min_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMinHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_max_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetMaxWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child1, 50);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, flex_grow_within_constrained_max_column) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetMaxHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child1, 50);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, child_min_max_width_flexing) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 120);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 0);
+  YGNodeStyleSetMinWidth(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 50);
+  YGNodeStyleSetMaxWidth(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, min_width_overrides_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 50);
+  YGNodeStyleSetMinWidth(root, 100);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, max_width_overrides_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetMaxWidth(root, 100);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, min_height_overrides_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root, 50);
+  YGNodeStyleSetMinHeight(root, 100);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, max_height_overrides_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root, 200);
+  YGNodeStyleSetMaxHeight(root, 100);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, min_max_percent_no_width_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexStart);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMinWidthPercent(root_child0, 10);
+  YGNodeStyleSetMaxWidthPercent(root_child0, 10);
+  YGNodeStyleSetMinHeightPercent(root_child0, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGNodeChildTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGNodeChildTest.cpp
new file mode 100644 (file)
index 0000000..9d6bb48
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, reset_layout_when_child_removed) {
+  const YGNodeRef root = YGNodeNew();
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeRemoveChild(root, root_child0);
+
+  ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeLayoutGetWidth(root_child0)));
+  ASSERT_TRUE(YGFloatIsUndefined(YGNodeLayoutGetHeight(root_child0)));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGPaddingTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGPaddingTest.cpp
new file mode 100644 (file)
index 0000000..f0d3752
--- /dev/null
@@ -0,0 +1,258 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGPaddingTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, padding_no_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 10);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetHeight(root));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, padding_container_match_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 10);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, padding_flex_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, padding_stretch_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root, YGEdgeLeft, 10);
+  YGNodeStyleSetPadding(root, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(root, YGEdgeRight, 10);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 10);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, padding_center_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetPadding(root, YGEdgeStart, 10);
+  YGNodeStyleSetPadding(root, YGEdgeEnd, 20);
+  YGNodeStyleSetPadding(root, YGEdgeBottom, 20);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, child_with_padding_align_end) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyFlexEnd);
+  YGNodeStyleSetAlignItems(root, YGAlignFlexEnd);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPadding(root_child0, YGEdgeLeft, 20);
+  YGNodeStyleSetPadding(root_child0, YGEdgeTop, 20);
+  YGNodeStyleSetPadding(root_child0, YGEdgeRight, 20);
+  YGNodeStyleSetPadding(root_child0, YGEdgeBottom, 20);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGPercentageTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGPercentageTest.cpp
new file mode 100644 (file)
index 0000000..2be0459
--- /dev/null
@@ -0,0 +1,1194 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGPercentageTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, percentage_width_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidthPercent(root_child0, 30);
+  YGNodeStyleSetHeightPercent(root_child0, 30);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_position_left_top) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 400);
+  YGNodeStyleSetHeight(root, 400);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeTop, 20);
+  YGNodeStyleSetWidthPercent(root_child0, 45);
+  YGNodeStyleSetHeightPercent(root_child0, 55);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(220, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(400, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(260, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(180, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(220, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_position_bottom_right) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 500);
+  YGNodeStyleSetHeight(root, 500);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeRight, 20);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeBottom, 10);
+  YGNodeStyleSetWidthPercent(root_child0, 55);
+  YGNodeStyleSetHeightPercent(root_child0, 15);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(-100, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(275, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(-50, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(275, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_cross) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_cross_min_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMinHeightPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 2);
+  YGNodeStyleSetMinHeightPercent(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(140, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_main_max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(148, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(148, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(52, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(148, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_cross_max_height) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 10);
+  YGNodeStyleSetMaxHeightPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_main_max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 15);
+  YGNodeStyleSetMaxWidthPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 10);
+  YGNodeStyleSetMaxWidthPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_cross_max_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 10);
+  YGNodeStyleSetMaxWidthPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 15);
+  YGNodeStyleSetMaxWidthPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_main_min_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 15);
+  YGNodeStyleSetMinWidthPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 10);
+  YGNodeStyleSetMinWidthPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(120, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(80, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_flex_basis_cross_min_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 10);
+  YGNodeStyleSetMinWidthPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 15);
+  YGNodeStyleSetMinWidthPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_multiple_nested_with_padding_margin_and_percentage_values) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 10);
+  YGNodeStyleSetMargin(root_child0, YGEdgeLeft, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeTop, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeRight, 5);
+  YGNodeStyleSetMargin(root_child0, YGEdgeBottom, 5);
+  YGNodeStyleSetPadding(root_child0, YGEdgeLeft, 3);
+  YGNodeStyleSetPadding(root_child0, YGEdgeTop, 3);
+  YGNodeStyleSetPadding(root_child0, YGEdgeRight, 3);
+  YGNodeStyleSetPadding(root_child0, YGEdgeBottom, 3);
+  YGNodeStyleSetMinWidthPercent(root_child0, 60);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeLeft, 5);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeTop, 5);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeRight, 5);
+  YGNodeStyleSetMargin(root_child0_child0, YGEdgeBottom, 5);
+  YGNodeStyleSetPaddingPercent(root_child0_child0, YGEdgeLeft, 3);
+  YGNodeStyleSetPaddingPercent(root_child0_child0, YGEdgeTop, 3);
+  YGNodeStyleSetPaddingPercent(root_child0_child0, YGEdgeRight, 3);
+  YGNodeStyleSetPaddingPercent(root_child0_child0, YGEdgeBottom, 3);
+  YGNodeStyleSetWidthPercent(root_child0_child0, 50);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetMarginPercent(root_child0_child0_child0, YGEdgeLeft, 5);
+  YGNodeStyleSetMarginPercent(root_child0_child0_child0, YGEdgeTop, 5);
+  YGNodeStyleSetMarginPercent(root_child0_child0_child0, YGEdgeRight, 5);
+  YGNodeStyleSetMarginPercent(root_child0_child0_child0, YGEdgeBottom, 5);
+  YGNodeStyleSetPadding(root_child0_child0_child0, YGEdgeLeft, 3);
+  YGNodeStyleSetPadding(root_child0_child0_child0, YGEdgeTop, 3);
+  YGNodeStyleSetPadding(root_child0_child0_child0, YGEdgeRight, 3);
+  YGNodeStyleSetPadding(root_child0_child0_child0, YGEdgeBottom, 3);
+  YGNodeStyleSetWidthPercent(root_child0_child0_child0, 45);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 4);
+  YGNodeStyleSetFlexBasisPercent(root_child1, 15);
+  YGNodeStyleSetMinWidthPercent(root_child1, 20);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(190, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(48, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(8, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(8, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(6, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(58, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(142, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(5, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(190, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(48, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(8, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(92, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(46, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(36, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(6, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(58, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(142, YGNodeLayoutGetHeight(root_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_margin_should_calculate_based_only_on_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetMarginPercent(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetMarginPercent(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetMarginPercent(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetMarginPercent(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 10);
+  YGNodeStyleSetHeight(root_child0_child0, 10);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(160, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_padding_should_calculate_based_only_on_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetPaddingPercent(root_child0, YGEdgeLeft, 10);
+  YGNodeStyleSetPaddingPercent(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetPaddingPercent(root_child0, YGEdgeRight, 10);
+  YGNodeStyleSetPaddingPercent(root_child0, YGEdgeBottom, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 10);
+  YGNodeStyleSetHeight(root_child0_child0, 10);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(170, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(20, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_absolute_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeLeft, 30);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeTop, 10);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_width_height_undefined_parent_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidthPercent(root_child0, 50);
+  YGNodeStyleSetHeightPercent(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percent_within_flex_grow) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 350);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidthPercent(root_child1_child0, 100);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child2, 100);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(350, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(350, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percentage_container_in_wrapping_container) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetJustifyContent(root, YGJustifyCenter);
+  YGNodeStyleSetAlignItems(root, YGAlignCenter);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionRow);
+  YGNodeStyleSetJustifyContent(root_child0_child0, YGJustifyCenter);
+  YGNodeStyleSetWidthPercent(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child0, 50);
+  YGNodeStyleSetHeight(root_child0_child0_child0, 50);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
+
+  const YGNodeRef root_child0_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0_child1, 50);
+  YGNodeStyleSetHeight(root_child0_child0_child1, 50);
+  YGNodeInsertChild(root_child0_child0, root_child0_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, percent_absolute_position) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 60);
+  YGNodeStyleSetHeight(root, 50);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
+  YGNodeStyleSetPositionType(root_child0, YGPositionTypeAbsolute);
+  YGNodeStyleSetPositionPercent(root_child0, YGEdgeLeft, 50);
+  YGNodeStyleSetWidthPercent(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidthPercent(root_child0_child0, 100);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidthPercent(root_child0_child1, 100);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(-60, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0_child1));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGPersistenceTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGPersistenceTest.cpp
new file mode 100644 (file)
index 0000000..9df861a
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGPercentageTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, cloning_shared_root) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  const YGNodeRef root2 = YGNodeClone(root);
+  YGNodeStyleSetWidth(root2, 100);
+
+  ASSERT_EQ(2, YGNodeGetChildCount(root2));
+  // The children should have referential equality at this point.
+  ASSERT_EQ(root_child0, YGNodeGetChild(root2, 0));
+  ASSERT_EQ(root_child1, YGNodeGetChild(root2, 1));
+
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(2, YGNodeGetChildCount(root2));
+  // Relayout with no changed input should result in referential equality.
+  ASSERT_EQ(root_child0, YGNodeGetChild(root2, 0));
+  ASSERT_EQ(root_child1, YGNodeGetChild(root2, 1));
+
+  YGNodeStyleSetWidth(root2, 150);
+  YGNodeStyleSetHeight(root2, 200);
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_EQ(2, YGNodeGetChildCount(root2));
+  // Relayout with changed input should result in cloned children.
+  const YGNodeRef root2_child0 = YGNodeGetChild(root2, 0);
+  const YGNodeRef root2_child1 = YGNodeGetChild(root2, 1);
+  ASSERT_NE(root_child0, root2_child0);
+  ASSERT_NE(root_child1, root2_child1);
+
+  // Everything in the root should remain unchanged.
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  // The new root now has new layout.
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root2));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root2_child0));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2_child0));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetHeight(root2_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root2_child1));
+  ASSERT_FLOAT_EQ(125, YGNodeLayoutGetTop(root2_child1));
+  ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root2_child1));
+  ASSERT_FLOAT_EQ(75, YGNodeLayoutGetHeight(root2_child1));
+
+  YGNodeFreeRecursive(root2);
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, mutating_children_of_a_clone_clones) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  ASSERT_EQ(0, YGNodeGetChildCount(root));
+
+  const YGNodeRef root2 = YGNodeClone(root);
+  ASSERT_EQ(0, YGNodeGetChildCount(root2));
+
+  const YGNodeRef root2_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root2, root2_child0, 0);
+
+  ASSERT_EQ(0, YGNodeGetChildCount(root));
+  ASSERT_EQ(1, YGNodeGetChildCount(root2));
+
+  const YGNodeRef root3 = YGNodeClone(root2);
+  ASSERT_EQ(1, YGNodeGetChildCount(root2));
+  ASSERT_EQ(1, YGNodeGetChildCount(root3));
+  ASSERT_EQ(YGNodeGetChild(root2, 0), YGNodeGetChild(root3, 0));
+
+  const YGNodeRef root3_child1 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root3, root3_child1, 1);
+  ASSERT_EQ(1, YGNodeGetChildCount(root2));
+  ASSERT_EQ(2, YGNodeGetChildCount(root3));
+  ASSERT_EQ(root3_child1, YGNodeGetChild(root3, 1));
+  ASSERT_NE(YGNodeGetChild(root2, 0), YGNodeGetChild(root3, 0));
+
+  const YGNodeRef root4 = YGNodeClone(root3);
+  ASSERT_EQ(root3_child1, YGNodeGetChild(root4, 1));
+
+  YGNodeRemoveChild(root4, root3_child1);
+  ASSERT_EQ(2, YGNodeGetChildCount(root3));
+  ASSERT_EQ(1, YGNodeGetChildCount(root4));
+  ASSERT_NE(YGNodeGetChild(root3, 0), YGNodeGetChild(root4, 0));
+
+  YGNodeFreeRecursive(root4);
+  YGNodeFreeRecursive(root3);
+  YGNodeFreeRecursive(root2);
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, cloning_two_levels) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 15);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1_0, 10);
+  YGNodeStyleSetFlexGrow(root_child1_0, 1);
+  YGNodeInsertChild(root_child1, root_child1_0, 0);
+
+  const YGNodeRef root_child1_1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1_1, 25);
+  YGNodeInsertChild(root_child1, root_child1_1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetHeight(root_child1_0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1_1));
+
+  const YGNodeRef root2_child0 = YGNodeClone(root_child0);
+  const YGNodeRef root2_child1 = YGNodeClone(root_child1);
+  const YGNodeRef root2 = YGNodeClone(root);
+
+  YGNodeStyleSetFlexGrow(root2_child0, 0);
+  YGNodeStyleSetFlexBasis(root2_child0, 40);
+
+  YGNodeRemoveAllChildren(root2);
+  YGNodeInsertChild(root2, root2_child0, 0);
+  YGNodeInsertChild(root2, root2_child1, 1);
+  ASSERT_EQ(2, YGNodeGetChildCount(root2));
+
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  // Original root is unchanged
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root_child1));
+  ASSERT_FLOAT_EQ(35, YGNodeLayoutGetHeight(root_child1_0));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1_1));
+
+  // New root has new layout at the top
+  ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root2_child0));
+  ASSERT_FLOAT_EQ(60, YGNodeLayoutGetHeight(root2_child1));
+
+  // The deeper children are untouched.
+  ASSERT_EQ(YGNodeGetChild(root2_child1, 0), root_child1_0);
+  ASSERT_EQ(YGNodeGetChild(root2_child1, 1), root_child1_1);
+
+  YGNodeFreeRecursive(root2);
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, cloning_and_freeing) {
+  const int32_t initialInstanceCount = YGNodeGetInstanceCount();
+
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  const YGNodeRef root2 = YGNodeClone(root);
+
+  // Freeing the original root should be safe as long as we don't free its
+  // children.
+  YGNodeFree(root);
+
+  YGNodeCalculateLayout(root2, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  YGNodeFreeRecursive(root2);
+
+  YGNodeFree(root_child0);
+  YGNodeFree(root_child1);
+
+  YGConfigFree(config);
+
+  ASSERT_EQ(initialInstanceCount, YGNodeGetInstanceCount());
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGRelayoutTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGRelayoutTest.cpp
new file mode 100644 (file)
index 0000000..cbda524
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, dont_cache_computed_flex_basis_between_layouts) {
+  const YGConfigRef config = YGConfigNew();
+  YGConfigSetExperimentalFeatureEnabled(config, YGExperimentalFeatureWebFlexBasis, true);
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeightPercent(root, 100);
+  YGNodeStyleSetWidthPercent(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasisPercent(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, 100, YGUndefined, YGDirectionLTR);
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, recalculate_resolvedDimonsion_onchange) {
+  const YGNodeRef root = YGNodeNew();
+
+  const YGNodeRef root_child0 = YGNodeNew();
+  YGNodeStyleSetMinHeight(root_child0, 10);
+  YGNodeStyleSetMaxHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeStyleSetMinHeight(root_child0, YGUndefined);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingFunctionTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingFunctionTest.cpp
new file mode 100644 (file)
index 0000000..82eba44
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+#include <yoga/Yoga-internal.h>
+
+TEST(YogaTest, rounding_value) {
+  // Test that whole numbers are rounded to whole despite ceil/floor flags
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, false, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, true, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.000001, 2.0, false, true));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, false, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, true, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.999999, 2.0, false, true));
+
+  // Test that numbers with fraction are rounded correctly accounting for ceil/floor flags
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.01, 2.0, false, false));
+  ASSERT_FLOAT_EQ(6.5, YGRoundValueToPixelGrid(6.01, 2.0, true, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(6.01, 2.0, false, true));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.99, 2.0, false, false));
+  ASSERT_FLOAT_EQ(6.0, YGRoundValueToPixelGrid(5.99, 2.0, true, false));
+  ASSERT_FLOAT_EQ(5.5, YGRoundValueToPixelGrid(5.99, 2.0, false, true));
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingMeasureFuncTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingMeasureFuncTest.cpp
new file mode 100644 (file)
index 0000000..33820c4
--- /dev/null
@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <yoga/Yoga.h>
+
+static YGSize _measureFloor(YGNodeRef node,
+                            float width,
+                            YGMeasureMode widthMode,
+                            float height,
+                            YGMeasureMode heightMode) {
+  return YGSize{
+      width = 10.2f, height = 10.2f,
+  };
+}
+
+static YGSize _measureCeil(YGNodeRef node,
+                           float width,
+                           YGMeasureMode widthMode,
+                           float height,
+                           YGMeasureMode heightMode) {
+  return YGSize{
+      width = 10.5f, height = 10.5f,
+  };
+}
+
+static YGSize _measureFractial(YGNodeRef node,
+  float width,
+  YGMeasureMode widthMode,
+  float height,
+  YGMeasureMode heightMode) {
+  return YGSize{
+    width = 0.5f, height = 0.5f,
+  };
+}
+
+TEST(YogaTest, rounding_feature_with_custom_measure_func_floor) {
+  const YGConfigRef config = YGConfigNew();
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_measureFloor);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGConfigSetPointScaleFactor(config, 0.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(10.2, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10.2, YGNodeLayoutGetHeight(root_child0));
+
+  YGConfigSetPointScaleFactor(config, 1.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(11, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(11, YGNodeLayoutGetHeight(root_child0));
+
+  YGConfigSetPointScaleFactor(config, 2.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(10.5, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10.5, YGNodeLayoutGetHeight(root_child0));
+
+  YGConfigSetPointScaleFactor(config, 4.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(10.25, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10.25, YGNodeLayoutGetHeight(root_child0));
+
+  YGConfigSetPointScaleFactor(config, 1.0f / 3.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(12.0, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(12.0, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_feature_with_custom_measure_func_ceil) {
+  const YGConfigRef config = YGConfigNew();
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  root_child0->setMeasureFunc(_measureCeil);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGConfigSetPointScaleFactor(config, 1.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(11, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(11, YGNodeLayoutGetHeight(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_feature_with_custom_measure_and_fractial_matching_scale) {
+  const YGConfigRef config = YGConfigNew();
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root_child0, YGEdgeLeft, 73.625);
+  root_child0->setMeasureFunc(_measureFractial);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  YGConfigSetPointScaleFactor(config, 2.0f);
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0.5, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(0.5, YGNodeLayoutGetHeight(root_child0));
+  ASSERT_FLOAT_EQ(73.5, YGNodeLayoutGetLeft(root_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGRoundingTest.cpp
new file mode 100644 (file)
index 0000000..303e9f0
--- /dev/null
@@ -0,0 +1,1077 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGRoundingTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, rounding_flex_basis_flex_grow_row_width_of_100) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(34, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(67, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(67, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(34, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(33, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_flex_basis_flex_grow_row_prime_number_width) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 113);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeInsertChild(root, root_child2, 2);
+
+  const YGNodeRef root_child3 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child3, 1);
+  YGNodeInsertChild(root, root_child3, 3);
+
+  const YGNodeRef root_child4 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child4, 1);
+  YGNodeInsertChild(root, root_child4, 4);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(22, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(68, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(22, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(90, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(68, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(22, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(45, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetLeft(root_child3));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child3));
+  ASSERT_FLOAT_EQ(22, YGNodeLayoutGetWidth(root_child3));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child3));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child4));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child4));
+  ASSERT_FLOAT_EQ(23, YGNodeLayoutGetWidth(root_child4));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child4));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_flex_basis_flex_shrink_row) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 101);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexShrink(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child1, 25);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexBasis(root_child2, 25);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(101, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(51, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(51, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(76, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(101, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(51, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_flex_basis_overrides_main_size) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 113);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_total_fractial) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 87.4f);
+  YGNodeStyleSetHeight(root, 113.4f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 0.7f);
+  YGNodeStyleSetFlexBasis(root_child0, 50.3f);
+  YGNodeStyleSetHeight(root_child0, 20.3f);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1.6f);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1.1f);
+  YGNodeStyleSetHeight(root_child2, 10.7f);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_total_fractial_nested) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 87.4f);
+  YGNodeStyleSetHeight(root, 113.4f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 0.7f);
+  YGNodeStyleSetFlexBasis(root_child0, 50.3f);
+  YGNodeStyleSetHeight(root_child0, 20.3f);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0_child0, 0.3f);
+  YGNodeStyleSetPosition(root_child0_child0, YGEdgeBottom, 13.3f);
+  YGNodeStyleSetHeight(root_child0_child0, 9.9f);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+
+  const YGNodeRef root_child0_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0_child1, 4);
+  YGNodeStyleSetFlexBasis(root_child0_child1, 0.3f);
+  YGNodeStyleSetPosition(root_child0_child1, YGEdgeTop, 13.3f);
+  YGNodeStyleSetHeight(root_child0_child1, 1.1f);
+  YGNodeInsertChild(root_child0, root_child0_child1, 1);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1.6f);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1.1f);
+  YGNodeStyleSetHeight(root_child2, 10.7f);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(-13, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(47, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(-13, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(12, YGNodeLayoutGetHeight(root_child0_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetTop(root_child0_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child0_child1));
+  ASSERT_FLOAT_EQ(47, YGNodeLayoutGetHeight(root_child0_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(59, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(30, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(87, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_fractial_input_1) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 113.4f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_fractial_input_2) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 113.6f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(114, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(114, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_fractial_input_3) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root, YGEdgeTop, 0.3f);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 113.4f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(114, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(114, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(65, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_fractial_input_4) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetPosition(root, YGEdgeTop, 0.7f);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 113.4f);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetFlexBasis(root_child0, 50);
+  YGNodeStyleSetHeight(root_child0, 20);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(1, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(1, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(113, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(64, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(25, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(89, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(24, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_inner_node_controversy_horizontal) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 320);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetHeight(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeight(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child0, 1);
+  YGNodeStyleSetHeight(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeight(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_inner_node_controversy_vertical) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetHeight(root, 320);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetWidth(root_child0, 10);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetWidth(root_child1, 10);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child0, 1);
+  YGNodeStyleSetWidth(root_child1_child0, 10);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetWidth(root_child2, 10);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, rounding_inner_node_controversy_combined) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 640);
+  YGNodeStyleSetHeight(root, 320);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child0, 1);
+  YGNodeStyleSetHeightPercent(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1, 1);
+  YGNodeStyleSetHeightPercent(root_child1, 100);
+  YGNodeInsertChild(root, root_child1, 1);
+
+  const YGNodeRef root_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child0, 1);
+  YGNodeStyleSetWidthPercent(root_child1_child0, 100);
+  YGNodeInsertChild(root_child1, root_child1_child0, 0);
+
+  const YGNodeRef root_child1_child1 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child1, 1);
+  YGNodeStyleSetWidthPercent(root_child1_child1, 100);
+  YGNodeInsertChild(root_child1, root_child1_child1, 1);
+
+  const YGNodeRef root_child1_child1_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child1_child0, 1);
+  YGNodeStyleSetWidthPercent(root_child1_child1_child0, 100);
+  YGNodeInsertChild(root_child1_child1, root_child1_child1_child0, 0);
+
+  const YGNodeRef root_child1_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child1_child2, 1);
+  YGNodeStyleSetWidthPercent(root_child1_child2, 100);
+  YGNodeInsertChild(root_child1, root_child1_child2, 2);
+
+  const YGNodeRef root_child2 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetFlexGrow(root_child2, 1);
+  YGNodeStyleSetHeightPercent(root_child2, 100);
+  YGNodeInsertChild(root, root_child2, 2);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(640, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(427, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(640, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(427, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetLeft(root_child1));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child0));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child0));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetTop(root_child1_child1));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child1));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child1));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child1_child0));
+  ASSERT_FLOAT_EQ(106, YGNodeLayoutGetHeight(root_child1_child1_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetTop(root_child1_child2));
+  ASSERT_FLOAT_EQ(214, YGNodeLayoutGetWidth(root_child1_child2));
+  ASSERT_FLOAT_EQ(107, YGNodeLayoutGetHeight(root_child1_child2));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child2));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child2));
+  ASSERT_FLOAT_EQ(213, YGNodeLayoutGetWidth(root_child2));
+  ASSERT_FLOAT_EQ(320, YGNodeLayoutGetHeight(root_child2));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGSizeOverflowTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGSizeOverflowTest.cpp
new file mode 100644 (file)
index 0000000..3fbcb30
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+// @Generated by gentest/gentest.rb from gentest/fixtures/YGSizeOverflowTest.html
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, nested_overflowing_child) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 200);
+  YGNodeStyleSetHeight(root_child0_child0, 200);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(-100, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, nested_overflowing_child_in_constraint_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeStyleSetHeight(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 200);
+  YGNodeStyleSetHeight(root_child0_child0, 200);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(-100, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
+
+TEST(YogaTest, parent_wrap_child_size_overflowing_parent) {
+  const YGConfigRef config = YGConfigNew();
+
+  const YGNodeRef root = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root, 100);
+  YGNodeStyleSetHeight(root, 100);
+
+  const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0, 100);
+  YGNodeInsertChild(root, root_child0, 0);
+
+  const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
+  YGNodeStyleSetWidth(root_child0_child0, 100);
+  YGNodeStyleSetHeight(root_child0_child0, 200);
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0));
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
+  ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
+  ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0));
+
+  YGNodeFreeRecursive(root);
+
+  YGConfigFree(config);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGStyleTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGStyleTest.cpp
new file mode 100644 (file)
index 0000000..08b7be2
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/YGNode.h>
+#include <iostream>
+
+TEST(YogaTest, copy_style_same) {
+  const YGNodeRef node0 = YGNodeNew();
+  const YGNodeRef node1 = YGNodeNew();
+  ASSERT_FALSE(node0->isDirty());
+
+  YGNodeCopyStyle(node0, node1);
+  ASSERT_FALSE(node0->isDirty());
+
+  YGNodeFree(node0);
+  YGNodeFree(node1);
+}
+
+TEST(YogaTest, copy_style_modified) {
+  const YGNodeRef node0 = YGNodeNew();
+  ASSERT_FALSE(node0->isDirty());
+  ASSERT_EQ(YGFlexDirectionColumn, YGNodeStyleGetFlexDirection(node0));
+  ASSERT_FALSE(YGNodeStyleGetMaxHeight(node0).unit != YGUnitUndefined);
+
+  const YGNodeRef node1 = YGNodeNew();
+  YGNodeStyleSetFlexDirection(node1, YGFlexDirectionRow);
+  YGNodeStyleSetMaxHeight(node1, 10);
+
+  YGNodeCopyStyle(node0, node1);
+  ASSERT_TRUE(node0->isDirty());
+  ASSERT_EQ(YGFlexDirectionRow, YGNodeStyleGetFlexDirection(node0));
+  ASSERT_FLOAT_EQ(10, YGNodeStyleGetMaxHeight(node0).value);
+
+  YGNodeFree(node0);
+  YGNodeFree(node1);
+}
+
+TEST(YogaTest, copy_style_modified_same) {
+  const YGNodeRef node0 = YGNodeNew();
+  YGNodeStyleSetFlexDirection(node0, YGFlexDirectionRow);
+  YGNodeStyleSetMaxHeight(node0, 10);
+  YGNodeCalculateLayout(node0, YGUndefined, YGUndefined, YGDirectionLTR);
+  ASSERT_FALSE(node0->isDirty());
+
+  const YGNodeRef node1 = YGNodeNew();
+  YGNodeStyleSetFlexDirection(node1, YGFlexDirectionRow);
+  YGNodeStyleSetMaxHeight(node1, 10);
+
+  YGNodeCopyStyle(node0, node1);
+  ASSERT_FALSE(node0->isDirty());
+
+  YGNodeFree(node0);
+  YGNodeFree(node1);
+}
+
+TEST(YogaTest, initialise_flexShrink_flexGrow) {
+  const YGNodeRef node0 = YGNodeNew();
+  YGNodeStyleSetFlexShrink(node0, 1);
+  ASSERT_EQ(1, YGNodeStyleGetFlexShrink(node0));
+
+  YGNodeStyleSetFlexShrink(node0, YGUndefined);
+  YGNodeStyleSetFlexGrow(node0, 3);
+  ASSERT_EQ(
+      0,
+      YGNodeStyleGetFlexShrink(
+          node0)); // Default value is Zero, if flex shrink is not defined
+  ASSERT_EQ(3, YGNodeStyleGetFlexGrow(node0));
+
+  YGNodeStyleSetFlexGrow(node0, YGUndefined);
+  YGNodeStyleSetFlexShrink(node0, 3);
+  ASSERT_EQ(
+      0,
+      YGNodeStyleGetFlexGrow(
+          node0)); // Default value is Zero, if flex grow is not defined
+  ASSERT_EQ(3, YGNodeStyleGetFlexShrink(node0));
+  YGNodeFree(node0);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGTraversalTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGTraversalTest.cpp
new file mode 100644 (file)
index 0000000..3c4771d
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, pre_order_traversal) {
+  YGNodeRef const root = YGNodeNew();
+  YGNodeRef const root_child0 = YGNodeNew();
+  YGNodeRef const root_child1 = YGNodeNew();
+  YGNodeRef const root_child0_child0 = YGNodeNew();
+  
+  YGNodeSetChildren(root, {root_child0, root_child1});
+  YGNodeInsertChild(root_child0, root_child0_child0, 0);
+  
+  std::vector<YGNodeRef> visited;
+  YGTraversePreOrder(root, [&visited](YGNodeRef node) {
+    visited.push_back(node);
+  });
+  
+  const std::vector<YGNodeRef> expected = {
+    root,
+    root_child0,
+    root_child0_child0,
+    root_child1
+  };
+  ASSERT_EQ(visited, expected);
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGTreeMutationTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGTreeMutationTest.cpp
new file mode 100644 (file)
index 0000000..273f22a
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+static std::vector<YGNodeRef> getChildren(YGNodeRef const node)
+{
+  const uint32_t count = YGNodeGetChildCount(node);
+  std::vector<YGNodeRef> children;
+  children.reserve(count);
+  for (uint32_t i = 0 ; i < count ; i++) {
+    children.push_back(YGNodeGetChild(node, i));
+  }
+  return children;
+}
+
+TEST(YogaTest, set_children_adds_children_to_parent) {
+  YGNodeRef const root = YGNodeNew();
+  YGNodeRef const root_child0 = YGNodeNew();
+  YGNodeRef const root_child1 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child0, root_child1});
+
+  const std::vector<YGNodeRef> children = getChildren(root);
+  const std::vector<YGNodeRef> expectedChildren = {root_child0, root_child1};
+  ASSERT_EQ(children, expectedChildren);
+
+  const std::vector<YGNodeRef> owners = {YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)};
+  const std::vector<YGNodeRef> expectedOwners = {root, root};
+  ASSERT_EQ(owners, expectedOwners);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, set_children_to_empty_removes_old_children) {
+  YGNodeRef const root = YGNodeNew();
+  YGNodeRef const root_child0 = YGNodeNew();
+  YGNodeRef const root_child1 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child0, root_child1});
+  YGNodeSetChildren(root, {});
+
+  const std::vector<YGNodeRef> children = getChildren(root);
+  const std::vector<YGNodeRef> expectedChildren = {};
+  ASSERT_EQ(children, expectedChildren);
+
+  const std::vector<YGNodeRef> owners = {YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)};
+  const std::vector<YGNodeRef> expectedOwners = {nullptr, nullptr};
+  ASSERT_EQ(owners, expectedOwners);
+
+  YGNodeFreeRecursive(root);
+}
+
+TEST(YogaTest, set_children_replaces_non_common_children) {
+  YGNodeRef const root = YGNodeNew();
+  YGNodeRef const root_child0 = YGNodeNew();
+  YGNodeRef const root_child1 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child0, root_child1});
+
+  YGNodeRef const root_child2 = YGNodeNew();
+  YGNodeRef const root_child3 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child2, root_child3});
+
+  const std::vector<YGNodeRef> children = getChildren(root);
+  const std::vector<YGNodeRef> expectedChildren = {root_child2, root_child3};
+  ASSERT_EQ(children, expectedChildren);
+
+  const std::vector<YGNodeRef> owners = {YGNodeGetOwner(root_child0), YGNodeGetOwner(root_child1)};
+  const std::vector<YGNodeRef> expectedOwners = {nullptr, nullptr};
+  ASSERT_EQ(owners, expectedOwners);
+
+  YGNodeFreeRecursive(root);
+  YGNodeFree(root_child0);
+  YGNodeFree(root_child1);
+}
+
+TEST(YogaTest, set_children_keeps_and_reorders_common_children) {
+  YGNodeRef const root = YGNodeNew();
+  YGNodeRef const root_child0 = YGNodeNew();
+  YGNodeRef const root_child1 = YGNodeNew();
+  YGNodeRef const root_child2 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child0, root_child1, root_child2});
+
+  YGNodeRef const root_child3 = YGNodeNew();
+
+  YGNodeSetChildren(root, {root_child2, root_child1, root_child3});
+
+  const std::vector<YGNodeRef> children = getChildren(root);
+  const std::vector<YGNodeRef> expectedChildren = {root_child2, root_child1, root_child3};
+  ASSERT_EQ(children, expectedChildren);
+
+  const std::vector<YGNodeRef> owners = {
+    YGNodeGetOwner(root_child0),
+    YGNodeGetOwner(root_child1),
+    YGNodeGetOwner(root_child2),
+    YGNodeGetOwner(root_child3)
+  };
+  const std::vector<YGNodeRef> expectedOwners = {nullptr, root, root, root};
+  ASSERT_EQ(owners, expectedOwners);
+
+  YGNodeFreeRecursive(root);
+  YGNodeFree(root_child0);
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/yoga/YGZeroOutLayoutRecursivlyTest.cpp b/automated-tests/src/dali-toolkit-third-party/yoga/YGZeroOutLayoutRecursivlyTest.cpp
new file mode 100644 (file)
index 0000000..92e7c8a
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include <gtest/gtest.h>
+#include <yoga/Yoga.h>
+
+TEST(YogaTest, zero_out_layout) {
+  const YGNodeRef root = YGNodeNew();
+  YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
+  YGNodeStyleSetWidth(root, 200);
+  YGNodeStyleSetHeight(root, 200);
+
+  const YGNodeRef child = YGNodeNew();
+  YGNodeInsertChild(root, child, 0);
+  YGNodeStyleSetWidth(child, 100);
+  YGNodeStyleSetHeight(child, 100);
+  YGNodeStyleSetMargin(child, YGEdgeTop, 10);
+  YGNodeStyleSetPadding(child, YGEdgeTop, 10);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetMargin(child, YGEdgeTop));
+  ASSERT_FLOAT_EQ(10, YGNodeLayoutGetPadding(child, YGEdgeTop));
+
+  YGNodeStyleSetDisplay(child, YGDisplayNone);
+
+  YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR);
+
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetMargin(child, YGEdgeTop));
+  ASSERT_FLOAT_EQ(0, YGNodeLayoutGetPadding(child, YGEdgeTop));
+
+  YGNodeFreeRecursive(root);
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
new file mode 100644 (file)
index 0000000..b9c8245
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2018 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 "dali-test-suite-utils.h"
+
+// EXTERNAL INCLUDES
+#include <ostream>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+
+using namespace Dali;
+
+int32_t test_return_value = TET_UNDEF;
+
+void tet_result(int32_t value)
+{
+  // First TET_PASS should set to zero
+  // first TET_FAIL should prevent any further TET_PASS from setting back to zero
+  // Any TET_FAIL should set to fail or leave as fail
+  if( test_return_value != 1 )
+    test_return_value = value;
+}
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+
+void tet_infoline(const char* str)
+{
+  fprintf(stderr, "%s\n", str);
+}
+
+void tet_printf(const char *format, ...)
+{
+  va_list arg;
+  va_start(arg, format);
+  vfprintf(stderr, format, arg);
+  va_end(arg);
+}
+
+bool operator==(TimePeriod a, TimePeriod b)
+{
+  return Equals(a.durationSeconds, b.durationSeconds) && Equals(a.delaySeconds, b.delaySeconds) ;
+}
+
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value )
+{
+  return ostream << "( Duration:" << value.durationSeconds << " Delay:" << value.delaySeconds << ")";
+}
+
+std::ostream& operator<<( std::ostream& ostream, Radian angle )
+{
+  ostream << angle.radian;
+  return ostream;
+}
+
+std::ostream& operator<<( std::ostream& ostream, Degree angle )
+{
+  ostream << angle.degree;
+  return ostream;
+}
+
+void DALI_TEST_EQUALS( const BaseHandle& baseHandle1, const BaseHandle& baseHandle2, const char* location )
+{
+  DALI_TEST_EQUALS< const BaseHandle& >( baseHandle1, baseHandle2, location );
+}
+
+void DALI_TEST_EQUALS( const size_t value1, const uint32_t value2, const char* location )
+{
+  DALI_TEST_EQUALS< uint32_t >( ( uint32_t )( value1 ), value2, location );
+}
+
+void DALI_TEST_EQUALS( const uint32_t value1, const size_t value2, const char* location )
+{
+  DALI_TEST_EQUALS< uint32_t >( value1, ( uint32_t )( value2 ), location );
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<9;++i)
+  {
+    if( ! (fabsf(m1[i] - m2[i])< GetRangedEpsilon(m1[i], m2[i])) )
+    {
+      equivalent = false;
+    }
+  }
+
+  if( !equivalent )
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n",
+               location,
+               m1[0], m1[3], m1[6],    m2[0], m2[3], m2[6],
+               m1[1], m1[4], m1[7],    m2[1], m2[4], m2[7],
+               m1[2], m1[5], m1[8],    m2[2], m2[5], m2[8] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<9;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n",
+               location,
+               m1[0], m1[3], m1[6],    m2[0], m2[3], m2[6],
+               m1[1], m1[4], m1[7],    m2[1], m2[4], m2[7],
+               m1[2], m1[5], m1[8],    m2[2], m2[5], m2[8] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool identical = true;
+
+  int32_t i;
+  for (i=0;i<16;++i)
+  {
+    if(m1[i] != m2[i])
+    {
+      identical = false;
+      break;
+    }
+  }
+
+  if (!identical)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n",
+             location,
+             m1[0], m1[4], m1[8],  m1[12],    m2[0], m2[4], m2[8],  m2[12],
+             m1[1], m1[5], m1[9],  m1[13],    m2[1], m2[5], m2[9],  m2[13],
+             m1[2], m1[6], m1[10], m1[14],    m2[2], m2[6], m2[10], m2[14],
+             m1[3], m1[7], m1[11], m1[15],    m2[3], m2[7], m2[11], m2[15] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<16;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n",
+             location,
+             m1[0], m1[4], m1[8],  m1[12],    m2[0], m2[4], m2[8],  m2[12],
+             m1[1], m1[5], m1[9],  m1[13],    m2[1], m2[5], m2[9],  m2[13],
+             m1[2], m1[6], m1[10], m1[14],    m2[2], m2[6], m2[10], m2[14],
+             m1[3], m1[7], m1[11], m1[15],    m2[3], m2[7], m2[11], m2[15] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+
+/**
+ * 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)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2, location);
+}
+
+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);
+    throw("TET_FAIL");
+  }
+}
+
+void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1, str2.c_str(), location);
+}
+
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location )
+{
+  if( NULL == strstr( e.condition, conditionSubString.c_str() ) )
+  {
+    fprintf(stderr, "Expected substring '%s' : actual exception string '%s' : location %s\n", conditionSubString.c_str(), e.condition, location );
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+// Functor to test whether an Applied signal is emitted
+ConstraintAppliedCheck::ConstraintAppliedCheck( bool& signalReceived )
+: mSignalReceived( signalReceived )
+{
+}
+
+void ConstraintAppliedCheck::operator()( Constraint& constraint )
+{
+  mSignalReceived = true;
+}
+
+void ConstraintAppliedCheck::Reset()
+{
+  mSignalReceived = false;
+}
+
+void ConstraintAppliedCheck::CheckSignalReceived()
+{
+  if ( !mSignalReceived )
+  {
+    fprintf(stderr,  "Expected Applied signal was not received\n" );
+    tet_result( TET_FAIL );
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+void ConstraintAppliedCheck::CheckSignalNotReceived()
+{
+  if ( mSignalReceived )
+  {
+    fprintf(stderr,  "Unexpected Applied signal was received\n" );
+    tet_result( TET_FAIL );
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+BufferImage CreateBufferImage(int32_t width, int32_t height, const Vector4& color)
+{
+  BufferImage image = BufferImage::New(width, height, Pixel::RGBA8888);
+
+  PixelBuffer* pixbuf = image.GetBuffer();
+
+  // Using a 4x4 image gives a better blend with the GL implementation
+  // than a 3x3 image
+  for(size_t i=0; i<16; i++)
+  {
+    pixbuf[i*4+0] = color.r*255;
+    pixbuf[i*4+1] = color.g*255;
+    pixbuf[i*4+2] = color.b*255;
+    pixbuf[i*4+3] = color.a*255;
+  }
+
+  return image;
+}
+
+BufferImage CreateBufferImage()
+{
+  return CreateBufferImage(4, 4, Color::WHITE);
+}
+
+void PrepareResourceImage( TestApplication& application, uint32_t imageWidth, uint32_t imageHeight, Pixel::Format pixelFormat )
+{
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetClosestImageSize(Vector2( imageWidth, imageHeight));
+
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
+  Integration::PixelBuffer* pixbuffer = bitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, imageWidth, imageHeight, imageWidth, imageHeight );
+  uint32_t bytesPerPixel = GetBytesPerPixel(  pixelFormat );
+  uint32_t initialColor = 0xFF;
+  memset( pixbuffer, initialColor, imageHeight*imageWidth*bytesPerPixel);
+
+  Integration::ResourcePointer resourcePtr(bitmap);
+  platform.SetSynchronouslyLoadedResource( resourcePtr );
+}
+
+namespace Test
+{
+
+struct ObjectDestructionFunctor
+{
+  // Create a ObjectDestructionFunctor passing in a Dali::RefObject* to be monitored and a bool variable.
+  // Create ObjectRegistry instance and connect to the ObjectDestroyedSignal passing in the above functor for the callback.
+  // Get the ObjectPointer (Actor::GetObjectPtr) of the Actor to be checked for destruction and assign it to the Dali::RefObject*
+  // Check the bool variable which would be true when object destroyed.
+  ObjectDestructionFunctor( Dali::RefObject* objectPtr, bool& refObjectDestroyed )
+  : refObjectPointerToCheck( objectPtr ),
+    refObjectDestroyedBoolean( refObjectDestroyed )
+  {
+    refObjectDestroyed = false;
+  }
+
+  void operator()( const Dali::RefObject* objectPointer )
+  {
+    if ( refObjectPointerToCheck == objectPointer )
+    {
+      refObjectDestroyedBoolean = true;
+    }
+  }
+
+  Dali::RefObject* refObjectPointerToCheck;
+  bool& refObjectDestroyedBoolean;
+};
+
+ObjectDestructionTracker::ObjectDestructionTracker()
+  :mRefObjectDestroyed( false)
+{
+}
+
+void ObjectDestructionTracker::Start( Actor actor )
+{
+  ObjectDestructionFunctor destructionFunctor( actor.GetObjectPtr(), mRefObjectDestroyed );
+
+  ObjectRegistry objectRegistry = Stage::GetCurrent().GetObjectRegistry();
+  objectRegistry.ObjectDestroyedSignal().Connect( this, destructionFunctor );
+}
+
+bool ObjectDestructionTracker::IsDestroyed()
+{
+   return mRefObjectDestroyed;
+}
+
+} // namespace Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h
new file mode 100644 (file)
index 0000000..577ca36
--- /dev/null
@@ -0,0 +1,446 @@
+#ifndef DALI_TEST_SUITE_UTILS_H
+#define DALI_TEST_SUITE_UTILS_H
+
+/*
+ * Copyright (c) 2019 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 <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <cstring>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <test-compare-types.h>
+
+void tet_infoline(const char*str);
+void tet_printf(const char *format, ...);
+
+#include "test-application.h"
+#include "test-actor-utils.h"
+#include "test-gesture-generator.h"
+
+using namespace Dali;
+
+#define STRINGIZE_I(text) #text
+#define STRINGIZE(text) STRINGIZE_I(text)
+
+/**
+ * Inspired by https://stackoverflow.com/questions/1706346/file-macro-manipulation-handling-at-compile-time
+ * answer by Chetan Reddy
+ */
+constexpr int32_t basenameIndex( const char * const path, const int32_t index = 0, const int32_t slashIndex = -1 )
+{
+   return path[ index ]
+       ? ( path[ index ] == '/'
+           ? basenameIndex( path, index + 1, index )
+           : basenameIndex( path, index + 1, slashIndex ) )
+       : ( slashIndex + 1 );
+}
+
+#define __FILELINE__ ( { static const int32_t basenameIdx = basenameIndex( __FILE__ ); \
+                         static_assert (basenameIdx >= 0, "compile-time basename" );   \
+                         __FILE__ ":" STRINGIZE(__LINE__) + basenameIdx ; } )
+
+#define TEST_LOCATION __FILELINE__
+#define TEST_INNER_LOCATION(x) ( std::string(x) + " (" + STRINGIZE(__LINE__) + ")" ).c_str()
+
+#define TET_UNDEF 2
+#define TET_FAIL 1
+#define TET_PASS 0
+
+extern int32_t test_return_value;
+
+void tet_result(int32_t value);
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+void tet_infoline(const char* str);
+void tet_printf(const char *format, ...);
+
+/**
+ * DALI_TEST_CHECK is a wrapper for tet_result.
+ * If the condition evaluates to false, the test is stopped.
+ * @param[in] The boolean expression to check
+ */
+#define DALI_TEST_CHECK(condition)                                                        \
+if ( (condition) )                                                                        \
+{                                                                                         \
+  tet_result(TET_PASS);                                                                   \
+}                                                                                         \
+else                                                                                      \
+{                                                                                         \
+  fprintf(stderr, "Test failed in %s, condition: %s\n", __FILELINE__, #condition );       \
+  tet_result(TET_FAIL);                                                                   \
+  throw("TET_FAIL");                                                                      \
+}
+
+
+bool operator==(TimePeriod a, TimePeriod b);
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value );
+std::ostream& operator<<( std::ostream& ostream, Radian angle );
+std::ostream& operator<<( std::ostream& ostream, Degree angle );
+
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<typename Type>
+inline void DALI_TEST_EQUALS(Type value1, Type value2, const char* location)
+{
+  if( !CompareType<Type>(value1, value2, 0.01f) )
+  {
+    std::ostringstream o;
+    o << value1 << " == " << value2 << std::endl;
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ */
+#define DALI_TEST_EQUAL( v1, v2 ) DALI_TEST_EQUALS( v1, v2, __FILELINE__ )
+
+template<typename Type>
+inline void DALI_TEST_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, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+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, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("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
+ * @param[in] value2 The second value
+ * @param[in] epsilon The values must be within this distance of each other
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<TimePeriod>( TimePeriod value1, TimePeriod value2, float epsilon, const char* location)
+{
+  if ((fabs(value1.durationSeconds - value2.durationSeconds) > epsilon))
+  {
+    fprintf(stderr, "Test failed in %s, checking durations %f == %f, epsilon %f\n", location, value1.durationSeconds, value2.durationSeconds, epsilon);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else if ((fabs(value1.delaySeconds - value2.delaySeconds) > epsilon))
+  {
+    fprintf(stderr, "Test failed in %s, checking delays %f == %f, epsilon %f\n", location, value1.delaySeconds, value2.delaySeconds, epsilon);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two base handles are equal.
+ * @param[in] baseHandle1 The first value
+ * @param[in] baseHandle2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const BaseHandle& baseHandle1, const BaseHandle& baseHandle2, const char* location );
+
+/**
+ * Test whether a size_t value and an uint32_t are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const size_t value1, const uint32_t value2, const char* location );
+
+/**
+ * Test whether an uint32_t and a size_t value and are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const uint32_t value1, const size_t value2, const char* location );
+
+/**
+ * Test whether two Matrix3 objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location);
+
+/** Test whether two Matrix3 objects are equal (fuzzy compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] epsilon The epsilon to use for comparison
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal (fuzzy-compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, 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
+ */
+template<>
+inline void DALI_TEST_EQUALS<const char*>( const char* str1, const char* str2, const char* location)
+{
+  if (strcmp(str1, str2))
+  {
+    fprintf(stderr, "Test failed in %s, checking '%s' == '%s'\n", location, str1, str2);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * 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
+ */
+template<>
+inline void DALI_TEST_EQUALS<const std::string&>( const std::string &str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2.c_str(), 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);
+
+/**
+ * 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);
+
+/**
+ * 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 char* str1, const std::string &str2, const char* location);
+
+/**
+ * Test whether one unsigned integer value is greater than another.
+ * Test succeeds if value1 > value2
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template< typename T >
+void DALI_TEST_GREATER( T value1, T value2, const char* location)
+{
+  if (!(value1 > value2))
+  {
+    std::cerr << "Test failed in " << location << ", checking " << value1 <<" > " << value2 << "\n";
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether the assertion condition that failed and thus triggered the
+ * exception \b e contained a given substring.
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ * @param[in] conditionSubString The text that we expect to be present in an
+ *                               assertion which triggered the exception.
+ * @param[in] location The TEST_LOCATION macro should be used here.
+ */
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location );
+
+/**
+ * Print the assert
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ */
+inline void DALI_TEST_PRINT_ASSERT( DaliException& e )
+{
+  tet_printf("Assertion %s failed at %s\n", e.condition, e.location );
+}
+
+/**
+ * Test that given piece of code triggers the right assertion
+ * Fails the test if the assert didn't occur.
+ * Turns off logging during the execution of the code to avoid excessive false positive log output from the assertions
+ * @param expressions code to execute
+ * @param assertstring the substring expected in the assert
+ */
+#define DALI_TEST_ASSERTION( expressions, assertstring ) \
+try \
+{ \
+  TestApplication::EnableLogging( false ); \
+  expressions; \
+  TestApplication::EnableLogging( true ); \
+  fprintf(stderr, "Test failed in %s, expected assert: '%s' didn't occur\n", __FILELINE__, assertstring ); \
+  tet_result(TET_FAIL); \
+  throw("TET_FAIL"); } \
+catch( Dali::DaliException& e ) \
+{ \
+  DALI_TEST_ASSERT( e, assertstring, TEST_LOCATION ); \
+}
+
+// Functor to test whether an Applied signal is emitted
+struct ConstraintAppliedCheck
+{
+  ConstraintAppliedCheck( bool& signalReceived );
+  void operator()( Constraint& constraint );
+  void Reset();
+  void CheckSignalReceived();
+  void CheckSignalNotReceived();
+  bool& mSignalReceived; // owned by individual tests
+};
+
+/**
+ * A Helper to test default functions
+ */
+template <typename T>
+struct DefaultFunctionCoverage
+{
+  DefaultFunctionCoverage()
+  {
+    T a;
+    T *b = new T(a);
+    DALI_TEST_CHECK(b);
+    a = *b;
+    delete b;
+  }
+};
+
+
+// Helper to Create buffer image
+BufferImage CreateBufferImage();
+BufferImage CreateBufferImage(int32_t width, int32_t height, const Vector4& color);
+
+
+// Prepare a resource image to be loaded. Should be called before creating the ResourceImage
+void PrepareResourceImage( TestApplication& application, uint32_t imageWidth, uint32_t imageHeight, Pixel::Format pixelFormat );
+
+// Test namespace to prevent pollution of Dali namespace, add Test helper functions here
+namespace Test
+{
+/**
+ *  @brief
+ *
+ *  Helper to check object destruction occurred
+ *  1) In main part of code create an ObjectDestructionTracker
+ *  2) Within sub section of main create object Actor test and call Start with Actor to test for destruction
+ *  3) Perform code which is expected to destroy Actor
+ *  4) Back in main part of code use IsDestroyed() to test if Actor was destroyed
+ */
+class ObjectDestructionTracker : public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Call in main part of code
+   */
+  ObjectDestructionTracker();
+
+  /**
+   * @brief Call in sub bock of code where the Actor being checked is still alive.
+   *
+   * @param[in] actor Actor to be checked for destruction
+   */
+  void Start( Actor actor );
+
+  /**
+   * @brief Call to check if Actor alive or destroyed.
+   *
+   * @return bool true if Actor was destroyed
+   */
+  bool IsDestroyed();
+
+private:
+  bool mRefObjectDestroyed;
+};
+
+} // namespace Test
+
+#endif // DALI_TEST_SUITE_UTILS_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.cpp
new file mode 100644 (file)
index 0000000..94c9530
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 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"
+
+
+std::ostream& operator<<( std::ostream& ostream, Dali::Toolkit::Visual::ResourceStatus status )
+{
+  switch(status)
+  {
+    case Dali::Toolkit::Visual::ResourceStatus::PREPARING:
+    {
+      ostream << "PREPARING";
+      break;
+    }
+    case Dali::Toolkit::Visual::ResourceStatus::READY:
+    {
+      ostream << "READY";
+      break;
+    }
+    case Dali::Toolkit::Visual::ResourceStatus::FAILED:
+    {
+      ostream << "FAILED";
+      break;
+    }
+  }
+  return ostream;
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-toolkit-test-suite-utils.h
new file mode 100644 (file)
index 0000000..da96fac
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef DALI_TOOLKIT_TEST_SUITE_UTILS_H
+#define DALI_TOOLKIT_TEST_SUITE_UTILS_H
+
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/visuals/visual-properties.h>
+
+// Put any toolkit specific operators for DALI_TEST_CHECK template here, before dali-test-suite-utils.h.
+
+std::ostream& operator<<( std::ostream& ostream, Dali::Toolkit::Visual::ResourceStatus status );
+
+// INTERNAL INCLUDES
+
+#include <dali-test-suite-utils.h>
+#include "toolkit-test-application.h"
+#include "toolkit-application.h"
+#include "toolkit-input-method-context.h"
+#include "toolkit-clipboard-event-notifier.h"
+
+#endif // DALI_TOOLKIT_TEST_SUITE_UTILS_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
new file mode 100644 (file)
index 0000000..b8ddd29
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2017 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 "dummy-control.h"
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+DummyControl::DummyControl()
+{
+}
+
+DummyControl::DummyControl(const DummyControl& control)
+: Control( control )
+{
+}
+
+DummyControl::~DummyControl()
+{
+}
+
+DummyControl DummyControl::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<DummyControl, DummyControlImpl>(handle);
+}
+
+DummyControl& DummyControl::operator=(const DummyControl& control)
+{
+  Control::operator=( control );
+  return *this;
+}
+
+// Used to test signal connections
+void DummyControlImpl::CustomSlot1( Actor actor )
+{
+  mCustomSlot1Called = true;
+}
+
+namespace {
+
+BaseHandle Create()
+{
+  return DummyControlImpl::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::DummyControl, Toolkit::Control, Create );
+DALI_TYPE_REGISTRATION_END()
+
+Dali::PropertyRegistration dummyControlVisualProperty01(
+  typeRegistration, "testVisual", Dali::Toolkit::DummyControl::Property::TEST_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+Dali::PropertyRegistration dummyControlVisualProperty02(
+  typeRegistration, "testVisual2", Dali::Toolkit::DummyControl::Property::TEST_VISUAL2, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+Dali::PropertyRegistration dummyControlVisualProperty03(
+  typeRegistration, "foregroundVisual", Dali::Toolkit::DummyControl::Property::FOREGROUND_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+Dali::PropertyRegistration dummyControlVisualProperty04(
+  typeRegistration, "focusVisual", Dali::Toolkit::DummyControl::Property::FOCUS_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+Dali::PropertyRegistration dummyControlVisualProperty05(
+  typeRegistration, "labelVisual", Dali::Toolkit::DummyControl::Property::LABEL_VISUAL, Dali::Property::MAP, &Dali::Toolkit::DummyControlImpl::SetProperty, &Dali::Toolkit::DummyControlImpl::GetProperty );
+
+}
+
+DummyControl DummyControlImpl::New()
+{
+  IntrusivePtr< DummyControlImpl > impl = new DummyControlImpl;
+  DummyControl control( *impl );
+  impl->Initialize();
+  return control;
+}
+
+DummyControlImpl::DummyControlImpl()
+: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_HOVER_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
+  mCustomSlot1Called(false)
+{
+}
+
+DummyControlImpl::~DummyControlImpl()
+{
+}
+
+void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual )
+{
+  DevelControl::RegisterVisual( *this, index, visual );
+
+  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+  if( iter == mRegisteredVisualIndices.end() )
+  {
+    mRegisteredVisualIndices.push_back(index);
+  }
+}
+
+void DummyControlImpl::RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled )
+{
+  DevelControl::RegisterVisual( *this, index, visual, enabled );
+
+  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+  if( iter == mRegisteredVisualIndices.end() )
+  {
+    mRegisteredVisualIndices.push_back(index);
+  }
+}
+
+void DummyControlImpl::UnregisterVisual( Property::Index index )
+{
+  DevelControl::UnregisterVisual( *this, index );
+
+  VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+  if( iter != mRegisteredVisualIndices.end() )
+  {
+    mRegisteredVisualIndices.erase(iter);
+  }
+}
+
+Toolkit::Visual::Base DummyControlImpl::GetVisual( Property::Index index )
+{
+  return DevelControl::GetVisual( *this, index );
+}
+
+void DummyControlImpl::EnableVisual( Property::Index index, bool enabled )
+{
+  DevelControl::EnableVisual( *this, index, enabled );
+}
+
+bool DummyControlImpl::IsVisualEnabled( Property::Index index )
+{
+  return DevelControl::IsVisualEnabled( *this, index );
+}
+
+Animation DummyControlImpl::CreateTransition( const Toolkit::TransitionData& transition )
+{
+  return DevelControl::CreateTransition( *this, transition );
+}
+
+void DummyControlImpl::DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes )
+{
+  DummyControl control( *this );
+  DevelControl::DoAction(  control, index, action, attributes);
+}
+
+void DummyControlImpl::SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value )
+{
+  Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(control.GetImplementation());
+
+  switch(index)
+  {
+    case Toolkit::DummyControl::Property::TEST_VISUAL:
+    case Toolkit::DummyControl::Property::TEST_VISUAL2:
+    case Toolkit::DummyControl::Property::FOREGROUND_VISUAL:
+    case Toolkit::DummyControl::Property::FOCUS_VISUAL:
+    case Toolkit::DummyControl::Property::LABEL_VISUAL:
+    {
+      Property::Map* map = value.GetMap();
+      if( map != NULL )
+      {
+        VisualFactory visualFactory = VisualFactory::Get();
+        Visual::Base visual = visualFactory.CreateVisual(*map);
+        dummyImpl.RegisterVisual(index, visual);
+      }
+      break;
+    }
+  }
+}
+
+Property::Value DummyControlImpl::GetProperty( BaseObject* object, Dali::Property::Index propertyIndex )
+{
+  Toolkit::DummyControl control = Toolkit::DummyControl::DownCast( Dali::BaseHandle( object ) );
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>( control.GetImplementation() );
+
+  Visual::Base visual = dummyImpl.GetVisual( propertyIndex );
+  Property::Map map;
+  if( visual )
+  {
+    visual.CreatePropertyMap( map );
+  }
+  Dali::Property::Value value = map;
+
+  return value;
+}
+
+
+Toolkit::DummyControl Impl::DummyControl::New()
+{
+  IntrusivePtr< Toolkit::Impl::DummyControl > impl = new Toolkit::Impl::DummyControl;
+  Toolkit::DummyControl control( *impl );
+  impl->Initialize();
+  return control;
+}
+
+int Impl::DummyControl::constructorCount;
+int Impl::DummyControl::destructorCount;
+
+Impl::DummyControl::DummyControl()
+: DummyControlImpl(),
+  initializeCalled(false),
+  activatedCalled(false),
+  onAccTouchedCalled(false),
+  onAccValueChangeCalled(false),
+  themeChangeCalled(false),
+  fontChangeCalled(false),
+  pinchCalled(false),
+  panCalled(false),
+  tapCalled(false),
+  longPressCalled(false),
+  stageConnectionCalled(false),
+  stageDisconnectionCalled(false),
+  childAddCalled(false),
+  childRemoveCalled(false),
+  sizeSetCalled(false),
+  sizeAnimationCalled(false),
+  touchEventCalled(false),
+  hoverEventCalled(false),
+  wheelEventCalled(false),
+  keyEventCalled(false),
+  keyInputFocusGained(false),
+  keyInputFocusLost(false)
+{
+  ++constructorCount;
+}
+
+Impl::DummyControl::~DummyControl()
+{
+  ++destructorCount;
+}
+
+void Impl::DummyControl::OnInitialize() { initializeCalled = true; }
+bool Impl::DummyControl::OnAccessibilityActivated() { activatedCalled = true; return true; }
+bool Impl::DummyControl::OnAccessibilityTouch(const TouchEvent& touchEvent) { onAccTouchedCalled = true; return true; }
+bool Impl::DummyControl::OnAccessibilityValueChange( bool isIncrease )
+{
+  onAccValueChangeCalled = true; return true;
+}
+
+void Impl::DummyControl::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+{
+  themeChangeCalled = change == StyleChange::THEME_CHANGE;
+  fontChangeCalled = change == StyleChange::DEFAULT_FONT_SIZE_CHANGE;
+}
+void Impl::DummyControl::OnPinch(const PinchGesture& pinch) { pinchCalled = true; }
+void Impl::DummyControl::OnPan(const PanGesture& pan) { panCalled = true; }
+void Impl::DummyControl::OnTap(const TapGesture& tap) { tapCalled = true; }
+void Impl::DummyControl::OnLongPress(const LongPressGesture& longPress) { longPressCalled = true; }
+void Impl::DummyControl::OnStageConnection( int depth ) { Control::OnStageConnection( depth ); stageConnectionCalled = true; }
+void Impl::DummyControl::OnStageDisconnection() { stageDisconnectionCalled = true; Control::OnStageDisconnection(); }
+void Impl::DummyControl::OnChildAdd(Actor& child) { childAddCalled = true; }
+void Impl::DummyControl::OnChildRemove(Actor& child) { childRemoveCalled = true; }
+void Impl::DummyControl::OnSizeSet(const Vector3& targetSize) { Control::OnSizeSet( targetSize ); sizeSetCalled = true; }
+void Impl::DummyControl::OnSizeAnimation(Animation& animation, const Vector3& targetSize) { Control::OnSizeAnimation( animation, targetSize ); sizeAnimationCalled = true; }
+bool Impl::DummyControl::OnTouchEvent(const TouchEvent& event) { touchEventCalled = true; return false; }
+bool Impl::DummyControl::OnHoverEvent(const HoverEvent& event) { hoverEventCalled = true; return false; }
+bool Impl::DummyControl::OnWheelEvent(const WheelEvent& event) { wheelEventCalled = true; return false; }
+bool Impl::DummyControl::OnKeyEvent(const KeyEvent& event) { keyEventCalled = true; return false;}
+void Impl::DummyControl::OnKeyInputFocusGained() { keyInputFocusGained = true; }
+void Impl::DummyControl::OnKeyInputFocusLost() { keyInputFocusLost = true; }
+
+void Impl::DummyControl::SetLayout( Property::Index visualIndex, Property::Map& map )
+{
+  Property::Value value( map );
+  mLayouts[visualIndex] = value;
+}
+
+void Impl::DummyControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  if ( mRelayoutCallback )
+  {
+    mRelayoutCallback( size );  // Execute callback if set
+  }
+
+  Property::Map emptyMap;
+
+  for( VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end() ; ++iter )
+  {
+    Visual::Base visual = GetVisual(*iter);
+    Property::Value value = mLayouts[*iter];
+    Property::Map* map = NULL;
+
+    if( value.GetType() != Property::NONE )
+    {
+      map = value.GetMap();
+    }
+    if( map == NULL )
+    {
+      map = &emptyMap;
+    }
+
+    visual.SetTransformAndSize( *map, size );
+  }
+}
+
+void Impl::DummyControl::SetRelayoutCallback( RelayoutCallbackFunc callback  )
+{
+  mRelayoutCallback = callback;
+}
+
+Vector3 Impl::DummyControl::GetNaturalSize()
+{
+  Vector2 currentSize;
+
+  for( auto elem : mRegisteredVisualIndices )
+  {
+    Vector2 naturalSize;
+    Visual::Base visual = GetVisual(elem);
+    visual.GetNaturalSize( naturalSize );
+    currentSize.width = std::max( naturalSize.width, currentSize.width );
+    currentSize.height = std::max( naturalSize.height, currentSize.height );
+  }
+
+  return Vector3( currentSize );
+}
+
+
+
+DummyControl DummyControl::New( bool override )
+{
+  DummyControl control;
+
+  if (override)
+  {
+    control = Impl::DummyControl::New();
+  }
+  else
+  {
+    control = DummyControlImpl::New();
+  }
+
+  return control;
+}
+
+DummyControl::DummyControl( DummyControlImpl& implementation )
+: Control( implementation )
+{
+}
+
+DummyControl::DummyControl( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<DummyControlImpl>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.h
new file mode 100644 (file)
index 0000000..1f32459
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef DALI_TOOLKIT_TEST_DUMMY_CONTROL_H
+#define DALI_TOOLKIT_TEST_DUMMY_CONTROL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/dali-toolkit.h>
+
+// EXTERNAL INCLUDES
+#include <functional>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class DummyControlImpl;
+class TransitionData;
+
+namespace Visual
+{
+class Base;
+}
+
+/**
+ * Control does not have a New method so use this dummy class for the handle.
+ */
+class DummyControl : public Control
+{
+public:
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property index
+  };
+
+  struct Property
+  {
+    enum Type
+    {
+      TEST_VISUAL = PROPERTY_START_INDEX,
+      TEST_VISUAL2,
+      FOREGROUND_VISUAL,
+      FOCUS_VISUAL,
+      LABEL_VISUAL
+    };
+  };
+
+  DummyControl();
+  DummyControl(const DummyControl& control);
+  ~DummyControl();
+
+  static DummyControl New( bool override = false );
+
+  static DummyControl DownCast( BaseHandle handle );
+
+
+  DummyControl& operator=(const DummyControl& control);
+
+public: // Not intended for application developers
+
+  DummyControl( DummyControlImpl& implementation );
+  DummyControl( Dali::Internal::CustomActor* internal );
+};
+
+/**
+ * Cannot create an instance of Internal::Control, so use this dummy class for the implementation.
+ * This class does not override any of Internal::Control's behaviour.
+ */
+class DummyControlImpl : public Toolkit::Internal::Control
+{
+public:
+
+  static DummyControl New();
+
+public:
+  inline void EnableGestureDetection(Gesture::Type type) { Internal::Control::EnableGestureDetection(type); }
+  inline void DisableGestureDetection(Gesture::Type type) { Internal::Control::DisableGestureDetection(type); }
+  inline PinchGestureDetector GetPinchGestureDetector() const { return Internal::Control::GetPinchGestureDetector(); }
+  inline PanGestureDetector GetPanGestureDetector() const { return Internal::Control::GetPanGestureDetector(); }
+  inline TapGestureDetector GetTapGestureDetector() const { return Internal::Control::GetTapGestureDetector(); }
+  inline LongPressGestureDetector GetLongPressGestureDetector() const { return Internal::Control::GetLongPressGestureDetector(); }
+
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual);
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base visual, bool enabled );
+  void UnregisterVisual( Property::Index index );
+  void EnableVisual( Property::Index index, bool enabled );
+  bool IsVisualEnabled( Property::Index index );
+  int GetVisualCount();
+  Toolkit::Visual::Base GetVisual( Property::Index index );
+  Animation CreateTransition( const Toolkit::TransitionData& transition );
+  void DoAction( Dali::Property::Index index, Dali::Property::Index action, const Dali::Property::Value attributes );
+
+  static void SetProperty( BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value );
+
+  static Property::Value GetProperty( BaseObject* object, Dali::Property::Index propertyIndex );
+
+  // Used to test signal connections
+  void CustomSlot1( Actor actor );
+
+  bool mCustomSlot1Called;
+  typedef std::vector<Property::Index> VisualIndices;
+  VisualIndices mRegisteredVisualIndices;
+
+protected:
+
+  DummyControlImpl();
+
+  virtual ~DummyControlImpl();
+};
+
+namespace Impl
+{
+
+/**
+ * Cannot create an instance of Internal::Control, so use this dummy class for the implementation.
+ * This class DOES override Internal::Control's behaviour.
+ */
+class DummyControl : public Toolkit::DummyControlImpl
+{
+public:
+
+  typedef std::function<void( Size )> RelayoutCallbackFunc;
+
+  static Toolkit::DummyControl New();
+
+  void SetLayout( Property::Index visualIndex, Property::Map& map );
+
+  void SetRelayoutCallback( RelayoutCallbackFunc callback );
+
+private:
+
+  DummyControl();
+
+  virtual ~DummyControl();
+
+private: // From Internal::Control
+
+  virtual void OnInitialize();
+  virtual bool OnAccessibilityActivated();
+  virtual bool OnAccessibilityTouch( const TouchEvent& touchEvent );
+  virtual bool OnAccessibilityValueChange( bool isIncrease );
+
+  virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change );
+  virtual void OnPinch(const PinchGesture& pinch);
+  virtual void OnPan(const PanGesture& pan);
+  virtual void OnTap(const TapGesture& tap);
+  virtual void OnLongPress(const LongPressGesture& longPress);
+  virtual Vector3 GetNaturalSize();
+
+private: // From CustomActorImpl
+
+  virtual void OnStageConnection( int depth );
+  virtual void OnStageDisconnection();
+  virtual void OnChildAdd(Actor& child);
+  virtual void OnChildRemove(Actor& child);
+  virtual void OnSizeSet(const Vector3& targetSize);
+  virtual void OnSizeAnimation(Animation& animation, const Vector3& targetSize);
+  virtual bool OnTouchEvent(const TouchEvent& event);
+  virtual bool OnHoverEvent(const HoverEvent& event);
+  virtual bool OnWheelEvent(const WheelEvent& event);
+  virtual bool OnKeyEvent(const KeyEvent& event);
+  virtual void OnKeyInputFocusGained();
+  virtual void OnKeyInputFocusLost();
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  DALI_INTERNAL DummyControl( const DummyControl& );
+  DALI_INTERNAL DummyControl& operator=( const DummyControl& );
+
+public:
+
+  bool initializeCalled;
+  bool activatedCalled;
+  bool onAccTouchedCalled;
+  bool onAccValueChangeCalled;
+  bool themeChangeCalled;
+  bool fontChangeCalled;
+  bool pinchCalled;
+  bool panCalled;
+  bool tapCalled;
+  bool longPressCalled;
+  bool stageConnectionCalled;
+  bool stageDisconnectionCalled;
+  bool childAddCalled;
+  bool childRemoveCalled;
+  bool sizeSetCalled;
+  bool sizeAnimationCalled;
+  bool touchEventCalled;
+  bool hoverEventCalled;
+  bool wheelEventCalled;
+  bool keyEventCalled;
+  bool keyInputFocusGained;
+  bool keyInputFocusLost;
+  static int constructorCount;
+  static int destructorCount;
+
+  Property::Map mLayouts;
+  RelayoutCallbackFunc mRelayoutCallback;
+
+};
+
+} // namespace Impl
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEST_DUMMY_CONTROL_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp
new file mode 100644 (file)
index 0000000..48bc26b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "mesh-builder.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/texture-set-image.h>
+
+namespace Dali
+{
+
+Shader CreateShader()
+{
+  return Shader::New( "vertexSrc", "fragmentSrc" );
+}
+
+TextureSet CreateTextureSet()
+{
+  return TextureSet::New();
+}
+
+TextureSet CreateTextureSet( Image image )
+{
+  TextureSet textureSet = TextureSet::New();
+  TextureSetImage( textureSet, 0u, image );
+  return textureSet;
+}
+
+PropertyBuffer CreatePropertyBuffer()
+{
+  Property::Map texturedQuadVertexFormat;
+  texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
+  texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
+
+  PropertyBuffer vertexData = PropertyBuffer::New( texturedQuadVertexFormat );
+  return vertexData;
+}
+
+Geometry CreateQuadGeometry(void)
+{
+  PropertyBuffer vertexData = CreatePropertyBuffer();
+  const float halfQuadSize = .5f;
+  struct TexturedQuadVertex { Vector2 position; Vector2 textureCoordinates; };
+  TexturedQuadVertex texturedQuadVertexData[4] = {
+    { Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f) },
+    { Vector2( halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f) },
+    { Vector2(-halfQuadSize,  halfQuadSize), Vector2(0.f, 1.f) },
+    { Vector2( halfQuadSize,  halfQuadSize), Vector2(1.f, 1.f) } };
+  vertexData.SetData(texturedQuadVertexData, 4);
+
+  unsigned short indexData[6] = { 0, 3, 1, 0, 2, 3 };
+
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexData );
+  geometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+
+  return geometry;
+}
+
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.h
new file mode 100644 (file)
index 0000000..d22f9c8
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef MESH_BUILDER_H
+#define MESH_BUILDER_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+
+namespace Dali
+{
+
+Shader CreateShader();
+TextureSet CreateTextureSet();
+TextureSet CreateTextureSet( Image image );
+Geometry CreateQuadGeometry();
+PropertyBuffer CreatePropertyBuffer();
+
+}
+
+#endif // MESH_BUILDER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp
new file mode 100644 (file)
index 0000000..38eb0b2
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "test-actor-utils.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/images/texture-set-image.h>
+
+// INTERNAL INCLUDES
+#include "mesh-builder.h"
+
+namespace Dali
+{
+
+namespace
+{
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = uColor;\n
+  }\n
+);
+
+} // unnamed namespace
+
+Actor CreateRenderableActor()
+{
+  return CreateRenderableActor( Image(), VERTEX_SHADER, FRAGMENT_SHADER );
+}
+
+Actor CreateRenderableActor( Image texture )
+{
+  return CreateRenderableActor( texture, VERTEX_SHADER, FRAGMENT_SHADER );
+}
+
+Actor CreateRenderableActor( Image texture, const std::string& vertexShader, const std::string& fragmentShader )
+{
+  // Create the geometry
+  Geometry geometry = CreateQuadGeometry();
+
+  // Create Shader
+  Shader shader = Shader::New( vertexShader, fragmentShader );
+
+  // Create renderer from geometry and material
+  Renderer renderer = Renderer::New( geometry, shader );
+
+  // Create actor and set renderer
+  Actor actor = Actor::New();
+  actor.AddRenderer( renderer );
+
+  // If we a texture, then create a texture-set and add to renderer
+  if( texture )
+  {
+    TextureSet textureSet = TextureSet::New();
+    TextureSetImage( textureSet, 0u, texture );
+    renderer.SetTextures( textureSet );
+
+    // Set actor to the size of the texture if set
+    actor.SetSize( texture.GetWidth(), texture.GetHeight() );
+  }
+
+  return actor;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-actor-utils.h
new file mode 100644 (file)
index 0000000..a62dcca
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_TEST_ACTOR_UTILS_H
+#define DALI_TEST_ACTOR_UTILS_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+
+class Actor;
+class Image;
+
+/**
+ * @brief Creates a simple renderable-actor with solid colored quad.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor();
+
+/**
+ * @brief Creates a renderable-actor with a texture.
+ * @param[in] texture Texture to set.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor( Image texture );
+
+/**
+ * @brief Creates a renderable-actor with a texture and custom shaders.
+ * @param[in] texture Texture to set.
+ * @param[in] vertexShader The vertex-shader.
+ * @param[in] fragmentShader The fragment-shader.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor( Image texture, const std::string& vertexShader, const std::string& fragmentShader );
+
+} // namespace Dali
+
+#endif // DALI_TEST_ACTOR_UTILS_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp
new file mode 100644 (file)
index 0000000..57c1e41
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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/dali.h>
+#include <test-animation-data.h>
+
+using namespace Dali;
+
+namespace Test
+{
+
+TestAnimationData::TestAnimationData()
+{
+}
+
+TestAnimationData::~TestAnimationData()
+{
+}
+
+TestAnimationData::AnimationDataElement::AnimationDataElement()
+: alphaFunction( AlphaFunction::DEFAULT ),
+  timePeriodDelay( 0.0f ),
+  timePeriodDuration( 1.0f )
+{
+}
+
+void TestAnimationData::Add( AnimationDataElement* animationDataElement )
+{
+  mAnimationDataList.PushBack( animationDataElement );
+}
+
+std::size_t TestAnimationData::Size() const
+{
+  return mAnimationDataList.Size();
+}
+
+void TestAnimationData::Clear()
+{
+  AnimationDataList::Iterator end = mAnimationDataList.End();
+  for( AnimationDataList::Iterator iter = mAnimationDataList.Begin(); iter != end; ++iter )
+  {
+    delete ( *iter );
+  }
+  mAnimationDataList.Clear();
+}
+
+
+void NewAnimator( const Property::Map& map, TestAnimationData::AnimationDataElement& element )
+{
+  // Now set the properties, or create children
+  for( unsigned int i = 0, animationMapCount = map.Count(); i < animationMapCount; ++i )
+  {
+    const StringValuePair& pair( map.GetPair( i ) );
+    const std::string& key( pair.first );
+    const Property::Value& value( pair.second );
+
+    if( key == "actor" || key == "target" )
+    {
+      element.target = value.Get< std::string >();
+    }
+    else if( key == "property" )
+    {
+      element.property = value.Get< std::string >();
+    }
+    else if( key == "value" )
+    {
+      element.value = value;
+    }
+    else if( key == "alphaFunction" )
+    {
+      std::string alphaFunctionValue = value.Get< std::string >();
+
+      if( alphaFunctionValue == "LINEAR" )
+      {
+        element.alphaFunction = AlphaFunction::LINEAR;
+      }
+      else if( alphaFunctionValue == "REVERSE" )
+      {
+        element.alphaFunction = AlphaFunction::REVERSE;
+      }
+      else if( alphaFunctionValue == "EASE_IN_SQUARE" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_IN_SQUARE;
+      }
+      else if( alphaFunctionValue == "EASE_OUT_SQUARE" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_OUT_SQUARE;
+      }
+      else if( alphaFunctionValue == "EASE_IN" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_IN;
+      }
+      else if( alphaFunctionValue == "EASE_OUT" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_OUT;
+      }
+      else if( alphaFunctionValue == "EASE_IN_OUT" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_IN_OUT;
+      }
+      else if( alphaFunctionValue == "EASE_IN_SINE" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_IN_SINE;
+      }
+      else if( alphaFunctionValue == "EASE_OUT_SINE" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_OUT_SINE;
+      }
+      else if( alphaFunctionValue == "EASE_IN_OUT_SINE" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_IN_OUT_SINE;
+      }
+      else if( alphaFunctionValue == "BOUNCE" )
+      {
+        element.alphaFunction = AlphaFunction::BOUNCE;
+      }
+      else if( alphaFunctionValue == "SIN" )
+      {
+        element.alphaFunction = AlphaFunction::SIN;
+      }
+      else if( alphaFunctionValue == "EASE_OUT_BACK" )
+      {
+        element.alphaFunction = AlphaFunction::EASE_OUT_BACK;
+      }
+    }
+    else if( key == "timePeriod" )
+    {
+      Property::Map timeMap = value.Get< Property::Map >();
+      for( unsigned int i = 0; i < timeMap.Count(); ++i )
+      {
+        const StringValuePair& pair( timeMap.GetPair( i ) );
+        if( pair.first == "delay" )
+        {
+          element.timePeriodDelay = pair.second.Get< float >();
+        }
+        else if( pair.first == "duration" )
+        {
+          element.timePeriodDuration = pair.second.Get< float >();
+        }
+      }
+    }
+    else if( key == "animator" )
+    {
+      if( value.GetType() == Property::MAP )
+      {
+        Property::Map* map = value.GetMap();
+        const Property::Map& mapref = *map;
+        NewAnimator( mapref, element ); // Merge the map into element
+      }
+    }
+  }
+}
+
+void NewAnimation( const Property::Map& map, TestAnimationData& outputAnimationData )
+{
+  TestAnimationData::AnimationDataElement* element = new TestAnimationData::AnimationDataElement();
+  NewAnimator( map, *element );
+
+  outputAnimationData.Add( element );
+}
+
+void NewAnimation( const Property::Array& array, TestAnimationData& outputAnimationData )
+{
+  for(unsigned int i=0; i<array.Size(); ++i )
+  {
+    TestAnimationData::AnimationDataElement* element = new TestAnimationData::AnimationDataElement();
+    const Property::Value& value = array.GetElementAt(i);
+    if( value.GetType() == Property::MAP )
+    {
+      Property::Map* map = value.GetMap();
+      NewAnimator( *map, *element );
+      outputAnimationData.Add( element );
+    }
+  }
+}
+
+} // Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-animation-data.h
new file mode 100644 (file)
index 0000000..ffd5b17
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DALI_TOOLKIT_TEST_TEST_ANIMATION_DATA_H
+#define DALI_TOOLKIT_TEST_TEST_ANIMATION_DATA_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.
+ */
+
+#include <dali/dali.h>
+#include <string>
+
+namespace Test
+{
+
+class TestAnimationData
+{
+public:
+  TestAnimationData();
+  ~TestAnimationData();
+
+  /**
+   * @brief AnimationDataElement Describes one part of an animation.
+   */
+  struct AnimationDataElement
+  {
+    std::string target;
+    std::string property;
+    Dali::Property::Value value;
+    Dali::AlphaFunction::BuiltinFunction alphaFunction;
+    float timePeriodDelay;
+    float timePeriodDuration;
+
+    AnimationDataElement();
+  };
+
+  /**
+   * @brief AnimationData holds the required data required to define an
+   * animation to be performed on a property source.
+   */
+  typedef Dali::Vector< AnimationDataElement* > AnimationDataList;
+
+  /**
+   * @brief Adds one AnimationDataElement to the list to describe one animation.
+   * @param[in] animationDataElement A pre-populated struct to add
+   */
+  void Add( AnimationDataElement* animationDataElement );
+
+  std::size_t Size() const;
+
+  void Clear();
+
+  AnimationDataList mAnimationDataList;
+};
+
+void NewAnimator( const Dali::Property::Map& map, TestAnimationData::AnimationDataElement& element );
+void NewAnimation( const Dali::Property::Map& map, TestAnimationData& outputAnimationData );
+void NewAnimation( const Dali::Property::Array& array, TestAnimationData& outputAnimationData );
+} // Test
+
+#endif  //DALI_TOOLKIT_TEST_TEST_ANIMATION_DATA_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.cpp
new file mode 100644 (file)
index 0000000..f85f14d
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2020 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 "test-application.h"
+
+namespace Dali
+{
+
+bool TestApplication::mLoggingEnabled = true;
+
+TestApplication::TestApplication( uint32_t surfaceWidth,
+                                  uint32_t surfaceHeight,
+                                  uint32_t  horizontalDpi,
+                                  uint32_t  verticalDpi,
+                                  bool initialize )
+: mCore( NULL ),
+  mSurfaceWidth( surfaceWidth ),
+  mSurfaceHeight( surfaceHeight ),
+  mFrame( 0u ),
+  mDpi{ horizontalDpi, verticalDpi },
+  mLastVSyncTime(0u)
+{
+  if( initialize )
+  {
+    Initialize();
+  }
+}
+
+void TestApplication::Initialize()
+{
+  CreateCore();
+  CreateScene();
+  InitializeCore();
+}
+
+void TestApplication::CreateCore()
+{
+  // We always need the first update!
+  mStatus.keepUpdating = Integration::KeepUpdating::STAGE_KEEP_RENDERING;
+
+  mCore = Dali::Integration::Core::New( mRenderController,
+                                        mPlatformAbstraction,
+                                        mGlAbstraction,
+                                        mGlSyncAbstraction,
+                                        mGlContextHelperAbstraction,
+                                        Integration::RenderToFrameBuffer::FALSE,
+                                        Integration::DepthBufferAvailable::TRUE,
+                                        Integration::StencilBufferAvailable::TRUE );
+
+  mCore->ContextCreated();
+
+  Dali::Integration::Log::LogFunction logFunction(&TestApplication::LogMessage);
+  Dali::Integration::Log::InstallLogFunction(logFunction);
+
+  Dali::Integration::Trace::LogContextFunction logContextFunction(&TestApplication::LogContext);
+  Dali::Integration::Trace::InstallLogContextFunction( logContextFunction );
+
+  Dali::Integration::Trace::LogContext( true, "Test" );
+}
+
+void TestApplication::CreateScene()
+{
+  mScene = Dali::Integration::Scene::New( Size( static_cast<float>( mSurfaceWidth ), static_cast<float>( mSurfaceHeight ) ) );
+  mScene.SetDpi( Vector2( static_cast<float>( mDpi.x ), static_cast<float>( mDpi.y ) ) );
+}
+
+void TestApplication::InitializeCore()
+{
+  mCore->SceneCreated();
+  mCore->Initialize();
+}
+
+TestApplication::~TestApplication()
+{
+  Dali::Integration::Log::UninstallLogFunction();
+  delete mCore;
+}
+
+void TestApplication::LogContext( bool start, const char* tag )
+{
+  if( start )
+  {
+    fprintf(stderr, "INFO: Trace Start: %s\n", tag);
+  }
+  else
+  {
+    fprintf(stderr, "INFO: Trace End: %s\n", tag);
+  }
+}
+
+void TestApplication::LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  if( mLoggingEnabled )
+  {
+    switch(level)
+    {
+      case Dali::Integration::Log::DebugInfo:
+        fprintf(stderr, "INFO: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugWarning:
+        fprintf(stderr, "WARN: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugError:
+        fprintf(stderr, "ERROR: %s", message.c_str());
+        break;
+      default:
+        fprintf(stderr, "DEFAULT: %s", message.c_str());
+        break;
+    }
+  }
+}
+
+Dali::Integration::Core& TestApplication::GetCore()
+{
+  return *mCore;
+}
+
+TestPlatformAbstraction& TestApplication::GetPlatform()
+{
+  return mPlatformAbstraction;
+}
+
+TestRenderController& TestApplication::GetRenderController()
+{
+  return mRenderController;
+}
+
+TestGlAbstraction& TestApplication::GetGlAbstraction()
+{
+  return mGlAbstraction;
+}
+
+TestGlSyncAbstraction& TestApplication::GetGlSyncAbstraction()
+{
+  return mGlSyncAbstraction;
+}
+
+TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
+{
+  return mGlContextHelperAbstraction;
+}
+
+void TestApplication::ProcessEvent(const Integration::Event& event)
+{
+  mCore->QueueEvent(event);
+  mCore->ProcessEvents();
+}
+
+void TestApplication::SendNotification()
+{
+  mCore->ProcessEvents();
+}
+
+void TestApplication::DoUpdate( uint32_t intervalMilliseconds, const char* location )
+{
+  if( GetUpdateStatus() == 0 &&
+      mRenderStatus.NeedsUpdate() == false &&
+      ! GetRenderController().WasCalled(TestRenderController::RequestUpdateFunc) )
+  {
+    fprintf(stderr, "WARNING - Update not required :%s\n", location==NULL?"NULL":location);
+  }
+
+  uint32_t nextVSyncTime = mLastVSyncTime + intervalMilliseconds;
+  float elapsedSeconds = static_cast<float>( intervalMilliseconds ) * 0.001f;
+
+  mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false );
+
+  GetRenderController().Initialize();
+
+  mLastVSyncTime = nextVSyncTime;
+}
+
+bool TestApplication::Render( uint32_t intervalMilliseconds, const char* location )
+{
+  DoUpdate( intervalMilliseconds, location );
+
+  mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
+  mCore->RenderScene( mScene, true /*render the off-screen buffers*/);
+  mCore->RenderScene( mScene, false /*render the surface*/);
+  mCore->PostRender( false /*do not skip rendering*/ );
+
+  mFrame++;
+
+  return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
+}
+
+uint32_t TestApplication::GetUpdateStatus()
+{
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::UpdateOnly( uint32_t intervalMilliseconds  )
+{
+  DoUpdate( intervalMilliseconds );
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::GetRenderNeedsUpdate()
+{
+  return mRenderStatus.NeedsUpdate();
+}
+
+bool TestApplication::RenderOnly( )
+{
+  // Update Time values
+  mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
+  mCore->RenderScene( mScene, true /*render the off-screen buffers*/);
+  mCore->RenderScene( mScene, false /*render the surface*/);
+  mCore->PostRender( false /*do not skip rendering*/ );
+
+  mFrame++;
+
+  return mRenderStatus.NeedsUpdate();
+}
+
+void TestApplication::ResetContext()
+{
+  mCore->ContextDestroyed();
+  mGlAbstraction.Initialize();
+  mCore->ContextCreated();
+}
+
+uint32_t TestApplication::Wait( uint32_t durationToWait )
+{
+  int time = 0;
+
+  for(uint32_t i = 0; i <= ( durationToWait / RENDER_FRAME_INTERVAL); i++)
+  {
+    SendNotification();
+    Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+  return time;
+}
+
+} // Namespace dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-application.h
new file mode 100644 (file)
index 0000000..a922e23
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_TEST_APPLICATION_H
+#define DALI_TEST_APPLICATION_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <test-platform-abstraction.h>
+#include "test-gl-sync-abstraction.h"
+#include "test-gl-abstraction.h"
+#include "test-gl-context-helper-abstraction.h"
+#include "test-render-controller.h"
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/resource-policies.h>
+#include <dali/integration-api/trace.h>
+#include <dali/integration-api/scene.h>
+
+namespace Dali
+{
+
+class DALI_CORE_API TestApplication : public ConnectionTracker
+{
+public:
+
+  // Default values derived from H2 device.
+  static const uint32_t DEFAULT_SURFACE_WIDTH = 480;
+  static const uint32_t DEFAULT_SURFACE_HEIGHT = 800;
+
+  static constexpr uint32_t DEFAULT_HORIZONTAL_DPI = 220;
+  static constexpr uint32_t DEFAULT_VERTICAL_DPI   = 217;
+
+  static const uint32_t DEFAULT_RENDER_INTERVAL = 1;
+
+  static const uint32_t RENDER_FRAME_INTERVAL = 16;
+
+  TestApplication( uint32_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                   uint32_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                   uint32_t horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                   uint32_t verticalDpi   = DEFAULT_VERTICAL_DPI,
+                   bool initialize = true );
+
+  void Initialize();
+  void CreateCore();
+  void CreateScene();
+  void InitializeCore();
+  virtual ~TestApplication();
+  static void LogMessage( Dali::Integration::Log::DebugPriority level, std::string& message );
+  static void LogContext( bool start, const char* tag );
+  Dali::Integration::Core& GetCore();
+  TestPlatformAbstraction& GetPlatform();
+  TestRenderController& GetRenderController();
+  TestGlAbstraction& GetGlAbstraction();
+  TestGlSyncAbstraction& GetGlSyncAbstraction();
+  TestGlContextHelperAbstraction& GetGlContextHelperAbstraction();
+  void ProcessEvent(const Integration::Event& event);
+  void SendNotification();
+  bool Render( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location=NULL );
+  uint32_t GetUpdateStatus();
+  bool UpdateOnly( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL );
+  bool RenderOnly( );
+  void ResetContext();
+  bool GetRenderNeedsUpdate();
+  uint32_t Wait( uint32_t durationToWait );
+  static void EnableLogging( bool enabled )
+  {
+    mLoggingEnabled = enabled;
+  }
+
+  Integration::Scene GetScene() const
+  {
+    return mScene;
+  }
+
+private:
+  void DoUpdate( uint32_t intervalMilliseconds, const char* location=NULL );
+
+protected:
+  TestPlatformAbstraction   mPlatformAbstraction;
+  TestRenderController      mRenderController;
+  TestGlAbstraction         mGlAbstraction;
+  TestGlSyncAbstraction     mGlSyncAbstraction;
+  TestGlContextHelperAbstraction mGlContextHelperAbstraction;
+
+  Integration::UpdateStatus mStatus;
+  Integration::RenderStatus mRenderStatus;
+
+  Integration::Core* mCore;
+  Dali::Integration::Scene mScene;
+
+  uint32_t mSurfaceWidth;
+  uint32_t mSurfaceHeight;
+  uint32_t mFrame;
+
+  struct { uint32_t x; uint32_t y; } mDpi;
+  uint32_t mLastVSyncTime;
+  static bool mLoggingEnabled;
+};
+
+} // Dali
+
+#endif // DALI_TEST_APPLICATION_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.cpp
new file mode 100644 (file)
index 0000000..3d25205
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * 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/dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <test-button.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+Property::Value ConvertAnimationMap( const Test::TestAnimationData& animationMap )
+{
+  // We have a data structure. Now convert it back into an array:
+  Property::Array animators;
+  for( unsigned int i=0; i<animationMap.Size(); ++i )
+  {
+    Property::Map animator;
+    animator.Insert( "target", Property::Value(animationMap.mAnimationDataList[i]->target ));
+    animator.Insert( "property", Property::Value(animationMap.mAnimationDataList[i]->property ));
+    animator.Insert( "value", Property::Value(animationMap.mAnimationDataList[i]->value ));
+    animator.Insert( "alphaFunction", Property::Value(animationMap.mAnimationDataList[i]->alphaFunction ));
+    animator.Insert( "timePeriodDelay", Property::Value(animationMap.mAnimationDataList[i]->timePeriodDelay ));
+    animator.Insert( "timePeriodDuration", Property::Value(animationMap.mAnimationDataList[i]->timePeriodDuration ));
+    animators.PushBack( animator );
+  }
+  Property::Value animation( animators );
+  return animation;
+}
+}
+
+namespace Test
+{
+namespace Impl
+{
+
+Test::TestButton TestButton::New()
+{
+  IntrusivePtr<TestButton> internalTestButton = new TestButton();
+  Test::TestButton button( *internalTestButton );
+  internalTestButton->Initialize();
+  return button;
+}
+
+TestButton::TestButton()
+: Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS|REQUIRES_STYLE_CHANGE_SIGNALS ) )
+{
+}
+
+TestButton::~TestButton()
+{
+}
+
+void TestButton::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Test::TestButton button = Test::TestButton::DownCast( Dali::BaseHandle( object ) );
+
+  if ( button )
+  {
+    TestButton& buttonImpl = GetImpl(button);
+    switch ( index )
+    {
+      case Test::TestButton::Property::PRESS_TRANSITION:
+      {
+        if( value.GetType() == Property::MAP )
+        {
+          Property::Map* valueMap = value.GetMap();
+          buttonImpl.mPressTransitionData.Clear();
+          NewAnimation( *valueMap, buttonImpl.mPressTransitionData );
+        }
+        else if( value.GetType() == Property::ARRAY )
+        {
+          Property::Array* valueArray = value.GetArray();
+          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;
+      }
+    }
+  }
+}
+
+Property::Value TestButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Test::TestButton button = Test::TestButton::DownCast( Dali::BaseHandle( object ) );
+
+  Property::Value value;
+
+  if ( button )
+  {
+    TestButton& buttonImpl = GetImpl(button);
+    switch ( propertyIndex )
+    {
+      case Test::TestButton::Property::PRESS_TRANSITION:
+      {
+        return ConvertAnimationMap(buttonImpl.mPressTransitionData);
+      }
+      case Test::TestButton::Property::RELEASE_TRANSITION:
+      {
+        return ConvertAnimationMap(buttonImpl.mReleaseTransitionData);
+      }
+      case Test::TestButton::Property::DISABLED_TRANSITION:
+      {
+        return ConvertAnimationMap(buttonImpl.mDisabledTransitionData);
+      }
+      case Test::TestButton::Property::ENABLED_TRANSITION:
+      {
+        return ConvertAnimationMap(buttonImpl.mEnabledTransitionData);
+      }
+      case Test::TestButton::Property::BACKGROUND_COLOR:
+      {
+        return Property::Value(buttonImpl.mBackgroundColor);
+      }
+      case Test::TestButton::Property::FOREGROUND_COLOR:
+      {
+        return Property::Value(buttonImpl.mForegroundColor);
+      }
+    }
+  }
+  return Property::Value();
+}
+
+BaseHandle Create()
+{
+  return TestButton::New();
+}
+
+// Generates typeRegistration static variable.
+DALI_TYPE_REGISTRATION_BEGIN( Test::TestButton, Dali::Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Test, TestButton, "pressTransition", ARRAY, PRESS_TRANSITION )
+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()
+
+} // Impl Namespace
+
+TestButton::TestButton()
+: Control()
+{
+}
+
+TestButton::TestButton(const TestButton& button)
+: Control( button )
+{
+}
+
+TestButton::TestButton(Impl::TestButton& impl)
+: Control(impl)
+{
+}
+
+TestButton::TestButton(Dali::Internal::CustomActor* internal)
+: Control(internal)
+{
+  VerifyCustomActorPointer<Impl::TestButton>(internal);
+}
+
+TestButton& TestButton::operator=( const TestButton& button)
+{
+  if(&button != this)
+  {
+    Control::operator=(button);
+  }
+  return *this;
+}
+
+TestButton::~TestButton()
+{
+}
+
+TestButton TestButton::New()
+{
+  return Impl::TestButton::New();
+}
+
+TestButton TestButton::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TestButton,Impl::TestButton>(handle);
+}
+
+} // namespace Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.h
new file mode 100644 (file)
index 0000000..c9a29e4
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_TOOLKIT_TEST_TEST_BUTTON_H
+#define DALI_TOOLKIT_TEST_TEST_BUTTON_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.
+ */
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <test-animation-data.h>
+
+namespace Test
+{
+namespace Impl
+{
+class TestButton;
+}
+
+class TestButton : public Dali::Toolkit::Control
+{
+public:
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000
+  };
+  struct Property
+  {
+    enum
+    {
+      PRESS_TRANSITION = PROPERTY_START_INDEX,
+      RELEASE_TRANSITION,
+      DISABLED_TRANSITION,
+      ENABLED_TRANSITION,
+      BACKGROUND_COLOR,
+      FOREGROUND_COLOR
+    };
+  };
+  TestButton();
+  TestButton(const TestButton& button);
+  TestButton(Impl::TestButton& impl);
+  TestButton(Dali::Internal::CustomActor* internal);
+  TestButton& operator=( const TestButton& button);
+  ~TestButton();
+  static TestButton New();
+  static TestButton DownCast( Dali::BaseHandle handle );
+};
+
+namespace Impl
+{
+
+class TestButton : public Dali::Toolkit::Internal::Control
+{
+public:
+  static Test::TestButton New();
+
+  static void SetProperty( Dali::BaseObject* object,
+                           Dali::Property::Index index,
+                           const Dali::Property::Value& value );
+
+  static Dali::Property::Value GetProperty( Dali::BaseObject* object,
+                                            Dali::Property::Index propertyIndex );
+
+protected:
+  TestButton();
+  virtual ~TestButton();
+
+public:
+  Test::TestAnimationData mPressTransitionData;
+  Test::TestAnimationData mReleaseTransitionData;
+  Test::TestAnimationData mDisabledTransitionData;
+  Test::TestAnimationData mEnabledTransitionData;
+  Dali::Vector4 mBackgroundColor;
+  Dali::Vector4 mForegroundColor;
+};
+
+inline TestButton& GetImpl( Test::TestButton& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  Dali::RefObject& object = handle.GetImplementation();
+  return static_cast<TestButton&>( object );
+}
+
+inline const TestButton& GetImpl( const Test::TestButton& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  const Dali::RefObject& object = handle.GetImplementation();
+  return static_cast<const TestButton&>( object );
+}
+
+} // Impl
+} // Test
+
+
+
+#endif // DALI_TOOLKIT_TEST_TEST_BUTTON_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-compare-types.h
new file mode 100644 (file)
index 0000000..5870028
--- /dev/null
@@ -0,0 +1,223 @@
+#ifndef DALI_TEST_COMPARE_TYPES_H
+#define DALI_TEST_COMPARE_TYPES_H
+
+/*
+ * Copyright (c) 2017 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/dali-core.h>
+using namespace Dali;
+
+
+template <typename Type>
+inline bool CompareType(Type value1, Type value2, float epsilon)
+{
+  return value1 == value2;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<float>(float value1, float value2, float epsilon)
+{
+  return fabsf(value1 - value2) < epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector2>(Vector2 vector1, Vector2 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon && fabsf(vector1.y - vector2.y)<epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector3 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector3>(Vector3 vector1, Vector3 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon;
+}
+
+
+/**
+ * A helper for fuzzy-comparing Vector4 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector4>(Vector4 vector1, Vector4 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon &&
+         fabsf(vector1.w - vector2.w)<epsilon;
+}
+
+template <>
+inline bool CompareType<Quaternion>(Quaternion q1, Quaternion q2, float epsilon)
+{
+  Quaternion q2N = -q2; // These quaternions represent the same rotation
+  return CompareType<Vector4>(q1.mVector, q2.mVector, epsilon) || CompareType<Vector4>(q1.mVector, q2N.mVector, epsilon);
+}
+
+template <>
+inline bool CompareType<Radian>(Radian q1, Radian q2, float epsilon)
+{
+  return CompareType<float>(q1.radian, q2.radian, epsilon);
+}
+
+template <>
+inline bool CompareType<Degree>(Degree q1, Degree q2, float epsilon)
+{
+  return CompareType<float>(q1.degree, q2.degree, epsilon);
+}
+
+template <>
+inline bool CompareType<Extents>(Extents extents1, Extents extents2, float epsilon)
+{
+  return (extents1.start == extents2.start) &&
+         (extents1.end == extents2.end) &&
+         (extents1.top == extents2.top) &&
+         (extents1.bottom == extents2.bottom);
+}
+
+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;
+  }
+
+  bool result = false;
+  switch(type)
+  {
+    case Property::BOOLEAN:
+    {
+      bool a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  a == b;
+      break;
+    }
+    case Property::INTEGER:
+    {
+      int a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  a == b;
+      break;
+    }
+    case Property::FLOAT:
+    {
+      float a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  CompareType<float>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR2:
+    {
+      Vector2 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector2>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR3:
+    {
+      Vector3 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector3>(a, b, epsilon);
+      break;
+    }
+    case Property::RECTANGLE:
+    case Property::VECTOR4:
+    {
+      Vector4 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector4>(a, b, epsilon);
+      break;
+    }
+    case Property::ROTATION:
+    {
+      Quaternion a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Quaternion>(a, b, epsilon);
+      break;
+    }
+    case Property::STRING:
+    {
+      std::string a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = (a.compare(b) == 0);
+      break;
+    }
+    case Property::MATRIX:
+    case Property::MATRIX3:
+    case Property::ARRAY:
+    case Property::MAP:
+    {
+      //TODO: Implement this?
+      DALI_ASSERT_ALWAYS( 0 && "Not implemented");
+      result = false;
+      break;
+    }
+    case Property::EXTENTS:
+    {
+      Extents a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Extents>( a, b, epsilon );
+      break;
+    }
+    case Property::NONE:
+    {
+      result = false;
+      break;
+    }
+  }
+
+  return result;
+}
+
+
+
+#endif
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.cpp
new file mode 100644 (file)
index 0000000..c0b55ce
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2019 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 "test-gesture-generator.h"
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/events/touch-event-integ.h>
+
+namespace
+{
+const uint32_t RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
+
+Integration::TouchEvent GenerateSingleTouch( PointState::Type state, const Vector2& screenPosition, uint32_t time )
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( state );
+  point.SetDeviceId(4);
+  point.SetScreenPosition( screenPosition );
+  point.SetDeviceClass( Device::Class::TOUCH );
+  point.SetDeviceSubclass( Device::Subclass::NONE );
+  touchEvent.points.push_back( point );
+  touchEvent.time = time;
+  return touchEvent;
+}
+
+Integration::TouchEvent GenerateDoubleTouch( PointState::Type stateA, const Vector2& screenPositionA, PointState::Type stateB, const Vector2& screenPositionB, uint32_t time )
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( stateA );
+  point.SetDeviceId(4);
+  point.SetScreenPosition( screenPositionA );
+  point.SetDeviceClass( Device::Class::TOUCH );
+  point.SetDeviceSubclass( Device::Subclass::NONE );
+  touchEvent.points.push_back( point );
+  point.SetScreenPosition( screenPositionB );
+  point.SetState( stateB);
+  point.SetDeviceId(7);
+  touchEvent.points.push_back( point );
+  touchEvent.time = time;
+  return touchEvent;
+}
+} // namespace
+
+namespace Dali
+{
+uint32_t TestGetFrameInterval()
+{
+  return RENDER_FRAME_INTERVAL;
+}
+
+void TestStartLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( x, y ), time ) );
+}
+
+void TestTriggerLongPress( TestApplication& application )
+{
+  application.GetPlatform().TriggerTimer();
+}
+
+void TestGenerateLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  TestStartLongPress( application, x, y, time );
+  TestTriggerLongPress( application );
+}
+
+void TestEndLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( x, y ), time ) );
+}
+
+void TestGeneratePinch( TestApplication& application)
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), PointState::DOWN, Vector2( 20.0f, 90.0f ), 150 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 28.0f ), PointState::MOTION, Vector2( 20.0f, 82.0f ), 160 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 37.0f ), PointState::MOTION, Vector2( 20.0f, 74.0f ), 170 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 46.0f ), PointState::MOTION, Vector2( 20.0f, 66.0f ), 180 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 55.0f ), PointState::MOTION, Vector2( 20.0f, 58.0f ), 190 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( 20.0f, 55.0f ), PointState::UP, Vector2( 20.0f, 58.0f ), 200 ) );
+}
+
+void TestStartPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, a1, PointState::DOWN, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 150 ) );
+}
+
+void TestContinuePinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time +150 ) );
+}
+
+void TestEndPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, a2, PointState::UP, b2, time +50 ) );
+}
+
+void TestGenerateMiniPan( TestApplication& application)
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), 250 ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, Vector2( 20.0f, 40.0f ), 251 ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( 20.0f, 40.0f ), 255 ) );
+}
+
+void TestStartPan( TestApplication& application, Vector2 start, Vector2 end, uint32_t& time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, start, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, end, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, end, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+}
+
+void TestMovePan( TestApplication& application, Vector2 pos, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, pos, time ) );
+}
+
+void TestEndPan( TestApplication& application, Vector2 pos, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, pos, time ) );
+}
+
+void TestGenerateTap( TestApplication& application, float x, float y, uint32_t time_down )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( x, y ), time_down ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( x, y ), time_down + 20 ) );
+}
+
+void TestGenerateTwoPointTap( TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( x1, y1 ), PointState::DOWN, Vector2( x2, y2 ), time_down ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( x1, y1 ), PointState::UP, Vector2( x2, y2 ), time_down + 20 ) );
+}
+
+void TestGenerateRotation( TestApplication& application )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), PointState::DOWN, Vector2( 20.0f, 90.0f ), 150 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 25.0f, 95.0f ), 160 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 30.0f, 100.0f ), 170 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 35.0f, 105.0f ), 180 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 40.0f, 110.0f ), 190 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( 20.0f, 20.0f ), PointState::UP, Vector2( 45.0f, 115.0f ), 200 ) );
+}
+
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, a1, PointState::DOWN, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 150 ) );
+}
+
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time +150 ) );
+}
+
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, a2, PointState::UP, b2, time +50 ) );
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gesture-generator.h
new file mode 100644 (file)
index 0000000..18051cf
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef DALI_TEST_GESTURE_GENERATOR_H
+#define DALI_TEST_GESTURE_GENERATOR_H
+
+/*
+ * Copyright (c) 2019 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 "test-application.h"
+
+namespace Dali
+{
+/**
+ * These functions use touch events to trigger a gesture, assuming the default gesture parameters are used
+ */
+
+/**
+ * Returns the frame interval used in ms
+ */
+uint32_t TestGetFrameInterval();
+
+/**
+ * Produces the initial touch of a long press
+ */
+void TestStartLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * Triggers the timer to begin a long press gesture
+ */
+void TestTriggerLongPress( TestApplication& application );
+
+/**
+ * Produces the initial press and triggers the timer to begin a long press gesture
+ */
+void TestGenerateLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * End a long press by lifting the touch
+ */
+void TestEndLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * Produces a vertical pinch gesture between (20,20) and (20,90)
+ */
+void TestGeneratePinch( TestApplication& application );
+
+/**
+ * Produces the gesture started event of a pinch, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestStartPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture continuing event of a pinch, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestContinuePinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture finished event of a pinch, using 2 touches, 50ms apart
+ */
+void TestEndPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a pan gesture from (20,20) to (20,40)
+ */
+void TestGenerateMiniPan( TestApplication& application );
+
+/**
+ * Produces the start event of a pan gesture, assuming minimum distance moved between start and end is greater than 15
+ * in either direction or 11 in both (x&y). Time will be incremented using the standard frame interval per touch movement
+ */
+void TestStartPan( TestApplication& application, Vector2 start, Vector2 end, uint32_t& time );
+
+/**
+ * Continues a pan event by creating a single touch at pos.
+ * N.B This does not increment the time
+ */
+void TestMovePan( TestApplication& application, Vector2 pos, uint32_t time = 400);
+
+/**
+ * End a pan gesture at position pos
+ */
+void TestEndPan( TestApplication& application, Vector2 pos, uint32_t time = 500);
+
+/**
+ * Produces a single point tap gesture with a 20ms interval
+ */
+void TestGenerateTap( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time_down = 100 );
+
+/**
+ * Produce a tap gesture with two touch points and a 20ms interval
+ */
+void TestGenerateTwoPointTap( TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down );
+
+/**
+ * Produces a rotation gesture.
+ */
+void TestGenerateRotation( TestApplication& application );
+
+/**
+ * Produces the gesture started event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture continuing event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture finished event of a rotation, using 2 touches, 50ms apart
+ */
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+} // namespace Dali
+
+#endif // DALI_TEST_GESTURE_GENERATOR_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
new file mode 100644 (file)
index 0000000..98a2fa5
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 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 "test-gl-abstraction.h"
+
+namespace Dali
+{
+
+TestGlAbstraction::TestGlAbstraction()
+{
+  Initialize();
+}
+
+TestGlAbstraction::~TestGlAbstraction() {}
+
+void TestGlAbstraction::Initialize()
+{
+  mCurrentProgram = 0;
+  mCompileStatus = GL_TRUE;
+  mLinkStatus = GL_TRUE;
+  mNumberOfActiveUniforms = 0;
+  mGetAttribLocationResult = 0;
+  mGetErrorResult = 0;
+  mGetStringResult = NULL;
+  mIsBufferResult = 0;
+  mIsEnabledResult = 0;
+  mIsFramebufferResult = 0;
+  mIsProgramResult = 0;
+  mIsRenderbufferResult = 0;
+  mIsShaderResult = 0;
+  mIsTextureResult = 0;
+  mActiveTextureUnit = 0;
+  mCheckFramebufferStatusResult = 0;
+  mFramebufferStatus = 0;
+  mFramebufferDepthAttached = 0;
+  mFramebufferStencilAttached = 0;
+  mFramebufferColorAttachmentCount = 0;
+  mFrameBufferColorStatus = 0;
+  mNumBinaryFormats = 0;
+  mBinaryFormats = 0;
+  mProgramBinaryLength = 0;
+
+  mVertexAttribArrayChanged = false;
+  mGetProgramBinaryCalled = false;
+
+  mLastShaderCompiled = 0;
+  mLastClearBitMask = 0;
+  mLastClearColor = Color::TRANSPARENT;
+  mClearCount = 0;
+
+  mLastBlendEquationRgb   = 0;
+  mLastBlendEquationAlpha = 0;
+  mLastBlendFuncSrcRgb    = 0;
+  mLastBlendFuncDstRgb    = 0;
+  mLastBlendFuncSrcAlpha  = 0;
+  mLastBlendFuncDstAlpha  = 0;
+  mLastAutoTextureIdUsed = 0;
+  mNumGeneratedTextures = 0;
+  mLastShaderIdUsed = 0;
+  mLastProgramIdUsed = 0;
+  mLastUniformIdUsed = 0;
+  mLastDepthMask = false;
+
+  mUniforms.clear();
+  mProgramUniforms1i.clear();
+  mProgramUniforms1f.clear();
+  mProgramUniforms2f.clear();
+  mProgramUniforms3f.clear();
+  mProgramUniforms4f.clear();
+
+  mCullFaceTrace.Reset();
+  mDepthFunctionTrace.Reset();
+  mEnableDisableTrace.Reset();
+  mShaderTrace.Reset();
+  mStencilFunctionTrace.Reset();
+  mScissorTrace.Reset();
+  mTextureTrace.Reset();
+  mTexParamaterTrace.Reset();
+  mDrawTrace.Reset();
+
+  for( unsigned int i=0; i<MAX_ATTRIBUTE_CACHE_SIZE; ++i )
+  {
+    mVertexAttribArrayState[i] = false;
+  }
+}
+
+void TestGlAbstraction::PreRender()
+{
+}
+
+void TestGlAbstraction::PostRender()
+{
+}
+
+bool TestGlAbstraction::IsSurfacelessContextSupported() const
+{
+  return true;
+}
+
+bool TestGlAbstraction::TextureRequiresConverting( const GLenum imageGlFormat, const GLenum textureGlFormat, const bool isSubImage ) const
+{
+  return ( ( imageGlFormat == GL_RGB ) && ( textureGlFormat == GL_RGBA ) );
+}
+
+} // Namespace dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams( "Enable", out.str() );
+  return blendEnabled;
+}
+
+bool BlendDisabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams( "Disable", out.str() );
+  return blendEnabled;
+}
+
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h
new file mode 100644 (file)
index 0000000..9f458fc
--- /dev/null
@@ -0,0 +1,2417 @@
+#ifndef TEST_GL_ABSTRACTION_H
+#define TEST_GL_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2020 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 <sstream>
+#include <string>
+#include <cstring>
+#include <map>
+#include <cstdio>
+#include <cstring> // for strcmp
+#include <typeinfo>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/rendering/frame-buffer-devel.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/gl-defines.h>
+#include <test-trace-call-stack.h>
+#include <test-compare-types.h>
+
+namespace Dali
+{
+
+static const unsigned int MAX_ATTRIBUTE_CACHE_SIZE = 64;
+static const char *mStdAttribs[MAX_ATTRIBUTE_CACHE_SIZE] =
+{
+    "aPosition",    // ATTRIB_POSITION
+    "aNormal",      // ATTRIB_NORMAL
+    "aTexCoord",    // ATTRIB_TEXCOORD
+    "aColor",       // ATTRIB_COLOR
+    "aBoneWeights", // ATTRIB_BONE_WEIGHTS
+    "aBoneIndices"  // ATTRIB_BONE_INDICES
+};
+
+class DALI_CORE_API TestGlAbstraction: public Dali::Integration::GlAbstraction
+{
+public:
+  TestGlAbstraction();
+  ~TestGlAbstraction();
+  void Initialize();
+
+  void PreRender();
+  void PostRender();
+
+  bool IsSurfacelessContextSupported() const;
+
+  bool TextureRequiresConverting( const GLenum imageGlFormat, const GLenum textureGlFormat, const bool isSubImage ) const;
+
+  /* OpenGL ES 2.0 */
+
+  inline void ActiveTexture( GLenum textureUnit )
+  {
+    mActiveTextureUnit = textureUnit - GL_TEXTURE0;
+  }
+
+  inline GLenum GetActiveTextureUnit() const
+  {
+    return mActiveTextureUnit + GL_TEXTURE0;
+  }
+
+  inline void AttachShader( GLuint program, GLuint shader )
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    namedParams["shader"] = ToString(shader);
+    mShaderTrace.PushCall("AttachShader", out.str(), namedParams);
+  }
+
+  inline void BindAttribLocation( GLuint program, GLuint index, const char* name )
+  {
+  }
+
+  inline void BindBuffer( GLenum target, GLuint buffer )
+  {
+  }
+
+  inline void BindFramebuffer( GLenum target, GLuint framebuffer )
+  {
+    //Add 010 bit;
+    mFramebufferStatus |= 2;
+  }
+
+  inline void BindRenderbuffer( GLenum target, GLuint renderbuffer )
+  {
+  }
+
+  /**
+   * This method can be used by test cases, to query the texture IDs that have been bound by BindTexture.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures() const
+  {
+    return mBoundTextures;
+  }
+
+  /**
+   * Query the texture IDs that have been bound with BindTexture, with a specific active texture unit.
+   * @param[in] activeTextureUnit The specific active texture unit.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures( GLuint activeTextureUnit ) const
+  {
+    return mActiveTextures[ activeTextureUnit - GL_TEXTURE0 ].mBoundTextures;
+  }
+
+  /**
+   * This method can be used by test cases, to clear the record of texture IDs that have been bound by BindTexture.
+   */
+  inline void ClearBoundTextures()
+  {
+    mBoundTextures.clear();
+
+    for( unsigned int i=0; i<MIN_TEXTURE_UNIT_LIMIT; ++i )
+    {
+      mActiveTextures[ i ].mBoundTextures.clear();
+    }
+  }
+
+  inline void BindTexture( GLenum target, GLuint texture )
+  {
+    // Record the bound textures for future checks
+    if( texture )
+    {
+      mBoundTextures.push_back( texture );
+
+      if( mActiveTextureUnit < MIN_TEXTURE_UNIT_LIMIT )
+      {
+        mActiveTextures[ mActiveTextureUnit ].mBoundTextures.push_back( texture );
+      }
+    }
+
+    std::stringstream out;
+    out << target << ", " << texture;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["texture"] = ToString(texture);
+
+    mTextureTrace.PushCall("BindTexture", out.str(), namedParams);
+  }
+
+  inline void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    mLastBlendColor.r = red;
+    mLastBlendColor.g = green;
+    mLastBlendColor.b = blue;
+    mLastBlendColor.a = alpha;
+  }
+
+  inline const Vector4& GetLastBlendColor() const
+  {
+    return mLastBlendColor;
+  }
+
+  inline void BlendEquation( GLenum mode )
+  {
+    mLastBlendEquationRgb   = mode;
+    mLastBlendEquationAlpha = mode;
+  }
+
+  inline void BlendEquationSeparate( GLenum modeRgb, GLenum modeAlpha )
+  {
+    mLastBlendEquationRgb   = modeRgb;
+    mLastBlendEquationAlpha = modeAlpha;
+  }
+
+  inline GLenum GetLastBlendEquationRgb() const
+  {
+    return mLastBlendEquationRgb;
+  }
+
+  inline GLenum GetLastBlendEquationAlpha() const
+  {
+    return mLastBlendEquationAlpha;
+  }
+
+  inline void BlendFunc(GLenum sfactor, GLenum dfactor)
+  {
+    mLastBlendFuncSrcRgb = sfactor;
+    mLastBlendFuncDstRgb = dfactor;
+    mLastBlendFuncSrcAlpha = sfactor;
+    mLastBlendFuncDstAlpha = dfactor;
+  }
+
+  inline void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+  {
+    mLastBlendFuncSrcRgb = srcRGB;
+    mLastBlendFuncDstRgb = dstRGB;
+    mLastBlendFuncSrcAlpha = srcAlpha;
+    mLastBlendFuncDstAlpha = dstAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncSrcRgb() const
+  {
+    return mLastBlendFuncSrcRgb;
+  }
+
+  inline GLenum GetLastBlendFuncDstRgb() const
+  {
+    return mLastBlendFuncDstRgb;
+  }
+
+  inline GLenum GetLastBlendFuncSrcAlpha() const
+  {
+    return mLastBlendFuncSrcAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncDstAlpha() const
+  {
+    return mLastBlendFuncDstAlpha;
+  }
+
+  inline void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+  {
+     mBufferDataCalls.push_back(size);
+  }
+
+  inline void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+  {
+     mBufferSubDataCalls.push_back(size);
+  }
+
+  inline GLenum CheckFramebufferStatus(GLenum target)
+  {
+    //If it has the three last bits set to 1 - 111, then the three minimum functions to create a
+    //Framebuffer texture have been called
+    if( mFramebufferStatus == 7 )
+    {
+      return GL_FRAMEBUFFER_COMPLETE;
+    }
+
+    return mCheckFramebufferStatusResult;
+  }
+
+  inline GLuint CheckFramebufferColorAttachmentCount()
+  {
+    return mFramebufferColorAttachmentCount;
+  }
+
+  inline GLenum CheckFramebufferDepthAttachment()
+  {
+    return mFramebufferDepthAttached;
+  }
+
+  inline GLenum CheckFramebufferStencilAttachment()
+  {
+    return mFramebufferStencilAttached;
+  }
+
+  inline void Clear(GLbitfield mask)
+  {
+    mClearCount++;
+    mLastClearBitMask = mask;
+  }
+
+  inline void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    mLastClearColor.r = red;
+    mLastClearColor.g = green;
+    mLastClearColor.b = blue;
+    mLastClearColor.a = alpha;
+  }
+
+  inline const Vector4& GetLastClearColor() const
+  {
+    return mLastClearColor;
+  }
+
+  inline void ClearDepthf(GLclampf depth)
+  {
+  }
+
+  inline void ClearStencil(GLint s)
+  {
+    std::stringstream out;
+    out << s;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["s"] = ToString( s );
+
+    mStencilFunctionTrace.PushCall( "ClearStencil", out.str(), namedParams );
+  }
+
+  inline void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+  {
+    mColorMaskParams.red = red;
+    mColorMaskParams.green = green;
+    mColorMaskParams.blue = blue;
+    mColorMaskParams.alpha = alpha;
+  }
+
+  inline void CompileShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["shader"] = ToString(shader);
+
+    mShaderTrace.PushCall("CompileShader", out.str(), namedParams);
+  }
+
+  inline void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+  {
+    std::stringstream out;
+    out << target<<", "<<level<<", "<<width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["internalformat"] = ToString(internalformat);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    namedParams["border"] = ToString(border);
+    namedParams["size"] = ToString(imageSize);
+
+    mTextureTrace.PushCall("CompressedTexImage2D", out.str(), namedParams);
+  }
+
+  inline void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+  {
+    std::stringstream out;
+    out << target << ", "<<level <<", " << xoffset << ", " << yoffset << ", " << width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["xoffset"] = ToString(xoffset);
+    namedParams["yoffset"] = ToString(yoffset);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    mTextureTrace.PushCall("CompressedTexSubImage2D", out.str(), namedParams);
+  }
+
+  inline void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+  {
+  }
+
+  inline void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline GLuint CreateProgram(void)
+  {
+    mShaderTrace.PushCall("CreateProgram", "");
+
+    ++mLastProgramIdUsed;
+    mUniforms[mLastProgramIdUsed] = UniformIDMap();
+    return mLastProgramIdUsed;
+  }
+
+  inline GLuint CreateShader(GLenum type)
+  {
+    std::stringstream out;
+    out << type;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["type"] = ToString(type);
+    mShaderTrace.PushCall("CreateShader", out.str(), namedParams);
+
+    return ++mLastShaderIdUsed;
+  }
+
+  inline void CullFace(GLenum mode)
+  {
+    std::stringstream out;
+    out << mode;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(mode);
+
+    mCullFaceTrace.PushCall("CullFace", out.str(), namedParams);
+  }
+
+  inline void DeleteBuffers(GLsizei n, const GLuint* buffers)
+  {
+  }
+
+  inline void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+  {
+  }
+
+  inline void DeleteProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+
+    mShaderTrace.PushCall("DeleteProgram", out.str(), namedParams);
+  }
+
+  inline void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+  {
+  }
+
+  inline void DeleteShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["shader"] = ToString(shader);
+
+    mShaderTrace.PushCall("DeleteShader", out.str(), namedParams);
+  }
+
+  inline void DeleteTextures(GLsizei n, const GLuint* textures)
+  {
+    std::stringstream out;
+    out << n << ", " << textures << " = [";
+
+    TraceCallStack::NamedParams namedParams;
+
+    for(GLsizei i=0; i<n; i++)
+    {
+      out << textures[i] << ", ";
+      std::stringstream paramName;
+      paramName<<"texture["<<i<<"]";
+      namedParams[paramName.str()] = ToString(textures[i]);
+      mDeletedTextureIds.push_back(textures[i]);
+      mNumGeneratedTextures--;
+    }
+    out << "]";
+
+    mTextureTrace.PushCall("DeleteTextures", out.str(), namedParams);
+  }
+
+  inline bool CheckNoTexturesDeleted()
+  {
+    return mDeletedTextureIds.size() == 0;
+  }
+
+  inline bool CheckTextureDeleted( GLuint textureId )
+  {
+    bool found = false;
+
+    for(std::vector<GLuint>::iterator iter=mDeletedTextureIds.begin(); iter != mDeletedTextureIds.end(); ++iter)
+    {
+      if(*iter == textureId)
+      {
+        found = true;
+        break;
+      }
+    }
+    return found;
+  }
+
+  inline void ClearDeletedTextures()
+  {
+    mDeletedTextureIds.clear();
+  }
+
+  inline void DepthFunc(GLenum func)
+  {
+    std::stringstream out;
+    out << func;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["func"] = ToString(func);
+
+    mDepthFunctionTrace.PushCall("DepthFunc", out.str(), namedParams);
+  }
+
+  inline void DepthMask(GLboolean flag)
+  {
+    mLastDepthMask = flag;
+  }
+
+  inline bool GetLastDepthMask() const
+  {
+    return mLastDepthMask;
+  }
+
+  inline void DepthRangef(GLclampf zNear, GLclampf zFar)
+  {
+  }
+
+  inline void DetachShader(GLuint program, GLuint shader)
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    namedParams["shader"] = ToString(shader);
+    mShaderTrace.PushCall("DetachShader", out.str(), namedParams);
+  }
+
+  inline void Disable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["cap"] = ToString(cap);
+    mEnableDisableTrace.PushCall("Disable", out.str(), namedParams);
+  }
+
+  inline void DisableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, false );
+  }
+
+  inline void DrawArrays(GLenum mode, GLint first, GLsizei count)
+  {
+    std::stringstream out;
+    out << mode << ", " << first << ", " << count;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] = ToString(mode);
+    namedParams["first"] = ToString(first);
+    namedParams["count"] = ToString(count);
+    mDrawTrace.PushCall("DrawArrays", out.str(), namedParams);
+  }
+
+  inline void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
+  {
+    std::stringstream out;
+    out << mode << ", " << count << ", " << type << ", indices";
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] = ToString(mode);
+    namedParams["count"] = ToString(count);
+    namedParams["type"] = ToString(type);
+    // Skip void pointers - are they of any use?
+    mDrawTrace.PushCall("DrawElements", out.str(), namedParams);
+  }
+
+  inline void Enable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["cap"] = ToString(cap);
+    mEnableDisableTrace.PushCall("Enable", out.str(), namedParams);
+  }
+
+  inline void EnableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, true);
+  }
+
+  inline void Finish(void)
+  {
+  }
+
+  inline void Flush(void)
+  {
+  }
+
+  inline void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+  {
+    if (attachment == GL_DEPTH_ATTACHMENT)
+    {
+      mFramebufferDepthAttached = true;
+    }
+    else if (attachment == GL_STENCIL_ATTACHMENT)
+    {
+      mFramebufferStencilAttached = true;
+    }
+  }
+
+  inline void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+  {
+    //Add 100 bit;
+    mFramebufferStatus |= 4;
+
+    //We check 4 attachment colors
+    if ((attachment >= GL_COLOR_ATTACHMENT0) && (attachment < GL_COLOR_ATTACHMENT0 + Dali::DevelFrameBuffer::MAX_COLOR_ATTACHMENTS))
+    {
+      uint8_t mask = 1 << (attachment - GL_COLOR_ATTACHMENT0);
+      if ((mFrameBufferColorStatus & mask) == 0)
+      {
+        mFrameBufferColorStatus |= mask;
+        ++mFramebufferColorAttachmentCount;
+      }
+    }
+  }
+
+  inline void FrontFace(GLenum mode)
+  {
+  }
+
+  inline void GenBuffers(GLsizei n, GLuint* buffers)
+  {
+    // avoids an assert in GpuBuffers
+    *buffers = 1u;
+  }
+
+  inline void GenerateMipmap(GLenum target)
+  {
+    std::stringstream out;
+    out<<target;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+
+    mTextureTrace.PushCall("GenerateMipmap", out.str(), namedParams);
+  }
+
+  inline void GenFramebuffers(GLsizei n, GLuint* framebuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      framebuffers[i] = i + 1;
+    }
+
+    //Add 001 bit, this function needs to be called the first one in the chain
+    mFramebufferStatus = 1;
+  }
+
+  inline void GenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      renderbuffers[i] = i + 1;
+    }
+  }
+
+  /**
+   * This method can be used by test cases, to manipulate the texture IDs generated by GenTextures.
+   * @param[in] ids A vector containing the next IDs to be generated
+   */
+  inline void SetNextTextureIds( const std::vector<GLuint>& ids )
+  {
+    mNextTextureIds = ids;
+  }
+
+  inline const std::vector<GLuint>& GetNextTextureIds()
+  {
+    return mNextTextureIds;
+  }
+
+  inline void GenTextures(GLsizei count, GLuint* textures)
+  {
+    for( int i=0; i<count; ++i )
+    {
+      if( !mNextTextureIds.empty() )
+      {
+        *(textures+i) = mNextTextureIds[0];
+        mNextTextureIds.erase( mNextTextureIds.begin() );
+      }
+      else
+      {
+        *(textures+i) = ++mLastAutoTextureIdUsed;
+      }
+      mNumGeneratedTextures++;
+    }
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["count"] = ToString(count);
+
+    std::stringstream out;
+    for(int i=0; i<count; i++)
+    {
+      out << textures[i];
+      if(i<count-1)
+      {
+        out << ", ";
+      }
+      std::ostringstream oss;
+      oss<<"indices["<<i<<"]";
+      namedParams[oss.str()] = ToString(textures[i]);
+    }
+
+    mTextureTrace.PushCall("GenTextures", out.str(), namedParams);
+  }
+
+  inline GLuint GetLastGenTextureId()
+  {
+    return mLastAutoTextureIdUsed;
+  }
+  inline GLuint GetNumGeneratedTextures()
+  {
+    return mNumGeneratedTextures;
+  }
+
+  inline void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+  }
+
+  inline void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+    switch(index)
+    {
+      case 0:
+        *length = snprintf(name, bufsize, "sTexture");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      case 1:
+        *length = snprintf(name, bufsize, "sEffect");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      case 2:
+        *length = snprintf(name, bufsize, "sGloss");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      default:
+        break;
+    }
+  }
+
+  inline void GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+  {
+  }
+
+  inline int  GetAttribLocation(GLuint program, const char* name)
+  {
+    std::string attribName(name);
+
+    for( unsigned int i = 0; i < ATTRIB_TYPE_LAST; ++i )
+    {
+      if( mStdAttribs[i] == attribName )
+      {
+        return i;
+      }
+    }
+
+    // 0 is a valid location
+    return 0;
+  }
+
+  inline void GetBooleanv(GLenum pname, GLboolean* params)
+  {
+  }
+
+  inline void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLenum GetError(void)
+  {
+    return mGetErrorResult;
+  }
+
+  inline void GetFloatv(GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetIntegerv(GLenum pname, GLint* params)
+  {
+    switch( pname )
+    {
+      case GL_MAX_TEXTURE_SIZE:
+        *params = 2048;
+        break;
+      case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *params = 8;
+        break;
+      case GL_NUM_PROGRAM_BINARY_FORMATS_OES:
+        *params = mNumBinaryFormats;
+        break;
+      case GL_PROGRAM_BINARY_FORMATS_OES:
+        *params = mBinaryFormats;
+        break;
+    }
+  }
+
+  inline void GetProgramiv(GLuint program, GLenum pname, GLint* params)
+  {
+    switch( pname )
+    {
+      case GL_LINK_STATUS:
+        *params = mLinkStatus;
+        break;
+      case GL_PROGRAM_BINARY_LENGTH_OES:
+        *params = mProgramBinaryLength;
+        break;
+      case GL_ACTIVE_UNIFORMS:
+        *params = mNumberOfActiveUniforms;
+        break;
+      case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+        *params = 100;
+        break;
+    }
+  }
+
+  inline void GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+  inline void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetShaderiv(GLuint shader, GLenum pname, GLint* params)
+  {
+    switch( pname ) {
+      case GL_COMPILE_STATUS:
+        *params = mCompileStatus;
+        break;
+    }
+  }
+
+  inline void GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+  inline void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+  {
+  }
+
+  inline const GLubyte* GetString(GLenum name)
+  {
+    return mGetStringResult;
+  }
+
+  inline void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetUniformfv(GLuint program, GLint location, GLfloat* params)
+  {
+  }
+
+  inline void GetUniformiv(GLuint program, GLint location, GLint* params)
+  {
+  }
+
+  inline GLint GetUniformLocation(GLuint program, const char* name)
+  {
+    ProgramUniformMap::iterator it = mUniforms.find(program);
+    if( it == mUniforms.end() )
+    {
+      // Not a valid program ID
+      mGetErrorResult = GL_INVALID_OPERATION;
+      return -1;
+    }
+
+    UniformIDMap& uniformIDs = it->second;
+    UniformIDMap::iterator it2 = uniformIDs.find( name );
+    if( it2 == uniformIDs.end() )
+    {
+      // Uniform not found, so add it...
+      uniformIDs[name] = ++mLastUniformIdUsed;
+      return mLastUniformIdUsed;
+    }
+
+    return it2->second;
+  }
+
+  inline void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+  {
+  }
+
+  inline void Hint(GLenum target, GLenum mode)
+  {
+  }
+
+  inline GLboolean IsBuffer(GLuint buffer)
+  {
+    return mIsBufferResult;
+  }
+
+  inline GLboolean IsEnabled(GLenum cap)
+  {
+    return mIsEnabledResult;
+  }
+
+  inline GLboolean IsFramebuffer(GLuint framebuffer)
+  {
+    return mIsFramebufferResult;
+  }
+
+  inline GLboolean IsProgram(GLuint program)
+  {
+    return mIsProgramResult;
+  }
+
+  inline GLboolean IsRenderbuffer(GLuint renderbuffer)
+  {
+    return mIsRenderbufferResult;
+  }
+
+  inline GLboolean IsShader(GLuint shader)
+  {
+    return mIsShaderResult;
+  }
+
+  inline GLboolean IsTexture(GLuint texture)
+  {
+    return mIsTextureResult;
+  }
+
+  inline void LineWidth(GLfloat width)
+  {
+  }
+
+  inline void LinkProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    mShaderTrace.PushCall("LinkProgram", out.str(), namedParams);
+
+    mNumberOfActiveUniforms=3;
+    GetUniformLocation(program, "sTexture");
+    GetUniformLocation(program, "sEffect");
+    GetUniformLocation(program, "sGloss");
+  }
+
+  inline void PixelStorei(GLenum pname, GLint param)
+  {
+  }
+
+  inline void PolygonOffset(GLfloat factor, GLfloat units)
+  {
+  }
+
+  inline void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+  {
+  }
+
+  inline void ReleaseShaderCompiler(void)
+  {
+  }
+
+  inline void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void SampleCoverage(GLclampf value, GLboolean invert)
+  {
+  }
+
+  inline void Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    mScissorParams.x = x;
+    mScissorParams.y = y;
+    mScissorParams.width = width;
+    mScissorParams.height = height;
+
+    std::stringstream out;
+    out << x << ", " << y << ", " << width << ", " << height;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["x"] = ToString( x );
+    namedParams["y"] = ToString( y );
+    namedParams["width"] = ToString( width );
+    namedParams["height"] = ToString( height );
+    mScissorTrace.PushCall( "Scissor", out.str(), namedParams );
+  }
+
+  inline void ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+  {
+  }
+
+  inline void ShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+  {
+    std::string stringBuilder;
+    for(int i = 0; i < count; ++i)
+    {
+      stringBuilder += string[i];
+    }
+    mShaderSources[shader] = stringBuilder;
+    mLastShaderCompiled = shader;
+  }
+
+  inline void GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+  {
+    const std::string shaderSource = mShaderSources[shader];
+    const int shaderSourceLength = static_cast<int>(shaderSource.length());
+    if( shaderSourceLength < bufsize )
+    {
+      strncpy( source, shaderSource.c_str(), shaderSourceLength );
+      *length = shaderSourceLength;
+    }
+    else
+    {
+      *length = bufsize -1;
+      strncpy(source, shaderSource.c_str(), *length);
+      source[*length] = 0x0;
+    }
+  }
+
+  inline std::string GetShaderSource(GLuint shader)
+  {
+    return mShaderSources[shader];
+  }
+
+  inline void StencilFunc(GLenum func, GLint ref, GLuint mask)
+  {
+    std::stringstream out;
+    out << func << ", " << ref << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["func"] = ToString( func );
+    namedParams["ref"] = ToString( ref );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilFunc", out.str(), namedParams );
+  }
+
+  inline void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+  {
+    std::stringstream out;
+    out << face << ", " << func << ", " << ref << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["func"] = ToString( func );
+    namedParams["ref"] = ToString( ref );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilFuncSeparate", out.str(), namedParams );
+  }
+
+  inline void StencilMask(GLuint mask)
+  {
+    std::stringstream out;
+    out << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilMask", out.str(), namedParams );
+  }
+
+  inline void StencilMaskSeparate(GLenum face, GLuint mask)
+  {
+    std::stringstream out;
+    out << face << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilMaskSeparate", out.str(), namedParams );
+  }
+
+  inline void StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    std::stringstream out;
+    out << fail << ", " << zfail << ", " << zpass;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["fail"] = ToString( fail );
+    namedParams["zfail"] = ToString( zfail );
+    namedParams["zpass"] = ToString( zpass );
+
+    mStencilFunctionTrace.PushCall( "StencilOp", out.str(), namedParams );
+  }
+
+  inline void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    std::stringstream out;
+    out << face << ", " << fail << ", " << zfail << "," << zpass;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["fail"] = ToString( fail );
+    namedParams["zfail"] = ToString( zfail );
+    namedParams["zpass"] = ToString( zpass );
+
+    mStencilFunctionTrace.PushCall( "StencilOpSeparate", out.str(), namedParams );
+  }
+
+  inline void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << target<<", "<<level<<", "<<width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["internalformat"] = ToString(internalformat);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    namedParams["border"] = ToString(border);
+    namedParams["format"] = ToString(format);
+    namedParams["type"] = ToString(type);
+
+    mTextureTrace.PushCall("TexImage2D", out.str(), namedParams);
+  }
+
+  inline void TexParameterf(GLenum target, GLenum pname, GLfloat param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["param"] = ToString(param);
+
+    mTexParamaterTrace.PushCall("TexParameterf", out.str(), namedParams);
+  }
+
+  inline void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["params[0]"] = ToString(params[0]);
+
+    mTexParamaterTrace.PushCall("TexParameterfv", out.str(), namedParams);
+  }
+
+  inline void TexParameteri(GLenum target, GLenum pname, GLint param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["param"] = ToString(param);
+    mTexParamaterTrace.PushCall("TexParameteri", out.str(), namedParams);
+  }
+
+  inline void TexParameteriv(GLenum target, GLenum pname, const GLint* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["params[0]"] = ToString(params[0]);
+    mTexParamaterTrace.PushCall("TexParameteriv", out.str(), namedParams);
+  }
+
+  inline void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << target << ", "<<level <<", " << xoffset << ", " << yoffset << ", " << width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["xoffset"] = ToString(xoffset);
+    namedParams["yoffset"] = ToString(yoffset);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    mTextureTrace.PushCall("TexSubImage2D", out.str(), namedParams);
+  }
+
+  inline void Uniform1f(GLint location, GLfloat value )
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, value ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params;
+    for( int i = 0; i < count; ++i )
+    {
+      params = params + ToString( v[i] ) + ",";
+    }
+
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform1i(GLint location, GLint x)
+  {
+    std::string params = ToString( x );
+
+    AddUniformCallToTraceStack( location,  params );
+
+    if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram, location, x ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2f(GLint location, GLfloat x, GLfloat y)
+  {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector2( x, y ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform2fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 Vector2( v[2*i], v[2*i+1] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2i(GLint location, GLint x, GLint y)
+  {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform2iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms3f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector3( x, y, z ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform3fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms3f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector3( v[3*i], v[3*i+1], v[3*i+2] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform3i(GLint location, GLint x, GLint y, GLint z)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform3iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms4f.SetUniformValue( mCurrentProgram,
+                                              location,
+                                              Vector4( x, y, z, w ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform4fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms4f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector4( v[4*i], v[4*i+1], v[4*i+2], v[4*i+3] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform4iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat3.SetUniformValue(
+            mCurrentProgram,
+            location,
+            Matrix3( value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat4.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Matrix( value ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UseProgram(GLuint program)
+  {
+    mCurrentProgram = program;
+  }
+
+  inline void ValidateProgram(GLuint program)
+  {
+  }
+
+  inline void VertexAttrib1f(GLuint indx, GLfloat x)
+  {
+  }
+
+  inline void VertexAttrib1fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+  {
+  }
+
+  inline void VertexAttrib2fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+  {
+  }
+
+  inline void VertexAttrib3fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+  }
+
+  inline void VertexAttrib4fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+  {
+  }
+
+  inline void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    std::string commaString(", ");
+    std::string params( std::to_string(x) + commaString + std::to_string(y) + commaString + std::to_string(width) + commaString + std::to_string(height) );
+
+    mViewportTrace.PushCall("Viewport", params);
+  }
+
+  /* OpenGL ES 3.0 */
+
+  inline void ReadBuffer(GLenum mode)
+  {
+  }
+
+  inline void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices)
+  {
+  }
+
+  inline void TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void GenQueries(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline void DeleteQueries(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsQuery(GLuint id)
+  {
+    return false;
+  }
+
+  inline void BeginQuery(GLenum target, GLuint id)
+  {
+  }
+
+  inline void EndQuery(GLenum target)
+  {
+  }
+
+  inline void GetQueryiv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline GLboolean UnmapBuffer(GLenum target)
+  {
+    return false;
+  }
+
+  inline void GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params)
+  {
+  }
+
+  inline void DrawBuffers(GLsizei n, const GLenum* bufs)
+  {
+  }
+
+  inline void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+  {
+  }
+
+  inline void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+  {
+  }
+
+  inline GLvoid* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+  {
+    return NULL;
+  }
+
+  inline void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+  {
+  }
+
+  inline void BindVertexArray(GLuint array)
+  {
+  }
+
+  inline void DeleteVertexArrays(GLsizei n, const GLuint* arrays)
+  {
+  }
+
+  inline void GenVertexArrays(GLsizei n, GLuint* arrays)
+  {
+  }
+
+  inline GLboolean IsVertexArray(GLuint array)
+  {
+    return false;
+  }
+
+  inline void GetIntegeri_v(GLenum target, GLuint index, GLint* data)
+  {
+  }
+
+  inline void BeginTransformFeedback(GLenum primitiveMode)
+  {
+  }
+
+  inline void EndTransformFeedback(void)
+  {
+  }
+
+  inline void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+  {
+  }
+
+  inline void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
+  {
+  }
+
+  inline void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode)
+  {
+  }
+
+  inline void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name)
+  {
+  }
+
+  inline void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+  {
+  }
+
+  inline void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
+  {
+  }
+
+  inline void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+  {
+  }
+
+  inline void VertexAttribI4iv(GLuint index, const GLint* v)
+  {
+  }
+
+  inline void VertexAttribI4uiv(GLuint index, const GLuint* v)
+  {
+  }
+
+  inline void GetUniformuiv(GLuint program, GLint location, GLuint* params)
+  {
+  }
+
+  inline GLint GetFragDataLocation(GLuint program, const GLchar *name)
+  {
+    return -1;
+  }
+
+  inline void Uniform1ui(GLint location, GLuint v0)
+  {
+  }
+
+  inline void Uniform2ui(GLint location, GLuint v0, GLuint v1)
+  {
+  }
+
+  inline void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+  {
+  }
+
+  inline void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+  {
+  }
+
+  inline void Uniform1uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform2uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform3uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform4uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value)
+  {
+  }
+
+  inline void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value)
+  {
+  }
+
+  inline void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+  {
+  }
+
+  inline const GLubyte* GetStringi(GLenum name, GLuint index)
+  {
+    return NULL;
+  }
+
+  inline void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+  {
+  }
+
+  inline void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices)
+  {
+  }
+
+  inline void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName)
+  {
+    return GL_INVALID_INDEX;
+  }
+
+  inline void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName)
+  {
+  }
+
+  inline void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+  {
+  }
+
+  inline void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+  {
+  }
+
+  inline void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount)
+  {
+  }
+
+  inline GLsync FenceSync(GLenum condition, GLbitfield flags)
+  {
+    return NULL;
+  }
+
+  inline GLboolean IsSync(GLsync sync)
+  {
+    return false;
+  }
+
+  inline void DeleteSync(GLsync sync)
+  {
+  }
+
+  inline GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+    return 0;
+  }
+
+  inline void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+  }
+
+  inline void GetInteger64v(GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values)
+  {
+  }
+
+  inline void GetInteger64i_v(GLenum target, GLuint index, GLint64* data)
+  {
+  }
+
+  inline void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GenSamplers(GLsizei count, GLuint* samplers)
+  {
+  }
+
+  inline void DeleteSamplers(GLsizei count, const GLuint* samplers)
+  {
+  }
+
+  inline GLboolean IsSampler(GLuint sampler)
+  {
+    return false;
+  }
+
+  inline void BindSampler(GLuint unit, GLuint sampler)
+  {
+  }
+
+  inline void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
+  {
+  }
+
+  inline void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param)
+  {
+  }
+
+  inline void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
+  {
+  }
+
+  inline void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param)
+  {
+  }
+
+  inline void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void VertexAttribDivisor(GLuint index, GLuint divisor)
+  {
+  }
+
+  inline void BindTransformFeedback(GLenum target, GLuint id)
+  {
+  }
+
+  inline void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline void GenTransformFeedbacks(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsTransformFeedback(GLuint id)
+  {
+    return false;
+  }
+
+  inline void PauseTransformFeedback(void)
+  {
+  }
+
+  inline void ResumeTransformFeedback(void)
+  {
+  }
+
+  inline void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)
+  {
+    mGetProgramBinaryCalled = true;
+  }
+
+  inline void ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length)
+  {
+  }
+
+  inline void ProgramParameteri(GLuint program, GLenum pname, GLint value)
+  {
+  }
+
+  inline void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
+  {
+  }
+
+  inline void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+  {
+  }
+
+  inline void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
+  {
+  }
+
+private:
+
+  inline void AddUniformCallToTraceStack( GLint location, std::string& value )
+    {
+    std::string name = "<not found>";
+    bool matched = false;
+
+    UniformIDMap& map = mUniforms[mCurrentProgram];
+    for (UniformIDMap::iterator it=map.begin(); it!=map.end(); ++it)
+    {
+      if( it->second == location )
+      {
+        name = it->first;
+        matched = true;
+        break;
+      }
+    }
+
+    if ( matched )
+    {
+      mSetUniformTrace.PushCall( name, value );
+    }
+  }
+
+
+public: // TEST FUNCTIONS
+  inline void SetCompileStatus( GLuint value ) { mCompileStatus = value; }
+  inline void SetLinkStatus( GLuint value ) { mLinkStatus = value; }
+  inline void SetGetAttribLocationResult(  int result) { mGetAttribLocationResult = result; }
+  inline void SetGetErrorResult(  GLenum result) { mGetErrorResult = result; }
+  inline void SetGetStringResult(  GLubyte* result) { mGetStringResult = result; }
+  inline void SetIsBufferResult(  GLboolean result) { mIsBufferResult = result; }
+  inline void SetIsEnabledResult(  GLboolean result) { mIsEnabledResult = result; }
+  inline void SetIsFramebufferResult(  GLboolean result) { mIsFramebufferResult = result; }
+  inline void SetIsProgramResult(  GLboolean result) { mIsProgramResult = result; }
+  inline void SetIsRenderbufferResult(  GLboolean result) { mIsRenderbufferResult = result; }
+  inline void SetIsShaderResult(  GLboolean result) { mIsShaderResult = result; }
+  inline void SetIsTextureResult(  GLboolean result) { mIsTextureResult = result; }
+  inline void SetCheckFramebufferStatusResult(  GLenum result) { mCheckFramebufferStatusResult = result; }
+  inline void SetNumBinaryFormats( GLint numFormats ) { mNumBinaryFormats = numFormats; }
+  inline void SetBinaryFormats( GLint binaryFormats ) { mBinaryFormats = binaryFormats; }
+  inline void SetProgramBinaryLength( GLint length ) { mProgramBinaryLength = length; }
+
+  inline bool GetVertexAttribArrayState(GLuint index)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return false;
+    }
+    return mVertexAttribArrayState[ index ];
+  }
+  inline void ClearVertexAttribArrayChanged() {  mVertexAttribArrayChanged = false; }
+  inline bool GetVertexAttribArrayChanged()  { return mVertexAttribArrayChanged; }
+
+  //Methods for CullFace verification
+  inline void EnableCullFaceCallTrace(bool enable) { mCullFaceTrace.Enable(enable); }
+  inline void ResetCullFaceCallStack() { mCullFaceTrace.Reset(); }
+  inline TraceCallStack& GetCullFaceTrace() { return mCullFaceTrace; }
+
+  //Methods for Enable/Disable call verification
+  inline void EnableEnableDisableCallTrace(bool enable) { mEnableDisableTrace.Enable(enable); }
+  inline void ResetEnableDisableCallStack() { mEnableDisableTrace.Reset(); }
+  inline TraceCallStack& GetEnableDisableTrace() { return mEnableDisableTrace; }
+
+  //Methods for Shader verification
+  inline void EnableShaderCallTrace(bool enable) { mShaderTrace.Enable(enable); }
+  inline void ResetShaderCallStack() { mShaderTrace.Reset(); }
+  inline TraceCallStack& GetShaderTrace() { return mShaderTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTextureCallTrace(bool enable) { mTextureTrace.Enable(enable); }
+  inline void ResetTextureCallStack() { mTextureTrace.Reset(); }
+  inline TraceCallStack& GetTextureTrace() { return mTextureTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTexParameterCallTrace(bool enable) { mTexParamaterTrace.Enable(enable); }
+  inline void ResetTexParameterCallStack() { mTexParamaterTrace.Reset(); }
+  inline TraceCallStack& GetTexParameterTrace() { return mTexParamaterTrace; }
+
+  //Methods for Draw verification
+  inline void EnableDrawCallTrace(bool enable) { mDrawTrace.Enable(enable); }
+  inline void ResetDrawCallStack() { mDrawTrace.Reset(); }
+  inline TraceCallStack& GetDrawTrace() { return mDrawTrace; }
+
+  //Methods for Depth function verification
+  inline void EnableDepthFunctionCallTrace(bool enable) { mDepthFunctionTrace.Enable(enable); }
+  inline void ResetDepthFunctionCallStack() { mDepthFunctionTrace.Reset(); }
+  inline TraceCallStack& GetDepthFunctionTrace() { return mDepthFunctionTrace; }
+
+  //Methods for Stencil function verification
+  inline void EnableStencilFunctionCallTrace(bool enable) { mStencilFunctionTrace.Enable(enable); }
+  inline void ResetStencilFunctionCallStack() { mStencilFunctionTrace.Reset(); }
+  inline TraceCallStack& GetStencilFunctionTrace() { return mStencilFunctionTrace; }
+
+  //Methods for Scissor verification
+  inline void EnableScissorCallTrace(bool enable) { mScissorTrace.Enable(enable); }
+  inline void ResetScissorCallStack() { mScissorTrace.Reset(); }
+  inline TraceCallStack& GetScissorTrace() { return mScissorTrace; }
+
+  //Methods for Uniform function verification
+  inline void EnableSetUniformCallTrace(bool enable) { mSetUniformTrace.Enable(enable); }
+  inline void ResetSetUniformCallStack() { mSetUniformTrace.Reset(); }
+  inline TraceCallStack& GetSetUniformTrace() { return mSetUniformTrace; }
+
+  //Methods for Viewport verification
+  inline void EnableViewportCallTrace(bool enable) { mViewportTrace.Enable(enable); }
+  inline void ResetViewportCallStack() { mViewportTrace.Reset(); }
+  inline TraceCallStack& GetViewportTrace() { return mViewportTrace; }
+
+  template <typename T>
+  inline bool GetUniformValue( const char* name, T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        return mProgramUniforms.GetUniformValue( programId, uniformId, value );
+      }
+    }
+    return false;
+  }
+
+
+  template <typename T>
+  inline bool CheckUniformValue( const char* name, const T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        if( mProgramUniforms.CheckUniformValue( programId, uniformId, value ) )
+        {
+          // the value matches
+          return true;
+        }
+      }
+    }
+
+    fprintf(stderr, "Not found, printing possible values:\n" );
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        T origValue;
+        if ( mProgramUniforms.GetUniformValue(programId, uniformId, origValue) )
+        {
+          std::stringstream out;
+          out << uniform_it->first << ": " << origValue;
+          fprintf(stderr, "%s\n", out.str().c_str() );
+        }
+      }
+    }
+    return false;
+  }
+
+  template <typename T>
+  inline bool GetUniformValue( GLuint programId, GLuint uniformId, T& outValue) const
+  {
+    const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( outValue );
+    return mProgramUniforms.GetUniformValue( programId, uniformId, outValue );
+  }
+
+  inline bool GetUniformIds( const char* name, GLuint& programId, GLuint& uniformId ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        programId = program_it->first;
+        uniformId = uniform_it->second;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  inline GLuint GetLastShaderCompiled() const
+  {
+    return mLastShaderCompiled;
+  }
+
+  inline GLuint GetLastProgramCreated() const
+  {
+    return mLastProgramIdUsed;
+  }
+
+  inline GLbitfield GetLastClearMask() const
+  {
+    return mLastClearBitMask;
+  }
+
+  enum AttribType
+  {
+    ATTRIB_UNKNOWN = -1,
+    ATTRIB_POSITION,
+    ATTRIB_NORMAL,
+    ATTRIB_TEXCOORD,
+    ATTRIB_COLOR,
+    ATTRIB_BONE_WEIGHTS,
+    ATTRIB_BONE_INDICES,
+    ATTRIB_TYPE_LAST
+  };
+
+  struct ScissorParams
+  {
+    GLint x;
+    GLint y;
+    GLsizei width;
+    GLsizei height;
+
+    ScissorParams() : x( 0 ), y( 0 ), width( 0 ), height( 0 ) { }
+  };
+
+  // Methods to check scissor tests
+  inline const ScissorParams& GetScissorParams() const { return mScissorParams; }
+
+  struct ColorMaskParams
+  {
+    GLboolean red;
+    GLboolean green;
+    GLboolean blue;
+    GLboolean alpha;
+
+    ColorMaskParams() : red( true ), green( true ), blue( true ), alpha( true ) { }
+  };
+
+  inline bool GetProgramBinaryCalled() const { return mGetProgramBinaryCalled; }
+
+  inline unsigned int GetClearCountCalled() const { return mClearCount; }
+
+  inline const ColorMaskParams& GetColorMaskParams() const { return mColorMaskParams; }
+
+  typedef std::vector<size_t> BufferDataCalls;
+  inline const BufferDataCalls& GetBufferDataCalls() const { return mBufferDataCalls; }
+  inline void ResetBufferDataCalls() { mBufferDataCalls.clear(); }
+
+  typedef std::vector<size_t> BufferSubDataCalls;
+  inline const BufferSubDataCalls& GetBufferSubDataCalls() const { return mBufferSubDataCalls; }
+  inline void ResetBufferSubDataCalls() { mBufferSubDataCalls.clear(); }
+
+private:
+  GLuint     mCurrentProgram;
+  GLuint     mCompileStatus;
+  BufferDataCalls mBufferDataCalls;
+  BufferSubDataCalls mBufferSubDataCalls;
+  GLuint     mLinkStatus;
+  GLint      mNumberOfActiveUniforms;
+  GLint      mGetAttribLocationResult;
+  GLenum     mGetErrorResult;
+  GLubyte*   mGetStringResult;
+  GLboolean  mIsBufferResult;
+  GLboolean  mIsEnabledResult;
+  GLboolean  mIsFramebufferResult;
+  GLboolean  mIsProgramResult;
+  GLboolean  mIsRenderbufferResult;
+  GLboolean  mIsShaderResult;
+  GLboolean  mIsTextureResult;
+  GLenum     mActiveTextureUnit;
+  GLenum     mCheckFramebufferStatusResult;
+  GLint      mFramebufferStatus;
+  GLenum     mFramebufferDepthAttached;
+  GLenum     mFramebufferStencilAttached;
+  GLuint     mFramebufferColorAttachmentCount;
+  GLuint     mFrameBufferColorStatus;
+  GLint      mNumBinaryFormats;
+  GLint      mBinaryFormats;
+  GLint      mProgramBinaryLength;
+  bool       mVertexAttribArrayState[MAX_ATTRIBUTE_CACHE_SIZE];
+  bool       mVertexAttribArrayChanged;                            // whether the vertex attrib array has been changed
+  bool       mGetProgramBinaryCalled;
+  typedef std::map< GLuint, std::string> ShaderSourceMap;
+  ShaderSourceMap mShaderSources;
+  GLuint     mLastShaderCompiled;
+  GLbitfield mLastClearBitMask;
+  Vector4 mLastClearColor;
+  unsigned int mClearCount;
+
+  Vector4 mLastBlendColor;
+  GLenum  mLastBlendEquationRgb;
+  GLenum  mLastBlendEquationAlpha;
+  GLenum  mLastBlendFuncSrcRgb;
+  GLenum  mLastBlendFuncDstRgb;
+  GLenum  mLastBlendFuncSrcAlpha;
+  GLenum  mLastBlendFuncDstAlpha;
+
+  GLboolean mLastDepthMask;
+
+  // Data for manipulating the IDs returned by GenTextures
+  GLuint mLastAutoTextureIdUsed;
+  GLuint mNumGeneratedTextures;
+  std::vector<GLuint> mNextTextureIds;
+  std::vector<GLuint> mDeletedTextureIds;
+  std::vector<GLuint> mBoundTextures;
+
+  struct ActiveTextureType
+  {
+    std::vector<GLuint> mBoundTextures;
+  };
+
+  ActiveTextureType mActiveTextures[ MIN_TEXTURE_UNIT_LIMIT ];
+
+  TraceCallStack mCullFaceTrace;
+  TraceCallStack mEnableDisableTrace;
+  TraceCallStack mShaderTrace;
+  TraceCallStack mTextureTrace;
+  TraceCallStack mTexParamaterTrace;
+  TraceCallStack mDrawTrace;
+  TraceCallStack mDepthFunctionTrace;
+  TraceCallStack mStencilFunctionTrace;
+  TraceCallStack mScissorTrace;
+  TraceCallStack mSetUniformTrace;
+  TraceCallStack mViewportTrace;
+
+  // Shaders & Uniforms
+  GLuint mLastShaderIdUsed;
+  GLuint mLastProgramIdUsed;
+  GLuint mLastUniformIdUsed;
+  typedef std::map< std::string, GLint > UniformIDMap;
+  typedef std::map< GLuint, UniformIDMap > ProgramUniformMap;
+  ProgramUniformMap mUniforms;
+
+  template <typename T>
+  struct ProgramUniformValue : public std::map< GLuint, std::map< GLint, T > >
+  {
+  public:
+    typedef std::map< GLint, T > UniformValueMap;
+    typedef std::map< GLuint, UniformValueMap > Map;
+
+    bool SetUniformValue( GLuint program, GLuint uniform, const T& value )
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // if its the first uniform for this program add it
+        std::pair< typename Map::iterator, bool > result =
+            Map::insert( typename Map::value_type( program, UniformValueMap() ) );
+        it = result.first;
+      }
+
+      UniformValueMap& uniforms = it->second;
+      uniforms[uniform] = value;
+
+      return true;
+    }
+
+    bool CheckUniformValue( GLuint program, GLuint uniform, const T& value ) const
+    {
+      T uniformValue;
+      if ( GetUniformValue( program, uniform, uniformValue ) )
+      {
+        return CompareType<T>(value, uniformValue, Math::MACHINE_EPSILON_10);
+      }
+
+      return false;
+    }
+
+    bool GetUniformValue( GLuint program, GLuint uniform, T& value ) const
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::const_iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+
+      const UniformValueMap& uniforms = it->second;
+      typename UniformValueMap::const_iterator it2 = uniforms.find( uniform );
+      if( it2 == uniforms.end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+      value = it2->second;
+
+      return true;
+    }
+
+    T GetZero() const;
+  };
+  ProgramUniformValue<int> mProgramUniforms1i;
+  ProgramUniformValue<float> mProgramUniforms1f;
+  ProgramUniformValue<Vector2> mProgramUniforms2f;
+  ProgramUniformValue<Vector3> mProgramUniforms3f;
+  ProgramUniformValue<Vector4> mProgramUniforms4f;
+  ProgramUniformValue<Matrix> mProgramUniformsMat4;
+  ProgramUniformValue<Matrix3> mProgramUniformsMat3;
+
+  inline const ProgramUniformValue<int>& GetProgramUniformsForType( const int ) const
+  {
+    return mProgramUniforms1i;
+  }
+  inline const ProgramUniformValue<float>& GetProgramUniformsForType( const float ) const
+  {
+    return mProgramUniforms1f;
+  }
+  inline const ProgramUniformValue<Vector2>& GetProgramUniformsForType( const Vector2& ) const
+  {
+    return mProgramUniforms2f;
+  }
+  inline const ProgramUniformValue<Vector3>& GetProgramUniformsForType( const Vector3& ) const
+  {
+    return mProgramUniforms3f;
+  }
+  inline const ProgramUniformValue<Vector4>& GetProgramUniformsForType( const Vector4& ) const
+  {
+    return mProgramUniforms4f;
+  }
+  inline const ProgramUniformValue<Matrix>& GetProgramUniformsForType( const Matrix& ) const
+  {
+    return mProgramUniformsMat4;
+  }
+  inline const ProgramUniformValue<Matrix3>& GetProgramUniformsForType( const Matrix3& ) const
+  {
+    return mProgramUniformsMat3;
+  }
+  inline void SetVertexAttribArray(GLuint index, bool state)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return;
+    }
+    mVertexAttribArrayState[ index ] = state;
+    mVertexAttribArrayChanged = true;
+  }
+
+  ScissorParams mScissorParams;
+  ColorMaskParams mColorMaskParams;
+};
+
+template <>
+inline int TestGlAbstraction::ProgramUniformValue<int>::GetZero() const
+{
+  return 0;
+}
+
+template <>
+inline float TestGlAbstraction::ProgramUniformValue<float>::GetZero() const
+{
+  return 0.0f;
+}
+
+template <>
+inline Vector2 TestGlAbstraction::ProgramUniformValue<Vector2>::GetZero() const
+{
+  return Vector2::ZERO;
+}
+
+template <>
+inline Vector3 TestGlAbstraction::ProgramUniformValue<Vector3>::GetZero() const
+{
+  return Vector3::ZERO;
+}
+
+template <>
+inline Vector4 TestGlAbstraction::ProgramUniformValue<Vector4>::GetZero() const
+{
+  return Vector4::ZERO;
+}
+
+template <>
+inline Matrix TestGlAbstraction::ProgramUniformValue<Matrix>::GetZero() const
+{
+  return Matrix();
+}
+
+template <>
+inline Matrix3 TestGlAbstraction::ProgramUniformValue<Matrix3>::GetZero() const
+{
+  return Matrix3( Matrix() );
+}
+
+} // namespace Dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack);
+bool BlendDisabled(const Dali::TraceCallStack& callStack);
+
+
+#endif // TEST_GL_ABSTRACTION_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-context-helper-abstraction.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-context-helper-abstraction.h
new file mode 100644 (file)
index 0000000..ce150d1
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
+#define TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/gl-context-helper-abstraction.h>
+
+namespace Dali
+{
+
+/**
+ * Class to emulate the GL context helper
+ */
+class DALI_CORE_API TestGlContextHelperAbstraction: public Integration::GlContextHelperAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  TestGlContextHelperAbstraction() {};
+
+  /**
+   * Destructor
+   */
+  ~TestGlContextHelperAbstraction() {};
+
+  /**
+   * @brief Switch to the surfaceless GL context
+   */
+  virtual void MakeSurfacelessContextCurrent() {};
+
+  /**
+   * @brief Clear the GL context
+   */
+  virtual void MakeContextNull() {};
+
+  /**
+   * @brief Wait until all GL rendering calls for the current GL context are executed
+   */
+  virtual void WaitClient() {};
+private:
+
+  TestGlContextHelperAbstraction( const TestGlContextHelperAbstraction& ); ///< Undefined
+  TestGlContextHelperAbstraction& operator=( const TestGlContextHelperAbstraction& ); ///< Undefined
+};
+
+} // Dali
+
+#endif // TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
new file mode 100644 (file)
index 0000000..858e930
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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 "test-gl-sync-abstraction.h"
+
+namespace Dali
+{
+
+TestSyncObject::TestSyncObject(TraceCallStack& trace)
+: synced(false),
+  mTrace(trace)
+{
+}
+
+TestSyncObject::~TestSyncObject()
+{
+}
+
+bool TestSyncObject::IsSynced()
+{
+  mTrace.PushCall("SyncObject::IsSynced", ""); // Trace the method
+  return synced;
+}
+
+
+
+TestGlSyncAbstraction::TestGlSyncAbstraction()
+{
+  Initialize();
+}
+
+/**
+ * Destructor
+ */
+TestGlSyncAbstraction::~TestGlSyncAbstraction()
+{
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    delete *iter;
+  }
+}
+
+/**
+ * Initialize the sync objects - clear down the map
+ */
+void TestGlSyncAbstraction::Initialize()
+{
+  mSyncObjects.clear();
+}
+
+/**
+ * Create a sync object
+ * @return the sync object
+ */
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObject( )
+{
+  mTrace.PushCall("CreateSyncObject", ""); // Trace the method
+
+  TestSyncObject* syncObject = new TestSyncObject(mTrace);
+  mSyncObjects.push_back( syncObject );
+  return syncObject;
+}
+
+/**
+ * Destroy a sync object
+ * @param[in] syncObject The object to destroy
+ */
+void TestGlSyncAbstraction::DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject )
+{
+  std::stringstream out;
+  out << syncObject;
+  mTrace.PushCall("DestroySyncObject", out.str()); // Trace the method
+
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    if( *iter == syncObject )
+    {
+      delete *iter;
+      mSyncObjects.erase(iter);
+      break;
+    }
+  }
+}
+
+
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncObject( )
+{
+  if( !mSyncObjects.empty() )
+  {
+    return mSyncObjects.back();
+  }
+  return NULL;
+}
+
+/**
+ * Test method to trigger the object sync behaviour.
+ * @param[in]
+ * @param[in] sync The sync value to set
+ */
+void TestGlSyncAbstraction::SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync )
+{
+  TestSyncObject* testSyncObject = static_cast<TestSyncObject*>(syncObject);
+  testSyncObject->synced = sync;
+}
+
+/**
+ * Turn trace on
+ */
+void TestGlSyncAbstraction::EnableTrace(bool enable) { mTrace.Enable(enable); }
+
+/**
+ * Reset the trace callstack
+ */
+void TestGlSyncAbstraction::ResetTrace() { mTrace.Reset(); }
+
+/**
+ * Get the trace object (allows test case to find methods on it)
+ */
+TraceCallStack& TestGlSyncAbstraction::GetTrace() { return mTrace; }
+
+int32_t TestGlSyncAbstraction::GetNumberOfSyncObjects()
+{
+  return static_cast<int32_t>( mSyncObjects.size() );
+}
+
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.h
new file mode 100644 (file)
index 0000000..775d209
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef TEST_GL_SYNC_ABSTRACTION_H
+#define TEST_GL_SYNC_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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 <sstream>
+#include <string>
+#include <map>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-sync-abstraction.h>
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+class DALI_CORE_API TestSyncObject : public Integration::GlSyncAbstraction::SyncObject
+{
+public:
+  TestSyncObject(TraceCallStack& trace);
+  ~TestSyncObject();
+  bool IsSynced();
+  bool synced;
+  TraceCallStack& mTrace;
+};
+
+/**
+ * Class to emulate the GL sync functions with tracing
+ */
+class DALI_CORE_API TestGlSyncAbstraction: public Integration::GlSyncAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  TestGlSyncAbstraction();
+
+  /**
+   * Destructor
+   */
+  ~TestGlSyncAbstraction();
+
+  /**
+   * Initialize the sync objects - clear down the map
+   */
+  void Initialize();
+
+  /**
+   * Create a sync object
+   * @return the sync object
+   */
+  virtual Integration::GlSyncAbstraction::SyncObject* CreateSyncObject( );
+
+  /**
+   * Destroy a sync object
+   * @param[in] syncObject The object to destroy
+   */
+  virtual void DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject );
+
+
+public: // TEST FUNCTIONS
+  Integration::GlSyncAbstraction::SyncObject* GetLastSyncObject( );
+
+  /**
+   * Test method to trigger the object sync behaviour.
+   * @param[in]
+   * @param[in] sync The sync value to set
+   */
+  void SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync );
+
+  /**
+   * Turn trace on
+   */
+  void EnableTrace(bool enable);
+
+  /**
+   * Reset the trace callstack
+   */
+  void ResetTrace();
+
+  /**
+   * Get the trace object (allows test case to find methods on it)
+   */
+  TraceCallStack& GetTrace();
+
+  /**
+   * Get the number of sync objects
+   *
+   * @return the number of sync objects
+   */
+  int32_t GetNumberOfSyncObjects();
+
+private:
+
+  TestGlSyncAbstraction( const TestGlSyncAbstraction& ); ///< Undefined
+  TestGlSyncAbstraction& operator=( const TestGlSyncAbstraction& ); ///< Undefined
+
+  typedef std::vector<TestSyncObject*>   SyncContainer;
+  typedef SyncContainer::iterator SyncIter;
+  SyncContainer mSyncObjects;  ///< The sync objects
+  TraceCallStack mTrace; ///< the trace call stack for testing
+};
+
+} // Dali
+
+#endif // TEST_GL_SYNC_ABSTRACTION_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
new file mode 100644 (file)
index 0000000..b42b9f9
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2020 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 "test-harness.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <testcase.h>
+#include <fcntl.h>
+
+namespace TestHarness
+{
+
+typedef std::map<int32_t, TestCase> RunningTestCases;
+
+const char* basename(const char* path)
+{
+  const char* ptr=path;
+  const char* slash=NULL;
+  for( ; *ptr != '\0' ; ++ptr )
+  {
+    if(*ptr == '/') slash=ptr;
+  }
+  if(slash != NULL) ++slash;
+  return slash;
+}
+
+void SuppressLogOutput()
+{
+  // Close stdout and stderr to suppress the log output
+  close(STDOUT_FILENO); // File descriptor number for stdout is 1
+  close(STDERR_FILENO); // File descriptor number for stderr is 2
+
+  // The POSIX specification requires that /dev/null must be provided,
+  // The open function always chooses the lowest unused file descriptor
+  // It is sufficient for stdout to be writable.
+  open("/dev/null", O_WRONLY); // Redirect file descriptor number 1 (i.e. stdout) to /dev/null
+  // When stderr is opened it must be both readable and writable.
+  open("/dev/null", O_RDWR); // Redirect file descriptor number 2 (i.e. stderr) to /dev/null
+}
+
+int32_t RunTestCase( struct ::testcase_s& testCase )
+{
+  int32_t result = EXIT_STATUS_TESTCASE_FAILED;
+
+// dont want to catch exception as we want to be able to get
+// gdb stack trace from the first error
+// by default tests should all always pass with no exceptions
+  if( testCase.startup )
+  {
+    testCase.startup();
+  }
+  try
+  {
+    result = testCase.function();
+  }
+  catch( const char* )
+  {
+    // just catch test fail exception, return is already set to EXIT_STATUS_TESTCASE_FAILED
+  }
+  if( testCase.cleanup )
+  {
+    testCase.cleanup();
+  }
+
+  return result;
+}
+
+
+int32_t RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
+{
+  int32_t testResult = EXIT_STATUS_TESTCASE_FAILED;
+
+  int32_t pid = fork();
+  if( pid == 0 ) // Child process
+  {
+    if( suppressOutput )
+    {
+      SuppressLogOutput();
+    }
+    else
+    {
+      printf("\n");
+      for(int32_t i=0; i<80; ++i) printf("#");
+      printf("\nTC: %s\n", testCase.name);
+      fflush(stdout);
+    }
+
+    int32_t status = RunTestCase( testCase );
+
+    if( ! suppressOutput )
+    {
+      fflush(stdout);
+      fflush(stderr);
+      fclose(stdout);
+      fclose(stderr);
+    }
+    exit( status );
+  }
+  else if(pid == -1)
+  {
+    perror("fork");
+    exit(EXIT_STATUS_FORK_FAILED);
+  }
+  else // Parent process
+  {
+    int32_t status = 0;
+    int32_t childPid = waitpid(pid, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", testCase.name, testResult);
+        }
+      }
+    }
+    else if(WIFSIGNALED(status) )
+    {
+      int32_t signal = WTERMSIG(status);
+      testResult = EXIT_STATUS_TESTCASE_ABORTED;
+      if( signal == SIGABRT )
+      {
+        printf("Test case %s failed: test case asserted\n", testCase.name );
+      }
+      else
+      {
+        printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
+      }
+    }
+    else if(WIFSTOPPED(status))
+    {
+      printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
+    }
+  }
+  fflush(stdout);
+  fflush(stderr);
+  return testResult;
+}
+
+void OutputStatistics( const char* processName, int32_t numPasses, int32_t numFailures )
+{
+  FILE* fp=fopen("summary.xml", "a");
+  if( fp != NULL )
+  {
+    fprintf( fp,
+             "  <suite name=\"%s\">\n"
+             "    <total_case>%d</total_case>\n"
+             "    <pass_case>%d</pass_case>\n"
+             "    <pass_rate>%5.2f</pass_rate>\n"
+             "    <fail_case>%d</fail_case>\n"
+             "    <fail_rate>%5.2f</fail_rate>\n"
+             "    <block_case>0</block_case>\n"
+             "    <block_rate>0.00</block_rate>\n"
+             "    <na_case>0</na_case>\n"
+             "    <na_rate>0.00</na_rate>\n"
+             "  </suite>\n",
+             basename(processName),
+             numPasses+numFailures,
+             numPasses,
+             (float)numPasses/(numPasses+numFailures),
+             numFailures,
+             (float)numFailures/(numPasses+numFailures) );
+    fclose(fp);
+  }
+}
+
+int32_t RunAll( const char* processName, ::testcase tc_array[] )
+{
+  int32_t numFailures = 0;
+  int32_t numPasses = 0;
+
+  // Run test cases in child process( to kill output/handle signals ), but run serially.
+  for( uint32_t i=0; tc_array[i].name; i++)
+  {
+    int32_t result = RunTestCaseInChildProcess( tc_array[i], false );
+    if( result == 0 )
+    {
+      numPasses++;
+    }
+    else
+    {
+      numFailures++;
+    }
+  }
+
+  OutputStatistics( processName, numPasses, numFailures);
+
+  return numFailures;
+}
+
+// Constantly runs up to MAX_NUM_CHILDREN processes
+int32_t RunAllInParallel(  const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+  int32_t numFailures = 0;
+  int32_t numPasses = 0;
+
+  RunningTestCases children;
+  std::vector<int32_t> failedTestCases;
+
+  // Fork up to MAX_NUM_CHILDREN processes, then
+  // wait. As soon as a proc completes, fork the next.
+
+  int32_t nextTestCase = 0;
+  int32_t numRunningChildren = 0;
+
+  while( tc_array[nextTestCase].name || numRunningChildren > 0)
+  {
+    // Create more children (up to the max number or til the end of the array)
+    while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
+    {
+      int32_t pid = fork();
+      if( pid == 0 ) // Child process
+      {
+        SuppressLogOutput();
+        exit( RunTestCase( tc_array[nextTestCase] ) );
+      }
+      else if(pid == -1)
+      {
+        perror("fork");
+        exit(EXIT_STATUS_FORK_FAILED);
+      }
+      else // Parent process
+      {
+        TestCase tc(nextTestCase, tc_array[nextTestCase].name);
+        children[pid] = tc;
+        nextTestCase++;
+        numRunningChildren++;
+      }
+    }
+
+    // Wait for the next child to finish
+
+    int32_t status=0;
+    int32_t childPid = waitpid(-1, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        int32_t testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
+          failedTestCases.push_back(children[childPid].testCase);
+          numFailures++;
+        }
+        else
+        {
+          numPasses++;
+        }
+        numRunningChildren--;
+      }
+    }
+
+    else if( WIFSIGNALED(status) || WIFSTOPPED(status))
+    {
+      status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
+
+      if( childPid > 0 )
+      {
+        RunningTestCases::iterator iter = children.find(childPid);
+        if( iter != children.end() )
+        {
+          printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
+          failedTestCases.push_back(iter->second.testCase);
+        }
+        else
+        {
+          printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
+        }
+
+        numFailures++;
+        numRunningChildren--;
+      }
+    }
+  }
+
+  OutputStatistics( processName, numPasses, numFailures );
+
+  if( reRunFailed )
+  {
+    for( uint32_t i=0; i<failedTestCases.size(); i++)
+    {
+      char* testCaseStrapline;
+      int32_t numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
+      printf("\n%s\n", testCaseStrapline);
+      for(int32_t j=0; j<numChars; j++)
+      {
+        printf("=");
+      }
+      printf("\n");
+      RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
+    }
+  }
+
+  return numFailures;
+}
+
+
+
+int32_t FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
+{
+  int32_t result = EXIT_STATUS_TESTCASE_NOT_FOUND;
+
+  for( int32_t i = 0; tc_array[i].name; i++ )
+  {
+    if( !strcmp(testCaseName, tc_array[i].name) )
+    {
+      return RunTestCase( tc_array[i] );
+    }
+  }
+
+  printf("Unknown testcase name: \"%s\"\n", testCaseName);
+  return result;
+}
+
+void Usage(const char* program)
+{
+  printf("Usage: \n"
+         "   %s <testcase name>\t\t Execute a test case\n"
+         "   %s \t\t Execute all test cases in parallel\n"
+         "   %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n"
+         "   %s -s\t\t Execute all test cases serially\n",
+         program, program, program, program);
+}
+
+} // namespace
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-harness.h
new file mode 100644 (file)
index 0000000..e40492c
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef TEST_HARNESS_H
+#define TEST_HARNESS_H
+
+/*
+ * Copyright (c) 2018 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 <stdio.h>
+#include <testcase.h>
+#include <cstdint>
+
+namespace TestHarness
+{
+
+enum ExitStatus
+{
+  EXIT_STATUS_TESTCASE_SUCCEEDED,   // 0
+  EXIT_STATUS_TESTCASE_FAILED,      // 1
+  EXIT_STATUS_TESTCASE_ABORTED,     // 2
+  EXIT_STATUS_FORK_FAILED,          // 3
+  EXIT_STATUS_WAITPID_FAILED,       // 4
+  EXIT_STATUS_BAD_ARGUMENT,         // 5
+  EXIT_STATUS_TESTCASE_NOT_FOUND    // 6
+};
+
+const int32_t MAX_NUM_CHILDREN(16);
+
+struct TestCase
+{
+  int32_t testCase;
+  const char* testCaseName;
+
+  TestCase()
+  : testCase(0),
+    testCaseName(NULL)
+  {
+  }
+
+  TestCase(int32_t tc, const char* name)
+  : testCase(tc),
+    testCaseName(name)
+  {
+  }
+  TestCase(const TestCase& rhs)
+  : testCase(rhs.testCase),
+    testCaseName(rhs.testCaseName)
+  {
+  }
+  TestCase& operator=(const TestCase& rhs)
+  {
+    testCase = rhs.testCase;
+    testCaseName = rhs.testCaseName;
+    return *this;
+
+  }
+};
+
+/**
+ * Run a test case
+ * @param[in] testCase The Testkit-lite test case to run
+ */
+int32_t RunTestCase( struct testcase_s& testCase );
+
+/**
+ * Run all test cases in parallel
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int32_t RunAllInParallel(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Run all test cases in serial
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @return 0 on success
+ */
+int32_t RunAll( const char* processName, testcase tc_array[] );
+
+/**
+ * Find the named test case in the given array, and run it
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] testCaseName the name of the test case to run
+ * @return 0 on success
+ */
+int32_t FindAndRunTestCase(::testcase tc_array[], const char* testCaseName);
+
+/**
+ * Display usage instructions for this program
+ * @param[in] program The name of this program
+ */
+void Usage(const char* program);
+
+} // namespace TestHarness
+
+#endif
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-intrusive-ptr.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-intrusive-ptr.h
new file mode 100644 (file)
index 0000000..5fb17da
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef TEST_INTRUSIVE_PTR_H
+#define TEST_INTRUSIVE_PTR_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <iostream>
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali-test-suite-utils.h>
+
+namespace Dali
+{
+
+template <typename T>
+struct UtcCoverageIntrusivePtr
+{
+  typedef IntrusivePtr<T> (*Creator)();
+
+  void Check( Creator creator)
+  {
+    IntrusivePtr<T> a = creator();
+    IntrusivePtr<T> b = creator();
+
+    DALI_TEST_CHECK( a.Get() );
+
+    a.Reset();
+
+    T* pB = b.Detach();
+
+    a.Reset(pB);
+
+    DALI_TEST_CHECK(a);
+
+    a.Reset();
+
+  };
+
+};
+
+} // Dali
+
+#endif // TEST_INTRUSIVE_PTR_H
+
+
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp
new file mode 100644 (file)
index 0000000..ee6c17a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 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 "test-application.h"
+#include "test-native-image.h"
+
+
+namespace Dali
+{
+
+TestNativeImagePointer TestNativeImage::New(uint32_t width, uint32_t height)
+{
+  return new TestNativeImage(width, height);
+}
+
+TestNativeImage::TestNativeImage(uint32_t width, uint32_t height)
+: mWidth(width), mHeight(height), mExtensionCreateCalls(0), mExtensionDestroyCalls(0), mTargetTextureCalls(0),createResult(true)
+{
+  mExtension = new TestNativeImageExtension();
+}
+
+TestNativeImage::~TestNativeImage()
+{
+}
+
+
+TestNativeImageNoExtPointer TestNativeImageNoExt::New(uint32_t width, uint32_t height)
+{
+  return new TestNativeImageNoExt(width, height);
+}
+
+TestNativeImageNoExt::TestNativeImageNoExt(uint32_t width, uint32_t height)
+: mWidth(width), mHeight(height), mExtensionCreateCalls(0), mExtensionDestroyCalls(0), mTargetTextureCalls(0),createResult(true)
+{
+}
+
+TestNativeImageNoExt::~TestNativeImageNoExt()
+{
+}
+
+} // namespace dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-native-image.h
new file mode 100644 (file)
index 0000000..0c215b7
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef TEST_NATIVE_IMAGE_H
+#define TEST_NATIVE_IMAGE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/images/native-image-interface.h>
+#include <dali/devel-api/images/native-image-interface-extension.h>
+#include <dali/integration-api/gl-defines.h>
+
+namespace Dali
+{
+class TestNativeImage;
+class TestNativeImageNoExt;
+typedef IntrusivePtr<TestNativeImage> TestNativeImagePointer;
+typedef IntrusivePtr<TestNativeImageNoExt> TestNativeImageNoExtPointer;
+
+class DALI_CORE_API TestNativeImageExtension: public Dali::NativeImageInterface::Extension
+{
+public:
+  inline const char* GetCustomFragmentPreFix(){return "#extension GL_OES_EGL_image_external:require\n";}
+  inline const char* GetCustomSamplerTypename(){return "samplerExternalOES";}
+
+  inline int32_t GetEglImageTextureTarget(){return GL_TEXTURE_EXTERNAL_OES;}
+
+};
+
+class DALI_CORE_API TestNativeImage : public Dali::NativeImageInterface
+{
+public:
+  static TestNativeImagePointer New(uint32_t width, uint32_t height);
+
+  inline void SetGlExtensionCreateResult(bool result){ createResult = result;}
+  inline virtual bool GlExtensionCreate() { ++mExtensionCreateCalls; return createResult;};
+  inline virtual void GlExtensionDestroy() { ++mExtensionDestroyCalls; };
+  inline virtual GLenum TargetTexture() { ++mTargetTextureCalls; return 0;};
+  inline virtual void PrepareTexture() {};
+  inline virtual uint32_t GetWidth() const {return mWidth;};
+  inline virtual uint32_t GetHeight() const {return mHeight;};
+  inline virtual bool RequiresBlending() const {return true;};
+  inline virtual Dali::NativeImageInterface::Extension* GetExtension() {return mExtension;}
+
+private:
+  TestNativeImage(uint32_t width, uint32_t height);
+  virtual ~TestNativeImage();
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+public:
+  int32_t mExtensionCreateCalls;
+  int32_t mExtensionDestroyCalls;
+  int32_t mTargetTextureCalls;
+
+  bool createResult;
+  TestNativeImageExtension* mExtension;
+};
+
+
+class DALI_CORE_API TestNativeImageNoExt : public Dali::NativeImageInterface
+{
+public:
+  static TestNativeImageNoExtPointer New(uint32_t width, uint32_t height);
+
+  inline void SetGlExtensionCreateResult(bool result){ createResult = result;}
+  inline virtual bool GlExtensionCreate() { ++mExtensionCreateCalls; return createResult;};
+  inline virtual void GlExtensionDestroy() { ++mExtensionDestroyCalls; };
+  inline virtual GLenum TargetTexture() { ++mTargetTextureCalls; return 1;};
+  inline virtual void PrepareTexture() {};
+  inline virtual uint32_t GetWidth() const {return mWidth;};
+  inline virtual uint32_t GetHeight() const {return mHeight;};
+  inline virtual bool RequiresBlending() const {return true;};
+
+private:
+  TestNativeImageNoExt(uint32_t width, uint32_t height);
+  virtual ~TestNativeImageNoExt();
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+public:
+  int32_t mExtensionCreateCalls;
+  int32_t mExtensionDestroyCalls;
+  int32_t mTargetTextureCalls;
+  bool createResult;
+};
+
+} // Dali
+
+#endif // TEST_NATIVE_IMAGE_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp
new file mode 100644 (file)
index 0000000..3962870
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2019 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 "test-platform-abstraction.h"
+#include "dali-test-suite-utils.h"
+#include <dali/integration-api/bitmap.h>
+
+namespace Dali
+{
+
+TestPlatformAbstraction::TestPlatformAbstraction()
+: mTrace(),
+  mIsLoadingResult( false ),
+  mClosestSize(),
+  mLoadFileResult(),
+  mSaveFileResult( false ),
+  mSynchronouslyLoadedResource(),
+  mTimerId(0),
+  mCallbackFunction(nullptr)
+{
+  Initialize();
+}
+
+TestPlatformAbstraction::~TestPlatformAbstraction()
+{
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( const std::string& filename,
+                                                              ImageDimensions size,
+                                                              FittingMode::Type fittingMode,
+                                                              SamplingMode::Type samplingMode,
+                                                              bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                                   ImageDimensions size,
+                                                   FittingMode::Type fittingMode,
+                                                   SamplingMode::Type samplingMode,
+                                                   bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+Integration::ResourcePointer TestPlatformAbstraction::LoadImageSynchronously( const Integration::BitmapResourceType& resourceType, const std::string& resourcePath )
+{
+  mTrace.PushCall("LoadResourceSynchronously", "");
+  return mSynchronouslyLoadedResource;
+}
+
+Integration::BitmapPtr TestPlatformAbstraction::DecodeBuffer( const Integration::BitmapResourceType& resourceType, uint8_t * buffer, size_t size )
+{
+  mTrace.PushCall("DecodeBuffer", "");
+  return mDecodedBitmap;
+}
+
+bool TestPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  mTrace.PushCall("LoadShaderBinaryFile", "");
+  if( mLoadFileResult.loadResult )
+  {
+    buffer = mLoadFileResult.buffer;
+  }
+
+  return mLoadFileResult.loadResult;
+}
+
+/** Call this every test */
+void TestPlatformAbstraction::Initialize()
+{
+  mTrace.Reset();
+  mTrace.Enable(true);
+  mIsLoadingResult=false;
+  mSynchronouslyLoadedResource.Reset();
+  mDecodedBitmap.Reset();
+}
+
+bool TestPlatformAbstraction::WasCalled(TestFuncEnum func)
+{
+  switch(func)
+  {
+    case LoadResourceSynchronouslyFunc:       return mTrace.FindMethod("LoadResourceSynchronously");
+    case LoadShaderBinaryFileFunc:            return mTrace.FindMethod("LoadShaderBinaryFile");
+    case SaveShaderBinaryFileFunc:            return mTrace.FindMethod("SaveShaderBinaryFile");
+  }
+  return false;
+}
+
+void TestPlatformAbstraction::SetIsLoadingResult(bool result)
+{
+  mIsLoadingResult = result;
+}
+
+void TestPlatformAbstraction::ClearReadyResources()
+{
+  mSynchronouslyLoadedResource.Reset();
+  mDecodedBitmap.Reset();
+}
+
+void TestPlatformAbstraction::SetClosestImageSize( const Vector2& size )
+{
+  mClosestSize = ImageDimensions( static_cast<uint32_t>( size.x ), static_cast<uint32_t>( size.y ) );
+}
+
+void TestPlatformAbstraction::SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer )
+{
+  mLoadFileResult.loadResult = result;
+  if( result )
+  {
+    mLoadFileResult.buffer = buffer;
+  }
+}
+
+void TestPlatformAbstraction::SetSaveFileResult( bool result )
+{
+  mSaveFileResult = result;
+}
+
+void TestPlatformAbstraction::SetSynchronouslyLoadedResource( Integration::ResourcePointer resource )
+{
+  mSynchronouslyLoadedResource = resource;
+}
+
+void TestPlatformAbstraction::SetDecodedBitmap( Integration::BitmapPtr bitmap )
+{
+  mDecodedBitmap = bitmap;
+}
+
+uint32_t TestPlatformAbstraction::StartTimer( uint32_t milliseconds, CallbackBase* callback )
+{
+  mCallbackFunction = callback;
+  mTimerId++;
+  return mTimerId;
+}
+
+void TestPlatformAbstraction::TriggerTimer()
+{
+  if (mCallbackFunction != nullptr)
+  {
+    CallbackBase::Execute( *mCallbackFunction );
+  }
+}
+
+void TestPlatformAbstraction::CancelTimer ( uint32_t timerId )
+{
+  mCallbackFunction = nullptr;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.h
new file mode 100644 (file)
index 0000000..7c1b010
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef DALI_TEST_PLATFORM_ABSTRACTION_H
+#define DALI_TEST_PLATFORM_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+#include <cstring>
+#include <string>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/public-api/math/vector2.h>
+
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+/**
+ * Concrete implementation of the platform abstraction class.
+ */
+class DALI_CORE_API TestPlatformAbstraction : public Dali::Integration::PlatformAbstraction
+{
+
+public:
+
+  /**
+   * Constructor
+   */
+  TestPlatformAbstraction();
+
+  /**
+   * Destructor
+   */
+  virtual ~TestPlatformAbstraction();
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( const std::string& filename,
+                                                 ImageDimensions size,
+                                                 FittingMode::Type fittingMode,
+                                                 SamplingMode::Type samplingMode,
+                                                 bool orientationCorrection );
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                               ImageDimensions size,
+                                               FittingMode::Type fittingMode,
+                                               SamplingMode::Type samplingMode,
+                                               bool orientationCorrection );
+
+  /**
+   * @copydoc PlatformAbstraction::LoadResourceSynchronously()
+   */
+  virtual Integration::ResourcePointer LoadImageSynchronously( const Integration::BitmapResourceType& resourceType, const std::string& resourcePath );
+
+  /**
+   * @copydoc PlatformAbstraction::DecodeBuffer()
+   */
+  virtual Integration::BitmapPtr DecodeBuffer( const Dali::Integration::BitmapResourceType& resourceType, uint8_t * buffer, size_t size );
+
+  /**
+   * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
+   */
+  virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
+
+  /**
+   * @copydoc PlatformAbstraction::SaveShaderBinaryFile()
+   */
+  virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const { return true; }
+
+  /**
+   * @copydoc PlatformAbstraction::StartTimer()
+   */
+  virtual uint32_t StartTimer( uint32_t milliseconds, CallbackBase* callback );
+
+  /*
+   * @copydoc PlatformAbstraction::CancelTimer()
+   */
+  virtual void CancelTimer ( uint32_t timerId );
+
+public: // TEST FUNCTIONS
+
+  // Enumeration of Platform Abstraction methods
+  typedef enum
+  {
+    LoadResourceSynchronouslyFunc,
+    LoadShaderBinaryFileFunc,
+    SaveShaderBinaryFileFunc
+  } TestFuncEnum;
+
+  /** Call this every test */
+  void Initialize();
+
+  inline void EnableTrace(bool enable) { mTrace.Enable(enable); }
+  inline void ResetTrace() { mTrace.Reset(); }
+  inline TraceCallStack& GetTrace() { return mTrace; }
+
+  /**
+   * @brief Checks if a platform function was called
+   * @param[in] func The function to check
+   * @return true if the function was called
+   */
+  bool WasCalled(TestFuncEnum func);
+
+  /**
+   * @brief Sets the result to return when IsLoading is called by Core.
+   * @param[in] result The result to set.
+   */
+  void SetIsLoadingResult(bool result);
+
+  /**
+   * @brief Clears all resource queues
+   */
+  void ClearReadyResources();
+
+  /**
+   * @brief Sets the value returned by GetClosestImageSize.
+   * @param[in] size The size that should be returned.
+   */
+  void SetClosestImageSize( const Vector2& size );
+
+  /**
+   * @brief Sets the result return by LoadFile.
+   * @param[in] result The value that LoadFile should return.
+   * @param[in] buffer The buffer of the loaded file.
+   */
+  void SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer );
+
+  /**
+   * @brief Sets the SaveFile result
+   * @param[in] result The value that SaveFile should return
+   */
+  void SetSaveFileResult( bool result );
+
+  /**
+   * @brief Sets the resource loaded by LoadResourceSynchronously
+   * @param[in] resource The loaded resource
+   */
+  void SetSynchronouslyLoadedResource( Integration::ResourcePointer resource );
+
+  /**
+   * @brief Sets the bitmap returned by DecodeBuffer()
+   * @param[in] bitmap The decoded bitmap
+   */
+  void SetDecodedBitmap( Integration::BitmapPtr bitmap );
+
+  /**
+   * @brief Triggers the previously stored callback function
+   */
+  void TriggerTimer();
+
+private:
+
+  TestPlatformAbstraction( const TestPlatformAbstraction& ); ///< Undefined
+  TestPlatformAbstraction& operator=( const TestPlatformAbstraction& ); ///< Undefined
+
+private:
+
+  struct LoadFileResult
+  {
+    inline LoadFileResult()
+    : loadResult(false)
+    {
+
+    }
+
+    bool loadResult;
+    Dali::Vector< unsigned char> buffer;
+  };
+
+  mutable TraceCallStack        mTrace;
+  bool                          mIsLoadingResult;
+  ImageDimensions               mClosestSize;
+
+  LoadFileResult                mLoadFileResult;
+  bool                          mSaveFileResult;
+
+  Integration::ResourcePointer  mSynchronouslyLoadedResource;
+  Integration::BitmapPtr        mDecodedBitmap;
+
+  uint32_t                      mTimerId;
+  CallbackBase*                 mCallbackFunction;
+};
+
+} // Dali
+
+#endif /* DALI_TEST_PLATFORM_ABSTRACTION_H */
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.cpp
new file mode 100644 (file)
index 0000000..6f845d4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017 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 "test-render-controller.h"
+
+namespace Dali
+{
+
+TestRenderController::TestRenderController()
+{
+  Initialize();
+}
+
+TestRenderController::~TestRenderController()
+{
+}
+
+void TestRenderController::RequestUpdate( bool forceUpdate )
+{
+  mRequestUpdateCalled = true;
+}
+
+void TestRenderController::RequestProcessEventsOnIdle( bool forceProcess )
+{
+  mRequestProcessEventsOnIdleCalled = true;
+}
+
+bool TestRenderController::WasCalled(TestRenderControllerFuncEnum func)
+{
+  switch(func)
+  {
+    case RequestUpdateFunc: return mRequestUpdateCalled;
+    case RequestProcessEventsOnIdleFunc: return mRequestProcessEventsOnIdleCalled;
+  }
+
+  return false;
+}
+
+void TestRenderController::Initialize()
+{
+  mRequestUpdateCalled = false;
+  mRequestProcessEventsOnIdleCalled = false;
+}
+
+
+} // namespace dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-render-controller.h
new file mode 100644 (file)
index 0000000..d44e7b6
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef TEST_RENDER_CONTROLLER_H
+#define TEST_RENDER_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/render-controller.h>
+
+namespace Dali
+{
+
+class DALI_CORE_API TestRenderController : public Dali::Integration::RenderController
+{
+public:
+  TestRenderController();
+  ~TestRenderController();
+
+  virtual void RequestUpdate( bool forceUpdate );
+  virtual void RequestProcessEventsOnIdle( bool forceProcess );
+
+  typedef enum
+  {
+    RequestUpdateFunc,
+    RequestProcessEventsOnIdleFunc,
+  } TestRenderControllerFuncEnum;
+
+  bool WasCalled(TestRenderControllerFuncEnum func);
+  void Initialize();
+
+
+private:
+  bool mRequestUpdateCalled;
+  bool mRequestProcessEventsOnIdleCalled;
+};
+
+} // Dali
+
+#endif // TEST_RENDER_CONTROLLER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-touch-utils.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-touch-utils.h
new file mode 100644 (file)
index 0000000..3a623cb
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef TEST_TOUCH_UTILS_H
+#define TEST_TOUCH_UTILS_H
+
+/*
+ * Copyright (c) 2019 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/actors/actor.h>
+
+namespace Dali
+{
+
+// Data for touch events
+struct TouchEventData
+{
+  TouchEventData()
+  : functorCalled(false),
+    receivedTouch(),
+    touchActor()
+  {
+  }
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    receivedTouch.points.clear();
+    receivedTouch.time = 0;
+
+    touchActor.Reset();
+  }
+
+  bool functorCalled;
+  TouchEvent receivedTouch;
+  Actor touchActor;
+};
+
+// Functor that sets the data when called
+struct TouchEventDataFunctor
+{
+  TouchEventDataFunctor(TouchEventData& data) : touchEventData(data) { }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    touchEventData.functorCalled = true;
+    touchEventData.touchActor = actor;
+    touchEventData.receivedTouch = touch;
+    return false;
+  }
+
+  // Generate a touch-event
+  Integration::TouchEvent GenerateSingleTouch( PointState::Type state, const Vector2& screenPosition ) const
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::Point point;
+    point.SetState( state );
+    point.SetScreenPosition( screenPosition );
+    touchEvent.points.push_back( point );
+    return touchEvent;
+  }
+
+  TouchEventData& touchEventData;
+};
+
+
+} // namespace Dali
+
+#endif // TEST_TOUCH_UTILS_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.cpp
new file mode 100644 (file)
index 0000000..f894389
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017 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 "test-trace-call-stack.h"
+#include <sstream>
+
+namespace Dali
+{
+
+std::string ToString(int x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+std::string ToString(unsigned int x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+std::string ToString(float x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+/**
+ * Constructor
+ */
+TraceCallStack::TraceCallStack() : mTraceActive(false) { }
+
+/**
+ * Destructor
+ */
+TraceCallStack::~TraceCallStack() { }
+
+/**
+ * Turn on / off tracing
+ */
+void TraceCallStack::Enable(bool enable) { mTraceActive = enable; }
+
+bool TraceCallStack::IsEnabled() { return mTraceActive; }
+
+/**
+ * Push a call onto the stack if the trace is active
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ */
+void TraceCallStack::PushCall(std::string method, std::string params)
+{
+  if(mTraceActive)
+  {
+    FunctionCall stackFrame(method, params);
+    mCallStack.push_back( stackFrame );
+  }
+}
+
+void TraceCallStack::PushCall(std::string method, std::string params, const TraceCallStack::NamedParams& altParams)
+{
+  if(mTraceActive)
+  {
+    FunctionCall stackFrame(method, params, altParams);
+    mCallStack.push_back( stackFrame );
+  }
+}
+
+/**
+ * Search for a method in the stack
+ * @param[in] method The name of the method
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethod(std::string method) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      found = true;
+      break;
+    }
+  }
+  return found;
+}
+
+bool TraceCallStack::FindMethodAndGetParameters(std::string method, std::string& params ) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      found = true;
+      params = mCallStack[i].paramList;
+      break;
+    }
+  }
+  return found;
+}
+
+int TraceCallStack::CountMethod(std::string method) const
+{
+  int numCalls = 0;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      numCalls++;
+    }
+  }
+  return numCalls;
+}
+
+/**
+ * Search for a method in the stack with the given parameter list
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethodAndParams(std::string method, std::string params) const
+{
+  return FindIndexFromMethodAndParams( method, params ) > -1;
+}
+
+bool TraceCallStack::FindMethodAndParams(std::string method, const NamedParams& params) const
+{
+  return FindIndexFromMethodAndParams( method, params ) > -1;
+}
+
+bool TraceCallStack::FindMethodAndParamsFromStartIndex( std::string method, std::string params, size_t& startIndex ) const
+{
+  for( size_t i = startIndex; i < mCallStack.size(); ++i )
+  {
+    if( ( mCallStack[i].method.compare( method ) == 0 ) && ( mCallStack[i].paramList.compare( params ) == 0 ) )
+    {
+      startIndex = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Search for a method in the stack with the given parameter list
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ * @return index in the stack where the method was found or -1 otherwise
+ */
+int32_t TraceCallStack::FindIndexFromMethodAndParams(std::string method, std::string params) const
+{
+  int32_t index = -1;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) && 0 == mCallStack[i].paramList.compare(params) )
+    {
+      index = static_cast<int32_t>( i );
+      break;
+    }
+  }
+  return index;
+}
+
+int TraceCallStack::FindIndexFromMethodAndParams(std::string method, const TraceCallStack::NamedParams& params) const
+{
+  int32_t index = -1;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      // Test each of the passed in parameters:
+      bool match = true;
+      for( NamedParams::const_iterator iter = params.begin() ; iter != params.end() ; ++iter )
+      {
+        NamedParams::const_iterator paramIter = mCallStack[i].namedParams.find(iter->first);
+        if( paramIter == params.end() || paramIter->second.compare(iter->second) != 0 )
+        {
+          match = false;
+          break;
+        }
+      }
+      if( match == true )
+      {
+        index = static_cast<int32_t>( i );
+        break;
+      }
+    }
+  }
+  return index;
+}
+
+
+/**
+ * Test if the given method and parameters are at a given index in the stack
+ * @param[in] index Index in the call stack
+ * @param[in] method Name of method to test
+ * @param[in] params A comma separated list of parameter values to test
+ */
+bool TraceCallStack::TestMethodAndParams(int index, std::string method, std::string params) const
+{
+  return ( 0 == mCallStack[index].method.compare(method) && 0 == mCallStack[index].paramList.compare(params) );
+}
+
+/**
+ * Reset the call stack
+ */
+void TraceCallStack::Reset()
+{
+  mCallStack.clear();
+}
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.h
new file mode 100644 (file)
index 0000000..d569cba
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef TEST_TRACE_CALL_STACK_H
+#define TEST_TRACE_CALL_STACK_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.
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <map>
+#include <sstream>
+
+namespace Dali
+{
+
+template<typename T>
+std::string ToString(const T& x)
+{
+  return "undefined";
+}
+
+std::string ToString(int x);
+std::string ToString(unsigned int x);
+std::string ToString(float x);
+
+/**
+ * Helper class to track method calls in the abstraction and search for them in test cases
+ */
+class TraceCallStack
+{
+public:
+
+  /// Typedef for passing and storing named parameters
+  typedef std::map< std::string, std::string > NamedParams;
+
+  /**
+   * Constructor
+   */
+  TraceCallStack();
+
+  /**
+   * Destructor
+   */
+  ~TraceCallStack();
+
+  /**
+   * Turn on / off tracing
+   */
+  void Enable(bool enable);
+
+  bool IsEnabled();
+
+  /**
+   * Push a call onto the stack if the trace is active
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   */
+  void PushCall(std::string method, std::string params);
+
+  /**
+   * Push a call onto the stack if the trace is active
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @param[in] altParams A map of named parameter values
+   */
+  void PushCall(std::string method, std::string params, const NamedParams& altParams);
+
+  /**
+   * Search for a method in the stack
+   * @param[in] method The name of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethod(std::string method) const;
+
+  /**
+   * Search for a method in the stack and return its parameters if found
+   * @param[in] method The name of the method
+   * @param[out] params of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndGetParameters(std::string method, std::string& params ) const;
+
+  /**
+   * Count how many times a method was called
+   * @param[in] method The name of the method
+   * @return The number of times it was called
+   */
+  int CountMethod(std::string method) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndParams(std::string method, std::string params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A map of named parameters to test for
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndParams(std::string method, const NamedParams& params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list.
+   * The search is done from a given index.
+   * This allows the order of methods and parameters to be checked.
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @param[in/out] startIndex The method index to start looking from.
+   *                This is updated if a method is found so subsequent
+   *                calls can search for methods occuring after this one.
+   * @return True if the method was in the stack
+   */
+  bool FindMethodAndParamsFromStartIndex( std::string method, std::string params, size_t& startIndex ) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @return index in the stack where the method was found or -1 otherwise
+   */
+  int FindIndexFromMethodAndParams(std::string method, std::string params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A map of named parameter values to match
+   * @return index in the stack where the method was found or -1 otherwise
+   */
+  int FindIndexFromMethodAndParams(std::string method, const NamedParams& params) const;
+
+  /**
+   * Test if the given method and parameters are at a given index in the stack
+   * @param[in] index Index in the call stack
+   * @param[in] method Name of method to test
+   * @param[in] params A comma separated list of parameter values to test
+   */
+  bool TestMethodAndParams(int index, std::string method, std::string params) const;
+
+  /**
+   * Reset the call stack
+   */
+  void Reset();
+
+  /**
+   * Method to display contents of the TraceCallStack.
+   * @return A string containing a list of function calls and parameters (may contain newline characters)
+   */
+  std::string GetTraceString()
+  {
+    std::stringstream traceStream;
+    std::size_t functionCount = mCallStack.size();
+    for( std::size_t i = 0; i < functionCount; ++i )
+    {
+      Dali::TraceCallStack::FunctionCall functionCall = mCallStack[ i ];
+      traceStream << "StackTrace: Index:" << i << ",  Function:" << functionCall.method << ",  ParamList:" << functionCall.paramList << std::endl;
+    }
+
+    return traceStream.str();
+  }
+
+private:
+  bool mTraceActive; ///< True if the trace is active
+
+  struct FunctionCall
+  {
+    std::string method;
+    std::string paramList;
+    NamedParams namedParams;
+    FunctionCall( const std::string& aMethod, const std::string& aParamList )
+    : method( aMethod ), paramList( aParamList )
+    {
+    }
+    FunctionCall( const std::string& aMethod, const std::string& aParamList, const NamedParams& altParams )
+    : method( aMethod ), paramList( aParamList ), namedParams( altParams )
+    {
+    }
+  };
+
+  std::vector< FunctionCall > mCallStack; ///< The call stack
+};
+
+} // namespace dali
+
+#endif // TEST_TRACE_CALL_STACK_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
new file mode 100644 (file)
index 0000000..df3e5d5
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2019 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/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/accessibility-action-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Stub for the AccessibilityAdaptor
+ */
+class AccessibilityAdaptor : public BaseObject
+{
+public: // Creation & Destruction
+
+  static Dali::AccessibilityAdaptor Get();
+
+  AccessibilityAdaptor();
+  ~AccessibilityAdaptor();
+
+public:
+
+  // Functions to modify mock returns:
+
+  void MockSetReadPosition( Vector2& position );
+
+  void SetEnabled(bool enabled)
+  {
+    mIsEnabled = enabled;
+  }
+
+  void SendPanGesture( const AccessibilityGestureEvent& panEvent );
+
+public:
+
+  bool IsEnabled() const;
+  void SetActionHandler(Dali::AccessibilityActionHandler& handler);
+  void SetGestureHandler(Dali::AccessibilityGestureHandler& handler);
+
+  Vector2 GetReadPosition() const;
+
+  bool HandleActionNextEvent(bool);
+  bool HandleActionPreviousEvent(bool);
+  bool HandleActionActivateEvent();
+  bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain);
+  bool HandleActionReadNextEvent(bool);
+  bool HandleActionReadPreviousEvent(bool);
+  bool HandleActionUpEvent();
+  bool HandleActionDownEvent();
+  bool HandleActionClearFocusEvent();
+  bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp);
+  bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp);
+  bool HandleActionBackEvent();
+  bool HandleActionEnableEvent();
+  bool HandleActionDisableEvent();
+  bool HandleActionScrollUpEvent();
+  bool HandleActionScrollDownEvent();
+  bool HandleActionPageLeftEvent();
+  bool HandleActionPageRightEvent();
+  bool HandleActionPageUpEvent();
+  bool HandleActionPageDownEvent();
+  bool HandleActionMoveToFirstEvent();
+  bool HandleActionMoveToLastEvent();
+  bool HandleActionReadFromTopEvent();
+  bool HandleActionReadFromNextEvent();
+  bool HandleActionZoomEvent();
+  bool HandleActionReadPauseResumeEvent();
+  bool HandleActionStartStopEvent();
+
+private:
+
+  bool mIsEnabled;
+  Dali::AccessibilityActionHandler* mActionHandler;
+  Dali::AccessibilityGestureHandler* mGestureHandler;
+  Vector2 mReadPosition;
+
+  static Dali::AccessibilityAdaptor mToolkitAccessibilityAdaptor;
+};
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::mToolkitAccessibilityAdaptor;
+
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  if( !mToolkitAccessibilityAdaptor )
+  {
+    mToolkitAccessibilityAdaptor = Dali::AccessibilityAdaptor( new Dali::Internal::Adaptor::AccessibilityAdaptor() );
+  }
+  return mToolkitAccessibilityAdaptor;
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+: mIsEnabled(false),
+  mActionHandler(NULL),
+  mGestureHandler(NULL),
+  mReadPosition( 0.0f, 0.0f )
+{
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return mReadPosition;
+}
+
+void AccessibilityAdaptor::MockSetReadPosition( Vector2& position )
+{
+  mReadPosition = position;
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return mIsEnabled;
+}
+
+void AccessibilityAdaptor::SendPanGesture( const AccessibilityGestureEvent& panEvent )
+{
+  mGestureHandler->HandlePanGesture( panEvent );
+}
+
+void AccessibilityAdaptor::SetActionHandler(Dali::AccessibilityActionHandler& handler)
+{
+  mActionHandler = &handler;
+}
+
+void AccessibilityAdaptor::SetGestureHandler(Dali::AccessibilityGestureHandler& handler)
+{
+  mGestureHandler = &handler;
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionNext( true );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionPrevious( true );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionActivate();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y,  bool allowReadAgain)
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionRead( allowReadAgain );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionReadNext( true );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionReadPrevious( true );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionUp();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionDown();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->ClearAccessibilityFocus();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  if( mActionHandler )
+  {
+    Dali::TouchEvent touchEvent;
+    touchEvent.points.push_back( point );
+    return mActionHandler->AccessibilityActionScroll( touchEvent );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  if( mActionHandler )
+  {
+    Dali::TouchEvent touchEvent;
+    touchEvent.points.push_back( point );
+    return mActionHandler->AccessibilityActionTouch( touchEvent );
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionBack();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->ChangeAccessibilityStatus();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->ChangeAccessibilityStatus();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionScrollUp();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionScrollDown();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionPageLeft();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionPageRight();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionPageUp();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionPageDown();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionMoveToFirst();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionMoveToLast();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionReadFromTop();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionReadFromNext();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionZoom();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionReadPauseResume();
+  }
+  return false;
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  if( mActionHandler )
+  {
+    return mActionHandler->AccessibilityActionStartStop();
+  }
+  return false;
+}
+
+static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor)
+{
+  BaseObject& handle = adaptor.GetBaseObject();
+  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
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+{
+}
+
+AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::Get();
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+}
+
+// Methods:
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetReadPosition();
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return Internal::Adaptor::GetImplementation(*this).IsEnabled();
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  Internal::Adaptor::GetImplementation(*this).SetActionHandler(handler);
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  Internal::Adaptor::GetImplementation(*this).SetGestureHandler(handler);
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionActivateEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y,  bool allowReadAgain)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadEvent( x, y, allowReadAgain );
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionClearFocusEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionScrollEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionTouchEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionBackEvent();
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  Internal::Adaptor::GetImplementation(*this).HandleActionEnableEvent();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  Internal::Adaptor::GetImplementation(*this).HandleActionDisableEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionScrollUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionScrollDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionPageLeftEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionPageRightEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionPageUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionPageDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionMoveToFirstEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionMoveToLastEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadFromTopEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadFromNextEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionZoomEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionReadPauseResumeEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  return Internal::Adaptor::GetImplementation(*this).HandleActionStartStopEvent();
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* adaptor )
+: BaseHandle( adaptor )
+{
+}
+
+} // namespace Dali
+
+
+namespace Test
+{
+namespace AccessibilityAdaptor
+{
+
+// Mock setup:
+
+void MockSetReadPosition( Dali::AccessibilityAdaptor adaptor, Dali::Vector2& position )
+{
+  Dali::Internal::Adaptor::GetImplementation(adaptor).MockSetReadPosition( position );
+}
+
+void SetEnabled( Dali::AccessibilityAdaptor adaptor, bool enabled )
+{
+  Dali::Internal::Adaptor::GetImplementation(adaptor).SetEnabled(enabled);
+}
+
+void SendPanGesture( Dali::AccessibilityAdaptor adaptor, const Dali::AccessibilityGestureEvent& panEvent )
+{
+  Dali::Internal::Adaptor::GetImplementation(adaptor).SendPanGesture( panEvent );
+}
+
+} // namespace AccessibilityAdaptor
+} // namespace Test
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h
new file mode 100644 (file)
index 0000000..a463baf
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H
+#define DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
+
+namespace Test
+{
+namespace AccessibilityAdaptor
+{
+
+void MockSetReadPosition( Dali::AccessibilityAdaptor adaptor, Dali::Vector2& position );
+void SetEnabled( Dali::AccessibilityAdaptor adaptor, bool enabled);
+void SendPanGesture( Dali::AccessibilityAdaptor adaptor, const Dali::AccessibilityGestureEvent& panEvent );
+
+} // namespace AccessibilityAdaptor
+} // namespace Test
+
+#endif // DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor-impl.h
new file mode 100644 (file)
index 0000000..7d6e853
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_TOOLKIT_ADAPTOR_IMPL_H
+#define DALI_TOOLKIT_ADAPTOR_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/integration-api/adaptor-framework/render-surface-interface.h>
+
+namespace Dali
+{
+class EglInterface;
+class DisplayConnection;
+class ThreadSynchronizationInterface;
+class Window;
+
+namespace Integration
+{
+class Scene;
+}
+
+using WindowContainer = std::vector<Window>;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class GraphicsInterface;
+class SceneHolder;
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+namespace Integration
+{
+
+class GlAbstraction;
+
+} // namespace Integration
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class Adaptor
+{
+public:
+  static Dali::Adaptor& New();
+  static Dali::Adaptor& Get();
+  Adaptor();
+  ~Adaptor();
+
+  void Start( Dali::Window window );
+
+  bool AddIdle( CallbackBase* callback, bool hasReturnValue );
+  void RemoveIdle( CallbackBase* callback );
+  void RunIdles();
+
+  static Integration::Scene GetScene( Dali::Window window );
+
+  Dali::RenderSurfaceInterface& GetSurface();
+  Dali::WindowContainer GetWindows();
+  Dali::SceneHolderList GetSceneHolders();
+
+  Dali::Internal::Adaptor::SceneHolder* GetWindow( Dali::Actor& actor );
+  void AddWindow( Internal::Adaptor::SceneHolder* window );
+  void RemoveWindow( Internal::Adaptor::SceneHolder* window );
+
+  Dali::Adaptor::AdaptorSignalType& ResizedSignal();
+  Dali::Adaptor::AdaptorSignalType& LanguageChangedSignal();
+  Dali::Adaptor::WindowCreatedSignalType& WindowCreatedSignal();
+
+  static Adaptor& GetImpl( Dali::Adaptor& adaptor ) { return *adaptor.mImpl; }
+  static const Adaptor& GetImpl( const Dali::Adaptor& adaptor ) { return *adaptor.mImpl; }
+
+private:
+
+  Vector<CallbackBase*> mCallbacks;
+  std::vector<Internal::Adaptor::SceneHolder*> mWindows;
+  Dali::Adaptor::AdaptorSignalType mResizedSignal;
+  Dali::Adaptor::AdaptorSignalType mLanguageChangedSignal;
+  Dali::Adaptor::WindowCreatedSignalType mWindowCreatedSignal;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ADAPTOR_IMPL_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp
new file mode 100644 (file)
index 0000000..7c50cc7
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2020 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 <algorithm>
+
+#include <toolkit-window-impl.h>
+
+// Don't want to include the actual window.h which otherwise will be indirectly included by adaptor.h.
+#define DALI_WINDOW_H
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+#include <toolkit-scene-holder-impl.h>
+#include <toolkit-adaptor-impl.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/scene.h>
+#include <test-application.h>
+
+namespace Dali
+{
+
+namespace
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// LogFactoryStub
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class LogFactory : public LogFactoryInterface
+{
+public:
+  LogFactory() = default;
+  virtual ~LogFactory() = default;
+
+private:
+  void InstallLogFunction() const override
+  {
+    Dali::Integration::Log::InstallLogFunction( &TestApplication::LogMessage );
+  }
+};
+LogFactory* gLogFactory = NULL; // For some reason, destroying this when the Adaptor is destroyed causes a crash in some test cases when running all of them.
+} //unnamed namespace
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Dali::Internal::Adaptor::Adaptor Stub
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Dali::Adaptor* gAdaptor = nullptr;
+
+Dali::Adaptor& Adaptor::New()
+{
+  DALI_ASSERT_ALWAYS( ! gAdaptor );
+  gAdaptor = new Dali::Adaptor;
+  return *gAdaptor;
+}
+
+Dali::Adaptor& Adaptor::Get()
+{
+  DALI_ASSERT_ALWAYS( gAdaptor );
+  return *gAdaptor;
+}
+
+Adaptor::Adaptor()
+{
+}
+
+Adaptor::~Adaptor()
+{
+  gAdaptor = nullptr;
+}
+
+void Adaptor::Start( Dali::Window window )
+{
+  AddWindow( &GetImplementation( window ) );
+}
+
+Integration::Scene Adaptor::GetScene( Dali::Window window )
+{
+  return window.GetScene();
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue )
+{
+  mCallbacks.PushBack( callback );
+  return true;
+}
+
+void Adaptor::RemoveIdle( CallbackBase* callback )
+{
+  mCallbacks.Erase( std::find_if( mCallbacks.Begin(), mCallbacks.End(),
+                                  [ &callback ] ( CallbackBase* current ) { return callback == current; } ) );
+}
+
+void Adaptor::RunIdles()
+{
+  for( auto& callback : mCallbacks )
+  {
+    CallbackBase::Execute( *callback );
+  }
+
+  mCallbacks.Clear();
+}
+
+Dali::RenderSurfaceInterface& Adaptor::GetSurface()
+{
+  DALI_ASSERT_ALWAYS( ! mWindows.empty() );
+
+  return reinterpret_cast < Dali::RenderSurfaceInterface& >( mWindows.front()->GetRenderSurface() );
+}
+
+Dali::WindowContainer Adaptor::GetWindows()
+{
+  Dali::WindowContainer windows;
+
+  for ( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    // Downcast to Dali::Window
+    Dali::Window window( dynamic_cast<Dali::Internal::Adaptor::Window*>( *iter ) );
+    if ( window )
+    {
+      windows.push_back( window );
+    }
+  }
+
+  return windows;
+}
+
+Dali::SceneHolderList Adaptor::GetSceneHolders()
+{
+  Dali::SceneHolderList sceneHolderList;
+
+  for( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    sceneHolderList.push_back( Dali::Integration::SceneHolder( *iter ) );
+  }
+
+  return sceneHolderList;
+}
+
+Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow( Dali::Actor& actor )
+{
+  Dali::Integration::Scene scene = Dali::Integration::Scene::Get( actor );
+
+  for( auto window : mWindows )
+  {
+    if ( scene == window->GetScene() )
+    {
+      return window;
+    }
+  }
+
+  return nullptr;
+}
+
+void Adaptor::AddWindow( Internal::Adaptor::SceneHolder* window )
+{
+  if ( window )
+  {
+    mWindows.push_back( window );
+
+    Dali::Integration::SceneHolder newWindow( window );
+    mWindowCreatedSignal.Emit( newWindow );
+  }
+}
+
+void Adaptor::RemoveWindow( Internal::Adaptor::SceneHolder* window )
+{
+  auto iter = std::find( mWindows.begin(), mWindows.end(), window );
+  if( iter != mWindows.end() )
+  {
+    mWindows.erase( iter );
+  }
+}
+
+Dali::Adaptor::AdaptorSignalType& Adaptor::ResizedSignal()
+{
+  return mResizedSignal;
+}
+
+Dali::Adaptor::AdaptorSignalType& Adaptor::LanguageChangedSignal()
+{
+  return mLanguageChangedSignal;
+}
+
+Dali::Adaptor::WindowCreatedSignalType& Adaptor::WindowCreatedSignal()
+{
+  return mWindowCreatedSignal;
+}
+
+} // namespace Adaptor
+} // namespace Internal
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Dali::Adaptor Stub
+//
+///////////////////////////////////////////////////////////////////////////////
+
+Adaptor::Adaptor()
+: mImpl( new Internal::Adaptor::Adaptor )
+{
+}
+
+Adaptor::~Adaptor()
+{
+  Internal::Adaptor::gAdaptor = nullptr;
+  delete mImpl;
+}
+
+void Adaptor::Start()
+{
+}
+
+void Adaptor::Pause()
+{
+}
+
+void Adaptor::Resume()
+{
+}
+
+void Adaptor::Stop()
+{
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue )
+{
+  return mImpl->AddIdle( callback, hasReturnValue );
+}
+
+void Adaptor::RemoveIdle( CallbackBase* callback )
+{
+  mImpl->RemoveIdle( callback );
+}
+
+void Adaptor::ReplaceSurface( Window window, Dali::RenderSurfaceInterface& surface )
+{
+}
+
+void Adaptor::ReplaceSurface( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& surface )
+{
+}
+
+Adaptor::AdaptorSignalType& Adaptor::ResizedSignal()
+{
+  return mImpl->ResizedSignal();
+}
+
+Adaptor::AdaptorSignalType& Adaptor::LanguageChangedSignal()
+{
+  return mImpl->LanguageChangedSignal();
+}
+
+Adaptor::WindowCreatedSignalType& Adaptor::WindowCreatedSignal()
+{
+  return mImpl->WindowCreatedSignal();
+}
+
+Dali::RenderSurfaceInterface& Adaptor::GetSurface()
+{
+  return mImpl->GetSurface();
+}
+
+Dali::WindowContainer Adaptor::GetWindows() const
+{
+  return mImpl->GetWindows();
+}
+
+Dali::SceneHolderList Adaptor::GetSceneHolders() const
+{
+  return mImpl->GetSceneHolders();
+}
+
+Any Adaptor::GetNativeWindowHandle()
+{
+  Any window;
+  return window;
+}
+
+Any Adaptor::GetNativeWindowHandle( Actor actor )
+{
+  return GetNativeWindowHandle();
+}
+
+void Adaptor::ReleaseSurfaceLock()
+{
+}
+
+void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+}
+
+Adaptor& Adaptor::Get()
+{
+  return Internal::Adaptor::Adaptor::Get();
+}
+
+bool Adaptor::IsAvailable()
+{
+  return Internal::Adaptor::gAdaptor;
+}
+
+void Adaptor::NotifySceneCreated()
+{
+}
+
+void Adaptor::NotifyLanguageChanged()
+{
+}
+
+void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+}
+
+void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+}
+
+void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+{
+}
+
+void Adaptor::SceneCreated()
+{
+}
+
+const LogFactoryInterface& Adaptor::GetLogFactory()
+{
+  if( gLogFactory == NULL )
+  {
+    gLogFactory = new LogFactory;
+  }
+  return *gLogFactory;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp
new file mode 100644 (file)
index 0000000..271d6ec
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-application.h"
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/devel-api/adaptor-framework/orientation.h>
+
+namespace Dali
+{
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Stub for the Application
+ */
+class Application
+{
+public:
+
+public:
+
+  Application(ToolkitApplication& toolkitApplication);
+  ~Application();
+
+public:
+
+  static std::string GetResourcePath();
+
+  //Orientation& GetOrientation();
+
+public: // static methods
+
+public:  // Signals
+
+private:
+
+  // Undefined
+  Application(const Application&);
+  Application& operator=(Application&);
+
+  ToolkitApplication& mToolkitApplication;
+
+  //Dali::Orientation* mOrientation;
+};
+
+namespace
+{
+Application* gApplication = NULL;
+}
+
+Application::Application(ToolkitApplication& toolkitApplication)
+: mToolkitApplication(toolkitApplication)
+//  ,mOrientation( new Dali::Orientation() )
+{
+}
+
+Application::~Application()
+{
+  //delete mOrientation;
+}
+
+std::string Application::GetResourcePath()
+{
+  return "";
+}
+//Orientation& Application::GetOrientation()
+//{
+//  return *mOrientation;
+//}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ToolkitApplication::DECODED_IMAGES_SUPPORTED;
+
+ToolkitApplication::ToolkitApplication()
+: mApplicationStub(new Application(*this))
+{
+  gApplication = mApplicationStub;
+}
+
+ToolkitApplication::~ToolkitApplication()
+{
+  delete mApplicationStub;
+  gApplication = NULL;
+}
+
+Application& ToolkitApplication::GetApplication()
+{
+  DALI_ASSERT_ALWAYS(gApplication);
+  return *gApplication;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-application.h
new file mode 100644 (file)
index 0000000..d444557
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_APPLICATION_H
+#define DALI_TOOLKIT_TOOLKIT_APPLICATION_H
+
+/*
+ * Copyright (c) 2019 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
+{
+
+class Application;
+
+/**
+ * This creates a stubbed Application so that Application calls work.
+ * Furthermore, it provides an interface to see if certain methods were invoked.
+ */
+class ToolkitApplication
+{
+public: // Construction & Destruction
+
+  ToolkitApplication();
+  ~ToolkitApplication();
+
+public: // Getters
+
+  Application& GetApplication();
+
+public: // Signal Emissions
+
+public: // TEST FUNCTIONS
+
+  // Enumeration of Application methods
+  enum TestFuncEnum
+  {
+  };
+
+  void Reset()
+  {
+    mFunctionsCalled.Reset();
+  }
+
+  bool WasCalled(TestFuncEnum func)
+  {
+    switch(func)
+    {
+    }
+    return false;
+  }
+
+  void ResetCallStatistics(TestFuncEnum func)
+  {
+    switch(func)
+    {
+    }
+  }
+
+private:
+
+  struct TestFunctions
+  {
+    TestFunctions()
+    {
+    }
+
+    void Reset()
+    {
+    }
+  };
+
+  TestFunctions mFunctionsCalled;
+
+  // The Application Stub
+  Application* mApplicationStub;
+  friend class Application;
+
+public: // Test static member
+  static bool DECODED_IMAGES_SUPPORTED;
+};
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOLKIT_APPLICATION_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
new file mode 100644 (file)
index 0000000..cbfe93e
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-clipboard-event-notifier.h"
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class ClipboardEventNotifier : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::ClipboardEventNotifier::ClipboardEventSignalType ClipboardEventSignalType;
+
+  // Creation
+  static Dali::ClipboardEventNotifier New();
+  static Dali::ClipboardEventNotifier Get();
+
+  // Public API
+  const std::string& GetContent() const;
+  void SetContent( const std::string& content );
+  void ClearContent();
+  void EmitContentSelectedSignal();
+
+  // Signals
+  ClipboardEventSignalType& ContentSelectedSignal()
+  {
+    return mContentSelectedSignal;
+  }
+
+private:
+  // Construction & Destruction
+  ClipboardEventNotifier();
+  virtual ~ClipboardEventNotifier();
+
+  // Undefined
+  ClipboardEventNotifier( const ClipboardEventNotifier& );
+  ClipboardEventNotifier& operator=( ClipboardEventNotifier& );
+
+private:
+
+  std::string mContent;    ///< The current selected content.
+  ClipboardEventSignalType mContentSelectedSignal;
+
+  static Dali::ClipboardEventNotifier mToolkitClipboardEventNotifier;
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::ClipboardEventNotifier& GetImplementation(Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+  inline static const Internal::Adaptor::ClipboardEventNotifier& GetImplementation(const Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    const BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+};
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::mToolkitClipboardEventNotifier;
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::New()
+{
+  return Get();
+}
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  if ( !mToolkitClipboardEventNotifier )
+  {
+    mToolkitClipboardEventNotifier = Dali::ClipboardEventNotifier( new ClipboardEventNotifier );
+  }
+  return mToolkitClipboardEventNotifier;
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return mContent;
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  mContent = content;
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  mContent.clear();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  if ( !mContentSelectedSignal.Empty() )
+  {
+    Dali::ClipboardEventNotifier handle( this );
+    mContentSelectedSignal.Emit( handle );
+  }
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+: mContent()
+{
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+} // namespace Adaptor
+} // namespace Internal
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+{
+}
+
+ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::Get();
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).GetContent();
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).SetContent(content);
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ClearContent();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).EmitContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventSignalType& ClipboardEventNotifier::ContentSelectedSignal()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier )
+: BaseHandle( notifier )
+{
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.h
new file mode 100644 (file)
index 0000000..282a0c0
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DALI_TOOLKIT_CLIPBOARD_EVENT_NOTIFIER_H
+#define DALI_TOOLKIT_CLIPBOARD_EVENT_NOTIFIER_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// PUBLIC INCLUDES
+#define DALI_CLIPBOARD_EVENT_NOTIFIER_H
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace Adaptor
+{
+class ClipboardEventNotifier;
+}
+}
+
+class ClipboardEventNotifier : public BaseHandle
+{
+public:
+  typedef Signal< void ( ClipboardEventNotifier& ) > ClipboardEventSignalType;
+
+  ClipboardEventNotifier();
+  static ClipboardEventNotifier Get();
+  ~ClipboardEventNotifier();
+
+  const std::string& GetContent() const;
+  void SetContent( const std::string& content );
+  void ClearContent();
+
+  void EmitContentSelectedSignal();
+  ClipboardEventSignalType& ContentSelectedSignal();
+
+  ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier );
+};
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOLKIT_CLIPBOARD_EVENT_NOTIFIER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp
new file mode 100644 (file)
index 0000000..1d06f25
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * 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 "toolkit-clipboard.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Clip Board
+ */
+
+class Clipboard :  public Dali::BaseObject
+{
+public:
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::Clipboard Get();
+
+  /**
+   * Constructor
+   * @param[in] ecoreXwin, The window is created by application.
+   */
+  Clipboard(/*Ecore_X_Window ecoreXwin*/);
+  virtual ~Clipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::SetItem()
+   */
+  bool SetItem(const std::string &itemData);
+
+  /**
+   * @copydoc Dali::Clipboard::RequestItem()
+   */
+  void RequestItem();
+
+  /**
+   * @copydoc Dali::Clipboard::NumberOfClipboardItems()
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @copydoc Dali::Clipboard::ShowClipboard()
+   */
+  void ShowClipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::HideClipboard()
+   */
+  void HideClipboard();
+
+  /**
+  * @copydoc Dali::Clipboard::IsVisible()
+  */
+  bool IsVisible() const;
+
+private:
+  Clipboard( const Clipboard& );
+  Clipboard& operator=( Clipboard& );
+
+  static Dali::Clipboard mToolkitClipboard;
+  bool mVisible;
+  std::string mItem;
+  int mCount;
+}; // class clipboard
+
+
+Dali::Clipboard Dali::Internal::Adaptor::Clipboard::mToolkitClipboard;
+
+
+Clipboard::Clipboard()
+{
+  mVisible = false;
+  mCount = 0;
+}
+
+Clipboard::~Clipboard()
+{
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  if( ! mToolkitClipboard )
+  {
+    mToolkitClipboard = Dali::Clipboard( new Dali::Internal::Adaptor::Clipboard() );
+  }
+  return mToolkitClipboard;
+}
+
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  mItem = itemData;
+  mCount = 1;
+  return true;
+}
+
+void Clipboard::RequestItem()
+{
+  Dali::ClipboardEventNotifier clipboardEventNotifier(Dali::ClipboardEventNotifier::Get());
+  if ( clipboardEventNotifier )
+  {
+    clipboardEventNotifier.SetContent( mItem );
+    clipboardEventNotifier.EmitContentSelectedSignal();
+  }
+}
+
+unsigned int Clipboard::NumberOfItems()
+{
+  return mCount;
+}
+
+void Clipboard::ShowClipboard()
+{
+  mVisible = true;
+}
+
+void Clipboard::HideClipboard()
+{
+  mVisible = false;
+}
+
+bool Clipboard::IsVisible() const
+{
+  return mVisible;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard)
+{
+  // Bypass any passed in clipboard handle - it probably won't be initialized
+  Dali::Clipboard theClipboard = Dali::Clipboard::Get();
+  BaseObject& object = theClipboard.GetBaseObject();
+  return static_cast<Internal::Adaptor::Clipboard&>(object);
+}
+
+inline static const  Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard)
+{
+  // Bypass any passed in clipboard handle - it probably won't be initialized
+  Dali::Clipboard theClipboard = Dali::Clipboard::Get();
+  const BaseObject& object = theClipboard.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Clipboard&>(object);
+}
+
+
+Clipboard::Clipboard()
+{
+}
+Clipboard::~Clipboard()
+{
+}
+Clipboard::Clipboard(Internal::Adaptor::Clipboard *impl)
+  : BaseHandle(impl)
+{
+}
+
+Clipboard Clipboard::Get()
+{
+  return Internal::Adaptor::Clipboard::Get();
+}
+bool Clipboard::SetItem( const std::string &itemData)
+{
+  return GetImplementation(*this).SetItem( itemData );
+}
+
+void Clipboard::RequestItem()
+{
+  GetImplementation(*this).RequestItem();
+}
+
+unsigned int Clipboard::NumberOfItems()
+{
+  return GetImplementation(*this).NumberOfItems();
+}
+
+void Clipboard::ShowClipboard()
+{
+  GetImplementation(*this).ShowClipboard();
+}
+
+void Clipboard::HideClipboard()
+{
+  GetImplementation(*this).HideClipboard();
+}
+
+bool Clipboard::IsVisible() const
+{
+  return GetImplementation(*this).IsVisible();
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.h
new file mode 100644 (file)
index 0000000..ad532cd
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef  TOOLKIT_CLIPBOARD_H
+#define  TOOLKIT_CLIPBOARD_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#define DALI_CLIPBOARD_H
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali DALI_IMPORT_API
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+class Clipboard;
+}
+}
+
+/**
+ * The Clipboard can operate using various funtion.
+ * Clipboard can manage it's item and set show / hide status.
+ */
+class Clipboard : public BaseHandle
+{
+public:
+  /**
+   * Create an uninitialized Clipboard;
+   *  this can be initialized with one of the derived Clipboard' New() methods
+   */
+  Clipboard();
+
+  /**
+   * Non virtual destructor.
+   */
+  ~Clipboard();
+
+  /**
+   * This constructor is used by Adaptor::GetClipboard().
+   * @param[in] clipboard A pointer to the clipboard.
+   */
+  Clipboard( Internal::Adaptor::Clipboard* clipboard );
+
+  /**
+   * Retrieve a handle to the ClipboardEventNotifier instance
+   * @return A handle to the Clipboard
+   */
+  static Clipboard Get();
+
+  /**
+   * Send the given string to the clipboard
+   * @param[in] itemData string to send to clip board
+   * @return bool true if the internal clip board sending was successful.
+   */
+  bool SetItem( const std::string& itemData );
+
+  /**
+   * Request clipboard service to retrieve an item
+   */
+  void RequestItem();
+
+  /**
+   * Returns the number of item currently in the clipboard
+   * @return unsigned int number of clipboard items
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * Show the clipboard window
+   */
+  void ShowClipboard();
+
+  /**
+   * Hide the clipboard window
+   */
+  void HideClipboard();
+
+  /**
+  * @brief Retrieves the clipboard's visibility
+  * @return bool true if the clipboard is visible.
+  */
+  bool IsVisible() const;
+
+};
+} // namespace Dali
+
+#endif // TOOLKIT_CLIPBOARD_H
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-environment-variable.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.cpp
new file mode 100644 (file)
index 0000000..f02bfb4
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 "toolkit-environment-variable.h"
+
+// EXTERNAL INCLUDE
+#include <cstddef>
+
+namespace Dali
+{
+
+namespace EnvironmentVariable
+{
+
+namespace
+{
+const char * gReturnValue = NULL;
+}
+
+const char * GetEnvironmentVariable( const char * variable )
+{
+  return gReturnValue;
+}
+
+void SetTestingEnvironmentVariable( bool testing)
+{
+  if( testing )
+  {
+    gReturnValue = "1";
+  }
+  else
+  {
+    gReturnValue = NULL;
+  }
+}
+
+} // namespace EnvironmentVariable
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.h
new file mode 100644 (file)
index 0000000..b1ebae0
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef DALI_TOOLKIT_ENVIRONMENT_VARIABLE_H
+#define DALI_TOOLKIT_ENVIRONMENT_VARIABLE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+#define DALI_ENVIRONMENT_VARIABLE_H
+
+#include <cstddef>
+
+namespace Dali
+{
+
+namespace EnvironmentVariable
+{
+
+const char * GetEnvironmentVariable( const char * variable );
+
+void SetTestingEnvironmentVariable( bool );
+
+} // namespace EnvironmentVariable
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_ENVIRONMENT_VARIABLE_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
new file mode 100644 (file)
index 0000000..02f3d8f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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 "toolkit-event-thread-callback.h"
+
+// EXTERNAL INCLUDES
+#include <cstddef>
+#include <semaphore.h>
+#include <math.h>
+#include <ctime>
+#include <climits>
+#include <cstdio>
+#include <unistd.h>
+#include <vector>
+#include <algorithm>
+
+namespace
+{
+// Note, this is not thread safe - however, should not be using
+// triggers from multiple threads - they should all be created on
+// event thread.
+std::vector<Dali::EventThreadCallback*> gEventThreadCallbacks;
+}
+
+
+namespace Dali
+{
+
+struct EventThreadCallback::Impl
+{
+  CallbackBase* callback;
+  sem_t mySemaphore;
+};
+
+EventThreadCallback::EventThreadCallback( CallbackBase* callback )
+: mImpl( new Impl() )
+{
+  mImpl->callback = callback;
+  sem_init( &(mImpl->mySemaphore), 0, 0 );
+
+  gEventThreadCallbacks.push_back(this);
+}
+
+EventThreadCallback::~EventThreadCallback()
+{
+  std::vector<EventThreadCallback*>::iterator iter =
+    std::find(gEventThreadCallbacks.begin(), gEventThreadCallbacks.end(), this);
+  if( iter != gEventThreadCallbacks.end() )
+  {
+    gEventThreadCallbacks.erase(iter);
+  }
+  delete mImpl;
+}
+
+void EventThreadCallback::Trigger()
+{
+  sem_post( &(mImpl->mySemaphore) );
+}
+
+// returns true if timed out rather than triggered
+bool EventThreadCallback::WaitingForTrigger()
+{
+  struct timespec now;
+  clock_gettime( CLOCK_REALTIME, &now );
+  if( now.tv_nsec < 999900000 ) // 999, 900, 000
+    now.tv_nsec += 1000;
+  else
+  {
+    now.tv_sec += 1;
+    now.tv_nsec = 0;
+  }
+
+  int error = sem_timedwait( &(mImpl->mySemaphore), &now );
+  return error != 0; // true if timeout
+}
+
+CallbackBase* EventThreadCallback::GetCallback()
+{
+  return mImpl->callback;
+}
+
+}
+
+
+namespace Test
+{
+
+bool WaitForEventThreadTrigger( int triggerCount, int timeoutInSeconds )
+{
+  struct timespec startTime;
+  struct timespec now;
+  clock_gettime( CLOCK_REALTIME, &startTime );
+  now.tv_sec = startTime.tv_sec;
+  now.tv_nsec = startTime.tv_nsec;
+
+  // Round robin poll of each semaphore:
+  while ( triggerCount > 0 )
+  {
+    if( gEventThreadCallbacks.size() > 0 )
+    {
+      for( std::vector<Dali::EventThreadCallback*>::iterator iter = gEventThreadCallbacks.begin();
+           iter != gEventThreadCallbacks.end(); ++iter )
+      {
+        Dali::EventThreadCallback* eventTrigger = (*iter);
+        Dali::CallbackBase* callback = eventTrigger->GetCallback();
+        bool timedout = eventTrigger->WaitingForTrigger();
+        if( ! timedout )
+        {
+          // Semaphore was unlocked - execute the trigger
+          Dali::CallbackBase::Execute( *callback );
+          triggerCount--;
+        }
+        if( triggerCount <= 0 )
+        {
+          break;
+        }
+      }
+    }
+    clock_gettime( CLOCK_REALTIME, &now );
+    if( now.tv_sec - startTime.tv_sec > timeoutInSeconds )
+    {
+      // Ensure we break out of the loop if elapsed time has passed
+      break;
+    }
+  }
+
+  clock_gettime( CLOCK_REALTIME, &now );
+  if( now.tv_sec > startTime.tv_sec + 1 )
+  {
+    fprintf(stderr, "WaitForEventThreadTrigger took %ld seconds\n", now.tv_sec - startTime.tv_sec );
+  }
+  return triggerCount == 0;
+}
+
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.h
new file mode 100644 (file)
index 0000000..9693e6e
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_TOOLKIT_EVENT_THREAD_CALLBACK_H
+#define DALI_TOOLKIT_EVENT_THREAD_CALLBACK_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+#define DALI_EVENT_THREAD_CALLBACK_H
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+class DALI_TOOLKIT_API EventThreadCallback
+{
+public:
+
+  EventThreadCallback( CallbackBase* callback );
+
+  ~EventThreadCallback();
+
+  void Trigger();
+
+  bool WaitingForTrigger();
+
+  CallbackBase* GetCallback();
+
+private:
+
+  // undefined copy constructor.
+  EventThreadCallback( const EventThreadCallback& );
+
+  // undefined assignment operator
+  EventThreadCallback& operator=( const EventThreadCallback& );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+}
+
+namespace Test
+{
+
+/**
+ * Wait for the tested code to create an event trigger, then
+ * wait for triggerCount Trigger calls to occur, and execute the trigger
+ * callback afterwards.
+ *
+ * Will wait for a maximum of 30s before failing the test and returning.
+ */
+bool WaitForEventThreadTrigger( int triggerCount, int timeoutInSeconds=30 );
+
+}
+
+
+#endif // DALI_TOOLKIT_EVENT_THREAD_CALLBACK_H
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..946880e
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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/common/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 mLoadFileReturn;
+  }
+
+  void SetLoadFileReturnValue(bool value)
+  {
+    mLoadFileReturn = value;
+  }
+
+private:
+  FeedbackPlayer()
+  : mLoadFileReturn{true}
+  {
+  }
+
+  virtual ~FeedbackPlayer()
+  {
+  }
+
+  FeedbackPlayer(const FeedbackPlayer&)
+  {
+  }
+
+  FeedbackPlayer& operator=(FeedbackPlayer&)
+  {
+    return *this;
+  }
+
+  bool mLoadFileReturn;
+};
+
+} // 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 )
+{
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+void SetLoadFileReturnValue(Dali::FeedbackPlayer feedbackPlayer, bool returnValue)
+{
+  GetImplementation(feedbackPlayer).SetLoadFileReturnValue( returnValue );
+}
+
+} // Adaptor
+} // Internal
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.cpp
new file mode 100755 (executable)
index 0000000..0f74724
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2019 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 "toolkit-input-method-context.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class RenderSurface;
+
+
+class InputMethodContext : public Dali::BaseObject
+{
+public:
+  typedef Dali::InputMethodContext::ActivatedSignalType ActivatedSignalType;
+  typedef Dali::InputMethodContext::KeyboardEventSignalType KeyboardEventSignalType;
+  typedef Dali::InputMethodContext::StatusSignalType StatusSignalType;
+  typedef Dali::InputMethodContext::VoidSignalType VoidSignalType;
+
+public:
+  static Dali::InputMethodContext New();
+
+  InputMethodContext( /* Ecore_X_Window ecoreXwin */ );
+  void Finalize();
+  void ConnectCallbacks();
+  void DisconnectCallbacks();
+  void Activate();
+  void Deactivate();
+  void Reset();
+
+  bool RestoreAfterFocusLost() const;
+  void SetRestoreAfterFocusLost( bool toggle );
+  void NotifyCursorPosition();
+  void SetCursorPosition( unsigned int cursorPosition );
+  unsigned int GetCursorPosition() const;
+  void SetSurroundingText( const std::string& text );
+  const std::string& GetSurroundingText() const;
+  void ApplyOptions( const InputMethodOptions& options );
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent );
+  void SetPreeditStyle( Dali::InputMethodContext::PreeditStyle type );
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const;
+
+public:  // Signals
+  ActivatedSignalType& ActivatedSignal() { return mActivatedSignal; }
+  KeyboardEventSignalType& EventReceivedSignal() { return mEventSignal; }
+  StatusSignalType& StatusChangedSignal() { return mKeyboardStatusSignal; }
+  VoidSignalType& ResizedSignal() { return mKeyboardResizeSignal; }
+  VoidSignalType& LanguageChangedSignal() { return mKeyboardLanguageChangedSignal; }
+
+protected:
+  virtual ~InputMethodContext();
+
+private:
+  void CreateContext( /*Ecore_X_Window ecoreXwin*/ );
+  void DeleteContext();
+
+private:
+  // Undefined
+  InputMethodContext( const InputMethodContext& );
+  InputMethodContext& operator=( InputMethodContext& );
+
+private:
+  int mIMFCursorPosition;
+  std::string mSurroundingText;
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
+  InputMethodOptions        mOptions;
+  Dali::InputMethodContext::PreEditAttributeDataContainer mPreeditAttrs; ///< Stores preedit attribute data
+
+  ActivatedSignalType      mActivatedSignal;
+  KeyboardEventSignalType  mEventSignal;
+  StatusSignalType         mKeyboardStatusSignal;
+  VoidSignalType           mKeyboardResizeSignal;
+  VoidSignalType           mKeyboardLanguageChangedSignal;
+
+  static Dali::InputMethodContext mToolkitInputMethodContext;
+
+public:
+
+inline static Internal::Adaptor::InputMethodContext& GetImplementation(Dali::InputMethodContext& inputMethodContext)
+{
+  BaseObject& handle = inputMethodContext.GetBaseObject();
+  return static_cast<Internal::Adaptor::InputMethodContext&>(handle);
+}
+
+inline static const  Internal::Adaptor::InputMethodContext& GetImplementation(const Dali::InputMethodContext& inputMethodContext)
+{
+  const BaseObject& handle = inputMethodContext.GetBaseObject();
+  return static_cast<const Internal::Adaptor::InputMethodContext&>(handle);
+}
+
+};
+
+Dali::InputMethodContext Dali::Internal::Adaptor::InputMethodContext::mToolkitInputMethodContext;
+
+Dali::InputMethodContext InputMethodContext::New()
+{
+  if( ! mToolkitInputMethodContext )
+  {
+    mToolkitInputMethodContext = Dali::InputMethodContext( new Dali::Internal::Adaptor::InputMethodContext() );
+  }
+  return mToolkitInputMethodContext;
+}
+
+InputMethodContext::InputMethodContext( /*Ecore_X_Window ecoreXwin*/ )
+: mIMFCursorPosition( 0 ),
+  mSurroundingText(),
+  mRestoreAfterFocusLost( false ),
+  mIdleCallbackConnected( false )
+{
+  CreateContext( /*ecoreXwin*/ );
+  ConnectCallbacks();
+}
+
+InputMethodContext::~InputMethodContext()
+{
+  DisconnectCallbacks();
+  DeleteContext();
+}
+
+void InputMethodContext::Finalize()
+{
+}
+
+void InputMethodContext::CreateContext( /*Ecore_X_Window ecoreXwin*/ )
+{
+}
+
+void InputMethodContext::DeleteContext()
+{
+}
+
+// Callbacks for predicitive text support.
+void InputMethodContext::ConnectCallbacks()
+{
+}
+
+void InputMethodContext::DisconnectCallbacks()
+{
+}
+
+void InputMethodContext::Activate()
+{
+}
+
+void InputMethodContext::Deactivate()
+{
+}
+
+void InputMethodContext::Reset()
+{
+}
+
+bool InputMethodContext::RestoreAfterFocusLost() const
+{
+  return mRestoreAfterFocusLost;
+}
+
+void InputMethodContext::SetRestoreAfterFocusLost( bool toggle )
+{
+  mRestoreAfterFocusLost = toggle;
+}
+
+void InputMethodContext::NotifyCursorPosition()
+{
+}
+
+void InputMethodContext::SetCursorPosition( unsigned int cursorPosition )
+{
+  mIMFCursorPosition = static_cast< int >( cursorPosition );
+}
+
+unsigned int InputMethodContext::GetCursorPosition() const
+{
+  return static_cast<unsigned int>( mIMFCursorPosition );
+}
+
+void InputMethodContext::SetSurroundingText( const std::string& text )
+{
+  mSurroundingText = text;
+}
+
+const std::string& InputMethodContext::GetSurroundingText() const
+{
+  return mSurroundingText;
+}
+
+void InputMethodContext::ApplyOptions( const InputMethodOptions& options )
+{
+}
+
+bool InputMethodContext::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  return false;
+}
+
+void InputMethodContext::SetPreeditStyle( Dali::InputMethodContext::PreeditStyle type )
+{
+  Dali::InputMethodContext::PreeditAttributeData data;
+  data.preeditType = type;
+  mPreeditAttrs.PushBack( data );
+}
+
+void InputMethodContext::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+  attrs = mPreeditAttrs;
+}
+} // Adaptor
+
+} // Internal
+
+
+/********************************************************************************/
+/*********************************  PUBLIC CLASS  *******************************/
+/********************************************************************************/
+
+InputMethodContext::InputMethodContext()
+{
+}
+
+InputMethodContext::~InputMethodContext()
+{
+}
+
+InputMethodContext InputMethodContext::New()
+{
+  return InputMethodContext::New( Actor() );
+}
+
+InputMethodContext InputMethodContext::New( Actor actor )
+{
+  return Internal::Adaptor::InputMethodContext::New();
+}
+
+void InputMethodContext::Finalize()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Finalize();
+}
+
+void InputMethodContext::Activate()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Activate();
+}
+
+void InputMethodContext::Deactivate()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Deactivate();
+}
+
+bool InputMethodContext::RestoreAfterFocusLost() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).RestoreAfterFocusLost();
+}
+
+void InputMethodContext::SetRestoreAfterFocusLost( bool toggle )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetRestoreAfterFocusLost( toggle );
+}
+
+void InputMethodContext::Reset()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Reset();
+}
+
+void InputMethodContext::NotifyCursorPosition()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).NotifyCursorPosition();
+}
+
+void InputMethodContext::SetCursorPosition( unsigned int SetCursorPosition )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
+}
+
+unsigned int InputMethodContext::GetCursorPosition() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetCursorPosition();
+}
+
+void InputMethodContext::SetSurroundingText( const std::string& text )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetSurroundingText( text );
+}
+
+const std::string& InputMethodContext::GetSurroundingText() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetSurroundingText();
+}
+
+void InputMethodContext::NotifyTextInputMultiLine( bool multiLine )
+{
+}
+
+void InputMethodContext::ApplyOptions( const InputMethodOptions& options )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).ApplyOptions( options );
+}
+
+bool InputMethodContext::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).FilterEventKey( keyEvent );
+}
+
+void InputMethodContext::SetPreeditStyle( Dali::InputMethodContext::PreeditStyle type )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetPreeditStyle( type );
+}
+
+void InputMethodContext::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetPreeditStyle( attrs );
+}
+
+// Signals
+InputMethodContext::ActivatedSignalType& InputMethodContext::ActivatedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).ActivatedSignal();
+}
+
+InputMethodContext::KeyboardEventSignalType& InputMethodContext::EventReceivedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).EventReceivedSignal();
+}
+
+InputMethodContext::StatusSignalType& InputMethodContext::StatusChangedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).StatusChangedSignal();
+}
+
+InputMethodContext::VoidSignalType& InputMethodContext::ResizedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).ResizedSignal();
+}
+
+InputMethodContext::VoidSignalType& InputMethodContext::LanguageChangedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).LanguageChangedSignal();
+}
+
+InputMethodContext::InputMethodContext(Internal::Adaptor::InputMethodContext *impl)
+  : BaseHandle(impl)
+{
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.h
new file mode 100755 (executable)
index 0000000..d53e02a
--- /dev/null
@@ -0,0 +1,404 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_INPUT_METHOD_CONTEXT_H
+#define DALI_TOOLKIT_TOOLKIT_INPUT_METHOD_CONTEXT_H
+
+/*
+ * Copyright (c) 2019 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_INPUT_METHOD_CONTEXT_H
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/devel-api/adaptor-framework/input-method-options.h>
+#include <dali/public-api/events/key-event.h>
+
+namespace Dali DALI_IMPORT_API
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class InputMethodContext;
+}
+}
+
+/**
+ * @brief The InputMethodContext class
+ *
+ * Specifically manages the ecore input method framework which enables the virtual or hardware keyboards.
+ */
+class InputMethodContext : public BaseHandle
+{
+public:
+
+  /**
+  * @brief The direction of text.
+  */
+  enum TextDirection
+  {
+    LeftToRight,
+    RightToLeft,
+  };
+
+  /**
+   * @brief Events that are generated by the InputMethodContext.
+   */
+  enum EventType
+  {
+    VOID,                ///< No event
+    PRE_EDIT,             ///< Pre-Edit changed
+    COMMIT,              ///< Commit recieved
+    DELETE_SURROUNDING,   ///< Event to delete a range of characters from the string
+    GET_SURROUNDING,      ///< Event to query string and cursor position
+    PRIVATE_COMMAND       ///< Private command sent from the input panel
+  };
+
+  /**
+   * @brief Enumeration for state of the input panel.
+   */
+  enum State
+  {
+    DEFAULT = 0,   ///< Unknown state
+    SHOW,          ///< Input panel is shown
+    HIDE,          ///< Input panel is hidden
+    WILL_SHOW      ///< Input panel in process of being shown
+  };
+
+  /**
+   * @brief Enumeration for the type of Keyboard.
+   */
+  enum KeyboardType
+  {
+    SOFTWARE_KEYBOARD,  ///< Software keyboard (Virtual keyboard) is default
+    HARDWARE_KEYBOARD   ///< Hardware keyboard
+  };
+
+  /**
+   * @brief Enumeration for the language mode of the input panel.
+   */
+  enum class InputPanelLanguage
+  {
+    AUTOMATIC,    ///< IME Language automatically set depending on the system display
+    ALPHABET      ///< Latin alphabet at all times
+  };
+
+  /**
+   * @brief Enumeration for the preedit style types.
+   */
+  enum class PreeditStyle
+  {
+    NONE,                    ///< None style
+    UNDERLINE,               ///< Underline substring style
+    REVERSE,                 ///< Reverse substring style
+    HIGHLIGHT,               ///< Highlight substring style
+    CUSTOM_PLATFORM_STYLE_1, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_2, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_3, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_4  ///< Custom style for platform
+  };
+
+  /**
+   * @brief This structure is for the preedit style types and indices.
+   */
+  struct PreeditAttributeData
+  {
+    PreeditAttributeData()
+    : preeditType( PreeditStyle::NONE ),
+      startIndex( 0 ),
+      endIndex( 0 )
+    {
+    }
+
+    PreeditStyle preeditType;  /// The preedit style type
+    unsigned int startIndex;   /// The start index of preedit
+    unsigned int endIndex;     /// The end index of preedit
+  };
+
+  /**
+   * @brief This structure is used to pass on data from the InputMethodContext regarding predictive text.
+   */
+  struct EventData
+  {
+    /**
+     * @brief Default Constructor.
+     */
+    EventData()
+    : predictiveString(),
+      eventName( VOID ),
+      cursorOffset( 0 ),
+      numberOfChars ( 0 )
+    {
+    };
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] aEventName The name of the event from the input method context.
+     * @param[in] aPredictiveString The pre-edit or commit string.
+     * @param[in] aCursorOffset Start position from the current cursor position to start deleting characters.
+     * @param[in] aNumberOfChars The number of characters to delete from the cursorOffset.
+     */
+    EventData( EventType aEventName, const std::string& aPredictiveString, int aCursorOffset, int aNumberOfChars )
+    : predictiveString( aPredictiveString ),
+      eventName( aEventName ),
+      cursorOffset( aCursorOffset ),
+      numberOfChars( aNumberOfChars )
+    {
+    }
+
+    // Data
+    std::string predictiveString; ///< The pre-edit or commit string.
+    EventType eventName;           ///< The name of the event from the input method context.
+    int cursorOffset;             ///< Start position from the current cursor position to start deleting characters.
+    int numberOfChars;            ///< number of characters to delete from the cursorOffset.
+  };
+
+  /**
+   * @brief Data required by input method context from the callback
+   */
+  struct CallbackData
+  {
+    /**
+     * @brief Constructor
+     */
+    CallbackData()
+    : currentText(),
+      cursorPosition( 0 ),
+      update( false ),
+      preeditResetRequired( false )
+    {
+    }
+
+    /**
+     * @brief Constructor
+     * @param[in] aUpdate True if cursor position needs to be updated
+     * @param[in] aCursorPosition new position of cursor
+     * @param[in] aCurrentText current text string
+     * @param[in] aPreeditResetRequired flag if preedit reset is required.
+     */
+    CallbackData( bool aUpdate, int aCursorPosition, const std::string& aCurrentText, bool aPreeditResetRequired )
+    : currentText( aCurrentText ),
+      cursorPosition( aCursorPosition ),
+      update( aUpdate ),
+      preeditResetRequired( aPreeditResetRequired )
+    {
+    }
+
+    std::string currentText;      ///< current text string
+    int cursorPosition;           ///< new position of cursor
+    bool update               :1; ///< if cursor position needs to be updated
+    bool preeditResetRequired :1; ///< flag if preedit reset is required.
+  };
+
+  typedef Signal< void (InputMethodContext&) > ActivatedSignalType; ///< Keyboard actived signal
+  typedef Signal< CallbackData ( InputMethodContext&, const EventData& ) > KeyboardEventSignalType; ///< keyboard events
+  typedef Signal< void () > VoidSignalType;
+  typedef Signal< void (bool) > StatusSignalType;
+
+  using PreEditAttributeDataContainer = Vector< Dali::InputMethodContext::PreeditAttributeData >;
+
+public:
+
+  /**
+   * @brief Create a handle to the instance of InputMethodContext.
+   * @return A handle to the InputMethodContext.
+   */
+  static InputMethodContext New();
+
+  /**
+   * @brief Create a handle to the instance of InputMethodContext.
+   *
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   * @return A handle to the InputMethodContext.
+   */
+  static InputMethodContext New( Actor actor );
+
+  /**
+   * @brief Finalize the InputMethodContext.
+   *
+   * It means that the context will be deleted.
+   */
+  void Finalize();
+
+  /**
+   * @brief Activate the input method context.
+   *
+   * It means that the text editing is started at somewhere.
+   * If the H/W keyboard isn't connected then it will show the virtual keyboard.
+   */
+  void Activate();
+
+  /**
+   * @brief Deactivate the input method context.
+   *
+   * It means that the text editing is finished at somewhere.
+   */
+  void Deactivate();
+
+  /**
+   * @brief Get the restoration status, which controls if the keyboard is restored after the focus lost then regained.
+   *
+   * If true then keyboard will be restored (activated) after focus is regained.
+   * @return restoration status.
+   */
+  bool RestoreAfterFocusLost() const;
+
+  /**
+   * @brief Set status whether the input method context has to restore the keyboard after losing focus.
+   *
+   * @param[in] toggle True means that keyboard should be restored after focus lost and regained.
+   */
+  void SetRestoreAfterFocusLost( bool toggle );
+
+  /**
+   * @brief Send message reset the pred-edit state / input method context module.
+   *
+   * Used to interupt pre-edit state maybe due to a touch input.
+   */
+  void Reset();
+
+  /**
+   * @brief Notifies ImfContext that the cursor position has changed, required for features like auto-capitalisation.
+   */
+  void NotifyCursorPosition();
+
+  /**
+   * @brief Sets cursor position stored in VirtualKeyboard, this is required by the ImfContext.
+   *
+   * @param[in] cursorPosition position of cursor
+   */
+  void SetCursorPosition( unsigned int cursorPosition );
+
+  /**
+   * @brief Gets cursor position stored in VirtualKeyboard, this is required by the ImfContext.
+   *
+   * @return current position of cursor
+   */
+  unsigned int GetCursorPosition() const;
+
+  /**
+   * @brief Method to store the string required by the input method context, this is used to provide predictive word suggestions.
+   *
+   * @param[in] text The text string surrounding the current cursor point.
+   */
+  void SetSurroundingText( const std::string& text );
+
+  /**
+   * @brief Gets current text string set within the input method context, this is used to offer predictive suggestions.
+   *
+   * @return current position of cursor
+   */
+  const std::string& GetSurroundingText() const;
+
+  /**
+  * @brief Notifies ImfContext that text input is set to multi line or not
+  */
+  void NotifyTextInputMultiLine( bool multiLine );
+
+  /**
+   * @brief Set one or more of the Input Method options
+   * @param[in] options The options to be applied
+   */
+  void ApplyOptions( const InputMethodOptions& options );
+
+  /**
+   * @brief Process event key down or up, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent );
+
+  /**
+   * @brief Sets the preedit type.
+   *
+   * @param[in] type The preedit style type
+   */
+  void SetPreeditStyle( PreeditStyle type );
+
+  /**
+   * @brief Gets the preedit attributes data.
+   *
+   * @param[out] attrs The preedit attributes data.
+   */
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const;
+
+public:
+
+  // Signals
+
+  /**
+   * @brief This is emitted when the virtual keyboard is connected to or the hardware keyboard is activated.
+   *
+   * @return The input method context Activated signal.
+   */
+  ActivatedSignalType& ActivatedSignal();
+
+  /**
+   * @brief This is emitted when the input method context receives an event.
+   *
+   * @return The Event signal containing the event data.
+   */
+  KeyboardEventSignalType& EventReceivedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard is shown or hidden.
+   *
+   * @return The signal connect to status changed event.
+   */
+  StatusSignalType& StatusChangedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard is resized.
+   *
+   * @return The signal to connect to resized event.
+   */
+  VoidSignalType& ResizedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard's language is changed.
+   *
+   * @return The signal to connect to language changed event.
+   */
+  VoidSignalType& LanguageChangedSignal();
+
+  // Construction & Destruction
+
+  /**
+   * @brief Constructor.
+   */
+  InputMethodContext();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~InputMethodContext();
+
+  /**
+   * @brief This constructor is used by InputMethodContext::Get().
+   *
+   * @param[in] inputMethodContext A pointer to the input method context.
+   */
+  explicit InputMethodContext( Internal::Adaptor::InputMethodContext* inputMethodContext );
+};
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOLKIT_INPUT_METHOD_CONTEXT_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-options.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-options.cpp
new file mode 100644 (file)
index 0000000..b306e7e
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+/**
+ * This is a copy of dali-adaptor/devel-api/adaptor-framework/input-method-options.cpp.
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/input-method-options.h>
+
+using namespace Dali::InputMethod;
+using namespace Dali::InputMethod::Category;
+
+namespace Dali
+{
+
+#define TOKEN_STRING(x) #x
+
+struct InputMethodOptions::Impl
+{
+  Impl()
+  {
+    mPanelLayout = PanelLayout::NORMAL;
+    mAutoCapital = AutoCapital::SENTENCE;
+    mButtonAction = ButtonAction::DEFAULT;
+    mVariation = NormalLayout::NORMAL;
+  }
+
+  PanelLayout::Type mPanelLayout;
+  AutoCapital::Type mAutoCapital;
+  ButtonAction::Type mButtonAction;
+  int mVariation:4;
+};
+
+InputMethodOptions::InputMethodOptions()
+{
+  mImpl.reset(new Impl());
+}
+
+InputMethodOptions::~InputMethodOptions()
+{
+  // destructor cannot be inlined and must be in a unit
+  // for unique_ptr to work with forward declaration
+}
+
+bool InputMethodOptions::IsPassword() const
+{
+  return (mImpl->mPanelLayout == Dali::InputMethod::PanelLayout::PASSWORD);
+}
+
+void InputMethodOptions::ApplyProperty( const Property::Map& settings )
+{
+  for ( unsigned int i = 0, count = settings.Count(); i < count; ++i )
+  {
+    Property::Key key = settings.GetKeyAt( i );
+    if( key.type == Property::Key::INDEX )
+    {
+      continue;
+    }
+
+    Property::Value item = settings.GetValue(i);
+
+    if( key == TOKEN_STRING( PANEL_LAYOUT ) )
+    {
+      if( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mPanelLayout = static_cast<InputMethod::PanelLayout::Type>(value);
+      }
+    }
+    else if ( key == TOKEN_STRING( BUTTON_ACTION ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mButtonAction = static_cast<InputMethod::ButtonAction::Type>(value);
+      }
+    }
+    else if ( key == TOKEN_STRING( AUTO_CAPITALIZE ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mAutoCapital = static_cast<InputMethod::AutoCapital::Type>(value);
+      }
+    }
+    else if( key == TOKEN_STRING( VARIATION ) )
+    {
+      if( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mVariation = value;
+      }
+    }
+    else
+    {
+    }
+  }
+}
+
+void InputMethodOptions::RetrieveProperty( Property::Map& settings )
+{
+  settings[TOKEN_STRING( PANEL_LAYOUT )] = mImpl->mPanelLayout;
+  settings[TOKEN_STRING( BUTTON_ACTION )] = mImpl->mButtonAction;
+  settings[TOKEN_STRING( AUTO_CAPITALIZE )] = mImpl->mAutoCapital;
+  settings[TOKEN_STRING( VARIATION )] = mImpl->mVariation;
+}
+
+bool InputMethodOptions::CompareAndSet( InputMethod::Category::Type type, const InputMethodOptions& options, int& index)
+{
+  return true;
+  bool updated = false;
+
+  switch (type)
+  {
+    case PANEL_LAYOUT:
+    {
+      if ( options.mImpl->mPanelLayout != mImpl->mPanelLayout )
+      {
+        mImpl->mPanelLayout = options.mImpl->mPanelLayout;
+        index = static_cast<int>(mImpl->mPanelLayout);
+        updated = true;
+      }
+      break;
+    }
+    case BUTTON_ACTION:
+    {
+      if ( options.mImpl->mButtonAction != mImpl->mButtonAction )
+      {
+        mImpl->mButtonAction = options.mImpl->mButtonAction;
+        index = static_cast<int>(mImpl->mButtonAction);
+        updated = true;
+      }
+      break;
+    }
+    case AUTO_CAPITALIZE:
+    {
+      if ( options.mImpl->mAutoCapital != mImpl->mAutoCapital )
+      {
+        mImpl->mAutoCapital = options.mImpl->mAutoCapital;
+        index = static_cast<int>(mImpl->mAutoCapital);
+        updated = true;
+      }
+      break;
+    }
+    case VARIATION:
+    {
+      if ( options.mImpl->mVariation != mImpl->mVariation )
+      {
+        mImpl->mVariation = options.mImpl->mVariation;
+        index = static_cast<int>(mImpl->mVariation);
+        updated = true;
+      }
+      break;
+    }
+  }
+  return updated;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.cpp
new file mode 100644 (file)
index 0000000..1e29a1c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-lifecycle-controller.h"
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+/********************************************************************************
+ * Stub for Dali::Internal::Adaptor::LifecycleController
+ ********************************************************************************/
+namespace Internal
+{
+namespace Adaptor
+{
+class LifecycleController : public BaseObject
+{
+public: // Creation & Destruction
+
+  LifecycleController();
+  ~LifecycleController();
+  static Dali::LifecycleController Get();
+
+
+public: // Signals
+  Dali::LifecycleController::LifecycleSignalType& InitSignal();
+
+private:
+  Dali::LifecycleController::LifecycleSignalType mInitSignal;
+  static Dali::LifecycleController mLifecycleController;
+};
+
+Dali::LifecycleController LifecycleController::mLifecycleController;
+
+LifecycleController::LifecycleController()
+{
+}
+
+LifecycleController::~LifecycleController()
+{
+}
+
+Dali::LifecycleController LifecycleController::Get()
+{
+  if( ! mLifecycleController )
+  {
+    mLifecycleController = Dali::LifecycleController(new Internal::Adaptor::LifecycleController());
+  }
+  return mLifecycleController;
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  return mInitSignal;
+}
+
+} // namespace Adaptor
+} // namespace Internal
+
+
+/********************************************************************************
+ * Stub for Dali::LifecycleController
+ ********************************************************************************/
+
+LifecycleController::LifecycleController(){}
+LifecycleController::~LifecycleController(){}
+
+LifecycleController LifecycleController::Get()
+{
+  // Get the physical keyboard handle
+  LifecycleController handle = Internal::Adaptor::LifecycleController::Get();
+  return handle;
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  BaseObject& object = GetBaseObject();
+  Internal::Adaptor::LifecycleController& controller = static_cast< Internal::Adaptor::LifecycleController& >( object );
+  return controller.InitSignal();
+}
+
+LifecycleController::LifecycleController( Internal::Adaptor::LifecycleController *impl )
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-lifecycle-controller.h
new file mode 100644 (file)
index 0000000..3069b15
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef TOOLKIT_LIFECYCLE_CONTROLLER_H
+#define TOOLKIT_LIFECYCLE_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class LifecycleController;
+}
+}
+
+class LifecycleController : public BaseHandle
+{
+public:
+  typedef Signal< void (void) > LifecycleSignalType;
+  LifecycleController();
+  ~LifecycleController();
+  static LifecycleController Get();
+  LifecycleSignalType& InitSignal();
+  LifecycleController( Internal::Adaptor::LifecycleController* impl );
+};
+
+
+} // namespace Dali
+
+#endif // TOOLKIT_LIFECYCLE_CONTROLLER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-native-image-source.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-native-image-source.cpp
new file mode 100755 (executable)
index 0000000..2277014
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/native-image-source.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+namespace Dali
+{
+
+NativeImageSourcePtr NativeImageSource::New( unsigned int width, unsigned int height, ColorDepth depth )
+{
+  Any empty;
+  NativeImageSourcePtr image = new NativeImageSource( width, height, depth, empty );
+  return image;
+}
+
+Any NativeImageSource::GetNativeImageSource()
+{
+  Any source;
+  return source;
+}
+
+NativeImageSourcePtr NativeImageSource::New( Any nativeImageSource )
+{
+  NativeImageSourcePtr image = new NativeImageSource(0, 0, COLOR_DEPTH_DEFAULT, nativeImageSource);
+  return image;
+}
+
+bool NativeImageSource::GetPixels( std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const
+{
+  return false;
+}
+
+bool NativeImageSource::EncodeToFile(const std::string& filename) const
+{
+  return false;
+}
+
+void NativeImageSource::SetSource( Any source )
+{
+}
+
+bool NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+{
+  return false;
+}
+
+bool NativeImageSource::GlExtensionCreate()
+{
+  return false;
+}
+
+void NativeImageSource::GlExtensionDestroy()
+{
+}
+
+unsigned int NativeImageSource::TargetTexture()
+{
+  return 0;
+}
+
+void NativeImageSource::PrepareTexture()
+{
+}
+
+unsigned int NativeImageSource::GetWidth() const
+{
+  return 0;
+}
+
+unsigned int NativeImageSource::GetHeight() const
+{
+  return 0;
+}
+
+bool NativeImageSource::RequiresBlending() const
+{
+  return false;
+}
+
+NativeImageInterface::Extension* NativeImageSource::GetExtension()
+{
+  return NULL;
+}
+
+NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource )
+{
+}
+
+NativeImageSource::~NativeImageSource()
+{
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp
new file mode 100644 (file)
index 0000000..b959638
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2018 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/orientation.h>
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+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
+};
+
+class Orientation : public BaseObject
+{
+public:
+  typedef Dali::Orientation::OrientationSignalType OrientationSignalType;
+
+  static Orientation* New(Window* window)
+  {
+    Orientation* orientation = new Orientation(window);
+    return orientation;
+  }
+  Orientation(Window* window)
+  {
+  }
+
+protected:
+  virtual ~Orientation()
+  {
+  }
+public:
+  int GetDegrees() const
+  {
+    return 0;
+  }
+  float GetRadians() const
+  {
+    return 0.0f;
+  }
+  void OnOrientationChanged( const RotationEvent& rotation )
+  {
+  }
+  OrientationSignalType& ChangedSignal()
+  {
+    return mChangedSignal;
+  }
+
+private:
+  Orientation(const Orientation&);
+  Orientation& operator=(Orientation&);
+  OrientationSignalType mChangedSignal;
+};
+
+} // Adaptor namespace
+} // Internal namespace
+
+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);
+}
+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);
+}
+
+Orientation::Orientation()
+{
+}
+Orientation::~Orientation()
+{
+}
+Orientation::Orientation(const Orientation& handle)
+: BaseHandle(handle)
+{
+}
+
+Orientation& Orientation::operator=(const Orientation& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+int Orientation::GetDegrees() const
+{
+  return GetImplementation(*this).GetDegrees();
+}
+
+float Orientation::GetRadians() const
+{
+  return GetImplementation(*this).GetRadians();
+}
+
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
+{
+  return GetImplementation(*this).ChangedSignal();
+}
+
+Orientation::Orientation( Internal::Adaptor::Orientation* orientation )
+: BaseHandle(orientation)
+{
+}
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
new file mode 100644 (file)
index 0000000..9cb217a
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-physical-keyboard.h"
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+/********************************************************************************
+ * Stub for Dali::Internal::Adaptor::PhysicalKeyboard
+ ********************************************************************************/
+namespace Internal
+{
+namespace Adaptor
+{
+class PhysicalKeyboard : public BaseObject
+{
+public: // Creation & Destruction
+
+  PhysicalKeyboard();
+  ~PhysicalKeyboard();
+  static Dali::PhysicalKeyboard Get();
+
+public:
+  bool IsAttached() const;
+
+public: // Signals
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType& StatusChangedSignal();
+
+private:
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType mStatusChangedSignal;
+  bool mIsAttached;
+  static Dali::PhysicalKeyboard mPhysicalKeyboard;
+};
+
+Dali::PhysicalKeyboard PhysicalKeyboard::mPhysicalKeyboard;
+
+PhysicalKeyboard::PhysicalKeyboard()
+: mIsAttached(true)
+{
+}
+
+PhysicalKeyboard::~PhysicalKeyboard()
+{
+}
+
+Dali::PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  if( ! mPhysicalKeyboard )
+  {
+    mPhysicalKeyboard = Dali::PhysicalKeyboard(new Internal::Adaptor::PhysicalKeyboard());
+  }
+  return mPhysicalKeyboard;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  return mIsAttached;
+}
+
+Dali::PhysicalKeyboard::PhysicalKeyboardSignalType& PhysicalKeyboard::StatusChangedSignal()
+{
+  return mStatusChangedSignal;
+}
+
+} // namespace Adaptor
+} // namespace Internal
+
+
+/********************************************************************************
+ * Stub for Dali::PhysicalKeyboard
+ ********************************************************************************/
+
+PhysicalKeyboard::PhysicalKeyboard(){}
+PhysicalKeyboard::~PhysicalKeyboard(){}
+
+PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  // Get the physical keyboard handle
+  PhysicalKeyboard handle = Internal::Adaptor::PhysicalKeyboard::Get();
+  return handle;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  const BaseObject& object = GetBaseObject();
+  const Internal::Adaptor::PhysicalKeyboard& pyke = static_cast< const Internal::Adaptor::PhysicalKeyboard& >( object );
+  return pyke.IsAttached();
+}
+
+PhysicalKeyboard::PhysicalKeyboardSignalType& PhysicalKeyboard::StatusChangedSignal()
+{
+  BaseObject& object = GetBaseObject();
+  Internal::Adaptor::PhysicalKeyboard& pyke = static_cast< Internal::Adaptor::PhysicalKeyboard& >( object );
+  return pyke.StatusChangedSignal();
+}
+
+PhysicalKeyboard::PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard *impl )
+: BaseHandle(impl)
+{
+}
+
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.h
new file mode 100644 (file)
index 0000000..4119640
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_TOOLKIT_PHYSICAL_KEYBOARD_H
+#define DALI_TOOLKIT_PHYSICAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class PhysicalKeyboard;
+}
+}
+
+class PhysicalKeyboard : public BaseHandle
+{
+public:
+  typedef Signal< void (PhysicalKeyboard) > PhysicalKeyboardSignalType;
+  PhysicalKeyboard();
+  ~PhysicalKeyboard();
+  static PhysicalKeyboard Get();
+  bool IsAttached() const;
+  PhysicalKeyboardSignalType& StatusChangedSignal();
+  PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard* impl );
+};
+
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_PHYSICAL_KEYBOARD_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h
new file mode 100644 (file)
index 0000000..b466cfc
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef DALI_TOOLKIT_SCENE_HOLDER_IMPL_H
+#define DALI_TOOLKIT_SCENE_HOLDER_IMPL_H
+
+/*
+ * Copyright (c) 2020 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/integration-api/adaptor-framework/render-surface-interface.h>
+
+#include <dali/integration-api/scene.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/object/base-object.h>
+
+namespace Dali
+{
+
+class TestRenderSurface : public Dali::RenderSurfaceInterface
+{
+public:
+
+  TestRenderSurface( PositionSize positionSize ) {};
+
+  virtual PositionSize GetPositionSize() const { PositionSize size; return size; };
+
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) { dpiHorizontal = dpiVertical = 96; }
+
+  virtual void InitializeGraphics() {};
+
+  virtual void CreateSurface() {};
+
+  virtual void DestroySurface() {};
+
+  virtual bool ReplaceGraphicsSurface() { return false; };
+
+  virtual void MoveResize( Dali::PositionSize positionSize ) {};
+
+  virtual void StartRender() {};
+
+  virtual bool PreRender( bool resizingSurface ) { return false; };
+
+  virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) {};
+
+  virtual void StopRender() {};
+
+  virtual void ReleaseLock() {};
+
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) {};
+
+  virtual RenderSurfaceInterface::Type GetSurfaceType() { return RenderSurfaceInterface::WINDOW_RENDER_SURFACE; };
+
+  virtual void MakeContextCurrent() {};
+
+  virtual Integration::DepthBufferAvailable GetDepthBufferRequired() { return Integration::DepthBufferAvailable::FALSE; };
+
+  virtual Integration::StencilBufferAvailable GetStencilBufferRequired() { return Integration::StencilBufferAvailable::FALSE; };
+
+  virtual void SetBackgroundColor( Vector4 color ) {};
+
+  virtual Vector4 GetBackgroundColor() { return Color::WHITE; };
+};
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class SceneHolder : public Dali::BaseObject
+{
+public:
+
+  SceneHolder( const Dali::Rect<int>& positionSize );
+
+  virtual ~SceneHolder();
+
+  void Add( Dali::Actor actor );
+
+  void Remove( Dali::Actor actor );
+
+  Dali::Layer GetRootLayer() const;
+
+  void SetBackgroundColor( Vector4 color );
+
+  Vector4 GetBackgroundColor() const;
+
+  void FeedTouchPoint( Dali::TouchPoint& point, int timeStamp );
+
+  void FeedWheelEvent( Dali::WheelEvent& wheelEvent );
+
+  void FeedKeyEvent( Dali::KeyEvent& keyEvent );
+
+  Dali::Integration::SceneHolder::KeyEventSignalType& KeyEventSignal();
+
+  Dali::Integration::SceneHolder::KeyEventGeneratedSignalType& KeyEventGeneratedSignal();
+
+  Dali::Integration::SceneHolder::TouchSignalType& TouchSignal();
+
+  Dali::Integration::SceneHolder::WheelEventSignalType& WheelEventSignal();
+
+  Integration::Scene GetScene();
+
+  Dali::RenderSurfaceInterface& GetRenderSurface();
+
+private:
+
+  TestRenderSurface mRenderSurface;
+  Integration::Scene mScene;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+inline Internal::Adaptor::SceneHolder& GetImplementation( Dali::Integration::SceneHolder& sceneHolder )
+{
+  DALI_ASSERT_ALWAYS( sceneHolder && "SceneHolder handle is empty" );
+  BaseObject& object = sceneHolder.GetBaseObject();
+  return static_cast<Internal::Adaptor::SceneHolder&>( object );
+}
+
+inline const Internal::Adaptor::SceneHolder& GetImplementation( const Dali::Integration::SceneHolder& sceneHolder )
+{
+  DALI_ASSERT_ALWAYS( sceneHolder && "SceneHolder handle is empty" );
+  const BaseObject& object = sceneHolder.GetBaseObject();
+  return static_cast<const Internal::Adaptor::SceneHolder&>( object );
+}
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCENE_HOLDER_IMPL_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder.cpp
new file mode 100644 (file)
index 0000000..320c859
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2020 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/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+#include <toolkit-scene-holder-impl.h>
+
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/base-object.h>
+
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <toolkit-adaptor-impl.h>
+
+using AdaptorImpl = Dali::Internal::Adaptor::Adaptor;
+
+namespace Dali
+{
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Dali::Internal::Adaptor::SceneHolder Stub
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+SceneHolder::SceneHolder( const Dali::Rect<int>& positionSize )
+: mRenderSurface( positionSize ),
+  mScene( Dali::Integration::Scene::New( Dali::Size( static_cast<float>( positionSize.width ), static_cast<float>( positionSize.height ) ) ) )
+{
+}
+
+SceneHolder::~SceneHolder()
+{
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    AdaptorImpl::GetImpl( AdaptorImpl::Get() ).RemoveWindow( this );
+  }
+}
+
+void SceneHolder::Add( Dali::Actor actor )
+{
+  mScene.Add( actor );
+}
+
+void SceneHolder::Remove( Dali::Actor actor )
+{
+  mScene.Remove( actor );
+}
+
+Dali::Layer SceneHolder::GetRootLayer() const
+{
+  return mScene.GetRootLayer();
+}
+
+void SceneHolder::SetBackgroundColor( Vector4 color )
+{
+  return mScene.SetBackgroundColor( color );
+}
+
+Vector4 SceneHolder::GetBackgroundColor() const
+{
+  return mScene.GetBackgroundColor();
+}
+
+void SceneHolder::FeedTouchPoint( Dali::TouchPoint& point, int timeStamp )
+{
+}
+
+void SceneHolder::FeedWheelEvent( Dali::WheelEvent& wheelEvent )
+{
+}
+
+void SceneHolder::FeedKeyEvent( Dali::KeyEvent& keyEvent )
+{
+}
+
+Dali::Integration::SceneHolder::KeyEventSignalType& SceneHolder::KeyEventSignal()
+{
+  return mScene.KeyEventSignal();
+}
+
+Dali::Integration::SceneHolder::KeyEventGeneratedSignalType& SceneHolder::KeyEventGeneratedSignal()
+{
+  return mScene.KeyEventGeneratedSignal();
+}
+
+Dali::Integration::SceneHolder::TouchSignalType& SceneHolder::TouchSignal()
+{
+  return mScene.TouchSignal();
+}
+
+Dali::Integration::SceneHolder::WheelEventSignalType& SceneHolder::WheelEventSignal()
+{
+  return mScene.WheelEventSignal();
+}
+
+Integration::Scene SceneHolder::GetScene()
+{
+  return mScene;
+}
+
+Dali::RenderSurfaceInterface& SceneHolder::GetRenderSurface()
+{
+  return mRenderSurface;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Dali::Integration::SceneHolder Stub
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace Integration
+{
+
+SceneHolder::SceneHolder()
+{
+  // Dali::Internal::Adaptor::Adaptor::Get().WindowCreatedSignal().Emit( *this );
+}
+
+SceneHolder::~SceneHolder()
+{
+}
+
+SceneHolder::SceneHolder( const SceneHolder& handle )
+: BaseHandle(handle)
+{
+}
+
+SceneHolder::SceneHolder( Internal::Adaptor::SceneHolder* internal )
+: BaseHandle(internal)
+{
+}
+
+SceneHolder& SceneHolder::operator=( const SceneHolder& rhs )
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+Dali::Integration::SceneHolder SceneHolder::Get( Dali::Actor actor )
+{
+  Internal::Adaptor::SceneHolder* sceneHolderImpl = nullptr;
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    sceneHolderImpl = AdaptorImpl::GetImpl( AdaptorImpl::Get() ).GetWindow( actor );
+  }
+
+  return Dali::Integration::SceneHolder( sceneHolderImpl );
+}
+
+void SceneHolder::Add( Actor actor )
+{
+  GetImplementation( *this ).Add( actor );
+}
+
+void SceneHolder::Remove( Actor actor )
+{
+  GetImplementation( *this ).Remove( actor );
+}
+
+Dali::Layer SceneHolder::GetRootLayer() const
+{
+  return GetImplementation( *this ).GetRootLayer();
+}
+
+void SceneHolder::SetBackgroundColor( Vector4 color )
+{
+  GetImplementation( *this ).SetBackgroundColor( color );
+}
+
+Vector4 SceneHolder::GetBackgroundColor() const
+{
+  return GetImplementation( *this ).GetBackgroundColor();
+}
+
+void SceneHolder::FeedTouchPoint( Dali::TouchPoint& point, int timeStamp )
+{
+  GetImplementation( *this ).FeedTouchPoint( point, timeStamp );
+}
+
+void SceneHolder::FeedWheelEvent( Dali::WheelEvent& wheelEvent )
+{
+  GetImplementation( *this ).FeedWheelEvent( wheelEvent );
+}
+
+void SceneHolder::FeedKeyEvent( Dali::KeyEvent& keyEvent )
+{
+  GetImplementation( *this ).FeedKeyEvent( keyEvent );
+}
+
+SceneHolder::KeyEventSignalType& SceneHolder::KeyEventSignal()
+{
+  return GetImplementation( *this ).KeyEventSignal();
+}
+
+SceneHolder::KeyEventGeneratedSignalType& SceneHolder::KeyEventGeneratedSignal()
+{
+  return GetImplementation( *this ).KeyEventGeneratedSignal();
+}
+
+SceneHolder::TouchSignalType& SceneHolder::TouchSignal()
+{
+  return GetImplementation( *this ).TouchSignal();
+}
+
+SceneHolder::WheelEventSignalType& SceneHolder::WheelEventSignal()
+{
+  return GetImplementation( *this ).WheelEventSignal();
+}
+
+} // Integration
+
+} // Dali
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..167f6d8
--- /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/common/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
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp
new file mode 100644 (file)
index 0000000..18c086f
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// HEADER
+#include "toolkit-style-monitor.h"
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace
+{
+const char* DEFAULT_THEME=
+  "{\n"
+  "  \"config\":\n"
+  "  {\n"
+  "    \"brokenImageUrl\":\"{DALI_IMAGE_DIR}broken.png\"\n"
+  "  },\n"
+  "  \"styles\":\n"
+  "  {\n"
+  "  \"textlabel\":\n"
+  "    {\n"
+  "      \"fontStyle\":{\"weight\":\"normal\"},\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("LucidaSans");
+std::string gFontStyle("Regular");
+int         gFontSize(1);
+}
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+/**
+ * Stub for the StyleMonitor
+ */
+class StyleMonitor : public BaseObject
+{
+public: // Creation & Destruction
+  static Dali::StyleMonitor Get();
+  StyleMonitor();
+  ~StyleMonitor();
+
+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();
+
+  void EmitStyleChangeSignal(StyleChange::Type styleChange)
+  {
+    mStyleChangeSignal.Emit(Dali::StyleMonitor(this), styleChange);
+  }
+
+private:
+  Dali::StyleMonitor::StyleChangeSignalType mStyleChangeSignal;
+  static Dali::StyleMonitor mToolkitStyleMonitor;
+
+  std::string mTheme;  ///<< Current theme name
+};
+
+Dali::StyleMonitor StyleMonitor::mToolkitStyleMonitor;
+
+Dali::StyleMonitor StyleMonitor::Get()
+{
+  if( ! mToolkitStyleMonitor )
+  {
+    mToolkitStyleMonitor = Dali::StyleMonitor( new Dali::Internal::Adaptor::StyleMonitor() );
+  }
+  return mToolkitStyleMonitor;
+}
+
+StyleMonitor::StyleMonitor()
+: mTheme("default")
+{
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return gFontFamily;
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return gFontStyle;
+}
+
+float StyleMonitor::GetDefaultFontSize() const
+{
+  return gFontSize;
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return mTheme;
+}
+
+void StyleMonitor::SetTheme(std::string path)
+{
+  mTheme = 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;
+}
+
+} // namespace Adaptor
+} // namespace Internal
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Internal::Adaptor::StyleMonitor& GetImplementation(Dali::StyleMonitor& monitor)
+{
+  BaseObject& object = monitor.GetBaseObject();
+  return static_cast<Internal::Adaptor::StyleMonitor&>(object);
+}
+const Internal::Adaptor::StyleMonitor& GetImplementation(const Dali::StyleMonitor& monitor)
+{
+  const BaseObject& object = monitor.GetBaseObject();
+  return static_cast<const Internal::Adaptor::StyleMonitor&>(object);
+}
+
+StyleMonitor::StyleMonitor()
+{
+}
+
+StyleMonitor::StyleMonitor(const StyleMonitor& monitor)
+: BaseHandle(monitor)
+{
+}
+
+StyleMonitor StyleMonitor::StyleMonitor::Get()
+{
+  return Internal::Adaptor::StyleMonitor::Get();
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return GetImplementation(*this).GetDefaultFontFamily();
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return GetImplementation(*this).GetDefaultFontStyle();
+}
+
+int StyleMonitor::GetDefaultFontSize() const
+{
+  return GetImplementation(*this).GetDefaultFontSize();
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return GetImplementation(*this).GetTheme();
+}
+
+void StyleMonitor::SetTheme(const std::string& themeFilePath)
+{
+  GetImplementation(*this).SetTheme(themeFilePath);
+}
+
+StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
+{
+  return GetImplementation(*this).StyleChangeSignal();
+}
+
+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 )
+  {
+    BaseHandle::operator=(monitor);
+  }
+  return *this;
+}
+
+StyleMonitor::StyleMonitor(Internal::Adaptor::StyleMonitor* internal)
+: BaseHandle(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
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.h
new file mode 100644 (file)
index 0000000..cd5dcfe
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_STYLE_MONITOR_H
+#define DALI_TOOLKIT_TOOLKIT_STYLE_MONITOR_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/adaptor-framework/style-change.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+
+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-test-application.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp
new file mode 100644 (file)
index 0000000..d3bdd42
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020 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 <toolkit-test-application.h>
+
+// INTERNAL INCLUDES
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <toolkit-adaptor-impl.h>
+#include <toolkit-lifecycle-controller.h>
+
+namespace Dali
+{
+
+using AdaptorImpl = Dali::Internal::Adaptor::Adaptor;
+
+ToolkitTestApplication::ToolkitTestApplication( size_t surfaceWidth, size_t surfaceHeight, float  horizontalDpi, float verticalDpi )
+: TestApplication( surfaceWidth, surfaceHeight, horizontalDpi, verticalDpi, false /* Do not Initialize Core */ ),
+  mMainWindow( new Dali::Window ),
+  mAdaptor( &AdaptorImpl::New() ) // Need to create Adaptor first as many singletons in dali-adaptor need it
+{
+  // Create Core next
+  CreateCore();
+
+  // Override Scene creation in TestApplication by creating a window.
+  // The window will create a Scene & surface and set up the scene's surface appropriately.
+  *mMainWindow = Window::New( PositionSize( 0, 0, surfaceWidth, surfaceHeight ), "" );
+  mScene = AdaptorImpl::GetScene( *mMainWindow );
+  mScene.SetDpi( Vector2( horizontalDpi, verticalDpi ) );
+
+  // Core needs to be initialized next before we start the adaptor
+  InitializeCore();
+
+  // This will also emit the window created signals
+  AdaptorImpl::GetImpl( *mAdaptor ).Start( *mMainWindow );
+
+  Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
+  lifecycleController.InitSignal().Emit();
+
+  // set the DPI value for font rendering
+  TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+  if( fontClient )
+  {
+    fontClient.SetDpi( mDpi.x, mDpi.y );
+  }
+}
+
+ToolkitTestApplication::~ToolkitTestApplication()
+{
+  // Need to delete core before we delete the adaptor.
+  delete mCore;
+  mCore = NULL;
+}
+
+void ToolkitTestApplication::RunIdles()
+{
+  AdaptorImpl::GetImpl( *mAdaptor.get() ).RunIdles();
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h
new file mode 100644 (file)
index 0000000..7dd21b5
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef DALI_TOOLKIT_TEST_APPLICATION_H
+#define DALI_TOOLKIT_TEST_APPLICATION_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+
+// INTERNAL INCLUDES
+#include <dali-test-suite-utils.h>
+
+namespace Dali
+{
+
+class Adaptor;
+class Window;
+
+/**
+ * Adds some functionality on top of TestApplication that is required by the Toolkit.
+ *
+ * This includes creation and destruction of the Adaptor and Window classes.
+ */
+class ToolkitTestApplication : public TestApplication
+{
+public:
+
+  ToolkitTestApplication( size_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                          size_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                          float  horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                          float  verticalDpi   = DEFAULT_VERTICAL_DPI );
+
+  ~ToolkitTestApplication();
+
+  /**
+   * @brief Executes the idle callbacks.
+   *
+   * Some controls like the text-field and the text-editor connect callbacks to the
+   * idle signal.
+   */
+  void RunIdles();
+
+private:
+
+  std::unique_ptr<Dali::Window> mMainWindow;
+  std::unique_ptr< Adaptor > mAdaptor;
+};
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEST_APPLICATION_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 100755 (executable)
index 0000000..cae7871
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2019 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/common/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,
+                            bool matchSystemLanguageDirection, LayoutDirection::Type layoutDirection ){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()
+  : mGlyphInfo()
+  {
+  }
+
+  ~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( Character charcode, const FontDescription& fontDescription, 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 ){}
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode ){return 0;}
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal ){return true;}
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItailc, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth ){}
+  PixelData CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth ){return PixelData();}
+  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;}
+  bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex ){return false;}
+private:
+  GlyphInfo    mGlyphInfo;
+}; // class FontClient
+
+
+class Shaping : public BaseObject
+{
+public:
+  Shaping()
+  : mText( NULL ),
+    mNumChars( 0 )
+  {
+  }
+
+  ~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 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);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/******************************************************************************/
+
+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,
+                                                bool matchSystemLanguageDirection,
+                                                LayoutDirection::Type layoutDirection )
+{
+  return GetImplementation( *this ).CreateInfo( paragraph, numberOfCharacters, matchSystemLanguageDirection, layoutDirection );
+}
+
+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::GlyphBufferData::GlyphBufferData()
+{
+}
+
+FontClient::GlyphBufferData::~GlyphBufferData()
+{
+}
+
+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( Character charcode, const FontDescription& fontDescription, PointSize26Dot6 pointSize, bool preferColor )
+{
+  return GetImplementation(*this).FindFallbackFont( charcode, fontDescription, 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 )
+{
+  GetImplementation(*this).GetFontMetrics( fontId, metrics );
+}
+
+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 )
+{
+  return GetImplementation(*this).GetGlyphMetrics( array, size, horizontal );
+}
+
+void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool softwareItailc, bool softwareBold, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+{
+  GetImplementation(*this).CreateBitmap( fontId, glyphIndex, softwareItailc, softwareBold, data, outlineWidth );
+}
+
+PixelData FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+{
+  return GetImplementation(*this).CreateBitmap( fontId, glyphIndex, outlineWidth );
+}
+
+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 );
+}
+
+bool FontClient::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
+{
+  return GetImplementation(*this).IsColorGlyph( fontId, glyphIndex );
+}
+
+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-timer.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
new file mode 100644 (file)
index 0000000..f9c89da
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-timer.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Timer;
+
+typedef IntrusivePtr<Timer> TimerPtr;
+
+Dali::Timer::TimerSignalType gTickSignal;
+int gTimerCount = 0;
+bool gKeepTimersRunning = false;
+
+/**
+ * Implementation of the timer
+ */
+class Timer : public BaseObject
+{
+public:
+  void MockEmitSignal();
+
+public:
+  static TimerPtr New( unsigned int milliSec );
+  Timer( unsigned int milliSec );
+  virtual ~Timer();
+
+  void Start();
+  void Stop();
+  void SetInterval( unsigned int interval );
+  unsigned int GetInterval() const;
+  bool IsRunning() const;
+  bool Tick();
+
+public: // Signals
+
+  Dali::Timer::TimerSignalType& TickSignal();
+
+private: // Implementation
+
+  // not implemented
+  Timer( const Timer& );
+  Timer& operator=( const Timer& );
+
+private: // Data
+
+  unsigned int mInterval;
+  bool mRunning;
+};
+
+inline Timer& GetImplementation(Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Timer&>(handle);
+}
+
+inline const Timer& GetImplementation(const Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  const BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Timer&>(handle);
+}
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  TimerPtr timerImpl = new Timer( milliSec );
+  return timerImpl;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mInterval( milliSec ),
+  mRunning( false )
+{
+  ++gTimerCount;
+}
+
+Timer::~Timer()
+{
+  --gTimerCount;
+}
+
+void Timer::Start()
+{
+  mRunning = true;
+}
+
+void Timer::Stop()
+{
+  mRunning = false;
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  mInterval = interval;
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mInterval;
+}
+
+bool Timer::IsRunning() const
+{
+  return mRunning;
+}
+
+bool Timer::Tick()
+{
+  return false;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return gTickSignal;
+}
+
+// Mock setup functions:
+
+void Timer::MockEmitSignal()
+{
+  if( gTimerCount > 1 )
+  {
+    // Only emit the signal if we have more than just the timer created in the test function
+    gTickSignal.Emit();
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+/********************************************************************************/
+/*********************************  PUBLIC CLASS  *******************************/
+/********************************************************************************/
+
+Timer::Timer()
+{
+
+}
+
+Timer Timer::New( unsigned int milliSec )
+{
+  Internal::Adaptor::TimerPtr internal = Internal::Adaptor::Timer::New( milliSec );
+  return Timer(internal.Get());
+}
+
+Timer::Timer( const Timer& timer )
+:BaseHandle( timer )
+{
+}
+
+Timer& Timer::operator=( const Timer& timer )
+{
+  // check self assignment
+  if( *this != timer )
+  {
+    BaseHandle::operator=(timer);
+  }
+  return *this;
+}
+
+Timer::~Timer()
+{
+}
+
+void Timer::Start()
+{
+  Internal::Adaptor::GetImplementation( *this ).Start();
+  Dali::Internal::Adaptor::gKeepTimersRunning = true;
+}
+
+void Timer::Stop()
+{
+  Internal::Adaptor::GetImplementation( *this ).Stop();
+}
+
+void Timer::SetInterval( unsigned int milliSec )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetInterval( milliSec );
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetInterval();
+}
+
+bool Timer::IsRunning() const
+{
+  return true;
+}
+
+Timer::TimerSignalType& Timer::TickSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).TickSignal();
+}
+
+Timer::Timer(Internal::Adaptor::Timer* timer)
+: BaseHandle(timer)
+{
+}
+
+// Mock setup functions:
+
+void Timer::MockEmitSignal()
+{
+  Internal::Adaptor::GetImplementation( *this ).MockEmitSignal();
+}
+
+} // namespace Dali
+
+
+namespace Test
+{
+
+int GetTimerCount()
+{
+  return Dali::Internal::Adaptor::gTimerCount;
+}
+
+void EmitGlobalTimerSignal()
+{
+  // @todo Multiplex timers properly.
+  Dali::Internal::Adaptor::gKeepTimersRunning = Dali::Internal::Adaptor::gTickSignal.Emit();
+}
+
+bool AreTimersRunning()
+{
+  return Dali::Internal::Adaptor::gKeepTimersRunning;
+}
+
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-timer.h
new file mode 100644 (file)
index 0000000..fdd44b4
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DALI_TOOLKIT_TOOLKIT_TIMER_H
+#define DALI_TOOLKIT_TOOLKIT_TIMER_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// PUBLIC INCLUDES
+#define DALI_TIMER_H
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Timer;
+}
+}
+
+class Timer : public BaseHandle
+{
+public:
+  void MockEmitSignal();
+
+public:
+  typedef Signal< bool () > TimerSignalType;
+  Timer();
+  static Timer New( unsigned int milliSec );
+  Timer( const Timer& timer );
+  Timer& operator=( const Timer& timer );
+  ~Timer();
+  static Timer DownCast( BaseHandle handle );
+  void Start();
+  void Stop();
+  void SetInterval( unsigned int milliSec );
+  unsigned int GetInterval() const;
+  bool IsRunning() const;
+  TimerSignalType& TickSignal();
+private:
+  Timer(Internal::Adaptor::Timer* timer);
+};
+
+} // namespace Dali
+
+namespace Test
+{
+int GetTimerCount();
+void EmitGlobalTimerSignal();
+bool AreTimersRunning();
+}
+
+#endif // DALI_TOOLKIT_TOOLKIT_TIMER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-trigger-event-factory.cpp
new file mode 100644 (file)
index 0000000..6f578e0
--- /dev/null
@@ -0,0 +1,54 @@
+
+#include <dali/public-api/signals/callback.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Toolkit
+{
+
+class TriggerEvent: public Dali::TriggerEventInterface
+{
+public:
+
+  TriggerEvent( Dali::CallbackBase* callback, Dali::TriggerEventInterface::Options Options );
+  ~TriggerEvent(){}
+
+  void Trigger();
+
+private:
+  Dali::CallbackBase* mCallback;
+
+};
+
+TriggerEvent::TriggerEvent( Dali::CallbackBase* callback, Dali::TriggerEventInterface::Options Options )
+  : mCallback( callback )
+{
+}
+
+void TriggerEvent::Trigger()
+{
+  Dali::CallbackBase::Execute( *mCallback );
+}
+
+} // namespace Toolkit
+
+} // namespace Internal
+
+} // namespace Dali
+
+Dali::TriggerEventInterface* Dali::TriggerEventFactory::CreateTriggerEvent( Dali::CallbackBase* callback, Dali::TriggerEventInterface::Options options )
+{
+  return new Dali::Internal::Toolkit::TriggerEvent( callback, options );
+}
+
+void Dali::TriggerEventFactory::DestroyTriggerEvent( Dali::TriggerEventInterface* triggerEventInterface )
+{
+  Dali::Internal::Toolkit::TriggerEvent* triggerEvent( static_cast< Dali::Internal::Toolkit::TriggerEvent *>(triggerEventInterface) );
+  delete triggerEvent;
+}
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp
new file mode 100644 (file)
index 0000000..7200f0f
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/dali.h>
+
+
+namespace Dali
+{
+
+TtsPlayer::TtsPlayer()
+{
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class TtsPlayer : public BaseObject
+{
+public:
+  TtsPlayer()
+  {
+  }
+
+  void Play(const std::string& text)
+  {
+  }
+
+  void Stop()
+  {
+  }
+
+  void Pause()
+  {
+  }
+
+  void Resume()
+  {
+  }
+
+  Dali::TtsPlayer::State GetState()
+  {
+    return Dali::TtsPlayer::READY;
+  }
+
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal()
+  {
+    return mStateChangedSignal;
+  }
+private:
+  Dali::TtsPlayer::StateChangedSignalType mStateChangedSignal;
+};
+
+
+inline TtsPlayer& GetImplementation(Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+  BaseObject& handle = player.GetBaseObject();
+  return static_cast<Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+inline const TtsPlayer& GetImplementation(const Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+  const BaseObject& handle = player.GetBaseObject();
+  return static_cast<const Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+} // Adaptor
+} // Internal
+
+static IntrusivePtr<Internal::Adaptor::TtsPlayer> ttsSingleton = NULL;
+
+TtsPlayer TtsPlayer::Get(Dali::TtsPlayer::Mode mode)
+{
+  if( ! ttsSingleton )
+  {
+    ttsSingleton.Reset( new Dali::Internal::Adaptor::TtsPlayer() );
+  }
+  TtsPlayer playerHandle(ttsSingleton.Get());
+
+  return playerHandle;
+}
+
+TtsPlayer::~TtsPlayer()
+{
+}
+
+TtsPlayer::TtsPlayer(const TtsPlayer& handle)
+: BaseHandle(handle)
+{
+}
+
+TtsPlayer& TtsPlayer::operator=(const TtsPlayer& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void TtsPlayer::Play(const std::string& text)
+{
+  // GetImplementation(*this).Play(text);
+}
+
+void TtsPlayer::Stop()
+{
+  // GetImplementation(*this).Stop();
+}
+
+void TtsPlayer::Pause()
+{
+  // GetImplementation(*this).Pause();
+}
+
+void TtsPlayer::Resume()
+{
+  // GetImplementation(*this).Resume();
+}
+
+TtsPlayer::State TtsPlayer::GetState()
+{
+  return READY; // GetImplementation(*this).GetState();
+}
+
+TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).StateChangedSignal();
+}
+
+TtsPlayer::TtsPlayer( Internal::Adaptor::TtsPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.cpp
new file mode 100755 (executable)
index 0000000..cf52774
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2019 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/vector-animation-renderer.h>
+#include <dali/public-api/object/base-object.h>
+#include <toolkit-application.h>
+#include <toolkit-vector-animation-renderer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class VectorAnimationRenderer: public Dali::BaseObject
+{
+public:
+
+  VectorAnimationRenderer( const std::string& url )
+  : mUrl( url ),
+    mRenderer(),
+    mWidth( 0 ),
+    mHeight( 0 ),
+    mPreviousFrame( 0 ),
+    mFrameRate( 60.0f )
+  {
+    mCount++;
+
+    if( mCount == 2 )
+    {
+      mFrameRate = 0.1f;
+    }
+  }
+
+  ~VectorAnimationRenderer()
+  {
+    mCount--;
+  }
+
+  void SetRenderer( Dali::Renderer renderer )
+  {
+    mRenderer = renderer;
+
+    if( mWidth != 0 && mHeight != 0 )
+    {
+      Dali::TextureSet textureSet = mRenderer.GetTextures();
+      Dali::Texture texture = Dali::Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, mWidth, mHeight );
+      textureSet.SetTexture( 0, texture );
+      mUploadCompletedSignal.Emit();
+    }
+  }
+
+  void SetSize( uint32_t width, uint32_t height )
+  {
+    mWidth = width;
+    mHeight = height;
+
+    if( mRenderer )
+    {
+      Dali::TextureSet textureSet = mRenderer.GetTextures();
+      Dali::Texture texture = Dali::Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, mWidth, mHeight );
+      textureSet.SetTexture( 0, texture );
+      mUploadCompletedSignal.Emit();
+    }
+  }
+
+  bool Render( uint32_t frameNumber )
+  {
+    if( frameNumber == 1 && mPreviousFrame != frameNumber )
+    {
+      mPreviousFrame = frameNumber;
+      // For test corverage
+      return false;
+    }
+    mPreviousFrame = frameNumber;
+    return true;
+  }
+
+  uint32_t GetTotalFrameNumber() const
+  {
+    return VECTOR_ANIMATION_TOTAL_FRAME_NUMBER;
+  }
+
+  float GetFrameRate() const
+  {
+    return mFrameRate;
+  }
+
+  void GetDefaultSize( uint32_t& width, uint32_t& height ) const
+  {
+    width = 100;
+    height = 100;
+  }
+
+  bool GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
+  {
+    if( marker.compare( VECTOR_ANIMATION_MARKER_NAME_1 ) == 0 )
+    {
+      startFrame = VECTOR_ANIMATION_MARKER_START_FRAME_1;
+      endFrame = VECTOR_ANIMATION_MARKER_END_FRAME_1;
+    }
+    else if( marker.compare( VECTOR_ANIMATION_MARKER_NAME_2 ) == 0 )
+    {
+      startFrame = VECTOR_ANIMATION_MARKER_START_FRAME_2;
+      endFrame = VECTOR_ANIMATION_MARKER_END_FRAME_2;
+    }
+    else
+    {
+      return false;
+    }
+    return true;
+  }
+
+  Dali::VectorAnimationRenderer::UploadCompletedSignalType& UploadCompletedSignal()
+  {
+    return mUploadCompletedSignal;
+  }
+
+public:
+
+  static uint32_t mCount;
+
+  std::string mUrl;
+  Dali::Renderer mRenderer;
+  uint32_t mWidth;
+  uint32_t mHeight;
+  uint32_t mPreviousFrame;
+  float mFrameRate;
+  Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
+};
+
+uint32_t VectorAnimationRenderer::mCount = 0;
+
+inline VectorAnimationRenderer& GetImplementation( Dali::VectorAnimationRenderer& renderer )
+{
+  DALI_ASSERT_ALWAYS( renderer && "VectorAnimationRenderer handle is empty." );
+  BaseObject& handle = renderer.GetBaseObject();
+  return static_cast< Internal::Adaptor::VectorAnimationRenderer& >( handle );
+}
+
+inline const VectorAnimationRenderer& GetImplementation( const Dali::VectorAnimationRenderer& renderer )
+{
+  DALI_ASSERT_ALWAYS( renderer && "VectorAnimationRenderer handle is empty." );
+  const BaseObject& handle = renderer.GetBaseObject();
+  return static_cast< const Internal::Adaptor::VectorAnimationRenderer& >( handle );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+/********************************************************************************/
+/*********************************  PUBLIC CLASS  *******************************/
+/********************************************************************************/
+
+VectorAnimationRenderer VectorAnimationRenderer::New( const std::string& url )
+{
+  Internal::Adaptor::VectorAnimationRenderer* animationRenderer = new Internal::Adaptor::VectorAnimationRenderer( url );
+
+  return VectorAnimationRenderer( animationRenderer );
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer()
+{
+}
+
+VectorAnimationRenderer::~VectorAnimationRenderer()
+{
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer( Internal::Adaptor::VectorAnimationRenderer* internal )
+: BaseHandle( internal )
+{
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer( const VectorAnimationRenderer& handle )
+: BaseHandle( handle )
+{
+}
+
+VectorAnimationRenderer& VectorAnimationRenderer::operator=( const VectorAnimationRenderer& rhs )
+{
+  BaseHandle::operator=( rhs );
+  return *this;
+}
+
+void VectorAnimationRenderer::Finalize()
+{
+}
+
+void VectorAnimationRenderer::SetRenderer( Renderer renderer )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetRenderer( renderer );
+}
+
+void VectorAnimationRenderer::SetSize( uint32_t width, uint32_t height )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetSize( width, height );
+}
+
+bool VectorAnimationRenderer::Render( uint32_t frameNumber )
+{
+  return Internal::Adaptor::GetImplementation( *this ).Render( frameNumber );
+}
+
+uint32_t VectorAnimationRenderer::GetTotalFrameNumber() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetTotalFrameNumber();
+}
+
+float VectorAnimationRenderer::GetFrameRate() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetFrameRate();
+}
+
+void VectorAnimationRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+  Internal::Adaptor::GetImplementation( *this ).GetDefaultSize( width, height );
+}
+
+void VectorAnimationRenderer::GetLayerInfo( Property::Map& map ) const
+{
+}
+
+bool VectorAnimationRenderer::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetMarkerInfo( marker, startFrame, endFrame );
+}
+
+VectorAnimationRenderer::UploadCompletedSignalType& VectorAnimationRenderer::UploadCompletedSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).UploadCompletedSignal();
+}
+
+} // namespace Dali;
+
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-vector-animation-renderer.h
new file mode 100755 (executable)
index 0000000..670c5ca
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef DALI_TOOLKIT_TEST_VECTOR_ANIMATION_RENDERER_H
+#define DALI_TOOLKIT_TEST_VECTOR_ANIMATION_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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 Test
+{
+
+#define VECTOR_ANIMATION_TOTAL_FRAME_NUMBER 5
+#define VECTOR_ANIMATION_MARKER_NAME_1 "marker1"
+#define VECTOR_ANIMATION_MARKER_NAME_2 "marker2"
+#define VECTOR_ANIMATION_MARKER_START_FRAME_1 0
+#define VECTOR_ANIMATION_MARKER_END_FRAME_1 2
+#define VECTOR_ANIMATION_MARKER_START_FRAME_2 2
+#define VECTOR_ANIMATION_MARKER_END_FRAME_2 3
+
+} // Test
+
+
+#endif // DALI_TOOLKIT_TEST_VECTOR_ANIMATION_RENDERER_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-video-player.cpp
new file mode 100755 (executable)
index 0000000..957681e
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2019 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/video-player.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/base-object.h>
+#include <toolkit-application.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class VideoPlayer: public Dali::BaseObject
+{
+public:
+
+  VideoPlayer()
+  : mUrl(),
+    mVolumeLeft( 0.0f ),
+    mVolumeRight( 0.0f ),
+    mFinishedSignal(),
+    mMuted( false ),
+    mLooping( false),
+    mPlayPosition( 0 ),
+    mDisplyMode( Dali::VideoPlayerPlugin::DisplayMode::DST_ROI )
+  {
+  }
+
+  void SetMuted( bool muted )
+  {
+    mMuted = muted;
+  }
+
+  bool IsMuted()
+  {
+    return mMuted;
+  }
+
+  void SetLooping( bool looping )
+  {
+    mLooping = looping;
+  }
+
+  bool IsLooping()
+  {
+    return mLooping;
+  }
+
+  void Stop()
+  {
+    if( !mFinishedSignal.Empty() )
+    {
+      mFinishedSignal.Emit();
+    }
+  }
+
+  int GetPlayPosition()
+  {
+    return mPlayPosition;
+  }
+
+  void SetPlayPosition( int pos )
+  {
+    mPlayPosition = pos;
+  }
+
+  Dali::VideoPlayerPlugin::DisplayMode::Type GetDisplayMode() const
+  {
+    return mDisplyMode;
+  }
+
+  void SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode )
+  {
+    mDisplyMode = mode;
+  }
+
+  Any GetMediaPlayer()
+  {
+    return NULL;
+  }
+
+
+public:
+
+  std::string mUrl;
+  float mVolumeLeft;
+  float mVolumeRight;
+  Dali::VideoPlayerPlugin::VideoPlayerSignalType mFinishedSignal;
+
+private:
+
+  bool mMuted;
+  bool mLooping;
+  int mPlayPosition;
+  Dali::VideoPlayerPlugin::DisplayMode::Type mDisplyMode;
+};
+
+inline VideoPlayer& GetImplementation( Dali::VideoPlayer& player )
+{
+  DALI_ASSERT_ALWAYS(player && "VideoPlayer handle is empty");
+  BaseObject& handle = player.GetBaseObject();
+  return static_cast< Internal::Adaptor::VideoPlayer& >( handle );
+}
+
+inline const VideoPlayer& GetImplementation( const Dali::VideoPlayer& player )
+{
+  DALI_ASSERT_ALWAYS(player && "VideoPlayer handle is empty");
+  const BaseObject& handle = player.GetBaseObject();
+  return static_cast< const Internal::Adaptor::VideoPlayer& >( handle );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+/********************************************************************************/
+/*********************************  PUBLIC CLASS  *******************************/
+/********************************************************************************/
+
+VideoPlayer::VideoPlayer()
+{
+}
+
+VideoPlayer::VideoPlayer( Internal::Adaptor::VideoPlayer* internal )
+: BaseHandle( internal )
+{
+}
+
+VideoPlayer::~VideoPlayer()
+{
+}
+
+VideoPlayer VideoPlayer::New()
+{
+  Internal::Adaptor::VideoPlayer* player = new Internal::Adaptor::VideoPlayer();
+
+  return VideoPlayer( player );
+}
+
+VideoPlayer::VideoPlayer( const VideoPlayer& player )
+: BaseHandle( player )
+{
+}
+
+VideoPlayer& VideoPlayer::operator=( const VideoPlayer& player )
+{
+  BaseHandle::operator=( player );
+  return *this;
+}
+
+VideoPlayer VideoPlayer::DownCast( BaseHandle handle )
+{
+  VideoPlayer videoPlayer;
+  return videoPlayer;
+}
+
+void VideoPlayer::SetUrl( const std::string& url )
+{
+  Internal::Adaptor::GetImplementation( *this ).mUrl = url;
+}
+
+std::string VideoPlayer::GetUrl()
+{
+  return Internal::Adaptor::GetImplementation( *this ).mUrl;
+}
+
+void VideoPlayer::SetLooping(bool looping)
+{
+  Internal::Adaptor::GetImplementation( *this ).SetLooping( looping );
+}
+
+bool VideoPlayer::IsLooping()
+{
+  return Internal::Adaptor::GetImplementation( *this ).IsLooping();
+}
+
+void VideoPlayer::Play()
+{
+}
+
+void VideoPlayer::Pause()
+{
+}
+
+void VideoPlayer::Stop()
+{
+  Internal::Adaptor::GetImplementation( *this ).Stop();
+}
+
+void VideoPlayer::SetMute( bool mute )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetMuted( mute );
+}
+
+bool VideoPlayer::IsMuted()
+{
+  return Internal::Adaptor::GetImplementation( *this ).IsMuted();
+}
+
+void VideoPlayer::SetVolume( float left, float right )
+{
+  Internal::Adaptor::GetImplementation( *this ).mVolumeLeft = left;
+  Internal::Adaptor::GetImplementation( *this ).mVolumeRight = right;
+}
+
+void VideoPlayer::GetVolume( float& left, float& right )
+{
+  left = Internal::Adaptor::GetImplementation( *this ).mVolumeLeft;
+  right = Internal::Adaptor::GetImplementation( *this ).mVolumeRight;
+}
+
+void VideoPlayer::SetRenderingTarget( Any target )
+{
+}
+
+void VideoPlayer::SetPlayPosition( int millisecond )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetPlayPosition( millisecond );
+}
+
+int VideoPlayer::GetPlayPosition()
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetPlayPosition();
+}
+
+void VideoPlayer::SetDisplayArea( DisplayArea area )
+{
+}
+
+void VideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
+{
+}
+
+Dali::VideoPlayerPlugin::DisplayRotation VideoPlayer::GetDisplayRotation()
+{
+  return Dali::VideoPlayerPlugin::ROTATION_NONE;
+}
+
+Dali::VideoPlayerPlugin::VideoPlayerSignalType& VideoPlayer::FinishedSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).mFinishedSignal;
+}
+
+void VideoPlayer::Forward( int millisecond )
+{
+}
+
+void VideoPlayer::Backward( int millisecond )
+{
+}
+
+bool VideoPlayer::IsVideoTextureSupported()
+{
+  return ToolkitApplication::DECODED_IMAGES_SUPPORTED;
+}
+
+void VideoPlayer::SetCodecType( Dali::VideoPlayerPlugin::CodecType type )
+{
+}
+
+Dali::VideoPlayerPlugin::CodecType VideoPlayer::GetCodecType() const
+{
+  return Dali::VideoPlayerPlugin::CodecType::DEFAULT;
+}
+
+void VideoPlayer::SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetDisplayMode( mode );
+}
+
+Dali::VideoPlayerPlugin::DisplayMode::Type VideoPlayer::GetDisplayMode() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetDisplayMode();
+}
+
+Any VideoPlayer::GetMediaPlayer()
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetMediaPlayer();
+}
+
+} // namespace 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
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-web-engine.cpp
new file mode 100755 (executable)
index 0000000..5316331
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * Copyright (c) 2018 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 "toolkit-timer.h"
+
+#include <dali/devel-api/adaptor-framework/web-engine.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/images/native-image.h>
+#include <toolkit-application.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class WebEngine;
+
+namespace
+{
+static WebEngine* gInstance = NULL;
+static int gInstanceCount = 0;
+
+bool OnGoBack();
+bool OnGoForward();
+bool OnLoadUrl();
+bool OnEvaluteJavaScript();
+bool OnClearHistory();
+
+static void ConnectToGlobalSignal( bool (*func)() )
+{
+  Dali::Timer timer = Dali::Timer::New( 0 );
+  timer.TickSignal().Connect( func );
+}
+
+static void DisconnectFromGlobalSignal( bool (*func)() )
+{
+  Dali::Timer timer = Dali::Timer::New( 0 );
+  timer.TickSignal().Disconnect( func );
+}
+}
+
+class WebEngine: public Dali::BaseObject
+{
+public:
+
+  WebEngine()
+    : mUrl()
+    , mCurrentPlusOnePos( 0 )
+    , mCacheModel( Dali::WebEnginePlugin::CacheModel::DOCUMENT_VIEWER )
+    , mCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy::NO_THIRD_PARTY )
+    , mUserAgent()
+    , mEnableJavaScript( true )
+    , mLoadImagesAutomatically( true )
+    , mDefaultTextEncodingName()
+    , mDefaultFontSize( 16 )
+    , mEvaluating( false )
+  {
+    gInstanceCount++;
+    gInstance = this;
+  }
+
+  virtual ~WebEngine()
+  {
+    gInstanceCount--;
+    if( !gInstanceCount )
+    {
+      gInstance = NULL;
+    }
+  }
+
+  void LoadUrl( const std::string& url )
+  {
+    mUrl = url;
+    ConnectToGlobalSignal( &OnLoadUrl );
+  }
+
+  const std::string& GetUrl() const
+  {
+    return mUrl;
+  }
+
+  bool CanGoForward() const
+  {
+    return mHistory.size() > mCurrentPlusOnePos;
+  }
+
+  void GoForward()
+  {
+    ConnectToGlobalSignal( &OnGoForward );
+  }
+
+  bool CanGoBack() const
+  {
+    return mCurrentPlusOnePos > 1;
+  }
+
+  void GoBack()
+  {
+    ConnectToGlobalSignal( &OnGoBack );
+  }
+
+  void EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+  {
+    if( resultHandler )
+    {
+      if( !mEvaluating )
+      {
+        ConnectToGlobalSignal( &OnEvaluteJavaScript );
+      }
+      mResultCallbacks.push_back( resultHandler );
+    }
+  }
+
+  void ClearHistory()
+  {
+    ConnectToGlobalSignal( &OnClearHistory );
+  }
+
+  Dali::WebEnginePlugin::CacheModel GetCacheModel() const
+  {
+    return mCacheModel;
+  }
+
+  void SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel )
+  {
+    mCacheModel = cacheModel;
+  }
+
+  Dali::WebEnginePlugin::CookieAcceptPolicy GetCookieAcceptPolicy() const
+  {
+    return mCookieAcceptPolicy;
+  }
+
+  void SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy )
+  {
+    mCookieAcceptPolicy = policy;
+  }
+
+  const std::string& GetUserAgent() const
+  {
+    return mUserAgent;
+  }
+
+  void SetUserAgent( const std::string& userAgent )
+  {
+    mUserAgent = userAgent;
+  }
+
+  bool IsJavaScriptEnabled() const
+  {
+    return mEnableJavaScript;
+  }
+
+  void EnableJavaScript( bool enabled )
+  {
+    mEnableJavaScript = enabled;
+  }
+
+  bool AreImagesAutomaticallyLoaded() const
+  {
+    return mLoadImagesAutomatically;
+  }
+
+  void LoadImagesAutomatically( bool automatic )
+  {
+    mLoadImagesAutomatically = automatic;
+  }
+
+  const std::string& GetDefaultTextEncodingName() const
+  {
+    return mDefaultTextEncodingName;
+  }
+
+  void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
+  {
+    mDefaultTextEncodingName = defaultTextEncodingName;
+  }
+
+  int GetDefaultFontSize() const
+  {
+    return mDefaultFontSize;
+  }
+
+  void SetDefaultFontSize( int defaultFontSize )
+  {
+    mDefaultFontSize = defaultFontSize;
+  }
+
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadStartedSignal()
+  {
+    return mPageLoadStartedSignal;
+  }
+
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadFinishedSignal()
+  {
+    return mPageLoadFinishedSignal;
+  }
+
+  Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& PageLoadErrorSignal()
+  {
+    return mPageLoadErrorSignal;
+  }
+
+  std::string                                                mUrl;
+  std::vector< std::string >                                 mHistory;
+  size_t                                                     mCurrentPlusOnePos;
+  Dali::WebEnginePlugin::CacheModel                          mCacheModel;
+  Dali::WebEnginePlugin::CookieAcceptPolicy                  mCookieAcceptPolicy;
+  std::string                                                mUserAgent;
+  bool                                                       mEnableJavaScript;
+  bool                                                       mLoadImagesAutomatically;
+  std::string                                                mDefaultTextEncodingName;
+  int                                                        mDefaultFontSize;
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType         mPageLoadStartedSignal;
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType         mPageLoadFinishedSignal;
+  Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType    mPageLoadErrorSignal;
+  std::vector< std::function< void( const std::string& ) > > mResultCallbacks;
+  bool                                                       mEvaluating;
+};
+
+inline WebEngine& GetImplementation( Dali::WebEngine& webEngine )
+{
+  DALI_ASSERT_ALWAYS( webEngine && "WebEngine handle is empty." );
+  BaseObject& handle = webEngine.GetBaseObject();
+  return static_cast< Internal::Adaptor::WebEngine& >( handle );
+}
+
+inline const WebEngine& GetImplementation( const Dali::WebEngine& webEngine )
+{
+  DALI_ASSERT_ALWAYS( webEngine && "WebEngine handle is empty." );
+  const BaseObject& handle = webEngine.GetBaseObject();
+  return static_cast< const Internal::Adaptor::WebEngine& >( handle );
+}
+
+namespace
+{
+
+bool OnGoBack()
+{
+  DisconnectFromGlobalSignal( &OnGoBack );
+
+  if( gInstance && gInstance->CanGoBack() )
+  {
+    gInstance->mCurrentPlusOnePos--;
+  }
+  return false;
+}
+
+bool OnGoForward()
+{
+  DisconnectFromGlobalSignal( &OnGoForward );
+
+  if( gInstance && gInstance->CanGoForward() )
+  {
+    gInstance->mCurrentPlusOnePos++;
+  }
+  return false;
+}
+
+bool OnLoadUrl()
+{
+  DisconnectFromGlobalSignal( &OnLoadUrl );
+
+  if( gInstance )
+  {
+    if( gInstance->mHistory.size() > gInstance->mCurrentPlusOnePos )
+    {
+      gInstance->mHistory.erase( gInstance->mHistory.begin() + gInstance->mCurrentPlusOnePos, gInstance->mHistory.end() );
+    }
+    gInstance->mHistory.push_back( gInstance->mUrl );
+    gInstance->mCurrentPlusOnePos++;
+    gInstance->mPageLoadStartedSignal.Emit( gInstance->mUrl );
+    gInstance->mPageLoadFinishedSignal.Emit( gInstance->mUrl );
+  }
+  return false;
+}
+
+bool OnEvaluteJavaScript()
+{
+  DisconnectFromGlobalSignal( &OnEvaluteJavaScript );
+
+  if( gInstance )
+  {
+    for( auto& func : gInstance->mResultCallbacks )
+    {
+      func("undefined");
+    }
+    gInstance->mResultCallbacks.clear();
+  }
+  return false;
+}
+
+bool OnClearHistory()
+{
+  DisconnectFromGlobalSignal( &OnClearHistory );
+
+  if( gInstance && gInstance->mCurrentPlusOnePos ) {
+    std::string url = gInstance->mHistory[ gInstance->mCurrentPlusOnePos - 1 ];
+    std::vector< std::string >().swap( gInstance->mHistory );
+    gInstance->mHistory.push_back( url );
+    gInstance->mCurrentPlusOnePos = 1;
+  }
+  return false;
+}
+} // namespace
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+// Dali::WebEngine Implementation
+WebEngine::WebEngine()
+{
+}
+
+WebEngine::WebEngine( Internal::Adaptor::WebEngine* internal )
+: BaseHandle( internal )
+{
+}
+
+WebEngine::~WebEngine()
+{
+}
+
+WebEngine WebEngine::New()
+{
+  Internal::Adaptor::WebEngine* baseObject = new Internal::Adaptor::WebEngine();
+
+  return WebEngine( baseObject );
+}
+
+WebEngine::WebEngine( const WebEngine& WebEngine )
+: BaseHandle( WebEngine )
+{
+}
+
+WebEngine& WebEngine::operator=( const WebEngine& webEngine )
+{
+  BaseHandle::operator=( webEngine );
+  return *this;
+}
+
+WebEngine WebEngine::DownCast( BaseHandle handle )
+{
+  return WebEngine( dynamic_cast< Internal::Adaptor::WebEngine* >( handle.GetObjectPtr() ) );
+}
+
+void WebEngine::Create( int width, int height, const std::string& locale, const std::string& timezoneId )
+{
+}
+
+void WebEngine::Destroy()
+{
+}
+
+void WebEngine::LoadUrl( const std::string& url )
+{
+  return Internal::Adaptor::GetImplementation( *this ).LoadUrl( url );
+}
+
+const std::string& WebEngine::GetUrl()
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetUrl();
+}
+
+NativeImageInterfacePtr WebEngine::GetNativeImageSource()
+{
+  Any source;
+  Dali::NativeImageSourcePtr sourcePtr = Dali::NativeImageSource::New( source );
+  return sourcePtr;
+}
+
+void WebEngine::LoadHTMLString( const std::string& htmlString )
+{
+}
+
+void WebEngine::Reload()
+{
+}
+
+void WebEngine::StopLoading()
+{
+}
+
+void WebEngine::Suspend()
+{
+}
+
+void WebEngine::Resume()
+{
+}
+
+bool WebEngine::CanGoForward()
+{
+  return Internal::Adaptor::GetImplementation( *this ).CanGoForward();
+}
+
+void WebEngine::GoForward()
+{
+  Internal::Adaptor::GetImplementation( *this ).GoForward();
+}
+
+bool WebEngine::CanGoBack()
+{
+  return Internal::Adaptor::GetImplementation( *this ).CanGoBack();
+}
+
+void WebEngine::GoBack()
+{
+  Internal::Adaptor::GetImplementation( *this ).GoBack();
+}
+
+void WebEngine::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+{
+  Internal::Adaptor::GetImplementation( *this ).EvaluateJavaScript( script, resultHandler );
+}
+
+void WebEngine::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void(const std::string&) > handler )
+{
+}
+
+void WebEngine::ClearHistory()
+{
+  Internal::Adaptor::GetImplementation( *this ).ClearHistory();
+}
+
+void WebEngine::ClearCache()
+{
+}
+
+void WebEngine::ClearCookies()
+{
+}
+
+Dali::WebEnginePlugin::CacheModel WebEngine::GetCacheModel() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetCacheModel();
+}
+
+void WebEngine::SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetCacheModel( cacheModel );
+}
+
+Dali::WebEnginePlugin::CookieAcceptPolicy WebEngine::GetCookieAcceptPolicy() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetCookieAcceptPolicy();
+}
+
+void WebEngine::SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetCookieAcceptPolicy( policy );
+}
+
+const std::string& WebEngine::GetUserAgent() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetUserAgent();
+}
+
+void WebEngine::SetUserAgent( const std::string& userAgent )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetUserAgent( userAgent );
+}
+
+bool WebEngine::IsJavaScriptEnabled() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).IsJavaScriptEnabled();
+}
+
+void WebEngine::EnableJavaScript( bool enabled )
+{
+  Internal::Adaptor::GetImplementation( *this ).EnableJavaScript( enabled );
+}
+
+bool WebEngine::AreImagesAutomaticallyLoaded() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).AreImagesAutomaticallyLoaded();
+}
+
+void WebEngine::LoadImagesAutomatically( bool automatic )
+{
+  Internal::Adaptor::GetImplementation( *this ).LoadImagesAutomatically( automatic );
+}
+
+const std::string& WebEngine::GetDefaultTextEncodingName() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetDefaultTextEncodingName();
+}
+
+void WebEngine::SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetDefaultTextEncodingName( defaultTextEncodingName );
+}
+
+int WebEngine::GetDefaultFontSize() const
+{
+  return Internal::Adaptor::GetImplementation( *this ).GetDefaultFontSize();
+}
+
+void WebEngine::SetDefaultFontSize( int defaultFontSize )
+{
+  Internal::Adaptor::GetImplementation( *this ).SetDefaultFontSize( defaultFontSize );
+}
+
+void WebEngine::SetSize( int width, int height )
+{
+}
+
+bool WebEngine::SendTouchEvent( const TouchData& touch )
+{
+  return true;
+}
+
+bool WebEngine::SendKeyEvent( const KeyEvent& event )
+{
+  return true;
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadStartedSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).PageLoadStartedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadFinishedSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).PageLoadFinishedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& WebEngine::PageLoadErrorSignal()
+{
+  return Internal::Adaptor::GetImplementation( *this ).PageLoadErrorSignal();
+}
+
+} // namespace Dali;
+
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h
new file mode 100644 (file)
index 0000000..25e0a16
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef TOOLKIT_WINDOW_IMPL_H
+#define TOOLKIT_WINDOW_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/integration-api/adaptor-framework/scene-holder.h>
+
+// INTERNAL INCLUDES
+#include <toolkit-window.h>
+#include <toolkit-scene-holder-impl.h>
+
+namespace Dali
+{
+
+typedef Dali::Rect<int> PositionSize;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Window : public SceneHolder
+{
+public:
+  Window( const PositionSize& positionSize );
+  virtual ~Window() = default;
+  static Window* New(const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent);
+  FocusChangeSignalType mFocusChangeSignal;
+  DevelWindow::VisibilityChangedSignalType mVisibilityChangedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif // TOOLKIT_WINDOW_IMPL_H
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp
new file mode 100644 (file)
index 0000000..d7878e3
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2020 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 "toolkit-window-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/base-object.h>
+
+#define DALI_WINDOW_H
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <toolkit-adaptor-impl.h>
+
+using AdaptorImpl = Dali::Internal::Adaptor::Adaptor;
+
+namespace Dali
+{
+
+class Window;
+
+/********************************************************************************
+ * Stub for Dali::Internal::Adaptor::Window
+ ********************************************************************************/
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+Window::Window( const PositionSize& positionSize )
+: SceneHolder( positionSize ),
+  mFocusChangeSignal(),
+  mVisibilityChangedSignal()
+{
+}
+
+Window* Window::New(const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  return new Window( positionSize );
+}
+
+} // Adaptor
+} // Internal
+
+inline Internal::Adaptor::Window& GetImplementation(Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  BaseObject& object = window.GetBaseObject();
+  return static_cast<Internal::Adaptor::Window&>(object);
+}
+
+inline const Internal::Adaptor::Window& GetImplementation(const Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  const BaseObject& object = window.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Window&>(object);
+}
+
+Window::Window()
+{
+}
+
+Window::~Window()
+{
+}
+
+Window::Window(const Window& handle)
+: BaseHandle( handle )
+{
+}
+
+Window& Window::operator=(const Window& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+Dali::Window Window::New( PositionSize windowPosition, const std::string& name, bool isTransparent )
+{
+  return New( windowPosition, name, "", isTransparent );
+}
+
+Dali::Window Window::New(PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent )
+{
+  Internal::Adaptor::Window* window = Internal::Adaptor::Window::New( windowPosition, name, className, isTransparent );
+
+  Dali::Window result( window );
+
+  // This will also emit the window created signals
+  AdaptorImpl::GetImpl( AdaptorImpl::Get() ).AddWindow( window );
+
+  return result;
+}
+
+Window::Window( Internal::Adaptor::Window* window )
+: BaseHandle( window )
+{
+}
+
+Integration::Scene Window::GetScene()
+{
+  return GetImplementation( *this ).GetScene();
+}
+
+Dali::RenderSurfaceInterface& Window::GetRenderSurface()
+{
+  return GetImplementation( *this ).GetRenderSurface();
+}
+
+void Window::Add( Actor actor )
+{
+  GetImplementation( *this ).Add( actor );
+}
+
+void Window::Remove( Actor actor )
+{
+  GetImplementation( *this ).Remove( actor );
+}
+
+Dali::Layer Window::GetRootLayer() const
+{
+  return GetImplementation( *this ).GetRootLayer();
+}
+
+void Window::SetBackgroundColor( const Vector4& color )
+{
+  GetImplementation( *this ).SetBackgroundColor( color );
+}
+
+Vector4 Window::GetBackgroundColor() const
+{
+  return GetImplementation( *this ).GetBackgroundColor();
+}
+
+void Window::Raise()
+{
+  GetImplementation( *this ).mFocusChangeSignal.Emit(*this, true);
+}
+
+void Window::Hide()
+{
+  GetImplementation( *this ).mVisibilityChangedSignal.Emit( *this, false );
+}
+
+FocusChangeSignalType& Window::FocusChangeSignal()
+{
+  return GetImplementation( *this ).mFocusChangeSignal;
+}
+
+namespace DevelWindow
+{
+
+Window Get( Actor actor )
+{
+  Internal::Adaptor::Window* windowImpl = nullptr;
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    windowImpl = static_cast<Internal::Adaptor::Window*>( AdaptorImpl::GetImpl( AdaptorImpl::Get() ).GetWindow( actor ) );
+  }
+
+  return Dali::Window( windowImpl );
+}
+
+Window DownCast( BaseHandle handle )
+{
+  Internal::Adaptor::Window* windowImpl = nullptr;
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    windowImpl = dynamic_cast<Dali::Internal::Adaptor::Window*>( handle.GetObjectPtr());
+  }
+  return Dali::Window( windowImpl );
+}
+
+EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window )
+{
+  return GetImplementation( window ).GetScene().EventProcessingFinishedSignal();
+}
+
+KeyEventSignalType& KeyEventSignal( Window window )
+{
+  return GetImplementation( window ).KeyEventSignal();
+}
+
+KeyEventGeneratedSignalType& KeyEventGeneratedSignal( Window window )
+{
+  return GetImplementation( window ).KeyEventGeneratedSignal();
+}
+
+TouchSignalType& TouchSignal( Window window )
+{
+  return GetImplementation( window ).TouchSignal();
+}
+
+WheelEventSignalType& WheelEventSignal( Window window )
+{
+  return GetImplementation( window ).WheelEventSignal();
+}
+
+VisibilityChangedSignalType& VisibilityChangedSignal( Window window )
+{
+  return GetImplementation( window ).mVisibilityChangedSignal;
+}
+
+} // namespace DevelWindow
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h
new file mode 100644 (file)
index 0000000..68ed472
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef TOOLKIT_WINDOW_H
+#define TOOLKIT_WINDOW_H
+
+/*
+ * Copyright (c) 2020 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/public-api/math/rect.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/integration-api/scene.h>
+
+namespace Dali
+{
+
+class Actor;
+class Layer;
+class RenderSurfaceInterface;
+struct KeyEvent;
+class TouchData;
+struct WheelEvent;
+
+typedef Dali::Rect<int> PositionSize;
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Window;
+}
+}
+
+class Window;
+typedef Signal< void (Window,bool) > FocusChangeSignalType;
+
+class Window : public BaseHandle
+{
+public:
+
+  static Window New(PositionSize windowPosition, const std::string& name, bool isTransparent = false);
+  static Window New(PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  Window();
+  ~Window();
+  Window(const Window& handle);
+  Window& operator=(const Window& rhs);
+
+  Integration::Scene GetScene();
+  Dali::RenderSurfaceInterface& GetRenderSurface();
+  void Add( Dali::Actor actor );
+  void Remove( Dali::Actor actor );
+  Dali::Layer GetRootLayer() const;
+  void SetBackgroundColor( const Vector4& color );
+  Vector4 GetBackgroundColor() const;
+  void Raise();
+  void Hide();
+  FocusChangeSignalType& FocusChangeSignal();
+
+public:
+  explicit Window( Internal::Adaptor::Window* window );
+};
+
+Internal::Adaptor::Window& GetImplementation(Dali::Window& window);
+const Internal::Adaptor::Window& GetImplementation(const Dali::Window& window);
+
+namespace DevelWindow
+{
+typedef Signal< void () > EventProcessingFinishedSignalType;
+typedef Signal< void (const KeyEvent&) > KeyEventSignalType;
+typedef Signal< bool (const KeyEvent&) > KeyEventGeneratedSignalType;
+typedef Signal< void (const TouchData&) > TouchSignalType;
+typedef Signal< void (const WheelEvent&) > WheelEventSignalType;
+typedef Signal< void ( Window, bool ) > VisibilityChangedSignalType;
+
+Dali::Window Get( Actor actor );
+Dali::Window DownCast(  BaseHandle handle );
+
+EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window );
+KeyEventSignalType& KeyEventSignal( Dali::Window window );
+KeyEventGeneratedSignalType& KeyEventGeneratedSignal( Dali::Window window );
+TouchSignalType& TouchSignal( Dali::Window window );
+WheelEventSignalType& WheelEventSignal( Window window );
+VisibilityChangedSignalType& VisibilityChangedSignal( Window window );
+}
+
+} // namespace Dali
+
+#endif // TOOLKIT_WINDOW_H
diff --git a/automated-tests/src/dali-toolkit/tct-dali-toolkit-core.cpp b/automated-tests/src/dali-toolkit/tct-dali-toolkit-core.cpp
new file mode 100644 (file)
index 0000000..5e64bd3
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-toolkit-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        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/utc-Dali-AccessibilityManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AccessibilityManager.cpp
new file mode 100644 (file)
index 0000000..dbbbd84
--- /dev/null
@@ -0,0 +1,2374 @@
+/*
+ * Copyright (c) 2019 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/dali-toolkit.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-accessibility-adaptor.h>
+#include <dummy-control.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+
+void utc_dali_toolkit_accessibility_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_accessibility_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+namespace
+{
+
+// Functors to test whether focus changed signal is emitted when the focus is changed
+class FocusChangedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusChangedCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mOriginalFocusedActor(),
+    mCurrentFocusedActor()
+  {
+  }
+
+  void Callback(Actor originalFocusedActor, Actor currentFocusedActor)
+  {
+    tet_infoline("Verifying FocusChangedCallback()");
+
+    if(originalFocusedActor == mCurrentFocusedActor)
+    {
+      mSignalVerified = true;
+    }
+
+    mOriginalFocusedActor = originalFocusedActor;
+    mCurrentFocusedActor = currentFocusedActor;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mOriginalFocusedActor;
+  Actor mCurrentFocusedActor;
+};
+
+// Functors to test whether focus overshot signal is emitted when there is no way to move focus further.
+class FocusOvershotCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusOvershotCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mCurrentFocusedActor(),
+    mFocusOvershotDirection(Toolkit::AccessibilityManager::OVERSHOT_NEXT)
+  {
+  }
+
+  void Callback(Actor currentFocusedActor, Toolkit::AccessibilityManager::FocusOvershotDirection direction)
+  {
+    tet_infoline("Verifying FocusOvershotCallback()");
+
+    if(currentFocusedActor == mCurrentFocusedActor && direction == mFocusOvershotDirection)
+    {
+      mSignalVerified = true;
+    }
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mCurrentFocusedActor;
+  Toolkit::AccessibilityManager::FocusOvershotDirection mFocusOvershotDirection;
+};
+
+// Functor to test whether focused actor activated signal is emitted.
+class FocusedActorActivatedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusedActorActivatedCallback()
+  {
+  }
+
+  void Callback(Actor activatedActor)
+  {
+    tet_infoline("Verifying FocusedActorActivatedCallback()");
+  }
+};
+
+} // namespace
+
+
+int UtcDaliAccessibilityManagerGet(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerGet");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  AccessibilityManager newManager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(newManager);
+
+  // Check that accessibility manager is a singleton
+  DALI_TEST_CHECK(manager == newManager);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSetAndGetAccessibilityAttribute(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSetAndGetAccessibilityAttribute");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == "");
+
+  manager.SetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL, "Description");
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == "Description");
+
+  manager.SetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL, "New description");
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == "New description");
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSetAndGetFocusOrder(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusOrder");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Actor first = Actor::New();
+  Actor second = Actor::New();
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0);
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 0);
+
+  // Set the focus order and description for the first actor
+  manager.SetFocusOrder(first, 1);
+  manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(second, 2);
+  manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second");
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // check that the focus order of the first actor is changed
+  manager.SetFocusOrder(first, 2);
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 2);
+  // make sure the change of focus order doesn't affect the actor's description
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // check that the focus order of the second actor is increased to 3
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 3);
+  // make sure the change of focus order doesn't affect the actor's description
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // check that the focus order of the second actor is changed to 1
+  manager.SetFocusOrder(second, 1);
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 1);
+  // make sure the change of focus order doesn't affect the actor's description
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Set the focus order and description for the third actor
+  Actor third = Actor::New();
+  manager.SetFocusOrder(third, 1);
+  manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third");
+  DALI_TEST_CHECK(manager.GetFocusOrder(third) == 1);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // check that the focus order of the second actor is increased to 2.
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  // make sure the change of focus order doesn't affect the actor's description
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // check that the focus order of the first actor is increased to 3.
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 3);
+  // make sure the change of focus order doesn't affect the actor's description
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerGenerateNewFocusOrder(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerGenerateNewFocusOrder");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DALI_TEST_CHECK(1 == manager.GenerateNewFocusOrder());
+  DALI_TEST_CHECK(1 == manager.GenerateNewFocusOrder());
+
+  Actor first = Actor::New();
+  Actor second = Actor::New();
+
+  // Set the focus order for the first actor
+  manager.SetFocusOrder(first, 1);
+  manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1);
+
+  //Test for new focus order
+  DALI_TEST_CHECK(2 == manager.GenerateNewFocusOrder());
+
+  // Set the focus order for the first actor
+  manager.SetFocusOrder(second, 2);
+  manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerGetActorByFocusOrder(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerGetActorByFocusOrder");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the actors and set their focus orders
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+
+  Actor third = Actor::New();
+  manager.SetFocusOrder(third, 3);
+
+  // Check that we get an empty handle as no actor is added to the stage yet.
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == Actor());
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == Actor());
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == Actor());
+
+  // Add the actors to the stage
+  Stage::GetCurrent().Add(first);
+  Stage::GetCurrent().Add(second);
+  Stage::GetCurrent().Add(third);
+
+  // Check that we get an empty handle because focus order 0 means undefined.
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(0) == Actor());
+
+  // Check that we get correct actors for the specified focus orders
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == first);
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == second);
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == third);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Change the focus order of the third actor to 1
+  manager.SetFocusOrder(third, 1);
+
+  // Check that we still get correct actors after changing their focus orders
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == third);
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == first);
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == second);
+
+  // Check that we get an empty handle because no actor has a focus order of 4
+  DALI_TEST_CHECK(manager.GetActorByFocusOrder(4) == Actor());
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSetAndGetCurrentFocusActor(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSetAndGetCurrentFocusActor");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+  Stage::GetCurrent().Add(second);
+
+  // Create the third actor but don't add it to the stage
+  Actor third = Actor::New();
+  manager.SetFocusOrder(third, 3);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that it will fail to set focus on an invalid actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(Actor()) == false);
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Check that it will fail to set focus on the third actor as it's not in the stage
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false);
+
+  // Add the third actor to the stage
+  Stage::GetCurrent().Add(third);
+
+  // make the third actor invisible
+  third.SetVisible(false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Check that it will fail to set focus on the third actor as it's invisible
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false);
+
+  // Make the third actor visible
+  third.SetVisible(true);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Make the third actor not focusable
+  Property::Index propertyActorFocusable = third.GetPropertyIndex("focusable");
+  third.SetProperty(propertyActorFocusable, false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Check that it will fail to set focus on the third actor as it's not focusable
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false);
+
+  // Make the third actor focusable
+  third.SetProperty(propertyActorFocusable, true);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Check that the focus is successfully moved to the third actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true);
+
+  // Make the current focused actor to be not focusable by setting its focus order to be 0
+  manager.SetFocusOrder(third, 0);
+
+  // Check that the focus is automatically cleared
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Set the focus order of the third actor again
+  manager.SetFocusOrder(third, 3);
+
+  // Check that the third actor can be focused successfully now
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerGetCurrentFocusGroup(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerGetCurrentFocusGroup");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Create an actor with two child actors and add it to the stage
+  Actor parent = Actor::New();
+  Actor firstChild = Actor::New();
+  Actor secondChild = Actor::New();
+  parent.Add(firstChild);
+  parent.Add(secondChild);
+  Stage::GetCurrent().Add(parent);
+
+  // Create three actors and add them as the children of the first child actor
+  Actor firstGrandChild = Actor::New();
+  Actor secondGrandChild = Actor::New();
+  Actor thirdGrandChild = Actor::New();
+  firstChild.Add(firstGrandChild);
+  firstChild.Add(secondGrandChild);
+  firstChild.Add(thirdGrandChild);
+
+  // Set focus order to the actors
+  manager.SetFocusOrder(parent, 1);
+  manager.SetFocusOrder(firstChild, 2);
+  manager.SetFocusOrder(firstGrandChild, 3);
+  manager.SetFocusOrder(secondGrandChild, 4);
+  manager.SetFocusOrder(thirdGrandChild, 5);
+  manager.SetFocusOrder(secondChild, 6);
+
+  // Set the parent and the first child actor as focus groups
+  manager.SetFocusGroup(parent, true);
+  DALI_TEST_CHECK(manager.IsFocusGroup(parent) == true);
+
+  // Set focus to the first grand child actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(firstGrandChild) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild);
+
+  // The current focus group should be the parent, As it is the immediate parent which is also a focus group.
+  DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == parent);
+
+  manager.SetFocusGroup(firstChild, true);
+  DALI_TEST_CHECK(manager.IsFocusGroup(firstChild) == true);
+
+  // The current focus group should be the firstChild, As it is the immediate parent which is also a focus group.
+  DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstChild);
+
+  manager.SetFocusGroup(firstGrandChild, true);
+  DALI_TEST_CHECK(manager.IsFocusGroup(firstGrandChild) == true);
+
+  // The current focus group should be itself, As it is also a focus group.
+  DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstGrandChild);
+
+  // Set focus to the second grand child actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(secondGrandChild) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild);
+
+  // The current focus group should be the firstChild, As it is the immediate parent which is also a
+  // focus group for the current focus actor.
+  DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstChild);
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerGetCurrentFocusOrder(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerGetCurrentFocusOrder");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  Actor first = Actor::New();
+  Stage::GetCurrent().Add(first);
+
+  Actor second = Actor::New();
+  Stage::GetCurrent().Add(second);
+
+  Actor third = Actor::New();
+  Stage::GetCurrent().Add(third);
+
+  // Set the focus order and description for the first actor
+  manager.SetFocusOrder(first, 1);
+  manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(second, 2);
+  manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second");
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(third, 3);
+  manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third");
+  DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 0);
+
+  // Set the focus on the first actor and test
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 1);
+
+  // Move the focus forward to the second actor and test
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 2);
+
+  // Move the focus forward to the third actor and test
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 3);
+
+  // Clear focus and test
+  manager.ClearFocus();
+  DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 0);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerMoveFocusForward(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerMoveFocusForward");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+  accAdaptor.HandleActionNextEvent(true);
+
+  Actor first = Actor::New();
+  Stage::GetCurrent().Add(first);
+
+  Actor second = Actor::New();
+  Stage::GetCurrent().Add(second);
+
+  Actor third = Actor::New();
+  Stage::GetCurrent().Add(third);
+
+  // Set the focus order and description for the first actor
+  manager.SetFocusOrder(first, 1);
+  manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(second, 2);
+  manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second");
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(third, 3);
+  manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third");
+  DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Set the focus on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Test the non-wrapped move first
+  manager.SetWrapMode(false);
+  DALI_TEST_CHECK(manager.GetWrapMode() == false);
+
+  // Move the focus forward to the second actor
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // Move the focus forward to the third actor
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Check that it will fail to move the focus forward again as the third actor is the last
+  // focusable actor in the focus chain
+  manager.MoveFocusForward();
+  // The focus should still be set on the third actor
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Now test the wrapped move
+  manager.SetWrapMode(true);
+  DALI_TEST_CHECK(manager.GetWrapMode() == true);
+
+  // Move the focus forward recursively and this time the first actor should be focused
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Make the second actor not focusable
+  Property::Index propertyActorFocusable = second.GetPropertyIndex("focusable");
+  second.SetProperty(propertyActorFocusable, false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Move the focus forward and check that the second actor should be skipped and
+  // the third actor should be focused now.
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Make the first actor invisible
+  first.SetVisible(false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Move the focus forward and check that the first actor should be skipped as it's
+  // invisible and the second actor should also be skipped as it's not focusable,
+  // so the focus will still be on the third actor
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Make the third actor invisible so that no actor can be focused.
+  third.SetVisible(false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Check that the focus move is failed as all the three actors can not be focused
+  manager.MoveFocusForward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerMoveFocusBackward(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerMoveFocusBackward");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  Actor first = Actor::New();
+  Stage::GetCurrent().Add(first);
+
+  Actor second = Actor::New();
+  Stage::GetCurrent().Add(second);
+
+  Actor third = Actor::New();
+  Stage::GetCurrent().Add(third);
+
+  // Set the focus order and description for the first actor
+  manager.SetFocusOrder(first, 1);
+  manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first");
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(second, 2);
+  manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second");
+  DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // Set the focus order and description for the second actor
+  manager.SetFocusOrder(third, 3);
+  manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third");
+  DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Set the focus on the third actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Test the non-wrapped move first
+  manager.SetWrapMode(false);
+  DALI_TEST_CHECK(manager.GetWrapMode() == false);
+
+  // Move the focus backward to the second actor
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "second");
+
+  // Move the focus backward to the first actor
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Check that it will fail to move the focus backward again as the first actor is the first
+  // focusable actor in the focus chain
+  manager.MoveFocusBackward();
+  // The focus should still be set on the first actor
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Now test the wrapped move
+  manager.SetWrapMode(true);
+  DALI_TEST_CHECK(manager.GetWrapMode() == true);
+
+  // Move the focus backward recursively and this time the third actor should be focused
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third");
+
+  // Make the second actor not focusable
+  Property::Index propertyActorFocusable = second.GetPropertyIndex("focusable");
+  second.SetProperty(propertyActorFocusable, false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Move the focus backward and check that the second actor should be skipped and
+  // the first actor should be focused now.
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Make the third actor invisible
+  third.SetVisible(false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Move the focus backward and check that the third actor should be skipped as it's
+  // invisible and the second actor should also be skipped as it's not focusable,
+  // so the focus will still be on the first actor
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+
+  // Make the first actor invisible so that no actor can be focused.
+  first.SetVisible(false);
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  // Check that the focus move is failed as all the three actors can not be focused
+  manager.MoveFocusBackward();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first");
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerClearFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerClearFocus");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+  Stage::GetCurrent().Add(second);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Clear the focus
+  manager.ClearFocus();
+
+  // Check that no actor is being focused now.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerReset(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerReset");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+  Stage::GetCurrent().Add(second);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Clear the focus
+  manager.Reset();
+
+  // Check that no actor is being focused now and the focus order of actors have been cleared
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0);
+  DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerFocusGroup(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerFocusGroup");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  // Create an actor with two child actors and add it to the stage
+  Actor parent = Actor::New();
+  Actor firstChild = Actor::New();
+  Actor secondChild = Actor::New();
+  parent.Add(firstChild);
+  parent.Add(secondChild);
+  Stage::GetCurrent().Add(parent);
+
+  // Create three actors and add them as the children of the first child actor
+  Actor firstGrandChild = Actor::New();
+  Actor secondGrandChild = Actor::New();
+  Actor thirdGrandChild = Actor::New();
+  firstChild.Add(firstGrandChild);
+  firstChild.Add(secondGrandChild);
+  firstChild.Add(thirdGrandChild);
+
+  // Set focus order to the actors
+  manager.SetFocusOrder(parent, 1);
+  manager.SetFocusOrder(firstChild, 2);
+  manager.SetFocusOrder(firstGrandChild, 3);
+  manager.SetFocusOrder(secondGrandChild, 4);
+  manager.SetFocusOrder(thirdGrandChild, 5);
+  manager.SetFocusOrder(secondChild, 6);
+
+  // Set the parent and the first child actor as focus groups
+  manager.SetFocusGroup(parent, true);
+  DALI_TEST_CHECK(manager.IsFocusGroup(parent) == true);
+
+  // The focus group of the parent should be itself, as it is set to be a focus group.
+  DALI_TEST_CHECK(manager.GetFocusGroup(parent) == parent);
+
+  // The focus group of the firstChild should be its parent, as it is the immediate parent which is also a group.
+  DALI_TEST_CHECK(manager.GetFocusGroup(firstChild) == parent);
+
+  manager.SetFocusGroup(firstChild, true);
+  DALI_TEST_CHECK(manager.IsFocusGroup(firstChild) == true);
+
+  // The focus group of the firstChild should be itself, as it is set to be a focus group now.
+  DALI_TEST_CHECK(manager.GetFocusGroup(firstChild) == firstChild);
+
+  // Enable wrap mode for focus movement.
+  manager.SetWrapMode(true);
+  DALI_TEST_CHECK(manager.GetWrapMode() == true);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that the focus is set on the parent actor.
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(parent) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == parent);
+
+  // Check that group mode is disabled.
+  DALI_TEST_CHECK(manager.GetGroupMode() == false);
+
+  // Check that the focus movement is wrapped as normal.
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == thirdGrandChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == parent);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild);
+
+  // Enable the group mode.
+  manager.SetGroupMode(true);
+  DALI_TEST_CHECK(manager.GetGroupMode() == true);
+
+  // Check that the focus movement is now limited to the current focus group.
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == thirdGrandChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild);
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSetAndGetFocusIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusIndicator");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Actor defaultFocusIndicatorActor = manager.GetFocusIndicatorActor();
+  DALI_TEST_CHECK(defaultFocusIndicatorActor);
+
+  Actor newFocusIndicatorActor = Actor::New();
+  manager.SetFocusIndicatorActor(newFocusIndicatorActor);
+  DALI_TEST_CHECK(manager.GetFocusIndicatorActor() == newFocusIndicatorActor);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSetAndGetFocusIndicatorWithFocusedActor(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusIndicatorWithFocusedActor");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  Actor defaultFocusIndicatorActor = manager.GetFocusIndicatorActor();
+  DALI_TEST_CHECK(defaultFocusIndicatorActor);
+
+  Actor focusedActor = Actor::New();
+  Stage::GetCurrent().Add( focusedActor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( focusedActor.GetChildCount(), 0u, TEST_LOCATION );
+
+  manager.SetFocusOrder( focusedActor, 1 );
+  manager.SetCurrentFocusActor( focusedActor );
+
+  DALI_TEST_EQUALS( focusedActor.GetChildCount(), 1u, TEST_LOCATION );
+  DALI_TEST_CHECK( focusedActor.GetChildAt(0) == defaultFocusIndicatorActor );
+
+  Actor newFocusIndicatorActor = Actor::New();
+  manager.SetFocusIndicatorActor( newFocusIndicatorActor );
+  DALI_TEST_CHECK(manager.GetFocusIndicatorActor() == newFocusIndicatorActor);
+  DALI_TEST_EQUALS( focusedActor.GetChildCount(), 1u, TEST_LOCATION );
+  DALI_TEST_CHECK( focusedActor.GetChildAt(0) == newFocusIndicatorActor );
+
+  // Disable Accessibility
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, false );
+  accAdaptor.HandleActionEnableEvent();
+
+  DALI_TEST_EQUALS( focusedActor.GetChildCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSignalFocusChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSignalFocusChanged");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool signalVerified = false;
+  FocusChangedCallback callback(signalVerified);
+  manager.FocusChangedSignal().Connect( &callback, &FocusChangedCallback::Callback );
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+  Stage::GetCurrent().Add(second);
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  // Clear the focus
+  manager.ClearFocus();
+
+  // Check that no actor is being focused now.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSignalFocusOvershot(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSignalFocusOvershot");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  bool signalVerified = false;
+  FocusOvershotCallback callback(signalVerified);
+  manager.FocusOvershotSignal().Connect(&callback, &FocusOvershotCallback::Callback);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  manager.SetFocusOrder(first, 1);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  manager.SetFocusOrder(second, 2);
+  Stage::GetCurrent().Add(second);
+
+  // Check that the wrap mode is disabled
+  DALI_TEST_CHECK(manager.GetWrapMode() == false);
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is moved to the second actor successfully.
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Check that the forward focus movement is overshot.
+  callback.mCurrentFocusedActor = second;
+  callback.mFocusOvershotDirection = Toolkit::AccessibilityManager::OVERSHOT_NEXT;
+  DALI_TEST_CHECK(manager.MoveFocusForward() == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(signalVerified);
+  callback.Reset();
+
+  // Enable the wrap mode
+  manager.SetWrapMode(true);
+  DALI_TEST_CHECK(manager.GetWrapMode() == true);
+
+  // Check that the forward focus movement is wrapped and no overshot happens.
+  DALI_TEST_CHECK(manager.MoveFocusForward() == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(signalVerified == false);
+
+  // Disable the wrap mode
+  manager.SetWrapMode(false);
+  DALI_TEST_CHECK(manager.GetWrapMode() == false);
+
+  // Check that the backward focus movement is overshot.
+  callback.mCurrentFocusedActor = first;
+  callback.mFocusOvershotDirection = Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS;
+  DALI_TEST_CHECK(manager.MoveFocusBackward() == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(signalVerified);
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerSignalFocusedActorActivated(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliAccessibilityManagerSignalFocusedActorActivated");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  FocusedActorActivatedCallback callback;
+  manager.FocusedActorActivatedSignal().Connect(&callback, &FocusedActorActivatedCallback::Callback);
+  DALI_TEST_CHECK(true);
+
+  END_TEST;
+}
+
+// Note: No negative test for GetReadPosition as it will always return something.
+int UtcDaliAccessibilityManagerGetReadPositionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliAccessibilityManagerGetReadPositionP");
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  Vector2 readPosition( manager.GetReadPosition() );
+  DALI_TEST_EQUALS( readPosition.x, 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+  DALI_TEST_EQUALS( readPosition.y, 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Functor to test if an accessibility signal has been called.
+class AccessibilityManagerSignalHandler : public Dali::ConnectionTracker
+{
+public:
+  AccessibilityManagerSignalHandler() :
+    mCalls( 0 )
+  {
+  }
+
+  bool Callback( AccessibilityManager& accessibilityManager )
+  {
+    mCalls++;
+    tet_infoline( "Signal called" );
+    return true;
+  }
+
+  unsigned int GetCalls() const
+  {
+    return mCalls;
+  }
+
+private:
+  unsigned int mCalls;  ///< Keeps track of how many times the signal has been called.
+};
+
+int UtcDaliAccessibilityManagerStatusChangedSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerStatusChangedSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.StatusChangedSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  // Cause a state change.
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionEnableEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerStatusChangedSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerStatusChangedSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.StatusChangedSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionNextSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionNextSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionNextEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionNextSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionNextSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPreviousSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPreviousSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionPreviousEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPreviousSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPreviousSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionActivateSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionActivateSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New();
+  button.SetSize(480, 800);
+  Stage::GetCurrent().Add(button);
+  manager.SetFocusOrder( button, 1 );
+  manager.SetCurrentFocusActor( button );
+
+  manager.ActionActivateSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionActivateEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionActivateSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionActivateSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionActivateSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadEvent( 100.0f, 200.0f, true );
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionOverSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionOverSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionOverSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  // Note that the ActionOverSignal is provoked by a read even when "allow read again" is set to false.
+  accessibilityAdaptor.HandleActionReadEvent( 100.0f, 200.0f, false );
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionOverSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionOverSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionOverSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadNextSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadNextSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadNextEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadNextSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadNextSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadPreviousSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadPreviousSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadPreviousEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadPreviousSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadPreviousSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionUpSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionUpSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accessibilityAdaptor, true );
+  accessibilityAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  dummyControl.SetSize(480, 800);
+  manager.SetFocusOrder( dummyControl, 1 );
+  Stage::GetCurrent().Add( dummyControl );
+  manager.SetCurrentFocusActor( dummyControl );
+
+  accessibilityAdaptor.HandleActionUpEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionUpSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionUpSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionDownSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionDownSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accessibilityAdaptor, true );
+  accessibilityAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New();
+  button.SetSize(480, 800);
+  Stage::GetCurrent().Add(button);
+  manager.SetFocusOrder( button, 1 );
+  manager.SetCurrentFocusActor( button );
+
+  accessibilityAdaptor.HandleActionDownEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionDownSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionDownSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionClearFocusSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionClearFocusSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionClearFocusSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionClearFocusEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionClearFocusSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionClearFocusSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionClearFocusSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionBackSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionBackSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionBackSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionBackEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionBackSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionBackSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionBackSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionScrollUpSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollUpSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionScrollUpEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionScrollUpSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollUpSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionScrollDownSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollDownSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionScrollDownEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionScrollDownSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollDownSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageLeftSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageLeftSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageLeftSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionPageLeftEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageLeftSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageLeftSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageLeftSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageRightSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageRightSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageRightSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionPageRightEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageRightSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageRightSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageRightSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageUpSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageUpSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionPageUpEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageUpSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageUpSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageDownSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageDownSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionPageDownEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionPageDownSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionPageDownSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionPageDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionMoveToFirstSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionMoveToFirstSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionMoveToFirstSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionMoveToFirstEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAccessibilityManagerActionMoveToFirstSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionMoveToFirstSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionMoveToFirstSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionMoveToLastSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionMoveToLastSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionMoveToLastSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionMoveToLastEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionMoveToLastSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionMoveToLastSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionMoveToLastSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadFromTopSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadFromTopSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadFromTopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadFromTopEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadFromTopSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadFromTopSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadFromTopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadFromNextSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadFromNextSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadFromNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadFromNextEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadFromNextSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadFromNextSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadFromNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionZoomSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionZoomSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New();
+  button.SetSize(480, 800);
+  Stage::GetCurrent().Add(button);
+  manager.SetFocusOrder( button, 1 );
+  manager.SetCurrentFocusActor( button );
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  manager.ActionZoomSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionZoomEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionZoomSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionZoomSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionZoomSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadIndicatorInformationSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadIndicatorInformationSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadIndicatorInformationSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadPauseResumeSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadPauseResumeSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get();
+  Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true );
+  accAdaptor.HandleActionEnableEvent();
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadPauseResumeSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionReadPauseResumeEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionReadPauseResumeSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionReadPauseResumeSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionReadPauseResumeSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionStartStopSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionStartStopSignalP" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionStartStopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  accessibilityAdaptor.HandleActionStartStopEvent();
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionStartStopSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionStartStopSignalN" );
+
+  AccessibilityManagerSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionStartStopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback );
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Functor to test if a accessibility scroll signal has been called.
+class AccessibilityManagerScrollSignalHandler : public Dali::ConnectionTracker
+{
+public:
+  AccessibilityManagerScrollSignalHandler() :
+    mCalls( 0 )
+  {
+  }
+
+  bool Callback( AccessibilityManager& accessibilityManager, const Dali::TouchEvent& touchEvent )
+  {
+    mCalls++;
+    mTouchEvent = touchEvent;
+    tet_infoline( "Signal called" );
+    return true;
+  }
+
+  unsigned int GetCalls() const
+  {
+    return mCalls;
+  }
+
+  const Dali::TouchEvent& GetTouchEvent() const
+  {
+    return mTouchEvent;
+  }
+
+private:
+  unsigned int mCalls;         ///< Keeps track of how many times the signal has been called.
+  Dali::TouchEvent mTouchEvent; ///< Stores the last touch event received.
+};
+
+int UtcDaliAccessibilityManagerActionScrollSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollSignalP" );
+
+  AccessibilityManagerScrollSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollSignal().Connect( &callback, &AccessibilityManagerScrollSignalHandler::Callback );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+
+  TouchPoint point( 0, TouchPoint::Started, 100.0f, 200.0f );
+  accessibilityAdaptor.HandleActionScrollEvent( point, 0u );
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION );
+
+  const TouchEvent& signalTouchEvent = callback.GetTouchEvent();
+  DALI_TEST_EQUALS( signalTouchEvent.GetPointCount(), 1u, TEST_LOCATION );
+
+  const TouchPoint& signalTouchPoint = signalTouchEvent.GetPoint( 0u );
+
+  DALI_TEST_EQUALS( signalTouchPoint.state, TouchPoint::Started, TEST_LOCATION );
+  DALI_TEST_EQUALS( signalTouchPoint.screen.x, 100.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( signalTouchPoint.screen.y, 200.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionScrollSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionScrollSignalN" );
+
+  AccessibilityManagerScrollSignalHandler callback;
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  manager.ActionScrollSignal().Connect( &callback, &AccessibilityManagerScrollSignalHandler::Callback );
+
+  DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAccessibilityManagerActionTouch(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerActionTouch" );
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyControl.SetSize(480, 800);
+  manager.SetFocusOrder( dummyControl, 1 );
+  Stage::GetCurrent().Add( dummyControl );
+  manager.SetCurrentFocusActor( dummyControl );
+
+  TouchPoint point( 0, TouchPoint::Started, 100.0f, 200.0f );
+  accessibilityAdaptor.HandleActionTouchEvent( point, 0u );
+
+  DALI_TEST_CHECK( dummyImpl.onAccTouchedCalled );
+
+  END_TEST;
+}
+
+
+int UtcDaliAccessibilityManagerHandlePanGesture(void)
+{
+  // Pan gesture sent from adaptor to manager via AccessibilityGestureHandler
+  // Adaptor.SetGestureHandler is called in Initialize (check it's the toolkit version)
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliAccessibilityManagerHandlePanGesture" );
+
+  AccessibilityManager manager = AccessibilityManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get();
+  DummyControl dummyControl = DummyControl::New(true);
+  dummyControl.SetSize(480, 800);
+  Stage::GetCurrent().Add( dummyControl );
+
+  AccessibilityGestureEvent panGestureEvent(AccessibilityGestureEvent::Started);
+  panGestureEvent.previousPosition = Vector2(0.f, 0.f);
+  panGestureEvent.currentPosition = Vector2(100.f, 0.f);
+  panGestureEvent.timeDelta = 16;
+  panGestureEvent.numberOfTouches = 1;
+
+  Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent );
+
+  panGestureEvent.state = AccessibilityGestureEvent::Continuing;
+  panGestureEvent.previousPosition = Vector2(100.f, 0.f);
+  panGestureEvent.currentPosition = Vector2(200.f, 0.f);
+  Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent );
+
+  panGestureEvent.state = AccessibilityGestureEvent::Finished;
+  panGestureEvent.previousPosition = Vector2(200.f, 0.f);
+  panGestureEvent.currentPosition = Vector2(300.f, 0.f);
+  Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent );
+
+
+  END_TEST;
+}
+
+// Methods missing coverage:
+// IsActorFocusableFunction
+// DoActivate
+// SetFocusable
+// TtsStateChanged
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Alignment.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Alignment.cpp
new file mode 100644 (file)
index 0000000..fc015f1
--- /dev/null
@@ -0,0 +1,1067 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_alignment_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_alignment_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+/// Compare an int (Or'd Alignment::Type) with an Alignment::Type value
+void DALI_TEST_EQUALS( int value1, Alignment::Type value2, const char* location )
+{
+  ::DALI_TEST_EQUALS< Alignment::Type >( static_cast< Alignment::Type >( value1 ), value2, location );
+}
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+} // namespace
+
+
+int UtcDaliAlignmentConstructorNegative(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment;
+
+  try
+  {
+    Alignment::Padding padding;
+    alignment.SetPadding(padding);
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "alignment", TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentConstructorPositive(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+
+  try
+  {
+    Alignment::Padding padding;
+    alignment.SetPadding(padding);
+    tet_result(TET_PASS);
+  }
+  catch (DaliException& exception)
+  {
+    tet_result(TET_FAIL);
+  }
+
+  Actor actor = alignment;
+  alignment = Alignment::DownCast( actor );
+
+  DALI_TEST_CHECK( alignment );
+  END_TEST;
+}
+
+int UtcDaliAlignmentConstructorRegister(void)
+{
+  ToolkitTestApplication application;
+
+  //Te ensure the object is registered after creation
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect(&TestCallback);
+  {
+    Alignment alignment = Alignment::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetAlignmentTypePositiveOffStage(void)
+{
+  ToolkitTestApplication application;
+
+  // Default, HorizontalCenter, VerticalCenter - Ensure they do not change!
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalCenter | Alignment::VerticalCenter));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalLeft, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::HorizontalLeft);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalRight, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::HorizontalRight);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalLeft, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalLeft | Alignment::VerticalTop));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalCenter, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::VerticalTop);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalRight, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalRight | Alignment::VerticalTop));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalLeft, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalLeft | Alignment::VerticalBottom));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalCenter, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::VerticalBottom);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+
+  // HorizontalRight, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalRight | Alignment::VerticalBottom));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetAlignmentTypePositiveOnStage(void)
+{
+  ToolkitTestApplication application;
+
+  // Default, HorizontalCenter, VerticalCenter - Ensure they do not change!
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalCenter | Alignment::VerticalCenter));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::HorizontalLeft);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::HorizontalRight);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalLeft | Alignment::VerticalTop));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalCenter, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::VerticalTop);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalTop
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalRight | Alignment::VerticalTop));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalLeft | Alignment::VerticalBottom));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalCenter, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::VerticalBottom);
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    // Check default values
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalRight | Alignment::VerticalBottom));
+    alignment.SetAlignmentType(type);
+    DALI_TEST_CHECK(alignment.GetAlignmentType() & type);
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetAlignmentTypeNegative(void)
+{
+  ToolkitTestApplication application;
+
+  // Setting HorizontalLeft, HorizontalCenter
+  {
+    Alignment alignment = Alignment::New();
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalLeft | Alignment::HorizontalCenter));
+    alignment.SetAlignmentType(type);
+    // center will prevail in conflict
+    DALI_TEST_CHECK( Alignment::HorizontalCenter & alignment.GetAlignmentType() );
+    DALI_TEST_CHECK( !(Alignment::HorizontalLeft & alignment.GetAlignmentType()) );
+  }
+
+  // Setting HorizontalCenter, HorizontalRight
+  {
+    Alignment alignment = Alignment::New();
+    Alignment::Type type(Alignment::Type(Alignment::HorizontalCenter | Alignment::HorizontalRight));
+
+    alignment.SetAlignmentType(type);
+    // center will prevail in conflict
+    DALI_TEST_CHECK( Alignment::HorizontalCenter & alignment.GetAlignmentType() );
+    DALI_TEST_CHECK( !(Alignment::HorizontalRight & alignment.GetAlignmentType()) );
+  }
+
+  // Setting VerticalTop, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+    Alignment::Type type(Alignment::Type(Alignment::VerticalTop | Alignment::VerticalCenter));
+    alignment.SetAlignmentType(type);
+    // center will prevail in conflict
+    DALI_TEST_CHECK( Alignment::VerticalCenter & alignment.GetAlignmentType() );
+    DALI_TEST_CHECK( !(Alignment::VerticalTop & alignment.GetAlignmentType()) );
+  }
+
+  // Setting VerticalCenter, VerticalBottom
+  {
+    Alignment alignment = Alignment::New();
+    Alignment::Type type(Alignment::Type(Alignment::VerticalTop | Alignment::VerticalBottom));
+    alignment.SetAlignmentType(type);
+    // top will prevail in conflict
+    DALI_TEST_CHECK( Alignment::VerticalTop & alignment.GetAlignmentType() );
+    DALI_TEST_CHECK( !(Alignment::VerticalBottom & alignment.GetAlignmentType()) );
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentGetAlignmentType(void)
+{
+  ToolkitTestApplication application;
+
+  // Default, HorizonalCenter, VerticalCenter
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalCenter
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalLeft);
+    DALI_TEST_EQUALS(Alignment::HorizontalLeft | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalCenter
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalRight);
+    DALI_TEST_EQUALS(Alignment::HorizontalRight | Alignment::VerticalCenter, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalTop
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalLeft, Alignment::VerticalTop);
+    DALI_TEST_EQUALS(Alignment::HorizontalLeft | Alignment::VerticalTop, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalCenter, VerticalTop
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalCenter, Alignment::VerticalTop);
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalTop, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalTop
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalRight, Alignment::VerticalTop);
+    DALI_TEST_EQUALS(Alignment::HorizontalRight | Alignment::VerticalTop, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalLeft, VerticalBottom
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalLeft, Alignment::VerticalBottom);
+    DALI_TEST_EQUALS(Alignment::HorizontalLeft | Alignment::VerticalBottom, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalCenter, VerticalBottom
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalCenter, Alignment::VerticalBottom);
+    DALI_TEST_EQUALS(Alignment::HorizontalCenter | Alignment::VerticalBottom, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // HorizontalRight, VerticalBottom
+  {
+    Alignment alignment = Alignment::New(Alignment::HorizontalRight, Alignment::VerticalBottom);
+    DALI_TEST_EQUALS(Alignment::HorizontalRight | Alignment::VerticalBottom, alignment.GetAlignmentType(), TEST_LOCATION);
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetScaling(void)
+{
+  ToolkitTestApplication application;
+
+  // ScaleToFill
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS(Alignment::ScaleNone, alignment.GetScaling(), TEST_LOCATION);
+    alignment.SetScaling(Alignment::ScaleToFill);
+    DALI_TEST_EQUALS(Alignment::ScaleToFill, alignment.GetScaling(), TEST_LOCATION);
+    application.Render();
+    application.SendNotification();
+
+    // For complete line coverage
+    alignment.SetAlignmentType(Alignment::HorizontalLeft);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::HorizontalRight);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalTop);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalBottom);
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // ScaleToFitKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS(Alignment::ScaleNone, alignment.GetScaling(), TEST_LOCATION);
+    alignment.SetScaling(Alignment::ScaleToFitKeepAspect);
+    DALI_TEST_EQUALS(Alignment::ScaleToFitKeepAspect, alignment.GetScaling(), TEST_LOCATION);
+    application.Render();
+    application.SendNotification();
+
+    // For complete line coverage
+    alignment.SetAlignmentType(Alignment::HorizontalLeft);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::HorizontalRight);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalTop);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalBottom);
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // ScaleToFillKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS(Alignment::ScaleNone, alignment.GetScaling(), TEST_LOCATION);
+    alignment.SetScaling(Alignment::ScaleToFillKeepAspect);
+    DALI_TEST_EQUALS(Alignment::ScaleToFillKeepAspect, alignment.GetScaling(), TEST_LOCATION);
+    application.Render();
+    application.SendNotification();
+
+    // For complete line coverage
+    alignment.SetAlignmentType(Alignment::HorizontalLeft);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::HorizontalRight);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalTop);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalBottom);
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // ShrinkToFit
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS(Alignment::ScaleNone, alignment.GetScaling(), TEST_LOCATION);
+    alignment.SetScaling(Alignment::ShrinkToFit);
+    DALI_TEST_EQUALS(Alignment::ShrinkToFit, alignment.GetScaling(), TEST_LOCATION);
+    application.Render();
+    application.SendNotification();
+
+    // For complete line coverage
+    alignment.SetAlignmentType(Alignment::HorizontalLeft);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::HorizontalRight);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalTop);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalBottom);
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+
+  // ShrinkToFitKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    alignment.Add(Actor::New());
+    Stage::GetCurrent().Add(alignment);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS(Alignment::ScaleNone, alignment.GetScaling(), TEST_LOCATION);
+    alignment.SetScaling(Alignment::ShrinkToFitKeepAspect);
+    DALI_TEST_EQUALS(Alignment::ShrinkToFitKeepAspect, alignment.GetScaling(), TEST_LOCATION);
+    application.Render();
+    application.SendNotification();
+
+    // For complete line coverage
+    alignment.SetAlignmentType(Alignment::HorizontalLeft);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::HorizontalRight);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalTop);
+    application.Render();
+    application.SendNotification();
+    alignment.SetAlignmentType(Alignment::VerticalBottom);
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(alignment);
+    application.Render();
+    application.SendNotification();
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentGetScaling(void)
+{
+  ToolkitTestApplication application;
+
+  // ScaleToFill
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleNone);
+
+    alignment.SetScaling(Alignment::ScaleToFill);
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleToFill);
+  }
+
+  // ScaleToFitKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleNone);
+
+    alignment.SetScaling(Alignment::ScaleToFitKeepAspect);
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleToFitKeepAspect);
+  }
+
+  // ScaleToFillKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleNone);
+
+    alignment.SetScaling(Alignment::ScaleToFillKeepAspect);
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleToFillKeepAspect);
+  }
+
+  // ShrinkToFit
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleNone);
+
+    alignment.SetScaling(Alignment::ShrinkToFit);
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ShrinkToFit);
+  }
+
+  // ShrinkToFitKeepAspect
+  {
+    Alignment alignment = Alignment::New();
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ScaleNone);
+
+    alignment.SetScaling(Alignment::ShrinkToFitKeepAspect);
+    DALI_TEST_CHECK(alignment.GetScaling() == Alignment::ShrinkToFitKeepAspect);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetPaddingPositive(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+
+  Alignment::Padding padding(1.0f, 1.5f, 2.f, 0.5f);
+  DALI_TEST_CHECK( fabs( padding.left - alignment.GetPadding().left ) > GetRangedEpsilon( padding.left, alignment.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( padding.right - alignment.GetPadding().right ) > GetRangedEpsilon( padding.right, alignment.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( padding.top - alignment.GetPadding().top ) > GetRangedEpsilon( padding.top, alignment.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( padding.bottom - alignment.GetPadding().bottom ) > GetRangedEpsilon( padding.bottom, alignment.GetPadding().bottom ) );
+
+  alignment.SetPadding(padding);
+  DALI_TEST_CHECK( fabs( padding.left - alignment.GetPadding().left ) < GetRangedEpsilon( padding.left, alignment.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( padding.right - alignment.GetPadding().right ) < GetRangedEpsilon( padding.right, alignment.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( padding.top - alignment.GetPadding().top ) < GetRangedEpsilon( padding.top, alignment.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( padding.bottom - alignment.GetPadding().bottom ) < GetRangedEpsilon( padding.bottom, alignment.GetPadding().bottom ) );
+  END_TEST;
+}
+
+int UtcDaliAlignmentSetPaddingNegative(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+
+  try
+  {
+    Alignment::Padding padding(-1.0f, 1.5f, 2.f, 0.f);
+    alignment.SetPadding(padding);
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f )", TEST_LOCATION );
+  }
+
+  try
+  {
+    Alignment::Padding padding(1.0f, 1.5f, -2.f, 0.f);
+    alignment.SetPadding(padding);
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f )", TEST_LOCATION );
+  }
+
+  try
+  {
+    Alignment::Padding padding(1.0f, 1.5f, 2.f, -1.f);
+    alignment.SetPadding(padding);
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f )", TEST_LOCATION );
+  }
+
+  try
+  {
+    Alignment::Padding padding(1.0f, -1.5f, 2.f, 0.f);
+    alignment.SetPadding(padding);
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f )", TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliAlignmentGetPadding(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  DALI_TEST_CHECK( fabs( alignment.GetPadding().left ) < GetRangedEpsilon( 0.f, alignment.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( alignment.GetPadding().right ) < GetRangedEpsilon( 0.f, alignment.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( alignment.GetPadding().top ) < GetRangedEpsilon( 0.f, alignment.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( alignment.GetPadding().bottom ) < GetRangedEpsilon( 0.f, alignment.GetPadding().bottom ) );
+
+  Alignment::Padding padding(1.0f, 1.5f, 2.f, 0.f);
+  alignment.SetPadding(padding);
+  DALI_TEST_CHECK( fabs( padding.left - alignment.GetPadding().left ) < GetRangedEpsilon( padding.left, alignment.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( padding.right - alignment.GetPadding().right ) < GetRangedEpsilon( padding.right, alignment.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( padding.top - alignment.GetPadding().top ) < GetRangedEpsilon( padding.top, alignment.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( padding.bottom - alignment.GetPadding().bottom ) < GetRangedEpsilon( padding.bottom, alignment.GetPadding().bottom ) );
+  END_TEST;
+}
+
+int UtcDaliAlignmentChildAddAndRemove(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  Stage::GetCurrent().Add(alignment);
+
+  application.Render();
+  application.SendNotification();
+
+  Actor actor = Actor::New();
+  alignment.Add(actor);
+
+  DALI_TEST_EQUALS(alignment.GetChildCount(), 1u, TEST_LOCATION);
+
+  application.Render();
+  application.SendNotification();
+
+  alignment.Remove(actor);
+
+  DALI_TEST_EQUALS(alignment.GetChildCount(), 0u, TEST_LOCATION);
+
+  application.Render();
+  application.SendNotification();
+
+  Stage::GetCurrent().Remove(alignment);
+  END_TEST;
+}
+
+int UtcDaliAlignmentSizeSetP(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  Stage::GetCurrent().Add(alignment);
+
+  application.Render();
+  application.SendNotification();
+
+  Vector2 size( 100.0f, 200.0f );
+  alignment.SetSize(size);
+
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+
+  DALI_TEST_EQUALS(size, alignment.GetTargetSize().GetVectorXY(), TEST_LOCATION);
+
+  Stage::GetCurrent().Remove(alignment);
+  END_TEST;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static bool TouchCallback(Actor actor, const TouchData& event)
+{
+  return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliAlignmentOnTouchEvent(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  alignment.SetSize(100.0f, 100.0f);
+  alignment.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(alignment);
+
+  alignment.TouchSignal().Connect(&TouchCallback);
+
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+
+  Integration::TouchEvent touchEvent(1);
+  Integration::Point point;
+  point.SetDeviceId( 1 );
+  point.SetState( PointState::DOWN);
+  point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+  touchEvent.AddPoint(point);
+  application.ProcessEvent(touchEvent);
+
+  tet_result(TET_PASS); // For line coverage, as long as there are no exceptions, we assume passed.
+  END_TEST;
+}
+
+int UtcDaliAlignmentOnKeyEvent(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  Stage::GetCurrent().Add(alignment);
+
+  alignment.SetKeyInputFocus();
+
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+
+  Integration::KeyEvent keyEvent;
+  application.ProcessEvent(keyEvent);
+
+  tet_result(TET_PASS); // For line coverage, as long as there are no exceptions, we assume passed.
+  END_TEST;
+}
+
+int UtcDaliAlignmentOnSizeAnimation(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  Stage::GetCurrent().Add(alignment);
+
+  Animation animation = Animation::New(100.0f);
+  animation.AnimateTo( Property( alignment, Actor::Property::SIZE ), Vector3( 100.0f, 150.0f, 200.0f ) );
+  animation.Play();
+
+  application.Render();
+  application.SendNotification();
+  application.Render();
+  application.SendNotification();
+
+  tet_result(TET_PASS); // For line coverage, as long as there are no exceptions, we assume passed.
+  END_TEST;
+}
+
+int UtcDaliAlignmentCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  Alignment alignment = Alignment::New();
+  Alignment emptyAlignment;
+
+  Alignment::Padding padding(100.0f, 150.0f, 200.f, 0.f);
+  alignment.SetPadding(padding);
+
+  Alignment alignmentCopy(alignment);
+  DALI_TEST_CHECK( fabs( padding.left - alignmentCopy.GetPadding().left ) < GetRangedEpsilon( padding.left, alignmentCopy.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( padding.right - alignmentCopy.GetPadding().right ) < GetRangedEpsilon( padding.right, alignmentCopy.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( padding.top - alignmentCopy.GetPadding().top ) < GetRangedEpsilon( padding.top, alignmentCopy.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( padding.bottom - alignmentCopy.GetPadding().bottom ) < GetRangedEpsilon( padding.bottom, alignmentCopy.GetPadding().bottom ) );
+
+  Alignment alignmentEmptyCopy(emptyAlignment);
+  DALI_TEST_CHECK(emptyAlignment == alignmentEmptyCopy);
+
+  Alignment alignmentEquals;
+  alignmentEquals = alignment;
+  DALI_TEST_CHECK( fabs( padding.left - alignmentEquals.GetPadding().left ) < GetRangedEpsilon( padding.left, alignmentEquals.GetPadding().left ) );
+  DALI_TEST_CHECK( fabs( padding.right - alignmentEquals.GetPadding().right ) < GetRangedEpsilon( padding.right, alignmentEquals.GetPadding().right ) );
+  DALI_TEST_CHECK( fabs( padding.top - alignmentEquals.GetPadding().top ) < GetRangedEpsilon( padding.top, alignmentEquals.GetPadding().top ) );
+  DALI_TEST_CHECK( fabs( padding.bottom - alignmentEquals.GetPadding().bottom ) < GetRangedEpsilon( padding.bottom, alignmentEquals.GetPadding().bottom ) );
+
+  Alignment alignmentEmptyEquals;
+  alignmentEmptyEquals = emptyAlignment;
+  DALI_TEST_CHECK(emptyAlignment == alignmentEmptyEquals);
+
+  // Self assignment
+  alignment = alignment;
+  DALI_TEST_CHECK(alignment == alignmentCopy);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
new file mode 100644 (file)
index 0000000..bb591dd
--- /dev/null
@@ -0,0 +1,915 @@
+
+/*
+ * Copyright (c) 2020 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 <toolkit-timer.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_animated_image_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_animated_image_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/application-icon-%02d.png";
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+}
+
+
+void CopyUrlsIntoArray( Property::Array& urls, int startIndex=0 )
+{
+  for( int i=20+startIndex;i<=30;++i)
+  {
+    char* url;
+    if(asprintf(&url, TEST_IMAGE_FILE_NAME, i) > 0)
+    {
+      Property::Value value(url);
+      urls.Add(value);
+      free(url);
+    }
+  }
+}
+
+int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedImageVisualGetPropertyMap" );
+
+  // request AnimatedImageVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base animatedImageVisual = factory.CreateVisual(
+    Property::Map()
+    .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+    .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+    .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+    .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+    .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT ));
+
+  Property::Map resultMap;
+  animatedImageVisual.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::ANIMATED_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_GIF_FILE_NAME );
+
+  // request AnimatedImageVisual with an URL
+  Visual::Base animatedImageVisual2 = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  resultMap.Clear();
+  animatedImageVisual2.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::ANIMATED_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_GIF_FILE_NAME );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedImageVisualGetPropertyMap for multi image" );
+
+  // request AnimatedImageVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  Visual::Base animatedImageVisual = factory.CreateVisual(
+    Property::Map()
+    .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+    .Add( "url", urls )
+    .Add( "batchSize", 4 )
+    .Add( "cacheSize", 8 )
+    .Add( "loopCount", 10 )
+    .Add( "frameDelay", 200 )
+    .Add( "pixelArea", Vector4() )
+    .Add( "wrapModeU", WrapMode::REPEAT )
+    .Add( "wrapModeV", WrapMode::DEFAULT ));
+
+  Property::Map resultMap;
+  animatedImageVisual.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::ANIMATED_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL, "url" );
+  DALI_TEST_CHECK( value );
+  Property::Array* resultUrls = value->GetArray();
+  DALI_TEST_CHECK( resultUrls );
+  DALI_TEST_EQUALS( resultUrls->Count(), urls.Count(), TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::BATCH_SIZE, "batchSize" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 4, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::CACHE_SIZE, "cacheSize" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 8, TEST_LOCATION );
+
+  value = resultMap.Find( Toolkit::DevelImageVisual::Property::LOOP_COUNT, "loopCount" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 10, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::FRAME_DELAY, "frameDelay" );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 200, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualJumpToAction(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 12);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 20 );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 6 );
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 6 ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualStopBehavior(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME);
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 8);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    // Expect that a batch of 4 textures has been requested. These will be serially loaded
+    // below.
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 1 );
+
+    // Expect the second batch has been requested
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualGif01(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, TEST_GIF_FILE_NAME );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 2);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    // Expect that a batch of 4 textures has been requested. These will be serially loaded
+    // below.
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 2, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    Test::EmitGlobalTimerSignal();
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(20);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualMultiImage01(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 8);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    // Expect that a batch of 4 textures has been requested. These will be serially loaded
+    // below.
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    application.SendNotification();
+    application.Render(16);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION );
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    tet_infoline( "Test that after 1 tick, and file loads completed, that we have 7 textures" );
+    Test::EmitGlobalTimerSignal();
+
+    // Expect the second batch has been requested
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 7, TEST_LOCATION );
+
+
+    tet_infoline( "Test that after 2 ticks that we have 6 textures" );
+
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 6, TEST_LOCATION );
+
+    tet_infoline("And that at least 2 textures were requested");
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 8, TEST_LOCATION );
+
+
+    tet_infoline( "Test that after 3rd tick that we have 7 textures and 1 request" );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 7, TEST_LOCATION );
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 8, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualMultiImage02(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  tet_infoline( "Test that the animated visual still works with zero sized cache" );
+
+  {
+    Property::Array urls;
+    CopyUrlsIntoArray( urls );
+
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 0);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 0);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap ); // TexMgr::Request load tId:0
+
+    // Expect that each image is loaded each tick
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Ready the visual after the visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);//glGenTextures 1
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_LOCATION );
+
+    tet_infoline( "Test that each tick, a new image is requested" );
+    Test::EmitGlobalTimerSignal(); // TexMgr::Remove tId:0
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, 10 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);//glGenTextures 2
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_LOCATION );
+
+    tet_infoline( "Test that each tick, a new image is requested" );
+    Test::EmitGlobalTimerSignal(); // Internal::~TextureSet()
+    application.SendNotification();
+    application.Render(16);//glDeleteTextures 2
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, 10 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);//glGenTextures 3
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_LOCATION );
+
+    tet_infoline( "Test that each tick, a new image is requested" );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);//glDeleteTextures 3
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, 10 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);//Gen4
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_LOCATION );
+    dummyControl.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualMultiImage03(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  {
+    Property::Array urls1, urls2;
+    CopyUrlsIntoArray( urls1 );
+    CopyUrlsIntoArray( urls2 );
+
+    Property::Map animatedImageMap1;
+    animatedImageMap1.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    animatedImageMap1.Insert( ImageVisual::Property::URL, Property::Value(urls1) );
+    animatedImageMap1.Insert( ImageVisual::Property::BATCH_SIZE, 3);
+    animatedImageMap1.Insert( ImageVisual::Property::CACHE_SIZE, 3);
+    animatedImageMap1.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    Property::Map animatedImageMap2;
+    animatedImageMap2.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    animatedImageMap2.Insert( ImageVisual::Property::URL, Property::Value(urls2) );
+    animatedImageMap2.Insert( ImageVisual::Property::BATCH_SIZE, 2);
+    animatedImageMap2.Insert( ImageVisual::Property::CACHE_SIZE, 2);
+    animatedImageMap2.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base animatedImageVisual1 = factory.CreateVisual( animatedImageMap1 );
+
+    tet_infoline( "Create two image views with the same URLs, offset by 1 frame.");
+
+    DummyControl dummyControl1 = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl1 = static_cast<Impl::DummyControl&>(dummyControl1.GetImplementation());
+    dummyImpl1.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual1 );
+    dummyControl1.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl1 );
+
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Ready the requested image after the first visual is on stage" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 3, TEST_LOCATION );
+
+    Visual::Base animatedImageVisual2 = factory.CreateVisual( animatedImageMap2 );
+    DummyControl dummyControl2 = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl2 = static_cast<Impl::DummyControl&>(dummyControl2.GetImplementation());
+    dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual2 );
+    dummyControl2.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl2 );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "The texture cache should be holding the requested images; check that the renderer has a texture" );
+    TextureSet ts = dummyControl2.GetRendererAt(0).GetTextures();
+    Texture t1 = ts.GetTexture( 0 );
+    DALI_TEST_EQUALS( ts.GetTextureCount(), 1, TEST_LOCATION );
+
+    tet_infoline( "Test that on the first tick, 1 new image is requested" );
+    Test::EmitGlobalTimerSignal(); // Both visuals should tick
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 3, TEST_LOCATION );
+
+    ts = dummyControl2.GetRendererAt(0).GetTextures();
+    Texture t2 = ts.GetTexture( 0 );
+    DALI_TEST_CHECK( t1 != t2 );
+
+    dummyControl1.Unparent();
+    dummyControl2.Unparent();
+  }
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualMultiImage04(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Test that if the cache size is the same as the number of urls, that once the cache is full, no new images are loaded" );
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 6);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 11);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    tet_infoline( "Expect that a batch of 7 textures has been requested." );
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Wait for the first batch to complete" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 6 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+
+    DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 6, TEST_LOCATION );
+    tet_infoline( "Test that after 1 tick, and 5 file loads completed, that we have 11 textures" );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+
+    // Expect the second batch has been requested
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 5 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 11, TEST_LOCATION );
+
+    tet_infoline( "Test that after 2 ticks that we have 11 textures and no requests" );
+
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, 5 ), false, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 11, TEST_LOCATION );
+
+    tet_infoline( "Test that after 3rd tick that we have 11 textures and no requests" );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, 5 ), false, TEST_LOCATION );
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 11, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+
+  tet_infoline("Test that removing the visual from stage deletes all textures");
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliAnimatedImageVisualMultiImage05(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  tet_infoline( "Test that if the cache size is the same as the number of urls, that removing a partially loaded visual removes all textures" );
+
+  Property::Array urls;
+  CopyUrlsIntoArray( urls );
+
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE );
+    propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) );
+    propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4);
+    propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 11);
+    propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 100);
+
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    tet_infoline( "Expect that a batch of 4 textures has been requested." );
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Wait for the first batch to complete" );
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+
+    tet_infoline( "Test that a timer has been started" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Test that a timer has been started" );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+
+    dummyControl.Unparent();
+  }
+
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  tet_infoline( "Test that pending batch of image loads are cancelled instead of uploaded");
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyControl, uint16_t frameCount, uint16_t loopCount, const char * location )
+{
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+
+  textureTrace.Enable(true);
+  Stage::GetCurrent().Add( dummyControl );
+  application.SendNotification();
+  application.Render(16);
+
+  tet_infoline( "Test that a timer has been created" );
+  DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_INNER_LOCATION( location ) );
+
+  for ( uint16_t i = 0; i < loopCount; i++ )
+  {
+    for ( uint16_t j = 0; j < frameCount; j++ )
+    {
+      if( i == 0 && j == 0 )
+      {
+        continue; // Because first frame is already showed and we call 2nd frame at the first time of timer animation.
+      }
+      tet_printf( "Test that after %u ticks, and we have %u frame \n", j + 1u, j + 1u );
+      Test::EmitGlobalTimerSignal();
+      application.SendNotification();
+      application.Render(16);
+      DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 1, TEST_INNER_LOCATION( location ) );
+      DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_INNER_LOCATION( location ) );
+    }
+    tet_printf( "\nTest Loop %u \n", i );
+  }
+
+  tet_printf( "Test that after %u loops, and we have no frame. Timer should stop \n", loopCount );
+  Test::EmitGlobalTimerSignal();
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_EQUALS( Test::AreTimersRunning(), false, TEST_INNER_LOCATION( location ) );
+
+  dummyControl.Unparent();
+}
+
+int UtcDaliAnimatedImageVisualLoopCount(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliAnimatedImageVisualLoopCount" );
+
+  {
+    // request AnimatedImageVisual with a property map
+    // Test with no (0) loop count
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 0 ));
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+    TestLoopCount( application, dummyControl, 4, 0, TEST_LOCATION );
+
+    // Test with no (1) loop count. Request AnimatedImageVisual with a property map
+    animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 1 ));
+
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+
+    TestLoopCount( application, dummyControl, 4, 1, TEST_LOCATION );
+
+    // Test with no (100) loop count. Request AnimatedImageVisual with a property map
+    animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, 100 ));
+
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+
+    TestLoopCount( application, dummyControl, 4, 100, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedImageVisualPlayback(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+
+  tet_infoline( "UtcDaliAnimatedImageVisualPlayback" );
+
+  {
+    // request AnimatedImageVisual with a property map
+    // Test with forever (-1) loop count
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base animatedImageVisual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+      .Add( ImageVisual::Property::PIXEL_AREA, Vector4() )
+      .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT )
+      .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT )
+      .Add( DevelImageVisual::Property::LOOP_COUNT, -1 ));
+
+    DummyControl dummyControl = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, animatedImageVisual );
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+    textureTrace.Enable(true);
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render(16);
+
+    tet_infoline( "Test that a timer has been created" );
+    DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION );
+
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
+
+    Property::Map attributes;
+    tet_infoline( "Test Pause action. Timer should stop after Pause action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::PAUSE, attributes );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::AreTimersRunning(), false, TEST_LOCATION );
+
+    tet_infoline( "Test Play action. Timer should Restart after Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::PLAY, attributes );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
+
+    tet_infoline( "Test Stop action. Timer should stop after Stop action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, attributes );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::AreTimersRunning(), false, TEST_LOCATION );
+
+    tet_infoline( "Test Play action. Timer should Restart after Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::PLAY, attributes );
+    Test::EmitGlobalTimerSignal();
+    application.SendNotification();
+    application.Render(16);
+    DALI_TEST_EQUALS( Test::AreTimersRunning(), true, TEST_LOCATION );
+
+    dummyControl.Unparent();
+  }
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
new file mode 100644 (file)
index 0000000..069a644
--- /dev/null
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (c) 2018 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 <chrono>
+#include <thread>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
+#include <toolkit-event-thread-callback.h>
+#include <toolkit-vector-animation-renderer.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_animated_vector_image_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_animated_vector_image_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* TEST_VECTOR_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/insta_camera.json";
+
+bool gAnimationFinishedSignalFired = false;
+
+void VisualEventSignal( Control control, Dali::Property::Index visualIndex, Dali::Property::Index signalId )
+{
+  if( visualIndex == DummyControl::Property::TEST_VISUAL && signalId == DevelAnimatedVectorImageVisual::Signal::ANIMATION_FINISHED )
+  {
+    gAnimationFinishedSignalFired = true;
+  }
+}
+
+}
+
+int UtcDaliVisualFactoryGetAnimatedVectorImageVisual01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedVectorImageVisual01: Request animated vector image visual with a json url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  // Test SetOffStage().
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetAnimatedVectorImageVisual02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedVectorImageVisual02: Request animated vector image visual with a Property::Map" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetAnimatedVectorImageVisual03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedVectorImageVisual03: Request animated vector image visual with a Property::Map" );
+
+  int startFrame = 1, endFrame = 3;
+  Property::Array playRange;
+  playRange.PushBack( startFrame );
+  playRange.PushBack( endFrame );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3  )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, playRange  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetAnimatedVectorImageVisual04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedVectorImageVisual04: Request animated vector image visual with a Property::Map" );
+
+  int startFrame = 1, endFrame = 3;
+  Property::Array playRange;
+  playRange.PushBack( startFrame );
+  playRange.PushBack( endFrame );
+
+  Property::Map propertyMap;
+  propertyMap.Add( "visualType", DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( "url", TEST_VECTOR_IMAGE_FILE_NAME )
+             .Add( "loopCount", 3 )
+             .Add( "playRange", playRange )
+             .Add( "stopBehavior", DevelImageVisual::StopBehavior::FIRST_FRAME )
+             .Add( "loopingMode", DevelImageVisual::LoopingMode::AUTO_REVERSE );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Map resultMap;
+  visual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( ImageVisual::Property::URL, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< std::string >() == TEST_VECTOR_IMAGE_FILE_NAME );
+
+  value = resultMap.Find( DevelImageVisual::Property::LOOP_COUNT, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == 3 );
+
+  value = resultMap.Find( DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY );
+  DALI_TEST_CHECK( value );
+
+  Property::Array* result = value->GetArray();
+  DALI_TEST_CHECK( result );
+
+  DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == startFrame );
+  DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == endFrame );
+
+  value = resultMap.Find( DevelImageVisual::Property::STOP_BEHAVIOR, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::StopBehavior::FIRST_FRAME );
+
+  value = resultMap.Find( DevelImageVisual::Property::LOOPING_MODE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::LoopingMode::AUTO_REVERSE );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualGetPropertyMap01" );
+
+  int startFrame = 1, endFrame = 3;
+  Property::Array playRange;
+  playRange.PushBack( startFrame );
+  playRange.PushBack( endFrame );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE,  DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
+
+  // request AnimatedVectorImageVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map resultMap;
+  resultMap = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelVisual::ANIMATED_VECTOR_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< std::string >() == TEST_VECTOR_IMAGE_FILE_NAME );
+
+  value = resultMap.Find( DevelImageVisual::Property::LOOP_COUNT, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == 3 );
+
+  value = resultMap.Find( DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY );
+  DALI_TEST_CHECK( value );
+
+  Property::Array* result = value->GetArray();
+  DALI_TEST_CHECK( result );
+
+  DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == startFrame );
+  DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == endFrame );
+
+  value = resultMap.Find( DevelImageVisual::Property::STOP_BEHAVIOR, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::StopBehavior::CURRENT_FRAME );
+
+  value = resultMap.Find( DevelImageVisual::Property::LOOPING_MODE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::LoopingMode::RESTART );
+
+  value = resultMap.Find( DevelImageVisual::Property::CONTENT_INFO, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  // request AnimatedVectorImageVisual with an URL
+  Visual::Base visual2 = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
+
+  resultMap.Clear();
+  visual2.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelVisual::ANIMATED_VECTOR_IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< std::string >() == TEST_VECTOR_IMAGE_FILE_NAME );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPlayback(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualPlayback" );
+
+  {
+    // request AnimatedVectorImageVisual with a property map
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base visual = factory.CreateVisual(
+      Property::Map()
+      .Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+      .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME ) );
+
+    DummyControl dummyControl = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummyControl.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+    dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+    Property::Map attributes;
+    tet_infoline( "Test Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+    Stage::GetCurrent().Add( dummyControl );
+    application.SendNotification();
+    application.Render( 16 );
+
+    std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );    // wait for one animation loop (16fps, 5frames, need 80ms)
+
+    Property::Map map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+    tet_infoline( "Test Pause action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );    // wait for next rasterize thread run
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PAUSED );
+
+    tet_infoline( "Test Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+    tet_infoline( "Test Stop action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+    tet_infoline( "Test Stop action again" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+    tet_infoline( "Test Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+    tet_infoline( "Off stage" );
+    dummyControl.Unparent();
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+    tet_infoline( "On stage again" );
+    Stage::GetCurrent().Add( dummyControl );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+    tet_infoline( "Test Play action" );
+    DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+    application.SendNotification();
+    application.Render(16);
+
+    map = dummyControl.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+    value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+    DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::PLAYING );
+
+    // Change Size
+    Vector3 newSize( 100.0f, 100.0f, 0.0f );
+    dummyControl.SetSize( newSize );
+
+    application.SendNotification();
+    application.Render(16);
+
+    // Size should be changed
+    Vector3 naturalSize = dummyControl.GetNaturalSize();
+    DALI_TEST_CHECK( naturalSize == newSize );
+
+    dummyControl.Unparent();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualCustomShader Test custom shader" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  Property::Map shader;
+  const std::string vertexShader = "Foobar";
+  const std::string fragmentShader = "Foobar sampler2D Foobar";
+  shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+  shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+  properties[Visual::Property::TYPE] = Visual::IMAGE;
+  properties[Visual::Property::SHADER] = shader;
+  properties[ImageVisual::Property::URL] = TEST_VECTOR_IMAGE_FILE_NAME;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  dummy.SetSize( 200.f, 200.f );
+  dummy.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( dummy );
+
+  application.SendNotification();
+  application.Render();
+
+  Renderer renderer = dummy.GetRendererAt( 0 );
+  Shader shader2 = renderer.GetShader();
+  Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  std::string resultFragmentShader, resultVertexShader;
+  Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+  fragment->Get( resultFragmentShader );
+  DALI_TEST_CHECK( resultFragmentShader.find( fragmentShader ) != std::string::npos );
+
+  Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+  vertex->Get( resultVertexShader );
+  DALI_TEST_CHECK( resultVertexShader.find( vertexShader ) != std::string::npos );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualNaturalSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualNaturalSize" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_VECTOR_IMAGE_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  Vector2 naturalSize;
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  visual.GetNaturalSize( naturalSize );
+
+  DALI_TEST_EQUALS( naturalSize, Vector2( 100.0f, 100.0f ), TEST_LOCATION );    // 100x100 is the content default size.
+
+  actor.SetSize( controlSize );
+
+  application.SendNotification();
+  application.Render();
+
+  visual.GetNaturalSize( naturalSize );
+
+  DALI_TEST_EQUALS( naturalSize, controlSize, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoopCount(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualLoopCount" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPlayRange(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualPlayRange" );
+
+  int startFrame = 1, endFrame = 3;
+  Property::Array array;
+  array.PushBack( endFrame );
+  array.PushBack( startFrame );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, array  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  int resultStartFrame, resultEndFrame;
+  Property::Array* result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( startFrame, resultStartFrame, TEST_LOCATION );
+  DALI_TEST_EQUALS( endFrame, resultEndFrame, TEST_LOCATION );
+
+  // Set invalid play range
+  array.Clear();
+  array.PushBack( 1 );
+  array.PushBack( 100 );
+
+  attributes.Clear();
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( startFrame, resultStartFrame, TEST_LOCATION );  // Should not be changed
+  DALI_TEST_EQUALS( endFrame, resultEndFrame, TEST_LOCATION );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, Property::Map() );
+
+  application.SendNotification();
+  application.Render();
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
+
+  array.Clear();
+  array.PushBack( 0 );
+  array.PushBack( 2 );
+
+  attributes.Clear();
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( 0, resultStartFrame, TEST_LOCATION );
+  DALI_TEST_EQUALS( 2, resultEndFrame, TEST_LOCATION );
+
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 2, TEST_LOCATION );    // CURRENT_FRAME_NUMBER should be changed also.
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPlayRangeMarker(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualPlayRangeMarker" );
+
+  Property::Array array;
+  array.PushBack( VECTOR_ANIMATION_MARKER_NAME_1 );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, array  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  int resultStartFrame, resultEndFrame;
+  Property::Array* result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_START_FRAME_1, resultStartFrame, TEST_LOCATION );
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_END_FRAME_1, resultEndFrame, TEST_LOCATION );
+
+  // Set 2 markers
+  array.Clear();
+  array.PushBack( VECTOR_ANIMATION_MARKER_NAME_1 );
+  array.PushBack( VECTOR_ANIMATION_MARKER_NAME_2 );
+
+  attributes.Clear();
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_START_FRAME_1, resultStartFrame, TEST_LOCATION );
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_END_FRAME_2, resultEndFrame, TEST_LOCATION );
+
+  // Set invalid play range
+  array.Clear();
+  array.PushBack( 1 );
+  array.PushBack( VECTOR_ANIMATION_MARKER_NAME_1 );
+
+  attributes.Clear();
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  result = value->GetArray();
+  result->GetElementAt( 0 ).Get( resultStartFrame );
+  result->GetElementAt( 1 ).Get( resultEndFrame );
+
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_START_FRAME_1, resultStartFrame, TEST_LOCATION );  // Should not be changed
+  DALI_TEST_EQUALS( VECTOR_ANIMATION_MARKER_END_FRAME_2, resultEndFrame, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualAnimationFinishedSignal" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  DevelControl::VisualEventSignal( actor ).Connect( &VisualEventSignal );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Wait for animation finish
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_STATE );
+  DALI_TEST_CHECK( value->Get< int >() == DevelImageVisual::PlayState::STOPPED );
+
+  DALI_TEST_EQUALS( gAnimationFinishedSignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualJumpTo(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualJumpTo" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 2 );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 2, TEST_LOCATION );
+
+  Property::Array array;
+  array.PushBack( 0 );
+  array.PushBack( 2 );
+
+  Property::Map attributes;
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 2, TEST_LOCATION );
+
+  // Change play range
+  attributes.Clear();
+  array.Clear();
+
+  array.PushBack( 0 );
+  array.PushBack( 4 );
+
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  attributes.Clear();
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Stop and jump to 3
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
+
+  // Jump to the same position
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualJumpToCurrentProgress" );
+
+  int startFrame = 1, endFrame = 3;
+  Property::Array playRange;
+  playRange.PushBack( startFrame );
+  playRange.PushBack( endFrame );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3  )
+             .Add( DevelImageVisual::Property::PLAY_RANGE, playRange  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::LOOP_COUNT );
+  DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
+
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY );
+  DALI_TEST_CHECK( value );
+
+  Property::Array* result = value->GetArray();
+  DALI_TEST_CHECK( result );
+
+  DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == startFrame );
+  DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == endFrame );
+
+  playRange.Clear();
+  playRange.PushBack( 0 );
+  playRange.PushBack( 2 );
+
+  Property::Map attributes;
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
+  attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 5 );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::LOOP_COUNT );
+  DALI_TEST_EQUALS( value->Get< int >(), 5, TEST_LOCATION );
+
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+  result = value->GetArray();
+  DALI_TEST_CHECK( result );
+
+  DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == 0 );
+  DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == 2 );
+
+  attributes.Clear();
+
+  playRange.Clear();
+  playRange.PushBack( startFrame );
+  playRange.PushBack( endFrame );
+
+  attributes.Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+
+  result = value->GetArray();
+  DALI_TEST_CHECK( result );
+
+  DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == startFrame );
+  DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == endFrame );
+
+  // Play and update property
+  attributes.Clear();
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 10 );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::LOOP_COUNT );
+  DALI_TEST_EQUALS( value->Get< int >(), 10, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualStopBehavior(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualStopBehavior" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
+             .Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 0, TEST_LOCATION );  // Should be the first frame
+
+  // Change stop behavior
+  attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  attributes.Clear();
+
+  // Play again
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+
+  Property::Value* value1 = map.Find( DevelImageVisual::Property::TOTAL_FRAME_NUMBER );
+  int totalFrameNumber = value1->Get< int >();
+
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), totalFrameNumber - 1, TEST_LOCATION );  // Should be the last frame
+
+  // Change stop behavior
+  attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::CURRENT_FRAME );
+  attributes.Add( DevelImageVisual::Property::LOOP_COUNT, -1 );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  attributes.Clear();
+
+  // Play again
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Pause
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, attributes );
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  int currentFrameNumber = value->Get< int >();
+
+  // Stop
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::STOP, attributes );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), currentFrameNumber, TEST_LOCATION );  // Should be same with currentFrameNumber
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualLoopingMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualLoopingMode" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME )
+             .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
+             .Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME )
+             .Add( DevelImageVisual::Property::LOOPING_MODE, DevelImageVisual::LoopingMode::AUTO_REVERSE );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  Property::Value* value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 0, TEST_LOCATION );  // Should be the first frame because of auto reverse
+
+  // Change stop behavior
+  attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::CURRENT_FRAME );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  // Play again
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), 0, TEST_LOCATION );  // Should be the first frame
+
+  // Change looping mode
+  attributes.Add( DevelImageVisual::Property::LOOPING_MODE, DevelImageVisual::LoopingMode::RESTART );
+
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  // Play again
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 1 - animation finished
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Property::Value* value1 = map.Find( DevelImageVisual::Property::TOTAL_FRAME_NUMBER );
+  int totalFrameNumber = value1->Get< int >();
+
+  map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+  value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
+  DALI_TEST_EQUALS( value->Get< int >(), totalFrameNumber - 1, TEST_LOCATION );  // Should be the last frame
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualPropertyNotification(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualPropertyNotification" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME  );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  Vector3 controlScale( 2.0f, 2.0f, 1.0f );
+  actor.SetSize( controlSize );
+  actor.SetScale( controlScale );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  application.SendNotification();
+  application.Render();
+
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  auto textureSet = renderer.GetTextures();
+  auto texture = textureSet.GetTexture(0);
+
+  DALI_TEST_EQUALS( controlSize.width * controlScale.width, texture.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( controlSize.height * controlScale.height, texture.GetHeight(), TEST_LOCATION );
+
+  // Change scale and size
+  controlSize = Vector2( 50.f, 40.f );
+  controlScale= Vector3( 0.5f, 0.5f, 1.0f );
+  actor.SetSize( controlSize );
+  actor.SetScale( controlScale );
+
+  application.SendNotification();
+  application.Render();
+
+  application.SendNotification();
+  application.Render();
+
+  renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  textureSet = renderer.GetTextures();
+  texture = textureSet.GetTexture(0);
+
+  DALI_TEST_EQUALS( controlSize.width * controlScale.width, texture.GetWidth(), TEST_LOCATION );
+  DALI_TEST_EQUALS( controlSize.height * controlScale.height, texture.GetHeight(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualMultipleInstances(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualMultipleInstances" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
+
+  Visual::Base visual1 = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual1 );
+
+  DummyControl actor1 = DummyControl::New( true );
+  DummyControlImpl& dummyImpl1 = static_cast< DummyControlImpl& >( actor1.GetImplementation() );
+  dummyImpl1.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual1 );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor1.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor1 );
+
+  propertyMap.Clear();
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
+
+  Visual::Base visual2 = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual2 );
+
+  DummyControl actor2 = DummyControl::New( true );
+  DummyControlImpl& dummyImpl2 = static_cast< DummyControlImpl& >( actor2.GetImplementation() );
+  dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual2 );
+
+  actor2.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor2 );
+
+  DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map() );
+
+  application.SendNotification();
+  application.Render();
+
+  std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
+
+  Property::Map attributes;
+  attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME );
+
+  DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+  DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+  DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map() );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor1.GetRendererCount() == 1u );
+  Renderer renderer1 = actor1.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer1 );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor2.GetRendererCount() == 1u );
+  Renderer renderer2 = actor2.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer2 );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualControlVisibilityChanged(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualControlVisibilityChanged" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  // Check rendering behavior
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+  DALI_TEST_CHECK( renderer.GetProperty< int >( DevelRenderer::Property::RENDERING_BEHAVIOR ) == DevelRenderer::Rendering::CONTINUOUSLY );
+
+  actor.SetVisible( false );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check rendering behavior again
+  DALI_TEST_CHECK( renderer.GetProperty< int >( DevelRenderer::Property::RENDERING_BEHAVIOR ) == DevelRenderer::Rendering::IF_REQUIRED );
+
+  END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualWindowVisibilityChanged(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedVectorImageVisualWindowVisibilityChanged" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+             .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Vector2 controlSize( 20.f, 30.f );
+  actor.SetSize( controlSize );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map attributes;
+  DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
+
+  // Check rendering behavior
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+  DALI_TEST_CHECK( renderer.GetProperty< int >( DevelRenderer::Property::RENDERING_BEHAVIOR ) == DevelRenderer::Rendering::CONTINUOUSLY );
+
+  Window window = DevelWindow::Get( actor );
+  window.Hide();
+
+  application.SendNotification();
+  application.Render();
+
+  // Check rendering behavior again
+  DALI_TEST_CHECK( renderer.GetProperty< int >( DevelRenderer::Property::RENDERING_BEHAVIOR ) == DevelRenderer::Rendering::IF_REQUIRED );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ArcVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ArcVisual.cpp
new file mode 100644 (file)
index 0000000..be12290
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2020 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 <chrono>
+//#include <thread>
+#include <dali-toolkit-test-suite-utils.h>
+//#include <toolkit-timer.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_arc_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_arc_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliVisualFactoryGetArcVisual01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetArcVisual01: Request arc visual with a Property::Map" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ARC )
+             .Add( Visual::Property::MIX_COLOR, Color::RED )
+             .Add( DevelArcVisual::Property::THICKNESS, 20.0f );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetArcVisual02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetArcVisual02: Request arc visual with a Property::Map" );
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ARC )
+             .Add( Visual::Property::MIX_COLOR, Color::RED )
+             .Add( DevelArcVisual::Property::THICKNESS, 20.0f )
+             .Add( DevelArcVisual::Property::START_ANGLE, 0.0f )
+             .Add( DevelArcVisual::Property::SWEEP_ANGLE, 90.0f )
+             .Add( DevelArcVisual::Property::CAP, DevelArcVisual::Cap::ROUND );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliArcVisualGetPropertyMap01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliArcVisualGetPropertyMap01" );
+
+  float thickness = 20.0f;
+  float startAngle = 0.0f, sweepAngle = 90.0f;
+
+  Property::Map propertyMap;
+  propertyMap.Add( "visualType", DevelVisual::ARC )
+             .Add( "mixColor", Color::RED )
+             .Add( "thickness", thickness )
+             .Add( "startAngle", startAngle )
+             .Add( "sweepAngle", sweepAngle )
+             .Add( "cap", DevelArcVisual::Cap::ROUND );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New( true );
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Map resultMap;
+  visual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Visual::Property::MIX_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector4 >(), Color::RED, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::THICKNESS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), thickness, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::START_ANGLE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), startAngle, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::SWEEP_ANGLE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), sweepAngle, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::CAP, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelArcVisual::Cap::ROUND );
+
+  // Test wrong values
+  propertyMap[DevelArcVisual::Property::THICKNESS] = "3.0f";
+  propertyMap[DevelArcVisual::Property::START_ANGLE] = "0.0f";
+  propertyMap[DevelArcVisual::Property::SWEEP_ANGLE] = "90.0f";
+  propertyMap[DevelArcVisual::Property::CAP] = "1";
+
+  visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  visual.CreatePropertyMap( resultMap );
+
+  value = resultMap.Find( DevelArcVisual::Property::THICKNESS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), 0.0f, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::START_ANGLE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), 0.0f, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::SWEEP_ANGLE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< float >(), 360.0f, TEST_LOCATION );
+
+  value = resultMap.Find( DevelArcVisual::Property::CAP, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == DevelArcVisual::Cap::BUTT );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AsyncImageLoader.cpp
new file mode 100644 (file)
index 0000000..ac4bcde
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2019 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 <stdlib.h>
+#include <unistd.h>
+#include <dali/dali.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 50*50, pixel format: RGBA8888
+static const char* gImage_50_RGBA = TEST_RESOURCE_DIR "/icon-delete.png";
+// resolution: 128*128, pixel format: RGB888
+static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+// for testing the ImageLoadedSignal
+class ImageLoadedSignalVerifier : public ConnectionTracker
+{
+public:
+
+  ImageLoadedSignalVerifier()
+  : mCount( 0 )
+  {}
+
+  virtual ~ImageLoadedSignalVerifier()
+  {}
+
+  void ImageLoaded( uint32_t id, PixelData pixelData )
+  {
+    mIDs.push_back( id );
+    mPixelDataList.push_back( pixelData );
+    mCount++;
+  }
+
+  int LoadedImageCount()
+  {
+    return mCount;
+  }
+
+  bool Verify( uint32_t id, uint32_t width, uint32_t height )
+  {
+    int size = mIDs.size();
+    for( int i = 0; i<size; i++  )
+    {
+      if( mIDs[i] == id )
+      {
+        return mPixelDataList[i].GetWidth() == width
+            && mPixelDataList[i].GetHeight() == height;
+      }
+    }
+
+    return false;
+  }
+
+private:
+
+  int mCount;
+
+  std::vector<uint32_t> mIDs;
+  std::vector<PixelData> mPixelDataList;
+};
+
+
+} // anonymous namespace
+
+void dali_async_image_loader_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_async_image_loader_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliImageAtlasNew01(void)
+{
+  ToolkitTestApplication application;
+
+  //invoke default handle constructor
+  AsyncImageLoader loader;
+
+  DALI_TEST_CHECK( !loader );
+
+  // initialise handle
+  loader = AsyncImageLoader::New();
+  DALI_TEST_CHECK( loader );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCopyConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New( );
+  DALI_TEST_CHECK( loader );
+
+  AsyncImageLoader loaderCopy(loader);
+  DALI_TEST_CHECK( loaderCopy );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderAssignmentOperator(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  DALI_TEST_CHECK( loader );
+
+  AsyncImageLoader loader2;
+  DALI_TEST_CHECK( !loader2 );
+
+  loader2 = loader;
+  DALI_TEST_CHECK( loader2 );
+  DALI_TEST_CHECK( loader == loader2 ); // the two handles are pointing to the same object.
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderDownCastP(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader asyncImageLoader = AsyncImageLoader::New();
+  BaseHandle object(asyncImageLoader);
+
+  AsyncImageLoader asyncImageLoader2 = AsyncImageLoader::DownCast( object );
+
+  DALI_TEST_CHECK( asyncImageLoader2 );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderDownCastN(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle unInitializedObject;
+  AsyncImageLoader asyncImageLoader = AsyncImageLoader::DownCast( unInitializedObject );
+
+  DALI_TEST_CHECK( !asyncImageLoader );
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderLoadAndLoadedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  ImageLoadedSignalVerifier loadedSignalVerifier;
+
+  loader.ImageLoadedSignal().Connect( &loadedSignalVerifier, &ImageLoadedSignalVerifier::ImageLoaded );
+
+  loader.Load( gImage_34_RGBA );
+  uint32_t id02 = loader.Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+  uint32_t id03 = loader.Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 3 );
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id02, 25, 25 ) );
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) );
+
+  END_TEST;
+}
+
+// Note: This is not an ideal test, but we cannot guarantee we can call Cancel() before the image has finished loading.
+int UtcDaliAsyncImageLoaderCancel(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+  ImageLoadedSignalVerifier loadedSignalVerifier;
+
+  loader.ImageLoadedSignal().Connect( &loadedSignalVerifier, &ImageLoadedSignalVerifier::ImageLoaded );
+
+  uint32_t id01 = loader.Load( gImage_34_RGBA, ImageDimensions( 34, 34 ) );
+  uint32_t id02 = loader.Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+  uint32_t id03 = loader.Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( loadedSignalVerifier.LoadedImageCount() == 3 );
+
+  DALI_TEST_CHECK( !loader.Cancel( id03 ) ); // Cannot cancel a task that is already implemeted
+
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id01, 34, 34 ) );   // first image is loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id02, 25, 25 ) );   // second image is loaded
+  DALI_TEST_CHECK( loadedSignalVerifier.Verify( id03, 100, 100 ) ); // third image is loaded
+
+  END_TEST;
+}
+
+int UtcDaliAsyncImageLoaderCancelAll(void)
+{
+  ToolkitTestApplication application;
+
+  AsyncImageLoader loader = AsyncImageLoader::New();
+
+  // Test that it is safe to call CancelAll even there is no loading task requested.
+  try
+  {
+    loader.CancelAll();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "AsyncImageLoader::LoadAll", TEST_LOCATION);
+  }
+
+  // Test that cancelling a non-existing loading task will return false
+  uint32_t id = 1;
+  DALI_TEST_CHECK( !(loader.Cancel( id )) );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-BloomView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-BloomView.cpp
new file mode 100644 (file)
index 0000000..b5a5942
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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-toolkit/devel-api/controls/bloom-view/bloom-view.h>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+
+void bloom_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void bloom_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Negative test case for a method
+int UtcDaliBloomViewUninitialized(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomViewUninitialized");
+
+  Toolkit::BloomView view;
+
+  try
+  {
+    // New() must be called to create a BloomView or it wont be valid.
+    Actor a = Actor::New();
+    view.Add( a );
+    DALI_TEST_CHECK( false );
+  }
+  catch (Dali::DaliException& e)
+  {
+    // Tests that a negative test of an assertion succeeds
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_CHECK(!view);
+  }
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliBloomViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomViewNew");
+
+  Toolkit::BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  Toolkit::BloomView view2 = Toolkit::BloomView::New(10, 1.0f, Pixel::RGB888, 0.5f, 0.5f);
+  DALI_TEST_CHECK( view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliBloomViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomViewDownCast");
+
+  Toolkit::BloomView view = Toolkit::BloomView::New();
+  BaseHandle handle(view);
+
+  Toolkit::BloomView bloomView = Toolkit::BloomView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( bloomView );
+  DALI_TEST_CHECK( bloomView == view );
+  END_TEST;
+}
+
+
+// Positive test case for a method
+int UtcDaliBloomViewPropertyNames(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomViewPropertyNames");
+
+  Toolkit::BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  // Check the names, this names are used in the shader code,
+  // if they change in the shader code, then it has to be updated here.
+  DALI_TEST_EQUALS( view.GetBloomThresholdPropertyIndex(), view.GetPropertyIndex("uBloomThreshold"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetBlurStrengthPropertyIndex(), view.GetPropertyIndex("BlurStrengthProperty"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetBloomIntensityPropertyIndex(), view.GetPropertyIndex("uBloomIntensity"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetBloomSaturationPropertyIndex(), view.GetPropertyIndex("uBloomSaturation"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetImageIntensityPropertyIndex(), view.GetPropertyIndex("uImageIntensity"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetImageSaturationPropertyIndex(), view.GetPropertyIndex("uImageSaturation"), TEST_LOCATION );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliBloomViewAddRemove(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomViewAddRemove");
+
+  Toolkit::BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(actor);
+  Stage::GetCurrent().Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+
+  view.Remove(actor);
+
+  DALI_TEST_CHECK( !actor.OnStage() );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliBloomActivateDeactivate(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBloomActivateDeactivate");
+
+  Toolkit::BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList.GetTaskCount() );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.Activate();
+
+  RenderTaskList taskList2 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u != taskList2.GetTaskCount() );
+
+  view.Deactivate();
+
+  RenderTaskList taskList3 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList3.GetTaskCount() );
+  END_TEST;
+}
+
+int UtcDaliBloomCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  BloomView view = Toolkit::BloomView::New();
+  DALI_TEST_CHECK( view );
+
+  BloomView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  BloomView assign;
+  DALI_TEST_CHECK( ! assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliBloomTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "BloomView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  BloomView view = BloomView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliBloomOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+
+  BloomView view = Toolkit::BloomView::New();
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 0.0f );
+  view.SetSize( size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-BubbleEmitter.cpp b/automated-tests/src/dali-toolkit/utc-Dali-BubbleEmitter.cpp
new file mode 100644 (file)
index 0000000..e8f0d98
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_bubble_emitter_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_bubble_emitter_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+namespace
+{
+
+const int RENDER_FRAME_INTERVAL = 16;
+
+static bool gObjectCreatedCallBackCalled;
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+static int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+static Texture CreateSolidColorTexture( ToolkitTestApplication& application, const Vector4& color, unsigned int width, unsigned int height )
+{
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height );
+  return texture;
+}
+}//namespace
+
+
+int UtcDaliBubbleEmitterNew(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliBubbleEmitterNew ");
+
+  // Test default constructor
+  BubbleEmitter emitter;
+  DALI_TEST_CHECK( !emitter );
+
+  // Test object creation
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+  DALI_TEST_CHECK( emitter );
+
+  // Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+
+  // Test copy constructor
+  BubbleEmitter emitterCopy( emitter );
+  DALI_TEST_CHECK( emitterCopy );
+
+  // Test down cast
+  Handle handleEmitter;
+  handleEmitter = emitter;
+  BubbleEmitter downCastEmitter = BubbleEmitter::DownCast( handleEmitter );
+  DALI_TEST_CHECK( downCastEmitter );
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterDownCast01(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliBubbleEmitterDownCast01 ");
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+
+  BaseHandle handle(emitter);
+  BubbleEmitter emitter2 = BubbleEmitter::DownCast(handle);
+  DALI_TEST_EQUALS( (bool)emitter2, true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterDownCast02(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliBubbleEmitterDownCast02 ");
+
+  Handle handle = Handle::New(); // Create a custom object
+  BubbleEmitter emitter = BubbleEmitter::DownCast(handle);
+  DALI_TEST_EQUALS( (bool)emitter, false, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterGetRootActor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterGetRootActor " );
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 270, Vector2( 5.f, 10.f ));
+
+  Actor root = emitter.GetRootActor();
+  DALI_TEST_CHECK( root );
+  DALI_TEST_CHECK( root.GetChildCount() == 0 );
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterSetBackground(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterSetBackground " );
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  unsigned int taskCount = taskList.GetTaskCount();
+
+  Texture bgImage = CreateSolidColorTexture( application, Color::RED, 50, 50 );
+  emitter.SetBackground( bgImage, Vector3(0.f, 0.f, 0.5f) );
+
+  DALI_TEST_CHECK( taskList.GetTaskCount() == taskCount+1 );
+
+  Wait(application, 500);
+  DALI_TEST_CHECK( taskList.GetTaskCount() == taskCount );
+  END_TEST;
+}
+
+//TODO: test case for BubbleEmitter::SetShapeImage(Image)
+// To test that the bubble-shape image is successfully switched in the sampler
+/*int UtcDaliBubbleEmitterSetShapeImage(void)
+{
+}*/
+
+int UtcDaliBubbleEmitterSetBubbleScale(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterSetBubbleScale " );
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 150, Vector2( 5.f, 10.f ));
+  DALI_TEST_CHECK(emitter);
+  Actor root = emitter.GetRootActor();
+  Stage::GetCurrent().Add( root );
+  root.SetPosition( Vector3::ZERO );
+  root.SetParentOrigin( ParentOrigin::CENTER );
+  root.SetAnchorPoint( AnchorPoint::CENTER );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Wait(application);
+
+  float scaleValue;
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uDynamicScale", scaleValue ) );
+  DALI_TEST_EQUALS( scaleValue, 1.f, TEST_LOCATION );
+
+  emitter.SetBubbleScale( 2.f );
+  Wait(application);
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uDynamicScale", scaleValue ) );
+  DALI_TEST_EQUALS( scaleValue, 2.f, TEST_LOCATION );
+
+  emitter.SetBubbleScale( 0.5f );
+  Wait(application);
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uDynamicScale", scaleValue ) );
+  DALI_TEST_EQUALS( scaleValue, 0.5f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterSetBubbleDensity01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterSetBubbleDensity " );
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+
+  try
+  {
+    emitter.SetBubbleDensity( 3.f );
+    DALI_TEST_CHECK(true);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_ASSERT(e, "density>0 && density<=9", TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterSetBubbleDensity02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterSetBubbleDensity " );
+
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage, 200, Vector2( 5.f, 10.f ));
+
+  try
+  {
+    emitter.SetBubbleDensity( 10.f );
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_ASSERT(e, "density>0 && density<=9", TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterEmitBubble(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterEmitBubble " );
+
+  Texture shapeImage1 = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( Vector2(50.f,50.f),shapeImage1, 200, Vector2( 5.f, 10.f ));
+
+  Actor root = emitter.GetRootActor();
+  Renderer bubbleRenderer = root.GetRendererAt( 0 );
+  Stage::GetCurrent().Add( root );
+  DALI_TEST_CHECK( bubbleRenderer );
+
+  Property::Index propertyIndex0 = bubbleRenderer.GetPropertyIndex( "uPercentage[0]" );
+  Property::Index propertyIndex1 = bubbleRenderer.GetPropertyIndex( "uPercentage[1]" );
+  float value0, value1;
+
+  Animation animation = Animation::New( 0.5f );
+  emitter.EmitBubble( animation, Vector2(40.f,40.f), Vector2(-5.f,-5.f), Vector2(30.f,30.f) );
+  emitter.EmitBubble( animation, Vector2(10.f,10.f), Vector2(5.f,5.f), Vector2(30.f,30.f) );
+  (bubbleRenderer.GetProperty(propertyIndex0)).Get( value0 );
+  (bubbleRenderer.GetProperty(propertyIndex1)).Get( value1 );
+  DALI_TEST_EQUALS(value0, 0.f, TEST_LOCATION );
+  DALI_TEST_EQUALS(value1, 0.f, TEST_LOCATION );
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value0 );
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value1 );
+  DALI_TEST_EQUALS(value0, 0.f, TEST_LOCATION );
+  DALI_TEST_EQUALS(value1, 0.f, TEST_LOCATION );
+
+  animation.Play();
+
+  Wait(application, 300);
+  propertyIndex0 = bubbleRenderer.GetPropertyIndex( "uPercentage[0]" );
+  propertyIndex1 = bubbleRenderer.GetPropertyIndex( "uPercentage[1]" );
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value0 );
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value1 );
+  DALI_TEST_CHECK( value0 >= 0.6f );
+  DALI_TEST_CHECK( value1 >= 0.6f );
+
+  Wait(application,500);
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value0 );
+  ( bubbleRenderer.GetCurrentProperty( propertyIndex0 ) ).Get( value1 );
+  DALI_TEST_EQUALS(value0, 1.f, TEST_LOCATION );
+  DALI_TEST_EQUALS(value1, 1.f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliBubbleEmitterRestore(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliBubbleEmitterRestore " );
+
+  Vector2 movementArea(50.f,50.f);
+  Texture shapeImage = CreateSolidColorTexture( application, Color::GREEN, 5, 5 );
+  BubbleEmitter emitter = BubbleEmitter::New( movementArea,shapeImage, 90, Vector2( 5.f, 10.f ));
+  Actor root = emitter.GetRootActor();
+  Stage::GetCurrent().Add( root );
+  root.SetPosition( Vector3::ZERO );
+  root.SetParentOrigin( ParentOrigin::CENTER );
+  root.SetAnchorPoint( AnchorPoint::CENTER );
+
+  Renderer renderer = root.GetRendererAt( 0 );
+  DALI_TEST_CHECK( renderer );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  float percentageValue;
+  Vector4 startEndPosValue;
+
+  Animation animation = Animation::New( 0.5f );
+  emitter.EmitBubble( animation, Vector2(40.f,40.f), Vector2(-5.f,-5.f), Vector2(30.f,30.f) );
+
+  Wait(application);
+
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uPercentage[0]", percentageValue ) );
+  DALI_TEST_EQUALS( percentageValue, 0.f, TEST_LOCATION );
+
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uStartEndPosition[0]", startEndPosValue ) );
+  DALI_TEST_EQUALS( startEndPosValue.x, 40.f - movementArea.x*0.5f, TEST_LOCATION );
+  DALI_TEST_EQUALS( startEndPosValue.y, 40.f- movementArea.x*0.5f, TEST_LOCATION );
+
+  animation.Play();
+  Wait(application, 200);
+  animation.Clear();
+
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uPercentage[0]", percentageValue ) );
+  DALI_TEST_CHECK( percentageValue < 0.5f && percentageValue >= 0.4);
+
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uStartEndPosition[0]", startEndPosValue ) );
+  DALI_TEST_EQUALS( startEndPosValue.x, 40.f- movementArea.x*0.5f, TEST_LOCATION );
+  DALI_TEST_EQUALS( startEndPosValue.y, 40.f- movementArea.x*0.5f, TEST_LOCATION );
+
+  emitter.Restore();
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "uPercentage[0]", percentageValue ) );
+  DALI_TEST_EQUALS( percentageValue, 0.f, TEST_LOCATION );
+
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uStartEndPosition[0]", startEndPosValue ) );
+  DALI_TEST_EQUALS( startEndPosValue,  Vector4::ZERO, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp
new file mode 100644 (file)
index 0000000..41c7153
--- /dev/null
@@ -0,0 +1,2030 @@
+/*
+ * Copyright (c) 2018 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 <iterator>
+#include <vector>
+#include <algorithm>
+#include <cstdlib>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <test-button.h>
+#include <test-animation-data.h>
+#include <dummy-control.h>
+
+
+#define STRINGIFY(A)#A
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace BuilderControlProperty
+{
+
+enum
+{
+  INTEGER_PROPERTY = Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1,
+  MATRIX3_PROPERTY,
+  MATRIX_PROPERTY,
+  NONE_PROPERTY
+};
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::Control::New();
+}
+
+int gSetPropertyCalledCount = 0;
+
+void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  ++gSetPropertyCalledCount;
+}
+
+Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  return Property::Value();
+}
+
+} // unnamed namespace
+
+// Properties
+Dali::TypeRegistration typeRegistration( "BuilderControl", typeid( Toolkit::Control ), Create );
+
+Dali::PropertyRegistration propertyInteger( typeRegistration, "integerProperty", INTEGER_PROPERTY, Property::INTEGER, &SetProperty, &GetProperty );
+Dali::PropertyRegistration propertyMatrix3( typeRegistration, "matrix3Property", MATRIX3_PROPERTY, Property::MATRIX3, &SetProperty, &GetProperty );
+Dali::PropertyRegistration propertyMatrix(  typeRegistration, "matrixProperty",  MATRIX_PROPERTY,  Property::MATRIX,  &SetProperty, &GetProperty );
+Dali::PropertyRegistration propertyNone(    typeRegistration, "noneProperty",    NONE_PROPERTY,    Property::NONE,    &SetProperty, &GetProperty );
+
+}
+
+namespace
+{
+
+struct BuilderFunctor
+{
+  BuilderFunctor( bool& called ) : mCalled( called )
+  {
+    mCalled = false;
+  }
+
+  void operator()()
+  {
+    mCalled = true;
+  }
+
+  bool& mCalled;
+};
+
+} // namespace
+
+
+
+void builder_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void builder_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliBuilderQuitSignal(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{"
+         "\"stage\":"
+         "[{"
+           "\"type\": \"Layer\","
+           "\"size\": [100,100,1],"
+           "\"parentOrigin\": \"TOP_LEFT\","
+           "\"anchorPoint\": \"TOP_LEFT\","
+           "\"maximumSize\": [100,100],"
+           "\"orientation\": [10,10,10,10],"
+           "\"clippingBox\": [10,10,10,10],"
+           "\"signals\": [{"
+             "\"name\": \"touch\","
+             "\"action\": \"quit\""
+           "}]"
+         "}]"
+      "}"
+  );
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Connect to builder's quit signal
+  bool functorCalled( false );
+  builder.QuitSignal().Connect( &application, BuilderFunctor( functorCalled ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+  DALI_TEST_CHECK( functorCalled );
+
+  END_TEST;
+}
+
+
+int UtcDaliBuilderAnimationP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+        "{"
+        "   \"constants\":"
+        "   {"
+        "     \"ALPHA_FUNCTION\":\"EASE_IN_OUT\""
+        "   },"
+        "   \"paths\":"
+        "   {"
+        "     \"path0\":"
+        "     {"
+        "       \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],"
+        "       \"curvature\":0.35"
+        "     }"
+        "   },"
+        "  \"animations\": {"
+        "    \"animate\": {"
+        "      \"loop\": true,"
+        "      \"endAction\": \"BAKE\","
+        "      \"disconnectAction\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"greeting\","
+        "        \"property\": \"position\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alphaFunction\": \"{ALPHA_FUNCTION}\","
+        "        \"relative\": true,"
+        "        \"timePeriod\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"visible\","
+        "         \"alphaFunction\": \"LINEAR\","
+        "         \"value\": true"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"sizeWidth\","
+        "         \"alphaFunction\": \"REVERSE\","
+        "         \"value\": 10.0"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_IN\","
+        "         \"value\": [10.0,20.0,30.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_OUT\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_IN_OUT\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_IN_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_OUT_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_IN_OUT_SINE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"BOUNCE\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"SIN\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       },"
+        "       {"
+        "         \"actor\": \"greeting\","
+        "         \"property\": \"orientation\","
+        "         \"alphaFunction\": \"EASE_OUT_BACK\","
+        "         \"value\": [0.0, 0.0, 0.0, 1.0]"
+        "       }"
+        "      ]"
+        "    },"
+        "    \"pathAnimation\": {"
+        "      \"duration\": 3.0,"
+        "      \"endAction\": \"DISCARD\","
+        "      \"disconnectAction\": \"BAKE_FINAL\","
+        "      \"properties\": [{"
+        "        \"actor\": \"greeting\","
+        "        \"path\":\"path0\","
+        "        \"forward\":[1,0,0],"
+        "        \"alphaFunction\": \"EASE_IN_OUT\","
+        "        \"timePeriod\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }]"
+        "    }"
+        "  },"
+        "  \"stage\": [{"
+        "    \"name\": \"greeting\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\","
+        "    \"inherit\": [\"basicText\"],"
+        "    \"position\": [0, -120, 0],"
+        "    \"size\": [200, 200, 1],"
+        "    \"orientation\": [0, 0, 30],"
+        "    \"signals\": [{"
+        "      \"name\": \"touch\","
+        "      \"action\": \"play\","
+        "      \"animation\": \"animate\""
+        "    }]"
+        "  }]"
+        "}");
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+  Animation anim = builder.CreateAnimation("animate");
+
+  DALI_TEST_CHECK( anim );
+
+  Property::Map map;
+  map["ALPHA_FUNCTION"] = "EASE_IN_SQUARE";
+  anim = builder.CreateAnimation("animate", map);
+
+  DALI_TEST_CHECK( anim );
+
+  anim = builder.CreateAnimation("pathAnimation");
+
+  DALI_TEST_CHECK( anim );
+
+  // trigger play
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+
+  END_TEST;
+}
+
+int UtcDaliBuilderAnimationN(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+        "{"
+        "   \"constants\":"
+        "   {"
+        "     \"TEXT\": \"Touch Me\","
+        "     \"NAME\": \"greeting\" "
+        "   },"
+        "   \"paths\":"
+        "   {"
+        "     \"path0\":"
+        "     {"
+        "       \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],"
+        "       \"curvature\":0.35"
+        "     }"
+        "   },"
+        "  \"animations\": {"
+        "    \"animate\": {"
+        "      \"loop\": true,"
+        "      \"endAction\": \"BAKE\","
+        "      \"disconnectAction\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"{NAME}\","
+        "        \"property\": \"positioninvalid\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alphaFunction\": \"EASE_IN_OUT\","
+        "        \"relative\": true,"
+        "        \"timePeriod\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }"
+        "      ]"
+        "    },"
+        "    \"animate2\": {"
+        "      \"loop\": true,"
+        "      \"endAction\": \"BAKE\","
+        "      \"disconnectAction\": \"BAKE\","
+        "      \"properties\":"
+        "      [{"
+        "        \"actor\": \"{NAME}\","
+        "        \"property\": \"positioninvalid\","
+        "        \"value\": [300, 300, -1000],"
+        "        \"alphaFunction\": \"EGGS_OVER_EASY\","
+        "        \"relative\": true,"
+        "        \"timePeriod\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }"
+        "      ]"
+        "    },"
+        "    \"pathAnimation\": {"
+        "      \"duration\": 3.0,"
+        "      \"endAction\": \"DISCARD\","
+        "      \"disconnectAction\": \"BAKE_FINAL\","
+        "      \"properties\": [{"
+        "        \"actor\": \"greeting\","
+        "        \"path\":\"pathDoesntExist\","
+        "        \"forward\":[1,0,0],"
+        "        \"alphaFunction\": \"EASE_IN_OUT\","
+        "        \"timePeriod\": {"
+        "          \"delay\": 0,"
+        "          \"duration\": 3"
+        "        }"
+        "      }]"
+        "    }"
+        "  },"
+        "  \"stage\": [{"
+        "    \"name\": \"greeting\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\","
+        "    \"inherit\": [\"basicText\"],"
+        "    \"position\": [0, -120, 0],"
+        "    \"size\": [200, 200, 1],"
+        "    \"orientation\": [0, 0, 30],"
+        "    \"signals\": [{"
+        "      \"name\": \"touch\","
+        "      \"action\": \"play\","
+        "      \"animation\": \"animate\""
+        "    }]"
+        "  },"
+        "  {"
+        "    \"name\": \"greeting2\","
+        "    \"type\": \"TextLabel\","
+        "    \"text\": \"Touch me\""
+        "  }]"
+        "}");
+
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+  Animation anim = builder.CreateAnimation("animate");
+
+  // log warning line coverage
+  anim = builder.CreateAnimation("pathAnimation");
+  DALI_TEST_CHECK(anim);
+
+  anim = builder.CreateAnimation("animate");
+  DALI_TEST_CHECK(anim);
+
+  anim = builder.CreateAnimation("animate2");
+  DALI_TEST_CHECK(anim);
+
+  // create referencing a different actor aka animation templates
+  Property::Map map;
+  map["NAME"] = "greeting2";
+  anim = builder.CreateAnimation("animate2", map);
+  DALI_TEST_CHECK(anim);
+
+  // alternative actor to use for FindChildByName
+  anim = builder.CreateAnimation("animate2", Dali::Stage::GetCurrent().GetRootLayer());
+  DALI_TEST_CHECK(anim);
+
+  // alternative actor to use for FindChildByName
+  anim = builder.CreateAnimation("animate2", map, Dali::Stage::GetCurrent().GetRootLayer());
+  DALI_TEST_CHECK(anim);
+
+
+  END_TEST;
+
+}
+
+int UtcDaliBuilderConstantsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{"
+      "\"constants\":"
+      "{"
+      "  \"IMAGE_PATH\": \"apath\","
+      "  \"WIDTH\": 22.3,"
+      "  \"ANCHOR\": \"TOP_LEFT\","
+      "  \"PADDING\": [1,2,3,4]"
+      "},"
+      "\"stage\":"
+      "[{"
+      "  \"type\": \"ImageView\","
+      "  \"name\": \"{NAME}\","
+      "  \"size\": [100,100,1],"
+      "  \"parentOrigin\": \"TOP_LEFT\","
+      "  \"anchorPoint\": \"{ANCHOR}\","
+      "  \"padding\": \"{PADDING}\","
+      "  \"image\": { \"url\": \"dir/{IMAGE_PATH}\" },"
+      "  \"sizeWidth\": \"{WIDTH}\","
+      "  \"signals\": [{"
+      "    \"name\": \"touch\","
+      "    \"action\": \"quit\""
+      "  }]"
+      "}]"
+      "}"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  builder.AddConstant( "NAME", "image" );
+
+  Property::Map map = builder.GetConstants();
+
+  Dali::Property::Value* pValue = map.Find( "NAME" );
+
+  DALI_TEST_CHECK( pValue );
+
+  pValue = map.Find( "IMAGE_PATH" );
+
+  DALI_TEST_CHECK( pValue );
+
+  Dali::Property::Value value = builder.GetConstant( "WIDTH" );
+
+  DALI_TEST_CHECK( value.GetType() != Property::NONE );
+
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+  DALI_TEST_CHECK( builder );
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("image");
+  DALI_TEST_CHECK( actor );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderTemplatesAndStylesP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "\"constants\":"
+      "{"
+      "  \"SIZE\": [10,20,30]"
+      "},"
+      "\"styles\":\n"
+      "{\n"
+      "  \"imageStyle\": \n"
+      "  {\n"
+      "    \"color\": [1,0,0,1],\n"
+      "    \"actors\": {\n"
+      "      \"childImage\": {\n"
+      "        \"color\": \"34\"\n"
+      "      }\n"
+      "    }\n"
+      "  }\n"
+      "},\n"
+      "\"templates\":\n"
+      "{\n"
+      "  \"imageViewTemplate\": { \n"
+      "    \"type\": \"ImageView\",\n"
+      "    \"styles\": [\"imageStyle\"]\n"
+      "  },\n"
+      "  \"imageTree\": { \n"
+      "    \"type\": \"ImageView\",\n"
+      "    \"styles\": [\"imageStyle\"],\n"
+      "    \"name\": \"image\",\n"
+      "    \"size\": \"{SIZE}\",\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"quit\"\n"
+      "    }],\n"
+      "    \"actors\": [\n"
+      "      {\n"
+      "        \"type\":\"ImageView\",\n"
+      "        \"name\":\"childImage\", \n"
+      "        \"color\": \n"
+      "          {\n"
+      "            \"r\": 10,\n"
+      "            \"g\": 10,\n"
+      "            \"b\": 10,\n"
+      "            \"a\": 100\n"
+      "          }\n"
+      "      },\n"
+      "      {\n"
+      "        \"type\":\"imageViewTemplate\",\n"
+      "        \"name\":\"childImage2\"\n"
+      "      }\n"
+      "    ]\n"
+      "  }\n"
+      "},\n"
+      "\"stage\":"
+      "[{"
+      "  \"type\": \"imageTree\","
+      "  \"size\": [100,100,1]"
+      "}]"
+      "}\n"
+  );
+
+  std::string stylejson(
+    "{\n"
+    " \"color\": [1,0,0,1],\n"
+    " \"actors\": {\n"
+    "   \"childImage\": {\n"
+    "     \"color\": \"#344353\"\n"
+    "   }\n"
+    " }\n"
+    "}\n"
+    );
+
+  std::string templatejson(
+    "{ \n"
+    "  \"type\": \"ImageView\",\n"
+    "  \"styles\": [\"imageStyle\"],\n"
+    "  \"name\": \"image\",\n"
+    "  \"size\": \"{SIZE}\",\n"
+    "  \"signals\": [{\n"
+    "    \"name\": \"touch\",\n"
+    "    \"action\": \"quit\"\n"
+    "  }],\n"
+    "  \"actors\": [\n"
+    "    {\n"
+    "      \"type\":\"ImageView\",\n"
+    "      \"name\":\"childImage\" \n"
+    "    }\n"
+    "  ]\n"
+    "}\n"
+    );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  ImageView actor = ImageView::DownCast( builder.Create( "imageTree" ) );
+  DALI_TEST_CHECK( actor );
+
+  Dali::Property::Map map;
+  map["SIZE"] = Vector3(100,100,1);
+  actor = ImageView::DownCast( builder.Create( "imageTree",  map ) );
+  DALI_TEST_CHECK( actor );
+
+  // create from json snippet
+  actor = ImageView::DownCast( builder.CreateFromJson( templatejson ) );
+  DALI_TEST_CHECK( actor );
+
+
+  // NB: already applied in create
+  DALI_TEST_CHECK( builder.ApplyStyle( "imageStyle",  actor ) );
+
+  // apply from json snippet
+  DALI_TEST_CHECK( builder.ApplyFromJson( actor, stylejson ) );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderRenderTasksP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "\"renderTasks\":\n"
+      "{\n"
+      "  \"task0\": {\n"
+      "    \"sourceActor\": \"image\",\n"
+      "    \"cameraActor\": \"camera\" \n"
+      "  }\n"
+      "},\n"
+      "\"stage\":\n"
+      "[\n"
+      "  { \n"
+      "    \"type\": \"CameraActor\",\n"
+      "    \"name\": \"camera\"\n"
+      "  }, \n"
+      "  { \n"
+      "    \"type\": \"ImageView\",\n"
+      "    \"name\": \"image\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"quit\"\n"
+      "    }],\n"
+      "    \"actors\": [\n"
+      "      {\n"
+      "        \"type\":\"ImageView\",\n"
+      "        \"name\":\"childImage\" \n"
+      "      }\n"
+      "    ]\n"
+      "  }\n"
+      "]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  unsigned int count = Stage::GetCurrent().GetRenderTaskList().GetTaskCount();
+
+  // coverage
+  builder.CreateRenderTask( "task0" );
+
+  DALI_TEST_CHECK( count <
+                   Stage::GetCurrent().GetRenderTaskList().GetTaskCount() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderChildActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parentOrigin\": \"TOP_LEFT\",\n"
+      "    \"anchorPoint\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"subActor\"\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"hide\",\n"
+      "      \"actor\": \"actor\",\n"
+      "      \"childActor\": \"subActor\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("subActor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderSetPropertyActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parentOrigin\": \"TOP_LEFT\",\n"
+      "    \"anchorPoint\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"subActor\"\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"set\",\n"
+      "      \"actor\": \"subActor\",\n"
+      "      \"property\": \"visible\",\n"
+      "      \"value\": false\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("subActor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderGenericActionP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parentOrigin\": \"TOP_LEFT\",\n"
+      "    \"anchorPoint\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"subActor\"\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"hide\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("actor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderPropertyNotificationP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parentOrigin\": \"TOP_LEFT\",\n"
+      "    \"anchorPoint\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"subActor\"\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"hide\"\n"
+      "    }],\n"
+      "    \"notifications\": [{\n"
+      "      \"property\": \"visible\",\n"
+      "      \"condition\": \"False\",\n"
+      "      \"action\": \"show\"\n"
+      "    },\n"
+      "    {\n"
+      "      \"property\": \"positionX\",\n"
+      "      \"condition\": \"LessThan\",\n"
+      "      \"arg0\": 0.0,\n"
+      "      \"action\": \"show\"\n"
+      "    },\n"
+      "    {\n"
+      "      \"property\": \"positionY\",\n"
+      "      \"condition\": \"GreaterThan\",\n"
+      "      \"arg0\": 200.0,\n"
+      "      \"action\": \"show\"\n"
+      "    },\n"
+      "    {\n"
+      "      \"property\": \"positionZ\",\n"
+      "      \"condition\": \"Inside\",\n"
+      "      \"arg0\": 0.0,\n"
+      "      \"arg1\": 10.0,\n"
+      "      \"action\": \"show\"\n"
+      "    },\n"
+      "    {\n"
+      "      \"property\": \"positionZ\",\n"
+      "      \"condition\": \"Outside\",\n"
+      "      \"arg0\": 40.0,\n"
+      "      \"arg1\": 50.0,\n"
+      "      \"action\": \"show\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Emit touch event and check that our quit method is called
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  touchEvent.points.push_back( point );
+  application.ProcessEvent( touchEvent );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("actor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderPropertyNotificationN(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"stage\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"notifications\": [{\n"
+      "      \"property\": \"visible\",\n"
+      "      \"condition\": \"ErrorCondition\",\n"
+      "      \"action\": \"show\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  try
+  {
+    Builder builder = Builder::New();
+    builder.LoadFromString( json );
+    builder.AddActors ( Stage::GetCurrent().GetRootLayer() );
+    DALI_TEST_CHECK( false );
+  }
+  catch(...)
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+
+
+int UtcDaliBuilderCustomPropertyP(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"
+      "    \"name\": \"image\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"quit\"\n"
+      "    }],\n"
+      "    \"properties\": {\n"
+      "      \"newproperty\": true\n"
+      "    },\n"
+      "    \"animatableProperties\": {\n"
+      "      \"newAnimatableproperty\": 3\n"
+      "    },\n"
+      "    \"actors\": [\n"
+      "      {\n"
+      "        \"type\":\"ImageView\",\n"
+      "        \"name\":\"childImage\" \n"
+      "      }\n"
+      "    ]\n"
+      "  }\n"
+      "}\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  ImageView actor = ImageView::DownCast( builder.Create( "imageTree" ) );
+  DALI_TEST_CHECK( actor );
+
+  // NB: already applied in create
+  Property::Index index = actor.GetPropertyIndex("newproperty");
+  DALI_TEST_CHECK( Property::INVALID_INDEX != index );
+  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 UtcDaliBuilderCustomShaderP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"ImageView\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"position\": [\n"
+    "        0.40461349487305,\n"
+    "        0.9150390625,\n"
+    "        0.0\n"
+    "      ],\n"
+    "      \"parentOrigin\": [0.5, 0.5, 0.5],\n"
+    "      \"size\": [200, 200, 0],\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": {\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"
+    "          \"name\": \"onStage\",\n"
+    "          \"action\": \"play\",\n"
+    "          \"animation\": \"Animation_1\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  ],\n"
+    "  \"animations\": {\n"
+    "    \"Animation_1\": {\n"
+    "      \"loop\":true,\n"
+    "      \"properties\": [\n"
+    "        {\n"
+    "          \"actor\": \"Image1\",\n"
+    "          \"property\": \"uTime\",\n"
+    "          \"value\": 10.0,\n"
+    "          \"alphaFunction\": \"LINEAR\",\n"
+    "          \"timePeriod\": {\n"
+    "            \"delay\": 0,\n"
+    "            \"duration\": 10.0\n"
+    "          }\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  }\n"
+    "}\n"
+
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  builder.AddActors ( "stage", Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("Image1");
+
+  // coverage
+  DALI_TEST_CHECK( actor );
+
+  END_TEST;
+}
+
+
+int UtcDaliBuilderLoadFromStringN(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "asdfsadf dsf asdf asdf {"
+         "\"stage\":"
+         "[{"
+           "\"type\": \"Actor\","
+           "\"size\": [100,100,1],"
+           "\"parentOrigin\": \"TOP_LEFT\","
+           "\"anchorPoint\": \"TOP_LEFT\","
+           "\"signals\": [{"
+             "\"name\": \"touch\","
+             "\"action\": \"quit\""
+           "}]"
+         "}]"
+      "}"
+  );
+  Builder builder = Builder::New();
+
+  bool assert1 = false;
+
+  try
+  {
+    builder.LoadFromString( json );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "!\"Cannot parse JSON\"", TEST_LOCATION);
+    assert1 = true;
+  }
+
+  DALI_TEST_CHECK( assert1 );
+
+  END_TEST;
+}
+
+
+int UtcDaliBuilderAddActorsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"arbitarysection\":\n"
+      "  [{\n"
+      "    \"type\": \"Actor\",\n"
+      "    \"name\": \"actor\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"parentOrigin\": \"TOP_LEFT\",\n"
+      "    \"anchorPoint\": \"TOP_LEFT\",\n"
+      "    \"actors\": [{\n"
+      "      \"type\": \"Actor\",\n"
+      "      \"name\": \"subActor\",\n"
+      "      \"visible\": false\n"
+      "    }],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"hide\",\n"
+      "      \"actor\": \"actor\",\n"
+      "      \"childActor\": \"subActor\"\n"
+      "    }]\n"
+      "  }]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors ( "arbitarysection", Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("subActor");
+  DALI_TEST_CHECK( actor );
+
+  DALI_TEST_CHECK( !actor.IsVisible() );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderPathConstraintsP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+    "{\n"
+    "  \"constants\":\n"
+    "  {\n"
+    "    \"FB_WIDTH\": 200.0,\n"
+    "    \"FB_HEIGHT\": 200.0,\n"
+    "    \"FB_SIZE\": [200,200],\n"
+    "    \"FB_ASPECT_RATIO\": 1\n"
+    "  },\n"
+    "  \"stage\": [\n"
+    "    {\n"
+    "      \"type\": \"ImageView\",\n"
+    "      \"name\": \"Image1\",\n"
+    "      \"size\": [200, 200, 0],\n"
+    "      \"parentOrigin\": [0.5, 0.5, 0.5],\n"
+    "      \"effect\": \"Ripple2D\",\n"
+    "      \"image\": {\n"
+    "        \"url\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\"\n"
+    "      },\n"
+    "      \"signals\": [\n"
+    "        {\n"
+    "          \"name\": \"onStage\",\n"
+    "          \"action\": \"play\",\n"
+    "          \"animation\": \"pathAnimation\"\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"onStage\",\n"
+    "          \"action\": \"applyConstraint\",\n"
+    "          \"constrainer\": \"constrainer0\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"positionX\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"colorRed\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"onStage\",\n"
+    "          \"action\": \"applyConstraint\",\n"
+    "          \"constrainer\": \"constrainer1\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"positionX\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"colorBlue\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"offStage\",\n"
+    "          \"action\": \"removeConstraints\",\n"
+    "          \"constrainer\": \"constrainer0\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"positionX\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"colorRed\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        },\n"
+    "        {\n"
+    "          \"name\": \"offStage\",\n"
+    "          \"action\": \"removeConstraints\",\n"
+    "          \"constrainer\": \"constrainer1\",\n"
+    "          \"properties\":\n"
+    "          [\n"
+    "            {\n"
+    "              \"source\": \"Image1\",\n"
+    "              \"sourceProperty\": \"positionX\",\n"
+    "              \"target\": \"Image1\",\n"
+    "              \"targetProperty\": \"colorBlue\",\n"
+    "              \"range\": [-300,300]\n"
+    "            }\n"
+    "          ]\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  ],\n"
+    "  \"paths\":\n"
+    "  {\n"
+    "    \"path0\":\n"
+    "    {\n"
+    "      \"points\":[ [-150, -50, 0], [0.0,70.0,0.0], [190.0,-150.0,0.0] ],\n"
+    "      \"curvature\":0.35\n"
+    "    }\n"
+    "  },\n"
+    "  \"constrainers\":\n"
+    "  {\n"
+    "    \"constrainer0\":\n"
+    "    {\n"
+    "      \"type\": \"PathConstrainer\",\n"
+    "      \"points\": [ [0, 0, 0], [0,0,0], [0,0,0] ],\n"
+    "      \"controlPoints\": [ [0, 0, 0], [0,0,0], [0,0,0] ]\n"
+    "    },\n"
+    "    \"constrainer1\":\n"
+    "    {\n"
+    "      \"type\": \"LinearConstrainer\",\n"
+    "      \"value\": [ 0, 0, 0 ]\n"
+    "    }\n"
+    "  },\n"
+    "  \"animations\": {\n"
+    "    \"pathAnimation\": {\n"
+    "      \"duration\": 3.0,\n"
+    "      \"properties\":\n"
+    "      [{\n"
+    "        \"actor\": \"Image1\",\n"
+    "        \"path\":\"path0\",\n"
+    "        \"forward\":[1,0,0],\n"
+    "        \"alphaFunction\": \"EASE_IN_OUT\",\n"
+    "        \"timePeriod\": {\n"
+    "          \"delay\": 0,\n"
+    "          \"duration\": 3\n"
+    "        }\n"
+    "      },\n"
+    "       {\n"
+    "         \"actor\": \"Image1\",\n"
+    "         \"property\": \"uTime\",\n"
+    "         \"value\": 10.0,\n"
+    "         \"alphaFunction\": \"LINEAR\",\n"
+    "         \"timePeriod\": {\n"
+    "           \"delay\": 0,\n"
+    "           \"duration\": 10.0\n"
+    "         },\n"
+    "         \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "       }]\n"
+    "    },\n"
+    "    \"Animation_1\": {\n"
+    "      \"loop\":true,\n"
+    "      \"properties\": [\n"
+    "        {\n"
+    "          \"actor\": \"Image1\",\n"
+    "          \"property\": \"uTime\",\n"
+    "          \"value\": 10.0,\n"
+    "          \"alphaFunction\": \"LINEAR\",\n"
+    "          \"timePeriod\": {\n"
+    "            \"delay\": 0,\n"
+    "            \"duration\": 10.0\n"
+    "          },\n"
+    "          \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "        }\n"
+    "      ]\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+
+  Builder builder = Builder::New();
+
+  // frame buffer coverage
+  builder.LoadFromString( json );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Dali::Path path =  builder.GetPath( "path0" );
+  DALI_TEST_CHECK( path );
+
+  Dali::Path path2 =  builder.GetPath( "path0" );
+  DALI_TEST_CHECK( path2 );
+  DALI_TEST_CHECK( path == path2 );
+
+  Dali::PathConstrainer constrainer0 = builder.GetPathConstrainer( "constrainer0" );
+  DALI_TEST_CHECK( constrainer0 );
+
+  Dali::PathConstrainer constrainer0_2 = builder.GetPathConstrainer( "constrainer0" );
+  DALI_TEST_CHECK( constrainer0_2 );
+  DALI_TEST_CHECK( constrainer0 == constrainer0_2 );
+
+  Dali::LinearConstrainer constrainer1 = builder.GetLinearConstrainer( "constrainer1" );
+  DALI_TEST_CHECK( constrainer1 );
+
+  Dali::LinearConstrainer constrainer1_2 = builder.GetLinearConstrainer( "constrainer1" );
+  DALI_TEST_CHECK( constrainer1 == constrainer1_2 );
+
+  // For coverage
+
+  Actor actor = Actor::New();
+  Stage::GetCurrent().Add( actor );
+  builder.AddActors( actor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  actor.GetChildAt( 0 ).Unparent();
+
+  END_TEST;
+}
+
+#define CHECK_MAP_ELEMENT( xMap, xKey, xType, xPropType, xExpected, xLocation ) \
+  {                                                                       \
+    Property::Value* value = xMap->Find( xKey );                          \
+    DALI_TEST_EQUALS( value==NULL, false, xLocation);                     \
+    if( value != NULL )                                                   \
+    {                                                                     \
+      DALI_TEST_EQUALS( value->GetType(), xPropType, xLocation );         \
+      xType result;                                                       \
+      value->Get(result);                                                 \
+      DALI_TEST_EQUALS( result, xExpected, TEST_LOCATION );               \
+      std::ostringstream oss;                                             \
+      oss << "Animation element " << xKey << "= " << result << std::endl; \
+      tet_printf( oss.str().c_str() );                                    \
+    }                                                                     \
+    else                                                                  \
+    {                                                                     \
+      tet_printf("Can't find map element " xKey "\n");                    \
+    }                                                                     \
+  }
+
+
+int UtcDaliBuilderMapping01(void)
+{
+  ToolkitTestApplication application;
+
+  const char* json =
+    "{\n"
+    "  \"mappings\":\n"
+    "  {\n"
+    "    \"buttonPressFadeOut\":{\n"
+    "      \"alphaFunction\":\"EASE_OUT\",\n"
+    "      \"timePeriod\":{\n"
+    "        \"delay\":0.0,\n"
+    "        \"duration\":0.4\n"
+    "      }\n"
+    "    },\n"
+    "    \"buttonPressFadeIn\":{\n"
+    "      \"alphaFunction\":\"EASE_IN\",\n"
+    "      \"timePeriod\":{\n"
+    "        \"delay\":0.4,\n"
+    "        \"duration\":0.5\n"
+    "      }\n"
+    "    },\n"
+    "    \"transition:buttonPressed\":\n"
+    "    [\n"
+    "      {\n"
+    "        \"target\": \"unselectedBackgroundRenderer\",\n"
+    "        \"property\": \"opacity\",\n"
+    "        \"value\": 0,\n"
+    "        \"animator\":\"<buttonPressFadeOut>\"\n"
+    "      }\n"
+    "    ],\n"
+    "    \"transition:buttonReleased\":\n"
+    "    [\n"
+    "      {\n"
+    "        \"target\": \"unselectedBackgroundRenderer\",\n"
+    "        \"property\": \"opacity\",\n"
+    "        \"value\": 1,\n"
+    "        \"animator\":\"<buttonPressFadeIn>\"\n"
+    "      },\n"
+    "      {\n"
+    "        \"target\": \"unselectedForegroundRenderer\",\n"
+    "        \"property\": \"scale\",\n"
+    "        \"value\": [ 1, 1, 1 ],\n"
+    "        \"animator\":\"<buttonPressFadeIn>\"\n"
+    "      },\n"
+    "      {\n"
+    "        \"target\": \"selectedBackgroundRenderer\",\n"
+    "        \"property\": \"opacity\",\n"
+    "        \"value\": 0,\n"
+    "        \"animator\": \"<buttonPressFadeOut>\"\n"
+    "      },\n"
+    "      {\n"
+    "        \"target\": \"selectedForegroundRenderer\",\n"
+    "        \"property\": \"scale\",\n"
+    "        \"value\": [ 0, 0, 0 ],\n"
+    "        \"animator\":\"<buttonPressFadeOut>\"\n"
+    "      }\n"
+    "    ]\n"
+    "  },\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"pressTransition\":\"<transition:buttonPressed>\",\n"
+    "      \"releaseTransition\":\"<transition:buttonReleased>\"\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  Test::TestButton testButton = Test::TestButton::New();
+  Stage::GetCurrent().Add( testButton );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( builder.ApplyStyle( "testbutton", testButton ) );
+
+  // Now check that it has loaded the transition correctly:
+  Property::Value transition = testButton.GetProperty(Test::TestButton::Property::PRESS_TRANSITION);
+  DALI_TEST_EQUALS( transition.GetType(), Property::ARRAY, TEST_LOCATION );
+  Property::Array* array = transition.GetArray();
+
+  DALI_TEST_EQUALS( array->Size(), 1, TEST_LOCATION );
+  Property::Value element = array->GetElementAt(0);
+  DALI_TEST_CHECK( element.GetType() == Property::MAP );
+  Property::Map* map = element.GetMap();
+
+  CHECK_MAP_ELEMENT(map, "target", std::string, Property::STRING, "unselectedBackgroundRenderer", TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "property", std::string, Property::STRING, "opacity", TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "alphaFunction", int, Property::INTEGER, (int)Dali::AlphaFunction::EASE_OUT, TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "timePeriodDelay", float, Property::FLOAT, 0.0f, TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "timePeriodDuration", float, Property::FLOAT, 0.4f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliBuilderMappingCycleCheck(void)
+{
+  ToolkitTestApplication application;
+
+  std::string json(
+    "{\n"
+    "  \"mappings\":\n"
+    "  {\n"
+    "    \"cyclicKey1\":\"<cyclicKey1>\",\n"
+    "    \"cyclicKey2\":\"<cyclicKey3>\",\n"
+    "    \"cyclicKey3\":\"<cyclicKey2>\",\n"
+    "    \"FadeOut\":{\n"
+    "      \"alphaFunction\":\"EASE_IN\",\n"
+    "      \"timePeriod\":{\n"
+    "        \"delay\":\"<cyclicKey3>\",\n"
+    "        \"duration\":0.6\n"
+    "      }\n"
+    "    },\n"
+    "    \"transition:buttonPressed\":\n"
+    "    [\n"
+    "      {\n"
+    "        \"target\": \"<cyclicKey1>\",\n"
+    "        \"property\": \"<cyclicKey2>\",\n"
+    "        \"value\": 0,\n"
+    "        \"animator\":\"<FadeOut>\"\n"
+    "      }\n"
+    "    ]\n"
+    "  },\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"pressTransition\":\"<transition:buttonPressed>\",\n"
+    "      \"releaseTransition\":\"<cyclicKey2>\",\n"
+    "      \"disabledTransition\":\"<cyclicKey3>\",\n"
+    "      \"enabledTransition\":\"<unknownKey>\"\n"
+    "    }\n"
+    "  }\n"
+    "}\n");
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  Test::TestButton testButton = Test::TestButton::New();
+  Stage::GetCurrent().Add( testButton );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( builder.ApplyStyle( "testbutton", testButton ) );
+
+  // Now check that it has loaded the transition correctly:
+  Property::Value transition = testButton.GetProperty(Test::TestButton::Property::PRESS_TRANSITION);
+  DALI_TEST_EQUALS( transition.GetType(), Property::ARRAY, TEST_LOCATION );
+  Property::Array* array = transition.GetArray();
+
+  DALI_TEST_EQUALS( array->Size(), 1, TEST_LOCATION );
+  Property::Value element = array->GetElementAt(0);
+  DALI_TEST_CHECK( element.GetType() == Property::MAP );
+  Property::Map* map = element.GetMap();
+
+  CHECK_MAP_ELEMENT(map, "target", std::string, Property::STRING, "", TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "property", std::string, Property::STRING, "", TEST_LOCATION);
+  CHECK_MAP_ELEMENT(map, "timePeriodDuration", float, Property::FLOAT, 0.6f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliBuilderTypeCasts(void)
+{
+  ToolkitTestApplication application;
+
+  std::string json(
+    "{"
+       "\"stage\":"
+       "[{"
+         "\"type\": \"Layer\","
+         "\"maximumSize\": { \"typeCast\":\"vector2\", \"value\":[100,15] },"
+         "\"position\":    { \"typeCast\":\"vector3\", \"value\":[100,10,1] },"
+         "\"color\":       { \"typeCast\":\"vector4\", \"value\":[0.5,0.5,0.5,1] },"
+         "\"sensitive\":   { \"typeCast\":\"boolean\", \"value\":false },"
+         "\"orientation\": { \"typeCast\":\"rotation\", \"value\":[10,10,10,10] },"
+         "\"colorMode\":   { \"typeCast\":\"string\", \"value\":\"USE_OWN_MULTIPLY_PARENT_COLOR\" },"
+         "\"clippingBox\": { \"typeCast\":\"rect\", \"value\":[10,10,10,10] },"
+         "\"padding\":     { \"typeCast\":\"extents\", \"value\":[10,10,10,10] }"
+      "}]"
+    "}"
+  );
+
+  Actor rootActor = Actor::New();
+  Stage::GetCurrent().Add( rootActor );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( rootActor );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor createdActor = rootActor.GetChildAt( 0 );
+  DALI_TEST_EQUALS( createdActor.GetMaximumSize(), Vector2(100.0f,15.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( createdActor.GetCurrentPosition(), Vector3(100.0f,10.0f,1.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( createdActor.GetCurrentColor(), Vector4(0.5f,0.5f,0.5f,1.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( createdActor.IsSensitive(), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( createdActor.GetColorMode(), USE_OWN_MULTIPLY_PARENT_COLOR, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderBuilderControl(void)
+{
+  ToolkitTestApplication application;
+
+  std::string json(
+    "{"
+       "\"stage\":"
+       "[{"
+         "\"type\": \"BuilderControl\","
+         "\"integerProperty\": 10,"
+         "\"matrix3Property\": [ 1,2,3,4,5,6,7,8,9 ],"
+         "\"matrixProperty\":  [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 ],"
+         "\"noneProperty\": 10"
+      "}]"
+    "}"
+  );
+
+  Actor rootActor = Actor::New();
+  Stage::GetCurrent().Add( rootActor );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( rootActor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( BuilderControlProperty::gSetPropertyCalledCount, 4, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliBuilderCustomControl(void)
+{
+  ToolkitTestApplication application;
+
+  std::string json(
+    "{"
+       "\"stage\":"
+       "[{"
+         "\"type\": \"DummyControl\","
+         "\"name\": \"I can haz custom Control\""
+      "}]"
+    "}"
+  );
+
+  Actor rootActor = Actor::New();
+  Stage::GetCurrent().Add( rootActor );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( rootActor );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor customControl = rootActor.FindChildByName( "I can haz custom Control" );
+
+  // Test that we have the correct type of custom control
+  DummyControl dummyControl = DummyControl::DownCast( customControl );
+  DALI_TEST_CHECK( dummyControl );
+  if( dummyControl )
+  {
+    DALI_TEST_CHECK( typeid(dummyControl.GetImplementation()) == typeid(DummyControlImpl) );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliBuilderActionsWithParams(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "\"stage\":\n"
+      "[\n"
+      "  { \n"
+      "    \"type\": \"ImageView\",\n"
+      "    \"name\": \"image\",\n"
+      "    \"size\": [100,100,1],\n"
+      "    \"signals\": [{\n"
+      "      \"name\": \"touch\",\n"
+      "      \"action\": \"show\",\n"
+      "      \"parameters\": {\n"
+      "        \"property1\" : 10,\n"
+      "        \"property2\" : [1,2],\n"
+      "        \"property3\" : [1,2,3],\n"
+      "        \"property4\" : [1,2,3,4]\n"
+      "      }\n"
+      "    }]\n"
+      "  }\n"
+      "]\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+  builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+  DALI_TEST_CHECK( true ); // For Coverage
+
+  END_TEST;
+}
+
+int UtcDaliBuilderConfigurationP(void)
+{
+  ToolkitTestApplication application;
+
+  // JSON with a quit event when the actor is touched
+  std::string json(
+      "{\n"
+      "  \"config\":\n"
+      "  {\n"
+      "    \"alwaysShowFocus\":true\n"
+      "  }\n"
+      "}\n"
+  );
+
+  Builder builder = Builder::New();
+  builder.LoadFromString( json );
+
+  Property::Map map = builder.GetConfigurations();
+
+  Dali::Property::Value* pValue = map.Find( "alwaysShowFocus" );
+
+  DALI_TEST_CHECK( pValue );
+
+  bool value = pValue->Get<bool>();
+
+  DALI_TEST_CHECK( value );
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP(void)
+{
+  std::vector<uint32_t> data = { 0, 1, 2, 3, 4, 5, std::numeric_limits<uint32_t>::min(), std::numeric_limits<uint32_t>::max()  };
+
+  Property::Value value;
+  EncodeBase64PropertyData( value, data );
+
+  std::cout << "Max uint32_t:" << std::numeric_limits<uint32_t>::max() << std::endl;
+  std::cout << "Input data:  ";
+  std::ostream_iterator<uint32_t> out_it (std::cout,", ");
+  std::copy ( data.begin(), data.end(), out_it );
+  std::cout << std::endl;
+
+  std::string output;
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, "AAAAAAEAAAACAAAAAwAAAAQAAAAFAAAAAAAAAP////8", TEST_LOCATION );
+
+  std::cout << "Output data:  " << output << std::endl;
+
+  END_TEST;
+}
+
+int UtcDaliBase64EncodingN(void)
+{
+  tet_infoline( "Test encoding an empty vector returns empty string" );
+  std::vector<uint32_t> data;
+
+  Property::Value value;
+  EncodeBase64PropertyData( value, data );
+
+  std::string output;
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+template <typename T>
+int b64l(std::vector<T>&data)
+{
+  auto lengthInBytes = 4*data.size();
+  return ceil( lengthInBytes * 1.33333f );
+}
+
+int UtcDaliBase64EncodingP02(void)
+{
+  tet_infoline( "Test encoding vectors of lengths m .. m+4 encode and decode back to the same length vectors" );
+
+  std::vector<uint32_t> testData;
+  for(int i=0; i<8; ++i ) // 8 chosen to stay within single string output
+  {
+    testData.push_back(i);
+  }
+  Property::Value value;
+  EncodeBase64PropertyData( value, testData );
+
+  std::string output;
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+  std::vector<uint32_t> outData;
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+  // n+1
+  testData.push_back( 12345 );
+  EncodeBase64PropertyData( value, testData );
+
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+  outData.clear();
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+  // n+2
+  testData.push_back( 67890 );
+  EncodeBase64PropertyData( value, testData );
+
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+  outData.clear();
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+  // n+3
+  testData.push_back( -1 );
+  EncodeBase64PropertyData( value, testData );
+
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+  outData.clear();
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( std::equal( testData.begin(), testData.end(), outData.begin()), true, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP03(void)
+{
+  tet_infoline( "Test encoding a vector of length 12 has output within single string" );
+
+  std::vector<uint32_t> testData;
+  for(int i=0; i<12; ++i )
+  {
+    testData.push_back(i);
+  }
+  Property::Value value;
+  EncodeBase64PropertyData( value, testData );
+
+  std::string output;
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output.empty(), false, TEST_LOCATION);
+  DALI_TEST_EQUALS( output.length(), b64l(testData), TEST_LOCATION );
+
+  std::vector<uint32_t> outData;
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP04(void)
+{
+  tet_infoline( "Test encoding a vector of length 13 has output split over 2 strings" );
+
+  std::vector<uint32_t> testData;
+  for(int i=0; i<13; ++i )
+  {
+    testData.push_back(i);
+  }
+  Property::Value value;
+  EncodeBase64PropertyData( value, testData );
+
+  auto array = value.GetArray();
+  DALI_TEST_CHECK( array );
+
+  DALI_TEST_EQUALS( array->Count(), 2, TEST_LOCATION );
+
+  std::vector<uint32_t> outData;
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP05(void)
+{
+  tet_infoline( "Test encoding a vector of length 24 has output split over 2 strings" );
+
+  std::vector<uint32_t> testData;
+  for(int i=0; i<24; ++i )
+  {
+    testData.push_back(i);
+  }
+  Property::Value value;
+  EncodeBase64PropertyData( value, testData );
+
+  auto array = value.GetArray();
+  DALI_TEST_CHECK( array );
+
+  DALI_TEST_EQUALS( array->Count(), 2, TEST_LOCATION );
+
+  std::vector<uint32_t> outData;
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64EncodingP06(void)
+{
+  tet_infoline( "Test encoding a vector of arbitrary length decodes OK." );
+
+  std::vector<uint32_t> testData;
+  for(int i=0; i<97; ++i )
+  {
+    testData.push_back(i);
+  }
+  Property::Value value;
+  EncodeBase64PropertyData( value, testData );
+
+  auto array = value.GetArray();
+  DALI_TEST_CHECK( array );
+
+  std::vector<uint32_t> outData;
+  DecodeBase64PropertyData( value, outData );
+  DALI_TEST_EQUALS( testData.size(), outData.size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliBase64DecodingN01(void)
+{
+  tet_infoline( "Test decoding empty string results in empty data" );
+
+  Property::Value value("");
+  std::vector<uint32_t> outputData;
+  DecodeBase64PropertyData( value, outputData);
+  DALI_TEST_EQUALS( outputData.size(), 0, TEST_LOCATION );
+  END_TEST;
+}
+
+
+int UtcDaliBase64DecodingN02(void)
+{
+  tet_infoline( "Test decoding array with non-string values results in empty data" );
+
+  Property::Array array;
+  array.Resize(2);
+  array[0] = "Stuff, things";
+  array[1] = 1;
+  Property::Value value(array);
+
+  std::vector<uint32_t> outputData;
+  DecodeBase64PropertyData( value, outputData);
+  DALI_TEST_EQUALS( outputData.size(), 0, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliBase64DecodingP01(void)
+{
+  tet_infoline( "Test decoding string of known data gives expected result");
+
+  std::string testInput("//////7+/v4DAgEA");
+  std::vector<uint32_t> expectedResults = { 0xffffffff, 0xfefefefe, 0x00010203 };
+
+  std::vector<uint32_t> outputData;
+  DecodeBase64PropertyData(Property::Value(testInput), outputData);
+
+  DALI_TEST_EQUALS( std::equal( expectedResults.begin(), expectedResults.end(), outputData.begin() ), true,
+                    TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp
new file mode 100644 (file)
index 0000000..b1c5386
--- /dev/null
@@ -0,0 +1,1010 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include "dali-toolkit-test-utils/toolkit-timer.h"
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+
+void utc_dali_toolkit_button_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_button_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static bool gIsCalledButtonCallback = false;
+static bool gIsCalledChildButtonCallback = false;
+
+static bool ButtonCallback( Button button )
+{
+  gIsCalledButtonCallback = true;
+  return false;
+}
+
+static bool ChildButtonCallback( Button button )
+{
+  gIsCalledChildButtonCallback = true;
+  return false;
+}
+
+static std::string GetButtonText( Button button )
+{
+  Property::Value value = button.GetProperty( Toolkit::Button::Property::LABEL );
+
+  Property::Map *labelProperty = value.GetMap();
+
+  std::string textLabel;
+
+  if ( labelProperty )
+  {
+    Property::Value* value = labelProperty->Find( Toolkit::TextVisual::Property::TEXT );
+    value->Get( textLabel );
+  }
+
+  return textLabel;
+}
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+Dali::Integration::Point GetPointDownInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 240, 400 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 240, 400 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointLeave()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::LEAVE );
+  point.SetScreenPosition( Vector2( 240, 400 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointEnter()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::MOTION );
+  point.SetScreenPosition( Vector2( 240, 400 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointDownOutside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpOutside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+} // namespace
+
+int UtcDaliButtonConstructorP(void)
+{
+  TestApplication application;
+
+  Button button;
+
+  DALI_TEST_CHECK( !button );
+  END_TEST;
+}
+
+int UtcDaliButtonCopyConstructorP(void)
+{
+  TestApplication application;
+
+  // Initialize an object, ref count == 1
+  Button button = PushButton::New();
+
+  Button copy( button );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliButtonAssignmentOperatorP(void)
+{
+  TestApplication application;
+
+  Button button = PushButton::New();
+
+  Button copy( button );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( button == copy );
+  END_TEST;
+}
+
+int UtcDaliButtonDownCastP(void)
+{
+  TestApplication application;
+
+  Button button = PushButton::New();
+
+  BaseHandle object(button);
+
+  Button button2 = Button::DownCast( object );
+  DALI_TEST_CHECK(button2);
+
+  Button button3 = DownCast< Button >(object);
+  DALI_TEST_CHECK(button3);
+  END_TEST;
+}
+
+int UtcDaliButtonDownCastN(void)
+{
+  TestApplication application;
+
+  BaseHandle unInitializedObject;
+
+  Button button1 = Button::DownCast( unInitializedObject );
+  DALI_TEST_CHECK( !button1 );
+
+  Button button2 = DownCast< Button >( unInitializedObject );
+  DALI_TEST_CHECK( !button2 );
+  END_TEST;
+}
+
+int UtcDaliButtonDisabledPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+
+  button.SetProperty( button.GetPropertyIndex("disabled"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("disabled")), true, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("disabled"), false );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("disabled")), false, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("disabled"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("disabled")), true, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("disabled"), false );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("disabled")), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonSetDisabledWithDifferentStates01P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliButtonSetDisabledWithDifferentStates01P\n");
+
+  Button button = PushButton::New();
+
+  bool SELECTED = true;
+
+  button.SetProperty( Button::Property::TOGGLABLE, true);
+  button.SetProperty( Button::Property::SELECTED, SELECTED );
+
+  button.SetProperty( Button::Property::DISABLED, true);
+
+  tet_infoline("Set button to SELECTED = false whilst disabled, should not change to false\n");
+  button.SetProperty( Button::Property::SELECTED, !SELECTED );
+
+  bool isSelected = button.GetProperty<bool>( Button::Property::SELECTED ) ;
+
+  DALI_TEST_EQUALS( isSelected, SELECTED , TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonSetDisabledWithDifferentStates02P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliButtonSetDisabledWithDifferentStates02\n");
+
+  Button button = PushButton::New();
+
+  bool SELECTED = true;
+
+  button.SetProperty( Button::Property::TOGGLABLE, true );
+  button.SetProperty( Button::Property::SELECTED, SELECTED );
+  button.SetProperty( Button::Property::DISABLED, true );
+
+  bool isSelected =  button.GetProperty<bool>( Button::Property::SELECTED );
+  DALI_TEST_EQUALS( isSelected, SELECTED , TEST_LOCATION );
+  tet_infoline("Set button to DISABLED = false whilst disabled and then set to unselected\n");
+
+  button.SetProperty( Button::Property::DISABLED, false);
+  button.SetProperty( Button::Property::SELECTED, !SELECTED );
+
+  isSelected = button.GetProperty<bool>( Button::Property::SELECTED );
+  DALI_TEST_EQUALS( isSelected, !SELECTED , TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonPropertyGetLabelAlignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPropertyGetLabelAlignment\n");
+
+  Button button = PushButton::New();
+  button.SetProperty( Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT, "END"  );
+  DALI_TEST_EQUALS( button.GetProperty<std::string>( Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT ), "END", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonIsDisabledP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( Button::Property::DISABLED, true);
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( Button::Property::DISABLED ), true, TEST_LOCATION );
+
+  button.SetProperty( Button::Property::DISABLED, false);
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( Button::Property::DISABLED ), false, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonAutoRepeatingPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( button.GetPropertyIndex("autoRepeating"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("autoRepeating")), true, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("autoRepeating"), false );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("autoRepeating")), false, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("autoRepeating"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("autoRepeating")), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonIsAutoRepeatingP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( Button::Property::AUTO_REPEATING, true);
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( Button::Property::AUTO_REPEATING ), true, TEST_LOCATION );
+
+  button.SetProperty( Button::Property::AUTO_REPEATING, false);
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( Button::Property::AUTO_REPEATING ), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonAutoRepeatingP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliButtonPressedSignalP  Setup Autorepeating and check multiple clicked signals received\n");
+
+  const float AUTO_REPEATING_DELAY = 0.15f;
+
+  Button button = PushButton::New();
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetPosition( 240, 400 );
+  button.SetSize( 100, 100 );
+  Stage::GetCurrent().Add( button );
+
+  application.SendNotification();
+  application.Render();
+
+  button.SetProperty( Toolkit::Button::Property::AUTO_REPEATING, true  );
+  button.SetProperty( Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY, AUTO_REPEATING_DELAY );
+  // connect to its touch signal
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  button.PressedSignal().Connect( &ButtonCallback );
+  button.ClickedSignal().Connect( &ButtonCallback );
+  bool clickedSignal = false;
+  bool pressedSignal = false;
+  button.ConnectSignal( testTracker, "pressed", CallbackFunctor(&pressedSignal) );
+  button.ConnectSignal( testTracker, "clicked", CallbackFunctor(&clickedSignal) );
+
+  Dali::Integration::TouchEvent event;
+
+  // Touch point down and up inside the button.
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gIsCalledButtonCallback, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( pressedSignal, true, TEST_LOCATION );
+  tet_infoline("Consume first clicked signal then wait\n");
+
+  gIsCalledButtonCallback = false;
+  Dali::Timer timer = Timer::New( AUTO_REPEATING_DELAY );
+  timer.MockEmitSignal();
+  application.Wait( AUTO_REPEATING_DELAY*2 );
+  DALI_TEST_EQUALS( clickedSignal, true, TEST_LOCATION );
+  tet_infoline("Check gIsCalledButtonCallback was called again after last consumption of it.\n");
+
+  DALI_TEST_EQUALS( gIsCalledButtonCallback, true, TEST_LOCATION );
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gIsCalledButtonCallback, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonInitialAutoRepeatingDelayPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( button.GetPropertyIndex("initialAutoRepeatingDelay"), 0.5f );
+
+  DALI_TEST_EQUALS( button.GetProperty<float>( button.GetPropertyIndex("initialAutoRepeatingDelay")), 0.5f, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("initialAutoRepeatingDelay"), 0.2f );
+
+  DALI_TEST_EQUALS( button.GetProperty<float>( button.GetPropertyIndex("initialAutoRepeatingDelay")), 0.2f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonNextAutoRepeatingDelayPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( button.GetPropertyIndex("nextAutoRepeatingDelay"), 0.5f );
+
+  DALI_TEST_EQUALS( button.GetProperty<float>( button.GetPropertyIndex("nextAutoRepeatingDelay")), 0.5f, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("nextAutoRepeatingDelay"), 0.2f );
+
+  DALI_TEST_EQUALS( button.GetProperty<float>( button.GetPropertyIndex("nextAutoRepeatingDelay")), 0.2f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonTogglableButtonPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  button.SetProperty( button.GetPropertyIndex("togglable"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("togglable")), true, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("togglable"), false );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("togglable")), false, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonSelectedPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+  button.SetProperty( button.GetPropertyIndex("togglable"), true );
+
+  button.SetProperty( button.GetPropertyIndex("selected"), true );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("selected")), true, TEST_LOCATION );
+
+  button.SetProperty( button.GetPropertyIndex("selected"), false );
+
+  DALI_TEST_EQUALS( button.GetProperty<bool>( button.GetPropertyIndex("selected")), false, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonSetLabelStringWithPropertyMapP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+  button.SetProperty( Toolkit::Button::Property::LABEL,
+                      Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                     .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                                     .Add( Toolkit::TextVisual::Property::TEXT, "Button Label")
+                     );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), "Button Label", TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonSetLabelStringWithPropertyMapStringsP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  tet_infoline(" UtcDaliButtonSetLabelStringWithPropertyMapStringsP Setting Button text using String then replacing with Enum then string");
+
+  Property::Map textVisualMapInitial;
+  textVisualMapInitial["visualType"] = "TEXT";
+  textVisualMapInitial["pointSize"] =  15.0f;
+  textVisualMapInitial["text"] = "button label initial";
+
+  button.SetProperty( Button::Property::LABEL, textVisualMapInitial );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), "button label initial", TEST_LOCATION );
+
+  tet_infoline(" UtcDaliButtonSetLabelStringWithPropertyMapStringsP Intermediate part of test");
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::TEXT );
+  propertyMap.Insert( Toolkit::TextVisual::Property::TEXT,  "error if this is the final text" );
+  propertyMap.Insert( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  button.SetProperty( Button::Property::LABEL, propertyMap );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), "error if this is the final text", TEST_LOCATION );
+
+  tet_infoline(" UtcDaliButtonSetLabelStringWithPropertyMapStringsP Final part of test");
+
+  Property::Map textVisualMap;
+  textVisualMap["visualType"] = "TEXT";
+  textVisualMap["pointSize"] =  15.0f;
+  textVisualMap["text"] = "Button Label";
+
+  button.SetProperty( Toolkit::Button::Property::LABEL, textVisualMap );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), "Button Label", TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonSetLabelWithStringP(void)
+{
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+
+  // Set default point size for text visual as style sheet not available.
+  button.SetProperty( Toolkit::Button::Property::LABEL,
+                      Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                     .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                                     );
+
+  button.SetProperty( Toolkit::Button::Property::LABEL, "Button Label" );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), "Button Label", TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliButtonSetLabelPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliButtonSetLabelPropertyP Set text label and then set again with new text");
+
+
+  const std::string TEST_LABEL1 = "test label one";
+  const std::string TEST_LABEL2 = "test label two";
+
+  Button button = PushButton::New();
+
+  button.SetProperty( Toolkit::Button::Property::LABEL,
+                        Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                       .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                                       .Add( Toolkit::TextVisual::Property::TEXT, TEST_LABEL1 )
+                     );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), TEST_LABEL1,  TEST_LOCATION );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::TEXT );
+  propertyMap.Insert( Toolkit::TextVisual::Property::TEXT,  TEST_LABEL2 );
+  propertyMap.Insert( Toolkit::TextVisual::Property::TEXT_COLOR, Color::BLUE );
+  propertyMap.Insert( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+  button.SetProperty( Button::Property::LABEL, propertyMap );
+
+  DALI_TEST_EQUALS( GetButtonText( button ), TEST_LABEL2,  TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonPressedSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliButtonPressedSignalP");
+
+  Button button = PushButton::New();
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetPosition( 240, 400 );
+  button.SetSize( 100, 100 );
+
+  Stage::GetCurrent().Add( button );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its touch signal
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  button.PressedSignal().Connect( &ButtonCallback );
+  button.ReleasedSignal().Connect( &ButtonCallback );
+  bool pressedSignal = false;
+  bool releasedSignal = false;
+  button.ConnectSignal( testTracker, "pressed",   CallbackFunctor(&pressedSignal) );
+  button.ConnectSignal( testTracker, "released",  CallbackFunctor(&releasedSignal) );
+
+  Dali::Integration::TouchEvent event;
+
+  // Test1. Touch point down and up inside the button.
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+  DALI_TEST_CHECK( pressedSignal );
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+  DALI_TEST_CHECK( releasedSignal );
+
+  // Test2. Touch point down and up outside the button.
+
+  pressedSignal = false;
+  releasedSignal = false;
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  DALI_TEST_CHECK( !pressedSignal );
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  DALI_TEST_CHECK( !releasedSignal );
+
+  // Test3. Touch point down inside and up outside the button.
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointLeave() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+
+  // Test4. Touch point down outside and up inside the button.
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointEnter() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  END_TEST;
+}
+
+int UtcDaliButtonClickedSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliButtonClickedSignalP");
+
+  Button button = PushButton::New();
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetPosition( 240, 400 );
+  button.SetSize( 100, 100 );
+
+  Stage::GetCurrent().Add( button );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its touch signal
+  button.ClickedSignal().Connect( &ButtonCallback );
+  bool clickedSignal = false;
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  button.ConnectSignal( testTracker, "clicked",   CallbackFunctor(&clickedSignal) );
+
+  Dali::Integration::TouchEvent event;
+
+  // Test1. Touch point down and up inside the button.
+
+  gIsCalledButtonCallback = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+  DALI_TEST_CHECK( clickedSignal );
+
+  // Test2. Touch point down and up outside the button.
+
+  gIsCalledButtonCallback = false;
+  clickedSignal = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  DALI_TEST_CHECK( !clickedSignal );
+
+  // Test3. Touch point down inside and up outside the button.
+
+  gIsCalledButtonCallback = false;
+  clickedSignal = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointLeave() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  DALI_TEST_CHECK( !clickedSignal );
+
+  // Test4. Touch point down outside and up inside the button.
+
+  gIsCalledButtonCallback = false;
+  clickedSignal = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointEnter() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gIsCalledButtonCallback );
+  DALI_TEST_CHECK( !clickedSignal );
+  END_TEST;
+}
+
+int UtcDaliButtonStateChangedSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliButtonStateChangedSignalP");
+
+  Button button = PushButton::New();
+
+  button.SetProperty( Button::Property::TOGGLABLE, true);
+
+  Stage::GetCurrent().Add( button );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its signal
+  button.StateChangedSignal().Connect( &ButtonCallback );
+  bool stateChangedSignal = false;
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  button.ConnectSignal( testTracker, "stateChanged",   CallbackFunctor(&stateChangedSignal) );
+
+  gIsCalledButtonCallback = false;
+  button.SetProperty( Button::Property::SELECTED, true);
+
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+  DALI_TEST_CHECK( stateChangedSignal );
+
+  gIsCalledButtonCallback = false;
+  stateChangedSignal = false;
+
+  button.SetProperty( Button::Property::SELECTED, false);
+  DALI_TEST_CHECK( gIsCalledButtonCallback );
+  DALI_TEST_CHECK( stateChangedSignal );
+  END_TEST;
+}
+
+int UtcDaliButtonSetProperty(void)
+{
+  tet_infoline("UtcDaliButtonSetProperty: ");
+  ToolkitTestApplication application;
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty(pushButton.GetPropertyIndex("disabled"), false);
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( pushButton.GetPropertyIndex("disabled")), false, TEST_LOCATION );
+
+  pushButton.SetProperty(pushButton.GetPropertyIndex("disabled"), true);
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( pushButton.GetPropertyIndex("disabled")), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonEventConsumption(void)
+{
+  /**
+   *  [ Parent ]
+   *  [ Child  ]
+   *
+   *  Child parented and positioned under parent.
+   *  Touch up and down performed on child.
+   *  Should only trigger signal on child.
+   */
+
+  ToolkitTestApplication application;
+
+  Button parentButton = PushButton::New();
+  parentButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  parentButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  parentButton.SetSize( 20, 20 );
+  Stage::GetCurrent().Add( parentButton );
+
+  Button childButton = PushButton::New();
+  childButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  childButton.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
+  childButton.SetSize( 20, 20 );
+  parentButton.Add( childButton );
+
+  // Reset signal flags
+  gIsCalledChildButtonCallback = false;
+  gIsCalledButtonCallback = false;
+
+  parentButton.ClickedSignal().Connect( &ButtonCallback );
+  childButton.ClickedSignal().Connect( &ChildButtonCallback );
+
+  // Peform a button click at coordinates (10,30) which is the child.
+  Dali::Integration::TouchEvent event;
+  event = Dali::Integration::TouchEvent();
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 30 ) );
+  event.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 10, 30 ) );
+  event.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gIsCalledChildButtonCallback, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( ! gIsCalledButtonCallback, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonRelease(void)
+{
+  /**
+   * Down event followed by interrupted event should signal Release.
+   */
+
+  ToolkitTestApplication application;
+
+  Button parentButton = PushButton::New();
+  parentButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  parentButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  parentButton.SetSize( 20, 20 );
+  Stage::GetCurrent().Add( parentButton );
+  parentButton.ReleasedSignal().Connect( &ButtonCallback );
+
+  // Reset signal flags
+  gIsCalledButtonCallback = false;
+
+  // Peform a button down and then button interrupted at coordinates (10,10).
+  Dali::Integration::TouchEvent event;
+  event = Dali::Integration::TouchEvent();
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  event.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  point.SetState( PointState::INTERRUPTED );
+  event.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gIsCalledButtonCallback, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliButtonMultiTouch(void)
+{
+  /**
+   * Down event followed by a multi touch point event should signal Release.
+   */
+
+  ToolkitTestApplication application;
+
+  Button button = PushButton::New();
+  button.SetProperty( Button::Property::TOGGLABLE, true);
+
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetSize( 20, 20 );
+  Stage::GetCurrent().Add( button );
+  button.ReleasedSignal().Connect( &ButtonCallback );
+
+  // Reset signal flags
+  gIsCalledButtonCallback = false;
+
+  // Peform a button down and then button interrupted at coordinates (10,10).
+  Dali::Integration::TouchEvent downEvent;
+  downEvent = Dali::Integration::TouchEvent();
+  Dali::Integration::Point point;
+
+  // Add Press button
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 15, 15 ) );
+  downEvent.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( downEvent );
+
+  // Release button
+  Dali::Integration::TouchEvent upEvent;
+  upEvent = Dali::Integration::TouchEvent();
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 15, 15 ) );
+  upEvent.AddPoint( point );
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( upEvent );
+
+  tet_infoline("Button should now be selected\n");
+  bool isSelected = button.GetProperty<bool>( Button::Property::SELECTED ) ;
+  DALI_TEST_EQUALS( isSelected, true, TEST_LOCATION );
+
+  // Add first point
+  Dali::Integration::TouchEvent multiEvent;
+  multiEvent = Dali::Integration::TouchEvent();
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  multiEvent.AddPoint( point );
+
+  // Add second point
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 15, 15 ) );
+  multiEvent.AddPoint( point );
+
+  tet_infoline("Before a multi touch event\n");
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( multiEvent );
+
+  DALI_TEST_EQUALS( gIsCalledButtonCallback, true, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-CheckBoxButton.cpp
new file mode 100644 (file)
index 0000000..a43cbf2
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2019 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 <test-application.h>
+#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+static bool gCheckBoxButtonState = false;
+bool CheckBoxButtonClicked( Button button )
+{
+  gCheckBoxButtonState = button.GetProperty<bool>(button.GetPropertyIndex("selected")) ;
+  return true;
+}
+
+static const char* TEST_IMAGE_ONE = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+const Vector2 TEST_IMAGE_SIZE = Vector2( 66.0f, 66.0f );
+
+static std::string GetButtonText( Button button )
+{
+  Property::Value value = button.GetProperty( Toolkit::Button::Property::LABEL );
+
+  Property::Map *labelProperty = value.GetMap();
+
+  std::string textLabel;
+
+  if ( labelProperty )
+  {
+    Property::Value* value = labelProperty->Find( Toolkit::TextVisual::Property::TEXT );
+    value->Get( textLabel );
+  }
+
+  return textLabel;
+}
+
+} // namespace
+
+void checkbox_button_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void checkbox_button_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliCheckBoxButtonConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox;
+
+  DALI_TEST_CHECK( !checkBox );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Initialize an object, ref count == 1
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  CheckBoxButton copy( checkBox );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  CheckBoxButton copy( checkBox );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( checkBox == copy );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonNewP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  DALI_TEST_CHECK( checkBox );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonDownCastP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  BaseHandle object(checkBox);
+
+  CheckBoxButton checkBox2 = CheckBoxButton::DownCast( object );
+  DALI_TEST_CHECK(checkBox2);
+
+  CheckBoxButton checkBox3 = DownCast< CheckBoxButton >(object);
+  DALI_TEST_CHECK(checkBox3);
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonDownCastN(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle unInitializedObject;
+
+  CheckBoxButton checkBox1 = CheckBoxButton::DownCast( unInitializedObject );
+  DALI_TEST_CHECK( !checkBox1 );
+
+  CheckBoxButton checkBox2 = DownCast< CheckBoxButton >( unInitializedObject );
+  DALI_TEST_CHECK( !checkBox2 );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxButtonSelectedPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCheckBoxButtonSetGetSelected");
+
+  CheckBoxButton checkBoxButton = CheckBoxButton::New();
+  checkBoxButton.StateChangedSignal().Connect( &CheckBoxButtonClicked );
+
+  // global var used to check if CheckBoxButtonClicked is called;
+  gCheckBoxButtonState = false;
+
+  checkBoxButton.SetProperty( checkBoxButton.GetPropertyIndex("selected"), true );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty<bool>(checkBoxButton.GetPropertyIndex("selected")), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gCheckBoxButtonState );
+
+  checkBoxButton.SetProperty( checkBoxButton.GetPropertyIndex("selected"), false );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty<bool>(checkBoxButton.GetPropertyIndex("selected")), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gCheckBoxButtonState );
+
+  checkBoxButton.SetProperty( checkBoxButton.GetPropertyIndex("selected"), true );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty<bool>(checkBoxButton.GetPropertyIndex("selected")), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gCheckBoxButtonState );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSetLabelP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  Property::Map propertyMap;
+
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+             .Add( Toolkit::TextVisual::Property::TEXT, "activate" )
+             .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  checkBox.SetProperty( checkBox.GetPropertyIndex("label"), propertyMap );
+
+  DALI_TEST_EQUALS( GetButtonText( checkBox ) , "activate", TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSetDisabledPropertyP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+  Stage::GetCurrent().Add( checkBox );
+
+  checkBox.SetSize( Vector2( 20.0f, 20.0f ) );
+  checkBox.SetProperty(checkBox.GetPropertyIndex("disabledUnselectedBackgroundVisual"),  "Image.jpg" );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map propertyMap;
+
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+             .Add( Toolkit::TextVisual::Property::TEXT, "activate" )
+             .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  checkBox.SetProperty(checkBox.GetPropertyIndex("disabled"), true);
+  checkBox.SetProperty( checkBox.GetPropertyIndex("label"), propertyMap );
+
+  DALI_TEST_EQUALS( checkBox.GetProperty<bool>(checkBox.GetPropertyIndex("disabled")), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetButtonText( checkBox ) , "activate", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSettingDisabled(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  checkBox.SetProperty(checkBox.GetPropertyIndex("disabled"), true);
+  DALI_TEST_CHECK(  checkBox.GetProperty<bool>(checkBox.GetPropertyIndex("disabled")) );
+
+  checkBox.SetProperty(checkBox.GetPropertyIndex("disabled"), false);
+
+  DALI_TEST_CHECK(  !checkBox.GetProperty<bool>(checkBox.GetPropertyIndex("disabled")) );
+
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSetLabelPadding(void)
+{
+  tet_infoline("UtcDaliCheckBoxSetLabelPadding\n");
+
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  Property::Map propertyMap;
+
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+             .Add( Toolkit::TextVisual::Property::TEXT, "activate" )
+             .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  checkBox.SetProperty( Toolkit::Button::Property::LABEL, propertyMap );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 orginalSize = checkBox.GetNaturalSize();
+
+  checkBox.SetProperty( Toolkit::DevelButton::Property::LABEL_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 paddingAddedSize = checkBox.GetNaturalSize();
+
+  DALI_TEST_EQUALS( checkBox.GetProperty<Vector4>( Toolkit::DevelButton::Property::LABEL_PADDING ), Vector4( 10.0f, 10.0f, 10.0f, 10.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  tet_infoline("Comparing original size of button with just text and button size with text and padding\n");
+
+  DALI_TEST_EQUALS( orginalSize.width +10.0f + 10.0f , paddingAddedSize.width, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( orginalSize.height +10.0f + 10.0f , paddingAddedSize.height, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSetForegroundPadding(void)
+{
+  tet_infoline("UtcDaliCheckBoxSetForegroundPadding\n");
+
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+
+  Property::Map propertyMap;
+
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+             .Add( Toolkit::TextVisual::Property::TEXT, "activate" )
+             .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  checkBox.SetProperty( Toolkit::Button::Property::LABEL, propertyMap );
+  checkBox.SetProperty( Toolkit::DevelButton::Property::LABEL_PADDING, Vector4( 5.0f, 5.0f, 5.0f, 5.0f ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf( "Button RelayoutSize with text(%f,%f)\n", checkBox.GetNaturalSize().width, checkBox.GetNaturalSize().height );
+
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetClosestImageSize( TEST_IMAGE_SIZE );
+
+  checkBox.SetProperty( Toolkit::Button::Property::UNSELECTED_VISUAL, TEST_IMAGE_ONE );
+  checkBox.SetProperty( Toolkit::Button::Property::SELECTED_VISUAL, TEST_IMAGE_ONE );
+
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 preVisualPaddingSize = checkBox.GetNaturalSize();
+
+  tet_printf( "Button RelayoutSize with text and icon (%f,%f)\n", checkBox.GetNaturalSize().width, checkBox.GetNaturalSize().height );
+
+  checkBox.SetProperty( Toolkit::DevelButton::Property::VISUAL_PADDING, Vector4( 25.0f, 25.0f, 25.0f, 25.0f ) );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 paddingAddedSize = checkBox.GetNaturalSize();
+
+  tet_printf( "Button RelayoutSize with text, icon and padding (%f,%f)\n", checkBox.GetNaturalSize().width, checkBox.GetNaturalSize().height );
+
+  DALI_TEST_EQUALS( checkBox.GetProperty<Vector4>( Toolkit::DevelButton::Property::VISUAL_PADDING ), Vector4( 25.0f, 25.0f, 25.0f, 25.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  tet_infoline("Comparing original size of button before adding padding to visual foreground\n");
+
+  DALI_TEST_GREATER( paddingAddedSize.width, preVisualPaddingSize.width , TEST_LOCATION );
+
+  tet_infoline("Text and Visual are side by side, visual height and padding must be greater than text height and padding for this test\n");
+
+  DALI_TEST_GREATER( paddingAddedSize.height, preVisualPaddingSize.height , TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Deprecated API Tests
+
+int UtcDaliCheckBoxButtonSetGetSelected(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCheckBoxButtonSetGetSelected");
+
+  CheckBoxButton checkBoxButton = CheckBoxButton::New();
+  checkBoxButton.StateChangedSignal().Connect( &CheckBoxButtonClicked );
+
+  // global var used to check if CheckBoxButtonClicked is called;
+  gCheckBoxButtonState = false;
+
+  checkBoxButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty( Button::Property::SELECTED ).Get<bool>(), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gCheckBoxButtonState );
+
+  checkBoxButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty( Button::Property::SELECTED ).Get<bool>(), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gCheckBoxButtonState );
+
+  checkBoxButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( checkBoxButton.GetProperty( Button::Property::SELECTED ).Get<bool>(), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gCheckBoxButtonState );
+  END_TEST;
+}
+
+int UtcDaliCheckBoxSetLabelDisabledP(void)
+{
+  ToolkitTestApplication application;
+
+  CheckBoxButton checkBox = CheckBoxButton::New();
+  Stage::GetCurrent().Add( checkBox );
+
+  checkBox.SetSize( Vector2( 20.0f, 20.0f ) );
+  checkBox.SetProperty(Button::Property::DISABLED_UNSELECTED_VISUAL, "Image.jpg" );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map propertyMap;
+
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+             .Add( Toolkit::TextVisual::Property::TEXT, "activate" )
+             .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f );
+
+  checkBox.SetProperty(checkBox.GetPropertyIndex("disabled"), true);
+  checkBox.SetProperty( checkBox.GetPropertyIndex("label"), propertyMap );
+
+  DALI_TEST_CHECK(  checkBox.GetProperty<bool>(checkBox.GetPropertyIndex("disabled")) );
+  DALI_TEST_EQUALS( GetButtonText(checkBox), "activate", TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ConfirmationPopup.cpp
new file mode 100644 (file)
index 0000000..9c3765d
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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 <stdlib.h>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/popup/confirmation-popup.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_confirmation_popup_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_confirmation_popup_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+static bool gSignalReceivedOK;
+static bool gSignalReceivedCancel;
+
+/**
+ * A connection tracker is required when connecting to a signal with a functor.
+ */
+class TestConnectionTrackerObject : public ConnectionTracker
+{
+};
+
+/**
+ * This functor is used to test the confirmation popup's OK signal connection.
+ */
+struct ConfirmationPopupOKTestFunctor
+{
+  ConfirmationPopupOKTestFunctor()
+  {
+  }
+
+  void operator()()
+  {
+    gSignalReceivedOK = true;
+  }
+};
+
+/**
+ * This functor is used to test the confirmation popup's Cancel signal connection.
+ */
+struct ConfirmationPopupCancelTestFunctor
+{
+  ConfirmationPopupCancelTestFunctor()
+  {
+  }
+
+  void operator()()
+  {
+    gSignalReceivedCancel = true;
+  }
+};
+
+} // unnamed namespace.
+
+
+int UtcDaliConfirmationPopupNewP( void )
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliConfirmationPopupNewP" );
+
+  // Create the ConfirmationPopup.
+  ConfirmationPopup popup;
+
+  DALI_TEST_CHECK( !popup );
+
+  popup = ConfirmationPopup::New();
+
+  DALI_TEST_CHECK( popup );
+
+  ConfirmationPopup popup2( popup );
+
+  DALI_TEST_CHECK( popup2 == popup );
+
+  // Additional check to ensure object is created by checking if it's registered.
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    ConfirmationPopup popup = ConfirmationPopup::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliConfirmationPopupDestructorP( void )
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliConfirmationPopupDestructorP" );
+
+  ConfirmationPopup* popup = new ConfirmationPopup();
+  delete popup;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliConfirmationPopupDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliConfirmationPopupDownCastP" );
+
+  Handle handle = ConfirmationPopup::New();
+
+  ConfirmationPopup popup = ConfirmationPopup::DownCast( handle );
+
+  DALI_TEST_CHECK( popup == handle );
+  END_TEST;
+}
+
+int UtcDaliConfirmationPopupDynamicSignalGenerationP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliConfirmationPopupDynamicSignalGenerationP" );
+
+  ConfirmationPopup popup = ConfirmationPopup::New();
+
+  TextLabel titleActor = TextLabel::New( "Title" );
+  popup.SetTitle( titleActor );
+
+  TextLabel contentActor = TextLabel::New( "Content" );
+  popup.SetContent( contentActor );
+
+  Actor footerActor = Actor::New();
+
+  // The confirmation popup can use any control type for the ok or cancel buttons.
+  // It requires that the name is "controlOk" to provide the "controlSignalOk" signal.
+  PushButton buttonOK = PushButton::New();
+  buttonOK.SetName( "controlOk" );
+  footerActor.Add( buttonOK );
+
+  PushButton buttonCancel = PushButton::New();
+  buttonCancel.SetName( "controlCancel" );
+  footerActor.Add( buttonCancel );
+
+  popup.SetFooter( footerActor );
+
+  // Tell the confirmation popup to connect to the signal in our button called "onStage".
+  popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED, "onStage" );
+  std::string resultProperty;
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED ).Get( resultProperty ) );
+  DALI_TEST_EQUALS( resultProperty, "onStage",  TEST_LOCATION );
+
+  // Connect to the confirmation popup's OK signal. This signal is dynamically created upon connection.
+  gSignalReceivedOK = false;
+  gSignalReceivedCancel = false;
+  TestConnectionTrackerObject* testTracker = new TestConnectionTrackerObject();
+  popup.ConnectSignal( testTracker, "controlSignalOk",   ConfirmationPopupOKTestFunctor() );
+
+  // Check no signal has occurred yet.
+  DALI_TEST_CHECK( !gSignalReceivedOK );
+  DALI_TEST_CHECK( !gSignalReceivedCancel );
+
+  // Provoke the signal.
+  Stage::GetCurrent().Add( popup );
+
+  // Check the signal has occurred.
+  DALI_TEST_CHECK( gSignalReceivedOK );
+  DALI_TEST_CHECK( !gSignalReceivedCancel );
+
+  // Remove the popup from the stage, and connect the cancel signal.
+  popup.Unparent();
+  popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED, "onStage" );
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED ).Get( resultProperty ) );
+  DALI_TEST_EQUALS( resultProperty, "onStage",  TEST_LOCATION );
+
+  popup.ConnectSignal( testTracker, "controlSignalCancel",   ConfirmationPopupCancelTestFunctor() );
+
+  // Check the cancel signal has not occurred yet.
+  DALI_TEST_CHECK( gSignalReceivedOK );
+  DALI_TEST_CHECK( !gSignalReceivedCancel );
+
+  // Provoke the signal.
+  Stage::GetCurrent().Add( popup );
+
+  // Check the cancel signal has occurred.
+  DALI_TEST_CHECK( gSignalReceivedOK );
+  DALI_TEST_CHECK( gSignalReceivedCancel );
+
+  END_TEST;
+}
+
+int UtcDaliConfirmationPopupDynamicSignalGenerationN(void)
+{
+  ToolkitTestApplication application;
+   tet_infoline( " UtcDaliConfirmationPopupDynamicSignalGenerationN" );
+
+   ConfirmationPopup popup = ConfirmationPopup::New();
+
+   TextLabel titleActor = TextLabel::New( "Title" );
+   popup.SetTitle( titleActor );
+
+   TextLabel contentActor = TextLabel::New( "Content" );
+   popup.SetContent( contentActor );
+
+   Actor footerActor = Actor::New();
+
+   PushButton buttonOK = PushButton::New();
+   buttonOK.SetName( "controlOkMisnamed" );
+   popup.SetFooter( buttonOK );
+
+   // Tell the confirmation popup to connect to the signal in our button called "onStage".
+   popup.SetProperty( Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED, "onStage" );
+
+   // Connect to the confirmation popup's OK signal.
+   gSignalReceivedOK = false;
+
+   // The connection will fail at this point as no actor with the name "controlOk" will be located.
+   TestConnectionTrackerObject* testTracker = new TestConnectionTrackerObject();
+   popup.ConnectSignal( testTracker, "controlSignalOk",   ConfirmationPopupOKTestFunctor() );
+
+   // Check no signal has occurred yet.
+   DALI_TEST_CHECK( !gSignalReceivedOK );
+
+   // Provoke the signal.
+   Stage::GetCurrent().Add( popup );
+
+   // Check the signal has still not occurred, as our button was incorrectly named.
+   DALI_TEST_CHECK( !gSignalReceivedOK );
+
+   END_TEST;
+}
+
+int UtcDaliConfirmationPopupTypeRegistryCreation(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliConfirmationPopupTypeRegistryCreation" );
+
+  TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "ConfirmationPopup" );
+  DALI_TEST_CHECK( typeInfo )
+
+  BaseHandle baseHandle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( baseHandle )
+
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( baseHandle );
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+
+  Stage::GetCurrent().Add( popup );
+  popup.SetDisplayState( Toolkit::Popup::SHOWN );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check the popup is shown.
+  DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::SHOWN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
new file mode 100755 (executable)
index 0000000..5255f10
--- /dev/null
@@ -0,0 +1,1196 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
+
+
+#include <toolkit-event-thread-callback.h>
+
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_control_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_control_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+
+bool gObjectCreatedCallBackCalled;
+
+void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+void TestVoidCallback()
+{
+}
+
+static bool gKeyInputFocusCallBackCalled;
+
+static void TestKeyInputFocusCallback( Control control )
+{
+  tet_infoline(" TestKeyInputFocusCallback");
+
+  gKeyInputFocusCallBackCalled = true;
+}
+
+const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/Kid1.svg";
+
+Vector4 GetControlBackgroundColor( Control& control )
+{
+  Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+
+  Vector4 color;
+  resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get( color );
+
+  return color;
+}
+
+bool gResourceReadySignalFired = false;
+
+void ResourceReadySignal( Control control )
+{
+  if( control.GetVisualResourceStatus( Control::Property::BACKGROUND ) == Visual::ResourceStatus::FAILED )
+  {
+    Property::Map propertyMap;
+    propertyMap.Insert( ImageVisual::Property::URL, TEST_SVG_FILE_NAME );
+    control.SetProperty( Control::Property::BACKGROUND, propertyMap );
+  }
+
+  gResourceReadySignalFired = true;
+}
+
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+int UtcDaliControlConstructor(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  DummyControl dummy;
+
+  DALI_TEST_CHECK( !Control::DownCast(dummy) );
+
+  dummy = DummyControl::New();
+
+  DALI_TEST_CHECK( Control::DownCast(dummy) );
+  END_TEST;
+}
+
+int UtcDaliControlNew(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control;
+
+  DALI_TEST_CHECK( !Control::DownCast(control) );
+
+  control = Control::New();
+
+  DALI_TEST_CHECK( Control::DownCast(control) );
+  END_TEST;
+}
+
+
+int UtcDaliControlRegister(void)
+{
+  ToolkitTestApplication application;
+
+  // Ensure the object is registered after creation
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    Alignment alignment = Alignment::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliControlCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl control = DummyControl::New();
+  Control emptyControl;
+
+  Control controlCopy( control );
+  DALI_TEST_CHECK( control == controlCopy );
+
+  Control emptyControlCopy( emptyControl );
+  DALI_TEST_CHECK( emptyControl == emptyControlCopy );
+
+  Control controlEquals;
+  controlEquals = control;
+  DALI_TEST_CHECK( control == controlEquals );
+
+  Control emptyControlEquals;
+  emptyControlEquals = emptyControl;
+  DALI_TEST_CHECK( emptyControl == emptyControlEquals );
+
+  // Self assignment
+  control = control;
+  DALI_TEST_CHECK( control == controlCopy );
+  END_TEST;
+}
+
+int UtcDaliControlDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl control;
+
+  DALI_TEST_CHECK( !Control::DownCast( control ) );
+
+  control = DummyControl::New();
+
+  DALI_TEST_CHECK( Control::DownCast( control ) );
+
+  Actor actor;
+
+  DALI_TEST_CHECK( !Control::DownCast( actor ) );
+
+  actor = Actor::New();
+
+  DALI_TEST_CHECK( !Control::DownCast( actor ) );
+  END_TEST;
+}
+
+int UtcDaliControlDownCastTemplate(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl control;
+
+  DALI_TEST_CHECK( !DummyControl::DownCast( control ));
+
+  control = DummyControl::New();
+
+  DALI_TEST_CHECK( DummyControl::DownCast( control ) );
+
+  Actor actor;
+
+  DALI_TEST_CHECK( !DummyControl::DownCast( actor ) );
+
+  actor = Actor::New();
+
+  DALI_TEST_CHECK( !DummyControl::DownCast( actor ) );
+  END_TEST;
+}
+
+int UtcDaliControlNavigationProperties(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  DALI_TEST_EQUALS( -1, control.GetProperty( DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  DALI_TEST_EQUALS( -1, control.GetProperty( DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  DALI_TEST_EQUALS( -1, control.GetProperty( DevelControl::Property::UP_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  DALI_TEST_EQUALS( -1, control.GetProperty( DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+
+  control.SetProperty( DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, 1 );
+  DALI_TEST_EQUALS( 1, control.GetProperty( DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, 2 );
+  DALI_TEST_EQUALS( 2, control.GetProperty( DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, 3 );
+  DALI_TEST_EQUALS( 3, control.GetProperty( DevelControl::Property::UP_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, 4 );
+  DALI_TEST_EQUALS( 4, control.GetProperty( DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+
+  control.SetProperty( DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, 15 );
+  DALI_TEST_EQUALS( 15, control.GetProperty( DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, 16 );
+  DALI_TEST_EQUALS( 16, control.GetProperty( DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, 17 );
+  DALI_TEST_EQUALS( 17, control.GetProperty( DevelControl::Property::UP_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+  control.SetProperty( DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, 18 );
+  DALI_TEST_EQUALS( 18, control.GetProperty( DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlKeyInputFocus(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  DummyControl control;
+
+  PushButton pushButton1 = PushButton::New();
+  stage.Add( pushButton1 );
+
+  pushButton1.SetKeyInputFocus();
+  DALI_TEST_CHECK( pushButton1.HasKeyInputFocus() );
+
+  pushButton1.ClearKeyInputFocus();
+  DALI_TEST_CHECK( !pushButton1.HasKeyInputFocus() );
+  END_TEST;
+}
+
+int UtcDaliControlGetImplementationN(void)
+{
+  ToolkitTestApplication application;
+  DummyControl control;
+
+  // Get Empty
+  {
+    try
+    {
+      Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( control );
+      (void)controlImpl; // Avoid unused warning
+      tet_result(TET_FAIL);
+    }
+    catch (DaliException &exception)
+    {
+      tet_result(TET_PASS);
+    }
+  }
+  END_TEST;
+}
+
+int UtcDaliControlGetImplementationConstN(void)
+{
+  ToolkitTestApplication application;
+  DummyControl control;
+
+  // Get Const Empty
+  {
+    try
+    {
+      const DummyControl constControl(control);
+      const Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( constControl );
+      (void)controlImpl; // Avoid unused warning
+      tet_result(TET_FAIL);
+    }
+    catch (DaliException &exception)
+    {
+      tet_result(TET_PASS);
+    }
+  }
+  END_TEST;
+}
+
+int UtcDaliControlGetImplementationP(void)
+{
+  ToolkitTestApplication application;
+  DummyControl control = DummyControl::New();
+
+  // Get
+  {
+    try
+    {
+      Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( control );
+      (void)controlImpl; // Avoid unused warning
+      tet_result(TET_PASS);
+    }
+    catch (DaliException &exception)
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+  END_TEST;
+}
+
+int UtcDaliControlGetImplementationConstP(void)
+{
+  ToolkitTestApplication application;
+  DummyControl control = DummyControl::New();
+  // Get Const
+  {
+    try
+    {
+      const DummyControl constControl(control);
+      const Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( constControl );
+      (void)controlImpl; // Avoid unused warning
+      tet_result(TET_PASS);
+    }
+    catch (DaliException &exception)
+    {
+      tet_result(TET_FAIL);
+    }
+  }
+  END_TEST;
+}
+
+int UtcDaliControlSignalConnectDisconnect(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControlImpl::New();
+
+    Actor actor = Actor::New();
+    DALI_TEST_EQUALS( actor.OnStageSignal().GetConnectionCount(), 0u, TEST_LOCATION );
+    Toolkit::Internal::Control& control = Toolkit::Internal::GetImplementation( dummy );
+    DummyControlImpl* dummyImpl = dynamic_cast<DummyControlImpl*>(&control);
+
+    if( dummyImpl == NULL )
+    {
+      tet_result( TET_FAIL );
+      END_TEST;
+    }
+
+    actor.OnStageSignal().Connect( dummyImpl, &DummyControlImpl::CustomSlot1 );
+    DALI_TEST_EQUALS( actor.OnStageSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( dummyImpl->mCustomSlot1Called, false, TEST_LOCATION );
+
+    Stage::GetCurrent().Add( actor );
+    DALI_TEST_EQUALS( dummyImpl->mCustomSlot1Called, true, TEST_LOCATION );
+
+    dummyImpl->mCustomSlot1Called = false;
+    actor.OnStageSignal().Disconnect( dummyImpl, &DummyControlImpl::CustomSlot1 );
+    DALI_TEST_EQUALS( actor.OnStageSignal().GetConnectionCount(), 0u, TEST_LOCATION );
+    Stage::GetCurrent().Remove( actor );
+    Stage::GetCurrent().Add( actor );
+    DALI_TEST_EQUALS( dummyImpl->mCustomSlot1Called, false, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliControlSignalAutomaticDisconnect(void)
+{
+  ToolkitTestApplication application;
+
+  Actor actor = Actor::New();
+
+  {
+    DummyControl dummy = DummyControlImpl::New();
+    Toolkit::Internal::Control& control = Toolkit::Internal::GetImplementation( dummy );
+    DummyControlImpl* dummyImpl = dynamic_cast<DummyControlImpl*>(&control);
+
+    if( dummyImpl == NULL )
+    {
+      tet_result( TET_FAIL );
+      END_TEST;
+    }
+
+    actor.OnStageSignal().Connect( dummyImpl, &DummyControlImpl::CustomSlot1 );
+    DALI_TEST_EQUALS( actor.OnStageSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+    DALI_TEST_EQUALS( dummyImpl->mCustomSlot1Called, false, TEST_LOCATION );
+
+    Stage::GetCurrent().Add( actor );
+    DALI_TEST_EQUALS( dummyImpl->mCustomSlot1Called, true, TEST_LOCATION );
+    Stage::GetCurrent().Remove( actor );
+  }
+  // dummyControl automatically disconnects
+
+  DALI_TEST_EQUALS( actor.OnStageSignal().GetConnectionCount(), 0u, TEST_LOCATION );
+
+  const Vector3 ignoredSize( 20, 20, 0 );
+  actor.SetSize( ignoredSize );
+  END_TEST;
+}
+
+int UtcDaliControlTestParameters(void)
+{
+  ToolkitTestApplication application;
+  DummyControl test = DummyControl::New();
+
+  test.SetSize( 0.7f, 0.7f, 0.7f );
+
+  Stage::GetCurrent().Add( test );
+
+  application.SendNotification();
+  application.Render();
+
+  float width = 640.0f;
+  float height = test.GetHeightForWidth( width );
+  DALI_TEST_EQUALS( 640.0f, height, TEST_LOCATION );
+  DALI_TEST_EQUALS( 640.0f, test.GetWidthForHeight( height ), TEST_LOCATION );
+
+  test.KeyEventSignal();
+
+  // Provide coverage for pointer destructor
+  Control* testControlPtr = new Control;
+  DALI_TEST_CHECK( testControlPtr );
+  delete testControlPtr;
+  END_TEST;
+}
+
+int UtcDaliControlBackgroundColor(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  DALI_TEST_CHECK( control.GetProperty( Control::Property::BACKGROUND ).Get< Property::Map >().Empty() );
+
+  control.SetProperty( Control::Property::BACKGROUND, Color::RED );
+
+  Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>() == Visual::COLOR );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>() == Color::RED );
+
+  control.SetProperty( Control::Property::BACKGROUND, Color::YELLOW );
+
+  propValue = control.GetProperty( Control::Property::BACKGROUND );
+  resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>() == Color::YELLOW );
+
+  END_TEST;
+}
+
+int UtcDaliControlBackgroundColorRendererCount(void)
+{
+  tet_infoline( "Test ensures we only create renderers when non-transparent color is requested or if we our clipping-mode is set to CLIP_CHILDREN" );
+
+  ToolkitTestApplication application;
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  tet_infoline( "Set transparent, no renderers should be created" );
+  control.SetBackgroundColor( Color::TRANSPARENT );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+  tet_infoline( "Set transparent alpha with positive RGB values, no renderers should be created, but returned color should reflect what we set" );
+  const Vector4 alphaZero( 1.0f, 0.5f, 0.25f, 0.0f );
+  control.SetBackgroundColor( alphaZero );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), alphaZero, TEST_LOCATION );
+
+  tet_infoline( "Set semi transparent alpha with positive RGB values, 1 renderer should be created, but returned color should reflect what we set" );
+  const Vector4 semiTransparent( 1.0f, 0.75f, 0.5f, 0.5f );
+  control.SetBackgroundColor( semiTransparent );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), semiTransparent, TEST_LOCATION );
+
+  tet_infoline( "Set transparent, ensure no renderers are created" );
+  control.SetBackgroundColor( Color::TRANSPARENT );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Set control to clip its children, a renderer should be created which will be transparent" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Set a color, only 1 renderer should exist" );
+  control.SetBackgroundColor( Color::RED );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::RED, TEST_LOCATION );
+
+  tet_infoline( "Clear the background, no renderers" );
+  control.ClearBackground();
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+
+  tet_infoline( "Set control to clip its children again, a renderer should be created which will be transparent" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  tet_infoline( "Disable clipping, no renderers" );
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::DISABLED );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( control.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetControlBackgroundColor( control ), Color::TRANSPARENT, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlBackgroundImage(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  tet_infoline( "Set first background image" );
+  control.SetProperty( Control::Property::BACKGROUND, "TestImage" );
+
+  Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>() == Visual::IMAGE );
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL ) );
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL )->Get<std::string>() == "TestImage" );
+
+  tet_infoline( "Set replacement background image" );
+  control.SetProperty( Control::Property::BACKGROUND, "TestImage2" );
+
+  propValue = control.GetProperty( Control::Property::BACKGROUND );
+  resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL ) );
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL )->Get<std::string>() == "TestImage2" );
+
+  END_TEST;
+}
+
+int UtcDaliControlBackgroundProperties(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  DALI_TEST_CHECK( control.GetProperty( Control::Property::BACKGROUND ).Get< Property::Map >().Empty() );
+
+  Property::Map imageMap;
+  imageMap[ Toolkit::Visual::Property::TYPE ] = Visual::IMAGE;
+  imageMap[ ImageVisual::Property::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( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(),(int)Visual::IMAGE, TEST_LOCATION );
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL ) );
+  DALI_TEST_EQUALS( resultMap->Find( ImageVisual::Property::URL )->Get<std::string>(), "TestImage", TEST_LOCATION );
+
+  Property::Map rendererMap;
+  rendererMap[Visual::Property::TYPE] = Visual::COLOR;
+  rendererMap[ColorVisual::Property::MIX_COLOR] = Color::CYAN;
+  control.SetProperty( Control::Property::BACKGROUND, rendererMap );
+  propValue = control.GetProperty( Control::Property::BACKGROUND );
+  resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(), (int)Visual::COLOR, TEST_LOCATION );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+  DALI_TEST_EQUALS( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>(), Color::CYAN, TEST_LOCATION );
+
+  Property::Map emptyMap;
+  control.SetProperty( Control::Property::BACKGROUND, emptyMap );
+  DALI_TEST_CHECK( control.GetProperty( Control::Property::BACKGROUND ).Get< Property::Map >().Empty() );
+
+  // set as URL
+  control.SetProperty( Control::Property::BACKGROUND, "Foobar.png" );
+  propValue = control.GetProperty( Control::Property::BACKGROUND );
+  resultMap = propValue.GetMap();
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(), (int)Visual::IMAGE, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultMap->Find( ImageVisual::Property::URL )->Get<std::string>(), "Foobar.png", TEST_LOCATION );
+
+  // set as Color
+  control.SetProperty( Control::Property::BACKGROUND, Color::RED );
+  propValue = control.GetProperty( Control::Property::BACKGROUND );
+  resultMap = propValue.GetMap();
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(), (int)Visual::COLOR, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlShadowProperties(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  DALI_TEST_CHECK( control.GetProperty( DevelControl::Property::SHADOW ).Get< Property::Map >().Empty() );
+
+  Property::Map imageMap;
+  imageMap[ Toolkit::Visual::Property::TYPE ] = Visual::IMAGE;
+  imageMap[ ImageVisual::Property::URL ] = "TestImage";
+  control.SetProperty( DevelControl::Property::SHADOW, imageMap );
+  Property::Value propValue = control.GetProperty( DevelControl::Property::SHADOW );
+  Property::Map* resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(),(int)Visual::IMAGE, TEST_LOCATION );
+  DALI_TEST_CHECK( resultMap->Find( ImageVisual::Property::URL ) );
+  DALI_TEST_EQUALS( resultMap->Find( ImageVisual::Property::URL )->Get<std::string>(), "TestImage", TEST_LOCATION );
+
+  Property::Map colorMap;
+  colorMap[Visual::Property::TYPE] = Visual::COLOR;
+  colorMap[ColorVisual::Property::MIX_COLOR] = Color::CYAN;
+  control.SetProperty( DevelControl::Property::SHADOW, colorMap );
+  propValue = control.GetProperty( DevelControl::Property::SHADOW );
+  resultMap = propValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(), (int)Visual::COLOR, TEST_LOCATION );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+  DALI_TEST_EQUALS( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>(), Color::CYAN, TEST_LOCATION );
+
+  Property::Map emptyMap;
+  control.SetProperty( DevelControl::Property::SHADOW, emptyMap );
+  DALI_TEST_CHECK( control.GetProperty( DevelControl::Property::SHADOW ).Get< Property::Map >().Empty() );
+
+  END_TEST;
+}
+
+int UtcDaliControlKeyProperties(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  DALI_TEST_EQUALS( control.HasKeyInputFocus(), control.GetProperty( Control::Property::KEY_INPUT_FOCUS ).Get< bool >(), TEST_LOCATION );
+
+  control.SetKeyInputFocus();
+  DALI_TEST_EQUALS( true, control.GetProperty( Control::Property::KEY_INPUT_FOCUS ).Get< bool >(), TEST_LOCATION );
+
+  control.ClearKeyInputFocus();
+  DALI_TEST_EQUALS( false, control.GetProperty( Control::Property::KEY_INPUT_FOCUS ).Get< bool >(), TEST_LOCATION );
+
+  control.SetProperty( Control::Property::KEY_INPUT_FOCUS, true );
+  DALI_TEST_EQUALS( true, control.HasKeyInputFocus(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlGestureSignals(void)
+{
+  ToolkitTestApplication application;
+  ConnectionTracker connectionTracker;
+  Control control = Control::New();
+
+  // Each gesture detector gets created when connecting to the gesture signals
+  DALI_TEST_CHECK( !control.GetTapGestureDetector() );
+  control.ConnectSignal( &connectionTracker, "tapped", &TestVoidCallback );
+  DALI_TEST_CHECK( control.GetTapGestureDetector() );
+
+  DALI_TEST_CHECK( !control.GetPanGestureDetector() );
+  control.ConnectSignal( &connectionTracker, "panned", &TestVoidCallback );
+  DALI_TEST_CHECK( control.GetPanGestureDetector() );
+
+  DALI_TEST_CHECK( !control.GetPinchGestureDetector() );
+  control.ConnectSignal( &connectionTracker, "pinched", &TestVoidCallback );
+  DALI_TEST_CHECK( control.GetPinchGestureDetector() );
+
+  DALI_TEST_CHECK( !control.GetLongPressGestureDetector() );
+  control.ConnectSignal( &connectionTracker, "longPressed",  &TestVoidCallback );
+  DALI_TEST_CHECK( control.GetLongPressGestureDetector() );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplKeyInputFocusGainedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  gKeyInputFocusCallBackCalled = false;
+  control.KeyInputFocusGainedSignal().Connect(&TestKeyInputFocusCallback);
+
+  application.SendNotification();
+  application.Render();
+
+  control.SetKeyInputFocus();
+
+  DALI_TEST_CHECK( control.HasKeyInputFocus() );
+
+  DALI_TEST_CHECK( gKeyInputFocusCallBackCalled );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplKeyInputFocusLostSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  Stage::GetCurrent().Add( control );
+
+  gKeyInputFocusCallBackCalled = false;
+  control.KeyInputFocusLostSignal().Connect(&TestKeyInputFocusCallback);
+
+  application.SendNotification();
+  application.Render();
+
+  control.SetKeyInputFocus();
+
+  DALI_TEST_CHECK( control.HasKeyInputFocus() );
+
+  control.ClearKeyInputFocus();
+
+  DALI_TEST_CHECK( gKeyInputFocusCallBackCalled );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplGetControlExtensionP(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( control );
+
+  DALI_TEST_CHECK( NULL == controlImpl.GetControlExtension() );
+
+  END_TEST;
+}
+
+int UtcDaliControlAutoClipping(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  tet_infoline( "Test to see if a renderer gets added when we are clipping children" );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlAutoClippingN(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+  control.SetProperty( Control::Property::BACKGROUND, Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::COLOR )
+                                                                     .Add( ColorVisual::Property::MIX_COLOR, Color::RED ) );
+
+  tet_infoline( "Test to ensure that a renderer does NOT get added when we are clipping children and already have renderers/visuals" );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); // Only 1, not 2
+
+  // Ensure the background color is still RED rather than what's set by the automatic clipping
+  Property::Value value = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  Property::Value* colorValue = map->Find(ColorVisual::Property::MIX_COLOR );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_EQUALS( colorValue->Get< Vector4 >(), Color::RED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlAutoClippingWhenAlreadyOnStage(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  tet_infoline( "Test to see if a renderer gets added when we are clipping children and when already on stage" );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlAutoClippingWhenAlreadyOnStageN(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+  control.SetProperty( Control::Property::BACKGROUND, Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::COLOR )
+                                                                     .Add( ColorVisual::Property::MIX_COLOR, Color::RED ) );
+
+  tet_infoline( "Test to ensure that a renderer does NOT get added when we are clipping children and already have renderers/visuals and when already on stage" );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION );
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1, control.GetRendererCount(), TEST_LOCATION ); // Still should be 1
+
+  // Ensure the background color is still RED rather than what's set by the automatic clipping
+  Property::Value value = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  Property::Value* colorValue = map->Find(ColorVisual::Property::MIX_COLOR );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_EQUALS( colorValue->Get< Vector4 >(), Color::RED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlSetTransformSize(void)
+{
+  ToolkitTestApplication application;
+  Control control = Control::New();
+
+  Property::Map transformMap;
+  transformMap.Add( Visual::Transform::Property::OFFSET, Vector2( 10, 10 ) )
+              .Add( Visual::Transform::Property::ANCHOR_POINT, Align::BOTTOM_END )
+              .Add( Visual::Transform::Property::ORIGIN, Align::BOTTOM_END )
+              .Add( Visual::Transform::Property::SIZE, Vector2( 10, 20 ) );
+
+  control.SetProperty( Control::Property::BACKGROUND, Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::COLOR )
+                                                                     .Add( Visual::Property::TRANSFORM, transformMap ) );
+
+  tet_infoline( "Test to ensure that the control background transform does not get overwritten when adding to the stage" );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  // Ensure the transform property still matches what we set
+  Property::Value value = control.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  Property::Value* transformValue = map->Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 10, 10 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::ANCHOR_POINT )->Get< int >(), (int)Align::BOTTOM_END, TEST_LOCATION );
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::ORIGIN )->Get< int >(), (int)Align::BOTTOM_END, TEST_LOCATION );
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::SIZE )->Get< Vector2 >(), Vector2( 10, 20 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliControlResourcesReady(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register 2 visuals and check ResourceReady when a visual is disabled" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMapLarge;
+  propertyMapLarge.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMapLarge.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+
+  Property::Map propertyMapSmall;
+  propertyMapSmall.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMapSmall.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+
+  Visual::Base smallVisual = factory.CreateVisual( propertyMapSmall );
+  smallVisual.SetName("smallVisual");
+  DALI_TEST_CHECK( smallVisual );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, smallVisual );
+
+  actor.SetSize( 200.f, 200.f );
+
+  Toolkit::Visual::ResourceStatus resourceStatus = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(resourceStatus), static_cast<int>(Toolkit::Visual::ResourceStatus::PREPARING), TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  resourceStatus = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL);
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(resourceStatus), static_cast<int>(Toolkit::Visual::ResourceStatus::READY), TEST_LOCATION );
+
+  Visual::Base largeVisual = factory.CreateVisual( propertyMapLarge );
+  largeVisual.SetName("largeVisual");
+  DALI_TEST_CHECK( largeVisual );
+
+  tet_infoline( "Register Visual but set disabled, IsResourceReady should be true" );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, largeVisual, false );
+
+  resourceStatus = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL2);
+  DALI_TEST_EQUALS( static_cast<int>(resourceStatus), static_cast<int>(Toolkit::Visual::ResourceStatus::PREPARING), TEST_LOCATION );
+
+  application.SendNotification();
+
+  resourceStatus = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL2);
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(resourceStatus), static_cast<int>(Toolkit::Visual::ResourceStatus::PREPARING), TEST_LOCATION );
+
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL2, true );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+
+  resourceStatus = actor.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL2);
+  DALI_TEST_EQUALS( static_cast<int>(resourceStatus), static_cast<int>(Toolkit::Visual::ResourceStatus::READY), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlResourcesReady02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Change a resource during ResourceReady callback" );
+
+  gResourceReadySignalFired = false;
+
+  Control control = Control::New();
+  control.SetSize( 200.f, 200.f );
+  control.ResourceReadySignal().Connect( &ResourceReadySignal );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( ImageVisual::Property::URL, "invalid.jpg" );
+  control.SetProperty( Control::Property::BACKGROUND, propertyMap );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( control.IsResourceReady(), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+  gResourceReadySignalFired = false;
+
+  END_TEST;
+}
+
+int UtcDaliControlMarginProperty(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  control.SetBackgroundColor( Color::BLUE );
+
+  control.SetProperty( Control::Property::MARGIN, Extents( 20, 10, 0, 0 ) );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( control.GetProperty<Extents>( Control::Property::MARGIN ), Extents( 20, 10, 0, 0 ), TEST_LOCATION );
+
+  // Parent control has one ImageView as a Child.
+  ImageView image = ImageView::New();
+  image.SetBackgroundColor( Color::RED );
+  image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  image.SetProperty( Control::Property::PADDING, Extents( 10, 10, 10, 10 ) );
+  control.Add( image );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( image.GetProperty<Extents>( Control::Property::PADDING ), Extents( 10, 10, 10, 10 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlPaddingProperty(void)
+{
+  ToolkitTestApplication application;
+
+  Control control = Control::New();
+  control.SetBackgroundColor( Color::BLUE );
+
+  control.SetProperty( Control::Property::PADDING, Extents( 15, 10, 5, 10 ) );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( control.GetProperty<Extents>( Control::Property::PADDING ), Extents( 15, 10, 5, 10 ), TEST_LOCATION );
+
+  Control child = Control::New();
+  control.Add(child);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( child.GetProperty<Vector3>( Dali::Actor::Property::POSITION ), Vector3( 15, 5, 0 ), TEST_LOCATION );
+
+  control.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,  Dali::LayoutDirection::RIGHT_TO_LEFT);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( child.GetProperty<Vector3>( Dali::Actor::Property::POSITION ), Vector3( 10, 5, 0 ), TEST_LOCATION );
+
+  control.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,  Dali::LayoutDirection::LEFT_TO_RIGHT);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( child.GetProperty<Vector3>( Dali::Actor::Property::POSITION ), Vector3( 15, 5, 0 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlDoAction(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "DoAction on a visual registered with a control" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable( true );
+
+  //Created AnimatedImageVisual
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base imageVisual = factory.CreateVisual( TEST_IMAGE_FILE_NAME, ImageDimensions() );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  Property::Map attributes;
+  DevelControl::DoAction( dummyControl,  DummyControl::Property::TEST_VISUAL, DevelImageVisual::Action::RELOAD, attributes );
+
+  tet_infoline( "Perform RELOAD action. should reload Image and generate a texture" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliControlDoActionWhenNotStage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "DoAction on a visual registered with a control but not staged" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable( true );
+
+  //Created AnimatedImageVisual
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base imageVisual = factory.CreateVisual( TEST_IMAGE_FILE_NAME, ImageDimensions() );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  dummyControl.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  Property::Map attributes;
+  DevelControl::DoAction( dummyControl,  DummyControl::Property::TEST_VISUAL, DevelImageVisual::Action::RELOAD, attributes );
+
+  tet_infoline( "Perform RELOAD action. should reload Image and generate a texture" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Adding control to stage will in turn add the visual to the stage" );
+
+  Stage::GetCurrent().Add( dummyControl );
+  application.SendNotification();
+  application.Render();
+  tet_infoline( "No change in textures could occurs as already loaded and cached texture will be used" );
+
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp
new file mode 100644 (file)
index 0000000..31f3094
--- /dev/null
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include "toolkit-style-monitor.h"
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+
+
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_control_impl_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_control_impl_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliControlImplNew(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control;
+
+  DALI_TEST_CHECK( !Control::DownCast(control) );
+
+  control = Toolkit::Internal::Control::New();
+
+  DALI_TEST_CHECK( Control::DownCast(control) );
+  END_TEST;
+}
+
+
+int UtcDaliControlImplEnableGestureDetector(void)
+{
+  ToolkitTestApplication application;
+
+  // Enable individually
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+    dummyImpl.EnableGestureDetection(Gesture::Pinch);
+    DALI_TEST_CHECK( dummyImpl.GetPinchGestureDetector() );
+
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+    dummyImpl.EnableGestureDetection(Gesture::Pan);
+    DALI_TEST_CHECK( dummyImpl.GetPanGestureDetector() );
+
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+    dummyImpl.EnableGestureDetection(Gesture::Tap);
+    DALI_TEST_CHECK( dummyImpl.GetTapGestureDetector() );
+
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+    dummyImpl.EnableGestureDetection(Gesture::LongPress);
+    DALI_TEST_CHECK( dummyImpl.GetLongPressGestureDetector() );
+  }
+
+  // Enable All
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetLongPressGestureDetector() );
+
+    // Enable when already enabled
+
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetLongPressGestureDetector() );
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplDisableGestureDetector(void)
+{
+  ToolkitTestApplication application;
+
+  // Disable individually
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( dummyImpl.GetPinchGestureDetector() );
+    dummyImpl.DisableGestureDetection(Gesture::Pinch);
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+
+    DALI_TEST_CHECK( dummyImpl.GetPanGestureDetector() );
+    dummyImpl.DisableGestureDetection(Gesture::Pan);
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+
+    DALI_TEST_CHECK( dummyImpl.GetTapGestureDetector() );
+    dummyImpl.DisableGestureDetection(Gesture::Tap);
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+
+    DALI_TEST_CHECK( dummyImpl.GetLongPressGestureDetector() );
+    dummyImpl.DisableGestureDetection(Gesture::LongPress);
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+  }
+
+  // Disable All
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( dummyImpl.GetLongPressGestureDetector() );
+
+    dummyImpl.DisableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+  }
+
+  // Disable When not enabled
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+
+    dummyImpl.DisableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( !dummyImpl.GetPinchGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetPanGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetTapGestureDetector() );
+    DALI_TEST_CHECK( !dummyImpl.GetLongPressGestureDetector() );
+  }
+
+  // Ensure control is detached if gesture detector is not deleted
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    PinchGestureDetector pinch = dummyImpl.GetPinchGestureDetector();
+    PanGestureDetector pan   = dummyImpl.GetPanGestureDetector();
+    TapGestureDetector tap = dummyImpl.GetTapGestureDetector();
+    LongPressGestureDetector longPress = dummyImpl.GetLongPressGestureDetector();
+
+    DALI_TEST_EQUALS( 0 == pinch.GetAttachedActorCount(), false, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == pan.GetAttachedActorCount(), false, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == tap.GetAttachedActorCount(), false, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == longPress.GetAttachedActorCount(), false, TEST_LOCATION );
+
+    dummyImpl.DisableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_EQUALS( 0 == pinch.GetAttachedActorCount(), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == pan.GetAttachedActorCount(), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == tap.GetAttachedActorCount(), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( 0 == longPress.GetAttachedActorCount(), true, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplOnGestureMethods(void)
+{
+  ToolkitTestApplication application;
+
+  // Check gesture actually happens
+  {
+    DummyControl dummy = DummyControl::New(true);
+    dummy.SetSize( Vector2(100.0f, 100.0f ) );
+
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    // Render and notify a couple of times
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+    application.Render();
+
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+    dummyImpl.EnableGestureDetection( Gesture::Type(Gesture::Pinch | Gesture::Pan | Gesture::Tap | Gesture::LongPress) );
+
+    DALI_TEST_CHECK( dummyImpl.pinchCalled == false );
+
+    TestGeneratePinch(application);
+
+    DALI_TEST_CHECK( dummyImpl.pinchCalled == true );
+
+    DALI_TEST_CHECK( dummyImpl.panCalled == false );
+
+    TestGenerateMiniPan(application);
+
+    DALI_TEST_CHECK( dummyImpl.panCalled == true );
+
+    DALI_TEST_CHECK( dummyImpl.tapCalled == false );
+
+    TestGenerateTap(application);
+
+    DALI_TEST_CHECK( dummyImpl.tapCalled == true );
+
+    DALI_TEST_CHECK( dummyImpl.longPressCalled == false );
+
+    TestGenerateLongPress(application);
+
+    DALI_TEST_CHECK( dummyImpl.longPressCalled == true );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliControlImplChildAddAndRemove(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Stage::GetCurrent().Add(dummy);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.childAddCalled, false, TEST_LOCATION );
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 0u, TEST_LOCATION );
+    Actor actor = Actor::New();
+    dummy.Add(actor);
+    DALI_TEST_EQUALS( dummyImpl.childAddCalled, true, TEST_LOCATION );
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 1u, TEST_LOCATION );
+
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.childRemoveCalled, false, TEST_LOCATION );
+    dummy.Remove( actor );
+    DALI_TEST_EQUALS( dummyImpl.childRemoveCalled, true, TEST_LOCATION );
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 0u, TEST_LOCATION );
+
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+    Stage::GetCurrent().Add(dummy);
+
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 0u, TEST_LOCATION );
+    Actor actor = Actor::New();
+    dummy.Add(actor);
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 1u, TEST_LOCATION );
+
+    application.Render();
+    application.SendNotification();
+
+    dummy.Remove( actor );
+    DALI_TEST_EQUALS( dummy.GetChildCount(), 0u, TEST_LOCATION );
+
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplStageConnection(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    DALI_TEST_EQUALS( dummyImpl.stageConnectionCalled, false, TEST_LOCATION );
+    Stage::GetCurrent().Add(dummy);
+    application.Render();
+    application.SendNotification();
+    DALI_TEST_EQUALS( dummyImpl.stageConnectionCalled, true, TEST_LOCATION );
+
+    DALI_TEST_EQUALS( dummyImpl.stageDisconnectionCalled, false, TEST_LOCATION );
+    Stage::GetCurrent().Remove(dummy);
+    application.Render();
+    application.SendNotification();
+    DALI_TEST_EQUALS( dummyImpl.stageDisconnectionCalled, true, TEST_LOCATION );
+  }
+
+  // Ensure full code coverage
+  {
+    unsigned int stageChildren = Stage::GetCurrent().GetLayer(0).GetChildCount();
+    DummyControl dummy = DummyControl::New();
+
+    DALI_TEST_EQUALS( Stage::GetCurrent().GetLayer(0).GetChildCount(), stageChildren, TEST_LOCATION );
+    Stage::GetCurrent().Add(dummy);
+    application.Render();
+    application.SendNotification();
+    DALI_TEST_EQUALS( Stage::GetCurrent().GetLayer(0).GetChildCount(), stageChildren + 1, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+    application.Render();
+    application.SendNotification();
+    DALI_TEST_EQUALS( Stage::GetCurrent().GetLayer(0).GetChildCount(), stageChildren, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplSizeSetP(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    Stage::GetCurrent().Add(dummy);
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.sizeSetCalled, false, TEST_LOCATION ); // Size not set, no onSizeSet called
+    Vector2 size(100.0f, 200.0f);
+    dummy.SetSize( size );
+
+    DALI_TEST_EQUALS( dummyImpl.sizeSetCalled, false, TEST_LOCATION ); // Size is going to get negotiated, no onSizeSet called
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( size, dummy.GetCurrentSize().GetVectorXY(), TEST_LOCATION );
+    DALI_TEST_EQUALS( dummyImpl.sizeSetCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliControlImplSizeSet2P(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New();
+    Stage::GetCurrent().Add(dummy);
+
+    Vector2 size(100.0f, 200.0f);
+    DALI_TEST_CHECK( size != dummy.GetCurrentSize().GetVectorXY() );
+
+    application.SendNotification();
+    application.Render();
+
+    dummy.SetSize(size);
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS(size, dummy.GetCurrentSize().GetVectorXY(), TEST_LOCATION);
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+
+int UtcDaliControlImplSizeAnimation(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    Stage::GetCurrent().Add(dummy);
+
+    DALI_TEST_EQUALS( dummyImpl.sizeAnimationCalled, false, TEST_LOCATION );
+    Animation animation = Animation::New(1.0f);
+    animation.AnimateTo( Property( dummy, Actor::Property::SIZE ), Vector3( 100.0f, 150.0f, 200.0f ) );
+    animation.Play();
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.sizeAnimationCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    Stage::GetCurrent().Add(dummy);
+
+    Animation animation = Animation::New(1.0f);
+    animation.AnimateTo( Property( dummy, Actor::Property::SIZE ), Vector3( 100.0f, 150.0f, 200.0f ) );
+    animation.Play();
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliControlImplTouchEvent(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.touchEventCalled, false, TEST_LOCATION );
+    Integration::TouchEvent touchEvent(1);
+    Integration::Point point;
+    point.SetDeviceId( 1 );
+    point.SetState( PointState::DOWN );
+    point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+    touchEvent.AddPoint(point);
+    application.ProcessEvent(touchEvent);
+    DALI_TEST_EQUALS( dummyImpl.touchEventCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    Integration::TouchEvent touchEvent(1);
+    Integration::Point point;
+    point.SetDeviceId( 1 );
+    point.SetState( PointState::DOWN );
+    point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+    touchEvent.AddPoint(point);
+    application.ProcessEvent(touchEvent);
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplHoverEvent(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.hoverEventCalled, false, TEST_LOCATION );
+    Integration::HoverEvent event(1);
+    Integration::Point point;
+    point.SetDeviceId( 1 );
+    point.SetState( PointState::MOTION );
+    point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+    event.AddPoint(point);
+    application.ProcessEvent( event );
+    DALI_TEST_EQUALS( dummyImpl.hoverEventCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    Integration::HoverEvent event(1);
+    Integration::Point point;
+    point.SetDeviceId( 1 );
+    point.SetState( PointState::MOTION );
+    point.SetScreenPosition( Vector2( 20.0f, 20.0f ) );
+    event.AddPoint(point);
+    application.ProcessEvent( event );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+int UtcDaliControlImplKeyEvent(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    Stage::GetCurrent().Add(dummy);
+    dummy.SetKeyInputFocus();
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.keyEventCalled, false, TEST_LOCATION );
+    Integration::KeyEvent keyEvent;
+    application.ProcessEvent(keyEvent);
+    DALI_TEST_EQUALS( dummyImpl.keyEventCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    Stage::GetCurrent().Add(dummy);
+    dummy.SetKeyInputFocus();
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    Integration::KeyEvent keyEvent;
+    application.ProcessEvent(keyEvent);
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplKeyInputFocusGained(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    Stage::GetCurrent().Add(dummy);
+
+    DALI_TEST_EQUALS( dummyImpl.keyInputFocusGained, false, TEST_LOCATION );
+
+    dummy.SetKeyInputFocus();
+
+    DALI_TEST_EQUALS( dummyImpl.keyInputFocusGained, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    Stage::GetCurrent().Add(dummy);
+    dummy.SetKeyInputFocus();
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplKeyInputFocusLost(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    Stage::GetCurrent().Add(dummy);
+
+    DALI_TEST_EQUALS( dummyImpl.keyInputFocusLost, false, TEST_LOCATION );
+
+    dummy.SetKeyInputFocus();
+    dummy.ClearKeyInputFocus();
+
+    DALI_TEST_EQUALS( dummyImpl.keyInputFocusLost, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    Stage::GetCurrent().Add(dummy);
+    dummy.SetKeyInputFocus();
+    dummy.ClearKeyInputFocus();
+
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    dummyImpl.IsKeyboardNavigationSupported();
+    dummyImpl.IsKeyboardFocusGroup();
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "Control" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  // Check if it's a control
+  DALI_TEST_CHECK( Control::DownCast(handle) );
+  END_TEST;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+namespace
+{
+static bool WheelEventCallback(Actor actor, const WheelEvent& event)
+{
+  return false;
+}
+}
+
+int UtcDaliControlImplWheelEvent(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    dummy.WheelEventSignal().Connect(&WheelEventCallback);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( dummyImpl.wheelEventCalled, false, TEST_LOCATION );
+
+    // simulate a wheel event
+    Vector2 screenCoordinates( 10.0f, 10.0f );
+    Integration::WheelEvent event( Integration::WheelEvent::MOUSE_WHEEL, 0, 0u, screenCoordinates, 1, 1000u );
+    application.ProcessEvent( event );
+    DALI_TEST_EQUALS( dummyImpl.wheelEventCalled, true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+
+  // Ensure full code coverage
+  {
+    DummyControl dummy = DummyControl::New();
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    dummy.WheelEventSignal().Connect(&WheelEventCallback);
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    // simulate a wheel event
+    Vector2 screenCoordinates( 20.0f, 20.0f );
+    Integration::WheelEvent event( Integration::WheelEvent::MOUSE_WHEEL, 0, 0u, screenCoordinates, 1, 1000u );
+    application.ProcessEvent( event );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplSetStyleName(void)
+{
+  ToolkitTestApplication application;
+
+  {
+    DummyControl dummy = DummyControl::New( true );
+
+    dummy.SetSize( Vector2( 100.0f, 100.0f ) );
+    dummy.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+    Stage::GetCurrent().Add(dummy);
+
+    dummy.SetStyleName("TestStyle");
+
+    DALI_TEST_CHECK( dummy.GetStyleName() == "TestStyle" );
+
+    Stage::GetCurrent().Remove(dummy);
+  }
+  END_TEST;
+}
+
+int UtcDaliControlImplOnStyleChangeN(void)
+{
+  ToolkitTestApplication application;
+  Control dummy = Control::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( dummy );
+
+  // test that style manager is being used, passing an empty handle does nothing but does not crash either
+  Dali::Toolkit::StyleManager styleManager;
+  controlImpl.OnStyleChange( styleManager, StyleChange::THEME_CHANGE );
+  // no crash so test passes
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+
+int UtcDaliControlImplOnAccessibilityPanP(void)
+{
+  ToolkitTestApplication application;
+  Control dummy = Control::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( dummy );
+
+  PanGesture pan;
+  DALI_TEST_EQUALS( false, controlImpl.OnAccessibilityPan( pan ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplOnAccessibilityTouchP(void)
+{
+  ToolkitTestApplication application;
+  Control dummy = Control::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( dummy );
+  TouchEvent touch;
+  DALI_TEST_EQUALS( false, controlImpl.OnAccessibilityTouch( touch ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplOnAccessibilityActivatedP(void)
+{
+  ToolkitTestApplication application;
+
+  Control dummy = Control::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( dummy );
+  DALI_TEST_EQUALS( false, controlImpl.OnAccessibilityActivated(), TEST_LOCATION );
+
+  // Invoke the control's activate action
+  TypeInfo type = TypeRegistry::Get().GetTypeInfo( "Control" );
+  DALI_TEST_CHECK( type );
+
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  Property::Map attributes;
+  DALI_TEST_EQUALS( false, handle.DoAction("accessibilityActivated",  attributes), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplGetNextKeyboardFocusableActorP(void)
+{
+  ToolkitTestApplication application;
+  Control dummy = Control::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( dummy );
+
+  Actor currentFocusedActor;
+  Actor result = controlImpl.GetNextKeyboardFocusableActor( currentFocusedActor, Control::KeyboardFocus::LEFT, false );
+
+  DALI_TEST_EQUALS( result, currentFocusedActor, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterThenReRegisterVisual(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index index =1;
+
+  DALI_TEST_CHECK( !dummyImpl.GetVisual( index )  );
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( index, visual );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+
+  Property::Map newMap;
+  newMap[Visual::Property::TYPE] = Visual::COLOR;
+  newMap[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+
+  visual = visualFactory.CreateVisual( newMap );
+  DALI_TEST_CHECK(visual);
+
+  // ReRegister with altered color visual
+  dummyImpl.RegisterVisual( index, visual );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+
+  tet_result(TET_PASS);
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterVisaulThenReRegisterToSelf(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index index =1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( index, visual );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+
+  // ReRegister to self
+  dummyImpl.RegisterVisual( index, visual );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterVisualToSelf(void)
+{
+  ToolkitTestApplication application;
+
+  Test::ObjectDestructionTracker objectDestructionTracker;
+
+  {
+    DummyControl dummy = DummyControl::New();
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+    objectDestructionTracker.Start( dummy );
+
+    Property::Index index = 1;
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base visual;
+
+    Property::Map map;
+    map[Visual::Property::TYPE] = Visual::COLOR;
+    map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+    visual = visualFactory.CreateVisual( map );
+    DALI_TEST_CHECK(visual);
+
+    // Register to self
+    dummyImpl.RegisterVisual( index, visual );
+
+    DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), false, TEST_LOCATION ); // Control not destroyed yet
+    DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+  }
+
+  DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), true, TEST_LOCATION ); // Should be destroyed
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterTwoVisuals(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index index =1;
+  Property::Index index2 =2;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+  Toolkit::Visual::Base secondVisual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( index, visual );
+
+  Property::Map newMap;
+  newMap[Visual::Property::TYPE] = Visual::COLOR;
+  newMap[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+
+  secondVisual = visualFactory.CreateVisual( newMap );
+  DALI_TEST_CHECK( secondVisual );
+
+  // ReRegister with altered color visual
+  dummyImpl.RegisterVisual( index2, secondVisual );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index2 ) == secondVisual );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterUnregisterVisual(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index index =1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( index, visual );
+
+  tet_infoline( "Add control with visual to stage and check renderer count is 1" );
+  Stage::GetCurrent().Add( dummy );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( index ) == visual );
+  DALI_TEST_EQUALS( dummy.GetRendererCount(), 1, TEST_LOCATION );
+
+  // Unregister visual
+  dummyImpl.UnregisterVisual( index );
+
+  tet_infoline( "Remove control with visual from stage and check renderer count is 0" );
+  Stage::GetCurrent().Remove( dummy );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( dummy.GetRendererCount(), 0, TEST_LOCATION );
+  DALI_TEST_CHECK( !dummyImpl.GetVisual( index ) );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterDisabledVisual(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index TEST_PROPERTY =1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( TEST_PROPERTY, visual, false );
+
+  DALI_TEST_CHECK( dummyImpl.GetVisual( TEST_PROPERTY ) == visual );
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == false );
+
+  Stage::GetCurrent().Add(dummy);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == false );
+
+  DALI_TEST_CHECK( dummy.OnStage() == true );
+
+  dummyImpl.EnableVisual( TEST_PROPERTY, true );
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == true );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplDisableRegisteredVisual(void)
+{
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index TEST_PROPERTY =1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( TEST_PROPERTY, visual );
+
+  Stage::GetCurrent().Add(dummy);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == true);
+
+  DALI_TEST_CHECK( dummy.OnStage() == true );
+
+  dummyImpl.EnableVisual( TEST_PROPERTY, false );
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == false );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplEnabledVisualParentRemovedFromStage(void)
+{
+  // Visual enabled but then parent removed from stage, test ensures visual/renderer are also removed from stage.
+  // Then adding parent back to stage should automatically put visual/renderer back
+
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index TEST_PROPERTY =1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( TEST_PROPERTY, visual, false );
+
+  Stage::GetCurrent().Add(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == false );
+  DALI_TEST_CHECK( dummy.OnStage() == true );
+  dummyImpl.EnableVisual( TEST_PROPERTY, true );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 1u );
+
+  // Remove control from stage, visual should be removed from stage too
+  Stage::GetCurrent().Remove(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 0u );
+
+  Stage::GetCurrent().Add(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 1u );
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY ) == true );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplRegisterTwoVisualsAndEnableOnlyOne(void)
+{
+  // Register 2 visuals and enable by default
+  // Disable 1 visual
+  // Remove control from stage then put it back
+  // Check that only 1 visual/renderer is staged.
+
+  ToolkitTestApplication application;
+
+  DummyControl dummy = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(dummy.GetImplementation());
+
+  Property::Index TEST_PROPERTY1 =1;
+  Property::Index TEST_PROPERTY2 =2;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual1;
+  Toolkit::Visual::Base visual2;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  Property::Map map2;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+
+  visual1 = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual1);
+
+  visual2 = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual2);
+
+  // Register index with a color visual
+  dummyImpl.RegisterVisual( TEST_PROPERTY1, visual1 );
+  // Register second index with a color visual
+  dummyImpl.RegisterVisual( TEST_PROPERTY2, visual2 );
+
+  Stage::GetCurrent().Add(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 2u );
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY1 ) == true );
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY1 ) == true);
+  DALI_TEST_CHECK( dummy.OnStage() == true );
+  dummyImpl.EnableVisual( TEST_PROPERTY2, false );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 1u );
+
+  // Remove control from stage, visual should be removed from stage too
+  Stage::GetCurrent().Remove(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 0u );
+
+  Stage::GetCurrent().Add(dummy);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( dummy.GetRendererCount() == 1u );
+
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY1 ) == true );
+  DALI_TEST_CHECK( dummyImpl.IsVisualEnabled( TEST_PROPERTY2 ) == false );
+
+  END_TEST;
+}
+int UtcDaliControlImplAutoClippingWithVisuals(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Test to ensure a renderer does NOT get added when we've already registered a visual which we haven't enabled" );
+
+  DummyControl control = DummyControl::New();
+  DummyControlImpl& controlImpl = static_cast<DummyControlImpl&>( control.GetImplementation() );
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+  controlImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual, false );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlImplAutoClippingWithVisualsAlreadyOnStage(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Test to ensure a renderer does NOT get added when we've already registered a visual which we haven't enabled and we're already on the stage" );
+
+  DummyControl control = DummyControl::New();
+  DummyControlImpl& controlImpl = static_cast<DummyControlImpl&>( control.GetImplementation() );
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+  controlImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual, false );
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  Stage::GetCurrent().Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  control.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_CHILDREN );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 0, control.GetRendererCount(), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp
new file mode 100644 (file)
index 0000000..0921d61
--- /dev/null
@@ -0,0 +1,841 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/actors/custom-actor-devel.h>
+#include <dali/devel-api/object/csharp-type-registry.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/control-wrapper.h>
+#include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_control_wrapper_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_control_wrapper_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+bool gOnRelayout = false;
+
+static bool gKeyInputFocusCallBackCalled;
+
+static void TestKeyInputFocusCallback( Control control )
+{
+  tet_infoline(" TestKeyInputFocusCallback");
+
+  gKeyInputFocusCallBackCalled = true;
+}
+} // namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+namespace Impl
+{
+struct TestCustomControl : public Toolkit::Internal::ControlWrapper
+{
+  /**
+   * Constructor
+   */
+  TestCustomControl()  : Toolkit::Internal::ControlWrapper( CustomControlBehaviour( Toolkit::Internal::ControlWrapper::DISABLE_STYLE_CHANGE_SIGNALS |
+          Toolkit::Internal::ControlWrapper::REQUIRES_KEYBOARD_NAVIGATION_SUPPORT )) ,
+          mDaliProperty( Property::INVALID_INDEX ),
+          mSizeSet( Vector3::ZERO ),
+          mTargetSize( Vector3::ZERO ),
+          mNego( false ),
+          mDepth( 0u )
+  {
+  }
+
+  TestCustomControl(bool nego)  : Toolkit::Internal::ControlWrapper( CustomControlBehaviour( Toolkit::Internal::ControlWrapper::DISABLE_STYLE_CHANGE_SIGNALS |
+          Toolkit::Internal::ControlWrapper::REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
+          mDaliProperty( Property::INVALID_INDEX ),
+          mSizeSet( Vector3::ZERO ),
+          mTargetSize( Vector3::ZERO ),
+          mNego( nego ),
+          mDepth( 0u )
+  {
+  }
+
+  /**
+   * Destructor
+   */
+  virtual ~TestCustomControl()
+  {
+  }
+
+  void Initialize( const char* name = NULL )
+  {
+    mDaliProperty = Self().RegisterProperty( "Dali", std::string("no"), Property::READ_WRITE );
+
+    OnInitialize( name );
+  }
+
+  using Control::OnInitialize; ///< To tell the compiler that we really do want to overload OnInitialize in this class & were not trying to override it
+  virtual void OnInitialize( const char* name ) {}
+
+  // From Toolkit::Internal::ControlWrapper
+  virtual void OnStageConnection( int depth )
+  {
+    mDepth = depth;
+    Control::OnStageConnection(depth);
+  }
+  virtual void OnStageDisconnection()
+  {
+    Control::OnStageDisconnection();
+  }
+  virtual void OnChildAdd( Actor& child )
+  {
+    Control::OnChildAdd(child);
+  }
+  virtual void OnChildRemove( Actor& child )
+  {
+    Control::OnChildRemove(child);
+  }
+  virtual void OnPropertySet( Property::Index index, Property::Value propertyValue )
+  {
+    Control::OnPropertySet(index, propertyValue);
+  }
+  virtual void OnSizeSet( const Vector3& targetSize )
+  {
+    mSizeSet = targetSize;
+    Control::OnSizeSet( targetSize );
+  }
+  virtual void OnSizeAnimation( Animation& animation, const Vector3& targetSize )
+  {
+    mTargetSize = targetSize;
+    Control::OnSizeAnimation( animation, targetSize );
+  }
+  virtual bool OnTouchEvent( const TouchEvent& event )
+  {
+    return true;
+  }
+  virtual bool OnHoverEvent( const HoverEvent& event )
+  {
+    return true;
+  }
+  virtual bool OnWheelEvent( const WheelEvent& event )
+  {
+    return true;
+  }
+  virtual bool OnKeyEvent( const KeyEvent& event )
+  {
+    return true;
+  }
+  virtual void OnKeyInputFocusGained()
+  {
+  }
+  virtual void OnKeyInputFocusLost()
+  {
+  }
+  virtual Vector3 GetNaturalSize()
+  {
+    return Vector3( 0.0f, 0.0f, 0.0f );
+  }
+
+  virtual float GetHeightForWidth( float width )
+  {
+    return 0.0f;
+  }
+
+  virtual float GetWidthForHeight( float height )
+  {
+    return 0.0f;
+  }
+
+  void TestRegisterVisual( Property::Index index, Toolkit::Visual::Base visual )
+  {
+    ControlWrapper::RegisterVisual( index, visual );
+
+    VisualIndices::iterator iter = std::find( mRegisteredVisualIndices.begin(), mRegisteredVisualIndices.end(), index );
+    if( iter == mRegisteredVisualIndices.end() )
+    {
+      mRegisteredVisualIndices.push_back(index);
+    }
+  }
+
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container )
+  {
+    gOnRelayout = true;
+
+    for( VisualIndices::iterator iter = mRegisteredVisualIndices.begin(); iter != mRegisteredVisualIndices.end() ; ++iter )
+    {
+      Visual::Base visual = GetVisual(*iter);
+      Property::Map map; // empty map enforces defaults
+      visual.SetTransformAndSize( map, size );
+    }
+  }
+
+  virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+  {
+  }
+
+  virtual void OnCalculateRelayoutSize( Dimension::Type dimension )
+  {
+  }
+
+  virtual float CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension )
+  {
+    return 0.0f;
+  }
+
+  virtual void OnLayoutNegotiated( float size, Dimension::Type dimension )
+  {
+  }
+
+  virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS )
+  {
+    return false;
+  }
+
+  void SetDaliProperty(std::string s)
+  {
+    Self().SetProperty(mDaliProperty, s);
+  }
+  void TestRelayoutRequest()
+  {
+    RelayoutRequest();
+  }
+
+  float TestGetHeightForWidthBase( float width )
+  {
+    return GetHeightForWidthBase( width );
+  }
+
+  float TestGetWidthForHeightBase( float height )
+  {
+    return GetWidthForHeightBase( height );
+  }
+
+  float TestCalculateChildSizeBase( const Dali::Actor& child, Dimension::Type dimension )
+  {
+    return CalculateChildSizeBase( child, dimension );
+  }
+
+  bool TestRelayoutDependentOnChildrenBase( Dimension::Type dimension )
+  {
+    return RelayoutDependentOnChildrenBase( dimension );
+  }
+
+  Property::Index mDaliProperty;
+  Vector3 mSizeSet;
+  Vector3 mTargetSize;
+  bool mNego;
+  unsigned int mDepth;
+
+  typedef std::vector<Property::Index> VisualIndices;
+  VisualIndices mRegisteredVisualIndices;
+};
+
+
+
+}
+
+static std::string customControlTypeName = "MyTestCustomControl";
+static TypeRegistration customControl( customControlTypeName, typeid(Dali::Toolkit::Control), NULL );
+
+
+int UtcDaliControlWrapperConstructor(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Toolkit::Internal::ControlWrapper* controlWrapperImpl = new Toolkit::Internal::ControlWrapper( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper;
+
+  DALI_TEST_CHECK( !ControlWrapper::DownCast( controlWrapper ) );
+
+  controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  DALI_TEST_CHECK( ControlWrapper::DownCast( controlWrapper ) );
+
+  Dali::TypeInfo typeInfo = DevelCustomActor::GetTypeInfo( controlWrapper );
+
+  DALI_TEST_EQUALS( typeInfo.GetName(), customControlTypeName, TEST_LOCATION);
+
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperDestructor(void)
+{
+  TestApplication application;
+
+  ControlWrapper control = ControlWrapper::New( customControlTypeName, *( new Toolkit::Internal::ControlWrapper( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ) ) );
+
+  ControlWrapper control2( control );
+
+  DALI_TEST_CHECK( control );
+  control.Reset();
+  DALI_TEST_CHECK( !control );
+
+  DALI_TEST_CHECK( control2 );
+  control2.Reset();
+  DALI_TEST_CHECK( !control2 );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRelayoutRequest(void)
+{
+  TestApplication application;
+
+  DALI_TEST_EQUALS( gOnRelayout, false, TEST_LOCATION );
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Stage::GetCurrent().Add( controlWrapper );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gOnRelayout, true, TEST_LOCATION );
+  gOnRelayout = false;
+
+  controlWrapperImpl->TestRelayoutRequest();
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gOnRelayout, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperImplGetHeightForWidthBase(void)
+{
+  TestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  float width = 300.0f;
+  float v = 0.0f;
+
+  application.SendNotification();
+  application.Render();
+
+  v = controlWrapperImpl->TestGetHeightForWidthBase( width );
+
+  DALI_TEST_EQUALS( width, v, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperGetWidthForHeightBase(void)
+{
+  TestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  float height = 300.0f;
+  float v = 0.0f;
+
+  application.SendNotification();
+  application.Render();
+
+  v = controlWrapperImpl->TestGetWidthForHeightBase( height );
+
+  DALI_TEST_EQUALS( height, v, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperCalculateChildSizeBase(void)
+{
+  TestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Actor child = Actor::New();
+  child.SetResizePolicy( Dali::ResizePolicy::FIXED, Dali::Dimension::ALL_DIMENSIONS );
+  child.SetSize(150, 150);
+
+  application.SendNotification();
+  application.Render();
+
+  float v = 9.99f;
+  v = controlWrapperImpl->TestCalculateChildSizeBase( child, Dali::Dimension::ALL_DIMENSIONS );
+  DALI_TEST_EQUALS( v, 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRelayoutDependentOnChildrenBase(void)
+{
+  TestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  bool v = false;
+
+  v = controlWrapperImpl->TestRelayoutDependentOnChildrenBase( Dali::Dimension::ALL_DIMENSIONS );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( v, true, TEST_LOCATION );
+
+  controlWrapper.SetResizePolicy( Dali::ResizePolicy::FIXED, Dali::Dimension::ALL_DIMENSIONS );
+  v = controlWrapperImpl->TestRelayoutDependentOnChildrenBase( Dali::Dimension::WIDTH );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( v, false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRegisterVisualToSelf(void)
+{
+  ToolkitTestApplication application;
+
+  Test::ObjectDestructionTracker objectDestructionTracker;
+
+  {
+    Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+    ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+    objectDestructionTracker.Start( controlWrapper );
+
+    Property::Index index = 1;
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base visual;
+
+    Property::Map map;
+    map[Visual::Property::TYPE] = Visual::COLOR;
+    map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+    visual = visualFactory.CreateVisual( map );
+    DALI_TEST_CHECK( visual );
+
+    // Register to self
+    controlWrapperImpl->RegisterVisual( index, visual );
+
+    DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), false, TEST_LOCATION ); // Control not destroyed yet
+    DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( index ), visual, TEST_LOCATION );
+  }
+
+  DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), true, TEST_LOCATION ); // Should be destroyed
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRegisterVisualWithDepthIndexToSelf(void)
+{
+  ToolkitTestApplication application;
+
+  Test::ObjectDestructionTracker objectDestructionTracker;
+
+  {
+    Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+    ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+    objectDestructionTracker.Start( controlWrapper );
+
+    Property::Index index = 1;
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base visual;
+
+    Property::Map map;
+    map[Visual::Property::TYPE] = Visual::COLOR;
+    map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+    visual = visualFactory.CreateVisual( map );
+    DALI_TEST_CHECK( visual );
+
+    // Register to self
+    controlWrapperImpl->RegisterVisual( index, visual, 4 );
+
+    DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), false, TEST_LOCATION ); // Control not destroyed yet
+    DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( index ), visual, TEST_LOCATION );
+    DALI_TEST_EQUALS( visual.GetDepthIndex(), 4, TEST_LOCATION );
+  }
+
+  DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), true, TEST_LOCATION ); // Should be destroyed
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRegisterDisabledVisual(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Property::Index TEST_PROPERTY = 1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  controlWrapperImpl->RegisterVisual( TEST_PROPERTY, visual, false );
+
+  DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( TEST_PROPERTY ), visual, TEST_LOCATION );
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( controlWrapper );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controlWrapper.OnStage(), true, TEST_LOCATION );
+
+  controlWrapperImpl->EnableVisual( TEST_PROPERTY, true );
+
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRegisterDisabledVisualWithDepthIndex(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Property::Index TEST_PROPERTY = 1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  controlWrapperImpl->RegisterVisual( TEST_PROPERTY, visual, false, 10 );
+
+  DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( TEST_PROPERTY ), visual, TEST_LOCATION );
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( visual.GetDepthIndex(), 10, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( controlWrapper );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( controlWrapper.OnStage(), true, TEST_LOCATION );
+
+  controlWrapperImpl->EnableVisual( TEST_PROPERTY, true );
+
+  DALI_TEST_EQUALS( controlWrapperImpl->IsVisualEnabled( TEST_PROPERTY ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperRegisterUnregisterVisual(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Property::Index index = 1;
+
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base visual;
+
+  Property::Map map;
+  map[Visual::Property::TYPE] = Visual::COLOR;
+  map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+  visual = visualFactory.CreateVisual( map );
+  DALI_TEST_CHECK(visual);
+
+  // Register index with a color visual
+  controlWrapperImpl->RegisterVisual( index, visual );
+
+  DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( index ), visual, TEST_LOCATION );
+
+  // Unregister visual
+  controlWrapperImpl->UnregisterVisual( index );
+
+  DALI_TEST_CHECK( !controlWrapperImpl->GetVisual( index ) );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperTransitionDataMap1N(void)
+{
+  TestApplication application;
+
+  Property::Map map;
+  map["target"] = "Actor1";
+  map["property"] = "randomProperty";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  //DummyControl actor = DummyControl::New();
+  controlWrapper.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  controlWrapper.SetName("Actor1");
+  controlWrapper.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(controlWrapper);
+
+  Animation anim = controlWrapperImpl->CreateTransition( transition );
+  DALI_TEST_CHECK( ! anim );
+
+  Property::Map returnedMap = transition.GetAnimatorAt(0);
+
+  Property::Value* value = returnedMap.Find("property");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( "randomProperty", value->Get<std::string>(), TEST_LOCATION );
+
+  value = returnedMap.Find("initialValue");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( Color::MAGENTA, value->Get<Vector4>(), TEST_LOCATION );
+
+  value = returnedMap.Find("targetValue");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( Color::RED, value->Get<Vector4>(), TEST_LOCATION );
+
+  value = returnedMap.Find("animator");
+  DALI_TEST_CHECK( value != NULL);
+  Property::Map returnedAnimatorMap = value->Get<Property::Map>();
+
+  value = returnedAnimatorMap.Find("alphaFunction");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( "EASE_OUT", value->Get<std::string>(), TEST_LOCATION );
+
+  value = returnedAnimatorMap.Find("timePeriod");
+  DALI_TEST_CHECK( value != NULL);
+  Property::Map returnedTimePeriodMap = value->Get<Property::Map>();
+
+  value = returnedTimePeriodMap.Find("delay");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( 0.5f, value->Get<float>(), TEST_LOCATION );
+
+  value = returnedTimePeriodMap.Find("duration");
+  DALI_TEST_CHECK( value != NULL);
+  DALI_TEST_EQUALS( 1.0f, value->Get<float>(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperApplyThemeStyle(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  controlWrapperImpl->ApplyThemeStyle();
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliControlWrapperTestControlProperties(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  Stage::GetCurrent().Add( controlWrapper );
+
+  // "background" property
+  Property::Map rendererMap;
+  rendererMap[Visual::Property::TYPE] = Visual::COLOR;
+  rendererMap[ColorVisual::Property::MIX_COLOR] = Color::RED;
+  controlWrapper.SetProperty( Control::Property::BACKGROUND, rendererMap );
+  Property::Value propertyValue = controlWrapper.GetProperty( Control::Property::BACKGROUND );
+  Property::Map* resultMap = propertyValue.GetMap();
+  DALI_TEST_CHECK( resultMap->Find( Toolkit::Visual::Property::TYPE ) );
+  DALI_TEST_EQUALS( resultMap->Find( Toolkit::Visual::Property::TYPE )->Get<int>(), (int)Visual::COLOR, TEST_LOCATION );
+  DALI_TEST_CHECK( resultMap->Find( ColorVisual::Property::MIX_COLOR ) );
+  DALI_TEST_EQUALS( resultMap->Find( ColorVisual::Property::MIX_COLOR )->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+  // "keyInputFocus" property
+  controlWrapper.SetProperty( Control::Property::KEY_INPUT_FOCUS, true );
+  DALI_TEST_EQUALS( true, controlWrapper.GetProperty( Control::Property::KEY_INPUT_FOCUS ).Get< bool >(), TEST_LOCATION );
+
+  // "styleName" property
+  controlWrapper.SetProperty( Control::Property::STYLE_NAME, "MyCustomStyle" );
+  DALI_TEST_EQUALS( "MyCustomStyle", controlWrapper.GetProperty( Control::Property::STYLE_NAME ).Get< std::string >(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperTypeRegistryCreation(void)
+{
+  ToolkitTestApplication application;
+
+  TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "ControlWrapper" );
+  DALI_TEST_CHECK( typeInfo )
+
+  // Check that we can't create a ControlWrapper instance
+  BaseHandle baseHandle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( !baseHandle )
+
+  END_TEST;
+}
+
+void SetProperty(BaseObject* object, const char* const name, Property::Value* value)
+{
+}
+Property::Value* GetProperty(BaseObject* object, const char* const name )
+{
+  return NULL;
+}
+
+int UtcDaliControlWrapperAnimateVisual(void)
+{
+  tet_infoline("Test that the control wrapper's visuals can be animated by name when registered");
+
+  ToolkitTestApplication application;
+  Test::ObjectDestructionTracker objectDestructionTracker;
+
+  {
+    Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+    ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+    Property::Index index = Control::CONTROL_PROPERTY_END_INDEX+1;
+    std::string visualName("colorVisual");
+    CSharpTypeRegistry::RegisterProperty( customControlTypeName, visualName, index, Property::VECTOR4, SetProperty, GetProperty );
+
+    objectDestructionTracker.Start( controlWrapper );
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base visual;
+
+    Property::Map map;
+    map[Visual::Property::TYPE] = Visual::COLOR;
+    map[ColorVisual::Property::MIX_COLOR] = Color::RED;
+
+    visual = visualFactory.CreateVisual( map );
+    DALI_TEST_CHECK( visual );
+
+    // Register to self
+    controlWrapperImpl->TestRegisterVisual( index, visual );
+
+    Stage::GetCurrent().Add( controlWrapper );
+    controlWrapper.SetSize( 100, 100 );
+    application.SendNotification();
+    application.Render(0); // Trigger animation start
+
+    Property::Map transition;
+    transition["target"] = visualName;
+    transition["property"] = "mixColor";
+    transition["targetValue"] = Color::GREEN;
+    Property::Map animator;
+    animator["alphaFunction"] = "LINEAR";
+    animator["duration"] = 1.0f;
+    animator["delay"] = 0.0f;
+    transition["animator"] = animator;
+
+    TransitionData transitionData = TransitionData::New(transition);
+    Animation anim = DevelControl::CreateTransition( *controlWrapperImpl, transitionData );
+    anim.Play();
+
+    application.SendNotification();
+    application.Render(0); // Trigger animation start
+
+    application.Render(1000); // animation end
+    application.Render(  10);
+
+    Property::Map visualMap;
+    visual.CreatePropertyMap( visualMap );
+    Property::Value* value = visualMap.Find(ColorVisual::Property::MIX_COLOR, "mixColor");
+    DALI_TEST_CHECK( value != NULL );
+    if( value )
+    {
+      Vector4 testColor = value->Get<Vector4>();
+      DALI_TEST_EQUALS( testColor, Color::GREEN, 0.001f, TEST_LOCATION );
+    }
+
+    DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), false, TEST_LOCATION ); // Control not destroyed yet
+    DALI_TEST_EQUALS( controlWrapperImpl->GetVisual( index ), visual, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( controlWrapper );
+  }
+
+  DALI_TEST_EQUALS( objectDestructionTracker.IsDestroyed(), true, TEST_LOCATION ); // Should be destroyed
+
+  END_TEST;
+}
+
+int UtcDaliControlWrapperEmitKeyFocusSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT );
+  ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl );
+
+  gKeyInputFocusCallBackCalled = false;
+  controlWrapper.KeyInputFocusGainedSignal().Connect(&TestKeyInputFocusCallback);
+
+  application.SendNotification();
+  application.Render();
+
+  controlWrapperImpl->EmitKeyInputFocusSignal( true );
+
+  DALI_TEST_CHECK( gKeyInputFocusCallBackCalled );
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-CubeTransitionEffect.cpp b/automated-tests/src/dali-toolkit/utc-Dali-CubeTransitionEffect.cpp
new file mode 100644 (file)
index 0000000..8d8cefb
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * 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-toolkit/devel-api/transition-effects/cube-transition-effect.h>
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h>
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h>
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+
+namespace
+{
+const unsigned int NUM_ROWS = 16;
+const unsigned int NUM_COLUMNS = 10;
+const Vector2 VIEW_AREA_SIZE( 480.0f, 800.0f );
+const float TRANSITION_DURATION = 0.5f;
+const float CUBE_DISPLACEMENT = 55.f;
+const Vector2 PAN_POSITION1( VIEW_AREA_SIZE.x * 0.75f, VIEW_AREA_SIZE.y * 0.25f );
+const Vector2 PAN_DISPLACEMENT1( -5.f, 5.f );
+const Vector2 PAN_POSITION2( VIEW_AREA_SIZE.x * 0.25f, VIEW_AREA_SIZE.y * 0.75f );
+const Vector2 PAN_DISPLACEMENT2( 5.f, 5.f );
+const Vector4 FULL_BRIGHTNESS(1.f,1.f,1.f,1.f);
+const Vector4 HALF_BRIGHTNESS(0.5f, 0.5f, 0.5f, 1.f);
+const int RENDER_FRAME_INTERVAL = 16;
+static const float FLT_EPISILON = 0.0001f;
+static const float EPISILON = 0.05f;
+const float TRANSITION_BEFORE_END_DURATION = TRANSITION_DURATION - 0.05f;
+
+static bool gObjectCreatedCallBackCalled;
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+/**
+ * Simulate time passed by, waiting for certain process to finish
+ * @param[in] application Test application instance
+ * @param[in] durationToPass Time to pass in milliseconds.
+ */
+void Wait(ToolkitTestApplication& application, float durationToPass)
+{
+  int duration = static_cast<int>(durationToPass*1000.f);
+  // wait 2 more frames to compensate the two frames used by the image waiting for the loading succeeded signal
+  for(int i = 0; i <=  duration/RENDER_FRAME_INTERVAL+2 ; i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+  }
+}
+
+
+
+//Callback class to test whether transition completed signal is emitted when the transition animation is finished
+class TransitionCompletedCallback : public Dali::ConnectionTracker
+{
+public:
+  TransitionCompletedCallback( bool& signalReceived, CubeTransitionEffect& effect, Texture& image )
+  : mSignalVerified( signalReceived ),
+    mCurrentEffect( effect ),
+    mActorTransitTo( image )
+  {
+  }
+
+  void Callback( CubeTransitionEffect effect, Texture image )
+  {
+    tet_infoline( "Verifying TransitionCompletedSignal" );
+
+    if( mCurrentEffect == effect && mActorTransitTo == image )
+    {
+      mSignalVerified = true;
+    }
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool&                  mSignalVerified;
+  CubeTransitionEffect&  mCurrentEffect;
+  Texture&               mActorTransitTo;
+};
+
+} // namespace
+
+
+
+void cube_transition_effect_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void cube_transition_effect_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliCubeTransitionWaveEffectNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionWaveEffectNew ");
+
+  CubeTransitionEffect waveEffect;
+
+  DALI_TEST_CHECK( !waveEffect );
+
+  waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+
+  DALI_TEST_CHECK( waveEffect );
+
+  waveEffect.Reset();
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+    waveEffect.SetSize( VIEW_AREA_SIZE );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionCrossEffectNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionCrossEffectNew ");
+
+  CubeTransitionEffect crossEffect;
+
+  DALI_TEST_CHECK( !crossEffect );
+
+  crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+
+  DALI_TEST_CHECK( crossEffect );
+
+  crossEffect.Reset();
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+    crossEffect.SetSize( VIEW_AREA_SIZE );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionFoldEffectNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliCubeTransitionFoldEffectNew " );
+
+  CubeTransitionEffect foldEffect;
+
+  DALI_TEST_CHECK( !foldEffect );
+
+  foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+
+  DALI_TEST_CHECK( foldEffect );
+
+  foldEffect.Reset();
+
+  //Additional check to ensure object is created by checking if it is registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+    foldEffect.SetSize( VIEW_AREA_SIZE );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionEffectSetGetTransitionDuration(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectSetGetTransitionDuration ");
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  DALI_TEST_EQUALS( TRANSITION_DURATION, waveEffect.GetTransitionDuration(), TEST_LOCATION );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  DALI_TEST_EQUALS( TRANSITION_DURATION, crossEffect.GetTransitionDuration(), TEST_LOCATION );
+
+  CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  DALI_TEST_EQUALS( TRANSITION_DURATION, foldEffect.GetTransitionDuration(), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionEffectSetGetCubeDisplacement(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectSetGetTransitionDuration ");
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS);
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  DALI_TEST_EQUALS( CUBE_DISPLACEMENT, waveEffect.GetCubeDisplacement(), TEST_LOCATION );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  DALI_TEST_EQUALS( CUBE_DISPLACEMENT, crossEffect.GetCubeDisplacement(), TEST_LOCATION );
+
+  //Cube displacement is not used in CubeTransitionFoldEffect
+  END_TEST;
+}
+
+//Test common codes in base class
+int UtcDaliCubeTransitionEffectGetRoot(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectGetRoot ");
+
+  unsigned int totalNum = NUM_ROWS*NUM_COLUMNS;
+
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  Stage::GetCurrent().Add( waveEffect );
+  waveEffect.SetCurrentTexture( texture );
+  waveEffect.SetTargetTexture( texture );
+
+  application.SendNotification();
+  application.Render();
+
+  waveEffect.StartTransition();
+
+  Wait( application, TRANSITION_DURATION * 0.5f );
+
+  // check that we have a total of NUM_ROWS*NUM_COLUMNS cubes;
+  Actor boxesRoot = waveEffect.GetChildAt(0);
+  DALI_TEST_CHECK( totalNum == boxesRoot.GetChildCount() );
+
+  // check that every cube has two children
+  DALI_TEST_CHECK( 2 == boxesRoot.GetChildAt(0).GetChildCount() );
+  DALI_TEST_CHECK( 2 == boxesRoot.GetChildAt(totalNum/2).GetChildCount() );
+  DALI_TEST_CHECK( 2 == boxesRoot.GetChildAt(totalNum-1).GetChildCount() );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionEffectIsTransitioning(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectIsTransiting ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  Stage::GetCurrent().Add( waveEffect );
+
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  DALI_TEST_CHECK( !waveEffect.IsTransitioning() );
+
+  waveEffect.SetCurrentTexture( texture );
+  waveEffect.SetTargetTexture( texture );
+  //transition is started
+  waveEffect.StartTransition();
+  DALI_TEST_CHECK( waveEffect.IsTransitioning() );
+  //transition is finished
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK( !waveEffect.IsTransitioning() );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  Stage::GetCurrent().Add( crossEffect );
+
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  DALI_TEST_CHECK( !crossEffect.IsTransitioning() );
+
+  crossEffect.SetCurrentTexture( texture );
+  crossEffect.SetTargetTexture( texture );
+  //transition is started
+  crossEffect.StartTransition(false);
+  DALI_TEST_CHECK( crossEffect.IsTransitioning() );
+  //transition is finished
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK( !crossEffect.IsTransitioning() );
+
+  CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  Stage::GetCurrent().Add( foldEffect );
+
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  DALI_TEST_CHECK( !foldEffect.IsTransitioning() );
+
+  foldEffect.SetCurrentTexture( texture );
+  foldEffect.SetTargetTexture( texture );
+  //transition is started
+  foldEffect.StartTransition(true);
+  DALI_TEST_CHECK(foldEffect.IsTransitioning() );
+  //transition is finished
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK( !foldEffect.IsTransitioning() );
+
+  END_TEST;
+}
+
+//Test common codes in base class
+int UtcDaliCubeTransitionEffectSetCurrentTexture(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectSetCurrentTexture ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetCurrentTexture( texture );
+
+  Stage::GetCurrent().Add( waveEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  waveEffect.StartTransition();
+
+  // the current image content is set to the tiles facing the camera
+  Actor currentTile = waveEffect.GetChildAt(0).GetChildAt(0).GetChildAt(0);
+  Actor targetTile = waveEffect.GetChildAt(0).GetChildAt(0).GetChildAt(1);
+
+  //check the pixel area set to the cube
+  Vector4 pixelAreaDef( 0.f, 0.f, 1.f / NUM_COLUMNS, 1.f / NUM_ROWS);
+
+  Property::Index textureRectIndex = currentTile.GetPropertyIndex( "uTextureRect" );
+  DALI_TEST_CHECK( textureRectIndex != Property::INVALID_INDEX );
+  Property::Value textureRectValue = currentTile.GetProperty( textureRectIndex );
+  DALI_TEST_CHECK( textureRectValue.GetType() == Property::VECTOR4 );
+  Vector4 pixelArea;
+  DALI_TEST_CHECK( textureRectValue.Get( pixelArea ) );
+
+  DALI_TEST_EQUALS( pixelAreaDef, pixelArea, FLT_EPISILON, TEST_LOCATION );
+
+  END_TEST;
+}
+
+//Test common codes in base class
+int UtcDaliCubeTransitionEffectSetTargetTexture(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectSetTargetTexture ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  Stage::GetCurrent().Add( waveEffect );
+
+  waveEffect.SetCurrentTexture( texture );
+  waveEffect.SetTargetTexture( texture );
+
+  Stage::GetCurrent().Add( waveEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  waveEffect.StartTransition();
+
+  // the target image content is set to the tiles currently invisible to the camera
+  Actor tile = waveEffect.GetChildAt(0).GetChildAt(0).GetChildAt(1);
+
+  //check the pixel area set to the cube
+  Vector4 pixelAreaDef( 0.f, 0.f, 1.f / NUM_COLUMNS, 1.f / NUM_ROWS);
+
+  Property::Index textureRectIndex = tile.GetPropertyIndex( "uTextureRect" );
+  DALI_TEST_CHECK( textureRectIndex != -1 );
+  Property::Value textureRectValue = tile.GetProperty( textureRectIndex );
+  DALI_TEST_CHECK( textureRectValue.GetType() == Property::VECTOR4 );
+  Vector4 pixelArea;
+  DALI_TEST_CHECK( textureRectValue.Get( pixelArea ) );
+
+  DALI_TEST_EQUALS( pixelAreaDef, pixelArea, FLT_EPISILON, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionWaveEffectStartTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionWaveEffectStartTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+
+  Devel::PixelBuffer pixelBuffer = LoadImageFromFile(TEST_RESOURCE_DIR "/gallery-small-1.jpg");
+  PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
+  texture.Upload( pixelData );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  waveEffect.SetCurrentTexture( texture );
+
+  Stage::GetCurrent().Add( waveEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  waveEffect.StartTransition( true );
+
+  Actor cube = waveEffect.GetChildAt(0).GetChildAt(0);
+
+  //check the cube rotation value and color values just before the end of different transitions
+  waveEffect.SetTargetTexture( texture );
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( texture );
+  waveEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( texture );
+  waveEffect.StartTransition(false);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( texture );
+  waveEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionCrossEffectStartTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionCrossEffectStartTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+
+  Devel::PixelBuffer pixelBuffer = LoadImageFromFile(TEST_RESOURCE_DIR "/gallery-small-1.jpg");
+  PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight() );
+  texture.Upload( pixelData );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  crossEffect.SetCurrentTexture( texture );
+  crossEffect.SetTargetTexture( texture );
+
+  Stage::GetCurrent().Add( crossEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  crossEffect.StartTransition(true);
+
+  Actor cube0 = crossEffect.GetChildAt(0).GetChildAt(0);
+  Actor cube1 = crossEffect.GetChildAt(0).GetChildAt(1);
+
+  //check the cube rotation value and color values just before the end of different transitions
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::XAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+
+  crossEffect.SetTargetTexture( texture );
+  crossEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::XAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+
+  crossEffect.SetTargetTexture( texture );
+  crossEffect.StartTransition(false);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::XAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  crossEffect.SetTargetTexture( texture );
+  crossEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::XAXIS), EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionFoldEffectStartTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionFoldEffectStartTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+  CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  foldEffect.SetCurrentTexture( texture );
+  foldEffect.SetTargetTexture( texture );
+
+  Stage::GetCurrent().Add( foldEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  foldEffect.StartTransition(true);
+
+  Actor cube0 = foldEffect.GetChildAt(0).GetChildAt(0);
+  Actor cube1 = foldEffect.GetChildAt(0).GetChildAt(1);
+
+  //check the cube rotation value and color values just before the end of different transitions
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  foldEffect.SetTargetTexture( texture );
+  foldEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+
+  foldEffect.SetTargetTexture( texture );
+  foldEffect.StartTransition(false);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(),FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+
+  foldEffect.SetTargetTexture( texture );
+  foldEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_BEFORE_END_DURATION );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( -Dali::ANGLE_90,  Vector3::YAXIS), EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), HALF_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), FULL_BRIGHTNESS, EPISILON, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionEffectSignalTransitionCompleted(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectSignalTransitionCompleted ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture firstTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 30, 30 );
+  Texture secondTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 20, 20 );
+  Texture thirdTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 40, 40 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  Stage::GetCurrent().Add( waveEffect );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  Stage::GetCurrent().Add( crossEffect );
+
+  CubeTransitionEffect foldEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  Stage::GetCurrent().Add( foldEffect );
+
+  bool signalVerified = false;
+  CubeTransitionEffect currentEffect;
+  Texture actorTransitTo;
+  TransitionCompletedCallback callback(signalVerified, currentEffect, actorTransitTo);
+  waveEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+  crossEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+  foldEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+
+  //check that the wave effect is used to transit to secondTexture
+  currentEffect = waveEffect;
+  actorTransitTo = secondTexture;
+  waveEffect.SetCurrentTexture( firstTexture );
+  waveEffect.SetTargetTexture( secondTexture );
+  waveEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  //check that the wave effect is used to transit to thirdTexture
+  actorTransitTo = thirdTexture;
+  waveEffect.SetTargetTexture( thirdTexture );
+  waveEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  //check that the cross effect is used to transit to secondTexture
+  currentEffect = crossEffect;
+  actorTransitTo = secondTexture;
+  crossEffect.SetCurrentTexture( thirdTexture );
+  crossEffect.SetTargetTexture( secondTexture );
+  crossEffect.StartTransition(true);
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  //check that the cross effect is used to transit to firstTexture
+  actorTransitTo = firstTexture;
+  crossEffect.SetTargetTexture( firstTexture );
+  crossEffect.StartTransition(false);
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  //check that the fold effect is used to transit to secondTexture
+  currentEffect = foldEffect;
+  actorTransitTo = secondTexture;
+  foldEffect.SetCurrentTexture( firstTexture );
+  foldEffect.SetTargetTexture( secondTexture );
+  foldEffect.StartTransition();
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK( callback.mSignalVerified );
+  callback.Reset();
+
+  //check that the fold effect is used to transit to thirdTexture
+  actorTransitTo = thirdTexture;
+  foldEffect.SetTargetTexture( thirdTexture );
+  foldEffect.StartTransition( false );
+  Wait( application, TRANSITION_DURATION );
+  DALI_TEST_CHECK( callback.mSignalVerified );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionEffectPauseResumeTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionEffectPauseResumeTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture firstTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 30, 30 );
+  Texture secondTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 20, 20 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  Stage::GetCurrent().Add( waveEffect );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  Stage::GetCurrent().Add( crossEffect );
+
+  CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  Stage::GetCurrent().Add( foldEffect );
+
+  bool signalVerified = false;
+  CubeTransitionEffect currentEffect;
+  Texture actorTransitTo;
+  TransitionCompletedCallback callback(signalVerified, currentEffect, actorTransitTo);
+  waveEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+  crossEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+  foldEffect.TransitionCompletedSignal().Connect( &callback, &TransitionCompletedCallback::Callback );
+
+  currentEffect = waveEffect;
+  actorTransitTo = secondTexture;
+  waveEffect.SetCurrentTexture( firstTexture );
+  waveEffect.SetTargetTexture( secondTexture );
+  // start transition; transit for 0.5*duration; pause for 0.5*duration;
+  // resume for 0.25*duration; pause for 0.25*duration; resume for another 0.25*duration;
+  // only until now the transition finished signal can be received
+  waveEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION*0.5f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  waveEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.5f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  waveEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  waveEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  waveEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  currentEffect = crossEffect;
+  actorTransitTo = firstTexture;
+  crossEffect.SetCurrentTexture( secondTexture );
+  crossEffect.SetTargetTexture( firstTexture );
+  // start transition; transit for 0.25*duration; pause for 0.2*duration;
+  // resume for 0.5*duration; pause for 0.2*duration; resume for another 0.25*duration;
+  // only until now the transition finished signal can be received
+  crossEffect.StartTransition(false);
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  crossEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.2f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  crossEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.5f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  crossEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.2f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  crossEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  callback.Reset();
+
+  currentEffect = foldEffect;
+  actorTransitTo = secondTexture;
+  foldEffect.SetCurrentTexture( firstTexture );
+  foldEffect.SetTargetTexture( secondTexture );
+  // start transition; transit for 0.5*duration; pause for 0.5*duration;
+  // resume for 0.25*duration; pause for 0.25*duration; resume for another 0.25*duration;
+  // only until now the transition finished signal can be received
+  foldEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION*0.5f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  foldEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.5f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  foldEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  foldEffect.PauseTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(!callback.mSignalVerified);
+  foldEffect.ResumeTransition();
+  Wait( application, TRANSITION_DURATION*0.25f );
+  DALI_TEST_CHECK(callback.mSignalVerified);
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionWaveEffectStopTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionWaveEffectStopTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture firstTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 30, 30 );
+  Texture secondTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 20, 20 );
+
+  CubeTransitionEffect waveEffect = CubeTransitionWaveEffect::New( NUM_ROWS, NUM_COLUMNS );
+  waveEffect.SetSize( VIEW_AREA_SIZE );
+  waveEffect.SetTransitionDuration( TRANSITION_DURATION );
+  waveEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  waveEffect.SetCurrentTexture( firstTexture );
+  waveEffect.SetTargetTexture( secondTexture );
+
+  Stage::GetCurrent().Add( waveEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  waveEffect.StartTransition(true);
+
+  Actor cube = waveEffect.GetChildAt(0).GetChildAt(0);
+
+  //check the cube rotation value and color values reset after stopping different transitions in the middle
+  Wait( application, TRANSITION_DURATION*0.2f );
+  waveEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( firstTexture );
+  waveEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION*0.4f );
+  waveEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( secondTexture );
+  waveEffect.StartTransition(false);
+  Wait( application, TRANSITION_DURATION*0.6f );
+  waveEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  waveEffect.SetTargetTexture( firstTexture );
+  waveEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_DURATION*0.8f );
+  waveEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionCrossEffectStopTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionCrossEffectStopTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture firstTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 30, 30 );
+  Texture secondTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 20, 20 );
+
+  CubeTransitionEffect crossEffect = CubeTransitionCrossEffect::New( NUM_ROWS, NUM_COLUMNS );
+  crossEffect.SetSize( VIEW_AREA_SIZE );
+  crossEffect.SetTransitionDuration( TRANSITION_DURATION );
+  crossEffect.SetCubeDisplacement( CUBE_DISPLACEMENT );
+  crossEffect.SetCurrentTexture( firstTexture );
+  crossEffect.SetTargetTexture( secondTexture );
+
+  Stage::GetCurrent().Add( crossEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  crossEffect.StartTransition(true);
+
+  Actor cube0 = crossEffect.GetChildAt(0).GetChildAt(0);
+  Actor cube1 = crossEffect.GetChildAt(0).GetChildAt(1);
+
+  //check the cube rotation values and color values reset after stop the different transitions in the middle
+  Wait( application, TRANSITION_DURATION*0.2f );
+  crossEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  crossEffect.SetTargetTexture( firstTexture );
+  crossEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION*0.4f );
+  crossEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  crossEffect.SetTargetTexture( secondTexture );
+  crossEffect.StartTransition(false);
+  Wait( application, TRANSITION_DURATION*0.6f );
+  crossEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::ZERO), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  crossEffect.SetTargetTexture( firstTexture );
+  crossEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_DURATION*0.8f );
+  crossEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::XAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliCubeTransitionFoldEffectStopTransition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliCubeTransitionFoldEffectStopTransition ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  Texture firstTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 30, 30 );
+  Texture secondTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, 20, 20 );
+
+  CubeTransitionEffect foldEffect = CubeTransitionFoldEffect::New( NUM_ROWS, NUM_COLUMNS );
+  foldEffect.SetSize( VIEW_AREA_SIZE );
+  foldEffect.SetTransitionDuration( TRANSITION_DURATION );
+  foldEffect.SetCurrentTexture( firstTexture );
+  foldEffect.SetTargetTexture( secondTexture );
+
+  Stage::GetCurrent().Add( foldEffect );
+
+  application.SendNotification();
+  application.Render();
+
+  foldEffect.StartTransition(true);
+
+  Actor cube0 = foldEffect.GetChildAt(0).GetChildAt(0);
+  Actor cube1 = foldEffect.GetChildAt(0).GetChildAt(1);
+
+  //check the cube rotation values and color values after stop the different transitions in the middle
+  Wait( application, TRANSITION_DURATION*0.2f );
+  foldEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::XAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  foldEffect.SetTargetTexture( firstTexture );
+  foldEffect.StartTransition(PAN_POSITION1, PAN_DISPLACEMENT1);
+  Wait( application, TRANSITION_DURATION*0.4f );
+  foldEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::XAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  foldEffect.SetTargetTexture( secondTexture );
+  foldEffect.StartTransition(false);
+  Wait( application, TRANSITION_DURATION*0.6f );
+  foldEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::XAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+
+  foldEffect.SetTargetTexture( firstTexture );
+  foldEffect.StartTransition(PAN_POSITION2, PAN_DISPLACEMENT2);
+  Wait( application, TRANSITION_DURATION*0.8f );
+  foldEffect.StopTransition();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+  DALI_TEST_EQUALS( cube1.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetCurrentOrientation(), Quaternion( Dali::ANGLE_0,  Vector3::YAXIS), FLT_EPISILON, TEST_LOCATION  );
+  DALI_TEST_EQUALS( cube0.GetChildAt(0).GetCurrentColor(), FULL_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  DALI_TEST_EQUALS( cube0.GetChildAt(1).GetCurrentColor(), HALF_BRIGHTNESS, FLT_EPISILON, TEST_LOCATION );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-DragAndDropDetector.cpp b/automated-tests/src/dali-toolkit/utc-Dali-DragAndDropDetector.cpp
new file mode 100755 (executable)
index 0000000..17686c1
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_drag_drop_detector_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_drag_drop_detector_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+  const int RENDER_FRAME_INTERVAL = 16;
+  struct SignalData
+  {
+    SignalData()
+    :functorCalled(false),
+    control(),
+    detector()
+    {
+    }
+
+    void Reset()
+    {
+      functorCalled = false;
+      control.Reset();
+    }
+
+    bool functorCalled;
+    Control control;
+    Dali::Toolkit::DragAndDropDetector detector;
+  };
+
+  struct DragSignalFunctor
+  {
+    DragSignalFunctor(SignalData& data, bool returnValue = true)
+    :signalData(data),
+    returnValue(returnValue)
+    {
+    }
+
+    bool operator()(Control control, Dali::Toolkit::DragAndDropDetector detector)
+    {
+      signalData.functorCalled = true;
+      signalData.control = control;
+      signalData.detector = detector;
+      return returnValue;
+    }
+
+    SignalData& signalData;
+    bool returnValue;
+    };
+
+  Integration::TouchEvent GenerateSingleTouch(TouchPoint::State state, const Vector2& screenPosition)
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::Point point;
+    point.SetState(static_cast<PointState::Type>(state));
+    point.SetScreenPosition(screenPosition);
+    touchEvent.points.push_back(point);
+    return touchEvent;
+  }
+}
+
+int UtcDaliDragAndDropDetectorConstructorN(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector;
+  DALI_TEST_CHECK(!detector);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  DALI_TEST_CHECK(detector);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorAttachN(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control;
+  detector.Attach(control);
+
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+  Control control1 = Control::New();
+  detector.Attach(control1);
+  DALI_TEST_EQUALS(1, detector.GetAttachedControlCount(), TEST_LOCATION);
+  detector.Attach(control1);
+  DALI_TEST_EQUALS(1, detector.GetAttachedControlCount(), TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorAttachP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control = Control::New();
+
+  detector.Attach(control);
+  DALI_TEST_EQUALS(1, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorDetachN(void)
+  {
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1;
+  Control control2 = Control::New();
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+  DALI_TEST_EQUALS(1, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  detector.Detach(control2);
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  detector.Detach(control1);
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+
+}
+
+int UtcDaliDragAndDropDetectorDetachP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  Control control3;
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+  detector.Attach(control3);
+
+  DALI_TEST_EQUALS(2, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  detector.Detach(control3);
+  DALI_TEST_EQUALS(2, detector.GetAttachedControlCount(), TEST_LOCATION);
+  detector.Detach(control2);
+  DALI_TEST_EQUALS(1, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  detector.Detach(control1);
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorDetachAllN(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  detector.DetachAll();
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+int UtcDaliDragAndDropDetectorDetachAllP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+  detector.DetachAll();
+  DALI_TEST_EQUALS(0, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorGetAttachedControlCountP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+  DALI_TEST_EQUALS(2, detector.GetAttachedControlCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorGetAttachedControlN(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+
+  detector.Attach(control1);
+
+  Control control = detector.GetAttachedControl(1);
+  DALI_TEST_CHECK(!control);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorGetAttachedControlP(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+  Control control = detector.GetAttachedControl(1);
+  DALI_TEST_CHECK(control);
+  DALI_TEST_EQUALS(control2, control, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorStartSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control = Control::New();
+  control.SetSize(100.0f, 100.0f);
+  control.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  Stage::GetCurrent().Add(control);
+  detector.Attach(control);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  DALI_TEST_CHECK(detector);
+  DALI_TEST_CHECK(control);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.StartedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control, data.control, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2(20.0f, 40.0f), data.detector.GetCurrentScreenPosition(), TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorEnteredSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.EnteredSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  Vector2 screenCoordinates(10.0f, 110.0f);
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control2, data.control, TEST_LOCATION);
+
+  data.Reset();
+
+  END_TEST;
+
+}
+
+int UtcDaliDragAndDropDetectorMovedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.MovedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  Vector2 screenCoordinates(10.0f, 110.0f);
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  screenCoordinates.x = 10.0f;
+  screenCoordinates.y = 120.0f;
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2(10.0f, 120.0f), data.detector.GetCurrentScreenPosition(), TEST_LOCATION);
+  DALI_TEST_EQUALS(control2, data.control, TEST_LOCATION);
+
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorExitedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  control1.SetLeaveRequired(true);
+  control2.SetLeaveRequired(true);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.ExitedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  Vector2 screenCoordinates(10.0f, 110.0f);
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  screenCoordinates.x = 20.0f;
+  screenCoordinates.y = 20.0f;
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control2, data.control, TEST_LOCATION);
+
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorDroppedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.DroppedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  Vector2 screenCoordinates(10.0f, 110.0f);
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  screenCoordinates.x = 10.0f;
+  screenCoordinates.y = 112.0f;
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Up, screenCoordinates));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control2, data.control, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2(10.0f, 112.0f), data.detector.GetCurrentScreenPosition(), TEST_LOCATION);
+  DALI_TEST_EQUALS(true, detector.GetContent().empty(), TEST_LOCATION);
+
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorEndedSignal(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.EndedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Down, Vector2(10.0f, 10.0f)));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control1, data.control, TEST_LOCATION);
+  data.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliDragAndDropDetectorGetContent(void)
+{
+  ToolkitTestApplication application;
+
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector::New();
+  Control control1 = Control::New();
+  Control control2 = Control::New();
+  control1.SetName("control1");
+  control2.SetName("control2");
+  control1.SetSize(100.0f,100.0f);
+  control2.SetSize(100.0f, 100.0f);
+  control1.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control2.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  control1.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  control1.SetPosition(0.0f, 0.0f);
+  control2.SetPosition(0.0f, 100.0f);
+
+  Stage::GetCurrent().Add(control1);
+  Stage::GetCurrent().Add(control2);
+
+  detector.Attach(control1);
+  detector.Attach(control2);
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  SignalData data;
+  DragSignalFunctor functor(data);
+  detector.DroppedSignal().Connect(&application, functor);
+
+  TestGenerateMiniPan(application);
+
+  Vector2 screenCoordinates(10.0f, 110.0f);
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Motion, screenCoordinates));
+
+  screenCoordinates.x = 10.0f;
+  screenCoordinates.y = 112.0f;
+  application.ProcessEvent(GenerateSingleTouch(TouchPoint::Up, screenCoordinates));
+
+  DALI_TEST_EQUALS(true, data.functorCalled, TEST_LOCATION);
+  DALI_TEST_EQUALS(control2, data.control, TEST_LOCATION);
+  DALI_TEST_EQUALS(Vector2(10.0f, 112.0f), data.detector.GetCurrentScreenPosition(), TEST_LOCATION);
+  DALI_TEST_EQUALS("control1", detector.GetContent(), TEST_LOCATION);
+
+  data.Reset();
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-EffectsView.cpp
new file mode 100644 (file)
index 0000000..d597f7a
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2017 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 <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/effects-view/effects-view.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_effectsview_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_effectsview_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliEffectsViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  DALI_TEST_CHECK( !view );
+
+  view = EffectsView::New( EffectsView::DROP_SHADOW );
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+
+  view.Reset();
+  view = EffectsView::New( EffectsView::EMBOSS );
+  DALI_TEST_CHECK( view );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  DALI_TEST_CHECK( view );
+
+  EffectsView copy( view );
+  DALI_TEST_CHECK( copy == view );
+
+  EffectsView assign;
+  DALI_TEST_CHECK( !assign );
+  assign = view;
+  DALI_TEST_CHECK( assign == view );
+
+  // Self assignment
+  assign = assign;
+  DALI_TEST_CHECK( assign );
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle view = EffectsView::New( EffectsView::EMBOSS );
+  DALI_TEST_CHECK( EffectsView::DownCast( view ) );
+
+  BaseHandle empty;
+  DALI_TEST_CHECK( ! EffectsView::DownCast( empty ) );
+
+  BaseHandle another = Actor::New();
+  DALI_TEST_CHECK( ! EffectsView::DownCast( another ) );
+
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliEffectsViewAddRemoveDropShadow(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliEffectsViewAddRemoveDropShadow");
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(actor);
+  Stage::GetCurrent().Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+  DALI_TEST_CHECK( actor.GetParent() );
+  DALI_TEST_CHECK( actor.GetParent() != view );
+
+  view.Remove(actor);
+
+  DALI_TEST_CHECK( !actor.OnStage() );
+  END_TEST;
+}
+
+
+int UtcDaliEffectsViewAddRemoveEmboss(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliEffectsViewAddRemoveEmboss");
+
+  tet_infoline("Checking number of render tasks = 1");
+  application.SendNotification();
+  application.Render();
+  Stage stage = Stage::GetCurrent();
+  DALI_TEST_EQUALS( stage.GetRenderTaskList().GetTaskCount(), 1, TEST_LOCATION );
+
+  tet_infoline("Create effects view");
+
+  EffectsView view = EffectsView::New( EffectsView::EMBOSS );
+  Vector3 offsetSet( 2.f, 3.f, 4.f );
+  Vector4 colorSet( 0.2f, 0.3f, 0.4f, 0.5f );
+  view.SetProperty( EffectsView::Property::EFFECT_OFFSET, offsetSet);
+  view.SetProperty( EffectsView::Property::EFFECT_COLOR, colorSet);
+  Vector3 offsetAnimate( 4.f, 6.f, 8.f );
+  float durationSeconds(0.05f);
+  Animation animation = Animation::New( durationSeconds );
+  animation.AnimateTo( Property(view,EffectsView::Property::EFFECT_OFFSET ), offsetAnimate );
+  animation.Play();
+
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+
+  view.Add(actor);
+  view.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  stage.Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Removing view from stage disables view");
+  stage.Remove(view);
+
+  tet_infoline("Checking number of render tasks = 1");
+  DALI_TEST_EQUALS( stage.GetRenderTaskList().GetTaskCount(), 1, TEST_LOCATION );
+
+  tet_infoline("Adding view to stage again re-enables view");
+  stage.Add(view);
+
+  tet_infoline("Removing view from stage disables view");
+  DALI_TEST_GREATER( stage.GetRenderTaskList().GetTaskCount(), 1u, TEST_LOCATION );
+  stage.Remove(view);
+  view.Reset();
+
+  tet_infoline("Checking number of render tasks = 1");
+  DALI_TEST_EQUALS( stage.GetRenderTaskList().GetTaskCount(), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliEffectsViewGetTypeP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  DALI_TEST_CHECK( view.GetType() == EffectsView::DROP_SHADOW );
+
+  view.Reset();
+  view = EffectsView::New( EffectsView::EMBOSS );
+  DALI_TEST_CHECK( view.GetType() == EffectsView::EMBOSS );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewOnStage(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New(EffectsView::EMBOSS);
+  view.SetSize(100.f, 100.f);
+  Stage stage = Stage::GetCurrent();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  stage.Add( view );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() > 1 );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewOffStage(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New(EffectsView::DROP_SHADOW);
+  view.SetSize(100.f, 100.f);
+  Stage stage = Stage::GetCurrent();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  stage.Add( view );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() > 1 );
+
+  stage.Remove( view );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTaskCount() == 1 );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewRefreshP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  try
+  {
+    view.Refresh();
+    DALI_TEST_CHECK( true );
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( false ); // Should not get here!
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewRefreshN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.Refresh();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetPixelFormatP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  try
+  {
+    view.SetPixelFormat( Pixel::RGBA8888 );
+    DALI_TEST_CHECK( true );
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( false ); // Should not get here!
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetPixelFormatN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetPixelFormat( Pixel::RGBA8888 );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSizeProperty(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+
+  Property::Index idx = view.GetPropertyIndex( "effectSize" );
+  DALI_TEST_EQUALS( idx, (Property::Index)EffectsView::Property::EFFECT_SIZE, TEST_LOCATION );
+
+  view.SetProperty( idx, 5 );
+  Property::Value value = view.GetProperty( EffectsView::Property::EFFECT_SIZE );
+  int size;
+  DALI_TEST_CHECK( value.Get(size) );
+  DALI_TEST_CHECK( size == 5 );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewOffsetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::EMBOSS );
+  Stage::GetCurrent().Add( view );
+
+  Property::Value value = view.GetProperty( EffectsView::Property::EFFECT_OFFSET );
+  Vector3 offsetValue;
+  DALI_TEST_CHECK( value.Get(offsetValue) );
+  DALI_TEST_EQUALS( offsetValue, Vector3::ZERO, TEST_LOCATION );
+
+  Vector3 offsetSet( 2.f, 3.f, 4.f );
+  view.SetProperty( EffectsView::Property::EFFECT_OFFSET, offsetSet);
+  application.SendNotification();
+  application.Render(0);
+  value = view.GetProperty( EffectsView::Property::EFFECT_OFFSET );
+  value.Get(offsetValue);
+  DALI_TEST_EQUALS( offsetValue, offsetSet, TEST_LOCATION );
+
+  Vector3 offsetAnimate( 4.f, 6.f, 8.f );
+  float durationSeconds(0.05f);
+  Animation animation = Animation::New( durationSeconds );
+  animation.AnimateTo( Property(view,EffectsView::Property::EFFECT_OFFSET ), offsetAnimate );
+  animation.Play();
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds*1000.0f) + 1u/*just beyond the animation duration*/);
+
+  value = view.GetCurrentProperty( EffectsView::Property::EFFECT_OFFSET );
+  value.Get(offsetValue);
+  DALI_TEST_EQUALS( offsetValue, offsetAnimate, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewColorProperty(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New( EffectsView::DROP_SHADOW );
+  Stage::GetCurrent().Add( view );
+
+  Property::Value value = view.GetProperty( EffectsView::Property::EFFECT_COLOR );
+  Vector4 colorValue;
+  DALI_TEST_CHECK( value.Get(colorValue) );
+  DALI_TEST_EQUALS( colorValue, Color::WHITE, TEST_LOCATION );
+
+  Vector4 colorSet( 0.2f, 0.3f, 0.4f, 0.5f );
+  view.SetProperty( EffectsView::Property::EFFECT_COLOR, colorSet);
+  application.SendNotification();
+  application.Render(0);
+  value = view.GetProperty( EffectsView::Property::EFFECT_COLOR );
+  value.Get(colorValue);
+  DALI_TEST_EQUALS( colorValue, colorSet, TEST_LOCATION );
+
+  Vector4 colorAnimate( 0.5f, 0.6f, 0.8f, 1.f );
+  float durationSeconds(0.05f);
+  Animation animation = Animation::New( durationSeconds );
+  animation.AnimateTo( Property(view,EffectsView::Property::EFFECT_COLOR ), colorAnimate );
+  animation.Play();
+  application.SendNotification();
+  application.Render(static_cast<unsigned int>(durationSeconds*1000.0f) + 1u/*just beyond the animation duration*/);
+
+  value = view.GetCurrentProperty( EffectsView::Property::EFFECT_COLOR );
+  value.Get(colorValue);
+  DALI_TEST_EQUALS( colorValue, colorAnimate, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetSetBackgroundColor(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New(EffectsView::DROP_SHADOW);
+  view.SetBackgroundColor( Color::RED );
+  DALI_TEST_CHECK( Color::RED == view.GetBackgroundColor() );
+
+  view.SetBackgroundColor( Color::YELLOW );
+  DALI_TEST_CHECK( Color::YELLOW == view.GetBackgroundColor() );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetBackgroundColorN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetBackgroundColor( Color::RED );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewGetBackgroundColorN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    Vector4 color = view.GetBackgroundColor();
+    (void)color;
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetRefreshOnDemandP(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view = EffectsView::New(EffectsView::DROP_SHADOW);
+  view.SetSize(100.f, 100.f);
+
+  Stage stage = Stage::GetCurrent();
+  stage.Add( view );
+  application.SendNotification();
+  application.Render();
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+
+  view.SetRefreshOnDemand( true );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ONCE );
+
+  view.SetRefreshOnDemand( false );
+  DALI_TEST_CHECK( renderTaskList.GetTask( 1 ).GetRefreshRate() == RenderTask::REFRESH_ALWAYS );
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSetRefreshOnDemandN(void)
+{
+  ToolkitTestApplication application;
+
+  EffectsView view;
+  try
+  {
+    view.SetRefreshOnDemand( false );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewSizeSet(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  {
+    EffectsView view = EffectsView::New(EffectsView::DROP_SHADOW);
+    view.SetSize( 200.0f, 200.0f, 0.0f );
+    stage.Add( view );
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 0.0f ), TEST_LOCATION );
+  }
+
+  {
+    EffectsView view = EffectsView::New(EffectsView::EMBOSS);
+    view.SetSize( 200.0f, 200.0f, 0.0f );
+    stage.Add( view );
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 0.0f ), TEST_LOCATION );
+  }
+
+  {
+    EffectsView view = EffectsView::New(EffectsView::DROP_SHADOW);
+    view.SetSize( 200.0f, 200.0f, 0.0f );
+    stage.Add( view );
+    application.SendNotification();
+    application.Render();
+
+    stage.Remove( view );
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( view.GetCurrentSize(), Vector3( 200.0f, 200.0f, 0.0f ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliEffectsViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "EffectsView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  EffectsView view = EffectsView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-FlexContainer.cpp b/automated-tests/src/dali-toolkit/utc-Dali-FlexContainer.cpp
new file mode 100755 (executable)
index 0000000..26e9585
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/actors/actor-devel.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_flexflexContainer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_flexflexContainer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* const PROPERTY_NAME_CONTENT_DIRECTION = "contentDirection";
+const char* const PROPERTY_NAME_FLEX_DIRECTION = "flexDirection";
+const char* const PROPERTY_NAME_FLEX_WRAP = "flexWrap";
+const char* const PROPERTY_NAME_JUSTIFY_CONTENT = "justifyContent";
+const char* const PROPERTY_NAME_ALIGN_ITEMS = "alignItems";
+const char* const PROPERTY_NAME_ALIGN_CONTENT =  "alignContent";
+const char* const CHILD_PROPERTY_NAME_FLEX = "flex";
+const char* const CHILD_PROPERTY_NAME_ALIGN_SELF = "alignSelf";
+const char* const CHILD_PROPERTY_NAME_FLEX_MARGIN =  "flexMargin";
+
+} // namespace
+
+int UtcDaliToolkitFlexContainerConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerConstructorP");
+  FlexContainer flexContainer;
+  DALI_TEST_CHECK( !flexContainer );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerNewP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerDownCastP");
+  FlexContainer flexContainer1 = FlexContainer::New();
+  BaseHandle object( flexContainer1 );
+
+  FlexContainer flexContainer2 = FlexContainer::DownCast( object );
+  DALI_TEST_CHECK( flexContainer2 );
+
+  FlexContainer flexContainer3 = DownCast< FlexContainer >( object );
+  DALI_TEST_CHECK( flexContainer3 );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerDownCastN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerDownCastN");
+  BaseHandle uninitializedObject;
+  FlexContainer flexContainer1 = FlexContainer::DownCast( uninitializedObject );
+  DALI_TEST_CHECK( !flexContainer1 );
+
+  FlexContainer flexContainer2 = DownCast< FlexContainer >( uninitializedObject );
+  DALI_TEST_CHECK( !flexContainer2 );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerCopyConstructorP");
+  FlexContainer flexContainer = FlexContainer::New();
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, FlexContainer::ROW_REVERSE );
+
+  FlexContainer copy( flexContainer );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ) == flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ) );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerAssingmentOperatorP");
+  FlexContainer flexContainer = FlexContainer::New();
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, FlexContainer::ROW_REVERSE );
+
+  FlexContainer copy = flexContainer;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ) == flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ) );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliToolkitFlexContainerGetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerGetPropertyP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  // Check Property Indices are correct
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_CONTENT_DIRECTION ) == FlexContainer::Property::CONTENT_DIRECTION );
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_FLEX_DIRECTION ) == FlexContainer::Property::FLEX_DIRECTION );
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_FLEX_WRAP ) == FlexContainer::Property::FLEX_WRAP );
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_JUSTIFY_CONTENT ) == FlexContainer::Property::JUSTIFY_CONTENT );
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_ALIGN_ITEMS ) == FlexContainer::Property::ALIGN_ITEMS );
+  DALI_TEST_CHECK( flexContainer.GetPropertyIndex( PROPERTY_NAME_ALIGN_CONTENT ) == FlexContainer::Property::ALIGN_CONTENT );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerSetPropertyP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  // Add flex container to the stage
+  Stage::GetCurrent().Add( flexContainer );
+
+  // Create two actors and add them to the container
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Add(actor1);
+  flexContainer.Add(actor2);
+
+  // Check content direction property.
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, FlexContainer::RTL );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::RTL, TEST_LOCATION );
+
+  // Check flex direction property.
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, FlexContainer::COLUMN_REVERSE );
+  DALI_TEST_EQUALS( (FlexContainer::FlexDirection)flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ), FlexContainer::COLUMN_REVERSE, TEST_LOCATION );
+
+  // Check flex wrap property.
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_WRAP, FlexContainer::WRAP );
+  DALI_TEST_EQUALS( (FlexContainer::WrapType)flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_WRAP ), FlexContainer::WRAP, TEST_LOCATION );
+
+  // Check justify content property.
+  flexContainer.SetProperty( FlexContainer::Property::JUSTIFY_CONTENT, FlexContainer::JUSTIFY_SPACE_BETWEEN );
+  DALI_TEST_EQUALS( (FlexContainer::Justification)flexContainer.GetProperty<int>( FlexContainer::Property::JUSTIFY_CONTENT ), FlexContainer::JUSTIFY_SPACE_BETWEEN, TEST_LOCATION );
+
+  // Check align items property.
+  flexContainer.SetProperty( FlexContainer::Property::ALIGN_ITEMS, FlexContainer::ALIGN_FLEX_START );
+  DALI_TEST_EQUALS( (FlexContainer::Alignment)flexContainer.GetProperty<int>( FlexContainer::Property::ALIGN_ITEMS ), FlexContainer::ALIGN_FLEX_START, TEST_LOCATION );
+
+  // Check align content property.
+  flexContainer.SetProperty( FlexContainer::Property::ALIGN_CONTENT, FlexContainer::ALIGN_STRETCH );
+  DALI_TEST_EQUALS( (FlexContainer::Alignment)flexContainer.GetProperty<int>( FlexContainer::Property::ALIGN_CONTENT ), FlexContainer::ALIGN_STRETCH, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliToolkitFlexContainerSetPropertyEnumP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerSetPropertyEnumP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  // Add flex container to the stage
+  Stage::GetCurrent().Add( flexContainer );
+
+  // Create two actors and add them to the container
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Add(actor1);
+  flexContainer.Add(actor2);
+
+  // Check content direction property.
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "RTL" );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::RTL, TEST_LOCATION );
+
+  // Check flex direction property.
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, "columnReverse" );
+  DALI_TEST_EQUALS( (FlexContainer::FlexDirection)flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ), FlexContainer::COLUMN_REVERSE, TEST_LOCATION );
+
+  // Check flex wrap property.
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_WRAP, "wrap" );
+  DALI_TEST_EQUALS( (FlexContainer::WrapType)flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_WRAP ), FlexContainer::WRAP, TEST_LOCATION );
+
+  // Check justify content property.
+  flexContainer.SetProperty( FlexContainer::Property::JUSTIFY_CONTENT, "spaceBetween" );
+  DALI_TEST_EQUALS( (FlexContainer::Justification)flexContainer.GetProperty<int>( FlexContainer::Property::JUSTIFY_CONTENT ), FlexContainer::JUSTIFY_SPACE_BETWEEN, TEST_LOCATION );
+
+  // Check align items property.
+  flexContainer.SetProperty( FlexContainer::Property::ALIGN_ITEMS, "flexStart" );
+  DALI_TEST_EQUALS( (FlexContainer::Alignment)flexContainer.GetProperty<int>( FlexContainer::Property::ALIGN_ITEMS ), FlexContainer::ALIGN_FLEX_START, TEST_LOCATION );
+
+  // Check align content property.
+  flexContainer.SetProperty( FlexContainer::Property::ALIGN_CONTENT, "stretch" );
+  DALI_TEST_EQUALS( (FlexContainer::Alignment)flexContainer.GetProperty<int>( FlexContainer::Property::ALIGN_CONTENT ), FlexContainer::ALIGN_STRETCH, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerSetChildPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerSetChildPropertyP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  // Add flex container to the stage
+  Stage::GetCurrent().Add( flexContainer );
+
+  // Create an actor and add it to the container
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( actor );
+
+  flexContainer.Add(actor);
+
+  // Check flex child property.
+  actor.SetProperty( FlexContainer::ChildProperty::FLEX, 2.0f );
+  DALI_TEST_EQUALS( actor.GetProperty<float>( FlexContainer::ChildProperty::FLEX ), 2.0f, TEST_LOCATION );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( CHILD_PROPERTY_NAME_FLEX ) == FlexContainer::ChildProperty::FLEX );
+
+  // Check align self child property.
+  actor.SetProperty( FlexContainer::ChildProperty::ALIGN_SELF, FlexContainer::ALIGN_FLEX_END );
+  DALI_TEST_EQUALS( (FlexContainer::Alignment)actor.GetProperty<int>( FlexContainer::ChildProperty::ALIGN_SELF ), FlexContainer::ALIGN_FLEX_END, TEST_LOCATION );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( CHILD_PROPERTY_NAME_ALIGN_SELF ) == FlexContainer::ChildProperty::ALIGN_SELF );
+
+  // Check flex margin child property.
+  actor.SetProperty( FlexContainer::ChildProperty::FLEX_MARGIN, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
+  DALI_TEST_EQUALS( actor.GetProperty<Vector4>( FlexContainer::ChildProperty::FLEX_MARGIN ), Vector4( 10.0f, 10.0f, 10.0f, 10.0f ), TEST_LOCATION );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( CHILD_PROPERTY_NAME_FLEX_MARGIN ) == FlexContainer::ChildProperty::FLEX_MARGIN );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+
+
+//Functor to test whether RelayoutSignal is emitted
+class RelayoutSignalHandler : public Dali::ConnectionTracker
+{
+public:
+
+  RelayoutSignalHandler( FlexContainer& actor )
+  : mSignalVerified( false ),
+    mActor( actor )
+  {
+  }
+
+  // callback to be connected to RelayoutSignal
+  void RelayoutCallback( Actor actor  )
+  {
+    if( mActor == actor )
+    {
+      mSignalVerified = true;
+    }
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool   mSignalVerified;
+  Actor& mActor;
+};
+
+int UtcDaliToolkitFlexContainerRemoveChildP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerSetPropertyP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  // Add flex container to the stage
+  Stage::GetCurrent().Add( flexContainer );
+
+  RelayoutSignalHandler relayoutSignal(flexContainer);
+  flexContainer.OnRelayoutSignal().Connect(&relayoutSignal, &RelayoutSignalHandler::RelayoutCallback );
+
+  // Create two actors and add them to the container
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Add(actor1);
+  flexContainer.Add(actor2);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( relayoutSignal.mSignalVerified, true, TEST_LOCATION );
+  relayoutSignal.Reset();
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Remove(actor1);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( relayoutSignal.mSignalVerified, true, TEST_LOCATION );
+  relayoutSignal.Reset();
+
+  flexContainer.Remove(actor2);
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( relayoutSignal.mSignalVerified, true, TEST_LOCATION );
+  relayoutSignal.Reset();
+
+  END_TEST;
+}
+
+namespace
+{
+
+// Functors to test whether PreFocusChange signal is emitted when the keyboard focus is about to change
+class PreFocusChangeCallback : public Dali::ConnectionTracker
+{
+public:
+  PreFocusChangeCallback(bool& signalReceived, Actor firstFocusActor)
+  : mSignalVerified(signalReceived),
+    mFirstFocusActor(firstFocusActor),
+    mDirection(Control::KeyboardFocus::LEFT)
+  {
+  }
+
+  Actor Callback(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction)
+  {
+    tet_infoline("Verifying PreFocusChangeCallback()");
+
+    mSignalVerified = true;
+    mDirection = direction;
+    if( ! proposedActorToFocus )
+    {
+      return mFirstFocusActor;
+    }
+    else
+    {
+      return proposedActorToFocus;
+    }
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+    mDirection = Control::KeyboardFocus::LEFT;
+  }
+
+  bool& mSignalVerified;
+  Actor mFirstFocusActor;
+  Control::KeyboardFocus::Direction mDirection;
+};
+
+// Functors to test whether focus changed signal is emitted when the keyboard focus is changed
+class FocusChangedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusChangedCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mOriginalFocusedActor(),
+    mCurrentFocusedActor()
+  {
+  }
+
+  void Callback(Actor originalFocusedActor, Actor currentFocusedActor)
+  {
+    tet_infoline("Verifying FocusChangedCallback()");
+
+    if(originalFocusedActor == mCurrentFocusedActor)
+    {
+      mSignalVerified = true;
+    }
+
+    mOriginalFocusedActor = originalFocusedActor;
+    mCurrentFocusedActor = currentFocusedActor;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mOriginalFocusedActor;
+  Actor mCurrentFocusedActor;
+};
+
+} // anonymous namespace
+
+
+int UtcDaliToolkitFlexContainerMoveFocus(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerSetPropertyP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, FlexContainer::ROW );
+
+  // Add flex container to the stage
+  Stage::GetCurrent().Add( flexContainer );
+  Size stageSize = Stage::GetCurrent().GetSize();
+
+  RelayoutSignalHandler relayoutSignal(flexContainer);
+  flexContainer.OnRelayoutSignal().Connect(&relayoutSignal, &RelayoutSignalHandler::RelayoutCallback );
+  flexContainer.SetSize( stageSize );
+
+  // Create two actors and add them to the container
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  actor1.SetKeyboardFocusable(true);
+  actor2.SetKeyboardFocusable(true);
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Add(actor1);
+  flexContainer.Add(actor2);
+
+  application.SendNotification();
+  application.Render();
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified, actor1);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  // Move the focus to the right
+  DALI_TEST_EQUALS(manager.MoveFocus(Control::KeyboardFocus::RIGHT), true, TEST_LOCATION);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_EQUALS(manager.GetCurrentFocusActor(), actor1, TEST_LOCATION);
+  preFocusChangeCallback.Reset();
+  DALI_TEST_EQUALS(focusChangedCallback.mCurrentFocusedActor, actor1, TEST_LOCATION);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_EQUALS(manager.MoveFocus(Control::KeyboardFocus::RIGHT), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(preFocusChangeCallback.mSignalVerified, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(manager.GetCurrentFocusActor(), actor2, TEST_LOCATION);
+  DALI_TEST_EQUALS(focusChangedCallback.mSignalVerified, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(focusChangedCallback.mCurrentFocusedActor, actor2, TEST_LOCATION);
+
+  preFocusChangeCallback.Reset();
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  DALI_TEST_EQUALS(manager.MoveFocus(Control::KeyboardFocus::LEFT), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(preFocusChangeCallback.mSignalVerified, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(manager.GetCurrentFocusActor(), actor1, TEST_LOCATION);
+  DALI_TEST_EQUALS(focusChangedCallback.mSignalVerified, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(focusChangedCallback.mCurrentFocusedActor, actor1, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexContainerRTLSupportP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexContainerRTLSupportP");
+  FlexContainer flexContainer = FlexContainer::New();
+  DALI_TEST_CHECK( flexContainer );
+
+  Actor actor0 = Actor::New();
+
+  Stage::GetCurrent().Add( actor0 );
+  actor0.Add( flexContainer );
+
+  // Create two actors and add them to the container
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexContainer.Add(actor1);
+  flexContainer.Add(actor2);
+
+  // Check flex direction property.
+  flexContainer.SetProperty( FlexContainer::Property::FLEX_DIRECTION, "row" );
+  DALI_TEST_EQUALS( (FlexContainer::FlexDirection)flexContainer.GetProperty<int>( FlexContainer::Property::FLEX_DIRECTION ), FlexContainer::ROW, TEST_LOCATION );
+
+  // Check content direction property.
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::INHERIT, TEST_LOCATION );
+
+  actor0.SetProperty( Dali::DevelActor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::RTL, TEST_LOCATION );
+
+  actor0.SetProperty( Dali::DevelActor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::LTR, TEST_LOCATION );
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "RTL" );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::RTL, TEST_LOCATION );
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "LTR" );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::LTR, TEST_LOCATION );
+
+  actor0.SetProperty( Dali::DevelActor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::LTR, TEST_LOCATION );
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "inherit" );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::RTL, TEST_LOCATION );
+
+  actor0.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::LTR, TEST_LOCATION );
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "inherit" );
+  DALI_TEST_EQUALS( (FlexContainer::ContentDirection)flexContainer.GetProperty<int>( FlexContainer::Property::CONTENT_DIRECTION ), FlexContainer::LTR, TEST_LOCATION );
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "LTR" );
+  application.SendNotification();
+  application.Render();
+
+  flexContainer.SetProperty( FlexContainer::Property::CONTENT_DIRECTION, "RTL" );
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp b/automated-tests/src/dali-toolkit/utc-Dali-FlexNode.cpp
new file mode 100755 (executable)
index 0000000..31a6bf2
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2019 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/devel-api/actors/actor-devel.h>
+#include <dali-toolkit/devel-api/layouting/flex-node.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_flexNodeContainer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_flexNodeContainer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const Flex::SizeTuple ITEM_SIZE = Flex::SizeTuple{ 10.0f, 10.0f };
+const Flex::SizeTuple ITEM_SIZE_CALLBACK_TEST = Flex::SizeTuple{ 15.0f, 15.0f };
+
+Flex::SizeTuple MeasureChild( Actor child, float width, int measureModeWidth, float height, int measureModeHeight)
+{
+  Flex::SizeTuple childSize = ITEM_SIZE;
+  if (child.GetName() == "callbackTest")
+  {
+    childSize = ITEM_SIZE_CALLBACK_TEST;
+  }
+  tet_printf(" MeasureChild test callback executed (%f,%f)\n", childSize.width, childSize.height );
+  return childSize;
+}
+
+}
+
+int UtcDaliToolkitFlexNodeConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeNewP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeAddChildWithMarginP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeAddChildWithMarginP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements as a Row
+  flexNode->SetFlexDirection(Flex::FlexDirection::ROW);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( actor );
+
+  Extents margin( 5,5,5,5);
+  flexNode->AddChild(actor, margin, &MeasureChild, 0);
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexDirection(), (int)Flex::FlexDirection::ROW, TEST_LOCATION );
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actorFrame = flexNode->GetNodeFrame(0);
+
+  tet_printf("Actor frame(left:%f,top:%f,right:%f,bottom:%f)\n", actorFrame.x, actorFrame.y, actorFrame.z, actorFrame.w);
+
+  DALI_TEST_EQUALS( actorFrame, Vector4( 5.0f, 5.0f, ITEM_SIZE.width+5, ITEM_SIZE.height+5 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeAddChildrenRowP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeAddChildrenRowP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements as a Row
+  flexNode->SetFlexDirection(Flex::FlexDirection::ROW);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexDirection(), (int)Flex::FlexDirection::ROW, TEST_LOCATION );
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width * 2, ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeAddChildrenColumnP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeAddChildrenColumnP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height *2 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliToolkitFlexNodeAddChildrenColumnJustify(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeAddChildrenColumnJustify");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  tet_infoline("Justify to the Start, align to start");
+  flexNode->SetFlexJustification(Flex::Justification::FLEX_START);
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_START );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexJustification(), (int)Flex::Justification::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexItemsAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |1      |
+    |2      |
+    |       |
+    |       |
+    |       |
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height *2 ), TEST_LOCATION );
+
+  tet_infoline(" Justify to the End, items should now be displayed at the bottom");
+  flexNode->SetFlexJustification( Flex::Justification::FLEX_END );
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_START );
+
+  // Recalulate layout
+  flexNode->CalculateLayout(480, 800, false);
+
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |       |
+    |       |
+    |       |
+    |1      |
+    |2      |
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, root.w - (ITEM_SIZE.height*2), ITEM_SIZE.width,  root.w - ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, root.w - ITEM_SIZE.height, ITEM_SIZE.width, root.w ), TEST_LOCATION );
+
+  tet_infoline(" Align to End, items should now be displayed at the bottom and the end");
+  flexNode->SetFlexJustification( Flex::Justification::FLEX_END );
+  flexNode->SetFlexItemsAlignment( Flex::Alignment::FLEX_END );
+  // Recalulate layout
+  flexNode->CalculateLayout(480, 800, false);
+
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  /*
+    ---------
+    |       |
+    |       |
+    |       |
+    |      1|
+    |      2|
+    ---------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( root.z - ITEM_SIZE.width, root.w - (ITEM_SIZE.height*2), root.z,  root.w - ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( root.z - ITEM_SIZE.width, root.w - ITEM_SIZE.height, root.z, root.w ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeSizingP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeSizingP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  DALI_TEST_EQUALS( flexNode->GetFlexWidth(), 480.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( flexNode->GetFlexHeight(), 800.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeWrapModeP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeWrapModeP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection( Flex::FlexDirection::ROW );
+  flexNode->SetFlexAlignment( Flex::Alignment::FLEX_START );
+  flexNode->SetFlexWrap( Flex::WrapType::NO_WRAP );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  Actor actor3 = Actor::New();
+  Actor actor4 = Actor::New();
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexJustification(), (int)Flex::Justification::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexItemsAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexAlignment(), (int)Flex::Alignment::FLEX_START, TEST_LOCATION );
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexWrap(), (int)Flex::WrapType::NO_WRAP, TEST_LOCATION );
+
+  flexNode->AddChild( actor1, Extents(0,0,0,0), &MeasureChild, 0 );
+  flexNode->AddChild( actor2, Extents(0,0,0,0), &MeasureChild, 1 );
+  flexNode->AddChild( actor2, Extents(0,0,0,0), &MeasureChild, 2 );
+  flexNode->AddChild( actor2, Extents(0,0,0,0), &MeasureChild, 3 );
+
+  flexNode->CalculateLayout(30, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+  Vector4 actor3Frame = flexNode->GetNodeFrame(2); // 2 is first child
+  Vector4 actor4Frame = flexNode->GetNodeFrame(3); // 3 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+  tet_printf("Actor 3 frame(left:%f,top:%f,right:cdt%f,bottom:%f)\n", actor3Frame.x, actor3Frame.y, actor3Frame.z, actor3Frame.w);
+  tet_printf("Actor 4 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor4Frame.x, actor4Frame.y, actor4Frame.z, actor4Frame.w);
+
+  /*
+    -------
+    |1 2 3 4     |
+    |     |
+    |     |
+    |     |
+    |     |
+    -------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f,            0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width*2, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3Frame, Vector4( ITEM_SIZE.width*2, 0.0f, ITEM_SIZE.width*3, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor4Frame, Vector4( ITEM_SIZE.width*3, 0.0f, ITEM_SIZE.width*4, ITEM_SIZE.height ), TEST_LOCATION );
+
+  flexNode->SetFlexWrap( Flex::WrapType::WRAP );
+
+  flexNode->CalculateLayout( 30, 800, false );
+  root = flexNode->GetNodeFrame(-1); // -1 is the root
+
+  DALI_TEST_EQUALS( (int)flexNode->GetFlexWrap(), (int)Flex::WrapType::WRAP, TEST_LOCATION );
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+  actor3Frame = flexNode->GetNodeFrame(2); // 2 is first child
+  actor4Frame = flexNode->GetNodeFrame(3); // 3 is second child
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+  tet_printf("Actor 3 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor3Frame.x, actor3Frame.y, actor3Frame.z, actor3Frame.w);
+  tet_printf("Actor 4 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor4Frame.x, actor4Frame.y, actor4Frame.z, actor4Frame.w);
+
+  /*
+    -------
+    |1 2 3|     |
+    |4    |
+    |     |
+    |     |
+    |     |
+    -------
+  */
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f,            0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( ITEM_SIZE.width, 0.0f, ITEM_SIZE.width*2, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3Frame, Vector4( ITEM_SIZE.width*2, 0.0f, ITEM_SIZE.width*3, ITEM_SIZE.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor4Frame, Vector4( 0.0,ITEM_SIZE.height, ITEM_SIZE.width, ITEM_SIZE.height*2 ), TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeRemoveChildP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeRemoveChildP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  actor1.SetName("Actor1");
+  actor2.SetName("Actor2");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE.width, ITEM_SIZE.width, ITEM_SIZE.height*2 ), TEST_LOCATION );
+
+  flexNode->RemoveChild(actor1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  actor2Frame = flexNode->GetNodeFrame(0);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE.width, ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeRemoveAllChildrenP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodeRemoveAllChildrenP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  actor1.SetName("Actor1");
+  actor2.SetName("Actor2");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  flexNode->RemoveChild(actor1);
+  flexNode->RemoveChild(actor2);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1FrameRemoved = flexNode->GetNodeFrame(0);
+  Vector4 actor2FrameRemoved = flexNode->GetNodeFrame(1);
+
+  tet_printf("Actor 1 frame(%f,%f,%f,%f)\n", actor1FrameRemoved.x, actor1FrameRemoved.y, actor1FrameRemoved.z, actor1FrameRemoved.w);
+  tet_printf("Actor 2 frame(%f,%f,%f,%f)\n", actor2FrameRemoved.x, actor2FrameRemoved.y, actor2FrameRemoved.z, actor2FrameRemoved.w);
+
+  DALI_TEST_NOT_EQUALS( actor1Frame, actor1FrameRemoved, 0.1, TEST_LOCATION );
+  DALI_TEST_NOT_EQUALS( actor2Frame, actor2FrameRemoved, 0.1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodePaddingMarginP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitFlexNodePaddingMarginP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+  flexNode->SetFlexDirection( Flex::FlexDirection::ROW );
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  Extents padding( 5,5,5,5);
+  Extents margin( 5,5,5,5);
+
+  flexNode->SetPadding( padding );
+  flexNode->SetMargin( margin );
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0);
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1);
+
+  /*  p = padding
+  -----
+  |ppppp|
+  |p1 2p|
+  |p   p|
+  |ppppp|
+  -------
+  */
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 5.0f, 5.0f, ITEM_SIZE.width +5 , ITEM_SIZE.height + 5 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 5+ ITEM_SIZE.width, 5.0f, (ITEM_SIZE.width*2) +5, ITEM_SIZE.height +5 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitFlexNodeCallbackTestP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToolkitFlexNodeCallbackTestP");
+  Flex::Node* flexNode = new Flex::Node();
+  DALI_TEST_CHECK( flexNode );
+
+  // Position elements in a Column
+  flexNode->SetFlexDirection(Flex::FlexDirection::COLUMN);
+
+  // Create two actors and add them to the parent flex node
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+
+  actor1.SetName("callbackTest");
+
+  DALI_TEST_CHECK( actor1 );
+  DALI_TEST_CHECK( actor2 );
+
+  flexNode->AddChild(actor1, Extents(0,0,0,0), &MeasureChild, 0);
+  flexNode->AddChild(actor2, Extents(0,0,0,0), &MeasureChild, 1);
+
+  flexNode->CalculateLayout(480, 800, false);
+
+  Vector4 root = flexNode->GetNodeFrame(-1); // -1 is the root
+  Vector4 actor1Frame = flexNode->GetNodeFrame(0); // 0 is first child
+  Vector4 actor2Frame = flexNode->GetNodeFrame(1); // 1 is second child
+
+  tet_printf("Root frame(left:%f,top:%f,right:%f,bottom:%f)\n", root.x, root.y, root.z, root.w);
+
+  tet_printf("Actor 1 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor1Frame.x, actor1Frame.y, actor1Frame.z, actor1Frame.w);
+  tet_printf("Actor 2 frame(left:%f,top:%f,right:%f,bottom:%f)\n", actor2Frame.x, actor2Frame.y, actor2Frame.z, actor2Frame.w);
+
+  DALI_TEST_EQUALS( actor1Frame, Vector4( 0.0f, 0.0f, ITEM_SIZE_CALLBACK_TEST.width, ITEM_SIZE_CALLBACK_TEST.height ), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2Frame, Vector4( 0.0f, ITEM_SIZE_CALLBACK_TEST.height, ITEM_SIZE.width, ITEM_SIZE_CALLBACK_TEST.height + ITEM_SIZE.height ), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-GaussianBlurView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-GaussianBlurView.cpp
new file mode 100644 (file)
index 0000000..531b94c
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+} // namespace
+
+void utc_gaussian_blur_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_gaussian_blur_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+class TestCallback : public ConnectionTracker
+{
+public:
+  TestCallback( Dali::Toolkit::GaussianBlurView& blurView )
+  : mBlurView( blurView )
+  {
+    mFinished = false;
+  }
+
+  void Connect()
+  {
+    mBlurView.FinishedSignal().Connect( this, &TestCallback::OnFinished );
+  }
+
+  void OnFinished( Dali::Toolkit::GaussianBlurView source )
+  {
+    mFinished = true;
+  }
+
+  bool mFinished;
+  Dali::Toolkit::GaussianBlurView& mBlurView;
+};
+
+// Negative test case for a method
+int UtcDaliGaussianBlurViewUninitialized(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewUninitialized");
+
+  Toolkit::GaussianBlurView view;
+
+  try
+  {
+    // New() must be called to create a GaussianBlurView or it wont be valid.
+    Actor a = Actor::New();
+    view.Add( a );
+    DALI_TEST_CHECK( false );
+  }
+  catch (Dali::DaliException& e)
+  {
+    // Tests that a negative test of an assertion succeeds
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_CHECK(!view);
+  }
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewNew");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  DALI_TEST_CHECK( view );
+
+  Toolkit::GaussianBlurView view2 = Toolkit::GaussianBlurView::New(5, 1.5f, Pixel::RGB888, 0.5f, 0.5f, false);
+  DALI_TEST_CHECK( view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewDownCast");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  BaseHandle handle(view);
+
+  Toolkit::GaussianBlurView gaussianBlurView = Toolkit::GaussianBlurView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( gaussianBlurView );
+  DALI_TEST_CHECK( gaussianBlurView == view );
+  END_TEST;
+}
+
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewPropertyNames(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewPropertyNames");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  DALI_TEST_CHECK( view );
+
+  // Check the names, this names are used in the shader code,
+  // if they change in the shader code, then it has to be updated here.
+  DALI_TEST_EQUALS( view.GetBlurStrengthPropertyIndex(), view.GetPropertyIndex("GaussianBlurStrengthPropertyName"), TEST_LOCATION );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewAddRemove(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewAddRemove");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(actor);
+  Stage::GetCurrent().Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+
+  view.Remove(actor);
+
+  DALI_TEST_CHECK( !actor.OnStage() );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurActivateDeactivate(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurActivateDeactivate");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  DALI_TEST_CHECK( view );
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList.GetTaskCount() );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.Activate();
+
+  RenderTaskList taskList2 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u != taskList2.GetTaskCount() );
+  DALI_TEST_CHECK( 2u == view.GetChildCount() );
+
+  view.Deactivate();
+
+  RenderTaskList taskList3 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList3.GetTaskCount() );
+  DALI_TEST_CHECK( 1u == view.GetChildCount() );
+
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewSetGetBackgroundColor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewSetGetBackgroundColor");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New();
+  DALI_TEST_CHECK( view );
+
+  view.SetBackgroundColor(Dali::Color::RED);
+  Vector4 color = view.GetBackgroundColor();
+  DALI_TEST_CHECK( color == Dali::Color::RED );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliGaussianBlurViewSetGetRenderTarget(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewSetGetRenderTarget");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New(5, 1.5f, Pixel::RGB888, 0.5f, 0.5f, true);
+  DALI_TEST_CHECK( view );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.Activate();
+
+  PixelData pixels = Toolkit::SyncImageLoader::Load( TEST_IMAGE_FILE_NAME );
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
+  texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
+
+  FrameBuffer renderTarget = FrameBuffer::New( 480, 800, FrameBuffer::Attachment::NONE );
+  view.SetUserImageAndOutputRenderTarget(texture, renderTarget);
+  DALI_TEST_CHECK( view.GetBlurredRenderTarget() == renderTarget );
+  END_TEST;
+}
+
+int UtcDaliGaussianBlurViewActivateOnce(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurActivateOnce");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New(5, 1.5f, Pixel::RGB888, 0.5f, 0.5f, true);
+  DALI_TEST_CHECK( view );
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList.GetTaskCount() );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.ActivateOnce();
+
+  RenderTaskList taskList2 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u != taskList2.GetTaskCount() );
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliGaussianBlurViewFinishedSignalN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliGaussianBlurViewFinishedSignalN");
+
+  Toolkit::GaussianBlurView view = Toolkit::GaussianBlurView::New(5, 1.5f, Pixel::RGB888, 0.5f, 0.5f, true);
+  DALI_TEST_CHECK( view );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.Activate();
+
+  TestCallback callback( view );
+  DALI_TEST_CHECK( callback.mFinished == false );
+
+  callback.Connect();
+
+  view.Deactivate();
+  application.SendNotification();
+
+  // FinishedSignal is only for ActivateOnce()
+  DALI_TEST_CHECK( callback.mFinished == false );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageAtlas.cpp
new file mode 100644 (file)
index 0000000..0422166
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2019 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 <stdlib.h>
+#include <unistd.h>
+#include <dali/dali.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 50*50, pixel format: RGBA8888
+static const char* gImage_50_RGBA = TEST_RESOURCE_DIR "/icon-delete.png";
+// resolution: 128*128, pixel format: RGB888
+static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+// Empty image, for testing broken image loading
+static const char* gEmptyImage = TEST_RESOURCE_DIR "/empty.bmp";
+
+const int RENDER_FRAME_INTERVAL = 16; ///< Duration of each frame in ms. (at approx 60FPS)
+
+PixelData CreatePixelData( unsigned int width, unsigned int height )
+{
+  unsigned int bufferSize = width*height*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
+
+  unsigned char* buffer= reinterpret_cast<unsigned char*>( malloc( bufferSize ) );
+  PixelData pixelData = PixelData::New( buffer, bufferSize, width, height, Pixel::RGBA8888, PixelData::FREE );
+
+  return pixelData;
+}
+
+Rect<int> TextureCoordinateToPixelArea( const Vector4& textureCoordinate, float size )
+{
+  Vector4 temp = textureCoordinate * size;
+  Rect<int> pixelArea;
+  pixelArea.x = static_cast<int>( temp.x );
+  pixelArea.y = static_cast<int>( temp.y );
+  pixelArea.width = static_cast<int>( temp.z-temp.x+1.01f );
+  pixelArea.height = static_cast<int>( temp.w-temp.y+1.01f );
+
+  return pixelArea;
+}
+
+Rect<int> TextureCoordinateToPixelArea( const Vector4& textureCoordinate, float width, float height )
+{
+  Rect<int> pixelArea;
+  pixelArea.x = static_cast<int>( textureCoordinate.x*width );
+  pixelArea.y = static_cast<int>( textureCoordinate.y*height);
+  pixelArea.width = static_cast<int>( (textureCoordinate.z-textureCoordinate.x)*width+1.01f );
+  pixelArea.height = static_cast<int>( (textureCoordinate.w-textureCoordinate.y)*height+1.01f );
+
+  return pixelArea;
+}
+
+bool IsOverlap( Rect<int> rect1, Rect<int> rect2 )
+{
+ return rect1.x < rect2.x+rect2.width
+     && rect2.x < rect1.x+rect1.width
+     && rect1.y < rect2.y+rect2.height
+     && rect2.y < rect1.y+rect1.height;
+}
+
+static unsigned int gCountOfTestFuncCall;
+class TestUploadObserver : public AtlasUploadObserver
+{
+public:
+  TestUploadObserver()
+  {}
+
+  virtual ~TestUploadObserver()
+  {}
+
+  void UploadCompleted()
+  {
+    gCountOfTestFuncCall++;
+  }
+};
+
+} // anonymous namespace
+
+void dali_image_atlas_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_image_atlas_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliImageAtlasNew(void)
+{
+  ToolkitTestApplication application;
+
+  // invoke default handle constructor
+  ImageAtlas atlas;
+
+  DALI_TEST_CHECK( !atlas );
+
+  // initialise handle
+  atlas = ImageAtlas::New( 32, 32 );
+
+  DALI_TEST_CHECK( atlas );
+  END_TEST;
+}
+
+int UtcDaliImageAtlasCopyConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  ImageAtlas atlas = ImageAtlas::New( 32, 32);
+  ImageAtlas atlasCopy(atlas);
+
+  DALI_TEST_EQUALS( (bool)atlasCopy, true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliImageAtlasAssignmentOperator(void)
+{
+  ToolkitTestApplication application;
+
+  ImageAtlas atlas = ImageAtlas::New( 32, 32 );
+
+  ImageAtlas atlas2;
+  DALI_TEST_EQUALS( (bool)atlas2, false, TEST_LOCATION );
+
+  atlas2 = atlas;
+  DALI_TEST_EQUALS( (bool)atlas2, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasGetAtlas(void)
+{
+  ToolkitTestApplication application;
+
+  ImageAtlas atlas = ImageAtlas::New( 32, 32 );
+  Texture image = atlas.GetAtlas();
+
+  // test the atlas created
+  DALI_TEST_EQUALS( (bool)image, true, TEST_LOCATION );
+  DALI_TEST_CHECK( image.GetHeight() == 32u );
+  DALI_TEST_CHECK( image.GetWidth() == 32u );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasGetOccupancyRate(void)
+{
+  ToolkitTestApplication application;
+
+  ImageAtlas atlas = ImageAtlas::New( 100, 100 );
+
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), 0.f, TEST_LOCATION );
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34) );
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), 34.f*34.f/10000.f, 0.001f, TEST_LOCATION );
+
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50) );
+  DALI_TEST_EQUALS( atlas.GetOccupancyRate(), (34.f*34.f+50.f*50.f)/10000.f, 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasSetBrokenImage(void)
+{
+  ToolkitTestApplication application;
+  unsigned int size = 200;
+  ImageAtlas atlas = ImageAtlas::New( size, size );
+
+  // Set broken image
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetClosestImageSize(Vector2( 34, 34));
+  atlas.SetBrokenImage( gImage_34_RGBA );
+
+  Vector4 textureRect;
+
+  // the empty image will be replaced with the broken image
+  platform.SetClosestImageSize(Vector2( 20, 20));
+  atlas.Upload( textureRect, gEmptyImage );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Rect<int> pixelArea = TextureCoordinateToPixelArea(textureRect, size);
+  DALI_TEST_EQUALS( pixelArea.width, 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.height, 20, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+int UtcDaliImageAtlasUploadP(void)
+{
+  ToolkitTestApplication application;
+  unsigned int size = 200;
+  ImageAtlas atlas = ImageAtlas::New( size, size );
+
+  TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+  callStack.Reset();
+  callStack.Enable(true);
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34) );
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50) );
+  Vector4 textureRect3;
+  atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128) );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  callStack.Enable(false);
+
+  Rect<int> pixelArea1 = TextureCoordinateToPixelArea(textureRect1, size);
+  DALI_TEST_EQUALS( pixelArea1.width, 34, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea1.height, 34, TEST_LOCATION );
+
+  TraceCallStack::NamedParams params;
+  params["width"] = ToString(pixelArea1.width);
+  params["height"] = ToString(pixelArea1.height);
+  params["xoffset"] = ToString(pixelArea1.x);
+  params["yoffset"] = ToString(pixelArea1.y);
+  DALI_TEST_CHECK( callStack.FindMethodAndParams("TexSubImage2D", params ));
+
+  Rect<int> pixelArea2 = TextureCoordinateToPixelArea(textureRect2, size);
+  DALI_TEST_EQUALS( pixelArea2.width, 50, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea2.height, 50, TEST_LOCATION );
+
+  params["width"] = ToString(pixelArea2.width);
+  params["height"] = ToString(pixelArea2.height);
+  params["xoffset"] = ToString(pixelArea2.x);
+  params["yoffset"] = ToString(pixelArea2.y);
+  DALI_TEST_CHECK( callStack.FindMethodAndParams("TexSubImage2D", params ) );
+
+  Rect<int> pixelArea3 = TextureCoordinateToPixelArea(textureRect3, size);
+  DALI_TEST_EQUALS( pixelArea3.width, 128, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea3.height, 128, TEST_LOCATION );
+
+  params["width"] = ToString(pixelArea3.width);
+  params["height"] = ToString(pixelArea3.height);
+  params["xoffset"] = ToString(pixelArea3.x);
+  params["yoffset"] = ToString(pixelArea3.y);
+  DALI_TEST_CHECK( callStack.FindMethodAndParams("TexSubImage2D", params ) );
+
+  DALI_TEST_CHECK( ! IsOverlap(pixelArea1, pixelArea2) );
+  DALI_TEST_CHECK( ! IsOverlap(pixelArea1, pixelArea3) );
+  DALI_TEST_CHECK( ! IsOverlap(pixelArea2, pixelArea3) );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasUploadWithObserver01(void)
+{
+  ToolkitTestApplication application;
+  ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver uploadObserver;
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, &uploadObserver );
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, NULL );
+  Vector4 textureRect3;
+  atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, &uploadObserver );
+
+  // waiting until all three images are loaded and uploaded to atlas
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasUploadWithObserver02(void)
+{
+  ToolkitTestApplication application;
+  ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver* uploadObserver = new TestUploadObserver;
+
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, uploadObserver );
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, uploadObserver );
+  Vector4 textureRect3;
+  atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, uploadObserver );
+
+  // destroy the object.
+  delete uploadObserver;
+
+ // waiting until all three images are loaded and uploaded to atlas
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.Render(RENDER_FRAME_INTERVAL);
+  application.SendNotification();
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasUploadWithObserver03(void)
+{
+  ToolkitTestApplication application;
+
+  gCountOfTestFuncCall = 0;
+  TestUploadObserver* uploadObserver = new TestUploadObserver;
+
+  {
+    ImageAtlas atlas = ImageAtlas::New( 200, 200 );
+
+    Vector4 textureRect1;
+    atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34), FittingMode::DEFAULT, true, uploadObserver );
+    Vector4 textureRect2;
+    atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50), FittingMode::DEFAULT, true, uploadObserver );
+    Vector4 textureRect3;
+    atlas.Upload( textureRect3, gImage_128_RGB, ImageDimensions(128, 128), FittingMode::DEFAULT, true, uploadObserver );
+  }
+
+  //ImageAtlas is out of scope, so it will get destroyed
+
+  application.Render(RENDER_FRAME_INTERVAL);
+  application.SendNotification();
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // Check that TestFunc is called twice
+  DALI_TEST_EQUALS( gCountOfTestFuncCall, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasRemove(void)
+{
+  ToolkitTestApplication application;
+  unsigned int size = 100;
+  ImageAtlas atlas = ImageAtlas::New( size, size );
+  Vector4 textureRect1;
+  atlas.Upload( textureRect1, gImage_34_RGBA, ImageDimensions(34, 34) );
+
+  atlas.Remove( textureRect1 );
+
+  Vector4 textureRect2;
+  atlas.Upload( textureRect2, gImage_50_RGBA, ImageDimensions(50, 50) );
+
+  // one pixel gap
+  Rect<int> pixelArea = TextureCoordinateToPixelArea(textureRect2, size);
+  DALI_TEST_EQUALS( pixelArea.x, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.y, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasImageView(void)
+{
+  ToolkitTestApplication application;
+
+  TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+  callStack.Reset();
+  callStack.Enable(true);
+
+  Property::Map imageMap1;
+
+  imageMap1[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap1[ ImageVisual::Property::DESIRED_HEIGHT ] = 34;
+  imageMap1[ ImageVisual::Property::DESIRED_WIDTH ] = 34;
+  imageMap1[ ImageVisual::Property::ATLASING] = true;
+
+  Property::Map imageMap2;
+
+  imageMap2[ ImageVisual::Property::URL ] = gImage_50_RGBA;
+  imageMap2[ ImageVisual::Property::DESIRED_HEIGHT ] = 50;
+  imageMap2[ ImageVisual::Property::DESIRED_WIDTH ] = 50;
+  imageMap2[ ImageVisual::Property::ATLASING ] = true;
+
+  ImageView imageView1 = ImageView::New();
+  imageView1.SetProperty( ImageView::Property::IMAGE, imageMap1 );
+
+  ImageView imageView2 = ImageView::New();
+  imageView2.SetProperty( ImageView::Property::IMAGE, imageMap2 );
+
+  // ImageView doesn't do size negotiation properly: it only listens to OnSizeSet:
+  imageView1.SetSize( 100, 100 );
+  imageView2.SetSize( 100, 100 );
+  imageView1.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  imageView2.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  application.GetPlatform().SetClosestImageSize(  Vector2(34, 34) );
+  Stage::GetCurrent().Add( imageView1 );
+  application.GetPlatform().SetClosestImageSize(  Vector2(50, 50) );
+  Stage::GetCurrent().Add( imageView2 );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  callStack.Enable(false);
+
+  TraceCallStack::NamedParams params1;
+  params1["width"] = "34";
+  params1["height"] = "34";
+  params1["xoffset"] = "0";
+  params1["yoffset"] = "0";
+
+  TraceCallStack::NamedParams params2;
+  params2["width"] = "50";
+  params2["height"] = "50";
+  params2["xoffset"] = "0";
+  params2["yoffset"] = "34";
+
+  DALI_TEST_EQUALS(  callStack.FindMethodAndParams("TexSubImage2D", params1 ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS(  callStack.FindMethodAndParams("TexSubImage2D", params2 ), true, TEST_LOCATION );
+
+  callStack.Reset();
+  callStack.Enable(true);
+
+  // remove the imageView2 from stage, the second image will also be removed from atlas
+  // then the space on the atlas will be used by the third image added.
+  Stage::GetCurrent().Remove( imageView2 );
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  Property::Map imageMap3;
+  imageMap3[ ImageVisual::Property::URL ] = gImage_128_RGB;
+  imageMap3[ ImageVisual::Property::DESIRED_HEIGHT ] = 100;
+  imageMap3[ ImageVisual::Property::DESIRED_WIDTH ] = 100;
+  imageMap3[ ImageVisual::Property::ATLASING ] = true;
+
+  ImageView imageView3 = ImageView::New();
+  imageView3.SetProperty( ImageView::Property::IMAGE, imageMap3 );
+
+  application.GetPlatform().SetClosestImageSize(  Vector2(100, 100) );
+  Stage::GetCurrent().Add( imageView3 );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  callStack.Enable(false);
+
+  TraceCallStack::NamedParams params3;
+  params3["width"] = "100";
+  params3["height"] = "100";
+  params3["xoffset"] = "0";
+  params3["yoffset"] = "34";
+
+  DALI_TEST_EQUALS(  callStack.FindMethodAndParams("TexSubImage2D", params3 ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageAtlasPackToAtlas(void)
+{
+  ToolkitTestApplication application;
+
+  std::vector<PixelData> pixelDataContainer;
+  pixelDataContainer.push_back( CreatePixelData( 20, 30 ) );
+  pixelDataContainer.push_back( CreatePixelData( 10, 10 ) );
+  pixelDataContainer.push_back( CreatePixelData( 45, 30 ) );
+  pixelDataContainer.push_back( CreatePixelData( 20, 20 ) );
+
+  Dali::Vector<Vector4> textureRects;
+  Texture texture = ImageAtlas::PackToAtlas( pixelDataContainer, textureRects  );
+
+ // --------------
+ // |            |
+ // |    45*30   |
+//  |            |
+//  --------------
+//  | 20 |    | 20*20
+//  |  * |____|
+//  | 30 |  |  10*10
+//  --------
+
+  DALI_TEST_EQUALS( texture.GetWidth(), 45, TEST_LOCATION );
+  DALI_TEST_EQUALS( texture.GetHeight(), 60, TEST_LOCATION );
+
+  Rect<int> pixelArea = TextureCoordinateToPixelArea(textureRects[0], texture.GetWidth(), texture.GetHeight());
+  DALI_TEST_EQUALS( pixelArea.x, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.y, 30, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.width, 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.height, 30, TEST_LOCATION );
+
+  pixelArea = TextureCoordinateToPixelArea(textureRects[1], texture.GetWidth(), texture.GetHeight());
+  DALI_TEST_EQUALS( pixelArea.x, 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.y, 50, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.width, 10, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.height, 10, TEST_LOCATION );
+
+  pixelArea = TextureCoordinateToPixelArea(textureRects[2], texture.GetWidth(), texture.GetHeight());
+  DALI_TEST_EQUALS( pixelArea.x, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.y, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.width, 45, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.height, 30, TEST_LOCATION );
+
+  pixelArea = TextureCoordinateToPixelArea(textureRects[3], texture.GetWidth(), texture.GetHeight());
+  DALI_TEST_EQUALS( pixelArea.x, 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.y, 30, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.width, 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelArea.height, 20, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
new file mode 100644 (file)
index 0000000..bd74fdb
--- /dev/null
@@ -0,0 +1,2652 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+#include <test-native-image.h>
+#include <sstream>
+#include <unistd.h>
+
+
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_image_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_image_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = aPosition + vec2(0.5);\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+  }\n
+);
+
+const char* TEST_IMAGE_FILE_NAME =  "gallery_image_01.jpg";
+const char* TEST_IMAGE_FILE_NAME2 =  "gallery_image_02.jpg";
+
+const char* TEST_IMAGE_1 = TEST_RESOURCE_DIR "/TB-gloss.png";
+const char* TEST_IMAGE_2 = TEST_RESOURCE_DIR "/tb-norm.png";
+
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 600*600, pixel format: RGB888
+static const char* gImage_600_RGB = TEST_RESOURCE_DIR "/test-image-600.jpg";
+
+// resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+
+void TestImage( ImageView imageView, BufferImage image )
+{
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  Property::Map map;
+  DALI_TEST_CHECK( value.Get( map ) );
+
+  DALI_TEST_CHECK( map.Find( "width" ) );
+  DALI_TEST_CHECK( map.Find( "height" ) );
+  DALI_TEST_CHECK( map.Find( "type" ) );
+
+  int width = 0;
+  DALI_TEST_CHECK( map[ "width" ].Get( width ) );
+  DALI_TEST_EQUALS( (unsigned int)width, image.GetWidth(), TEST_LOCATION );
+
+  int height = 0;
+  DALI_TEST_CHECK( map[ "height" ].Get( height ) );
+  DALI_TEST_EQUALS( (unsigned int)height, image.GetHeight(), TEST_LOCATION );
+
+  std::string type;
+  DALI_TEST_CHECK( map[ "type" ].Get( type ) );
+  DALI_TEST_EQUALS( type, "BufferImage", TEST_LOCATION );
+}
+
+void TestImage( ImageView imageView, ResourceImage image )
+{
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  Property::Map map;
+  DALI_TEST_CHECK( value.Get( map ) );
+
+  if( map.Find( "width" ) )
+  {
+    int width = 0;
+    DALI_TEST_CHECK( map[ "width" ].Get( width ) );
+    DALI_TEST_EQUALS( (unsigned int)width, image.GetWidth(), TEST_LOCATION );
+  }
+
+  if( map.Find( "height" ) )
+  {
+    int height = 0;
+    DALI_TEST_CHECK( map[ "height" ].Get( height ) );
+    DALI_TEST_EQUALS( (unsigned int)height, image.GetHeight(), TEST_LOCATION );
+  }
+
+  DALI_TEST_CHECK( map.Find( "type" ) );
+
+  std::string type;
+  DALI_TEST_CHECK( map[ "type" ].Get( type ) );
+  DALI_TEST_EQUALS( type, "ResourceImage", TEST_LOCATION );
+
+  std::string filename;
+  DALI_TEST_CHECK( map[ "filename" ].Get( filename ) );
+  DALI_TEST_EQUALS( filename, image.GetUrl(), TEST_LOCATION );
+}
+
+void TestUrl( ImageView imageView, const std::string url )
+{
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  std::string urlActual;
+  DALI_TEST_CHECK( value.Get( urlActual ) );
+  DALI_TEST_EQUALS( urlActual, url, TEST_LOCATION );
+}
+
+} // namespace
+
+int UtcDaliImageViewNewP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  DALI_TEST_CHECK( imageView );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewNewImageP(void)
+{
+  ToolkitTestApplication application;
+
+  BufferImage image = CreateBufferImage( 100, 200, Vector4( 1.f, 1.f, 1.f, 1.f ) );
+  ImageView imageView = ImageView::New( image );
+
+  DALI_TEST_CHECK( imageView );
+  TestImage( imageView, image );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewNewUrlP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New( TEST_IMAGE_FILE_NAME );
+  DALI_TEST_CHECK( imageView );
+
+  TestUrl( imageView, TEST_IMAGE_FILE_NAME );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView;
+
+  DALI_TEST_CHECK( !imageView );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Initialize an object, ref count == 1
+  ImageView imageView = ImageView::New();
+
+  ImageView copy( imageView );
+  DALI_TEST_CHECK( copy );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  ImageView copy( imageView );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_EQUALS( imageView, copy, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewDownCastP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  BaseHandle object(imageView);
+
+  ImageView imageView2 = ImageView::DownCast( object );
+  DALI_TEST_CHECK(imageView2);
+
+  ImageView imageView3 = DownCast< ImageView >( object );
+  DALI_TEST_CHECK(imageView3);
+
+  END_TEST;
+}
+
+int UtcDaliImageViewDownCastN(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle unInitializedObject;
+
+  ImageView imageView1 = ImageView::DownCast( unInitializedObject );
+  DALI_TEST_CHECK( !imageView1 );
+
+  ImageView imageView2 = DownCast< ImageView >( unInitializedObject );
+  DALI_TEST_CHECK( !imageView2 );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "ImageView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  ImageView imageView = ImageView::DownCast( handle );
+  DALI_TEST_CHECK( imageView );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetGetProperty01(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  Property::Index idx = imageView.GetPropertyIndex( "image" );
+  DALI_TEST_EQUALS( idx, (Property::Index)ImageView::Property::IMAGE, TEST_LOCATION );
+
+  imageView.SetProperty( idx, TEST_IMAGE_FILE_NAME );
+  TestUrl( imageView, TEST_IMAGE_FILE_NAME );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetGetProperty02(void)
+{
+  ToolkitTestApplication application;
+
+  Image image = CreateBufferImage( 10, 10, Color::WHITE );
+  ImageView imageView = ImageView::New(image);
+  Vector4 fullImageRect( 0.f, 0.f, 1.f, 1.f );
+
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelAreaUniform, fullImageRect, TEST_LOCATION );
+
+  Property::Value value = imageView.GetProperty( ImageView::Property::PIXEL_AREA );
+  Vector4 pixelAreaValue;
+  DALI_TEST_CHECK( value.Get(pixelAreaValue) );
+  DALI_TEST_EQUALS( pixelAreaValue, fullImageRect, TEST_LOCATION );
+
+  Vector4 pixelAreaSet( 0.2f, 0.2f, 0.3f, 0.3f );
+  imageView.SetProperty( ImageView::Property::PIXEL_AREA, pixelAreaSet);
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView.GetProperty( ImageView::Property::PIXEL_AREA );
+  value.Get(pixelAreaValue);
+  DALI_TEST_EQUALS( pixelAreaValue, pixelAreaSet, TEST_LOCATION );
+
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelAreaUniform, pixelAreaSet, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetGetProperty03(void)
+{
+  ToolkitTestApplication application;
+
+  Image image = CreateBufferImage( 10, 10, Color::WHITE );
+  ImageView imageView = ImageView::New(image);
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  // conventional alpha blending
+  Renderer renderer = imageView.GetRendererAt( 0 );
+  Property::Value value = renderer.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  bool enable;
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  // pre-multiplied alpha blending
+  imageView.SetProperty( Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA, true );
+  application.SendNotification();
+  application.Render();
+
+  int srcFactorRgb    = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  int destFactorRgb   = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  int srcFactorAlpha  = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  int destFactorAlpha = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  value = renderer.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPreMultipliedAlphaPng(void)
+{
+  ToolkitTestApplication application;
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable( true );
+
+  Property::Map imageMap;
+  imageMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap[ ImageVisual::Property::RELEASE_POLICY] = ImageVisual::ReleasePolicy::NEVER;   // To keep the texture cache
+
+  ImageView imageView1 = ImageView::New();
+  imageView1.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  Stage::GetCurrent().Add( imageView1 );
+
+  Property::Value value = imageView1.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  bool enable;
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );    // Default value is true
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView1.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );    // Keep true
+
+  // conventional alpha blending
+  Renderer renderer1 = imageView1.GetRendererAt( 0 );
+  value = renderer1.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );
+
+  int srcFactorRgb    = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  int destFactorRgb   = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  int srcFactorAlpha  = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  int destFactorAlpha = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );  // A new texture should be generated.
+  textureTrace.Reset();
+
+  // Disable pre-multiplied alpha blending
+  imageView1.SetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA, false );
+
+  // Reload the image
+  Property::Map attributes;
+  DevelControl::DoAction( imageView1, ImageView::Property::IMAGE, DevelImageVisual::Action::RELOAD, attributes );
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView1.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  // conventional alpha blending
+  value = renderer1.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  srcFactorRgb    = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  destFactorRgb   = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  srcFactorAlpha  = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  destFactorAlpha = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::SRC_ALPHA );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );  // A new texture should be generated.
+  textureTrace.Reset();
+
+  // Make a new ImageView using the same image
+  ImageView imageView2 = ImageView::New();
+  imageView2.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  Stage::GetCurrent().Add( imageView2 );
+
+  application.SendNotification();
+  application.Render();
+
+  Renderer renderer2 = imageView2.GetRendererAt( 0 );
+  value = renderer2.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );
+
+  srcFactorRgb    = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  destFactorRgb   = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  srcFactorAlpha  = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  destFactorAlpha = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); // The cached texture should be used.
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPreMultipliedAlphaJpg(void)
+{
+  ToolkitTestApplication application;
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable( true );
+
+  Property::Map imageMap;
+  imageMap[ ImageVisual::Property::URL ] = gImage_600_RGB;
+  imageMap[ ImageVisual::Property::RELEASE_POLICY] = ImageVisual::ReleasePolicy::NEVER;   // To keep the texture cache
+
+  ImageView imageView1 = ImageView::New();
+  imageView1.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  Stage::GetCurrent().Add( imageView1 );
+
+  Property::Value value = imageView1.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  bool enable;
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( enable );    // Default value is true
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView1.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );    // Should be false after loading
+
+  // conventional alpha blending
+  Renderer renderer1 = imageView1.GetRendererAt( 0 );
+  value = renderer1.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  int srcFactorRgb    = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  int destFactorRgb   = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  int srcFactorAlpha  = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  int destFactorAlpha = renderer1.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::SRC_ALPHA );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );  // A new texture should be generated.
+  textureTrace.Reset();
+
+  ImageView imageView2 = ImageView::New();
+  imageView2.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  // Disable pre-multiplied alpha blending
+  imageView2.SetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA, false );
+
+  Stage::GetCurrent().Add( imageView2 );
+
+  application.SendNotification();
+  application.Render();
+
+  value = imageView2.GetProperty( ImageView::Property::PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  // conventional alpha blending
+  Renderer renderer2 = imageView2.GetRendererAt( 0 );
+  value = renderer2.GetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_CHECK( value.Get( enable ) );
+  DALI_TEST_CHECK( !enable );
+
+  srcFactorRgb    = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  destFactorRgb   = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  srcFactorAlpha  = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  destFactorAlpha = renderer2.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::SRC_ALPHA );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION ); // The cached texture should be used.
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPixelArea(void)
+{
+  // Test pixel area property
+  ToolkitTestApplication application;
+
+  // Gif image, use AnimatedImageVisual internally
+  // Atlasing is applied to pack multiple frames, use custom wrap mode
+  ImageView gifView = ImageView::New();
+  const Vector4 pixelAreaVisual( 0.f, 0.f, 2.f, 2.f );
+  gifView.SetProperty( ImageView::Property::IMAGE,
+                       Property::Map().Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME )
+                                      .Add( ImageVisual::Property::PIXEL_AREA, pixelAreaVisual ) );
+
+  // Add to stage
+  Stage stage = Stage::GetCurrent();
+  stage.Add( gifView );
+
+  // loading started
+  application.SendNotification();
+  application.Render(16);
+  DALI_TEST_CHECK( gifView.GetRendererCount() == 1u );
+
+  const Vector4 fullTextureRect( 0.f, 0.f, 1.f, 1.f );
+  // test that the pixel area value defined in the visual property map is registered on renderer
+  Renderer renderer = gifView.GetRendererAt(0);
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelAreaVisual, TEST_LOCATION );
+
+  // test that the shader has the default pixel area value registered.
+  Shader shader = renderer.GetShader();
+  pixelAreaValue = shader.GetProperty( shader.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), fullTextureRect, TEST_LOCATION );
+
+  // test that the uniform uses the pixelArea property on the renderer.
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelAreaVisual, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  // set the pixelArea property on the control
+  const Vector4 pixelAreaControl( -1.f, -1.f, 3.f, 3.f );
+  gifView.SetProperty( ImageView::Property::PIXEL_AREA, pixelAreaControl );
+  application.SendNotification();
+  application.Render(16);
+
+  // check the pixelArea property on the control
+  pixelAreaValue = gifView.GetProperty( gifView.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelAreaControl, TEST_LOCATION );
+  // test that the uniform uses the pixelArea property on the control.
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelAreaControl, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliImageViewAsyncLoadingWithoutAltasing(void)
+{
+  ToolkitTestApplication application;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  const std::vector<GLuint>& textures = gl.GetBoundTextures();
+  size_t numTextures = textures.size();
+
+  // Async loading, no atlasing for big size image
+  ImageView imageView = ImageView::New( gImage_600_RGB );
+
+  // By default, Aysnc loading is used
+  Stage::GetCurrent().Add( imageView );
+  imageView.SetSize(100, 100);
+  imageView.SetParentOrigin( ParentOrigin::CENTER );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+  application.SendNotification();
+
+  const std::vector<GLuint>& textures2 = gl.GetBoundTextures();
+  DALI_TEST_GREATER( textures2.size(), numTextures, TEST_LOCATION );
+
+
+
+  END_TEST;
+}
+
+int UtcDaliImageViewAsyncLoadingWithAtlasing(void)
+{
+  ToolkitTestApplication application;
+
+  //Async loading, automatic atlasing for small size image
+  TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+  callStack.Reset();
+  callStack.Enable(true);
+
+  Property::Map imageMap;
+
+  imageMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 34;
+  imageMap[ ImageVisual::Property::DESIRED_WIDTH ] = 34;
+  imageMap[ ImageVisual::Property::ATLASING] = true;
+
+  ImageView imageView = ImageView::New();
+  imageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+  imageView.SetProperty( Toolkit::Control::Property::PADDING, Extents( 10u, 10u, 10u, 10u ) );
+
+  // By default, Aysnc loading is used
+  // loading is not started if the actor is offStage
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+  application.Render(16);
+  application.SendNotification();
+
+  imageView.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,  Dali::LayoutDirection::RIGHT_TO_LEFT );
+  application.SendNotification();
+  application.Render(16);
+  application.Render(16);
+  application.SendNotification();
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  callStack.Enable(false);
+
+  TraceCallStack::NamedParams params;
+  params["width"] = ToString(34);
+  params["height"] = ToString(34);
+  DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewAsyncLoadingWithAtlasing02(void)
+{
+  ToolkitTestApplication application;
+
+  //Async loading, automatic atlasing for small size image
+  TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+  callStack.Reset();
+  callStack.Enable(true);
+
+  Property::Map asyncLoadingMap;
+  asyncLoadingMap[ "url" ] = gImage_34_RGBA;
+  asyncLoadingMap[ "desiredHeight" ] = 34;
+  asyncLoadingMap[ "desiredWidth" ] = 34;
+  asyncLoadingMap[ "synchronousLoading" ] = false;
+  asyncLoadingMap[ "atlasing" ] = true;
+
+  ImageView imageView = ImageView::New();
+  imageView.SetProperty( ImageView::Property::IMAGE, asyncLoadingMap );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render(16);
+  application.Render(16);
+  application.SendNotification();
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  callStack.Enable(false);
+
+  TraceCallStack::NamedParams params;
+  params["width"] = ToString(34);
+  params["height"] = ToString(34);
+  DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSyncLoading(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing sync loading and size using index key property map");
+
+  Property::Map syncLoadingMap;
+  syncLoadingMap[ ImageVisual::Property::SYNCHRONOUS_LOADING ] = true;
+  syncLoadingMap[ ImageVisual::Property::ATLASING ] = true;
+
+  // Sync loading, no atlasing for big size image
+  {
+    ImageView imageView = ImageView::New();
+
+    // Sync loading is used
+    syncLoadingMap[ ImageVisual::Property::URL ] = gImage_600_RGB;
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+  }
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+
+    // Sync loading is used
+    syncLoadingMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+    syncLoadingMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 34;
+    syncLoadingMap[ ImageVisual::Property::DESIRED_WIDTH ] = 34;
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    Stage::GetCurrent().Add( imageView );
+    application.SendNotification();
+    application.Render(16);
+
+    TraceCallStack::NamedParams params;
+    params["width"] = ToString(34);
+    params["height"] = ToString(34);
+    DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ),
+                      true, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliImageViewSyncLoading02(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing sync loading and size using string key property map");
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+
+    // Sync loading is used
+    Property::Map syncLoadingMap;
+    syncLoadingMap[ "url" ] = gImage_34_RGBA;
+    syncLoadingMap[ "desiredHeight" ] = 34;
+    syncLoadingMap[ "desiredWidth" ] = 34;
+    syncLoadingMap[ "synchronousLoading" ] = true;
+    syncLoadingMap[ "atlasing" ] = true;
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    Stage::GetCurrent().Add( imageView );
+    application.SendNotification();
+    application.Render(16);
+
+    TraceCallStack::NamedParams params;
+    params["width"] = ToString(34);
+    params["height"] = ToString(34);
+    DALI_TEST_EQUALS( callStack.FindMethodAndParams( "TexSubImage2D", params ),
+                      true, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliImageViewAddedTexture(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing image view with texture provided manager url");
+
+  ImageView imageView = ImageView::New();
+
+  // empty texture is ok, though pointless from app point of view
+  TextureSet  empty;
+  std::string url = TextureManager::AddTexture(empty);
+  DALI_TEST_CHECK(url.size() > 0u);
+
+  Property::Map propertyMap;
+  propertyMap[ImageVisual::Property::URL] = url;
+  imageView.SetProperty(ImageView::Property::IMAGE, propertyMap);
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSizeWithBackground(void)
+{
+  ToolkitTestApplication application;
+
+  int width = 100;
+  int height = 200;
+  ImageView imageView = ImageView::New();
+
+  imageView.SetProperty( Control::Property::BACKGROUND,
+                         {
+                           { Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE },
+                           { Toolkit::ImageVisual::Property::URL, TEST_RESOURCE_DIR "/gallery-small-1.jpg" },
+                           { ImageVisual::Property::DESIRED_WIDTH, width },
+                           { ImageVisual::Property::DESIRED_HEIGHT, height },
+                         }
+                       );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetCurrentSize().width, (float)width, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageView.GetCurrentSize().height, (float)height, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSizeWithBackgroundAndImage(void)
+{
+  ToolkitTestApplication application;
+
+  int widthBackground = 100;
+  int heightBackground = 200;
+  int width = 300;
+  int height = 400;
+  Image image = CreateBufferImage( width, height, Vector4(1.f, 1.f, 1.f, 1.f) );
+
+  ImageView imageView = ImageView::New();
+
+  imageView.SetProperty( Control::Property::BACKGROUND,
+                         {
+                           { Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE },
+                           { Toolkit::ImageVisual::Property::URL, TEST_RESOURCE_DIR "/gallery-small-1.jpg" },
+                           { ImageVisual::Property::DESIRED_WIDTH, widthBackground },
+                           { ImageVisual::Property::DESIRED_HEIGHT, heightBackground },
+                          }
+                       );
+
+  imageView.SetImage( image );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetCurrentSize().width, (float)width, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageView.GetCurrentSize().height, (float)height, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewHeightForWidthBackground(void)
+{
+  ToolkitTestApplication application;
+
+  int widthBackground = 100;
+  int heightBackground = 200;
+
+  ImageView imageView = ImageView::New();
+
+  imageView.SetProperty( Control::Property::BACKGROUND,
+                         {
+                           { Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE },
+                           { Toolkit::ImageVisual::Property::URL, TEST_RESOURCE_DIR "/gallery-small-1.jpg" },
+                           { ImageVisual::Property::DESIRED_WIDTH, widthBackground },
+                           { ImageVisual::Property::DESIRED_HEIGHT, heightBackground }
+                         }
+                       );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  Control control = Control::DownCast( imageView );
+  DALI_TEST_CHECK( control );
+  DALI_TEST_EQUALS( imageView.GetHeightForWidth( 123.f ), control.GetHeightForWidth( 123.f ), TEST_LOCATION );
+  DALI_TEST_EQUALS( imageView.GetWidthForHeight( 321.f ), control.GetWidthForHeight( 321.f ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewHeightForWidthBackgroundAndImage(void)
+{
+  ToolkitTestApplication application;
+
+  int widthBackground = 100;
+  int heightBackground = 200;
+  int width = 300;
+  int height = 400;
+
+  Image image = CreateBufferImage( width, height, Vector4(1.f, 1.f, 1.f, 1.f) );
+
+  ImageView imageView = ImageView::New();
+
+  imageView.SetProperty( Control::Property::BACKGROUND,
+                         {
+                           { Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE },
+                           { Toolkit::ImageVisual::Property::URL, TEST_RESOURCE_DIR "/gallery-small-1.jpg" },
+                           { ImageVisual::Property::DESIRED_WIDTH, widthBackground },
+                           { ImageVisual::Property::DESIRED_HEIGHT, heightBackground }
+                         }
+                       );
+
+  imageView.SetImage( image );
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetHeightForWidth( width ), (float)height, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageView.GetWidthForHeight( height ), (float)width, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetBufferImage(void)
+{
+  ToolkitTestApplication application;
+
+  int width1 = 300;
+  int height1 = 400;
+  BufferImage image1 = CreateBufferImage( width1, height1, Vector4( 1.f, 1.f, 1.f, 1.f ) );
+  ImageView imageView = ImageView::New();
+  imageView.SetImage( image1 );
+
+  TestImage( imageView, image1 );
+
+  int width2 = 600;
+  int height2 = 500;
+  BufferImage image2 = CreateBufferImage( width2, height2, Vector4( 1.f, 1.f, 1.f, 1.f ) );
+  imageView.SetImage( image2 );
+
+  TestImage( imageView, image2 );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageUrl(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  imageView.SetImage( TEST_IMAGE_FILE_NAME );
+  TestUrl( imageView, TEST_IMAGE_FILE_NAME );
+
+
+  imageView.SetImage( TEST_IMAGE_FILE_NAME2 );
+  TestUrl( imageView, TEST_IMAGE_FILE_NAME2 );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageOnstageP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  ResourceImage image1 = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetImage( image1 );
+  TestImage( imageView, image1 );
+
+  int width = 300;
+  int height = 400;
+  BufferImage image2 = CreateBufferImage( width, height, Vector4( 1.f, 1.f, 1.f, 1.f ) );
+  imageView.SetImage( image2 );
+  TestImage( imageView, image2 );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageOnstageN(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+
+  ResourceImage image1 = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetImage( image1 );
+  TestImage( imageView, image1 );
+
+  Image image2;
+  imageView.SetImage( image2 );
+
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  //the value should be empty
+  std::string url;
+  DALI_TEST_CHECK( !value.Get( url ) );
+
+  Property::Map map;
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageOffstageP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+  Stage::GetCurrent().Remove( imageView );
+
+  ResourceImage image1 = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetImage( image1 );
+  TestImage( imageView, image1 );
+
+  int width = 300;
+  int height = 400;
+  BufferImage image2 = CreateBufferImage( width, height, Vector4( 1.f, 1.f, 1.f, 1.f ) );
+  imageView.SetImage( image2 );
+  TestImage( imageView, image2 );
+
+  END_TEST;
+}
+
+bool gResourceReadySignalFired = false;
+Vector3 gNaturalSize;
+
+void ResourceReadySignal( Control control )
+{
+  gResourceReadySignalFired = true;
+}
+
+int UtcDaliImageViewCheckResourceReady(void)
+{
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+  // Check ImageView with background and main image, to ensure both visuals are marked as loaded
+  ImageView imageView = ImageView::New( TEST_GIF_FILE_NAME );
+
+  imageView.SetProperty( Control::Property::BACKGROUND,
+                         {
+                           { Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE },
+                           { Toolkit::ImageVisual::Property::URL, TEST_RESOURCE_DIR "/gallery-small-1.jpg" },
+                           { ImageVisual::Property::DESIRED_WIDTH, 100 },
+                           { ImageVisual::Property::DESIRED_HEIGHT, 200 }
+                          }
+                       );
+
+  DALI_TEST_EQUALS( imageView.IsResourceReady(), false, TEST_LOCATION );
+
+  imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+  Stage::GetCurrent().Add( imageView );
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageOffstageN(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+
+  Stage::GetCurrent().Add( imageView );
+  application.SendNotification();
+  application.Render();
+  Stage::GetCurrent().Remove( imageView );
+
+  ResourceImage image1 = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetImage( image1 );
+  TestImage( imageView, image1 );
+
+  Image image2;
+  imageView.SetImage( image2 );
+
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  //the value should be empty
+  std::string url;
+  DALI_TEST_CHECK( !value.Get( url ) );
+
+  Property::Map map;
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageN(void)
+{
+  ToolkitTestApplication application;
+
+  Image image1;
+  ImageView imageView = ImageView::New();
+  imageView.SetImage( image1 );
+
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+
+  //the value should be empty
+  std::string url;
+  DALI_TEST_CHECK( !value.Get( url ) );
+
+  Property::Map map;
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );
+
+  std::string resource_url;
+  Property::Value val = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  DALI_TEST_CHECK( !val.Get( resource_url ) );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSetImageTypeChangesP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+
+  Stage::GetCurrent().Add( imageView );
+
+  std::string url;
+  Property::Map map;
+  Toolkit::Visual::Base visual;
+
+  Property::Value value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );        // Value should be empty
+  DALI_TEST_CHECK( ! visual );           // Visual should be invalid
+
+  // Set a URL
+  imageView.SetImage( "TEST_URL" );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( value.Get( url ) );   // Value should NOT be empty
+  DALI_TEST_CHECK( ! value.Get( map ) ); // Value should be empty
+  DALI_TEST_CHECK( visual );             // Visual should be valid
+
+  // Set an empty Image
+  imageView.SetImage( Image() );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );        // Value should be empty
+  DALI_TEST_CHECK( ! visual );           // Visual should be invalid
+
+  // Set an Image
+  ResourceImage image1 = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+  imageView.SetImage( image1 );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  DALI_TEST_CHECK( value.Get( map ) );   // Value should NOT be empty
+  DALI_TEST_CHECK( visual );             // Visual should be valid
+
+  // Set an empty URL
+  imageView.SetImage( "" );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  value.Get( map );
+  DALI_TEST_CHECK( map.Empty() );        // Value should be empty
+  DALI_TEST_CHECK( ! visual );           // Visual should be invalid
+
+  // Set a URL in property map
+  Property::Map propertyMap;
+  propertyMap[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+  imageView.SetProperty( ImageView::Property::IMAGE, propertyMap );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  DALI_TEST_CHECK( value.Get( map ) );   // Value should NOT be empty
+  DALI_TEST_CHECK( visual );             // Visual should be valid
+
+  // Set a URL in property map again
+  propertyMap[ImageVisual::Property::URL] = gImage_34_RGBA;
+  imageView.SetProperty( ImageView::Property::IMAGE, propertyMap );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  DALI_TEST_CHECK( value.Get( map ) );   // Value should NOT be empty
+  DALI_TEST_CHECK( visual );             // Visual should be valid
+
+  // Set an empty URL in property map
+  propertyMap[ImageVisual::Property::URL] = std::string();
+  imageView.SetProperty( ImageView::Property::IMAGE, propertyMap );
+
+  application.SendNotification();
+  application.Render( 16 );
+
+  value = imageView.GetProperty( imageView.GetPropertyIndex( "image" ) );
+  visual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+
+  DALI_TEST_CHECK( ! value.Get( url ) ); // Value should be empty
+  DALI_TEST_CHECK( value.Get( map ) );   // Value should NOT be empty
+  DALI_TEST_CHECK( ! visual );           // Visual should be invalid
+
+  END_TEST;
+}
+
+int UtcDaliImageViewResourceUrlP(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  DALI_TEST_CHECK( imageView.GetProperty( ImageView::Property::IMAGE ).Get< std::string >().empty() );
+
+  imageView.SetProperty( ImageView::Property::IMAGE, "TestString" );
+  DALI_TEST_EQUALS( imageView.GetProperty( ImageView::Property::IMAGE ).Get< std::string >(), "TestString", TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Scenarios 1: ImageView from regular image
+int UtcDaliImageViewSetImageBufferImage(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  int width = 300;
+  int height = 400;
+  BufferImage image = CreateBufferImage( width, height, Color::WHITE );
+
+  imageView.SetImage( image );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_2D << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  END_TEST;
+}
+
+// Scenarios 2: ImageView from Native image
+int UtcDaliImageViewSetImageNativeImage(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  int width = 200;
+  int height = 500;
+  TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height );
+  NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) );
+
+  imageView.SetImage( nativeImage );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_EXTERNAL_OES << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  END_TEST;
+}
+
+// Scenarios 3: ImageView initially from regular image but then SetImage called with Native image
+int UtcDaliImageViewSetImageBufferImageToNativeImage(void)
+{
+  ToolkitTestApplication application;
+
+  int width = 300;
+  int height = 400;
+  BufferImage image = CreateBufferImage( width, height, Color::WHITE );
+
+  ImageView imageView = ImageView::New( image );
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_2D << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  width = 200;
+  height = 500;
+  TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height );
+  NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) );
+  imageView.SetImage( nativeImage );
+
+  ids.clear();
+  ids.push_back( 24 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream nextTextureParams;
+  nextTextureParams << GL_TEXTURE_EXTERNAL_OES << ", " << 24;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nextTextureParams.str()) );
+
+  END_TEST;
+}
+
+// Scenarios 4: ImageView initially from Native image but then SetImage called with regular image
+int UtcDaliImageViewSetImageNativeImageToBufferImage(void)
+{
+  ToolkitTestApplication application;
+
+  int width = 300;
+  int height = 400;
+  TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height );
+  NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) );
+
+  ImageView imageView = ImageView::New( nativeImage );
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_EXTERNAL_OES << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  width = 200;
+  height = 500;
+  BufferImage image = CreateBufferImage( width, height, Color::WHITE );
+  imageView.SetImage( image );
+
+  ids.clear();
+  ids.push_back( 24 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream nextTextureParams;
+  nextTextureParams << GL_TEXTURE_2D << ", " << 24;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nextTextureParams.str()) );
+
+  END_TEST;
+}
+
+// Scenarios 5: ImageView from Native image with custom shader
+int UtcDaliImageViewSetImageNativeImageWithCustomShader(void)
+{
+  ToolkitTestApplication application;
+
+  int width = 300;
+  int height = 400;
+
+  Property::Map customShader;
+  customShader.Insert( "vertexShader", VERTEX_SHADER );
+  customShader.Insert( "fragmentShader", FRAGMENT_SHADER );
+
+  Property::Array shaderHints;
+  shaderHints.PushBack( "requiresSelfDepthTest" );
+  shaderHints.PushBack( "outputIsTransparent" );
+  shaderHints.PushBack( "outputIsOpaque" );
+  shaderHints.PushBack( "modifiesGeometry" );
+
+  customShader.Insert( "hints", shaderHints );
+
+  Property::Map map;
+  map.Insert( "shader", customShader );
+
+  TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height );
+  NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) );
+
+  ImageView imageView = ImageView::New( nativeImage );
+  imageView.SetProperty( ImageView::Property::IMAGE, map );
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_EXTERNAL_OES << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  END_TEST;
+}
+
+// Scenarios 6: ImageView initially from regular image with custom shader but then SetImage called with Native
+int UtcDaliImageViewSetImageBufferImageWithCustomShaderToNativeImage(void)
+{
+  ToolkitTestApplication application;
+
+  int width = 300;
+  int height = 400;
+
+  Property::Map customShader;
+  customShader.Insert( "vertexShader", VERTEX_SHADER );
+  customShader.Insert( "fragmentShader", FRAGMENT_SHADER );
+
+  Property::Array shaderHints;
+  shaderHints.PushBack( "requiresSelfDepthTest" );
+  shaderHints.PushBack( "outputIsTransparent" );
+  shaderHints.PushBack( "outputIsOpaque" );
+  shaderHints.PushBack( "modifiesGeometry" );
+
+  customShader.Insert( "hints", shaderHints );
+
+  Property::Map map;
+  map.Insert( "shader", customShader );
+
+  BufferImage image = CreateBufferImage( width, height, Color::WHITE );
+
+  ImageView imageView = ImageView::New( image );
+  imageView.SetProperty( ImageView::Property::IMAGE, map );
+  Stage::GetCurrent().Add( imageView );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  gl.EnableTextureCallTrace( true );
+
+  std::vector< GLuint > ids;
+  ids.push_back( 23 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream params;
+  params << GL_TEXTURE_2D << ", " << 23;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", params.str()) );
+
+  TestNativeImagePointer nativeImageInterface = TestNativeImage::New( width, height );
+  NativeImage nativeImage = NativeImage::New( *(nativeImageInterface.Get()) );
+  imageView.SetImage( nativeImage );
+
+  ids.clear();
+  ids.push_back( 24 );
+  application.GetGlAbstraction().SetNextTextureIds( ids );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethod("BindTexture") );
+
+  std::stringstream nativeImageParams;
+  nativeImageParams << GL_TEXTURE_EXTERNAL_OES << ", " << 24;
+  DALI_TEST_CHECK( gl.GetTextureTrace().FindMethodAndParams("BindTexture", nativeImageParams.str()) );
+
+
+  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;
+}
+
+
+int UtcDaliImageViewReplaceImage(void)
+{
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+  int width = 100;
+  int height = 200;
+  Image image = CreateBufferImage( width, height, Vector4(1.f, 1.f, 1.f, 1.f) );
+
+  // Check ImageView with background and main image, to ensure both visuals are marked as loaded
+  ImageView imageView = ImageView::New( TEST_IMAGE_1 );
+
+  DALI_TEST_EQUALS( imageView.IsResourceReady(), false, TEST_LOCATION );
+
+  imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render(16);
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( imageView.GetRendererCount(), 1u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  gResourceReadySignalFired = false;
+
+  imageView.SetImage(TEST_IMAGE_2);
+
+  application.SendNotification();
+  application.Render(16);
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( imageView.GetRendererCount(), 1u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+void OnRelayoutOverride( Size size )
+{
+  gNaturalSize = size; // Size Relayout is using
+}
+
+int UtcDaliImageViewReplaceImageAndGetNaturalSize(void)
+{
+  ToolkitTestApplication application;
+
+  // Check ImageView with background and main image, to ensure both visuals are marked as loaded
+  ImageView imageView = ImageView::New( TEST_IMAGE_1 );
+  imageView.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+  DummyControl dummyControl = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyControl.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+
+  dummyControl.Add( imageView );
+  dummyImpl.SetRelayoutCallback( &OnRelayoutOverride );
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gNaturalSize.width, 1024.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( gNaturalSize.height, 1024.0f, TEST_LOCATION );
+
+  gNaturalSize = Vector3::ZERO;
+
+  imageView.SetImage(gImage_600_RGB);
+
+  // Waiting for resourceReady so SendNotifcation not called here.
+
+  // loading started, this waits for the loader thread for max 30 seconds
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // Trigger a potential relayout
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gNaturalSize.width, 600.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( gNaturalSize.height, 600.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewResourceReadySignalWithImmediateLoad(void)
+{
+  tet_infoline("Test Setting Image with IMMEDIATE load and receving ResourceReadySignal before staged.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+  Property::Map imageMap;
+
+  imageMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap[ ImageVisual::Property::LOAD_POLICY ] =  ImageVisual::LoadPolicy::IMMEDIATE;
+
+  tet_infoline("Creating ImageView without URL so image does not start loading");
+  ImageView imageView = ImageView::New();
+  tet_infoline("Connect to image loaded signal before setting image");
+  imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+  tet_infoline("Setting Image with IMMEDIATE load, signal already connected so will be triggered.");
+  imageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewResourceReadySignalWithReusedImage(void)
+{
+  tet_infoline("Test Setting Image that was already loaded by another ImageView and still getting ResourceReadySignal.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+  Property::Map imageMap;
+
+  imageMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap[ ImageVisual::Property::LOAD_POLICY ] =  ImageVisual::LoadPolicy::IMMEDIATE;
+
+  ImageView imageView = ImageView::New();
+  imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+  imageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+  gResourceReadySignalFired = false;
+
+  ImageView imageViewWithExistingImage = ImageView::New();
+  imageViewWithExistingImage.ResourceReadySignal().Connect( &ResourceReadySignal);
+  imageViewWithExistingImage.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewResourceReadySignalWithReusedImage02(void)
+{
+  tet_infoline("Test Setting Image that was already loaded by another ImageView and still getting ResourceReadySignal when staged.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalFired = false;
+
+  Property::Map imageImmediateLoadingMap;
+  imageImmediateLoadingMap[ ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageImmediateLoadingMap[ ImageVisual::Property::LOAD_POLICY ] =  ImageVisual::LoadPolicy::IMMEDIATE;
+
+  tet_infoline("Immediate load an image");
+  ImageView imageView = ImageView::New();
+  imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+  imageView.SetProperty( ImageView::Property::IMAGE, imageImmediateLoadingMap );
+
+  // loading started, this waits for the loader thread
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(16);
+
+  tet_infoline("Check image loaded");
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+  gResourceReadySignalFired = false;
+
+  tet_infoline("Create another ImageView with the same URL");
+  ImageView imageViewWithExistingImage = ImageView::New( gImage_34_RGBA );
+  tet_infoline("Connect to ResourceReady signal for second ImageView, it should still fire as resource is ready");
+  imageViewWithExistingImage.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+  Stage::GetCurrent().Add( imageViewWithExistingImage );
+
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPaddingProperty(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Property::Map imagePropertyMap;
+  imagePropertyMap[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::IMAGE;
+  imagePropertyMap[ Toolkit::ImageVisual::Property::URL ] = TEST_RESOURCE_DIR "/gallery-small-1.jpg" ;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_WIDTH ] = 128;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 128;
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE , imagePropertyMap );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  imageView.SetProperty( Control::Property::PADDING, Extents( 15, 10, 5, 10 ) );
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetProperty<Extents>( Control::Property::PADDING ), Extents( 15, 10, 5, 10 ), TEST_LOCATION );
+
+  ImageView childImage = ImageView::New();
+  childImage.SetBackgroundColor( Color::BLACK );
+  childImage.SetSize( 10.f, 10.f );
+  imageView.Add( childImage );
+
+  application.SendNotification();
+  application.Render();
+
+  // Child ImageView should be positioned dependinig on Parent ImageView's Padding value
+  DALI_TEST_EQUALS( childImage.GetProperty<Vector3>( Dali::Actor::Property::POSITION ), Vector3( 15, 5, 0 ), TEST_LOCATION );
+
+  // Check whether Image Visual transforms on ImageVieiw::OnRelayout()
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+  Toolkit::Visual::Base imageVisual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* transformValue = resultMap.Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+
+  // Image Visual should be positioned depending on ImageView's padding
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 15, 5 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPaddingProperty02(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Property::Map imagePropertyMap;
+  imagePropertyMap[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::IMAGE;
+  imagePropertyMap[ Toolkit::ImageVisual::Property::URL ] = TEST_RESOURCE_DIR "/Kid1.svg" ;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_WIDTH ] = 128;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 128;
+  imagePropertyMap[ DevelVisual::Property::VISUAL_FITTING_MODE ] = Toolkit::DevelVisual::FIT_KEEP_ASPECT_RATIO;
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE , imagePropertyMap );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  imageView.SetProperty( Control::Property::PADDING, Extents( 15, 10, 5, 10 ) );
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetProperty<Extents>( Control::Property::PADDING ), Extents( 15, 10, 5, 10 ), TEST_LOCATION );
+
+  // Check whether Image Visual transforms on ImageVieiw::OnRelayout()
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+  Toolkit::Visual::Base imageVisual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* transformValue = resultMap.Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+
+  // Image Visual should be positioned depending on ImageView's padding
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 15, 5 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPaddingProperty03(void)
+{
+  tet_infoline("Test Setting Image Padding then removing it.");
+
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Property::Map imagePropertyMap;
+  imagePropertyMap[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::IMAGE;
+  imagePropertyMap[ Toolkit::ImageVisual::Property::URL ] = TEST_RESOURCE_DIR "/Kid1.svg" ;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_WIDTH ] = 128;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 128;
+  imagePropertyMap[ DevelVisual::Property::VISUAL_FITTING_MODE ] = Toolkit::DevelVisual::FIT_KEEP_ASPECT_RATIO;
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE , imagePropertyMap );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  imageView.SetProperty( Control::Property::PADDING, Extents( 15, 10, 5, 10 ) );
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetProperty<Extents>( Control::Property::PADDING ), Extents( 15, 10, 5, 10 ), TEST_LOCATION );
+
+  tet_infoline("Remove Padding and test Visual is position correctly");
+
+  imageView.SetProperty( Control::Property::PADDING, Extents( 0, 0, 0, 0 ) );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether Image Visual transforms on ImageVieiw::OnRelayout()
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+  Toolkit::Visual::Base imageVisual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* transformValue = resultMap.Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+
+  // Image Visual should be positioned depending on ImageView's padding
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 0, 0 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewPaddingProperty04(void)
+{
+  tet_infoline("Test Setting Image Padding then removing it. Visual Fitting Mode as Fill");
+
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Property::Map imagePropertyMap;
+  imagePropertyMap[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::IMAGE;
+  imagePropertyMap[ Toolkit::ImageVisual::Property::URL ] = TEST_RESOURCE_DIR "/Kid1.svg" ;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_WIDTH ] = 128;
+  imagePropertyMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 128;
+  imagePropertyMap[ DevelVisual::Property::VISUAL_FITTING_MODE ] = Toolkit::DevelVisual::FILL;
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE , imagePropertyMap );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  imageView.SetProperty( Control::Property::PADDING, Extents( 15, 10, 5, 10 ) );
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetProperty<Extents>( Control::Property::PADDING ), Extents( 15, 10, 5, 10 ), TEST_LOCATION );
+
+  tet_infoline("Remove Padding and test Visual is position correctly");
+
+  imageView.SetProperty( Control::Property::PADDING, Extents( 0, 0, 0, 0 ) );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether Image Visual transforms on ImageVieiw::OnRelayout()
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+  Toolkit::Visual::Base imageVisual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* transformValue = resultMap.Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+
+  // Image Visual should be positioned depending on ImageView's padding
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 0, 0 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewTransformTest01(void)
+{
+  tet_infoline("Test Setting a offset transform on the ImageView");
+
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  Property::Map imagePropertyMap;
+  imagePropertyMap.Add( Toolkit::Visual::Property::TYPE,Toolkit::Visual::IMAGE )
+                  .Add( Toolkit::ImageVisual::Property::URL,TEST_RESOURCE_DIR "/Kid1.svg" )
+                  .Add( ImageVisual::Property::DESIRED_WIDTH,120 )
+                  .Add( ImageVisual::Property::DESIRED_HEIGHT,120 )
+                  .Add( DevelVisual::Property::VISUAL_FITTING_MODE, Toolkit::DevelVisual::FILL )
+                  .Add( Visual::Property::TRANSFORM,
+                        Property::Map().Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                                             Vector2( Visual::Transform::Policy::ABSOLUTE, Visual::Transform::Policy::ABSOLUTE ) )
+                                       .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( 8, 8 ) ) );
+
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE , imagePropertyMap );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  Stage::GetCurrent().Add( imageView );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check whether Image Visual transforms on ImageVieiw::OnRelayout()
+  Toolkit::Internal::Control& controlImpl = Toolkit::Internal::GetImplementation( imageView );
+  Toolkit::Visual::Base imageVisual = DevelControl::GetVisual( controlImpl, ImageView::Property::IMAGE );
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* transformValue = resultMap.Find( Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( transformValue );
+  Property::Map* retMap = transformValue->GetMap();
+  DALI_TEST_CHECK( retMap );
+
+  // Image Visual should be positioned depending on ImageView's padding
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET )->Get< Vector2 >(), Vector2( 8, 8 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( retMap->Find( Visual::Transform::Property::OFFSET_POLICY )->Get< Vector2 >(), Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewUsingAtlasAndGetNaturalSize(void)
+{
+  ToolkitTestApplication application;
+
+  // Check ImageView with background and main image, to ensure both visuals are marked as loaded
+  ImageView imageView = ImageView::New();
+  Property::Map imageMap;
+  imageMap[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::IMAGE;
+  imageMap[ Toolkit::ImageVisual::Property::URL ] = gImage_34_RGBA;
+  imageMap[ Toolkit::ImageVisual::Property::ATLASING ] = true;
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, imageMap );
+  Stage::GetCurrent().Add( imageView );
+
+  // Trigger a potential relayout
+  application.SendNotification();
+  application.Render();
+
+  Vector3 naturalSize = imageView.GetNaturalSize();
+
+  DALI_TEST_EQUALS( naturalSize.width, 34.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( naturalSize.height, 34.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewFillMode(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Create an ImageVisual without padding and set the fill-mode to fill" );
+  tet_infoline( "  There should be no need to change the transform, our size-policy should be relative and size should be [1,1]");
+
+  ImageView imageView = ImageView::New();
+  Property::Map imageMap;
+  imageMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
+  imageMap.Add( Toolkit::ImageVisual::Property::URL, gImage_600_RGB );
+  imageMap.Add( DevelVisual::Property::VISUAL_FITTING_MODE, DevelVisual::FittingMode::FILL );
+
+  imageView.SetProperty( Toolkit::ImageView::Property::IMAGE, imageMap );
+
+  Stage::GetCurrent().Add( imageView );
+
+  // Trigger a potential relayout
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( Toolkit::Internal::GetImplementation( imageView ), Toolkit::ImageView::Property::IMAGE );
+  Property::Map returnedMap;
+  visual.CreatePropertyMap( returnedMap );
+
+  Property::Value* value = returnedMap.Find( Toolkit::Visual::Property::TRANSFORM );
+  DALI_TEST_CHECK( value );
+  Property::Map* map = value->GetMap();
+  DALI_TEST_CHECK( map );
+
+  // If there's
+  value = map->Find( Toolkit::Visual::Transform::Property::SIZE );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get< Vector2 >(), Vector2::ONE, TEST_LOCATION ); // Relative size so will take up 100%
+
+  value = map->Find( Toolkit::Visual::Transform::Property::SIZE_POLICY );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< int >() == Toolkit::Visual::Transform::Policy::RELATIVE );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewCustomShader(void)
+{
+  ToolkitTestApplication application;
+
+  // Set a custom shader with an image url
+  {
+    Property::Map properties;
+    Property::Map shader;
+    const std::string vertexShader = "Foobar";
+    const std::string fragmentShader = "Foobar";
+    shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+    shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+    properties[Visual::Property::TYPE] = Visual::IMAGE;
+    properties[Visual::Property::SHADER] = shader;
+    properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+
+    ImageView imageView = ImageView::New();
+    imageView.SetProperty( ImageView::Property::IMAGE, properties );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    Renderer renderer = imageView.GetRendererAt( 0 );
+    Shader shader2 = renderer.GetShader();
+    Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+    DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+    Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+    DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+  }
+
+  // Set a custom shader after setting an image url
+  {
+    Property::Map properties;
+    Property::Map shader;
+    const std::string vertexShader = "Foobar";
+    const std::string fragmentShader = "Foobar";
+    shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+    shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+    properties[Visual::Property::SHADER] = shader;
+
+    ImageView imageView = ImageView::New( TEST_IMAGE_FILE_NAME );
+    imageView.SetProperty( ImageView::Property::IMAGE, properties );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    Renderer renderer = imageView.GetRendererAt( 0 );
+    Shader shader2 = renderer.GetShader();
+    Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+    DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+    Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+    DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+  }
+
+  // Set a custom shader before setting an image url
+  {
+    Property::Map properties;
+    Property::Map shader;
+    const std::string vertexShader = "Foobar";
+    const std::string fragmentShader = "Foobar";
+    shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+    shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+    properties[Visual::Property::SHADER] = shader;
+
+    ImageView imageView = ImageView::New();
+    imageView.SetProperty( ImageView::Property::IMAGE, properties );
+    imageView.SetProperty( ImageView::Property::IMAGE, TEST_IMAGE_FILE_NAME );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    Renderer renderer = imageView.GetRendererAt( 0 );
+    Shader shader2 = renderer.GetShader();
+    Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+    DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+    Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+    DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+  }
+
+  // Set a custom shader after setting a property map
+  {
+    Property::Map properties;
+    Property::Map shader;
+    const std::string vertexShader = "Foobar";
+    const std::string fragmentShader = "Foobar";
+    shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+    shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+    properties[Visual::Property::SHADER] = shader;
+
+    Property::Map properties1;
+    properties1[Visual::Property::TYPE] = Visual::IMAGE;
+    properties1[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+
+    ImageView imageView = ImageView::New();
+    imageView.SetProperty( ImageView::Property::IMAGE, properties1 );
+    imageView.SetProperty( ImageView::Property::IMAGE, properties );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    Renderer renderer = imageView.GetRendererAt( 0 );
+    Shader shader2 = renderer.GetShader();
+    Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+    DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+    Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+    DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+  }
+
+  // Set a custom shader before setting a property map
+  {
+    Property::Map properties;
+    Property::Map shader;
+    const std::string vertexShader = "Foobar";
+    const std::string fragmentShader = "Foobar";
+    shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+    shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+    properties[Visual::Property::SHADER] = shader;
+
+    Property::Map properties1;
+    properties1[Visual::Property::TYPE] = Visual::IMAGE;
+    properties1[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+
+    ImageView imageView = ImageView::New();
+    imageView.SetProperty( ImageView::Property::IMAGE, properties );
+    imageView.SetProperty( ImageView::Property::IMAGE, properties1 );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    Renderer renderer = imageView.GetRendererAt( 0 );
+    Shader shader2 = renderer.GetShader();
+    Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+    DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+    Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+    DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+
+namespace
+{
+static int gFailCounter = 0;
+const int MAX_RETRIES(3);
+
+void ReloadImage(ImageView imageView)
+{
+  Property::Map imageImmediateLoadingMap;
+  imageImmediateLoadingMap[ ImageVisual::Property::URL ] = "Non-existant-image.jpg";
+  imageImmediateLoadingMap[ ImageVisual::Property::LOAD_POLICY ] =  ImageVisual::LoadPolicy::IMMEDIATE;
+
+  tet_infoline("Immediate load an image");
+  imageView.SetProperty( ImageView::Property::IMAGE, imageImmediateLoadingMap );
+}
+
+void ResourceFailedReload( Control control )
+{
+  gFailCounter++;
+  if( gFailCounter < MAX_RETRIES )
+  {
+    ReloadImage(ImageView::DownCast(control));
+  }
+}
+}
+
+int UtcDaliImageViewReloadFailedOnResourceReadySignal(void)
+{
+  tet_infoline("Test reloading failed image from within signal handler.");
+
+  ToolkitTestApplication application;
+
+  gFailCounter = 0;
+
+  ImageView imageView = ImageView::New();
+  imageView.ResourceReadySignal().Connect( &ResourceFailedReload );
+  DALI_TEST_EQUALS( gFailCounter, 0, TEST_LOCATION );
+  ReloadImage(imageView);
+
+  // loading started, this waits for the loader thread to complete
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( gFailCounter, 1, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( gFailCounter, 2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+  DALI_TEST_EQUALS( gFailCounter, 3, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewLoadRemoteSVG(void)
+{
+  tet_infoline("Test load from a remote server.");
+
+  ToolkitTestApplication application;
+  Toolkit::ImageView imageView;
+  imageView = Toolkit::ImageView::New(  );
+  imageView.SetImage("https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/check.svg");
+  // Victor. Temporary (or permanent?) update as the url above seems not to work from time to time ...
+  imageView.SetImage("https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/SVG_logo.svg/64px-SVG_logo.svg.png");
+  imageView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  imageView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  imageView.SetSize(300, 300);
+  imageView.SetPosition( Vector3( 150.0f , 150.0f , 0.0f ) );
+
+  Stage::GetCurrent().Add( imageView );
+
+  DALI_TEST_CHECK( imageView );
+
+  DALI_TEST_EQUALS( imageView.GetRendererCount(), 0u, TEST_LOCATION );
+
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( imageView.GetRendererCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewSyncSVGLoading(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing SVG image sync loading");
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+
+    // Sync loading is used
+    Property::Map syncLoadingMap;
+    syncLoadingMap.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::IMAGE );
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::URL,  TEST_RESOURCE_DIR "/svg1.svg"  );
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING,  true);
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    Stage::GetCurrent().Add( imageView );
+    DALI_TEST_CHECK( imageView );
+
+    application.SendNotification();
+    application.Render(16);
+    Vector3 naturalSize = imageView.GetNaturalSize();
+
+    DALI_TEST_EQUALS( naturalSize.width, 100.0f, TEST_LOCATION );
+    DALI_TEST_EQUALS( naturalSize.height, 100.0f, TEST_LOCATION );
+
+  }
+  END_TEST;
+}
+
+int UtcDaliImageViewAsyncSVGLoading(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing SVG image async loading");
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+
+    // Sync loading is used
+    Property::Map syncLoadingMap;
+    syncLoadingMap.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::IMAGE );
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::URL,  TEST_RESOURCE_DIR "/svg1.svg"  );
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING,  false);
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    Stage::GetCurrent().Add( imageView );
+    DALI_TEST_CHECK( imageView );
+
+    application.SendNotification();
+    application.Render(16);
+    Vector3 naturalSize = imageView.GetNaturalSize();
+
+    DALI_TEST_EQUALS( naturalSize.width, 100.0f, TEST_LOCATION );
+    DALI_TEST_EQUALS( naturalSize.height, 100.0f, TEST_LOCATION );
+  }
+  END_TEST;
+}
+
+int UtcDaliImageViewSVGLoadingSyncSetInvalidValue(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("ImageView Testing SVG image async loading");
+
+  // Sync loading, automatic atlasing for small size image
+  {
+    TraceCallStack& callStack = application.GetGlAbstraction().GetTextureTrace();
+    callStack.Reset();
+    callStack.Enable(true);
+
+    ImageView imageView = ImageView::New( );
+
+    // Sync loading is used
+    Property::Map syncLoadingMap;
+    syncLoadingMap.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::IMAGE );
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::URL,  TEST_RESOURCE_DIR "/svg1.svg"  );
+
+    // Check to set invalid value
+    // The SYNCHRONOUS_LOADING property must be set to the bool value.
+    // Check if error log is outputted when setting other value like string.
+    // Even if the wrong value is set, the image will be shown normally, and the synchronous value should be the default value(false).
+    syncLoadingMap.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, std::to_string(5) );
+    imageView.SetProperty( ImageView::Property::IMAGE, syncLoadingMap );
+
+    Stage::GetCurrent().Add( imageView );
+    DALI_TEST_CHECK( imageView );
+
+    application.SendNotification();
+    application.Render(16);
+    Vector3 naturalSize = imageView.GetNaturalSize();
+    DALI_TEST_EQUALS( naturalSize.width, 100.0f, TEST_LOCATION );
+    DALI_TEST_EQUALS( naturalSize.height, 100.0f, TEST_LOCATION );
+
+    Property::Value value = imageView.GetProperty( ImageView::Property::IMAGE );
+    Property::Map* map = value.GetMap();
+    DALI_TEST_CHECK( map );
+
+    Property::Value* sync = map->Find( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING );
+    DALI_TEST_CHECK( sync );
+    DALI_TEST_EQUALS( false, sync->Get< bool >(), TEST_LOCATION );
+
+  }
+  END_TEST;
+}
+
+int UtcDaliImageViewSvgLoadingFailure(void)
+{
+  ToolkitTestApplication application;
+
+  // Local svg file
+  {
+    gResourceReadySignalFired = false;
+
+    ImageView imageView = ImageView::New( TEST_RESOURCE_DIR "/Kid1.svg" );
+    imageView.SetSize( 200.f, 200.f );
+    imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+    DALI_TEST_EQUALS( imageView.IsResourceReady(), false, TEST_LOCATION );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+
+    // loading started, this waits for the loader thread
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+
+    DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+    DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( imageView.GetVisualResourceStatus( ImageView::Property::IMAGE ), Visual::ResourceStatus::FAILED, TEST_LOCATION );
+  }
+
+  // Remote svg file
+  {
+    gResourceReadySignalFired = false;
+
+    ImageView imageView = ImageView::New( "https://bar.org/foobar.svg" );
+    imageView.SetSize( 200.f, 200.f );
+    imageView.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+    DALI_TEST_EQUALS( imageView.IsResourceReady(), false, TEST_LOCATION );
+
+    Stage::GetCurrent().Add( imageView );
+
+    application.SendNotification();
+
+    // loading started, this waits for the loader thread
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(16);
+
+    DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+    DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( imageView.GetVisualResourceStatus( ImageView::Property::IMAGE ), Visual::ResourceStatus::FAILED, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+namespace
+{
+
+static int gResourceReadySignalCounter = 0;
+
+void OnResourceReadySignal( Control control )
+{
+  gResourceReadySignalCounter++;
+
+  if( gResourceReadySignalCounter == 1 )
+  {
+    // Set image twice
+    ImageView::DownCast( control ).SetImage( gImage_34_RGBA );
+    ImageView::DownCast( control ).SetImage( gImage_34_RGBA );
+  }
+}
+
+}
+
+int UtcDaliImageViewSetImageOnResourceReadySignal(void)
+{
+  tet_infoline("Test setting image from within signal handler.");
+
+  ToolkitTestApplication application;
+
+  gResourceReadySignalCounter = 0;
+
+  ImageView imageView = ImageView::New( gImage_34_RGBA );
+  imageView.ResourceReadySignal().Connect( &OnResourceReadySignal );
+
+  Stage::GetCurrent().Add( imageView );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( gResourceReadySignalCounter, 2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( imageView.IsResourceReady(), true, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ImageVisual.cpp
new file mode 100644 (file)
index 0000000..327d0f0
--- /dev/null
@@ -0,0 +1,2384 @@
+/*
+ * Copyright (c) 2020 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 <vector>
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_image_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_image_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery-small-1.jpg";
+const char* TEST_BROKEN_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/a-random-nonimage.jpg";
+const char* TEST_LARGE_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/tbcol.png";
+const char* TEST_SMALL_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/icon-edit.png";
+const char* TEST_REMOTE_IMAGE_FILE_NAME = "https://www.tizen.org/sites/all/themes/tizen_theme/logo.png";
+const char* TEST_INVALID_FILE_NAME =  TEST_RESOURCE_DIR  "/invalid.jpg";
+const char* TEST_REMOTE_INVALID_FILE_NAME = "https://www.tizen.org/invalid.png";
+const char* TEST_MASK_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/mask.png";
+const char* TEST_ROTATED_IMAGE =  TEST_RESOURCE_DIR  "/keyboard-Landscape.jpg";
+
+
+bool gResourceReadySignalFired = false;
+std::vector<int> gReadyIds = {};
+void ResourceReadySignal( Control control )
+{
+  gResourceReadySignalFired = true;
+  gReadyIds.push_back(control.GetId());
+}
+void ClearReadyIds()
+{
+  gReadyIds.clear();
+}
+
+Actor CreateActorWithImageVisual(const Property::Map& map)
+{
+  VisualFactory factory = VisualFactory::Get();
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Visual::Base visual = factory.CreateVisual( map );
+  DALI_TEST_CHECK( visual );
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  return actor;
+}
+
+
+Visual::Base CreateVisualWithPolicy( const char* url, Property::Index key, const Property::Value& value )
+{
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  url );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
+  propertyMap.Insert( key , value );
+
+  return factory.CreateVisual( propertyMap );
+}
+
+} // namespace
+
+void TestVisualRender( ToolkitTestApplication& application,
+                       DummyControl& actor,
+                       Visual::Base& visual,
+                       std::size_t expectedSamplers = 0,
+                       ImageDimensions imageDimensions = ImageDimensions(),
+                       Integration::ResourcePointer resourcePtr = Integration::ResourcePointer())
+{
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  if( resourcePtr )
+  {
+    // set the image size, for test case, this needs to be set before loading started
+    application.GetPlatform().SetClosestImageSize(  Vector2(imageDimensions.GetWidth(), imageDimensions.GetHeight()) );
+  }
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification(); // Send messages to update
+  application.Render();           // process update and render
+  application.SendNotification(); // process any signals to event
+
+  if( resourcePtr )
+  {
+    DALI_TEST_EQUALS( application.GetPlatform().WasCalled(TestPlatformAbstraction::LoadResourceSynchronouslyFunc ), true, TEST_LOCATION);
+  }
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+}
+
+static void TestMixColor( Visual::Base visual, Property::Index mixColorIndex, const Vector4& testColor )
+{
+  Property::Map map;
+  visual.CreatePropertyMap(map);
+  Property::Value* value = map.Find( mixColorIndex );
+  DALI_TEST_CHECK( value );
+  Vector3 mixColor1;
+  DALI_TEST_CHECK( value->Get( mixColor1 ) );
+  DALI_TEST_EQUALS( mixColor1, Vector3(testColor), 0.001, TEST_LOCATION );
+
+  value = map.Find( Visual::Property::MIX_COLOR );
+  DALI_TEST_CHECK( value );
+  Vector4 mixColor2;
+  DALI_TEST_CHECK( value->Get( mixColor2 ) );
+  DALI_TEST_EQUALS( mixColor2, testColor, 0.001, TEST_LOCATION );
+
+  value = map.Find( Visual::Property::OPACITY );
+  DALI_TEST_CHECK( value );
+  float opacity;
+  DALI_TEST_CHECK( value->Get( opacity ) );
+  DALI_TEST_EQUALS( opacity, testColor.a, 0.001, TEST_LOCATION );
+}
+
+
+
+int UtcDaliImageVisualPropertyMap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+  factory.SetPreMultiplyOnLoad( true );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<float>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+  DALI_TEST_EQUALS( preMultipliedAlpha, 1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual without pre-multiplied alpha" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+  factory.SetPreMultiplyOnLoad( false );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+  DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualNoPremultipliedAlpha02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with no alpha channel" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto renderer = actor.GetRendererAt(0);
+  auto preMultipliedIndex = renderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  auto preMultipliedAlpha = renderer.GetProperty<bool>( preMultipliedIndex );
+  auto preMultipliedAlpha2 = renderer.GetProperty<bool>( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+  DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  int srcFactorRgb    = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  int destFactorRgb   = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  int srcFactorAlpha  = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  int destFactorAlpha = renderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::SRC_ALPHA );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  textureTrace.Reset();
+
+  // Make a new visual with the same image
+  Visual::Base newVisual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( newVisual );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  DummyControl newActor = DummyControl::New();
+  DummyControlImpl& newDummyImpl = static_cast< DummyControlImpl& >( newActor.GetImplementation() );
+  newDummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, newVisual );
+
+  newActor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( newActor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( newActor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( newActor.GetRendererCount(), 1u, TEST_LOCATION );
+  auto newRenderer = newActor.GetRendererAt( 0 );
+  preMultipliedIndex = newRenderer.GetPropertyIndex( "preMultipliedAlpha" );
+  DALI_TEST_CHECK( preMultipliedIndex != Property::INVALID_INDEX );
+  preMultipliedAlpha = newRenderer.GetProperty< bool >( preMultipliedIndex );
+  preMultipliedAlpha2 = newRenderer.GetProperty< bool >( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA );
+
+  DALI_TEST_EQUALS( preMultipliedAlpha, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( preMultipliedAlpha2, false, TEST_LOCATION );
+
+  srcFactorRgb    = newRenderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_RGB );
+  destFactorRgb   = newRenderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_RGB );
+  srcFactorAlpha  = newRenderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_SRC_ALPHA );
+  destFactorAlpha = newRenderer.GetProperty<int>( Renderer::Property::BLEND_FACTOR_DEST_ALPHA );
+  DALI_TEST_CHECK( srcFactorRgb == BlendFactor::SRC_ALPHA );
+  DALI_TEST_CHECK( destFactorRgb == BlendFactor::ONE_MINUS_SRC_ALPHA );
+  DALI_TEST_CHECK( srcFactorAlpha == BlendFactor::ONE );
+  DALI_TEST_CHECK( destFactorAlpha == BlendFactor::ONE_MINUS_SRC_ALPHA );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualRemoteImageLoad(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request remote image visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_REMOTE_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualTextureReuse1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request remote image visual with a Property::Map; request a second visual with the same property map - should reuse texture" );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::RELEASE_POLICY,  ImageVisual::ReleasePolicy::DETACHED );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Actor actor = CreateActorWithImageVisual( propertyMap );
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION );
+  textureTrace.Reset();
+  drawTrace.Reset();
+
+  Actor actor2 = CreateActorWithImageVisual( propertyMap );
+  Stage::GetCurrent().Add(actor2);
+
+  application.SendNotification(); // Send messages to update
+  application.Render();           // process update and render
+  application.SendNotification(); // process any signals to event
+
+  DALI_TEST_EQUALS( actor2.GetRendererCount(), 1u, TEST_LOCATION );
+
+  tet_infoline("Test that 2 draw calls occur with no new texture gens/binds, i.e. both\n"
+               "draw calls use the same texture as the previous draw call\n" );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 0, TEST_LOCATION );
+
+  tet_infoline("Test that removing 1 actor doesn't delete the texture\n");
+
+  Stage::GetCurrent().Remove( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  tet_infoline("Test that removing last actor does delete the texture\n");
+
+  Stage::GetCurrent().Remove( actor2 ); // Detaches remaining ImageVisual
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor2.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualTextureReuse2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request remote image visual with a Property::Map; request a second visual with the same url but different property map - should create new texture" );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_IMAGE_FILE_NAME );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Actor actor = CreateActorWithImageVisual( propertyMap );
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION );
+  textureTrace.Reset();
+  drawTrace.Reset();
+
+  propertyMap.Insert( ImageVisual::Property::SAMPLING_MODE, Dali::SamplingMode::NEAREST );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, 100 );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, 100 );
+  Actor actor2 = CreateActorWithImageVisual( propertyMap );
+  Stage::GetCurrent().Add(actor2);
+
+  application.SendNotification();
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor2.GetRendererCount(), 1u, TEST_LOCATION );
+
+  tet_infoline("Test that 2 draw calls occur with 1 new texture gen/bind, i.e. both "
+               "renderers are using different textures\n" );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.CountMethod("DrawArrays"), 2, TEST_LOCATION );
+  TraceCallStack::NamedParams tex1;
+  tex1["texture"] = "1";
+  TraceCallStack::NamedParams tex2;
+  tex1["texture"] = "2";
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex1), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethodAndParams("BindTexture", tex2), true, TEST_LOCATION );
+
+  tet_infoline("Test that removing 1 actor deletes it's texture\n");
+
+  Stage::GetCurrent().Remove( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  tet_infoline("Test that removing last actor deletes it's texture\n");
+
+  Stage::GetCurrent().Remove( actor2 );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor2.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualImageHandle(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with an image handle" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME);
+  Visual::Base visual = factory.CreateVisual( image );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  const int width=512;
+  const int height=513;
+
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+  bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, width, height,width, height );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  TestVisualRender( application, actor, visual, 1u,
+                    ImageDimensions(width, height),
+                    Integration::ResourcePointer(bitmap) );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliImageVisualCustomWrapModePixelArea(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map, test custom wrap mode and pixel area with atlasing" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test wrap mode with atlasing. Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+  const int width=34;
+  const int height=34;
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_SMALL_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+  propertyMap.Insert( ImageVisual::Property::ATLASING, true );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable( true );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add( actor );
+
+  // loading started
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // WITH atlasing, the wrapping is handled manually in shader, so the following gl function should not be called
+  std::stringstream out;
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+  out.str("");
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  Property::Value wrapModeValue = renderer.GetProperty( renderer.GetPropertyIndex( "wrapMode" ) );
+  Vector2 wrapMode( WrapMode::MIRRORED_REPEAT-1, WrapMode::REPEAT-1 );
+  DALI_TEST_EQUALS( wrapModeValue.Get<Vector2>(), wrapMode, TEST_LOCATION );
+  Vector2 wrapModeUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector2>( "wrapMode", wrapModeUniform ) );
+  DALI_TEST_EQUALS( wrapMode, wrapModeUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualCustomWrapModeNoAtlas(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map, test custom wrap mode and pixel area without atlasing" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Test wrap mode without atlasing. Image with a size bigger than 512*512 will NOT be uploaded as a part of the atlas.
+  const int width=600;
+  const int height=600;
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH, width );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT, height );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  propertyMap.Insert( ImageVisual::Property::PIXEL_AREA, pixelArea );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT );
+  propertyMap.Insert( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable( true );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add( actor );
+
+  // loading started
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // WITHOUT atlasing, the wrapping is handled by setting gl texture parameters
+  std::stringstream out;
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+  out.str("");
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+  DALI_TEST_CHECK( texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  Property::Index wrapModeIndex = renderer.GetPropertyIndex( "wrapMode" );
+  DALI_TEST_CHECK(wrapModeIndex == Property::INVALID_INDEX);
+
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualAnimateMixColor(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Animate mix color" );
+
+  application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert("mixColor", Color::BLUE);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  actor.SetColor(Color::BLACK);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index index = DevelHandle::GetPropertyIndex( renderer, Visual::Property::MIX_COLOR );
+  Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  tet_infoline("Test that the renderer has the mixColor property");
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+  const Vector4 TARGET_MIX_COLOR( 1.0f, 0.0f, 0.0f, 0.5f );
+
+  Property::Map map;
+  map["target"] = "testVisual";
+  map["property"] = "mixColor";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = TARGET_MIX_COLOR;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 4.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  Animation animation = dummyImpl.CreateTransition( transition );
+
+  blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+  animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0); // Ensure animation starts
+  application.Render(2000u); // Halfway point
+  Vector3 testColor( 1.0f, 0.0f, 0.5f );
+
+  // uColor.a should be actor's alpha * mixColor.a.
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>( "uColor", Vector4( 0.5f, 0.5f, 0.5f, 0.75f ) ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>( "mixColor", testColor ), true, TEST_LOCATION );
+
+  application.Render(2000u); // Halfway point between blue and white
+
+  DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>( "uColor", Vector4( 1.0f, 1.0f, 1.0f, 0.5f ) ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>( "mixColor", Vector3( TARGET_MIX_COLOR ) ), true, TEST_LOCATION );
+
+  TestMixColor( visual, Visual::Property::MIX_COLOR, TARGET_MIX_COLOR );
+
+  blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualAnimateOpacity(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Animate image visual opacity" );
+
+  application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert("opacity", 0.5f);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  actor.SetColor(Color::BLACK);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+  {
+    tet_infoline( "Test that the opacity can be increased to full via animation, and that the blend mode is set appropriately at the start and end of the animation." );
+
+    Property::Map map;
+    map["target"] = "testVisual";
+    map["property"] = "opacity";
+    map["targetValue"] = 1.0f;
+    map["animator"] = Property::Map()
+      .Add("alphaFunction", "LINEAR")
+      .Add("timePeriod", Property::Map()
+           .Add("delay", 0.0f)
+           .Add("duration", 4.0f));
+
+    Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+    Animation animation = dummyImpl.CreateTransition( transition );
+    animation.Play();
+
+    application.SendNotification();
+    application.Render(0);     // Ensure animation starts
+    application.Render(2000u); // Halfway point through animation
+    application.SendNotification(); // Handle any signals
+
+    Vector4 color;
+    DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+    DALI_TEST_EQUALS( color.a, 0.75f, TEST_LOCATION );
+
+    application.Render(2001u); // end
+    application.SendNotification(); // ensure animation finished signal is sent
+
+    DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+    DALI_TEST_EQUALS( color.a, 1.0f, TEST_LOCATION );
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+  }
+
+
+  {
+    tet_infoline( "Test that the opacity can be reduced via animation, and that the blend mode is set appropriately at the start and end of the animation." );
+
+    Property::Map map;
+    map["target"] = "testVisual";
+    map["property"] = Visual::Property::OPACITY;
+    map["targetValue"] = 0.1f;
+    map["animator"] = Property::Map()
+      .Add("alphaFunction", "LINEAR")
+      .Add("timePeriod", Property::Map()
+           .Add("delay", 0.0f)
+           .Add("duration", 4.0f));
+
+    Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+    Animation animation = dummyImpl.CreateTransition( transition );
+    animation.Play();
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render(0);     // Ensure animation starts
+    application.Render(2000u); // Halfway point
+    application.SendNotification();
+
+    Vector4 color;
+    DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+    DALI_TEST_EQUALS( color.a, 0.55f, TEST_LOCATION );
+
+    application.Render(2016u); // end
+    application.SendNotification();
+
+    DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+    DALI_TEST_EQUALS( color.a, 0.1f, TEST_LOCATION );
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+  }
+
+
+  END_TEST;
+}
+
+
+
+int UtcDaliImageVisualAnimateOpacity02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Animate image visual opacity" );
+
+  application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert("opacity", 0.5f);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  actor.SetColor(Color::BLACK);
+
+  tet_infoline( "Test that the opacity doesn't animate when actor not staged" );
+
+  Property::Array array;
+
+  Property::Map map;
+  map["target"] = "testVisual";
+  map["property"] = "opacity";
+  map["initialValue"] = 0.0f;
+  map["targetValue"] = 1.0f;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 4.0f));
+
+  Property::Map map2;
+  map2["target"] = "testVisual";
+  map2["property"] = "size";
+  map2["targetValue"] = Vector2(1.0f, 1.0f);
+
+  array.Add( map ).Add(map2);
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( array );
+  Animation animation = dummyImpl.CreateTransition( transition );
+
+  Stage::GetCurrent().Add(actor);
+  application.SendNotification();
+  application.Render(0);     // Ensure animation starts
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  animation = dummyImpl.CreateTransition( transition );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);     // Ensure animation starts
+  application.Render(2000u); // Halfway point through animation
+  application.SendNotification(); // Handle any signals
+
+  blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+  Vector4 color;
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+  DALI_TEST_EQUALS( color.a, 0.5f, TEST_LOCATION );
+
+  application.Render(2001u); // end
+  application.SendNotification(); // ensure animation finished signal is sent
+
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", color ) );
+  DALI_TEST_EQUALS( color.a, 1.0f, TEST_LOCATION );
+
+  blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+int UtcDaliImageVisualAnimatePixelArea(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "ImageVisual animate pixel area" );
+
+  application.GetPlatform().SetClosestImageSize( Vector2(100, 100) );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::IMAGE);
+  propertyMap.Insert(ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert("mixColor", Color::BLUE);
+  propertyMap.Insert(ImageVisual::Property::SYNCHRONOUS_LOADING, true);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  actor.SetColor(Color::BLACK);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index index = DevelHandle::GetPropertyIndex( renderer, Visual::Property::MIX_COLOR );
+
+  tet_infoline("Test that the renderer has the mixColor property");
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+  // TransitionData only takes string keys
+  Property::Map map;
+  map["target"] = "testVisual";
+  map["property"] = "pixelArea";
+  map["initialValue"] = Vector4( 0,0,0,1 );
+  map["targetValue"] = Vector4( 0,0,1,1 ); // Animate width from zero to full
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 4.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  Animation animation = dummyImpl.CreateTransition( transition );
+  animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);     // Ensure animation starts
+  application.Render(2000u); // Halfway point
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4(0.0f, 0.0f, 0.5f, 1.0f )), true, TEST_LOCATION );
+
+  application.Render(2000u); // End of animation
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("pixelArea", Vector4( 0.0f, 0.0f, 1.0f, 1.0f )), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualTextureCancelRemoteLoad(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request remote image visual, then destroy visual to cancel load" );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_IMAGE_FILE_NAME );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  Actor actor = CreateActorWithImageVisual( propertyMap );
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+
+  Stage::GetCurrent().Remove( actor );
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualTextureCancelAsyncLoad(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Load image asynchronosly, cancel loading, then load again" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable( true );
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable( true );
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+  dummyImpl.RegisterVisual( Control::Property::BACKGROUND, visual );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Cancel loading
+  Stage::GetCurrent().Remove( actor );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Create another visual with the same image
+  visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  dummyImpl.RegisterVisual( Control::Property::BACKGROUND, visual );
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( drawTrace.FindMethod("DrawArrays"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualSetInvalidAsyncImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with invalid images - should draw broken.png" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_INVALID_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualSetInvalidSyncImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with invalid images - should draw broken.png" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_INVALID_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualSetInvalidRemoteImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with invalid images - should draw broken.png" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Local invalid file, asynchronous loading
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_REMOTE_INVALID_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL),Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+
+  dummyImpl.UnregisterVisual(  Control::CONTROL_PROPERTY_END_INDEX + 1 );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualSynchronousLoadAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask with synchronous loading" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL),Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Do not wait for any EventThreadTrigger in synchronous alpha mask.
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+
+  dummyImpl.UnregisterVisual(  Control::CONTROL_PROPERTY_END_INDEX + 1 );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualRemoteAlphaMask(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with a Property::Map containing an Alpha mask" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  const std::string MASK_IMAGE = TEST_REMOTE_IMAGE_FILE_NAME;
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ALPHA_MASK_URL, MASK_IMAGE );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+
+  DALI_TEST_EQUALS(*testMap.Find(ImageVisual::Property::ALPHA_MASK_URL),Property::Value(MASK_IMAGE), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  DALI_TEST_EQUALS( actor.IsResourceReady(), false, TEST_LOCATION );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualAlphaMaskCrop(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Request image visual with an Alpha mask and scale/cropping" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_LARGE_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::MASK_CONTENT_SCALE, 1.6f );
+  propertyMap.Insert( ImageVisual::Property::CROP_TO_MASK, true );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  Property::Map testMap;
+  visual.CreatePropertyMap(testMap);
+  DALI_TEST_EQUALS( *testMap.Find(ImageVisual::Property::ALPHA_MASK_URL),Property::Value(TEST_MASK_IMAGE_FILE_NAME), TEST_LOCATION );
+  DALI_TEST_EQUALS( *testMap.Find(ImageVisual::Property::MASK_CONTENT_SCALE), Property::Value(1.6f), TEST_LOCATION );
+  DALI_TEST_EQUALS( *testMap.Find(ImageVisual::Property::CROP_TO_MASK),Property::Value(true), TEST_LOCATION );
+
+  // For tesing the LoadResourceFunc is called, a big image size should be set, so the atlasing is not applied.
+  // Image with a size smaller than 512*512 will be uploaded as a part of the atlas.
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 3 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 size;
+  visual.GetNaturalSize(size);
+
+  DALI_TEST_EQUALS( size, Vector2( 100.0f, 100.0f ), 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( actor.IsResourceReady(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy01 Detached Policy, disabling visual with this policy deletes texture" );
+
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DETACHED );
+  DALI_TEST_CHECK( imageVisual );
+
+  // Set up debug trace
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visual with control and ensure it has the only handle" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset();
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  // Test renderer and texture created
+  tet_infoline( "Confirm texture created" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  tet_infoline( "Disable visual causing the texture to be deleted" );
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false );
+
+  application.SendNotification();
+  application.Render(0);
+  // Test renderer and textures removed.
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy02 Destroyed Policy, Texture should be deleted when visual destroyed" );
+
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DESTROYED );
+  DALI_TEST_CHECK( imageVisual );
+
+  // Setup debug trace
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visual with control and ensure it has the only handle" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  // Test renderer and texture created
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  tet_infoline( "Destroy visual by UnRegistering visual with control, check renderer is destroyed" );
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+
+  // Test texture removed after visual destroyed.
+  tet_infoline( "Ensure texture is deleted after visual destroyed" );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy03 Never Policy, texture should not be deleted after visual destroyed" );
+
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::NEVER );
+  DALI_TEST_CHECK( imageVisual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visual with control and ensure it has the only handle" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  // Test renderer and texture created
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  tet_infoline( "Destroy visual by UnRegistering visual with control, check renderer is destroyed" );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture is not deleted as policy is set to NEVER" );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy04 Two visuals with different policies sharing a texture" );
+
+  tet_infoline( "Create first visual with Never release policy" );
+  Visual::Base imageVisualNever = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::NEVER );
+
+  tet_infoline( "Create second visual with Destroyed release policy");
+    Visual::Base imageVisualDestroyed = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DESTROYED );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisualNever );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, imageVisualDestroyed );
+  imageVisualNever.Reset(); // reduce ref count so only the control keeps the visual alive.
+  imageVisualDestroyed.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+
+  // Test initially zero renderers
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  tet_infoline( "Ensure a texture is created, shared amongst both visuals.  Each visual has its own renderer" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 2u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  // Test renderer removed when visual destroyed
+  DALI_TEST_CHECK( actor.GetRendererCount() == 2u );
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL2 );  // TEST_VISUAL2 no longer requires the texture as release policy DESTROYED
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  application.SendNotification();
+  application.Render();
+
+  // Test texture was not deleted as TEST_VISUAL release policy is NEVER so it is still required.
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure a texture is not deleted as second visual used the NEVER release policy" );
+  // Test texture was not deleted as TEST_VISUAL release policy is NEVER so it is still required.
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy05 Testing settung by string currents correct enum" );
+
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMapNeverReleasePolicy;
+  propertyMapNeverReleasePolicy.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
+  propertyMapNeverReleasePolicy.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
+  propertyMapNeverReleasePolicy.Insert( "releasePolicy" , "never" );
+
+  Visual::Base imageVisualNever = factory.CreateVisual( propertyMapNeverReleasePolicy );
+
+  Property::Map resultMap;
+  imageVisualNever.CreatePropertyMap( resultMap );
+  DALI_TEST_CHECK( ! resultMap.Empty() );
+
+  DALI_TEST_EQUALS( ( resultMap.Find( ImageVisual::Property::RELEASE_POLICY ) )->Get<int>(), (int)ImageVisual::ReleasePolicy::NEVER, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy06 Never Policy, texture should not be affected by Disabling and Enabling visual" );
+
+  Visual::Base imageVisual= CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::NEVER );
+  DALI_TEST_CHECK( imageVisual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visual with control and ensure it has the only handle" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  // Test renderer and texture created
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Disable Visual and check texture not affected" );
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false );
+  application.SendNotification();
+  application.Render(0);
+  tet_infoline( "Check renderer is destroyed when visual off stage" );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Re-enable Visual and check texture not affected" );
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, true );
+  application.SendNotification();
+  application.Render(0);
+  tet_infoline( "Check texture not affected and renderer is destroyed when visual off stage" );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualReleasePolicy07(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualReleasePolicy07 Two visuals with different policies sharing a texture DETACHED and DESTROYED" );
+
+  tet_infoline( "Create first visual with DESTROYED release policy" );
+  Visual::Base imageVisualDestroyed = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DESTROYED );
+
+
+  tet_infoline( "Create second visual with DETACHED release policy");
+  Visual::Base imageVisualDetached = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::RELEASE_POLICY, ImageVisual::ReleasePolicy::DETACHED );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisualDestroyed );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, imageVisualDetached );
+  imageVisualDestroyed.Reset(); // reduce ref count so only the control keeps the visual alive.
+  imageVisualDetached.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+
+  // Test initially zero renderers
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render(0);
+  tet_infoline( "Ensure a texture is created, shared amongst both visuals.  Each visual has its own renderer" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 2u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  // Test renderer removed when visual destroyed
+  DALI_TEST_CHECK( actor.GetRendererCount() == 2u );
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL2, false );  // TEST_VISUAL2 no longer requires the texture as release policy DETACHED
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  application.SendNotification();
+  application.Render();
+
+  // Test texture was not deleted as TEST_VISUAL release policy is DESTROYED and is still required.
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure a texture is not deleted as second visual used the DESTROYED release policy" );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy01 Load a visual image before attaching to stage" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
+  propertyMap.Insert( "loadPolicy" , ImageVisual::LoadPolicy::IMMEDIATE );
+
+  Visual::Base imageVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+  DALI_TEST_CHECK( ! resultMap.Empty() );
+  DALI_TEST_EQUALS( ( resultMap.Find( ImageVisual::Property::LOAD_POLICY ) )->Get<int>(), (int)ImageVisual::LoadPolicy::IMMEDIATE, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // Ensure texture has been uploaded
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture loading starts after visual created" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  tet_infoline( "Ensure nothing triggers another load as texure already loaded" );
+  const unsigned int TIME_OUT_3_SECONDS = 3;
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, TIME_OUT_3_SECONDS ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+
+  // Ensure texture is deleted when no longer needed (ref count was correct )
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy01 Load a visual image only after attached to stage" );
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::ATTACHED );
+
+  const unsigned int TIME_OUT_3_SECONDS = 3;
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1, TIME_OUT_3_SECONDS ), false, TEST_LOCATION );
+
+  // Act on meeage queue even although nothing expected to load
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture is not generated yet" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), false, TEST_LOCATION );
+  textureTrace.Reset();
+
+  tet_infoline( "Register visuals with control and ensure it has the only handles" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  tet_infoline( "Allow image time to load" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure texture generated and renderer created" );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+
+  // Ensure texture is delete when no longer needed
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.CountMethod("DeleteTextures"), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy03 Load a visual image and receive ResourceReady Signal when loaded" );
+
+  const bool VISUAL_NOT_ENABLED( false ); // Instead of just passing 'false' into an API.
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create a control and connect to resource ready signal without adding to stage" );
+  DummyControl actor = DummyControl::New(true);
+  actor.ResourceReadySignal().Connect( &ResourceReadySignal);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor.SetSize(200.f, 200.f);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE );
+
+  tet_infoline( "Registering visual allows control to get a signal once loaded even if visual not enabled( not staged )" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual, VISUAL_NOT_ENABLED );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  tet_infoline( "Allow image time to load resource" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render();
+
+  // Ensure texture has been uploaded
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy04 First part  Load a visual image before attaching to stage");
+  tet_infoline( "Second part, Reuse the same image in aonther control and check resource ready signal fired" );
+
+  const bool VISUAL_NOT_ENABLED( false ); // Instead of just passing false into an API.
+
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create a control and connect to resource ready signal" );
+  DummyControl actor = DummyControl::New(true);
+  actor.ResourceReadySignal().Connect( &ResourceReadySignal);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor.SetSize(200.f, 200.f);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE );
+
+  tet_infoline( "Registering visual allows control to get a signal once loaded even if visual not enabled( staged )" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual, VISUAL_NOT_ENABLED );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  tet_infoline( "Allow image time to load" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Testing texture is loaded and resource ready signal fired" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  tet_infoline( "Original control correctly signalled, now testing for signal with new Control reusing the image" );
+
+  gResourceReadySignalFired = false; // Reset signal check ready for testing next Control
+  Visual::Base imageVisual2 = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE );
+  DummyControl actor2 = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl2 = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor2.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+  tet_infoline( "Registering visual this should trigger the loading signal as is already image loaded for previous control" );
+  dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual2 );
+  imageVisual2.Reset(); // reduce ref count so only the control keeps the visual alive.
+  actor2.SetSize(200.f, 200.f);
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 0 ), true, TEST_LOCATION ); // Not expecting any further loading as texture is being reused.
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualLoadPolicy05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadPolicy05 LoadPolicy::ATTACHED (default) First part  Load a visual image before attaching to stage");
+  tet_infoline( "Second part, Reuse the same image in aonther control and check resource ready signal fired" );
+  // Set up trace debug
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  tet_infoline( "Create a control and connect to resource ready signal" );
+  DummyControl actor = DummyControl::New(true);
+  actor.ResourceReadySignal().Connect( &ResourceReadySignal);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+
+  tet_infoline( "Create visual with ATTACHED load policy" );
+  Visual::Base imageVisual = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::ATTACHED );
+
+  tet_infoline( "Registering visual allows control to get a signal once loaded" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  imageVisual.Reset(); // reduce ref count so only the control keeps the visual alive.
+
+  tet_infoline( "Allow image time to load" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Testing texture is loaded and resource ready signal fired" );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  tet_infoline( "Original control correctly signalled, now testing for signal with new Control reusing the image" );
+
+  gResourceReadySignalFired = false; // Reset signal check ready for testing next Control
+  Visual::Base imageVisual2 = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::ATTACHED );
+  DummyControl actor2 = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl2 = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor2.ResourceReadySignal().Connect( &ResourceReadySignal);
+
+  tet_infoline( "Registering visual this should trigger the loading signal as is already image loaded for previous control" );
+  dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual2 );
+  imageVisual2.Reset(); // reduce ref count so only the control keeps the visual alive.
+  actor2.SetSize(200.f, 200.f);
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 0 ), true, TEST_LOCATION ); // Not expecting any further loading as texture is being reused.
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliImageVisualOrientationCorrection(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualOrientationCorrection Enabling OrientationCorrection should rotate an image with exif (90deg) orientation data with requested" );
+
+  VisualFactory factory = VisualFactory::Get();
+  tet_infoline( "Create visual with Orientation correction set OFF" );
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_ROTATED_IMAGE );
+  propertyMap.Insert( "orientationCorrection", false );
+  Visual::Base imageVisual = factory.CreateVisual( propertyMap );
+
+  tet_infoline( "Create control for visual, need to loaded it" );
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  Stage::GetCurrent().Add( actor );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Vector2 originalImageSize;
+  tet_infoline( "Get size of original visual to compare later with rotated image" );
+  imageVisual.GetNaturalSize( originalImageSize );
+  DALI_TEST_GREATER( originalImageSize.width, originalImageSize.height, TEST_LOCATION ); // Width and Height must be different for this test.
+  imageVisual.Reset();  // remove handle so can unregister it and remove from cache
+  dummyImpl.UnregisterVisual( DummyControl::Property::TEST_VISUAL );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Create visual with Orientation correction set ON " );
+  propertyMap.Clear();
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_ROTATED_IMAGE );
+  propertyMap.Insert( ImageVisual::Property::ORIENTATION_CORRECTION, true );
+  imageVisual = factory.CreateVisual( propertyMap );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual );
+  // Wait for image to load
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Vector2 rotatedImageSize;
+  imageVisual.GetNaturalSize( rotatedImageSize );
+  tet_infoline( "Confirm that visual has rotated" );
+  DALI_TEST_EQUALS( originalImageSize.width, rotatedImageSize.height , TEST_LOCATION );
+  DALI_TEST_EQUALS( originalImageSize.height, rotatedImageSize.width , TEST_LOCATION );
+
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  // check the Property::ORIENTATION_CORRECTION value from the returned map
+  Property::Value* typeValue = resultMap.Find( ImageVisual::Property::ORIENTATION_CORRECTION,  Property::BOOLEAN );
+  DALI_TEST_EQUALS( typeValue->Get<bool>(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliImageVisualCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualCustomShader Test custom shader" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  Property::Map shader;
+  const std::string vertexShader = "Foobar";
+  const std::string fragmentShader = "Foobar";
+  shader[Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+  shader[Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+  properties[Visual::Property::TYPE] = Visual::IMAGE;
+  properties[Visual::Property::SHADER] = shader;
+  properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  dummy.SetSize( 200.f, 200.f );
+  dummy.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( dummy );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Renderer renderer = dummy.GetRendererAt( 0 );
+  Shader shader2 = renderer.GetShader();
+  Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+  DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+  Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+  DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+
+  shader.Clear();
+
+  shader[Visual::Shader::Property::HINTS] = Shader::Hint::OUTPUT_IS_TRANSPARENT;
+  properties[Visual::Property::SHADER] = shader;
+
+  Visual::Base visual1 = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy1 = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl1 = static_cast< Impl::DummyControl& >( dummy1.GetImplementation() );
+  dummyImpl1.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual1 );
+  dummy1.SetSize( 200, 200 );
+  dummy1.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( dummy1 );
+
+  TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+  glAbstraction.EnableEnableDisableCallTrace( true );
+
+  application.SendNotification();
+  application.Render();
+
+  TraceCallStack& glEnableStack = glAbstraction.GetEnableDisableTrace();
+  std::ostringstream blendStr;
+  blendStr << GL_BLEND;
+  DALI_TEST_CHECK( glEnableStack.FindMethodAndParams( "Enable", blendStr.str().c_str() ) );
+
+  END_TEST;
+}
+
+
+void ResourceReadyLoadNext( Control control )
+{
+  static int callNumber = 0;
+
+  gResourceReadySignalFired = true;
+  gReadyIds.push_back(control.GetId());
+
+  if( callNumber == 0 )
+  {
+    DALI_TEST_EQUALS( control.GetVisualResourceStatus(DummyControl::Property::TEST_VISUAL), Toolkit::Visual::ResourceStatus::FAILED, TEST_LOCATION );
+
+    tet_infoline( "Create visual with loaded image from within the signal handler" );
+    VisualFactory factory = VisualFactory::Get();
+    Visual::Base imageVisual = factory.CreateVisual( TEST_IMAGE_FILE_NAME, ImageDimensions{20,30} );
+
+    Impl::DummyControl& controlImpl = static_cast<Impl::DummyControl&>(control.GetImplementation());
+    controlImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual ); // This should trigger another signal.
+    callNumber = 1;
+  }
+  else
+  {
+    tet_infoline( "3rd signal called" );
+    DALI_TEST_CHECK(true);
+  }
+}
+
+int UtcDaliImageVisualLoadReady01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliImageVisualLoadReady01");
+  tet_infoline( "First part:  Load an image visual for one resource, then another image visual for a second resource.");
+  tet_infoline( "Second part, In the ready signal for the second image visual, add a 3rd visual with the first URL" );
+  tet_infoline( "Should get a ready signal for all three visuals");
+
+  ClearReadyIds();
+
+  tet_infoline( "Create a control and connect to resource ready signal" );
+  DummyControl actor = DummyControl::New(true);
+  int actor1Id = actor.GetId();
+  actor.ResourceReadySignal().Connect( &ResourceReadySignal);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add(actor);
+
+  tet_infoline( "Create visual with IMMEDIATE load policy" );
+  Visual::Base imageVisual1 = CreateVisualWithPolicy( TEST_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE );
+
+  tet_infoline( "Registering visual allows control to get a signal once loaded even if visual not enabled( staged )" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual1 );
+
+
+  tet_infoline( "Allow image time to load" );
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Testing texture is loaded and resource ready signal fired" );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gReadyIds[0], actor1Id, TEST_LOCATION );
+
+
+  tet_infoline( "Original control correctly signalled, now testing failing image" );
+
+  gResourceReadySignalFired = false; // Reset signal check ready for testing next Control
+  ClearReadyIds();
+
+  Visual::Base imageVisual2 = CreateVisualWithPolicy( TEST_BROKEN_IMAGE_FILE_NAME, ImageVisual::Property::LOAD_POLICY, ImageVisual::LoadPolicy::IMMEDIATE );
+
+  DummyControl actor2 = DummyControl::New(true);
+  int actor2Id = actor2.GetId();
+  Impl::DummyControl& dummyImpl2 = static_cast<Impl::DummyControl&>(actor2.GetImplementation());
+  actor2.ResourceReadySignal().Connect( &ResourceReadyLoadNext);
+
+  tet_infoline( "Registering visual this should trigger the ready signal when the image fails to load" );
+  dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, imageVisual2 );
+
+  actor2.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add(actor2);
+
+  tet_infoline( "Wait for loading thread to finish");
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( gResourceReadySignalFired, true, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( gReadyIds[0], actor2Id, TEST_LOCATION);
+
+  tet_infoline( "Check for 3rd signal");
+  application.SendNotification();
+  DALI_TEST_EQUALS( gReadyIds.size(), 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( gReadyIds[1], actor2Id, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ItemLayout.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ItemLayout.cpp
new file mode 100755 (executable)
index 0000000..4098d72
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+const unsigned int TOTAL_ITEM_NUMBER = 200;
+const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
+
+
+// Implementation of ItemFactory for providing actors to ItemView
+class TestItemFactory : public ItemFactory
+{
+public:
+
+  /**
+   * Constructor
+   * @param application class, stored as reference
+   */
+  TestItemFactory()
+  {
+  }
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~TestItemFactory()
+  {
+  }
+
+public: // From ItemFactory
+
+  /**
+   * Query the number of items available from the factory.
+   * The maximum available item has an ID of GetNumberOfItems() - 1.
+   */
+  virtual unsigned int GetNumberOfItems()
+  {
+    return TOTAL_ITEM_NUMBER;
+  }
+
+  /**
+   * Create an Actor to represent a visible item.
+   * @param itemId
+   * @return the created actor.
+   */
+  virtual Actor NewItem(unsigned int itemId)
+  {
+    // Create a renderable actor for this item
+    Image image = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+    Actor actor = CreateRenderableActor(image);
+
+    return actor;
+  }
+};
+
+class TestItemLayout;
+
+typedef IntrusivePtr<TestItemLayout> TestItemLayoutPtr;
+
+// Implementation of ItemLayout
+class TestItemLayout : public ItemLayout
+{
+public:
+
+  /**
+   * Constructor
+   */
+  TestItemLayout()
+  {
+  }
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~TestItemLayout()
+  {
+  }
+
+  /**
+   * Create a new grid layout.
+   */
+  static TestItemLayoutPtr New()
+  {
+    return TestItemLayoutPtr(new TestItemLayout());
+  }
+
+public: // From ItemLayout
+
+  /**
+   * Query the minimum valid layout position; this is a negative value.
+   *
+   * When scrolling, the first item will move within the range 0 to GetMinimumLayoutPosition().
+   * @param[in] numberOfItems The current number of items in the layout.
+   * @param[in] layoutSize The size of the layout area.
+   * @return The minimum layout position.
+   */
+  virtual float GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
+  {
+    return 0.0f;
+  }
+
+  /**
+   * Query the closest anchor position for the given layout position.
+   *
+   * This anchor position is the position where all the items in the layout are aligned to
+   * their rounded layout positions in integer.
+   * @param[in] layoutPosition The layout position.
+   * @return The closest anchor position for the given layout position.
+   */
+  virtual float GetClosestAnchorPosition(float layoutPosition) const
+  {
+    return 0.0f;
+  }
+
+  /**
+   * Query the layout position for the first item in the layout to move to when the layout
+   * needs to scroll to a particular item.
+   *
+   * @param[in] itemId The ID of an item in the layout.
+   * @return The layout position for the first item in the layout to move to.
+   */
+  virtual float GetItemScrollToPosition(unsigned int itemId) const
+  {
+    return 0.0f;
+  }
+
+  /**
+   * Query the items within a given layout-area.
+   *
+   * @param[in] firstItemPosition The layout-position of the first item in the layout.
+   * @param[in] layoutSize The size of the layout area.
+   * @return The ID of the first & last visible item.
+   */
+  virtual ItemRange GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
+  {
+    return ItemRange(0, 10);
+  }
+
+  /**
+   * Query the number of items that should be reserved, for scrolling purposes.
+   *
+   * @param[in] layoutSize The size of the layout area.
+   * @return The number of extra items.
+   */
+  virtual unsigned int GetReserveItemCount(Vector3 layoutSize) const
+  {
+    return 0;
+  }
+
+  /**
+   * Retrieve the default size of an item in the layout.
+   *
+   * @param[in] itemId The ID of an item in the layout.
+   * @param[in] layoutSize The layout size
+   * @param[out] itemSize The target size of an item.
+   */
+  virtual void GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
+  {
+  }
+
+  /**
+   * @brief Query the scroll direction of the layout.
+   * @return The scroll direction in degrees.
+   */
+  virtual Degree GetScrollDirection() const
+  {
+    return Degree( 0.0f );
+  }
+
+  /**
+   * @brief Query the scroll speed factor of the layout while dragging.
+   * @return The scroll speed factor of the layout.
+   */
+  virtual float GetScrollSpeedFactor() const
+  {
+    return 0;
+  }
+
+  /**
+   * @brief Query the maximum swipe speed in pixels per second.
+   * @return speed The maximum swipe speed.
+   */
+  virtual float GetMaximumSwipeSpeed() const
+  {
+    return 0;
+  }
+
+  /**
+   * @brief Get the duration of the flick animation in second.
+   * @return The duration of the flick animation.
+   */
+  virtual float GetItemFlickAnimationDuration() const
+  {
+    return 0;
+  }
+
+  /*
+   * @brief Applies constraints defined by the layout to an actor.
+   *
+   * @param[in] actor The actor to constrain.
+   * @param[in] itemId The ID of the item represented by the actor.
+   * @param[in] layoutSize the current size of the item view instance.
+   * @param[in] itemViewActor The item view instance which requests the application of constraints.
+   */
+  virtual void ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
+  {
+  }
+
+  /**
+   * @brief Gets the position of a given item
+   *
+   * @param[in] itemID id of the item we want to get its position
+   * @param[in] currentLayoutPosition the current layout position of the item view instance
+   * @param[in] layoutSize the current size of the item view instance
+   * @return The item position (x,y,z)
+   */
+  virtual Vector3 GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
+  {
+    return Vector3::ZERO;
+  }
+};
+
+} // namespace
+
+int UtcDaliItemLayoutSetAndGetOrientation(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  // Set the orientation of the layout to be horizontal from left to right
+  ItemLayoutPtr layout = view.GetLayout(0);
+
+  DALI_TEST_CHECK(gridLayout == layout);
+
+  layout->SetOrientation(ControlOrientation::Left);
+
+  // Check the orientation of the layout is horizontal from left to right
+  DALI_TEST_CHECK(layout->GetOrientation() == ControlOrientation::Left);
+
+  Vector3 itemSize(100.0f, 100.0f, 100.0f);
+  layout->SetItemSize(itemSize);
+
+  Vector3 itemSize1;
+  layout->GetItemSize(0u, Vector3(Stage::GetCurrent().GetSize()), itemSize1);
+
+  DALI_TEST_CHECK(itemSize == itemSize1);
+
+  float position = layout->GetClosestOnScreenLayoutPosition(0, 0.0f, Vector3(Stage::GetCurrent().GetSize()));
+
+  DALI_TEST_EQUALS(position, 0.0f, TEST_LOCATION);
+
+  int focusItem = layout->GetNextFocusItemID(0, TOTAL_ITEM_NUMBER, Control::KeyboardFocus::LEFT, true);
+
+  DALI_TEST_CHECK(focusItem != 0);
+
+  float flickSpeedFactor = layout->GetFlickSpeedFactor();
+
+  DALI_TEST_CHECK(flickSpeedFactor != 0.0f);
+
+  // White box test here: -( itemId / NoOfItemsPerRow(default 4) ) * NoOfItemsPerRow
+  DALI_TEST_EQUALS( -1.0f, gridLayout->GetItemScrollToPosition( 1 ), TEST_LOCATION );
+
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+  view.AddLayout(*depthLayout);
+
+  layout = view.GetLayout(1);
+  DALI_TEST_CHECK(depthLayout == layout);
+
+  ItemLayoutPtr listLayout = DefaultItemLayout::New( DefaultItemLayout::LIST );
+  view.AddLayout(*listLayout);
+
+  layout = view.GetLayout(2);
+  DALI_TEST_CHECK(listLayout == layout);
+
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  view.AddLayout(*spiralLayout);
+
+  layout = view.GetLayout(3);
+  DALI_TEST_CHECK(spiralLayout == layout);
+  END_TEST;
+}
+
+int UtcDaliItemLayoutGetExtension(void)
+{
+  ToolkitTestApplication application;
+
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  DALI_TEST_CHECK( gridLayout );
+  DALI_TEST_CHECK( !gridLayout->GetExtension() );
+
+  END_TEST;
+}
+
+int UtcDaliItemLayoutGetClosestOnScreenLayoutPosition(void)
+{
+  ToolkitTestApplication application;
+
+  TestItemLayoutPtr layout = TestItemLayout::New();
+  DALI_TEST_CHECK( layout );
+  DALI_TEST_EQUALS(layout->GetClosestOnScreenLayoutPosition(0, 0.0f, Vector3::ZERO), 0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS(layout->GetClosestOnScreenLayoutPosition(0, 0.0f, Vector3(-800.0f, -1200.0f, 0.0f)), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliItemLayoutGetNextFocusItemID(void)
+{
+  ToolkitTestApplication application;
+
+  TestItemLayoutPtr layout = TestItemLayout::New();
+  DALI_TEST_CHECK( layout );
+  DALI_TEST_EQUALS(layout->GetNextFocusItemID(0, 100, Control::KeyboardFocus::LEFT, true), 99, TEST_LOCATION );
+  DALI_TEST_EQUALS(layout->GetNextFocusItemID(110, 100, Control::KeyboardFocus::RIGHT, true), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliItemLayoutSetAndGetLayoutProperties(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+
+  // Set the property of the grid layout
+  Property::Map gridLayoutProperty;
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::GRID) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::ITEM_SIZE, Dali::Property::Value(Vector3(200, 200,50)) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_ROW_SPACING, Dali::Property::Value(50.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_COLUMN_NUMBER, Dali::Property::Value(4) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_COLUMN_SPACING, Dali::Property::Value(50.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_TOP_MARGIN, Dali::Property::Value(95.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_BOTTOM_MARGIN, Dali::Property::Value(20.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_SIDE_MARGIN, Dali::Property::Value(20.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_SCROLL_SPEED_FACTOR, Dali::Property::Value(0.03f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_ITEM_FLICK_ANIMATION_DURATION, Dali::Property::Value(0.015f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_MAXIMUM_SWIPE_SPEED, Dali::Property::Value(100.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::ORIENTATION, Dali::Property::Value((int)ControlOrientation::Up) );
+  gridLayout->SetLayoutProperties(gridLayoutProperty);
+
+  view.AddLayout(*gridLayout);
+  ItemLayoutPtr layout = view.GetLayout(0);
+  DALI_TEST_CHECK(gridLayout == layout);
+  Property::Map firstLayout = gridLayout->GetLayoutProperties();
+
+  //Check all the properties of grid layout
+  DALI_TEST_EQUALS( gridLayoutProperty.Count(), firstLayout.Count(), TEST_LOCATION );
+
+  for( unsigned int mapIdx = 0, mapCount = firstLayout.Count(); mapIdx < mapCount; ++mapIdx )
+  {
+    KeyValuePair propertyPair( firstLayout.GetKeyValue( mapIdx ) );
+    if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+    {
+      int layoutType = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS( layoutType, (int)DefaultItemLayout::GRID, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::ITEM_SIZE)
+    {
+      Vector3 size = propertyPair.second.Get<Vector3>();
+      DALI_TEST_EQUALS( size, Vector3(200, 200,50), TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_ROW_SPACING)
+    {
+      float rowSpacing = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS( rowSpacing, 50.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_COLUMN_NUMBER)
+    {
+      int number = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS(number, 4, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_COLUMN_SPACING)
+    {
+      float columnSpacing = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(columnSpacing, 50.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_TOP_MARGIN)
+    {
+      float topMargin = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(topMargin, 95.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_BOTTOM_MARGIN)
+    {
+      float bottomMargin = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(bottomMargin, 20.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_SIDE_MARGIN)
+    {
+      float sideMargin = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(sideMargin, 20.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_SCROLL_SPEED_FACTOR)
+    {
+      float scrollSpeedFactor = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(scrollSpeedFactor, 0.03f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_ITEM_FLICK_ANIMATION_DURATION)
+    {
+      float animationDuration = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(animationDuration, 0.015f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_MAXIMUM_SWIPE_SPEED)
+    {
+      float swipSpeed = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(swipSpeed, 100.0f, TEST_LOCATION );
+    }
+  }
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+
+  // Set the property of the depth layout
+  Property::Map depthLayoutProperty;
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::DEPTH) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_COLUMN_NUMBER, Dali::Property::Value(3) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_ROW_NUMBER, Dali::Property::Value(26.0f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_ROW_SPACING, Dali::Property::Value(55.0f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_TILT_ANGLE, Dali::Property::Value(Math::PI*0.15f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_ITEM_TILT_ANGLE, Dali::Property::Value(-Math::PI*0.025f ) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_SCROLL_SPEED_FACTOR, Dali::Property::Value(0.02f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_ITEM_FLICK_ANIMATION_DURATION, Dali::Property::Value(0.03f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_MAXIMUM_SWIPE_SPEED, Dali::Property::Value(50.0f) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::ORIENTATION, Dali::Property::Value((int)ControlOrientation::Up) );
+  depthLayout->SetLayoutProperties(depthLayoutProperty);
+
+  view.AddLayout(*depthLayout);
+  layout = view.GetLayout(1);
+  DALI_TEST_CHECK(depthLayout == layout);
+
+  Property::Map secondLayout = depthLayout->GetLayoutProperties();
+
+  //Check all the properties of grid layout
+  DALI_TEST_EQUALS( depthLayoutProperty.Count(), secondLayout.Count(), TEST_LOCATION );
+  for( unsigned int mapIdx = 0, mapCount = secondLayout.Count(); mapIdx < mapCount; ++mapIdx )
+  {
+    KeyValuePair propertyPair( secondLayout.GetKeyValue( mapIdx ) );
+    if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+    {
+      int layoutType = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS( layoutType, (int)DefaultItemLayout::DEPTH, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::ORIENTATION)
+    {
+      int orientation = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS(orientation, (int)ControlOrientation::Up, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::ITEM_SIZE)
+    {
+      Vector3 size = propertyPair.second.Get<Vector3>();
+      DALI_TEST_EQUALS( size, Vector3(200, 200,50), TEST_LOCATION );
+    }
+
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_COLUMN_NUMBER)
+    {
+      int columnNumber = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS( columnNumber, 3, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_ROW_NUMBER)
+    {
+      float rowNumber = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(rowNumber, 26.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_ROW_SPACING)
+    {
+      float rowSpacing = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(rowSpacing, 55.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_TILT_ANGLE)
+    {
+      float tiltAngle = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(tiltAngle, Math::PI*0.15f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_ITEM_TILT_ANGLE)
+    {
+      float itemTiltAngle = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(itemTiltAngle, -Math::PI*0.025f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_SCROLL_SPEED_FACTOR)
+    {
+      float scrollSpeedFactor = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(scrollSpeedFactor, 0.02f, TEST_LOCATION );
+    }
+
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_ITEM_FLICK_ANIMATION_DURATION)
+    {
+      float animationDuration = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(animationDuration, 0.03f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::DEPTH_MAXIMUM_SWIPE_SPEED)
+    {
+      float swipSpeed = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(swipSpeed, 50.0f, TEST_LOCATION );
+    }
+  }
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+
+  // Set the property of the spiral layout
+  Property::Map spiralLayoutPrperty;
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::SPIRAL) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING, Dali::Property::Value((Math::PI*2.0f)/9.5f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT, Dali::Property::Value(-0.125f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_REVOLUTION_DISTANCE, Dali::Property::Value(190.0f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_SCROLL_SPEED_FACTOR, Dali::Property::Value(0.01f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_ITEM_FLICK_ANIMATION_DURATION, Dali::Property::Value(0.1f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_MAXIMUM_SWIPE_SPEED, Dali::Property::Value(30.0f) );
+  spiralLayout->SetLayoutProperties(spiralLayoutPrperty);
+
+  view.AddLayout(*spiralLayout);
+  layout = view.GetLayout(2);
+  DALI_TEST_CHECK(spiralLayout == layout);
+
+  Property::Map thridLayout = spiralLayout->GetLayoutProperties();
+
+  //Check all the properties of grid layout
+  DALI_TEST_EQUALS( spiralLayoutPrperty.Count(), thridLayout.Count(), TEST_LOCATION );
+
+  for( unsigned int mapIdx = 0, mapCount = thridLayout.Count(); mapIdx < mapCount; ++mapIdx )
+  {
+    KeyValuePair propertyPair( thridLayout.GetKeyValue( mapIdx ) );
+    if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+    {
+      int layoutType = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS( layoutType, (int)DefaultItemLayout::SPIRAL, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING)
+    {
+      float columnNumber = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS( columnNumber, (Math::PI*2.0f)/9.5f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT)
+    {
+      float rowNumber = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(rowNumber, -0.125f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_REVOLUTION_DISTANCE)
+    {
+      float rowSpacing = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(rowSpacing, 190.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_SCROLL_SPEED_FACTOR)
+    {
+      float scrollSpeedFactor = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(scrollSpeedFactor, 0.01f, TEST_LOCATION );
+    }
+
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_ITEM_FLICK_ANIMATION_DURATION)
+    {
+      float animationDuration = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(animationDuration, 0.1f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::SPIRAL_MAXIMUM_SWIPE_SPEED)
+    {
+      float swipSpeed = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS(swipSpeed, 30.0f, TEST_LOCATION );
+    }
+  }
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Vector3 stageSize(stage.GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+  view.ActivateLayout(1, stageSize, 0.5f);
+  view.ActivateLayout(2, stageSize, 0.5f);
+  END_TEST;
+
+}
+
+int UtcDaliItemRangeIntersection(void)
+{
+  ToolkitTestApplication application;
+
+  unsigned int uBeginItemFirst = 100u, uEndItemFirst = 300u;
+  unsigned int uBeginItemSecond = 290u, uEndItemSecond = 400;
+  unsigned int uInterBeginCheck=290u , uInterEndCheck=301u;
+  bool bIsInThisRange = false, bOutOfThisRange = false;
+
+  Toolkit::ItemRange objItemRangeFirst(uBeginItemFirst, uEndItemFirst);
+  Toolkit::ItemRange objItemRangeSecond(uBeginItemSecond, uEndItemSecond);
+  ItemRange itmInterSect = objItemRangeFirst.Intersection(objItemRangeSecond);
+
+  bIsInThisRange = itmInterSect.Within(uInterBeginCheck);
+  DALI_TEST_EQUALS(bIsInThisRange, true, TEST_LOCATION );
+
+  bOutOfThisRange = itmInterSect.Within(uInterEndCheck);
+  DALI_TEST_EQUALS(bOutOfThisRange, false, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ItemView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ItemView.cpp
new file mode 100755 (executable)
index 0000000..4891370
--- /dev/null
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (c) 2019 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 <float.h>       // for FLT_MAX
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_item_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_item_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const unsigned int TOTAL_ITEM_NUMBER = 400;
+const char* TEST_IMAGE_FILE_NAME = "gallery_image_01.jpg";
+
+const int RENDER_FRAME_INTERVAL = 16;                     ///< Duration of each frame in ms. (at approx 60FPS)
+
+static bool gObjectCreatedCallBackCalled;
+static bool gOnLayoutActivatedCalled;                     ///< Whether the LayoutActivated signal was invoked.
+static bool gOnScrollUpdateCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+static void OnLayoutActivated()
+{
+  gOnLayoutActivatedCalled = true;
+}
+
+static void OnScrollUpdate( const Vector2& position )
+{
+  gOnScrollUpdateCalled = true;
+}
+
+Integration::TouchEvent GenerateSingleTouch( PointState::Type state, const Vector2& screenPosition, uint32_t time )
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( state );
+  point.SetDeviceId(4);
+  point.SetScreenPosition( screenPosition );
+  point.SetDeviceClass( Device::Class::TOUCH );
+  point.SetDeviceSubclass( Device::Subclass::NONE );
+  touchEvent.points.push_back( point );
+  touchEvent.time = time;
+  return touchEvent;
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+// Implementation of ItemFactory for providing actors to ItemView
+class TestItemFactory : public ItemFactory
+{
+public:
+
+  /**
+   * Constructor
+   * @param application class, stored as reference
+   */
+  TestItemFactory()
+  {
+  }
+
+public: // From ItemFactory
+
+  /**
+   * Query the number of items available from the factory.
+   * The maximum available item has an ID of GetNumberOfItems() - 1.
+   */
+  virtual unsigned int GetNumberOfItems()
+  {
+    return TOTAL_ITEM_NUMBER;
+  }
+
+  /**
+   * Create an Actor to represent a visible item.
+   * @param itemId
+   * @return the created actor.
+   */
+  virtual Actor NewItem(unsigned int itemId)
+  {
+    // Create a renderable actor for this item
+    Image image = ResourceImage::New( TEST_IMAGE_FILE_NAME );
+    Actor actor = CreateRenderableActor(image);
+
+    return actor;
+  }
+};
+
+} // namespace
+
+
+int UtcDaliItemViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  DALI_TEST_CHECK(view);
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect(&TestCallback);
+  {
+    TestItemFactory factory;
+    ItemView view = ItemView::New(factory);
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliItemViewDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  const ItemView itemViewConst = ItemView::New(factory);
+  ItemView itemView(itemViewConst);
+
+  BaseHandle handle(itemView);
+
+  ItemView newItemView = ItemView::DownCast( handle );
+  DALI_TEST_CHECK( itemView );
+  DALI_TEST_CHECK( newItemView == itemView );
+  END_TEST;
+}
+
+int UtcDaliItemViewAddAndGetLayout(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  // As we have added one layout, check the number of layout is now 1
+  DALI_TEST_CHECK(view.GetLayoutCount() == 1);
+
+  // Create a depth layout and add it to ItemView
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+  view.AddLayout(*depthLayout);
+
+  // As we have added another layout, check the number of layout is now 2
+  DALI_TEST_CHECK(view.GetLayoutCount() == 2);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  view.AddLayout(*spiralLayout);
+
+  // As we have added another layout, check the number of layout is now 3
+  DALI_TEST_CHECK(view.GetLayoutCount() == 3);
+
+  // Check we are getting the correct layout from ItemView
+  DALI_TEST_CHECK(view.GetLayout(0) == gridLayout);
+  DALI_TEST_CHECK(view.GetLayout(1) == depthLayout);
+  DALI_TEST_CHECK(view.GetLayout(2) == spiralLayout);
+  END_TEST;
+}
+
+int UtcDaliItemViewAddAndRemoveLayout(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  // As we have added one layout, check the number of layout is now 1
+  DALI_TEST_CHECK(view.GetLayoutCount() == 1);
+
+  // Create a depth layout and add it to ItemView
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+  view.AddLayout(*depthLayout);
+
+  // As we have added another layout, check the number of layout is now 2
+  DALI_TEST_CHECK(view.GetLayoutCount() == 2);
+
+  // Check we are getting the correct layout from ItemView
+  DALI_TEST_CHECK(view.GetLayout(0) == gridLayout);
+  DALI_TEST_CHECK(view.GetLayout(1) == depthLayout);
+
+  // Remove the grid layout
+  view.RemoveLayout(0);
+
+  // As we have removed the grid layout, check the number of layout is now 1
+  DALI_TEST_CHECK(view.GetLayoutCount() == 1);
+
+  // Check we are getting the correct layout from ItemView
+  DALI_TEST_CHECK(view.GetLayout(0) == depthLayout);
+
+  // Remove the depth layout
+  view.RemoveLayout(0);
+
+  // As we also removed the depth layout, check the number of layout is now 0
+  DALI_TEST_CHECK(view.GetLayoutCount() == 0);
+  END_TEST;
+}
+
+int UtcDaliItemViewActivateLayoutAndGetActiveLayout(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  // Create a depth layout and add it to ItemView
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+  view.AddLayout(*depthLayout);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  view.AddLayout(*spiralLayout);
+
+  // As we have added three layouts, check the number of layout is now 3
+  DALI_TEST_CHECK(view.GetLayoutCount() == 3);
+
+  // Check there is no active layout at the moment
+  DALI_TEST_CHECK(view.GetActiveLayout() == NULL);
+
+  // Activate the depth layout
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(1, stageSize, 0.5f);
+
+  // Check the current active layout is the depth layout
+  DALI_TEST_CHECK(view.GetActiveLayout() == depthLayout);
+
+  // Activate the grid layout
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  // Check the current active layout is the grid layout
+  DALI_TEST_CHECK(view.GetActiveLayout() == gridLayout);
+
+  // Activate the spiral layout
+  view.ActivateLayout(2, stageSize, 0.5f);
+
+  // Check the current active layout is the spiral layout
+  DALI_TEST_CHECK(view.GetActiveLayout() == spiralLayout);
+  END_TEST;
+}
+
+int UtcDaliItemViewDeactivateCurrentLayout(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  gridLayout->SetOrientation(ControlOrientation::Down);
+  view.AddLayout(*gridLayout);
+
+  // Check there is no active layout at the moment
+  DALI_TEST_CHECK(view.GetActiveLayout() == NULL);
+
+  // Activate the grid layout
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  // Check the current active layout is the grid layout
+  DALI_TEST_CHECK(view.GetActiveLayout() == gridLayout);
+
+  // Deactivate the current layout
+  view.DeactivateCurrentLayout();
+
+  // Check there is no active layout at the moment
+  DALI_TEST_CHECK(view.GetActiveLayout() == NULL);
+  END_TEST;
+}
+
+int UtcDaliItemViewGetItemAndGetItemId(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  gridLayout->SetOrientation(ControlOrientation::Left);
+  view.AddLayout(*gridLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  // Get the item given the item ID
+  Actor itemActor = view.GetItem(2);
+
+  // Check we are getting the correct Item ID given the specified actor
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 2);
+  END_TEST;
+}
+
+int UtcDaliItemViewRemoveItem(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  gridLayout->SetOrientation(ControlOrientation::Right);
+  view.AddLayout(*gridLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  // Get the item given the item ID 2 and 3
+  Actor oldItemActorID2 = view.GetItem(2);
+  Actor oldItemActorID3 = view.GetItem(3);
+
+  // Remove the item with ID 2
+  view.RemoveItem(2, 0.0f);
+
+  // Get the new item given the item ID 2 and 3
+  Actor newItemActorID2 = view.GetItem(2);
+  Actor newItemActorID3 = view.GetItem(3);
+
+  // Check the original item with item ID 2 was deleted and now item ID 2 represents the original item with ID 3
+  DALI_TEST_CHECK(view.GetItemId(newItemActorID2) == 2);
+  DALI_TEST_CHECK(oldItemActorID2 != newItemActorID2);
+  DALI_TEST_CHECK(newItemActorID2 == oldItemActorID3);
+
+  // scroll to the end of item view
+  view.ScrollToItem(TOTAL_ITEM_NUMBER - 1, 0.00f);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Refresh the item view
+  view.Refresh();
+
+  Actor itemActorID390 = view.GetItem(390);
+  DALI_TEST_CHECK(view.GetItemId(itemActorID390) == 390);
+
+  // Remove the item with ID 2 (which is now before the current item range)
+  view.RemoveItem(2, 0.0f);
+
+  // Check the original item with item ID 2 was deleted and now item ID 389 represents the original item with ID 390
+  DALI_TEST_CHECK(view.GetItemId(itemActorID390) == 389);
+  DALI_TEST_CHECK(view.GetItem(389) == itemActorID390);
+
+  END_TEST;
+}
+
+int UtcDaliItemViewGetCurrentLayoutPosition(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a depth layout and add it to ItemView
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+  depthLayout->SetOrientation(ControlOrientation::Up);
+  view.AddLayout(*depthLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.0f);
+
+  // Check the current layout position for the 10th items is 9.0f
+  DALI_TEST_EQUALS(view.GetCurrentLayoutPosition(9), 9.0f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetMinimumSwipeSpeed(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Set the minimum swipe speed to be 1.5f
+  view.SetMinimumSwipeSpeed(1.5f);
+
+  // Check the minimum swipe speed is 1.5f
+  DALI_TEST_EQUALS(view.GetMinimumSwipeSpeed(), 1.5f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetMinimumSwipeDistance(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Set the minimum swipe distance to be 2.5f
+  view.SetMinimumSwipeDistance(2.5f);
+
+  // Check the minimum swipe distance is 2.5f
+  DALI_TEST_EQUALS(view.GetMinimumSwipeDistance(), 2.5f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetAnchoring(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Disable the anchor animation
+  view.SetAnchoring(false);
+
+  // Check the anchor animation is disabled
+  DALI_TEST_CHECK(view.GetAnchoring() == false);
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetAnchoringDuration(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Set the duration of anchor animation to be 1.5f
+  view.SetAnchoringDuration(1.5f);
+
+  // Check the duration of anchor animation is 1.5f
+  DALI_TEST_EQUALS(view.GetAnchoringDuration(), 1.5f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetRefreshInterval(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Set the interval between refreshes to be 20
+  view.SetRefreshInterval(20);
+
+  view.Refresh();
+
+  // Check the interval between refreshes is 20
+  DALI_TEST_CHECK(view.GetRefreshInterval() == 20);
+  END_TEST;
+}
+
+int UtcDaliItemViewScrollToItem(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+  Vector3 vec(480.0f, 800.0f, 0.0f);
+  ItemLayoutPtr layout = DefaultItemLayout::New( DefaultItemLayout::DEPTH );
+
+  view.SetName("view actor");
+  view.AddLayout(*layout);
+  view.SetSize(vec);
+
+  Stage::GetCurrent().Add(view);
+  layout->SetOrientation(ControlOrientation::Down);
+  view.ActivateLayout(0, vec, 0.0f);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // render 10 frames
+  for(int i = 0; i < 10; ++i)
+  {
+    application.Render(16); // 60hz frames
+  }
+
+  // Confirm: we have actors in the view.
+  std::vector<unsigned int> indices;
+  for(unsigned int i = 0; i < 10; i++)
+  {
+    Actor testActor = view.GetItem(i);
+    if (testActor)
+    {
+      indices.push_back(i);
+    }
+  }
+
+  try
+  {
+    if (!indices.empty())
+    {
+      const unsigned int firstTargetIndex = indices[indices.size()-1];
+      // scroll to last item
+      view.ScrollToItem(firstTargetIndex, 0.00f);
+      for(int i = 0; i < 10; ++i)
+      {
+        application.Render(16); // 60hz frames
+      }
+
+      std::size_t moveCount = 0;
+      for(std::size_t i = 0; i < indices.size(); i++)
+      {
+        float layoutPosBefore = view.GetCurrentLayoutPosition(i);
+        view.ScrollToItem(indices[i], 0.0f);
+        float layoutPosAfter = view.GetCurrentLayoutPosition(i);
+
+        if (fabs(layoutPosBefore-layoutPosAfter) <= FLT_EPSILON)
+        {
+          ++moveCount;
+        }
+      }
+
+      DALI_TEST_CHECK((moveCount == indices.size()));
+    }
+  }
+  catch(...)
+  {
+    tet_result(TET_FAIL);
+  }
+
+  Stage::GetCurrent().Remove(view);
+  END_TEST;
+}
+
+int UtcDaliItemViewSetAndGetWheelScrollDistanceStep(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Set the scroll distance step for the wheel event to be 100.0f
+  view.SetWheelScrollDistanceStep(100.0f);
+
+  // Check the scroll distance step is 100.0f
+  DALI_TEST_EQUALS(view.GetWheelScrollDistanceStep(), 100.0f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliItemViewInsertItemP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID);
+  gridLayout->SetOrientation(ControlOrientation::Left);
+  view.AddLayout(*gridLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.0f);
+
+  // Get the specified item where new item to be inserted before that
+  Actor itemActor = view.GetItem(2);
+
+  ItemId id = view.GetItemId( itemActor );
+
+  // Check we are getting the correct Item ID given the specified actor
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 2);
+
+  Actor newActor = Actor::New();
+
+  view.InsertItem(Item(id, newActor), 0.0f);
+
+  DALI_TEST_CHECK(view.GetItem(2) == newActor);
+
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 3);
+  DALI_TEST_CHECK(view.GetItem(3) == itemActor);
+
+  // scroll to the end of item view
+  view.ScrollToItem(TOTAL_ITEM_NUMBER - 1, 0.00f);
+
+  application.SendNotification();
+  application.Render(0);
+
+  // Refresh the item view
+  view.Refresh();
+
+  Actor itemActorID390 = view.GetItem(390);
+  DALI_TEST_CHECK(view.GetItemId(itemActorID390) == 390);
+
+  // Insert the item with ID 2 (which is now before the current item range)
+  Actor anotherNewActor = Actor::New();
+  view.InsertItem(Item(id, anotherNewActor), 0.0f);
+
+  // Check that item ID 391 now represents the original item with ID 390
+  DALI_TEST_CHECK(view.GetItemId(itemActorID390) == 391);
+  DALI_TEST_CHECK(view.GetItem(391) == itemActorID390);
+
+  END_TEST;
+}
+
+int UtcDaliItemViewInsertItemsP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a depth layout and add it to ItemView
+  ItemLayoutPtr depthLayout = DefaultItemLayout::New( DefaultItemLayout::DEPTH);
+  depthLayout->SetOrientation(ControlOrientation::Right);
+  view.AddLayout(*depthLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  unsigned int itemCount = view.GetChildCount();
+
+  // Get the specified item where new items to be inserted before that
+  Actor itemActor = view.GetItem(1);
+
+  // Check we are getting the correct Item ID given the specified item
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 1);
+
+  ItemContainer insertList;
+
+  for( unsigned int i = 1u; i < 11; ++i )
+  {
+    Actor child = view.GetChildAt( i );
+    Actor newActor = Actor::New();
+    newActor.SetName("Inserted");
+    insertList.push_back( Item( view.GetItemId(child), newActor ) );
+  }
+
+  if( !insertList.empty() )
+  {
+    view.InsertItems( insertList, 0.5f );
+  }
+
+  DALI_TEST_CHECK(view.GetChildCount() == itemCount + 10);
+
+  // Check that new items are inserted in the correct positions
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 11);
+  DALI_TEST_CHECK(view.GetItem(11) == itemActor);
+
+  ItemIdContainer removeList;
+
+  for( unsigned int i = 0u; i < view.GetChildCount(); ++i )
+  {
+    Actor child = view.GetChildAt( i );
+
+    if( child.GetName() == "Inserted" )
+    {
+      removeList.push_back( view.GetItemId(child) );
+    }
+  }
+
+  if( ! removeList.empty() )
+  {
+    view.RemoveItems( removeList, 0.5f );
+  }
+
+  DALI_TEST_CHECK(view.GetChildCount() == itemCount);
+
+  // Check that new items are removed correctly so that we are getting the correct Item ID given the specified item
+  DALI_TEST_CHECK(view.GetItemId(itemActor) == 1);
+  DALI_TEST_CHECK(view.GetItem(1) == itemActor);
+
+  END_TEST;
+}
+
+int UtcDaliItemViewReplaceItemP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  view.AddLayout(*spiralLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  Actor newActor = Actor::New();
+
+  view.ReplaceItem( Item( 5, newActor ), 0.5f );
+
+  DALI_TEST_CHECK(view.GetItem(5) == newActor);
+
+  END_TEST;
+}
+
+int UtcDaliItemViewReplaceItemsP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  spiralLayout->SetOrientation( ControlOrientation::Down );
+  view.AddLayout(*spiralLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  ItemContainer replaceList;
+
+  for( unsigned int i = 0u; i < 10; ++i )
+  {
+    Actor child = view.GetItem( i );
+    Actor newActor = Actor::New();
+    newActor.SetName("Replaced");
+
+    replaceList.push_back( Item( i, newActor ) );
+  }
+
+  if( !replaceList.empty() )
+  {
+    view.ReplaceItems( replaceList, 0.5f );
+  }
+
+  DALI_TEST_CHECK(view.GetItem(0).GetName() == "Replaced");
+  DALI_TEST_CHECK(view.GetItem(8).GetName() == "Replaced");
+  END_TEST;
+}
+
+int UtcDaliItemViewGetItemsRangeP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  spiralLayout->SetOrientation( ControlOrientation::Left );
+  view.AddLayout(*spiralLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  ItemRange itemRange(0, 0);
+
+  view.GetItemsRange(itemRange);
+
+  DALI_TEST_CHECK(itemRange.Within(0));
+  END_TEST;
+}
+
+int UtcDaliItemViewSetItemsAnchorPointP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a spiral layout and add it to ItemView
+  ItemLayoutPtr spiralLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  spiralLayout->SetOrientation( ControlOrientation::Right );
+  view.AddLayout(*spiralLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  Vector3 anchorPoint(10.0f, 10.0f, 0.0f);
+
+  view.SetItemsAnchorPoint(anchorPoint);
+
+  DALI_TEST_CHECK(view.GetItemsAnchorPoint() == anchorPoint);
+  DALI_TEST_CHECK(view.GetItem(0).GetCurrentAnchorPoint() == anchorPoint);
+  END_TEST;
+}
+
+int UtcDaliItemViewSetItemsParentOriginP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  Vector3 parentOrigin(10.0f, 10.0f, 0.0f);
+
+  view.SetItemsParentOrigin(parentOrigin);
+
+  DALI_TEST_CHECK(view.GetItemsParentOrigin() == parentOrigin);
+  DALI_TEST_CHECK(view.GetItem(0).GetCurrentParentOrigin() == parentOrigin);
+  END_TEST;
+}
+
+int UtcDaliItemFactoryGetExtention(void)
+{
+  ToolkitTestApplication application;
+  TestItemFactory factory;
+  DALI_TEST_CHECK( factory.GetExtension() == NULL );
+  END_TEST;
+}
+
+int UtcDaliItemViewLayoutActivatedSignalP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+
+  Stage::GetCurrent().Add( view );
+
+  // Connect the layout activated signal
+  view.LayoutActivatedSignal().Connect( &OnLayoutActivated );
+
+  gOnLayoutActivatedCalled = false;
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(Dali::Stage::GetCurrent().GetSize());
+  view.ActivateLayout(0, stageSize, 0.1f);
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  DALI_TEST_EQUALS( gOnLayoutActivatedCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliItemViewSetGetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+  DALI_TEST_CHECK(view);
+
+  // Event side properties
+
+  // Test "minimumSwipeSpeed" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("minimumSwipeSpeed") == ItemView::Property::MINIMUM_SWIPE_SPEED  );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::MINIMUM_SWIPE_SPEED).Get<float>(), view.GetMinimumSwipeSpeed(), TEST_LOCATION );
+  view.SetProperty( ItemView::Property::MINIMUM_SWIPE_SPEED, 2.5f );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::MINIMUM_SWIPE_SPEED).Get<float>(), 2.5f, TEST_LOCATION );
+
+  // Test "minimumSwipeDistance" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("minimumSwipeDistance") == ItemView::Property::MINIMUM_SWIPE_DISTANCE  );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::MINIMUM_SWIPE_DISTANCE).Get<float>(), view.GetMinimumSwipeDistance(), TEST_LOCATION );
+  view.SetProperty( ItemView::Property::MINIMUM_SWIPE_DISTANCE, 8.725f );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::MINIMUM_SWIPE_DISTANCE).Get<float>(), 8.725f, TEST_LOCATION );
+
+  // Test "wheelScrollDistanceStep" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("wheelScrollDistanceStep") == ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP  );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP).Get<float>(), view.GetWheelScrollDistanceStep(), TEST_LOCATION );
+  view.SetProperty( ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP, 5.0f );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP).Get<float>(), 5.0f, TEST_LOCATION );
+
+  // Test "snapToItemEnabled" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("snapToItemEnabled") == ItemView::Property::SNAP_TO_ITEM_ENABLED  );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::SNAP_TO_ITEM_ENABLED).Get<bool>(), view.GetAnchoring(), TEST_LOCATION );
+  view.SetProperty( ItemView::Property::SNAP_TO_ITEM_ENABLED, true );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::SNAP_TO_ITEM_ENABLED).Get<bool>(), true, TEST_LOCATION );
+
+  // Test "refreshInterval" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("refreshInterval") == ItemView::Property::REFRESH_INTERVAL  );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::REFRESH_INTERVAL).Get<float>(), view.GetRefreshInterval(), TEST_LOCATION );
+  view.SetProperty( ItemView::Property::REFRESH_INTERVAL, 11.0f );
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::REFRESH_INTERVAL).Get<float>(), 11.0f, TEST_LOCATION );
+
+  // Test "layout" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("layout") == ItemView::Property::LAYOUT  );
+  Property::Map gridLayoutProperty;
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::GRID) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::ITEM_SIZE, Dali::Property::Value(Vector3(200, 200,50)) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_ROW_SPACING, Dali::Property::Value(50.0f) );
+  gridLayoutProperty.Insert( DefaultItemLayoutProperty::GRID_COLUMN_NUMBER, Dali::Property::Value(4) );
+
+  Property::Map depthLayoutProperty;
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::DEPTH) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_COLUMN_NUMBER, Dali::Property::Value(3) );
+  depthLayoutProperty.Insert( DefaultItemLayoutProperty::DEPTH_ROW_NUMBER, Dali::Property::Value(26.0f) );
+
+  Property::Map spiralLayoutPrperty;
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::SPIRAL) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING, Dali::Property::Value((Math::PI*2.0f)/9.5f) );
+  spiralLayoutPrperty.Insert( DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT, Dali::Property::Value(-0.125f) );
+
+  Property::Map listLayoutPrperty;
+  listLayoutPrperty.Insert( DefaultItemLayoutProperty::TYPE, Dali::Property::Value((int)DefaultItemLayout::LIST) );
+  listLayoutPrperty.Insert( DefaultItemLayoutProperty::ITEM_SIZE, Dali::Property::Value(Vector3(100, 100,50)) );
+
+
+  Property::Array layoutArray;
+  layoutArray.PushBack(gridLayoutProperty);
+  layoutArray.PushBack(depthLayoutProperty);
+  layoutArray.PushBack(spiralLayoutPrperty);
+  layoutArray.PushBack(listLayoutPrperty);
+
+  view.SetProperty( ItemView::Property::LAYOUT, layoutArray);
+
+  Property::Array getLayoutArray;
+  DALI_TEST_CHECK( view.GetProperty( ItemView::Property::LAYOUT ).Get( getLayoutArray ) );
+
+  //Check that the result is the same as
+  DALI_TEST_EQUALS( layoutArray.Count(), getLayoutArray.Count(), TEST_LOCATION );
+  Property::Map firstLayout = *((getLayoutArray.GetElementAt( 0 )).GetMap());
+
+  for( unsigned int mapIdx = 0, mapCount = firstLayout.Count(); mapIdx < mapCount; ++mapIdx )
+  {
+    KeyValuePair propertyPair( firstLayout.GetKeyValue( mapIdx ) );
+    if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+    {
+      int layoutType = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS( layoutType, (int)DefaultItemLayout::GRID, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::ITEM_SIZE)
+    {
+      Vector3 size = propertyPair.second.Get<Vector3>();
+      DALI_TEST_EQUALS( size, Vector3(200, 200,50), TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_ROW_SPACING)
+    {
+      float spacing = propertyPair.second.Get<float>();
+      DALI_TEST_EQUALS( spacing, 50.0f, TEST_LOCATION );
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::GRID_COLUMN_NUMBER)
+    {
+      int number = propertyPair.second.Get<int>();
+      DALI_TEST_EQUALS(number, 4, TEST_LOCATION );
+    }
+  }
+  view.SetProperty( ItemView::Property::LAYOUT, layoutArray);
+
+
+  // Test "overshootEnabled" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("overshootEnabled") == Scrollable::Property::OVERSHOOT_ENABLED  );
+  DALI_TEST_EQUALS( view.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), view.IsOvershootEnabled(), TEST_LOCATION );
+  view.SetProperty( Scrollable::Property::OVERSHOOT_ENABLED, false );
+  DALI_TEST_EQUALS( view.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), false, TEST_LOCATION );
+
+  // Test "overshootSize" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("overshootSize") == Scrollable::Property::OVERSHOOT_SIZE  );
+  Vector2 overshootSize = Vector2(100.0f,100.0f);
+  view.SetProperty( Scrollable::Property::OVERSHOOT_SIZE, overshootSize );
+  DALI_TEST_EQUALS( view.GetProperty(Scrollable::Property::OVERSHOOT_SIZE).Get<Vector2>(), overshootSize, TEST_LOCATION );
+
+  // Animatable properties
+
+  // Test "layoutPosition" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("layoutPosition") == ItemView::Property::LAYOUT_POSITION  );
+  view.SetProperty( ItemView::Property::LAYOUT_POSITION, 20.5f );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::LAYOUT_POSITION).Get<float>(), 20.5f, TEST_LOCATION );
+
+  // Test "scrollSpeed" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("scrollSpeed") == ItemView::Property::SCROLL_SPEED  );
+  view.SetProperty( ItemView::Property::SCROLL_SPEED, 3.35f );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::SCROLL_SPEED).Get<float>(), 3.35f, TEST_LOCATION );
+
+  // Test "overshoot" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("overshoot") == ItemView::Property::OVERSHOOT  );
+  view.SetProperty( ItemView::Property::OVERSHOOT, 0.15f );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::OVERSHOOT).Get<float>(), 0.15f, TEST_LOCATION );
+
+  // Test "scrollDirection" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("scrollDirection") == ItemView::Property::SCROLL_DIRECTION  );
+  view.SetProperty( ItemView::Property::SCROLL_DIRECTION, Vector2(0.85f, 0.5f) );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::SCROLL_DIRECTION).Get<Vector2>(), Vector2(0.85f, 0.5f), TEST_LOCATION );
+
+  // Test "layoutOrientation" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("layoutOrientation") == ItemView::Property::LAYOUT_ORIENTATION  );
+  view.SetProperty( ItemView::Property::LAYOUT_ORIENTATION, 2 );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::LAYOUT_ORIENTATION).Get<int>(), 2, TEST_LOCATION );
+
+  // Test "scrollContentSize" property
+  DALI_TEST_CHECK( view.GetPropertyIndex("scrollContentSize") == ItemView::Property::SCROLL_CONTENT_SIZE  );
+  view.SetProperty( ItemView::Property::SCROLL_CONTENT_SIZE, 250.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( view.GetProperty(ItemView::Property::SCROLL_CONTENT_SIZE).Get<float>(), 250.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliItemViewOvershootVertical(void)
+{
+  ToolkitTestApplication application;
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+  stage.Add(view);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(stage.GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  view.SetProperty( Scrollable::Property::OVERSHOOT_ENABLED, true );
+  DALI_TEST_EQUALS( view.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), true, TEST_LOCATION );
+
+  view.SetProperty( Scrollable::Property::OVERSHOOT_SIZE, Vector2(30, 30) );
+
+  Wait(application);
+
+  // Do a pan starting from 100,100 and moving down
+  Vector2 pos(100.0f, 100.0f);
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::DOWN, pos, 100 ) );
+  application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+
+  pos.y += 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<200;i++)
+  {
+    application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+    pos.y += 5.0f;
+    Wait(application);
+  }
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::UP, pos, 100 ) );
+
+  Wait(application, 100);
+
+  // Do a pan starting from 100,100 and moving up
+  pos = Vector2(100.0f, 300.0f);
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::DOWN, pos, 100 ) );
+  application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+
+  pos.y -= 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<200;i++)
+  {
+    application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+    pos.y -= 5.0f;
+    Wait(application);
+  }
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::UP, pos, 100 ) );
+  Wait(application, 100);
+  END_TEST;
+}
+
+int UtcDaliItemViewOvershootHorizontal(void)
+{
+  ToolkitTestApplication application;
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::SPIRAL );
+  view.AddLayout(*gridLayout);
+  stage.Add(view);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(stage.GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  view.SetProperty( Scrollable::Property::OVERSHOOT_ENABLED, true );
+  DALI_TEST_EQUALS( view.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), true, TEST_LOCATION );
+
+  view.SetProperty( Scrollable::Property::OVERSHOOT_SIZE, Vector2(30, 30) );
+
+  Wait(application);
+
+  // Do a pan starting from 100,100 and moving left
+  Vector2 pos(100.0f, 100.0f);
+  application.ProcessEvent( GenerateSingleTouch(PointState::DOWN, pos, 100 ));
+  application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ));
+  pos.x -= 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<200;i++)
+  {
+    application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+    pos.x -= 5.0f;
+    Wait(application);
+  }
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::UP, pos, 100 ) );
+  Wait(application, 100);
+
+  // Do a pan starting from 100,100 and moving right
+  pos = Vector2(100.0f, 100.0f);
+  application.ProcessEvent( GenerateSingleTouch(PointState::DOWN, pos, 100 ) );
+  application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+  pos.x += 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<200;i++)
+  {
+    application.ProcessEvent( GenerateSingleTouch(PointState::MOTION, pos, 100 ) );
+    pos.x += 5.0f;
+    Wait(application);
+  }
+
+  application.ProcessEvent( GenerateSingleTouch(PointState::UP, pos, 100 ) );
+  Wait(application, 100);
+
+  END_TEST;
+}
+
+int UtcDaliItemEnableDisableRefresh(void)
+{
+  ToolkitTestApplication application;
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+
+  // Create the ItemView actor
+  TestItemFactory factory;
+  ItemView view = ItemView::New(factory);
+
+  // Create a grid layout and add it to ItemView
+  ItemLayoutPtr gridLayout = DefaultItemLayout::New( DefaultItemLayout::GRID );
+  view.AddLayout(*gridLayout);
+  stage.Add(view);
+
+  // Activate the grid layout so that the items will be created and added to ItemView
+  Vector3 stageSize(stage.GetSize());
+  view.ActivateLayout(0, stageSize, 0.5f);
+
+  //Connect to signal scroll updated
+  view.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+
+  Property::Map attributes;
+  view.DoAction("enableRefresh", attributes );
+  gOnScrollUpdateCalled = true;
+  view.SetProperty( ItemView::Property::LAYOUT_POSITION, 100.0f );
+  application.SendNotification();
+  application.Render(1000);
+  DALI_TEST_EQUALS( gOnScrollUpdateCalled, true, TEST_LOCATION );
+
+
+  view.DoAction("disableRefresh", attributes );
+  gOnScrollUpdateCalled = false;
+  view.SetProperty( ItemView::Property::LAYOUT_POSITION, 100.0f );
+  application.SendNotification();
+  application.Render(1000);
+
+  DALI_TEST_EQUALS( gOnScrollUpdateCalled, false, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-JsonParser.cpp b/automated-tests/src/dali-toolkit/utc-Dali-JsonParser.cpp
new file mode 100644 (file)
index 0000000..258add1
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ * 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-toolkit/devel-api/builder/json-parser.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_json_parser_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_json_parser_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+std::string ReplaceQuotes(const std::string &in_s)
+{
+  std::string s(in_s);
+  // wrong as no embedded quote but had regex link problems
+  std::replace(s.begin(), s.end(), '\'', '"');
+  return s;
+}
+
+void CompareTrees(const TreeNode& a, const TreeNode& b)
+{
+  DALI_TEST_CHECK( a.GetType() == b.GetType() );
+
+  DALI_TEST_CHECK( a.Size() == b.Size() );
+
+  if( a.GetName() )
+  {
+    DALI_TEST_CHECK( std::string( a.GetName() ) == std::string( b.GetName() ) );
+  }
+
+  DALI_TEST_CHECK( a.HasSubstitution() == b.HasSubstitution() );
+
+  switch( a.GetType() )
+  {
+    case TreeNode::OBJECT:
+    case TreeNode::ARRAY:
+    {
+      for( TreeNode::ConstIterator aiter = a.CBegin(), biter = b.CBegin();
+           aiter != a.CEnd() && biter != b.CEnd(); ++aiter, ++biter )
+      {
+        CompareTrees( (*aiter).second, (*biter).second );
+      }
+      break;
+    }
+    case TreeNode::STRING:
+    {
+      DALI_TEST_CHECK( std::string( a.GetString() ) == std::string( b.GetString() ) );
+      break;
+    }
+    case TreeNode::FLOAT:
+    {
+      DALI_TEST_CHECK( a.GetFloat() == b.GetFloat() );
+      break;
+    }
+    case TreeNode::INTEGER:
+    {
+      DALI_TEST_CHECK( a.GetInteger() == b.GetInteger());
+      break;
+    }
+    case TreeNode::BOOLEAN:
+    {
+      DALI_TEST_CHECK( a.GetBoolean() == b.GetBoolean() );
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+
+}
+
+
+int UtcDaliJsonParserMethod01(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON basic test");
+
+  std::string s1( ReplaceQuotes(
+"{ \
+  'string':'value2', \
+  'integer':2, \
+  'float':2.0, \
+  'boolean':true, \
+  'nil':null, \
+  'array':[1,2,3], \
+  'object':{'key':'value'} \
+}"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  const TreeNode* root = parser.GetRoot();
+
+  DALI_TEST_CHECK(root);
+
+  DALI_TEST_CHECK(root->Size());
+
+  TreeNode::ConstIterator iter = root->CBegin();
+  DALI_TEST_CHECK(iter != root->CEnd());
+
+  const TreeNode* node = NULL;
+
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::STRING);
+  DALI_TEST_CHECK(std::string((*iter).first) == std::string("string"));
+  DALI_TEST_CHECK(std::string(node->GetString()) == std::string("value2"));
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::INTEGER);
+  DALI_TEST_CHECK(std::string((*iter).first) == std::string("integer"));
+  DALI_TEST_CHECK(node->GetInteger() == 2);
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::FLOAT);
+  DALI_TEST_CHECK(std::string((*iter).first) == std::string("float"));
+  DALI_TEST_CHECK(node->GetFloat() == 2.0);
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::BOOLEAN);
+  DALI_TEST_CHECK(std::string((*iter).first) == std::string("boolean"));
+  DALI_TEST_CHECK(node->GetBoolean());
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::IS_NULL);
+  DALI_TEST_CHECK(std::string((*iter).first) == std::string("nil"));
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::ARRAY);
+  DALI_TEST_CHECK(node->Size() == 3);
+  TreeNode::ConstIterator iterArray = node->CBegin();
+
+  DALI_TEST_CHECK(iterArray != node->CEnd());
+  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
+  DALI_TEST_CHECK( (*iterArray).first == NULL );
+  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 1);
+
+  ++iterArray;
+  DALI_TEST_CHECK(iterArray != node->CEnd());
+  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
+  DALI_TEST_CHECK( (*iterArray).first == NULL );
+  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 2);
+
+  ++iterArray;
+  DALI_TEST_CHECK(iterArray != node->CEnd());
+  DALI_TEST_CHECK( ((*iterArray).second).GetType() == TreeNode::INTEGER);
+  DALI_TEST_CHECK( (*iterArray).first == NULL );
+  DALI_TEST_CHECK( ((*iterArray).second).GetInteger() == 3);
+
+  ++iter;
+  DALI_TEST_CHECK(iter != root->CEnd());
+  node = &((*iter).second);
+  DALI_TEST_CHECK(node);
+  DALI_TEST_CHECK(node->GetType() == TreeNode::OBJECT);
+  DALI_TEST_CHECK(node->Size() == 1);
+
+  TreeNode::ConstIterator iterObject = node->CBegin();
+  DALI_TEST_CHECK(iterObject != node->CEnd());
+  DALI_TEST_CHECK( ((*iterObject).second).GetType() == TreeNode::STRING);
+  DALI_TEST_CHECK( std::string((*iterObject).first) == std::string("key" ));
+  DALI_TEST_CHECK( std::string(((*iterObject).second).GetString()) == std::string("value"));
+
+  ++iter;
+  DALI_TEST_CHECK(!( iter != root->CEnd() ));
+
+  ++iter; // Go past the end
+
+  iter++; // Use the other operator using the post increment operator
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod02(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Comments");
+
+  std::string s1( ReplaceQuotes("         \
+// some comments with empty line above  \n\
+{                                         \
+  // inline comments                    \n\
+  'key':'value', // endline comments    \n\
+  // more inline comments               \n\
+  'key2':'value2'                         \
+}                                         \
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  const TreeNode* root = parser.GetRoot();
+
+  DALI_TEST_CHECK(root);
+
+  DALI_TEST_CHECK(root->Size());
+
+  const TreeNode& node = (*root->CBegin()).second;
+
+  DALI_TEST_CHECK(node.GetType() == TreeNode::STRING);
+
+  DALI_TEST_CHECK(node.GetString() == std::string("value"));
+
+  DALI_TEST_CHECK((*root->CBegin()).first == std::string("key"));
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+
+int UtcDaliJsonParserMethod03(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Empty line comment");
+
+  std::string s1( ReplaceQuotes(
+"/*\n" \
+"c comment\n" \
+"*/"\
+"// next empty line comment\n"\
+"//\n"\
+"{\n"\
+"  'key':'value'\n"\
+"}\n"\
+));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  const TreeNode* root = parser.GetRoot();
+
+  DALI_TEST_CHECK(root);
+
+  DALI_TEST_CHECK(root->Size());
+
+  const TreeNode& node = (*root->CBegin()).second;
+
+  DALI_TEST_CHECK(node.GetType() == TreeNode::STRING);
+
+  DALI_TEST_CHECK(node.GetString() == std::string("value"));
+
+  DALI_TEST_CHECK((*root->CBegin()).first == std::string("key"));
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod04(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Merge");
+
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'animations':                                                         \
+  {                                                                     \
+    'bump':                                                             \
+    {                                                                   \
+      'properties':                                                     \
+      [                                                                 \
+        {                                                               \
+          'actor':'bump-image',                                         \
+          'property':'uLightPosition',                                  \
+          'value':[0.8, 0.0, -1.5],                                     \
+          'alphaFunction': 'BOUNCE',                                    \
+          'timePeriod': { 'duration': 2.5 }                            \
+        }                                                               \
+      ]                                                                 \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  std::string s2( ReplaceQuotes("                                       \
+{                                                                       \
+  'animations':                                                         \
+  {                                                                     \
+    'bump':                                                             \
+    {                                                                   \
+      'duration': 5.0,                                                  \
+      'loop': true,                                                     \
+      'endAction':'DISCARD'                                            \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  parser.Parse( s2 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  const TreeNode* root = parser.GetRoot();
+  DALI_TEST_CHECK(root);
+
+  const TreeNode *node = root->Find("bump");
+  DALI_TEST_CHECK(node);
+
+  DALI_TEST_CHECK(static_cast<int>(node->Size()) == 4);
+
+  DALI_TEST_CHECK( node->GetChild("duration") );
+  DALI_TEST_CHECK( node->GetChild("loop") );
+  DALI_TEST_CHECK( node->GetChild("properties") );
+
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod05(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Pack & Write");
+
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'animations':                                                         \
+  {                                                                     \
+    'bump':                                                             \
+    {                                                                   \
+      'properties':                                                     \
+      [                                                                 \
+        {                                                               \
+          'actor':'bump-image',                                         \
+          'property':'uLightPosition',                                  \
+          'value':[0.8, 0.0, -1.5],                                     \
+          'alphaFunction': 'BOUNCE',                                    \
+          'timePeriod': { 'duration': 2.5 }                            \
+        }                                                               \
+      ]                                                                 \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  if(parser.ParseError())
+  {
+    std::cout << "Error: " << parser.GetErrorDescription() << std::endl;
+    std::cout << "   at: " << parser.GetErrorLineNumber() << "(" << parser.GetErrorPosition() << ")" << std::endl;
+  }
+  DALI_TEST_CHECK(!parser.ParseError());
+
+  std::stringstream a;
+  parser.Write(a, 2);
+
+  parser.Pack();
+
+  std::stringstream b;
+  parser.Write(b, 2);
+
+  DALI_TEST_CHECK( a.str() == b.str() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+namespace
+{
+
+static const int NUMBER_OK_TESTS = 36;
+const char *TEST_OK[NUMBER_OK_TESTS] = {
+  "{ 'hex': '\u0123\u4567\u89AB\uCDEF\uabcd\uef4A' }",
+  "{ 'special': '`1~!@#$%^&*()_+-={:[,]}|;.</>?' }",
+  "{ 'slash': '/ & \' }",
+  "{'object with 1 member':['array with 1 element']}",
+  "[{}, [], -42, true, false, null]",
+  "{ 'integer': 1234567890 }",
+  "{ 'integer': 1234567890 }",
+  "{ 'real': -9876.543210 }",
+  "{ 'e': 0.123456789e-12 }",
+  "{ 'E': 1.234567890E+34 }",
+  "{ '':  23456789012E66 }",
+  "{ 'zero': 0 }",
+  "{ 'one': 1 }",
+  "{ 'space': ' ' }",
+  "{ 'backslash': '\' }",
+  "{ 'controls': '\\b\\f\\n\\r\\t' }",
+  "{ 'alpha': 'abcdefghijklmnopqrstuvwyz' }",
+  "{ 'ALPHA': 'ABCDEFGHIJKLMNOPQRSTUVWYZ' }",
+  "{ 'digit': '0123456789' }",
+  "{ '0123456789': 'digit' }",
+  "{ 'true': true }",
+  "{ 'false': false }",
+  "{ 'null': null }",
+  "{ 'array':[  ] }",
+  "{ 'object':{  } }",
+  "{ 'address': '1 Communication Centre. South Street' }",
+  "{ 'url': 'http://www.JSON.org/' }",
+  "{ 'comment': '// /* <!-- --' }",
+  "{ '# -- --> */': ' ' }",
+  "{ ' s p a c e d ' :[1,2 , 3,4 , 5        ,          6           ,7        ]}",
+  "{ 'compact':[1,2,3,4,5,6,7]}",
+  "{ 'quotes': '&#34; \\u0022 %22 0x22 034 &#x22;' }",
+  "{ '\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:': 'A key can be any string'}",
+  "[ 0.5 ,98.6, 99.44,1066,1e1,0.1e1,1e-1,1e00,2e+00,2e-00, 'rosebud']",
+  "{'JSON Test Pattern pass3': { 'The outermost value': 'must be an object or array.', 'In this test': 'It is an object.' } }",
+  "[[[[[[[[[[[[[[[[[[['Not too deep']]]]]]]]]]]]]]]]]]]",
+};
+}
+
+
+int UtcDaliJsonParserMethod06(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Parse Success");
+
+  JsonParser parser = JsonParser::New();
+
+  for(int i = 0; i < NUMBER_OK_TESTS; ++i)
+  {
+    parser = JsonParser::New();
+
+    parser.Parse( ReplaceQuotes(TEST_OK[i]) );
+
+    if(parser.ParseError())
+    {
+      tet_printf("Valid JSON parse test %d Failed", i);
+      tet_printf("%s", ReplaceQuotes(TEST_OK[i]).c_str());
+
+      tet_printf("JSON Error %d:%d: %s (%d)", parser.GetErrorLineNumber(), parser.GetErrorColumn(), parser.GetErrorDescription().c_str(), parser.GetErrorPosition());
+    }
+
+    DALI_TEST_CHECK(!parser.ParseError());
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+namespace
+{
+
+static const int NUMBER_FAIL_TESTS = 34;
+const char *TEST_FAIL[] = {
+  "[' tab\t   character  \t in\t string   ']",
+  "['Extra close']]",
+  "['Colon instead of comma': false]",
+  "{'Numbers cannot have leading zeroes': 013}",
+  "['Bad value', truth]",
+  "['Illegal backslash escape: \017']",
+  "['Bad value', truth]['Illegal backslash escape: \017']",
+  "{'Comma instead if closing brace': true,",
+  "{'Double colon':: null}",
+  "{'Extra comma': true,}",
+  "['Unclosed array'",
+  "{'Illegal invocation': alert()}",
+  "{'Missing colon' null}",
+  "[0e]",
+  "{unquoted_key: 'keys must be quoted'}",
+  "'A JSON payload should be an object or array, not a string.'",
+  "[\naked]",
+  "{'Illegal expression': 1 + 2}",
+  "{'Extra value after close': true} 'misplaced quoted value'",
+  "[0e+]",
+  "[+23456789012E66]",
+  "['extra comma',]",
+  "['Comma after the close'],",
+  "['double extra comma',,]",
+  "['Illegal backslash escape: \x15']",
+  "['line\nbreak']",
+  "{'Comma instead of colon', null}",
+  "['mismatch'}",
+  "['line\nbreak']",
+  "[0e+-1]",
+  "{'Numbers cannot be hex': 0x14}",
+  "[   , '<-- missing value']",
+  "[{'no comma':1} {'b:2}]",
+  "{'extra comma':1,}",
+};
+}
+
+int UtcDaliJsonParserMethod07(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Fail");
+
+  JsonParser parser = JsonParser::New();
+
+  for(int i = 0; i < NUMBER_FAIL_TESTS; ++i)
+  {
+    parser = JsonParser::New();
+
+    parser.Parse( ReplaceQuotes(TEST_FAIL[i]) );
+
+    if(!parser.ParseError())
+    {
+      tet_printf("Invalid JSON parse test %d Failed", i);
+      tet_printf("%s", ReplaceQuotes(TEST_FAIL[i]).c_str());
+      tet_printf("JSON Error %d:%d %s (%s)", parser.GetErrorLineNumber(), parser.GetErrorColumn(),
+                 parser.GetErrorDescription().c_str(), parser.GetErrorPosition());
+    }
+
+    DALI_TEST_CHECK(parser.ParseError());
+  }
+
+
+  parser = JsonParser::New();
+
+  parser.Parse( "['single quote']" );
+
+  if(!parser.ParseError())
+  {
+    tet_printf("['single quote']");
+  }
+
+  DALI_TEST_CHECK(parser.ParseError());
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod08(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON error reporting");
+
+  std::string s1( ReplaceQuotes("\
+{                                         \n\
+  'float':,],                             \n\
+}                                         \n\
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  DALI_TEST_CHECK(parser.ParseError());
+
+  DALI_TEST_CHECK(1  == parser.GetErrorLineNumber());
+  DALI_TEST_CHECK(53 == parser.GetErrorPosition());
+  DALI_TEST_CHECK(11 == parser.GetErrorColumn());
+  DALI_TEST_CHECK("Missing Value" == parser.GetErrorDescription());
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod09(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON Pack()");
+
+  std::string s1( ReplaceQuotes("\
+{                                         \
+  'string':'value2',                      \
+  'integer':2,                            \
+  'float':2.3,                            \
+  'boolean':true,                         \
+  'nil':null,                             \
+  'array':[1,2,3],                        \
+  'object':{'key':'value'}                \
+}                                         \
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  std::stringstream ss1;
+  parser.Write(ss1, 2);
+
+  parser.Pack(); // Pack() moves strings
+
+  std::stringstream ss2;
+  parser.Write(ss2, 2);
+
+  DALI_TEST_CHECK(ss1.str() == ss2.str());
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod10(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("JSON empty data");
+
+  std::string s1( "" );
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  DALI_TEST_CHECK(parser.ParseError());
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliJsonParserMethod11(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("JSON tree copy");
+
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'animations':                                                         \
+  {                                                                     \
+    'bump':                                                             \
+    {                                                                   \
+      'properties':                                                     \
+      [                                                                 \
+        {                                                               \
+          'actor':'bump-image',                                         \
+          'property':'uLightPosition',                                  \
+          'value':[0.8, 0.0, -1.5],                                     \
+          'alphaFunction': 'BOUNCE',                                    \
+          'timePeriod': { 'duration': 2.5 }                            \
+        }                                                               \
+      ]                                                                 \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+
+  parser.Parse( s1 );
+
+  JsonParser parser2 = JsonParser::New(*parser.GetRoot());
+
+  DALI_TEST_CHECK(parser.GetRoot());
+  DALI_TEST_CHECK(parser2.GetRoot());
+
+  CompareTrees( *parser.GetRoot(), *parser2.GetRoot() );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+
+int UtcDaliJsonParserMerge1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("JSON tree merge");
+
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'styles':                                                             \
+  {                                                                     \
+    'button':                                                           \
+    {                                                                   \
+      'backgroundColor':[0.8, 0.0, 1.0, 1.0],                           \
+      'foregroundColor':[1, 1, 1, 1]                                    \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+  JsonParser testParser = JsonParser::New();
+
+  testParser.Parse( s1 );
+
+  parser.Parse( s1 );
+  parser.Parse( s1 ); // Merge the tree into itself. The value array should not grow.
+
+  DALI_TEST_CHECK(parser.GetRoot());
+
+  CompareTrees( *parser.GetRoot(), *testParser.GetRoot() );
+
+  END_TEST;
+}
+
+int UtcDaliJsonParserDownCast(void)
+{
+  BaseHandle handle = JsonParser::New();
+  JsonParser parser = JsonParser::DownCast( handle );
+  DALI_TEST_CHECK( parser );
+  END_TEST;
+}
+
+int UtcDaliJsonParserTreeNodeCount(void)
+{
+  std::string s1( ReplaceQuotes("                                       \
+{                                                                       \
+  'styles':                                                             \
+  {                                                                     \
+    'button':                                                           \
+    {                                                                   \
+      'backgroundColor':[0.8, 0.0, 1.0, 1.0],                           \
+      'foregroundColor':[1, 1, 1, 1]                                    \
+    }                                                                   \
+  }                                                                     \
+}                                                                       \
+"));
+
+  JsonParser parser = JsonParser::New();
+  parser.Parse( s1 );
+
+  const TreeNode* treeNode = parser.GetRoot();
+  DALI_TEST_EQUALS(1, treeNode->Count("styles"), TEST_LOCATION );
+  DALI_TEST_EQUALS(0, treeNode->Count("random"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliJsonParserTreeNodeFind(void)
+{
+  std::string s1( ReplaceQuotes("\
+{                                         \
+  'string':'value2',                      \
+  'integer':2,                            \
+  'float':2.3,                            \
+  'boolean':true,                         \
+  'nil':null,                             \
+  'array':[1,2,3],                        \
+  'object':{'key':'value'}                \
+}                                         \
+"));
+
+  JsonParser parser = JsonParser::New();
+  parser.Parse( s1 );
+
+  const TreeNode* treeNode = parser.GetRoot();
+  const TreeNode* childNode = treeNode->Find("string");
+  DALI_TEST_CHECK( childNode );
+  const TreeNode* sameNode = childNode->Find("string");
+  DALI_TEST_EQUALS( sameNode, childNode, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-KeyInputFocusManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-KeyInputFocusManager.cpp
new file mode 100755 (executable)
index 0000000..4686512
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2017 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/key-event-integ.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali/devel-api/common/stage-devel.h>
+
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+/**
+ * Callback class for KeyInputFocusChanged signal.
+ */
+class KeyInputFocusChangedCallback : public Dali::ConnectionTracker
+{
+public:
+  /**
+   * Constructor
+   * @param[in]  gainActor  Ref to the actor that should be set as the one that gains key input focus.
+   * @param[in]  lostActor  Ref to the actor that should be set as the one that loses key input focus.
+   */
+  KeyInputFocusChangedCallback( Control& gainActor, Control& lostActor )
+  : mActorGain( gainActor ),
+    mActorLost( lostActor )
+  {
+  }
+
+  void Callback( Control gainingActor, Control lostActor )
+  {
+    mActorGain = gainingActor;
+    mActorLost = lostActor;
+  }
+
+  Control& mActorGain;
+  Control& mActorLost;
+};
+
+// Stores data that is populated in the callback and will be read by the TET cases
+struct SignalData
+{
+  SignalData()
+  : functorCalled(false)
+  {}
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    receivedKeyEvent.keyModifier = 0;
+    receivedKeyEvent.keyPressedName.clear();
+    receivedKeyEvent.keyPressed.clear();
+
+  }
+
+  bool functorCalled;
+  KeyEvent receivedKeyEvent;
+};
+
+/**
+ * Callback class for KeyEvent signal of control.
+ */
+class KeyEventCallback : public Dali::ConnectionTracker
+{
+public:
+  /**
+   * Constructor
+   * @param[in]  returnValue  Set return value of KeyEvent callback.
+   * */
+  KeyEventCallback( bool consumed )
+  : mConsumed( consumed ),
+    mIsCalled( false )
+  {
+  }
+
+  bool Callback( Control control, const KeyEvent& keyEvent )
+  {
+    mIsCalled = true;
+    return mConsumed;
+  }
+
+  void Callback( const KeyEvent& keyEvent )
+  {
+    mIsCalled = true;
+  }
+
+  bool mConsumed;
+  bool mIsCalled;
+};
+
+} // namespace
+
+void key_input_focus_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void key_input_focus_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliKeyInputFocusManagerGet(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyInputFocusManagerGet");
+
+  KeyInputFocusManager manager;
+  {
+    manager = KeyInputFocusManager::Get();
+    DALI_TEST_CHECK(manager);
+  }
+
+  KeyInputFocusManager newManager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(newManager);
+
+  // Check that focus manager is a singleton
+  DALI_TEST_CHECK(manager == newManager);
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerSetFocus01(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Check that there is no focused control. Set focus to control. Check it is now the focused actor and receives KeyInputFocusGained signal");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Control focusedControl = manager.GetCurrentFocusControl();
+  DALI_TEST_CHECK( ! focusedControl );
+
+  DummyControl dummy = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+  dummy.SetSize(100.0f, 100.0f);
+  stage.Add( dummy );
+  DALI_TEST_CHECK( ! dummyImpl.keyInputFocusGained );
+
+  manager.SetFocus( dummy );
+  DALI_TEST_CHECK( dummy.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummyImpl.keyInputFocusGained );
+
+  focusedControl = manager.GetCurrentFocusControl();
+  DALI_TEST_CHECK( focusedControl );
+  DALI_TEST_CHECK( focusedControl == dummy );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerSetFocus02(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Set focus to control. Check it is now the focused actor and receives KeyInputFocusGained signal. Set focuse to another control - check that the first control receives KeyInputFocusLost");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  Impl::DummyControl& dummy1Impl = static_cast<Impl::DummyControl&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  manager.SetFocus( dummy1 );
+  DALI_TEST_CHECK( dummy1.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+
+  DummyControl dummy2 = DummyControl::New(true);
+  Impl::DummyControl& dummy2Impl = static_cast<Impl::DummyControl&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  manager.SetFocus( dummy2 );
+  DALI_TEST_CHECK( dummy2.HasKeyInputFocus()); // Also tests IsKeyboardListener() API
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained );
+  dummy1Impl.keyInputFocusGained = false;
+
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerKeyEventPropagation01(void)
+{
+
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline("Test KeyEvent propagation. If focused control doesn't consume KeyEvent, KeyEvent will be recursively delivered to the control and its parents, until the event is consumed or the stage is reached. In this case, KeyEvent is delivered to KeyboardFocusManager via Stage's KeyEventSignal");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  KeyEventCallback stageCallback( false );
+  stage.KeyEventSignal().Connect( &stageCallback, &KeyEventCallback::Callback );
+
+  DummyControl dummy1 = DummyControl::New(true);
+  dummy1.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback1( false );
+  dummy1.KeyEventSignal().Connect( &callback1, &KeyEventCallback::Callback );
+  stage.Add( dummy1 );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  dummy2.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback2( false );
+  dummy2.KeyEventSignal().Connect( &callback2, &KeyEventCallback::Callback );
+  dummy1.Add( dummy2 );
+
+  DummyControl dummy3 = DummyControl::New(true);
+  Impl::DummyControl& dummy3Impl = static_cast<Impl::DummyControl&>(dummy3.GetImplementation());
+  dummy3.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback3( false );
+  dummy3.KeyEventSignal().Connect( &callback3, &KeyEventCallback::Callback );
+  dummy2.Add( dummy3 );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+
+  manager.SetFocus( dummy3 );
+  DALI_TEST_CHECK( dummy3Impl.keyInputFocusGained );
+
+  Integration::KeyEvent event( "a", "", "a", 0, 0, 0, Integration::KeyEvent::Up, "", "", Device::Class::TOUCH, Device::Subclass::NONE );
+  application.ProcessEvent(event);
+
+  DALI_TEST_CHECK( callback1.mIsCalled );
+  DALI_TEST_CHECK( callback2.mIsCalled );
+  DALI_TEST_CHECK( callback3.mIsCalled );
+  DALI_TEST_CHECK( stageCallback.mIsCalled );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerKeyEventPropagation02(void)
+{
+
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline("Test KeyEvent propagation. If focused control doesn't consume KeyEvent, KeyEvent will be recursively delivered to the control and its parents, until the event is consumed or the stage is reached. In this case, KeyEvent is delivered from dummy3 to dummy2");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  dummy1.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback1( false );
+  dummy1.KeyEventSignal().Connect( &callback1, &KeyEventCallback::Callback );
+  stage.Add( dummy1 );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  dummy2.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback2( true );
+  dummy2.KeyEventSignal().Connect( &callback2, &KeyEventCallback::Callback );
+  dummy1.Add( dummy2 );
+
+  DummyControl dummy3 = DummyControl::New(true);
+  Impl::DummyControl& dummy3Impl = static_cast<Impl::DummyControl&>(dummy3.GetImplementation());
+  dummy3.SetSize(100.0f, 100.0f);
+  KeyEventCallback callback3( false );
+  dummy3.KeyEventSignal().Connect( &callback3, &KeyEventCallback::Callback );
+  dummy2.Add( dummy3 );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy3Impl.keyInputFocusLost );
+
+  manager.SetFocus( dummy3 );
+  DALI_TEST_CHECK( dummy3Impl.keyInputFocusGained );
+
+  Integration::KeyEvent event( "a", "", "a", 0, 0, 0, Integration::KeyEvent::Up, "", "", Device::Class::TOUCH, Device::Subclass::NONE );
+  application.ProcessEvent(event);
+
+  DALI_TEST_CHECK( !callback1.mIsCalled );
+  DALI_TEST_CHECK( callback2.mIsCalled );
+  DALI_TEST_CHECK( callback3.mIsCalled );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerGetCurrentFocusControl(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Add 2 controls, check they each get focused. Re-focus the first control - ensure it's now got focus (check signals)");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  Impl::DummyControl& dummy1Impl = static_cast<Impl::DummyControl&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  DummyControl dummy2 = DummyControl::New(true);
+  Impl::DummyControl& dummy2Impl = static_cast<Impl::DummyControl&>(dummy2.GetImplementation());
+  dummy2.SetSize(100.0f, 100.0f);
+  stage.Add( dummy2 );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl() );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+
+  manager.SetFocus(dummy2);
+  DALI_TEST_CHECK( dummy2 == manager.GetCurrentFocusControl() );
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusLost );
+  // Reset signal received
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+  dummy2Impl.keyInputFocusGained = false;
+  dummy2Impl.keyInputFocusLost = false;
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK( dummy1 == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( dummy2Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy2Impl.keyInputFocusGained );
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerRemoveFocus(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" Add focus controls. Test that removing focus from control which has focus. ");
+
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  DummyControl dummy1 = DummyControl::New(true);
+  Impl::DummyControl& dummy1Impl = static_cast<Impl::DummyControl&>(dummy1.GetImplementation());
+  dummy1.SetSize(100.0f, 100.0f);
+  stage.Add( dummy1 );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusLost );
+
+  manager.SetFocus(dummy1);
+  DALI_TEST_CHECK(dummy1 == manager.GetCurrentFocusControl());
+  dummy1Impl.keyInputFocusGained = false;
+  dummy1Impl.keyInputFocusLost = false;
+
+  manager.RemoveFocus(dummy1);
+  DALI_TEST_CHECK(Control() == manager.GetCurrentFocusControl());
+  DALI_TEST_CHECK( dummy1Impl.keyInputFocusLost );
+  DALI_TEST_CHECK( ! dummy1Impl.keyInputFocusGained );
+
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerSignalKeyInputFocusChanged(void)
+{
+  ToolkitTestApplication application;
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" UtcDaliKeyInputFocusManagerSignalKeyInputFocusChanged");
+
+  PushButton pushButton1 = PushButton::New();
+  PushButton pushButton2 = PushButton::New();
+
+  stage.Add( pushButton1 );
+  stage.Add( pushButton2 );
+
+  PushButton gainActor, lostActor;
+  KeyInputFocusChangedCallback callback( gainActor, lostActor );
+  manager.KeyInputFocusChangedSignal().Connect( &callback, &KeyInputFocusChangedCallback::Callback );
+
+  manager.SetFocus(pushButton1);
+
+  DALI_TEST_CHECK( gainActor == pushButton1 );
+  DALI_TEST_CHECK( lostActor == Control() );
+
+  gainActor.Reset();
+  lostActor.Reset();
+
+  manager.SetFocus(pushButton2);
+
+  DALI_TEST_CHECK( gainActor == pushButton2 );
+  DALI_TEST_CHECK( lostActor == pushButton1 );
+
+  gainActor.Reset();
+  lostActor.Reset();
+
+  // Removing the focus actor from the stage would also result in signal emission.
+  stage.Remove( pushButton1 );
+  stage.Remove( pushButton2 );
+
+  DALI_TEST_CHECK( gainActor == Control() );
+  DALI_TEST_CHECK( lostActor == Control() );
+  END_TEST;
+}
+
+int UtcDaliKeyInputFocusManagerSignalKeyInputFocusChangedforNewWindow(void)
+{
+  ToolkitTestApplication application;
+  KeyInputFocusManager manager = KeyInputFocusManager::Get();
+
+  tet_infoline(" UtcDaliKeyInputFocusManagerSignalKeyInputFocusChanged");
+
+  PushButton pushButton1 = PushButton::New();
+  PushButton pushButton2 = PushButton::New();
+
+  Window window = Window::New(PositionSize(0,0,0,0) ,"", false);
+  DALI_TEST_CHECK( window );
+
+  window.Add( pushButton1 );
+  window.Add( pushButton2 );
+
+  PushButton gainActor, lostActor;
+  KeyInputFocusChangedCallback callback( gainActor, lostActor );
+  manager.KeyInputFocusChangedSignal().Connect( &callback, &KeyInputFocusChangedCallback::Callback );
+
+  manager.SetFocus(pushButton1);
+
+  DALI_TEST_CHECK( gainActor == pushButton1 );
+  DALI_TEST_CHECK( lostActor == Control() );
+
+  gainActor.Reset();
+  lostActor.Reset();
+
+  manager.SetFocus(pushButton2);
+
+  DALI_TEST_CHECK( gainActor == pushButton2 );
+  DALI_TEST_CHECK( lostActor == pushButton1 );
+
+  gainActor.Reset();
+  lostActor.Reset();
+
+  // Removing the focus actor from the window would also result in signal emission.
+  window.Remove( pushButton1 );
+  window.Remove( pushButton2 );
+  DALI_TEST_CHECK( gainActor == Control() );
+  DALI_TEST_CHECK( lostActor == Control() );
+
+  window.Reset();
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp
new file mode 100755 (executable)
index 0000000..a759616
--- /dev/null
@@ -0,0 +1,1618 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_keyboard_focus_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_keyboard_focus_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+namespace
+{
+
+const std::string DEFAULT_DEVICE_NAME("hwKeyboard");
+
+// Functors to test whether GetNextFocusableActor() method of CustomAlgorithmInterface is called when the keyboard focus is about to change
+class CustomAlgorithm : public Dali::Toolkit::DevelKeyboardFocusManager::CustomAlgorithmInterface
+{
+public:
+  CustomAlgorithm(bool& interfaceVerified)
+  : mInterfaceVerified(interfaceVerified),
+    mCurrentFocusedActor(),
+    mProposedActorToFocus(),
+    mDirection(Control::KeyboardFocus::LEFT)
+  {
+  }
+
+  Actor GetNextFocusableActor(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction)
+  {
+    tet_infoline("Verifying CustomAlgorithm()");
+
+    mInterfaceVerified = true;
+
+    mCurrentFocusedActor = currentFocusedActor;
+    mProposedActorToFocus = proposedActorToFocus;
+    mDirection = direction;
+
+    return mProposedActorToFocus;
+  }
+
+  void Reset()
+  {
+    mInterfaceVerified = false;
+    mCurrentFocusedActor = Actor();
+    mProposedActorToFocus = Actor();
+    mDirection = Control::KeyboardFocus::LEFT;
+  }
+
+  bool& mInterfaceVerified;
+  Actor mCurrentFocusedActor;
+  Actor mProposedActorToFocus;
+  Control::KeyboardFocus::Direction mDirection;
+};
+
+// Functors to test whether PreFocusChange signal is emitted when the keyboard focus is about to change
+class PreFocusChangeCallback : public Dali::ConnectionTracker
+{
+public:
+  PreFocusChangeCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mCurrentFocusedActor(),
+    mProposedActorToFocus(),
+    mDirection(Control::KeyboardFocus::LEFT)
+  {
+  }
+
+  Actor Callback(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction)
+  {
+    tet_infoline("Verifying PreFocusChangeCallback()");
+
+    mSignalVerified = true;
+
+    mCurrentFocusedActor = currentFocusedActor;
+    mProposedActorToFocus = proposedActorToFocus;
+    mDirection = direction;
+
+    return mProposedActorToFocus;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+    mCurrentFocusedActor = Actor();
+    mProposedActorToFocus = Actor();
+    mDirection = Control::KeyboardFocus::LEFT;
+  }
+
+  bool& mSignalVerified;
+  Actor mCurrentFocusedActor;
+  Actor mProposedActorToFocus;
+  Control::KeyboardFocus::Direction mDirection;
+};
+
+// Functors to test whether focus changed signal is emitted when the keyboard focus is changed
+class FocusChangedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusChangedCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mOriginalFocusedActor(),
+    mCurrentFocusedActor()
+  {
+  }
+
+  void Callback(Actor originalFocusedActor, Actor currentFocusedActor)
+  {
+    tet_infoline("Verifying FocusChangedCallback()");
+
+    if(originalFocusedActor == mCurrentFocusedActor)
+    {
+      mSignalVerified = true;
+    }
+
+    mOriginalFocusedActor = originalFocusedActor;
+    mCurrentFocusedActor = currentFocusedActor;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mOriginalFocusedActor;
+  Actor mCurrentFocusedActor;
+};
+
+// Functors to test whether focus group changed signal is emitted when the keyboard focus group is changed
+class FocusGroupChangedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusGroupChangedCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mCurrentFocusedActor(),
+    mForward(true)
+  {
+  }
+
+  void Callback(Actor currentFocusedActor, bool forward)
+  {
+    tet_infoline("Verifying FocusGroupChangedCallback()");
+
+    mSignalVerified = true;
+
+    mCurrentFocusedActor = currentFocusedActor;
+    mForward = forward;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mCurrentFocusedActor;
+  bool mForward;
+};
+
+// Functors to test whether focused actor activated signal is emitted when the focused actor is activated
+class FocusedActorActivatedCallback : public Dali::ConnectionTracker
+{
+public:
+  FocusedActorActivatedCallback(bool& signalReceived)
+  : mSignalVerified(signalReceived),
+    mActivatedActor()
+  {
+  }
+
+  void Callback(Actor activatedActor)
+  {
+    tet_infoline("Verifying FocusedActorActivatedCallback()");
+
+    mSignalVerified = true;
+
+    mActivatedActor = activatedActor;
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool& mSignalVerified;
+  Actor mActivatedActor;
+};
+
+class KeyEventCallback : public Dali::ConnectionTracker
+{
+public:
+  /**
+   * Constructor
+   * @param[in]  returnValue  Set return value of KeyEvent callback.
+   * */
+  KeyEventCallback( bool consumed )
+  : mConsumed( consumed ),
+    mIsCalled( false )
+  {
+  }
+
+  bool Callback( Control control, const KeyEvent& keyEvent )
+  {
+    mIsCalled = true;
+    return mConsumed;
+  }
+
+  void Callback( const KeyEvent& keyEvent )
+  {
+    mIsCalled = true;
+  }
+
+  bool mConsumed;
+  bool mIsCalled;
+};
+
+// Used to connect to signals via the ConnectSignal Handle method
+struct CallbackFunctor
+{
+  CallbackFunctor()
+  {
+  }
+
+  void operator()()
+  {
+  }
+};
+
+} // namespace
+
+int UtcDaliKeyboardFocusManagerGet(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardKeyboardFocusManagerGet");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager;
+
+  manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  KeyboardFocusManager newManager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(newManager);
+
+  // Check that focus manager is a singleton
+  DALI_TEST_CHECK(manager == newManager);
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSetAndGetCurrentFocusActor(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSetAndGetCurrentFocusActor");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Create the third actor but don't add it to the stage
+  Actor third = Actor::New();
+
+  // Check that no actor is being focused yet.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+
+  // Check that it will fail to set focus on an invalid actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(Actor()) == false);
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Check that it will fail to set focus on the third actor as it's not in the stage
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Add the third actor to the stage
+  Stage::GetCurrent().Add(third);
+
+  // Check that it will fail to set focus on the third actor as it's not focusable
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Make the third actor focusable
+  third.SetKeyboardFocusable(true);
+
+  // Check that the focus is successfully moved to the third actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerMoveFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerMoveFocus");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Move the focus to the right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+  preFocusChangeCallback.Reset();
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and the first actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+  preFocusChangeCallback.Reset();
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == second);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::UP);
+  preFocusChangeCallback.Reset();
+  DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
+
+  // Create a 2x2 table view and try to move focus inside it
+  TableView tableView = TableView::New( 2, 2 );
+  Stage::GetCurrent().Add(tableView);
+
+  // Create the third actor
+  Actor third = Actor::New();
+  third.SetKeyboardFocusable(true);
+
+  // Create the fourth actor
+  Actor fourth = Actor::New();
+  fourth.SetKeyboardFocusable(true);
+
+  // Add the four children to table view
+  tableView.AddChild(first, TableView::CellPosition(0, 0));
+  tableView.AddChild(second, TableView::CellPosition(0, 1));
+  tableView.AddChild(third, TableView::CellPosition(1, 0));
+  tableView.AddChild(fourth, TableView::CellPosition(1, 1));
+
+  // Set the focus to the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards down
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == third);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == third);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left. The focus move will fail as no way to move it upwards
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::LEFT);
+  preFocusChangeCallback.Reset();
+  DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
+
+  // Enable the loop
+  manager.SetFocusGroupLoop(true);
+  DALI_TEST_CHECK(manager.GetFocusGroupLoop() == true);
+
+  // Move the focus towards left again. The focus should move to the fourth actor.
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth);
+  focusChangedCallback.Reset();
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Move the focus to the right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+  preFocusChangeCallback.Reset();
+
+  bool customAlgorithmInterfaceVerified = false;
+  CustomAlgorithm customAlgorithm(customAlgorithmInterfaceVerified);
+  Toolkit::DevelKeyboardFocusManager::SetCustomAlgorithm(manager, customAlgorithm);
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and the first actor is focused, it should invoke CustomAlgorithm
+  DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
+  DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::RIGHT);
+  customAlgorithm.Reset();
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and the first actor is focused, it should invoke CustomAlgorithm
+  DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
+  DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::RIGHT);
+  customAlgorithm.Reset();
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should invoke CustomAlgorithm
+  DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
+  DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == second);
+  DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::UP);
+  customAlgorithm.Reset();
+  DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
+
+  END_TEST;
+}
+int UtcDaliKeyboardFocusManagerFocusablePropertiesMoveFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  PushButton button1 = PushButton::New();
+  PushButton button2 = PushButton::New();
+  button1.SetKeyboardFocusable(true);
+  button2.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(button1);
+  Stage::GetCurrent().Add(button2);
+
+  // Set the focus to the button1
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(button1) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == button1);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  focusChangedCallback.Reset();
+
+  // set the navigation properties of button1
+  button1.SetProperty(Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetId()));
+  button1.SetProperty(Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetId()));
+  button1.SetProperty(Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetId()));
+  button1.SetProperty(Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetId()));
+
+  // set the navigation properties of button2
+  button2.SetProperty(Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetId()));
+  button2.SetProperty(Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetId()));
+  button2.SetProperty(Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetId()));
+  button2.SetProperty(Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetId()));
+
+  // Move the focus towards left
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+  // Confirm whether focus is moved to button2
+  DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+
+  // Confirm whether focus is moved to button1
+  DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button2);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == true);
+
+  // Confirm whether focus is moved to button2
+  DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards down
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true);
+
+  // Confirm whether focus is moved to button1
+  DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button2);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  focusChangedCallback.Reset();
+
+  // Create a 1x1 table view and try to move focus inside it
+  TableView tableView = TableView::New( 1, 1 );
+  Stage::GetCurrent().Add(tableView);
+
+  PushButton button = PushButton::New();
+  button.SetKeyboardFocusable(true);
+  tableView.AddChild(button, TableView::CellPosition(0, 0));
+
+  // set the navigation properties of button3
+  button.SetProperty(Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetId()));
+
+  // Set the focus to the button
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(button) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == button);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+
+  // Confirm whether focus is moved to button1
+  DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  focusChangedCallback.Reset();
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerClearFocus(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerClearFocus");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Clear the focus
+  manager.ClearFocus();
+
+  // Check that no actor is being focused now.
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSetAndGetFocusGroupLoop(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSetAndGetFocusGroupLoop");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Check that the focus movement is not looped within the same focus group by default
+  DALI_TEST_CHECK(manager.GetFocusGroupLoop() == false);
+
+  // Enable the loop
+  manager.SetFocusGroupLoop(true);
+  DALI_TEST_CHECK(manager.GetFocusGroupLoop() == true);
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSetAsFocusGroup(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSetAsFocusGroup");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create an actor and check that it is not a focus group by default
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK(manager.IsFocusGroup(actor) == false);
+
+  // Set the actor as focus group
+  manager.SetAsFocusGroup(actor, true);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(manager.IsFocusGroup(actor) == true);
+
+  // Set the actor not as focus group
+  manager.SetAsFocusGroup(actor, false);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(manager.IsFocusGroup(actor) == false);
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerGetFocusGroup(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerGetFocusGroup");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create an actor with two child actors and add it to the stage
+  Actor parent = Actor::New();
+  Actor child = Actor::New();
+  parent.Add(child);
+  Stage::GetCurrent().Add(parent);
+
+  // Create three actors and add them as the children of the first child actor
+  Actor grandChild = Actor::New();
+  child.Add(grandChild);
+
+  // Set the parent and the first child actor as focus groups
+  manager.SetAsFocusGroup(parent, true);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(manager.IsFocusGroup(parent) == true);
+
+  // The current focus group should be the parent, As it is the immediate parent which is also a focus group.
+  DALI_TEST_CHECK(manager.GetFocusGroup(grandChild) == parent);
+
+  manager.SetAsFocusGroup(child, true);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(manager.IsFocusGroup(child) == true);
+
+  // The focus group should be the child, As it is the immediate parent which is also a focus group.
+  DALI_TEST_CHECK(manager.GetFocusGroup(grandChild) == child);
+
+  manager.SetAsFocusGroup(grandChild, true);
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(manager.IsFocusGroup(grandChild) == true);
+
+  // The current focus group should be itself, As it is also a focus group.
+  DALI_TEST_CHECK(manager.GetFocusGroup(grandChild) == grandChild);
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSetAndGetFocusIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSetAndGetFocusIndicator");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  Actor defaultFocusIndicatorActor = manager.GetFocusIndicatorActor();
+  DALI_TEST_CHECK(defaultFocusIndicatorActor);
+
+  Actor newFocusIndicatorActor = Actor::New();
+  manager.SetFocusIndicatorActor(newFocusIndicatorActor);
+  DALI_TEST_CHECK(manager.GetFocusIndicatorActor() == newFocusIndicatorActor);
+  END_TEST;
+}
+
+
+int UtcDaliKeyboardFocusManagerSignalFocusedActorActivated(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSignalFocusedActorActivated");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool focusedActorActivatedSignalVerified = false;
+  FocusedActorActivatedCallback focusedActorActivatedCallback(focusedActorActivatedSignalVerified);
+  manager.FocusedActorEnterKeySignal().Connect( &focusedActorActivatedCallback, &FocusedActorActivatedCallback::Callback );
+
+  Integration::KeyEvent returnEvent( "Return", "", "", 0, 0, 0, Integration::KeyEvent::Up, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true
+  application.ProcessEvent(returnEvent);
+
+  // Create the first button and add it to the stage
+  PushButton firstPushButton = PushButton::New();
+  firstPushButton.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(firstPushButton);
+
+  // Create the second button and add it to the stage
+  PushButton secondPushButton = PushButton::New();
+  secondPushButton.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(secondPushButton);
+
+  // Check that the focus is set on the first button
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(firstPushButton) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstPushButton);
+
+  // Send the return event to activate the first button
+  application.ProcessEvent(returnEvent);
+  DALI_TEST_CHECK(focusedActorActivatedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusedActorActivatedCallback.mActivatedActor == firstPushButton);
+  focusedActorActivatedCallback.Reset();
+
+  // Check that the focus is set on the second button
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(secondPushButton) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondPushButton);
+
+  // Send the return event again to activate the second button
+  application.ProcessEvent(returnEvent);
+  DALI_TEST_CHECK(focusedActorActivatedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusedActorActivatedCallback.mActivatedActor == secondPushButton);
+  focusedActorActivatedCallback.Reset();
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSignalFocusGroupChanged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSignalFocusGroupChanged");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool focusGroupChangedSignalVerified = false;
+  FocusGroupChangedCallback focusGroupChangedCallback(focusGroupChangedSignalVerified);
+  manager.FocusGroupChangedSignal().Connect( &focusGroupChangedCallback, &FocusGroupChangedCallback::Callback );
+
+  Integration::KeyEvent tabEvent( "Tab", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent shiftTabEvent( "Tab", "", "", 0, 1, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true
+  application.ProcessEvent(tabEvent);
+
+  // Send the tab event to change focus group in the forward direction
+  application.ProcessEvent(tabEvent);
+  DALI_TEST_CHECK(focusGroupChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusGroupChangedCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(focusGroupChangedCallback.mForward == true);
+  focusGroupChangedCallback.Reset();
+
+  // Send the shift tab event to change focus group in the backward direction
+  application.ProcessEvent(shiftTabEvent);
+  DALI_TEST_CHECK(focusGroupChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusGroupChangedCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(focusGroupChangedCallback.mForward == false);
+  focusGroupChangedCallback.Reset();
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSignals(void)
+{
+  ToolkitTestApplication application;
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( manager );
+
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  DALI_TEST_EQUALS( true, manager.ConnectSignal( testTracker, "keyboardPreFocusChange", CallbackFunctor() ), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, manager.ConnectSignal( testTracker, "keyboardFocusChanged", CallbackFunctor() ), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, manager.ConnectSignal( testTracker, "keyboardFocusGroupChanged", CallbackFunctor() ), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, manager.ConnectSignal( testTracker, "keyboardFocusedActorEnterKey", CallbackFunctor() ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerMoveFocusBackward(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerMoveFocusBackward");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  // Create the first actor and add it to the stage
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Create the third actor and add it to the stage
+  Actor third = Actor::New();
+  third.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(third);
+
+  // Create the fourth actor and add it to the stage
+  Actor fourth = Actor::New();
+  fourth.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(fourth);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+
+  // Check that the focus is set on the third  actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+
+  // Check that the focus is set on the third  actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(fourth) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+
+  // Move the focus backward
+  manager.MoveFocusBackward();
+
+  // Check that it current focused actor is third actor
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+
+  // Remove the second actor on stage
+  second.Unparent();
+
+  // Reset the first actor
+  first.Unparent();
+  first.Reset();
+
+  // Move the focus backward
+  manager.MoveFocusBackward();
+
+  // Check that it current focused actor is third actor
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+
+  // Make history stack full
+  for(int i = 0 ; i < 31 ; i ++)
+  {
+    Actor actor = Actor::New();
+    actor.SetKeyboardFocusable(true);
+    Stage::GetCurrent().Add(actor);
+    manager.SetCurrentFocusActor(actor);
+  }
+
+  for(int i = 0 ; i < 31 ; i ++)
+  {
+    manager.MoveFocusBackward();
+  }
+
+  // Check that it current focused actor is not second actor
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() != second);
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerChangeFocusDirectionByKeyEvents(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerChangeFocusDirectionByKeyEvents");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  Integration::KeyEvent leftEvent( "Left", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent rightEvent( "Right", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent upEvent( "Up", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent downEvent( "Down", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent pageUpEvent( "Prior", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  Integration::KeyEvent pageDownEvent( "Next", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true
+  application.ProcessEvent(leftEvent);
+
+  // Create a 2x2 table view and try to move focus inside it
+  TableView tableView = TableView::New( 2, 2 );
+  Stage::GetCurrent().Add(tableView);
+
+  // Create the first actor
+  Actor first = Actor::New();
+  first.SetKeyboardFocusable(true);
+
+  // Create the second actor
+  Actor second = Actor::New();
+  second.SetKeyboardFocusable(true);
+
+  // Create the third actor
+  Actor third = Actor::New();
+  third.SetKeyboardFocusable(true);
+
+  // Create the fourth actor
+  Actor fourth = Actor::New();
+  fourth.SetKeyboardFocusable(true);
+
+  // Add the four children to table view
+  tableView.AddChild(first, TableView::CellPosition(0, 0));
+  tableView.AddChild(second, TableView::CellPosition(0, 1));
+  tableView.AddChild(third, TableView::CellPosition(1, 0));
+  tableView.AddChild(fourth, TableView::CellPosition(1, 1));
+
+  // Set the focus to the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Send the right key event to move the focus towards right
+  application.ProcessEvent(rightEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  focusChangedCallback.Reset();
+
+  // Send the down key event to move the focus towards down
+  application.ProcessEvent(downEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth);
+  focusChangedCallback.Reset();
+
+  // Send the down event to move the focus towards left
+  application.ProcessEvent(leftEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == third);
+  focusChangedCallback.Reset();
+
+  // Send the up event to move the focus towards up
+  application.ProcessEvent(upEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == third);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Send the pape up event, but focus should not be moved because page up is not supported by table view
+  application.ProcessEvent(pageUpEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::PAGE_UP);
+  preFocusChangeCallback.Reset();
+
+  // Send the pape down event, but focus should not be moved because page down is not supported by table view
+  application.ProcessEvent(pageDownEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::PAGE_DOWN);
+  preFocusChangeCallback.Reset();
+
+  // Clear the focus
+  manager.ClearFocus();
+
+  // Send the pape up event, but nothing was focued so focus manager will try the initial focus
+  preFocusChangeCallback.Reset();
+  application.ProcessEvent(pageUpEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+
+  // Clear the focus again
+  manager.ClearFocus();
+
+  // Send the pape down event, but nothing was focued so focus manager will try the initial focus
+  preFocusChangeCallback.Reset();
+  application.ProcessEvent(pageDownEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+
+  // Clear the focus again
+  manager.ClearFocus();
+
+  // Send the up event for line coverage, but nothing was focued so focus manager will try the initial focus
+  preFocusChangeCallback.Reset();
+  application.ProcessEvent(upEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+
+  // Clear the focus again
+  manager.ClearFocus();
+
+  // Send the down event for line coverage, but nothing was focued so focus manager will try the initial focus
+  preFocusChangeCallback.Reset();
+  application.ProcessEvent(downEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerSignalChangedBySpaceKeyEvent(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerSignalChangedBySpaceKeyEvent");
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  Integration::KeyEvent spaceEvent( "space", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true
+  application.ProcessEvent(spaceEvent);
+
+  // Send the space event
+  application.ProcessEvent(spaceEvent);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+
+  // Clear the focus again
+  manager.ClearFocus();
+
+  // Send the space event again for line coverage
+  preFocusChangeCallback.Reset();
+  application.ProcessEvent(spaceEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+
+  END_TEST;
+}
+
+
+
+int UtcDaliKeyboardFocusManagerMoveFocusTestStateChange(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerMoveFocusTestStateChange");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "KeyboardFocusManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool preFocusChangeSignalVerified = false;
+  PreFocusChangeCallback preFocusChangeCallback(preFocusChangeSignalVerified);
+  manager.PreFocusChangeSignal().Connect( &preFocusChangeCallback, &PreFocusChangeCallback::Callback );
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  // Create the first actor and add it to the stage
+  Control first = Control::New();
+  first.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(first);
+
+  // Create the second actor and add it to the stage
+  Control second = Control::New();
+  second.SetKeyboardFocusable(true);
+  Stage::GetCurrent().Add(second);
+
+  // Move the focus to the right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+  preFocusChangeCallback.Reset();
+
+  // Check that the focus is set on the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+
+  // Because no layout control in the stage and the first actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::RIGHT);
+  preFocusChangeCallback.Reset();
+
+  // Check that the focus is set on the second actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == false);
+
+  // Because no layout control in the stage and no actor is focused, it should emit the PreFocusChange signal
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == second);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::UP);
+  preFocusChangeCallback.Reset();
+  DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
+
+  // Create a 2x2 table view and try to move focus inside it
+  TableView tableView = TableView::New( 2, 2 );
+  Stage::GetCurrent().Add(tableView);
+
+  // Create the third actor
+  Control third = Control::New();
+  third.SetKeyboardFocusable(true);
+
+  // Create the fourth actor
+  Control fourth = Control::New();
+  fourth.SetKeyboardFocusable(true);
+
+  // Add the four children to table view
+  tableView.AddChild(first, TableView::CellPosition(0, 0));
+  tableView.AddChild(second, TableView::CellPosition(0, 1));
+  tableView.AddChild(third, TableView::CellPosition(1, 0));
+  tableView.AddChild(fourth, TableView::CellPosition(1, 1));
+
+  // Set the focus to the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+
+  focusChangedCallback.Reset();
+
+  // Move the focus towards right
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+
+  focusChangedCallback.Reset();
+
+  // Move the focus towards down
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::DOWN) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth);
+
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == third);
+
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+
+  focusChangedCallback.Reset();
+
+  // Move the focus towards up
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == third);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  focusChangedCallback.Reset();
+
+  // Move the focus towards left. The focus move will fail as no way to move it upwards
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == false);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mSignalVerified);
+  DALI_TEST_CHECK(preFocusChangeCallback.mCurrentFocusedActor == first);
+  DALI_TEST_CHECK(preFocusChangeCallback.mProposedActorToFocus == Actor());
+  DALI_TEST_CHECK(preFocusChangeCallback.mDirection == Control::KeyboardFocus::LEFT);
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+
+  preFocusChangeCallback.Reset();
+  DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
+
+  // Enable the loop
+  manager.SetFocusGroupLoop(true);
+  DALI_TEST_CHECK(manager.GetFocusGroupLoop() == true);
+
+  // Move the focus towards left again. The focus should move to the fourth actor.
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == fourth);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == fourth);
+
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+
+  focusChangedCallback.Reset();
+
+  // Clear the focus
+  manager.ClearFocus();
+  DALI_TEST_EQUALS(first.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(second.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(third.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+  DALI_TEST_EQUALS(fourth.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::NORMAL, TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerFocusedActorUnstaged(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Ensure we cannot set an actor to be focused if it is not staged and that we do not retrieve an actor if it has been unstaged" );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  Actor actor = Actor::New();
+  actor.SetKeyboardFocusable( true );
+
+  tet_infoline( "Attempt to set unstaged actor, no actor should be returned from KeyboardFocusManager" );
+  manager.SetCurrentFocusActor( actor );
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  tet_infoline( "Add actor to stage and attempt to set, our actor should be returned from KeyboardFocusManager" );
+  Stage::GetCurrent().Add( actor );
+  manager.SetCurrentFocusActor( actor );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor() == actor );
+
+  tet_infoline( "Remove actor from stage and attempt to retrieve, no actor should be returned from KeyboardFocusManager" );
+  actor.Unparent();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerEnableFocusIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Ensure we cannot set an actor to be focused if it is not staged and that we do not retrieve an actor if it has been unstaged" );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  Actor actor = Actor::New();
+  actor.SetKeyboardFocusable( true );
+  Stage::GetCurrent().Add( actor );
+  manager.SetCurrentFocusActor( actor );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true and add focus indicator to focused actor.
+  Integration::KeyEvent rightEvent( "Right", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  application.ProcessEvent(rightEvent);
+
+  Actor indicatorActor = manager.GetFocusIndicatorActor();
+
+  tet_infoline( "Indicator is added to focused actor" );
+  DALI_TEST_CHECK( actor == indicatorActor.GetParent() );
+
+  Dali::Toolkit::DevelKeyboardFocusManager::EnableFocusIndicator(manager, false);
+  DALI_TEST_CHECK( !Dali::Toolkit::DevelKeyboardFocusManager::IsFocusIndicatorEnabled(manager) );
+
+  tet_infoline( "Indicator is removed from focused actor because mUseFocusIndicator is false" );
+  DALI_TEST_CHECK( !indicatorActor.GetParent() );
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerCheckConsumedKeyEvent(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Ensure Window can't receive KeyEvent when Control already consumed it" );
+  Dali::Integration::Scene scene = application.GetScene();
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  // Create the first actor and add it to the stage
+  Control control = Control::New();
+  control.SetKeyboardFocusable(true);
+  scene.Add(control);
+
+  KeyEventCallback controlCallback( true );
+  control.KeyEventSignal().Connect( &controlCallback, &KeyEventCallback::Callback );
+
+  KeyEventCallback sceneCallback( false );
+  scene.KeyEventSignal().Connect( &sceneCallback, &KeyEventCallback::Callback );
+
+  manager.SetCurrentFocusActor( control );
+
+  // Press Any key to notice physical keyboard event is comming to KeyboardFocusManager
+  // It makes mIsFocusIndicatorEnabled true and add focus indicator to focused actor.
+  Integration::KeyEvent event1( "Right", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE );
+  application.ProcessEvent(event1);
+
+  DALI_TEST_CHECK( controlCallback.mIsCalled );
+  DALI_TEST_CHECK( !sceneCallback.mIsCalled );
+
+  END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerFocusPerWindow(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Ensure Memory focus actors for each window ");
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  Window firstWindow = Window::New(PositionSize(0,0,300,500) ,"", false);
+  DALI_TEST_CHECK( firstWindow );
+  Control first = Control::New();
+  first.SetKeyboardFocusable(true);
+  firstWindow.Add(first);
+
+  Window secondWindow = Window::New(PositionSize(0,0,400,600) ,"", false);
+  DALI_TEST_CHECK( secondWindow );
+  Control second = Control::New();
+  second.SetKeyboardFocusable(true);
+  secondWindow.Add( second );
+
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  firstWindow.Raise();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+
+  secondWindow.Remove( second );
+  secondWindow.Raise();
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() != second);
+
+  secondWindow.Reset();
+  END_TEST;
+}
+
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Magnifier.cpp
new file mode 100644 (file)
index 0000000..2771fbd
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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 <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/magnifier/magnifier.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_magnifier_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_magnifier_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliMagnifierNew(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier magnifier;
+  DALI_TEST_CHECK( !magnifier );
+
+  magnifier = Magnifier::New();
+  DALI_TEST_CHECK( magnifier );
+
+  Stage::GetCurrent().Add( magnifier );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view = Magnifier::New();
+  DALI_TEST_CHECK( view );
+
+  Magnifier copy( view );
+  DALI_TEST_CHECK( copy == view );
+
+  Magnifier assign;
+  DALI_TEST_CHECK( !assign );
+  assign = view;
+  DALI_TEST_CHECK( assign == view );
+
+  // Self assignment
+  assign = assign;
+  DALI_TEST_CHECK( assign );
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle view = Magnifier::New();
+  DALI_TEST_CHECK( Magnifier::DownCast( view ) );
+
+  BaseHandle empty;
+  DALI_TEST_CHECK( ! Magnifier::DownCast( empty ) );
+
+  BaseHandle another = Actor::New();
+  DALI_TEST_CHECK( ! Magnifier::DownCast( another ) );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "Magnifier" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  Magnifier view = Magnifier::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSetSourceActorP(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  RenderTaskList renderTaskList = stage.GetRenderTaskList();
+  DALI_TEST_CHECK( renderTaskList.GetTaskCount() > 1 );
+
+  Actor actor = Actor::New();
+  stage.Add( actor );
+  DALI_TEST_CHECK( stage.GetRenderTaskList().GetTask( 1 ).GetSourceActor() != actor );
+
+  view.SetSourceActor( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( stage.GetRenderTaskList().GetTask( 1 ).GetSourceActor(), actor, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSetSourceActorN(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view;
+
+  try
+  {
+    view.SetSourceActor( Actor::New() );
+    DALI_TEST_CHECK( false ); // should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierFrameVisibility(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::FRAME_VISIBILITY, false );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), false, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::FRAME_VISIBILITY, true );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::FRAME_VISIBILITY ).Get< bool >(), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierMagnificationFactor(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  float magnificationFactor( 200.0f );
+
+  DALI_TEST_CHECK( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >() != magnificationFactor );
+
+  view.SetProperty( Magnifier::Property::MAGNIFICATION_FACTOR, magnificationFactor );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), magnificationFactor, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), magnificationFactor, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::MAGNIFICATION_FACTOR, 1.0f );
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), 1.0f, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::MAGNIFICATION_FACTOR ).Get< float >(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierSourcePosition(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  Magnifier view = Magnifier::New();
+  stage.Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position( 100.0f, 200.0f, 300.0f );
+
+  DALI_TEST_CHECK( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >() != position );
+
+  view.SetProperty( Magnifier::Property::SOURCE_POSITION, position );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >(), position, TEST_LOCATION );
+
+  view.SetProperty( Magnifier::Property::SOURCE_POSITION, Vector3::ONE );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( view.GetProperty( Magnifier::Property::SOURCE_POSITION ).Get< Vector3 >(), Vector3::ONE, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliMagnifierOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+
+  Magnifier view = Magnifier::New();
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 0.0f );
+  view.SetSize( size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Model3dView.cpp
new file mode 100644 (file)
index 0000000..0d699f6
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+
+void model_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
+const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/";
+}
+
+// Negative test case for a method
+int UtcDaliModelViewUninitialized(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliModel3dViewUninitialized");
+
+  Toolkit::Model3dView view;
+
+  try
+  {
+    // New() must be called to create a Model3dView or it wont be valid.
+    Actor a = Actor::New();
+    view.Add( a );
+    DALI_TEST_CHECK( false );
+  }
+  catch (Dali::DaliException& e)
+  {
+    // Tests that a negative test of an assertion succeeds
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_CHECK(!view);
+  }
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliModelViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliModel3dViewNew");
+
+  Toolkit::Model3dView view = Toolkit::Model3dView::New();
+  DALI_TEST_CHECK( view );
+
+  Toolkit::Model3dView view2 = Toolkit::Model3dView::New("","","");
+  DALI_TEST_CHECK( view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliModelViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliModelViewDownCast");
+
+  Toolkit::Model3dView view = Toolkit::Model3dView::New();
+  BaseHandle handle(view);
+
+  Toolkit::Model3dView modelView = Toolkit::Model3dView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( modelView );
+  DALI_TEST_CHECK( modelView == view );
+  END_TEST;
+}
+
+
+// Positive test case for a method
+int UtcDaliModelViewPropertyNames(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliModel3dViewPropertyNames");
+
+  Toolkit::Model3dView view = Toolkit::Model3dView::New();
+  DALI_TEST_CHECK( view );
+
+  view.SetProperty( Model3dView::Property::GEOMETRY_URL, Dali::Property::Value( TEST_OBJ_FILE_NAME ) );
+  Property::Value val = view.GetProperty( Model3dView::Property::GEOMETRY_URL );
+  std::string obj_file_name;
+  DALI_TEST_CHECK( val.Get( obj_file_name ) );
+  DALI_TEST_EQUALS( obj_file_name, TEST_OBJ_FILE_NAME, TEST_LOCATION );
+
+  view.SetProperty( Model3dView::Property::MATERIAL_URL, Dali::Property::Value( TEST_MTL_FILE_NAME ) );
+  val = view.GetProperty( Model3dView::Property::MATERIAL_URL );
+  DALI_TEST_CHECK( val.Get( obj_file_name ) );
+  DALI_TEST_EQUALS( obj_file_name, TEST_MTL_FILE_NAME, TEST_LOCATION );
+
+  view.SetProperty( Model3dView::Property::IMAGES_URL, Dali::Property::Value( TEST_RESOURCE_LOCATION ) );
+  val = view.GetProperty( Model3dView::Property::IMAGES_URL );
+  DALI_TEST_CHECK( val.Get( obj_file_name ) );
+  DALI_TEST_EQUALS( obj_file_name, TEST_RESOURCE_LOCATION, TEST_LOCATION );
+
+  Stage::GetCurrent().Add(view);
+
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliModelViewAddRemove(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliModel3dViewAddRemove");
+
+  Toolkit::Model3dView view = Toolkit::Model3dView::New();
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(actor);
+  Stage::GetCurrent().Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+
+  view.Remove(actor);
+
+  DALI_TEST_CHECK( !actor.OnStage() );
+  END_TEST;
+}
+
+
+int UtcDaliModelCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  Model3dView view = Toolkit::Model3dView::New();
+  DALI_TEST_CHECK( view );
+
+  Model3dView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  Model3dView assign;
+  DALI_TEST_CHECK( ! assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliModelTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "Model3dView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  Model3dView view = Model3dView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliModelOnSizeSet(void)
+{
+  ToolkitTestApplication application;
+
+  Model3dView view = Toolkit::Model3dView::New();
+
+  Stage::GetCurrent().Add( view );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 size( 200.0f, 300.0f, 0.0f );
+  view.SetSize( size );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( view.GetCurrentSize(), size, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-NavigationView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-NavigationView.cpp
new file mode 100644 (file)
index 0000000..e91b2cc
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * 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 <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/navigation-view/navigation-view.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_navigationView_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_navigationView_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliNavigationTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "NavigationView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  NavigationView view = NavigationView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  NavigationView navigationView;
+  DALI_TEST_CHECK( !navigationView );
+
+  navigationView = NavigationView::New();
+  DALI_TEST_CHECK( navigationView );
+
+  Stage::GetCurrent().Add( navigationView );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  NavigationView view = NavigationView::New();
+  DALI_TEST_CHECK( view );
+
+  NavigationView copy( view );
+  DALI_TEST_CHECK( copy == view );
+
+  NavigationView assign;
+  DALI_TEST_CHECK( !assign );
+  assign = view;
+  DALI_TEST_CHECK( assign == view );
+
+  // Self assignment
+  assign = assign;
+  DALI_TEST_CHECK( assign );
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle view = NavigationView::New();
+  DALI_TEST_CHECK( NavigationView::DownCast( view ) );
+
+  BaseHandle empty;
+  DALI_TEST_CHECK( ! NavigationView::DownCast( empty ) );
+
+  BaseHandle another = Actor::New();
+  DALI_TEST_CHECK( ! NavigationView::DownCast( another ) );
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewPush(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  // 1 Create and Add Navigation View to stage, actor count should be zero
+  NavigationView naviView = NavigationView::New();
+  stage.Add( naviView );
+
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 0,  TEST_LOCATION );
+
+  // 2 Add Actor to Navigation View, actor count should increase to 1
+
+  Actor TestParentActor1 = Actor::New();
+  naviView.Push( TestParentActor1 );
+
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 1,  TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewPop(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  // 1 Create Navigation View
+  NavigationView naviView = NavigationView::New();
+  stage.Add( naviView );
+
+  // 2 Push initial Actor
+  Actor testParentActor1 = Actor::New();
+  testParentActor1.SetName("TestParentActor1");
+  naviView.Push( testParentActor1 );
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 1 ,  TEST_LOCATION );
+
+  // 3 Push Second Actor which contains a child actor
+  Actor testParentActor2 = Actor::New();
+  testParentActor2.SetName("TestParentActor2");
+  Actor testChildActor1 = Actor::New();
+  testParentActor2.Add( testChildActor1 );
+  naviView.Push( testParentActor2 );
+
+
+  // 4 Pop head actor, it should be TestParentActor2
+  Actor poppedActor = naviView.Pop();
+  DALI_TEST_EQUALS( poppedActor.GetName() ,  "TestParentActor2", TEST_LOCATION );
+
+  // 5 Navigation View child count should be 1
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 1 ,  TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewPushAndPop(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  // 1 Create Navigation View
+  NavigationView naviView = NavigationView::New();
+  stage.Add( naviView );
+
+  // 2 Push initial Actor
+  Actor testParentActor1 = Actor::New();
+  testParentActor1.SetName("TestParentActor1");
+  naviView.Push( testParentActor1 );
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 1 ,  TEST_LOCATION );
+
+  // 3 Push Second Actor which contains a child actor
+  Actor testParentActor2 = Actor::New();
+  testParentActor2.SetName("TestParentActor2");
+  Actor testChildActor1 = Actor::New();
+  testParentActor2.Add( testChildActor1 );
+  naviView.Push( testParentActor2 );
+
+  // 3 Push third Actor which contains a child actor
+  Actor testParentActor3 = Actor::New();
+  testParentActor3.SetName("TestParentActor3");
+  Actor testChildActor2 = Actor::New();
+  testParentActor2.Add( testChildActor2 );
+  naviView.Push( testParentActor3 );
+
+  // 4 Pop head actor,  it should be TestParentActor3
+  Actor poppedActor = naviView.Pop();
+  DALI_TEST_EQUALS( poppedActor.GetName() ,  "TestParentActor3", TEST_LOCATION );
+
+  // 5 Pop head actor,  it should be TestParentActor2
+  Actor poppedActor2 = naviView.Pop();
+  DALI_TEST_EQUALS( poppedActor2.GetName() ,  "TestParentActor2", TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliNavigationViewPreventLastPop(void)
+{
+  ToolkitTestApplication application;
+
+  Stage stage = Stage::GetCurrent();
+
+  // 1 Create Navigation View
+  NavigationView naviView = NavigationView::New();
+  stage.Add( naviView );
+
+  // 2 Push initial Actor
+  Actor testParentActor1 = Actor::New();
+  testParentActor1.SetName("TestParentActor1");
+  naviView.Push( testParentActor1 );
+  DALI_TEST_EQUALS( naviView.GetChildCount(), 1 ,  TEST_LOCATION );
+
+  // 3 Push Second Actor which contains a child actor
+  Actor testParentActor2 = Actor::New();
+  testParentActor2.SetName("TestParentActor2");
+  Actor testChildActor1 = Actor::New();
+  testParentActor2.Add( testChildActor1 );
+  naviView.Push( testParentActor2 );
+
+  // 4 Pop head actor, it should be TestParentActor2
+  Actor poppedActor1 = naviView.Pop();
+  DALI_TEST_EQUALS( poppedActor1.GetName() ,  "TestParentActor2", TEST_LOCATION );
+
+
+  // 5 Try to Pop head actor, Should be empty hence can not get name of Actor
+  Actor poppedActorEmpty = naviView.Pop();
+
+  try
+  {
+    const std::string hasNoName = poppedActorEmpty.GetName();
+    tet_infoline( hasNoName.c_str() );
+    DALI_TEST_CHECK( false ); // should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-PageTurnView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-PageTurnView.cpp
new file mode 100644 (file)
index 0000000..24c5d09
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2019 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 <string.h>
+#include <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-factory.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const int RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
+const unsigned int TOTAL_PAGE_NUMBER = 20;
+const Vector2 VIEW_PAGE_SIZE( 300.f,400.f );
+const Vector2 SPINE_SHADOW_PARAMETER( 60.0f, 30.0f );
+
+static bool gObjectCreatedCallBackCalled;
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+
+static Vector2 PerformGestureDiagonalSwipe(ToolkitTestApplication& application, Vector2 start, Vector2 direction, int frames, uint32_t& time, bool toStart = true, bool toFinish = true)
+{
+  Vector2 pos( start );
+
+  if( toStart )
+  {
+    // Now do a pan starting from (start + 20) and heading (direction)
+    Vector2 pos_start_jump( start + Vector2(15.0f, 0.0f) );
+    TestStartPan( application, start, pos_start_jump, time );
+    pos += direction;
+  }
+
+  time += Wait(application);
+
+  for(int i = 0;i<frames;i++)
+  {
+    pos += direction;
+    TestMovePan(application, pos, time );
+    time += Wait(application);
+  }
+
+  if(toFinish)
+  {
+    pos += direction;
+    TestEndPan(application, pos, time );
+    time += Wait(application);
+  }
+
+  return pos;
+}
+
+
+//Functor to test whether PageTurnSignal / PagePanSignal is emitted
+class PageSignalCallback : public Dali::ConnectionTracker
+{
+public:
+
+  PageSignalCallback( bool& signalReceived, PageTurnView& view, unsigned int& pageIndex, bool& isForwards )
+  : mSignalVerified( signalReceived ),
+    mView( view ),
+    mPageIndex( pageIndex ),
+    mIsTurningForwards( isForwards )
+  {
+  }
+
+  // callback to be connected to PageTurnSignal
+  void PageTurnSignalCallback( PageTurnView view, unsigned int pageIndex, bool isTurningForward )
+  {
+    tet_infoline( "Verifying PageTurnedSignal" );
+
+    if( mView == view && mPageIndex == pageIndex && mIsTurningForwards == isTurningForward )
+    {
+      mSignalVerified = true;
+    }
+  }
+
+  // callback to be connected to PagePanSignal
+  void PagePanSignalCallback( PageTurnView view )
+  {
+    tet_infoline( "Verifying PagePannedSignal" );
+
+    if( mView == view )
+    {
+      mSignalVerified = true;
+    }
+  }
+
+  void Reset()
+  {
+    mSignalVerified = false;
+  }
+
+  bool&         mSignalVerified;
+  PageTurnView& mView;
+  unsigned int& mPageIndex;
+  bool&         mIsTurningForwards;
+
+};
+
+
+//Implementation of PageFactory for providing page actors to PageTurnView
+class TestPageFactory : public PageFactory
+{
+public:
+
+  TestPageFactory( bool returnValidTexture = true )
+  : mValidTexture( returnValidTexture )
+  {
+    mTotalPageNumber = TOTAL_PAGE_NUMBER;
+  }
+
+  /**
+   * Query the number of pages available from the factory.
+   * The maximum available page has an ID of GetNumberOfPages()-1.
+   */
+  virtual unsigned int GetNumberOfPages()
+  {
+    return mTotalPageNumber;
+  }
+
+  /**
+   * Create an texture to represent a page content.
+   * @param[in] pageId The ID of the page to create.
+   * @return An image, or an empty handle if the ID is out of range.
+   */
+  virtual Texture NewPage( unsigned int pageId )
+  {
+    if( mValidTexture )
+    {
+      return Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGB888, 100, 100 );
+    }
+    return Texture(); // empty handle
+  }
+
+private:
+  unsigned int            mTotalPageNumber;
+  bool                    mValidTexture;
+};
+
+}// namespace
+
+void dali_page_turn_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_page_turn_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliPageTurnPortraitViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnViewNew ");
+
+  // Test default constructor
+  PageTurnView portraitView;
+  DALI_TEST_CHECK( !portraitView );
+
+  // Test object creation
+  TestPageFactory factory;
+  portraitView = PageTurnPortraitView::New( factory, VIEW_PAGE_SIZE );
+  DALI_TEST_CHECK( portraitView );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    TestPageFactory factory;
+    PageTurnView portraitView = PageTurnPortraitView::New( factory, VIEW_PAGE_SIZE );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+
+  // Test copy constructor
+  PageTurnView viewCopy( portraitView );
+  DALI_TEST_CHECK( viewCopy );
+
+  // Test down cast
+  Handle handleView;
+  handleView = portraitView;
+  PageTurnView downCastView = PageTurnView::DownCast( handleView );
+  DALI_TEST_CHECK( downCastView );
+
+  END_TEST;
+}
+
+int UtcDaliPageTurnLandscapeViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnViewNew ");
+
+  //Test default constructor
+  PageTurnView landscapeView;
+  DALI_TEST_CHECK( !landscapeView );
+
+  // Test object creation
+  TestPageFactory factory;
+  landscapeView = PageTurnLandscapeView::New( factory, VIEW_PAGE_SIZE );
+  DALI_TEST_CHECK( landscapeView );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    TestPageFactory factory;
+    PageTurnView landscapeView = PageTurnLandscapeView::New( factory, VIEW_PAGE_SIZE );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+
+  // Test copy constructor
+  PageTurnView viewCopy( landscapeView );
+  DALI_TEST_CHECK( viewCopy );
+
+  // Test down cast
+  Handle handleView;
+  handleView = landscapeView;
+  PageTurnView downCastView = PageTurnView::DownCast( handleView );
+  DALI_TEST_CHECK( downCastView );
+
+  END_TEST;
+}
+
+int UtcDaliPageTurnPortraitViewCopyConstructorAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnPortraitViewCopyConstructorAndAssignment ");
+
+  // Test default constructor
+  PageTurnPortraitView portraitView;
+  DALI_TEST_CHECK( !portraitView );
+
+  // Test object creation
+  TestPageFactory factory;
+  portraitView = PageTurnPortraitView::New( factory, VIEW_PAGE_SIZE );
+  DALI_TEST_CHECK( portraitView );
+
+  // Test copy constructor
+  PageTurnPortraitView viewCopy( portraitView );
+  DALI_TEST_CHECK( viewCopy );
+
+  // Test assignment
+  PageTurnPortraitView portraitView2;
+  portraitView2 = portraitView;
+  DALI_TEST_CHECK( portraitView2 );
+  DALI_TEST_CHECK( portraitView == portraitView2);
+
+  // Test down cast
+  Handle handleView;
+  handleView = portraitView;
+  PageTurnPortraitView downCastView = PageTurnPortraitView::DownCast( handleView );
+  DALI_TEST_CHECK( downCastView );
+
+  END_TEST;
+}
+
+int UtcDaliPageTurnLandscapeViewCopyConstructorAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnLandscapeViewCopyConstructorAndAssignment ");
+
+  // Test default constructor
+  PageTurnLandscapeView landscapeView;
+  DALI_TEST_CHECK( !landscapeView );
+
+  // Test object creation
+  TestPageFactory factory;
+  landscapeView = PageTurnLandscapeView::New( factory, VIEW_PAGE_SIZE );
+  DALI_TEST_CHECK( landscapeView );
+
+  // Test copy constructor
+  PageTurnLandscapeView viewCopy( landscapeView );
+  DALI_TEST_CHECK( viewCopy );
+
+  // Test assignment
+  PageTurnLandscapeView landscapeView2;
+  landscapeView2 = landscapeView;
+  DALI_TEST_CHECK( landscapeView2 );
+  DALI_TEST_CHECK( landscapeView == landscapeView2);
+
+  // Test down cast
+  Handle handleView;
+  handleView = landscapeView;
+  PageTurnLandscapeView downCastView = PageTurnLandscapeView::DownCast( handleView );
+  DALI_TEST_CHECK( downCastView );
+
+  END_TEST;
+}
+
+int UtcDaliPageTurnViewSetGetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnViewSetGetProperty ");
+
+  TestPageFactory factory;
+  PageTurnView landscapeView = PageTurnLandscapeView::New( factory, VIEW_PAGE_SIZE );
+  DALI_TEST_CHECK( landscapeView );
+
+  Stage::GetCurrent().Add( landscapeView );
+
+  // Test "viewPageSize" property
+  DALI_TEST_CHECK( landscapeView.GetPropertyIndex("viewPageSize") == PageTurnView::Property::VIEW_PAGE_SIZE  );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::VIEW_PAGE_SIZE).Get<Vector2>(), VIEW_PAGE_SIZE, TEST_LOCATION );
+
+  Vector2 newSize( VIEW_PAGE_SIZE.x*0.75, VIEW_PAGE_SIZE.y*0.5f );
+  landscapeView.SetProperty( PageTurnView::Property::VIEW_PAGE_SIZE, newSize );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::VIEW_PAGE_SIZE).Get<Vector2>(), newSize, TEST_LOCATION );
+  Wait( application);
+  DALI_TEST_EQUALS( Vector2(landscapeView.GetTargetSize()), Vector2(newSize.x*2.f, newSize.y), TEST_LOCATION);
+
+  landscapeView.SetProperty( PageTurnView::Property::VIEW_PAGE_SIZE,newSize*1.5f);
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::VIEW_PAGE_SIZE).Get<Vector2>(), newSize*1.5f, TEST_LOCATION );
+  Wait( application);
+  DALI_TEST_EQUALS( Vector2(landscapeView.GetTargetSize()), Vector2(newSize.x*3.f, newSize.y*1.5f), TEST_LOCATION);
+
+  // Test "currentPageId" property
+  DALI_TEST_CHECK( landscapeView.GetPropertyIndex("currentPageId") == PageTurnView::Property::CURRENT_PAGE_ID );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 0, TEST_LOCATION );
+
+  int pageId = static_cast<int>(TOTAL_PAGE_NUMBER)/3;
+  landscapeView.SetProperty( PageTurnView::Property::CURRENT_PAGE_ID, pageId );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), pageId, TEST_LOCATION );
+
+  landscapeView.SetProperty( PageTurnView::Property::CURRENT_PAGE_ID, pageId*2 );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), pageId*2, TEST_LOCATION );
+
+  // Test "spinShadow" property
+  DALI_TEST_CHECK( landscapeView.GetPropertyIndex( "spineShadow" ) == PageTurnView::Property::SPINE_SHADOW );
+  landscapeView.SetProperty( PageTurnView::Property::SPINE_SHADOW, SPINE_SHADOW_PARAMETER );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::SPINE_SHADOW).Get<Vector2>(), SPINE_SHADOW_PARAMETER, TEST_LOCATION );
+
+  landscapeView.SetProperty( PageTurnView::Property::SPINE_SHADOW,  SPINE_SHADOW_PARAMETER*0.75f );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::SPINE_SHADOW).Get<Vector2>(), SPINE_SHADOW_PARAMETER*0.75f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPageTurnPortraitViewSignals(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnPortraitViewSignals ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+
+  TestPageFactory factory;
+  Vector2 size = Stage::GetCurrent().GetSize();
+  PageTurnView portraitView = PageTurnPortraitView::New( factory, size );
+  portraitView.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( portraitView );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // [0]: testing PageTurnStartedSignal;  [1]: testing PageTurnFinishedSignal
+  // [2]: testing PagePanStartedSignal;   [3]: testing PagePanFinishedSignal
+  bool signalVerified[4] = {false, false, false, false};
+  PageTurnView currentView;
+  unsigned int pageIndex;
+  bool isTurningForwards;
+
+  PageSignalCallback callbackTurnStarted( signalVerified[0], currentView, pageIndex, isTurningForwards );
+  portraitView.PageTurnStartedSignal().Connect( &callbackTurnStarted, &PageSignalCallback::PageTurnSignalCallback );
+
+  PageSignalCallback callbackTurnFinished( signalVerified[1], currentView, pageIndex, isTurningForwards );
+  portraitView.PageTurnFinishedSignal().Connect( &callbackTurnFinished, &PageSignalCallback::PageTurnSignalCallback );
+
+  PageSignalCallback callbackPanStarted( signalVerified[2], currentView, pageIndex, isTurningForwards );
+  portraitView.PagePanStartedSignal().Connect( &callbackPanStarted, &PageSignalCallback::PagePanSignalCallback );
+
+  PageSignalCallback callbackPanFinished( signalVerified[3], currentView, pageIndex, isTurningForwards );
+  portraitView.PagePanFinishedSignal().Connect( &callbackPanFinished, &PageSignalCallback::PagePanSignalCallback );
+
+  DALI_TEST_CHECK( !callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  currentView = portraitView;
+
+  //-----Test 1: pan 10 frames from position(size * 0.75f) to position(size * 0.25f), page 0 will be turned forward----
+  pageIndex = 0;
+  isTurningForwards = true;
+  // Do a pan moving up diagonally
+  uint32_t time = 0;
+  Vector2 start = size * 0.75f;
+  Vector2 direction = -size*0.05f; //-size*0.5f/10.f;
+
+  DALI_TEST_EQUALS( portraitView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 0, TEST_LOCATION );
+  PerformGestureDiagonalSwipe( application, start, direction, 5, time, true, false);
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  PerformGestureDiagonalSwipe( application, start+direction*5.f, direction, 5, time, false, true);
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+
+  time += Wait(application, 1000);
+  DALI_TEST_CHECK( callbackTurnFinished.mSignalVerified );
+  // the page is turned over
+  DALI_TEST_EQUALS( portraitView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), (int)(pageIndex+1), TEST_LOCATION );
+
+  //---Test 2: pan from position( size*0.5f ) to position( size.width, size.height*0.5f ) to position( size * 0.75f ), page 1 will bent then slid back---
+  callbackTurnStarted.Reset();
+  callbackTurnFinished.Reset();
+  callbackPanStarted.Reset();
+  callbackPanFinished.Reset();
+  portraitView.SetProperty( PageTurnView::Property::CURRENT_PAGE_ID, 5 );
+  pageIndex = 5;
+  isTurningForwards = true;
+
+  //pan 10 frames from position( size.width, size.height*0.5f ) to position( size * 0.75f )
+  start = Vector2( size.width, size.height*0.5f );
+  direction = Vector2(-size.width*0.025f, size.height*0.025f);
+  PerformGestureDiagonalSwipe( application, start, direction, 5, time, true, false);
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  signalVerified[0] = false;
+  isTurningForwards = false;
+  PerformGestureDiagonalSwipe( application, start + direction*2 , direction, 5, time, false, true);
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified ); // start the sliding back
+
+  time += Wait(application, 1000);
+  DALI_TEST_CHECK( callbackTurnFinished.mSignalVerified );
+  DALI_TEST_EQUALS( portraitView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), (int)pageIndex, TEST_LOCATION ); // the page is not turned over
+
+  // ----Test 3: pan 10 frames from position( size*0.25f ) to position( size.width*0.75f, size.height*0.25f ), the previous page will be turned backwards---
+  callbackTurnStarted.Reset();
+  callbackTurnFinished.Reset();
+  callbackPanStarted.Reset();
+  callbackPanFinished.Reset();
+  portraitView.SetProperty( PageTurnView::Property::CURRENT_PAGE_ID, 10);
+  pageIndex = 9; // will turn the previous page back
+  isTurningForwards = false;
+  start = size*0.25f;
+  direction = Vector2(size.x*0.05f, 0.f);
+  PerformGestureDiagonalSwipe( application, start, direction, 4, time, true, false);
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  PerformGestureDiagonalSwipe( application, start+direction*5.f, direction, 5, time, false, true);
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+
+  Wait( application, 1000 );
+
+  DALI_TEST_CHECK( callbackTurnFinished.mSignalVerified );
+  DALI_TEST_EQUALS( portraitView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 9, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPageTurnLanscapeViewSignals(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnLanscapeViewSignals ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+  /***
+   * -----------------
+   * |               |
+   * |---------------|
+   * |bookboo|bookboo|
+   * |kbookbo|kbookbo|
+   * |okbookb|okbookb|
+   * |ookbook|ookbook|
+   * |bookboo|bookboo|
+   * |---------------|
+   * |               |
+   * ----------------
+   */
+
+  TestPageFactory factory;
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  PageTurnView landscapeView = PageTurnLandscapeView::New( factory, Vector2(stageSize.x*0.5f, stageSize.x*0.8f) );
+  landscapeView.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( landscapeView );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render(RENDER_FRAME_INTERVAL);
+
+  // [0]: testing PageTurnStartedSignal;  [1]: testing PageTurnFinishedSignal
+  // [2]: testing PagePanStartedSignal;   [3]: testing PagePanFinishedSignal
+  bool signalVerified[4] = {false, false, false, false};
+  PageTurnView currentView;
+  unsigned int pageIndex;
+  bool isTurningForwards;
+
+  PageSignalCallback callbackTurnStarted( signalVerified[0], currentView, pageIndex, isTurningForwards );
+  landscapeView.PageTurnStartedSignal().Connect( &callbackTurnStarted, &PageSignalCallback::PageTurnSignalCallback );
+
+  PageSignalCallback callbackTurnFinished( signalVerified[1], currentView, pageIndex, isTurningForwards );
+  landscapeView.PageTurnFinishedSignal().Connect( &callbackTurnFinished, &PageSignalCallback::PageTurnSignalCallback );
+
+  PageSignalCallback callbackPanStarted( signalVerified[2], currentView, pageIndex, isTurningForwards );
+  landscapeView.PagePanStartedSignal().Connect( &callbackPanStarted, &PageSignalCallback::PagePanSignalCallback );
+
+  PageSignalCallback callbackPanFinished( signalVerified[3], currentView, pageIndex, isTurningForwards );
+  landscapeView.PagePanFinishedSignal().Connect( &callbackPanFinished, &PageSignalCallback::PagePanSignalCallback );
+
+  DALI_TEST_CHECK( !callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  currentView = landscapeView;
+
+  //-----Test 1: pan 10 frames from position(stageSize.x * 0.85f, stageSize.y*0.5) to position(stageSize.x * 0.45f, stageSize.y*0.5-stageSize.x * 0.3f), page 0 will be turned forward----
+  pageIndex = 0;
+  isTurningForwards = true;
+  // Do a pan to the left.
+  uint32_t time = 0;
+  Vector2 start = Vector2(stageSize.x * 0.85f, stageSize.y*0.5);
+  Vector2 direction = Vector2(-stageSize.x*0.04f, -stageSize.x*0.03f);
+
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 0, TEST_LOCATION );
+  PerformGestureDiagonalSwipe( application, start, direction, 5, time, true, false);
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  PerformGestureDiagonalSwipe( application, start+direction*5.f, direction, 5, time, false, true);
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+
+  time += Wait(application, 1000);
+  DALI_TEST_CHECK( callbackTurnFinished.mSignalVerified );
+  // the page is turned over
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), (int)(pageIndex+1), TEST_LOCATION );
+
+  //---Test 2: pan from position(stageSize.x * 0.15f, stageSize.y*0.5) to position(stageSize.x * 0.45f, stageSize.y*0.5) page 4 will be turned back---
+  callbackTurnStarted.Reset();
+  callbackTurnFinished.Reset();
+  callbackPanStarted.Reset();
+  callbackPanFinished.Reset();
+  isTurningForwards = false;
+
+  //pan 10 frames from position( size.width, size.height*0.5f ) to position( size * 0.75f )
+  start = Vector2( stageSize.x * 0.15f, stageSize.y*0.5f );
+  direction = Vector2(stageSize.x * 0.03f, 0.f);
+  PerformGestureDiagonalSwipe( application, start, direction, 5, time, true, false);
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  PerformGestureDiagonalSwipe( application, start + direction*5.f , direction, 5, time, false, true);
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+
+  time += Wait(application, 1000);
+  DALI_TEST_CHECK( callbackTurnFinished.mSignalVerified );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 0, TEST_LOCATION ); // the first page is turned back
+
+  // ----Test 3: pan 10 frames from position( size*0.55f ) to position( size.width*0.8f, size.height*0.5f ), no page turn will be started---
+  callbackTurnStarted.Reset();
+  callbackTurnFinished.Reset();
+  callbackPanStarted.Reset();
+  callbackPanFinished.Reset();
+  isTurningForwards = false;
+  start = stageSize*0.55f;
+  direction = Vector2(stageSize.x*0.025f, 0.f);
+  PerformGestureDiagonalSwipe( application, start, direction, 5, time, true, false);
+  DALI_TEST_CHECK( callbackPanStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackPanFinished.mSignalVerified );
+
+  PerformGestureDiagonalSwipe( application, start+direction*5.f, direction, 5, time, false, true);
+  DALI_TEST_CHECK( !callbackTurnStarted.mSignalVerified );
+  DALI_TEST_CHECK( callbackPanFinished.mSignalVerified );
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+
+  Wait( application, 1000 );
+
+  DALI_TEST_CHECK( !callbackTurnFinished.mSignalVerified );
+  DALI_TEST_EQUALS( landscapeView.GetProperty(PageTurnView::Property::CURRENT_PAGE_ID).Get<int>(), 0, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPageImageFactoryGetExtention(void)
+{
+  ToolkitTestApplication application;
+  TestPageFactory factory;
+  DALI_TEST_CHECK( factory.GetExtension() == NULL );
+  END_TEST;
+}
+
+int UtcDaliPageTurnEmptyTextureHandle(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliPageTurnEmptyTextureHandle ");
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE );
+
+  TestPageFactory factory( false /* returns empty handles */ );
+  Vector2 size = Stage::GetCurrent().GetSize();
+  try
+  {
+    PageTurnView portraitView = PageTurnPortraitView::New( factory, size );
+    portraitView.SetParentOrigin( ParentOrigin::CENTER );
+    Stage::GetCurrent().Add( portraitView );
+
+    tet_result(TET_FAIL);
+  }
+  catch (DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "must pass in valid texture", TEST_LOCATION );
+  }
+  catch (...)
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Popup.cpp
new file mode 100755 (executable)
index 0000000..882dfa2
--- /dev/null
@@ -0,0 +1,1469 @@
+/*
+ * Copyright (c) 2017 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 <stdlib.h>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include "dali-toolkit-test-utils/toolkit-timer.h"
+
+#include <dali.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_popup_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_popup_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+const int RENDER_FRAME_INTERVAL = 10;                          ///< Duration of each frame in ms.
+const int RENDER_ANIMATION_TEST_DURATION_MS = 2000;            ///< 2000ms to test animation.
+const int RENDER_ANIMATION_TEST_DURATION_FRAMES = RENDER_ANIMATION_TEST_DURATION_MS / RENDER_FRAME_INTERVAL; ///< equivalent frames.
+const Vector3 DEFAULT_BUTTON_SIZE(100.0f, 50.0f, 0.0f);
+
+Dali::Integration::Point GetPointDown()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointUp()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+/**
+ * Counts how many descendants root Actor has, including
+ * itself.
+ *
+ * @param[in] root The root actor to count from.
+ * @return The number of descendants including root actor itself.
+ */
+int DescendentCount( const Actor& root )
+{
+  unsigned int numChildren = root.GetChildCount();
+
+  int count = 1;
+
+  for( unsigned int i = 0; i < numChildren; ++i )
+  {
+    count += DescendentCount( root.GetChildAt( i ) );
+  }
+
+  return count;
+}
+
+bool HasAncestor( Actor child, Actor ancestor )
+{
+  while( child && child != ancestor )
+  {
+    child = child.GetParent();
+  }
+
+  return ( child == ancestor );
+}
+
+static Toolkit::Popup::DisplayState gPopupState = Toolkit::Popup::HIDDEN;
+static bool gTouchedOutside;
+
+// Signal callbacks
+
+static void OnPopupTouchedOutside()
+{
+  gTouchedOutside = true;
+}
+
+static void OnPopupShowing()
+{
+  gPopupState = Toolkit::Popup::SHOWING;
+}
+
+static void OnPopupShown()
+{
+  gPopupState = Toolkit::Popup::SHOWN;
+}
+
+static void OnPopupHiding()
+{
+  gPopupState = Toolkit::Popup::HIDING;
+}
+
+static void OnPopupHidden()
+{
+  gPopupState = Toolkit::Popup::HIDDEN;
+}
+
+void ConnectStateSignals( Toolkit::Popup popup )
+{
+  popup.ShowingSignal().Connect( &OnPopupShowing );
+  popup.ShownSignal().Connect( &OnPopupShown );
+  popup.HidingSignal().Connect( &OnPopupHiding );
+  popup.HiddenSignal().Connect( &OnPopupHidden );
+}
+
+void WaitAnimation( ToolkitTestApplication& application )
+{
+  // Wait for a while (allow animation to complete), and then check state.
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+}
+
+/**
+ * A connection tracker is required when connecting to a signal with a functor.
+ */
+class TestConnectionTrackerObject : public ConnectionTracker
+{
+};
+
+/**
+ * This functor is used to test the popup's signal connection.
+ */
+struct PopupTestFunctor
+{
+  PopupTestFunctor()
+  {
+  }
+
+  void operator()()
+  {
+  }
+};
+
+// Generate a KeyEvent to send to Core.
+Integration::KeyEvent GenerateKey( const std::string& keyName,
+                                   const std::string& logicalKey,
+                                   const std::string& keyString,
+                                   int keyCode,
+                                   int keyModifier,
+                                   unsigned long timeStamp,
+                                   const Integration::KeyEvent::State& keyState,
+                                   const std::string& compose = "",
+                                   const std::string& deviceName = "",
+                                   const Device::Class::Type& deviceClass = Device::Class::NONE,
+                                   const Device::Subclass::Type& deviceSubclass = Device::Subclass::NONE
+                                   )
+{
+  return Integration::KeyEvent( keyName,
+                                logicalKey,
+                                keyString,
+                                keyCode,
+                                keyModifier,
+                                timeStamp,
+                                keyState,
+                                compose,
+                                deviceName,
+                                deviceClass,
+                                deviceSubclass );
+}
+
+} // Anonymous namespace
+
+/*
+ * This test checks popup creation.
+ */
+int UtcDaliPopupNewP( void )
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupNewP" );
+
+  // Create the Popup actor.
+  Popup popup;
+
+  DALI_TEST_CHECK( !popup );
+
+  popup = Popup::New();
+
+  DALI_TEST_CHECK( popup );
+
+  Popup popup2( popup );
+
+  DALI_TEST_CHECK( popup2 == popup );
+
+  // Additional check to ensure object is created by checking if it's registered.
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    Popup popup = Popup::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+/*
+ * This test checks popup destruction.
+ */
+int UtcDaliPopupDestructorP( void )
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupDestructorP" );
+
+  Popup* popup = new Popup();
+  delete popup;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliPopupDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupDownCastP" );
+
+  Handle handle = Popup::New();
+
+  Popup popup = Popup::DownCast( handle );
+
+  DALI_TEST_CHECK( popup == handle );
+  END_TEST;
+}
+
+int UtcDaliPopupSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupSetProperty" );
+
+  Popup popup = Popup::New();
+
+  //Test properties
+  std::string testString = "Hello World";
+
+  TextLabel textActorIn = TextLabel::New( testString );
+  Property::Map map;
+  Scripting::CreatePropertyMap( textActorIn, map );
+  popup.SetProperty( popup.GetPropertyIndex( "title" ), map );
+  TextLabel textActorOut = TextLabel::DownCast( popup.GetTitle() );
+  std::string resultText;
+  DALI_TEST_CHECK( textActorOut.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) );
+  DALI_TEST_EQUALS( testString, resultText, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupSetTitleP(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupSetTitleP" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  // Put in show state so it's layer is connected to popup (for ancestor check).
+  popup.SetDisplayState( Popup::SHOWN );
+
+  TextLabel titleActor = TextLabel::New();
+  titleActor.SetProperty( Toolkit::TextLabel::Property::TEXT, "title" );
+
+  DALI_TEST_CHECK( !popup.GetTitle() );
+  popup.SetTitle( titleActor );
+  TextLabel textActor = TextLabel::DownCast( popup.GetTitle() );
+  DALI_TEST_CHECK( textActor == titleActor );
+
+  std::string resultText;
+  DALI_TEST_CHECK( textActor.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) );
+
+  DALI_TEST_CHECK( ( popup.GetTitle() ) && ( resultText == "title" ) );
+  // verify titleActor is actually inside popup, and not elsewhere on stage, or off even.
+  DALI_TEST_CHECK( HasAncestor( titleActor, popup ) );
+
+  TextLabel titleActor2 = TextLabel::New();
+  titleActor2.SetProperty( Toolkit::TextLabel::Property::TEXT, "anothertitle" );
+  popup.SetTitle( titleActor2 );
+  DALI_TEST_CHECK( popup.GetTitle() != titleActor );
+  DALI_TEST_CHECK( popup.GetTitle() == titleActor2 );
+  DALI_TEST_CHECK( TextLabel::DownCast( popup.GetTitle() ).GetProperty( Toolkit::TextLabel::Property::TEXT ).Get( resultText ) );
+
+  DALI_TEST_CHECK( ( popup.GetTitle() ) && ( resultText == "anothertitle" ) );
+
+  // verify titleActor is actually inside popup, and not elsewhere on stage, or off even.
+  DALI_TEST_CHECK( HasAncestor( titleActor2, popup ) );
+  END_TEST;
+}
+
+int UtcDaliPopupSetTitleN(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupSetTitleN" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  TextLabel titleActor = TextLabel::New( "text" );
+  popup.SetTitle( titleActor );
+
+  DALI_TEST_CHECK( popup.GetTitle() );
+
+  // Set a bad title value.
+  // Confirm this has disabled the title.
+  Actor badActor;
+  popup.SetTitle( badActor );
+
+  DALI_TEST_CHECK( !popup.GetTitle() );
+
+  END_TEST;
+}
+
+int UtcDaliPopupSetContentP(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupSetContentP" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  Stage::GetCurrent().Add( popup );
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f );
+
+  // Put in show state so it's layer is connected to popup (for ancestor check).
+  popup.SetDisplayState( Popup::SHOWN );
+
+  PushButton button = PushButton::New();
+  DALI_TEST_CHECK( !HasAncestor( button, popup ) );
+  popup.SetFooter( button );
+  // Hide and then re-show popup to cause button to be rearranged and added to popup.
+  popup.SetDisplayState( Popup::HIDDEN );
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_CHECK( HasAncestor( button, popup ) );
+  END_TEST;
+}
+
+int UtcDaliPopupSetContentN(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupSetContentN" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  TextLabel content = TextLabel::New( "text" );
+  popup.SetContent( content );
+
+  DALI_TEST_CHECK( popup.GetContent() );
+
+  // Set a bad title value.
+  Actor badActor;
+  popup.SetContent( badActor );
+
+  DALI_TEST_CHECK( !popup.GetContent() );
+
+  END_TEST;
+}
+
+int UtcDaliPopupSetFooterP(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupSetFooterP");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  Stage::GetCurrent().Add( popup );
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f );
+  // Put in show state so it's layer is connected to popup (for ancestor check).
+  popup.SetDisplayState( Popup::SHOWN );
+
+  PushButton button = PushButton::New();
+  DALI_TEST_CHECK( !HasAncestor(button, popup) );
+  popup.SetFooter( button );
+  // Hide and then re-show popup to cause button to be rearranged and added to popup.
+  popup.SetDisplayState( Popup::HIDDEN );
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_CHECK( HasAncestor( button, popup ) );
+  END_TEST;
+}
+
+int UtcDaliPopupSetFooterN(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupSetFooterN");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  PushButton button = PushButton::New();
+  popup.SetFooter( button );
+
+  DALI_TEST_CHECK( popup.GetFooter() );
+
+  // Set a bad title value.
+  Actor badActor;
+  popup.SetFooter( badActor );
+
+  DALI_TEST_CHECK( !popup.GetFooter() );
+
+  END_TEST;
+}
+
+int UtcDaliPopupSetControlFooterMultiple(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupSetControlFooterMultiple");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  Stage::GetCurrent().Add( popup );
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f );
+  // Put in show state so it's layer is connected to popup (for ancestor check).
+  popup.SetDisplayState( Popup::SHOWN );
+
+  Actor container = Actor::New();
+  PushButton button1 = PushButton::New();
+  PushButton button2 = PushButton::New();
+  DALI_TEST_CHECK( !HasAncestor( button1, popup ) );
+  DALI_TEST_CHECK( !HasAncestor( button2, popup ) );
+  container.Add( button1 );
+  container.Add( button2 );
+  popup.SetFooter( container );
+
+  // Hide and then re-show popup to cause button to be rearranged and added to popup.
+  popup.SetDisplayState( Popup::HIDDEN );
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_CHECK( HasAncestor( button1, popup ) );
+  DALI_TEST_CHECK( HasAncestor( button2, popup ) );
+  END_TEST;
+}
+
+int UtcDaliPopupSetStateP(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupSetStateP");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 0.0f );
+
+  DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::HIDDEN, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_EQUALS( Popup::SHOWN, popup.GetDisplayState(), TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  DALI_TEST_EQUALS( Popup::HIDDEN, popup.GetDisplayState(), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPopupSetStateN(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupSetStateN");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 1.0f );
+
+  DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::HIDDEN, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_EQUALS( Popup::SHOWING, popup.GetDisplayState(), TEST_LOCATION );
+
+  // Test cancelling a show before it has finished.
+  popup.SetDisplayState( Popup::HIDDEN );
+  DALI_TEST_EQUALS( Popup::HIDING, popup.GetDisplayState(), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPopupDisplayStateSignal(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupDisplayStateSignal" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  ConnectStateSignals( popup );
+
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, 1.0f );
+  popup.SetDisplayState( Popup::SHOWN );
+  DALI_TEST_EQUALS( Popup::SHOWING, popup.GetDisplayState(), TEST_LOCATION );
+  DALI_TEST_EQUALS( gPopupState, Popup::SHOWING, TEST_LOCATION );
+
+  // Wait for a while (allow animation to complete), and then check state.
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++)
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  DALI_TEST_EQUALS( Popup::SHOWN, popup.GetDisplayState(), TEST_LOCATION );
+  DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION );
+
+  // Hide slowly
+  popup.SetDisplayState( Popup::HIDDEN );
+  DALI_TEST_EQUALS( Popup::HIDING, popup.GetDisplayState(), TEST_LOCATION );
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDING, TEST_LOCATION );
+
+  // Wait for a while (allow animation to complete), and then check state.
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++)
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  DALI_TEST_EQUALS( Popup::HIDDEN, popup.GetDisplayState(), TEST_LOCATION );
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupShowHide(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupShowHide");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  ConnectStateSignals( popup );
+
+  Actor container = Actor::New();
+  PushButton button1 = PushButton::New();
+  PushButton button2 = PushButton::New();
+  button1.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() );
+  button2.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() );
+  container.Add( button1 );
+  container.Add( button2 );
+  popup.SetFooter( container );
+
+  // Show
+  // Note: in most popup animation implementations show would result in
+  // popup being onstage immediately following Show(). However we can't
+  // assume for all. e.g. If one creates a animation with a delay.
+  popup.SetDisplayState( Popup::SHOWN );
+
+  // Wait for a while (allow animation to complete), and then check state.
+  for(int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++)
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  // Hide
+  popup.SetDisplayState( Popup::HIDDEN );
+
+  // Wait for a while (allow animation to complete), and then check state.
+  for(int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+  }
+
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyTailVisibility(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupShowHideTail");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  Stage::GetCurrent().Add( popup );
+
+  popup.SetProperty( Popup::Property::TAIL_VISIBILITY, false );
+  popup.SetDisplayState( Popup::SHOWN );
+
+  int withoutTailCount = DescendentCount( popup );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+
+  popup.SetProperty( Popup::Property::TAIL_POSITION, "BOTTOM_CENTER" );
+  popup.SetProperty( Popup::Property::TAIL_VISIBILITY, true );
+  popup.SetDisplayState( Popup::SHOWN );
+
+  int withTailCount = DescendentCount( popup );
+
+  // There should be more actors if the Tail has been added.
+  DALI_TEST_CHECK( withTailCount > withoutTailCount );
+
+  // Hide again
+  popup.SetDisplayState( Popup::HIDDEN );
+  popup.SetProperty( Popup::Property::TAIL_VISIBILITY, false );
+  popup.SetDisplayState( Popup::SHOWN );
+  int withoutTailCount2 = DescendentCount(popup);
+
+  DALI_TEST_CHECK( withTailCount > withoutTailCount2 );
+  END_TEST;
+}
+
+int UtcDaliPopupOnTouchedOutsideSignal(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliPopupOnTouchedOutside");
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetParentOrigin( ParentOrigin::CENTER );
+  popup.SetAnchorPoint( ParentOrigin::CENTER );
+  popup.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+  popup.SetSize( 50.0f, 50.0f );
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  Stage::GetCurrent().Add( popup );
+  popup.OutsideTouchedSignal().Connect( &OnPopupTouchedOutside );
+  popup.SetDisplayState( Popup::SHOWN );
+
+  application.SendNotification();
+  application.Render();
+
+  gTouchedOutside = false;
+  Dali::Integration::TouchEvent event;
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDown() );
+  application.ProcessEvent( event );
+
+  application.SendNotification();
+  application.Render();
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUp() );
+  application.ProcessEvent( event );
+
+  application.SendNotification();
+  application.Render();
+
+  // Confirm the signal is ignored if touch_transparent.
+  gTouchedOutside = false;
+  popup.SetProperty( Popup::Property::TOUCH_TRANSPARENT, true );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDown() );
+  application.ProcessEvent( event );
+
+  application.SendNotification();
+  application.Render();
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUp() );
+  application.ProcessEvent( event );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( !gTouchedOutside );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyAutoHide(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupPropertyAutoHide" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  ConnectStateSignals( popup );
+
+  Actor container = Actor::New();
+  PushButton button1 = PushButton::New();
+  button1.SetSize( DEFAULT_BUTTON_SIZE.GetVectorXY() );
+  container.Add( button1 );
+  popup.SetFooter( container );
+
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  float getAnimationDuration = 0.0f;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::ANIMATION_DURATION ).Get( getAnimationDuration ) );
+  DALI_TEST_EQUALS( getAnimationDuration, 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  popup.SetProperty( Popup::Property::AUTO_HIDE_DELAY, 200 );
+  int getAutoHideDelay = 0;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::AUTO_HIDE_DELAY ).Get( getAutoHideDelay ) );
+  DALI_TEST_EQUALS( getAutoHideDelay, 200, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( popup );
+
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+
+  // Show
+  // Note: in most popup animation implementations show would result in
+  // popup being onstage immediately following Show(). However we can't
+  // assume for all. e.g. If one creates a animation with a delay.
+  popup.SetDisplayState( Popup::SHOWN );
+
+  DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION );
+
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  // Force the timer used by the popup to expire,
+  // this will cause the popup to hide automatically.
+  Dali::Timer timer = Timer::New( 0 );
+  timer.MockEmitSignal();
+
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/*
+ * This test checks all animation modes to confirm they all trigger all display states at the expected times.
+ */
+int UtcDaliPopupPropertyAnimationMode(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline( " UtcDaliPopupPropertyAnimationMode" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  ConnectStateSignals( popup );
+  popup.SetTitle( TextLabel::New( "Title" ) );
+  Stage::GetCurrent().Add( popup );
+
+  std::string animationModes[] = { "NONE", "ZOOM", "FADE", "CUSTOM" };
+
+  // Try both default and zero animation duration, as zero has a special case for some animation types.
+  for( int j = 0; j <= 1; j++ )
+  {
+    // On the second loop, set duration to zero.
+    if( j == 1 )
+    {
+      popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+    }
+
+    // Loop through 4 animation modes.
+    for( int i = 0; i < 4; i++ )
+    {
+      popup.SetProperty( Popup::Property::ANIMATION_MODE, animationModes[i] );
+
+      std::string checkMode;
+      DALI_TEST_CHECK( popup.GetProperty( Popup::Property::ANIMATION_MODE ).Get( checkMode ) )
+
+      DALI_TEST_EQUALS( checkMode, animationModes[i], TEST_LOCATION );
+
+      popup.SetProperty( Toolkit::Popup::Property::DISPLAY_STATE, "SHOWN" );
+      std::string resultState;
+
+      // Only wait for animation if it isn't instant.
+      if( j == 0 )
+      {
+        DALI_TEST_EQUALS( gPopupState, Popup::SHOWING, TEST_LOCATION );
+        DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::DISPLAY_STATE ).Get( resultState ) );
+        DALI_TEST_EQUALS( resultState, "SHOWING", TEST_LOCATION );
+        WaitAnimation( application );
+      }
+
+      DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION );
+      DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::DISPLAY_STATE ).Get( resultState ) );
+      DALI_TEST_EQUALS( resultState, "SHOWN", TEST_LOCATION );
+      popup.SetDisplayState( Popup::HIDDEN );
+
+      if( j == 0 )
+      {
+        DALI_TEST_EQUALS( gPopupState, Popup::HIDING, TEST_LOCATION );
+        DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::DISPLAY_STATE ).Get( resultState ) );
+        DALI_TEST_EQUALS( resultState, "HIDING", TEST_LOCATION );
+        WaitAnimation( application );
+      }
+
+      DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+      DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::DISPLAY_STATE ).Get( resultState ) );
+      DALI_TEST_EQUALS( resultState, "HIDDEN", TEST_LOCATION );
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyTitle(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyTitle" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  std::string testLabelText = "TitleTest";
+  TextLabel titleLabel = TextLabel::New();
+  titleLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, testLabelText );
+  Actor title = titleLabel;
+  Property::Map map;
+  Scripting::CreatePropertyMap( title, map );
+  popup.SetProperty( Toolkit::Popup::Property::TITLE, map );
+
+  Property::Map resultMap;
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::TITLE ).Get( resultMap ) );
+
+  Property::Value* resultProperty = resultMap.Find( "text" );
+  DALI_TEST_CHECK( resultProperty );
+
+  std::string resultText;
+  DALI_TEST_CHECK( resultProperty->Get( resultText ) );
+
+  DALI_TEST_EQUALS( resultText, testLabelText, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyContent(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyContent" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  std::string testLabelText = "ContentTest";
+  TextLabel contentLabel = TextLabel::New();
+  contentLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, testLabelText );
+  Actor content = contentLabel;
+  Property::Map map;
+  Scripting::CreatePropertyMap( content, map );
+  popup.SetProperty( Toolkit::Popup::Property::CONTENT, map );
+
+  Property::Map resultMap;
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::CONTENT ).Get( resultMap ) );
+
+  Property::Value* resultProperty = resultMap.Find( "text" );
+  DALI_TEST_CHECK( resultProperty );
+
+  std::string resultText;
+  DALI_TEST_CHECK( resultProperty->Get( resultText ) );
+
+  DALI_TEST_EQUALS( resultText, testLabelText, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyFooter(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyFooter" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  std::string testLabelText = "FooterTest";
+  TextLabel footerLabel = TextLabel::New();
+  footerLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, testLabelText );
+  Actor footer = footerLabel;
+  Property::Map map;
+  Scripting::CreatePropertyMap( footer, map );
+  popup.SetProperty( Toolkit::Popup::Property::FOOTER, map );
+
+  Property::Map resultMap;
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::FOOTER ).Get( resultMap ) );
+
+  Property::Value* resultProperty = resultMap.Find( "text" );
+  DALI_TEST_CHECK( resultProperty );
+
+  std::string resultText;
+  DALI_TEST_CHECK( resultProperty->Get( resultText ) );
+
+  DALI_TEST_EQUALS( resultText, testLabelText, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyContextualMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyContextualMode" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  std::string testLabelText = "ContentTest";
+
+  TextLabel contentLabel = TextLabel::New();
+
+  popup.SetContent( contentLabel );
+
+  // Placement actor to parent the popup from so the popup's contextual position can be relative to it.
+  Actor placement = Actor::New();
+  placement.SetParentOrigin( ParentOrigin::CENTER );
+  placement.SetAnchorPoint( AnchorPoint::CENTER );
+  placement.SetSize( 1.0f, 1.0f );
+  placement.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  Stage::GetCurrent().Add( placement );
+
+  placement.Add( popup );
+
+  // Test all contextual modes.
+  const char* mode[5] = { "NON_CONTEXTUAL", "ABOVE", "RIGHT", "BELOW", "LEFT" };
+  Vector2 offsetValues[5];
+  offsetValues[0] = Vector2( 0.375f, 0.0f );
+  offsetValues[1] = Vector2( -0.125f, -10.5f );
+  offsetValues[2] = Vector2( 10.875f, -0.5f );
+  offsetValues[3] = Vector2( -0.125f, 10.5f );
+  offsetValues[4] = Vector2( -10.875f, -0.5f );
+
+  for( int i = 0; i < 5; ++i )
+  {
+    popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, mode[i] );
+
+    std::string propertyResult;
+    DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE ).Get( propertyResult ) );
+    DALI_TEST_EQUALS( propertyResult, std::string( mode[i] ), TEST_LOCATION );
+
+    popup.SetDisplayState( Popup::SHOWN );
+    application.SendNotification();
+    application.Render();
+
+    // Check the position of the label within the popup.
+    DALI_TEST_EQUALS( contentLabel.GetCurrentWorldPosition().GetVectorXY(), offsetValues[i], TEST_LOCATION );
+
+    popup.SetDisplayState( Popup::HIDDEN );
+    application.SendNotification();
+    application.Render();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyBacking(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyBacking" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  Stage::GetCurrent().Add( popup );
+
+  Actor backing = popup.FindChildByName( "popupBacking" );
+  DALI_TEST_CHECK( backing );
+
+  DALI_TEST_EQUALS( backing.GetCurrentOpacity(), 1.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  // Check enabled property.
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( backing.GetCurrentOpacity(), 0.5f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( backing.GetCurrentOpacity(), 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  popup.SetProperty( Popup::Property::BACKING_ENABLED, false );
+  bool propertyResult;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::BACKING_ENABLED ).Get( propertyResult ) );
+  DALI_TEST_EQUALS( propertyResult, false, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( backing.GetCurrentOpacity(), 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( backing.GetCurrentOpacity(), 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  // Check color property.
+  popup.SetProperty( Popup::Property::BACKING_ENABLED, true );
+  popup.SetProperty( Popup::Property::BACKING_COLOR, Vector4( 1.0f, 0.0f, 0.0f, 1.0f ) );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+
+  Vector4 resultColor;
+  popup.GetProperty( Popup::Property::BACKING_COLOR ).Get( resultColor );
+  DALI_TEST_EQUALS( resultColor, Vector4( 1.0f, 0.0f, 0.0f, 1.0f ), Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyBackgroundImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyBackgroundImage" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  Stage::GetCurrent().Add( popup );
+
+  // Check setting an image
+  popup.SetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE, "invalid-image.png" );
+  std::string resultString;
+  popup.GetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE ).Get( resultString );
+  DALI_TEST_EQUALS( resultString, "invalid-image.png", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyCustomAnimation(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyCustomAnimation" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  TextLabel content = TextLabel::New( "text" );
+  popup.SetContent( content );
+
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 1.0f );
+  popup.SetProperty( Popup::Property::ANIMATION_MODE, "CUSTOM" );
+
+  Actor popupContainer = popup.FindChildByName( "popupContainer" );
+  DALI_TEST_CHECK( popupContainer );
+
+  Vector3 entryAnimationDestination( 300.0f, 200.0f, 0.0f );
+  Vector3 exitAnimationDestination( -300.0f, -200.0f, 0.0f );
+
+  Property::Map animationMapEntry;
+  animationMapEntry.Insert( "actor", "customAnimationPopup" );
+  animationMapEntry.Insert( "property", "position" );
+  animationMapEntry.Insert( "value", entryAnimationDestination );
+  animationMapEntry.Insert( "alphaFunction",  "EASE_OUT" );
+
+  Property::Array timePeriodMapEntry;
+  timePeriodMapEntry.PushBack( 0.0f );
+  timePeriodMapEntry.PushBack( 1.0f );
+
+  animationMapEntry.Insert( "timePeriod",  timePeriodMapEntry );
+
+  Property::Map animationMapExit;
+  animationMapExit.Insert( "actor", "customAnimationPopup" );
+  animationMapExit.Insert( "property", "position" );
+  animationMapExit.Insert( "value", exitAnimationDestination );
+  animationMapExit.Insert( "alphaFunction",  "EASE_IN" );
+
+  Property::Array timePeriodMapExit;
+  timePeriodMapExit.PushBack( 0.0f );
+  timePeriodMapExit.PushBack( 1.0f );
+
+  animationMapExit.Insert( "timePeriod",  timePeriodMapExit );
+
+  popup.SetProperty( Toolkit::Popup::Property::ENTRY_ANIMATION, animationMapEntry );
+  popup.SetProperty( Toolkit::Popup::Property::EXIT_ANIMATION, animationMapExit );
+
+  Property::Map resultMap;
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::ENTRY_ANIMATION ).Get( resultMap ) );
+  DALI_TEST_EQUALS( resultMap.Count(), 0u, TEST_LOCATION );
+  DALI_TEST_CHECK( popup.GetProperty( Toolkit::Popup::Property::EXIT_ANIMATION ).Get( resultMap ) );
+  DALI_TEST_EQUALS( resultMap.Count(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( popup );
+  popup.SetDisplayState( Popup::SHOWN );
+
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  // Test the popup has animated to it's entry-transition destination.
+  DALI_TEST_EQUALS( popupContainer.GetCurrentWorldPosition(), entryAnimationDestination, 0.1f, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+
+  for( int j = 0; j < RENDER_ANIMATION_TEST_DURATION_FRAMES; j++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  DALI_TEST_EQUALS( popupContainer.GetCurrentWorldPosition(), exitAnimationDestination, 0.1f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+static bool gPushButtonClicked;
+static bool PushButtonClicked( Button button )
+{
+  gPushButtonClicked = true;
+  return true;
+}
+
+int UtcDaliPopupPropertyTouchTransparent(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyTouchTransparent" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  TextLabel content = TextLabel::New( "text" );
+  popup.SetContent( content );
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  popup.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  popup.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  popup.SetSize( 100, 100 );
+  popup.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+
+  // Create a button (to go underneath the popup).
+  PushButton button = Toolkit::PushButton::New();
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetSize( 100, 100 );
+  button.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+
+  button.ClickedSignal().Connect( &PushButtonClicked );
+
+  Stage::GetCurrent().Add( button );
+
+  button.Add( popup );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+
+  gPushButtonClicked = false;
+  Dali::Integration::TouchEvent event;
+
+  // Perform a click, the popup should block the click from hitting the button.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDown() );
+  application.ProcessEvent( event );
+  application.SendNotification();
+  application.Render();
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUp() );
+  application.ProcessEvent( event );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( !gPushButtonClicked );
+
+  // Enable touch transparency.
+  popup.SetProperty( Popup::Property::TOUCH_TRANSPARENT, true );
+  bool propertyResult;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::TOUCH_TRANSPARENT ).Get( propertyResult ) );
+  DALI_TEST_EQUALS( propertyResult, true, TEST_LOCATION );
+
+  // Perform a click, the popup should allow the click to travel through to the button.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDown() );
+  application.ProcessEvent( event );
+  application.SendNotification();
+  application.Render();
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUp() );
+  application.ProcessEvent( event );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( gPushButtonClicked );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyTail(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyTail" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  popup.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  popup.SetSize( 100, 100 );
+  popup.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  TextLabel content = TextLabel::New( "text" );
+  popup.SetContent( content );
+
+  std::string imageFilename = "invalid-image.jpg";
+  popup.SetProperty( Popup::Property::TAIL_DOWN_IMAGE, imageFilename );
+  popup.SetProperty( Popup::Property::TAIL_UP_IMAGE, imageFilename );
+  popup.SetProperty( Popup::Property::TAIL_RIGHT_IMAGE, imageFilename );
+  popup.SetProperty( Popup::Property::TAIL_LEFT_IMAGE, imageFilename );
+
+  std::string resultString;
+  popup.GetProperty( Toolkit::Popup::Property::TAIL_DOWN_IMAGE ).Get( resultString );
+  DALI_TEST_EQUALS( resultString, imageFilename, TEST_LOCATION );
+  popup.GetProperty( Toolkit::Popup::Property::TAIL_UP_IMAGE ).Get( resultString );
+  DALI_TEST_EQUALS( resultString, imageFilename, TEST_LOCATION );
+  popup.GetProperty( Toolkit::Popup::Property::TAIL_RIGHT_IMAGE ).Get( resultString );
+  DALI_TEST_EQUALS( resultString, imageFilename, TEST_LOCATION );
+  popup.GetProperty( Toolkit::Popup::Property::TAIL_LEFT_IMAGE ).Get( resultString );
+  DALI_TEST_EQUALS( resultString, imageFilename, TEST_LOCATION );
+
+  popup.SetProperty( Popup::Property::TAIL_VISIBILITY, true );
+  bool boolResult;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::TAIL_VISIBILITY ).Get( boolResult ) );
+  DALI_TEST_EQUALS( boolResult, true, TEST_LOCATION );
+
+  Actor tailActor;
+  Vector3 tailPosition( ParentOrigin::TOP_CENTER );
+
+  popup.SetProperty( Popup::Property::TAIL_POSITION, tailPosition );
+  Vector3 vectorResult;
+  DALI_TEST_CHECK( popup.GetProperty( Popup::Property::TAIL_POSITION ).Get( vectorResult ) );
+  DALI_TEST_EQUALS( vectorResult, tailPosition, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( popup );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+  tailActor = popup.FindChildByName( "tailImage" );
+  DALI_TEST_CHECK( tailActor );
+
+  float baseValX = tailActor.GetCurrentWorldPosition().x;
+
+  DALI_TEST_GREATER( baseValX, tailActor.GetCurrentWorldPosition().y, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  tailPosition = ParentOrigin::CENTER_LEFT;
+  popup.SetProperty( Popup::Property::TAIL_POSITION, tailPosition );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+  tailActor = popup.FindChildByName( "tailImage" );
+  DALI_TEST_CHECK( tailActor );
+
+  float baseValY = tailActor.GetCurrentWorldPosition().y;
+  DALI_TEST_GREATER( baseValX, tailActor.GetCurrentWorldPosition().x, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  tailPosition = ParentOrigin::BOTTOM_CENTER;
+  popup.SetProperty( Popup::Property::TAIL_POSITION, tailPosition );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+  tailActor = popup.FindChildByName( "tailImage" );
+  DALI_TEST_CHECK( tailActor );
+  DALI_TEST_EQUALS( tailActor.GetCurrentWorldPosition().x, baseValX, TEST_LOCATION );
+  DALI_TEST_GREATER( tailActor.GetCurrentWorldPosition().y, baseValY, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  tailPosition = ParentOrigin::CENTER_RIGHT;
+  popup.SetProperty( Popup::Property::TAIL_POSITION, tailPosition );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+  tailActor = popup.FindChildByName( "tailImage" );
+  DALI_TEST_CHECK( tailActor );
+  DALI_TEST_GREATER( tailActor.GetCurrentWorldPosition().x, baseValX, TEST_LOCATION );
+  DALI_TEST_EQUALS( tailActor.GetCurrentWorldPosition().y, baseValY, TEST_LOCATION );
+
+  popup.SetDisplayState( Popup::HIDDEN );
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliPopupTypeToast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupTypeToast" );
+
+  TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "PopupToast" );
+  DALI_TEST_CHECK( typeInfo )
+
+  BaseHandle baseHandle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( baseHandle )
+
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( baseHandle );
+  gPopupState = Toolkit::Popup::HIDDEN;
+  ConnectStateSignals( popup );
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 1.0f );
+
+  popup.SetTitle( Toolkit::TextLabel::New( "This is a Toast Popup.\nIt will auto-hide itself" ) );
+  Stage::GetCurrent().Add( popup );
+  popup.SetDisplayState( Toolkit::Popup::SHOWN );
+
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  // Check the toast popup is shown.
+  DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION );
+
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  // Check the toast popup hides.
+  Dali::Timer timer = Timer::New( 0 );
+  timer.MockEmitSignal();
+
+  for( int i = 0; i < RENDER_ANIMATION_TEST_DURATION_FRAMES; i++ )
+  {
+    application.SendNotification();
+    application.Render( RENDER_FRAME_INTERVAL );
+  }
+
+  DALI_TEST_EQUALS( gPopupState, Popup::HIDDEN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupTypeRegistryCreation(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupTypeRegistryCreation" );
+
+  TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "Popup" );
+  DALI_TEST_CHECK( typeInfo )
+
+  BaseHandle baseHandle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( baseHandle )
+
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( baseHandle );
+  gPopupState = Toolkit::Popup::HIDDEN;
+  ConnectStateSignals( popup );
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+
+  Stage::GetCurrent().Add( popup );
+  popup.SetDisplayState( Toolkit::Popup::SHOWN );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check the popup is shown.
+  DALI_TEST_EQUALS( gPopupState, Popup::SHOWN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupPropertyTypeRegistryConnectSignal(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupPropertyTypeRegistryConnectSignal" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+
+  TestConnectionTrackerObject* testTracker = new TestConnectionTrackerObject();
+  // Note: The emmision of this signals has already been tested in other tests.
+  DALI_TEST_CHECK( popup.ConnectSignal( testTracker, "touchedOutside",  PopupTestFunctor() ) );
+  DALI_TEST_CHECK( popup.ConnectSignal( testTracker, "showing", PopupTestFunctor() ) );
+  DALI_TEST_CHECK( popup.ConnectSignal( testTracker, "shown", PopupTestFunctor() ) );
+  DALI_TEST_CHECK( popup.ConnectSignal( testTracker, "hiding", PopupTestFunctor() ) );
+  DALI_TEST_CHECK( popup.ConnectSignal( testTracker, "hidden", PopupTestFunctor() ) );
+
+  // Test connecting to an invalid signal does not work.
+  DALI_TEST_CHECK( !popup.ConnectSignal( testTracker, "invalid", PopupTestFunctor() ) );
+
+  END_TEST;
+}
+
+int UtcDaliPopupOnControlChildAdd(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupOnControlChildAdd" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  std::string testLabelText = "ContentTest";
+  TextLabel contentLabel = TextLabel::New( testLabelText );
+
+  popup.Add( contentLabel );
+
+  DALI_TEST_CHECK( HasAncestor( contentLabel, popup ) );
+
+  END_TEST;
+}
+
+int UtcDaliPopupOnKeyEvent(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliPopupOnKeyEvent" );
+
+  // Create the Popup actor
+  Popup popup = Popup::New();
+  popup.SetProperty( Popup::Property::ANIMATION_DURATION, 0.0f );
+  Stage::GetCurrent().Add( popup );
+
+  popup.SetDisplayState( Popup::SHOWN );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::SHOWN, TEST_LOCATION );
+
+  popup.SetKeyInputFocus();
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Down, "", "", Device::Class::TOUCH, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( popup.GetDisplayState(), Popup::HIDDEN, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPopupSetPopupBackgroundBorderProperty(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Set the background border property of a popup & retrieve it" );
+  Popup popup = Popup::New();
+
+  Rect< int > rect( 40, 30, 20, 10 );
+  tet_infoline( "Ensure value we want to set is different from what is already set" );
+  DALI_TEST_CHECK( rect != popup.GetProperty( Popup::Property::POPUP_BACKGROUND_BORDER ).Get< Rect< int > >() );
+
+  tet_infoline( "Set the property and retrieve it to make sure it's the value we set" );
+  popup.SetProperty( Popup::Property::POPUP_BACKGROUND_BORDER, rect );
+  DALI_TEST_EQUALS( rect, popup.GetProperty( Popup::Property::POPUP_BACKGROUND_BORDER ).Get< Rect< int > >(), TEST_LOCATION );
+
+  tet_infoline( "Set a vector4 as well which should also work" );
+  Vector4 vectorValue( 10.0f, 20.0f, 30.0f, 40.0f );
+  popup.SetProperty( Popup::Property::POPUP_BACKGROUND_BORDER, vectorValue );
+  DALI_TEST_EQUALS( Rect< int >( 10, 20, 30, 40 ), popup.GetProperty( Popup::Property::POPUP_BACKGROUND_BORDER ).Get< Rect< int > >(), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ProgressBar.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ProgressBar.cpp
new file mode 100644 (file)
index 0000000..a43b2c6
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2017 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>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using Dali::Toolkit::ProgressBar;
+
+
+void utc_dali_toolkit_progressbar_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_progressbar_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static const char* trackImage = TEST_RESOURCE_DIR "/progress-bar-skin-track-progress.png";
+static const char* progressImage = TEST_RESOURCE_DIR "/progress-bar-skin-progress-progress.png";
+static const char* secondaryProgressImage = TEST_RESOURCE_DIR "/progress-bar-skin-secondary-progress.png";
+static const char* indeterminateImage = TEST_RESOURCE_DIR "/progress-bar-skin-indeterminate.png";
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+}
+
+int UtcDaliProgressBarNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliProgressBarNew");
+
+  // Create the ProgressBar actor
+  ProgressBar progressBar;
+
+  DALI_TEST_CHECK( !progressBar );
+
+  progressBar = ProgressBar::New();
+
+  DALI_TEST_CHECK( progressBar );
+
+  ProgressBar progressBar2(progressBar);
+
+  DALI_TEST_CHECK( progressBar2 == progressBar );
+
+  ProgressBar progressBar3;
+  progressBar3 = progressBar2;
+
+  DALI_TEST_CHECK( progressBar3 == progressBar2 );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    ProgressBar progressBar = ProgressBar::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliProgressBarDestructor(void)
+{
+  ToolkitTestApplication application;
+
+  ProgressBar* progressBar = new ProgressBar();
+  delete progressBar;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliProgressBarDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  Handle handle = ProgressBar::New();
+
+  ProgressBar progressBar = ProgressBar::DownCast( handle );
+
+  DALI_TEST_CHECK( progressBar == handle );
+  END_TEST;
+}
+
+static bool gProgressBarValueChangedCallBackCalled = false;
+
+static void OnProgressBarValueChanged( ProgressBar progressBar, float value, float secondaryValue )
+{
+  gProgressBarValueChangedCallBackCalled = true;
+}
+
+int UtcDaliProgressBarSignals(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliProgressBarSignals");
+
+  // Create the ProgressBar actor
+  ProgressBar progressBar = ProgressBar::New();
+  Stage::GetCurrent().Add( progressBar );
+  progressBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  progressBar.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  progressBar.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  progressBar.SetPosition( 0.0f, 0.0f );
+  progressBar.ValueChangedSignal().Connect( &OnProgressBarValueChanged );
+
+  progressBar.SetProperty(ProgressBar::Property::PROGRESS_VALUE, 0.2f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gProgressBarValueChangedCallBackCalled);
+
+  //Check Secondary progress value can make signal
+  gProgressBarValueChangedCallBackCalled = false;
+  progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VALUE, 0.2f);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gProgressBarValueChangedCallBackCalled);
+  END_TEST;
+}
+
+int UtcDaliProgressBarSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliProgressBarSetPropertyP" );
+
+  ProgressBar progressBar = ProgressBar::New();
+  progressBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  progressBar.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  progressBar.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  progressBar.SetPosition( 0.0f, 0.0f );
+  progressBar.ValueChangedSignal().Connect( &OnProgressBarValueChanged );
+  Stage::GetCurrent().Add(progressBar);
+  application.SendNotification();
+  application.Render();
+
+  Property::Map map;
+  map["visualType"] = "IMAGE";
+  map[Toolkit::ImageVisual::Property::URL] = trackImage;
+  progressBar.SetProperty(ProgressBar::Property::TRACK_VISUAL, map);
+
+  Property::Value value = progressBar.GetProperty(ProgressBar::Property::TRACK_VISUAL);
+  Property::Map* resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  Property::Value* urlValue = resultMap->Find( Toolkit::ImageVisual::Property::URL );
+  std::string urlString;
+  urlValue->Get( urlString );
+  DALI_TEST_CHECK( !urlString.empty() ) ;
+  DALI_TEST_EQUALS( urlString, trackImage, TEST_LOCATION );
+
+  Property::Map colorMap;
+  colorMap["visualType"] = "COLOR";
+  colorMap[Toolkit::ColorVisual::Property::MIX_COLOR] = Color::RED;
+  progressBar.SetProperty(ProgressBar::Property::TRACK_VISUAL, colorMap);
+
+  value = progressBar.GetProperty(ProgressBar::Property::TRACK_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  Property::Value* colorValue = resultMap->Find( Toolkit::ColorVisual::Property::MIX_COLOR );
+  Vector4 color = Color::TRANSPARENT;
+  colorValue->Get( color );
+  DALI_TEST_CHECK( color != Color::TRANSPARENT );
+  DALI_TEST_EQUALS( color, Color::RED, TEST_LOCATION );
+
+  map[Toolkit::ImageVisual::Property::URL] = progressImage;
+  progressBar.SetProperty(ProgressBar::Property::PROGRESS_VISUAL, map);
+
+  value = progressBar.GetProperty(ProgressBar::Property::PROGRESS_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  urlValue = resultMap->Find( Toolkit::ImageVisual::Property::URL );
+  urlValue->Get( urlString );
+  DALI_TEST_CHECK( !urlString.empty() ) ;
+  DALI_TEST_EQUALS( urlString, progressImage, TEST_LOCATION );
+
+  progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VISUAL, secondaryProgressImage);
+
+  value = progressBar.GetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  urlValue = resultMap->Find( Toolkit::ImageVisual::Property::URL );
+  urlValue->Get( urlString );
+  DALI_TEST_CHECK( !urlString.empty() ) ;
+  DALI_TEST_EQUALS( urlString, secondaryProgressImage, TEST_LOCATION );
+
+  map[Toolkit::ImageVisual::Property::URL] = secondaryProgressImage;
+  progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VISUAL, map);
+
+  value = progressBar.GetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  urlValue = resultMap->Find( Toolkit::ImageVisual::Property::URL );
+  urlValue->Get( urlString );
+  DALI_TEST_CHECK( !urlString.empty() ) ;
+  DALI_TEST_EQUALS( urlString, secondaryProgressImage, TEST_LOCATION );
+
+  map[Toolkit::ImageVisual::Property::URL] = indeterminateImage;
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE_VISUAL, map);
+
+  value = progressBar.GetProperty(ProgressBar::Property::INDETERMINATE_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  urlValue = resultMap->Find( Toolkit::ImageVisual::Property::URL );
+  urlValue->Get( urlString );
+  DALI_TEST_CHECK( !urlString.empty() ) ;
+  DALI_TEST_EQUALS( urlString, indeterminateImage, TEST_LOCATION );
+
+  progressBar.SetProperty(ProgressBar::Property::LABEL_VISUAL, "test1");
+
+  value = progressBar.GetProperty(ProgressBar::Property::LABEL_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  Property::Value* textValue = resultMap->Find(Toolkit::TextVisual::Property::TEXT);
+
+  std::string textString;
+  textValue->Get( textString );
+  DALI_TEST_CHECK( !textString.empty() );
+  DALI_TEST_EQUALS( textString, std::string( "test1" ), TEST_LOCATION );
+
+  Property::Map textVisualMap2;
+  textVisualMap2.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
+  textVisualMap2.Insert( Toolkit::TextVisual::Property::TEXT, "test2" );
+  textVisualMap2.Insert( Toolkit::TextVisual::Property::POINT_SIZE, 12.0f );
+  progressBar.SetProperty(ProgressBar::Property::LABEL_VISUAL, textVisualMap2);
+
+  value = progressBar.GetProperty(ProgressBar::Property::LABEL_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  textValue = resultMap->Find(Toolkit::TextVisual::Property::TEXT);
+
+  textValue->Get( textString );
+  DALI_TEST_CHECK( !textString.empty() );
+  DALI_TEST_EQUALS( textString, std::string( "test2" ), TEST_LOCATION );
+
+  progressBar.SetProperty(ProgressBar::Property::LABEL_VISUAL, "test3");
+
+  value = progressBar.GetProperty(ProgressBar::Property::LABEL_VISUAL);
+  resultMap = value.GetMap();
+  DALI_TEST_CHECK( resultMap );
+  textValue = resultMap->Find(Toolkit::TextVisual::Property::TEXT);
+
+  std::string textString2;
+  textValue->Get( textString2 );
+  DALI_TEST_CHECK( !textString2.empty() );
+  DALI_TEST_EQUALS( textString2, std::string( "test3" ), TEST_LOCATION );
+
+  Property::Map transitionMap;
+  transitionMap["target"] = "indeterminateVisual";
+  transitionMap["property"] = "offset";
+  transitionMap["initialValue"] = Vector2( 0.0f, 0.0f );
+  transitionMap["targetValue"] = Vector2( 10.0f, 0.0f );
+  transitionMap["animator"] = Property::Map().Add("alphaFunction", "EASE_IN_OUT_BACK")
+                                             .Add("timePeriod", Property::Map().Add("delay", 0.5f).Add("duration", 1.0f));
+  Property::Array array;
+  array.PushBack( transitionMap );
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION, array);
+
+  Property::Map transitionMap2;
+  transitionMap2["target"] = "indeterminateVisual";
+  transitionMap2["property"] = "offset";
+  transitionMap2["initialValue"] = Vector2( 0.0f, 0.0f );
+  transitionMap2["targetValue"] = Vector2( 15.0f, 0.0f );
+  transitionMap2["animator"] = Property::Map().Add("alphaFunction", "EASE_IN_OUT_BACK")
+                                             .Add("timePeriod", Property::Map().Add("delay", 0.5f).Add("duration", 1.0f));
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION, transitionMap2);
+  END_TEST;
+}
+
+int UtcDaliProgressBarSetPropertyP1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliProgressBarSetPropertyP1" );
+
+  ProgressBar progressBar = ProgressBar::New();
+  progressBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  progressBar.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  progressBar.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  progressBar.SetPosition( 0.0f, 0.0f );
+  progressBar.ValueChangedSignal().Connect( &OnProgressBarValueChanged );
+
+  Stage::GetCurrent().Add(progressBar);
+  application.SendNotification();
+  application.Render();
+
+  float val = progressBar.GetProperty<float>(ProgressBar::Property::PROGRESS_VALUE);
+  DALI_TEST_EQUALS(val, 0.0f, TEST_LOCATION);
+
+  // test to download a file of 100k in chunks
+  float lowerBound = 0, upperBound = 100, progressValue = 0, secondaryProgressValue = 0, chunkValue = 0;
+
+  while( chunkValue <= upperBound )
+  {
+    progressValue = (chunkValue - lowerBound ) / ( upperBound - lowerBound );
+    progressBar.SetProperty(ProgressBar::Property::PROGRESS_VALUE, progressValue);
+    val = progressBar.GetProperty<float>(ProgressBar::Property::PROGRESS_VALUE);
+    DALI_TEST_EQUALS(val, progressValue, TEST_LOCATION);
+    chunkValue = chunkValue + 10;
+  }
+
+  // test to download a file of 1000k in chunks
+  lowerBound = 0, upperBound = 1000, progressValue = 0, chunkValue = 0;
+
+  while( chunkValue <= upperBound )
+  {
+    progressValue = (chunkValue - lowerBound ) / ( upperBound - lowerBound );
+    progressBar.SetProperty(ProgressBar::Property::PROGRESS_VALUE, progressValue);
+    val = progressBar.GetProperty<float>(ProgressBar::Property::PROGRESS_VALUE);
+    DALI_TEST_EQUALS(val, progressValue, TEST_LOCATION);
+    chunkValue = chunkValue + 100;
+  }
+
+  val = progressBar.GetProperty<float>(ProgressBar::Property::SECONDARY_PROGRESS_VALUE);
+  DALI_TEST_EQUALS(val, 0.0f, TEST_LOCATION);
+
+  // test to download a file of 100k in chunks
+  lowerBound = 0, upperBound = 100, secondaryProgressValue = 0, chunkValue = 0;
+
+  while( chunkValue <= upperBound )
+  {
+    secondaryProgressValue = (chunkValue - lowerBound ) / ( upperBound - lowerBound );
+    progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VALUE, secondaryProgressValue);
+    val = progressBar.GetProperty<float>(ProgressBar::Property::SECONDARY_PROGRESS_VALUE);
+    DALI_TEST_EQUALS(val, secondaryProgressValue, TEST_LOCATION);
+    chunkValue = chunkValue + 10;
+  }
+
+  // test to download a file of 1000k in chunks
+  lowerBound = 0, upperBound = 1000, secondaryProgressValue = 0, chunkValue = 0;
+
+  while( chunkValue <= upperBound )
+  {
+    secondaryProgressValue = (chunkValue - lowerBound ) / ( upperBound - lowerBound );
+    progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VALUE, secondaryProgressValue);
+    val = progressBar.GetProperty<float>(ProgressBar::Property::SECONDARY_PROGRESS_VALUE);
+    DALI_TEST_EQUALS(val, secondaryProgressValue, TEST_LOCATION);
+    chunkValue = chunkValue + 100;
+  }
+
+  END_TEST;
+}
+
+int UtcDaliProgressBarSetPropertyP2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliProgressBarSetPropertyP2" );
+
+  ProgressBar progressBar = ProgressBar::New();
+  progressBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  progressBar.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  progressBar.SetPosition( 0.0f, 0.0f );
+  progressBar.SetProperty(ProgressBar::Property::LABEL_VISUAL, "test");
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE, true);
+  progressBar.SetProperty(ProgressBar::Property::TRACK_VISUAL, trackImage);
+  progressBar.SetProperty(ProgressBar::Property::PROGRESS_VISUAL, progressImage);
+  progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VISUAL, secondaryProgressImage);
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE_VISUAL, indeterminateImage);
+
+  Property::Map transitionMap;
+  transitionMap["target"] = "indeterminateVisual";
+  transitionMap["property"] = "offset";
+  transitionMap["initialValue"] = Vector2( 0.0f, 0.0f );
+  transitionMap["targetValue"] = Vector2( 10.0f, 0.0f );
+  transitionMap["animator"] = Property::Map().Add("alphaFunction", "EASE_IN_OUT_BACK")
+                                             .Add("timePeriod", Property::Map().Add("delay", 0.5f).Add("duration", 1.0f));
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION, transitionMap);
+  progressBar.SetProperty(ProgressBar::Property::PROGRESS_VALUE, 0.2f);
+  progressBar.SetProperty(ProgressBar::Property::SECONDARY_PROGRESS_VALUE, 0.3f);
+
+  progressBar.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  progressBar.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  Stage::GetCurrent().Add(progressBar);
+  application.SendNotification();
+  application.Render();
+
+  // Test get/set INDETERMINATE
+  bool val = progressBar.GetProperty<bool>(ProgressBar::Property::INDETERMINATE);
+  DALI_TEST_EQUALS(val, true, TEST_LOCATION);
+
+  progressBar.SetProperty(ProgressBar::Property::INDETERMINATE, false);
+  val = progressBar.GetProperty<bool>(ProgressBar::Property::INDETERMINATE);
+  DALI_TEST_EQUALS(val, false, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp
new file mode 100644 (file)
index 0000000..a013d58
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
+
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_pushbutton_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_pushbutton_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static const char* TEST_IMAGE_ONE = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+static const Vector2 INSIDE_TOUCH_POINT_POSITON  = Vector2( 240, 400 );
+static const Vector3 BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS  = Vector3( 200, 360, 0 );
+static const Size BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS  = Size( 100, 100 );
+
+static bool gPushButtonSelectedState = false;
+bool PushButtonSelected( Button button )
+{
+  gPushButtonSelectedState = button.GetProperty<bool>(button.GetPropertyIndex("selected") );
+  return true;
+}
+
+static bool gPushButtonPressed = false;
+
+static bool PushButtonPressed( Button button )
+{
+  gPushButtonPressed = true;
+  return true;
+}
+
+static bool gPushButtonReleased = false;
+
+static bool PushButtonReleased( Button button )
+{
+  gPushButtonReleased = true;
+  return true;
+}
+
+static bool gPushButtonClicked = false;
+
+static bool PushButtonClicked( Button button )
+{
+  gPushButtonClicked = true;
+  return gPushButtonClicked;
+}
+
+Dali::Integration::Point GetPointDownInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+Dali::Integration::Point GetPointLeave()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::LEAVE );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+Dali::Integration::Point GetPointEnter()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::MOTION );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+Dali::Integration::Point GetPointDownOutside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpOutside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( Vector2( 10, 10 ) );
+  return point;
+}
+
+// Set up the position of the button for the default test events
+void SetupButtonForTestTouchEvents( ToolkitTestApplication& application, Button& button, bool useDefaultImages )
+{
+  button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  button.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  button.SetPosition( BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS );
+  if ( useDefaultImages )
+  {
+    const Vector2 TEST_IMAGE_SIZE = Vector2( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+    TestPlatformAbstraction& platform = application.GetPlatform();
+    platform.SetClosestImageSize( TEST_IMAGE_SIZE );
+    button.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, TEST_IMAGE_ONE );
+    button.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, TEST_IMAGE_ONE );
+  }
+}
+
+static std::string GetButtonText( Button button )
+{
+  Property::Value value = button.GetProperty( Toolkit::Button::Property::LABEL );
+
+  Property::Map *labelProperty = value.GetMap();
+
+  std::string textLabel;
+
+  if ( labelProperty )
+  {
+    Property::Value* value = labelProperty->Find( Toolkit::TextVisual::Property::TEXT );
+    value->Get( textLabel );
+  }
+
+  return textLabel;
+}
+
+} //namespace
+
+int UtcDaliPushButtonConstructorP(void)
+{
+  TestApplication application;
+
+  PushButton button;
+
+  DALI_TEST_CHECK( !button );
+  END_TEST;
+}
+
+int UtcDaliPushButtonCopyConstructorP(void)
+{
+  TestApplication application;
+
+  // Initialize an object, ref count == 1
+  PushButton button = PushButton::New();
+
+  PushButton copy( button );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliPushButtonAssignmentOperatorP(void)
+{
+  TestApplication application;
+
+  PushButton button = PushButton::New();
+
+  PushButton copy( button );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( button == copy );
+  END_TEST;
+}
+
+int UtcDaliPushButtonNewP(void)
+{
+  TestApplication application;
+
+  PushButton button = PushButton::New();
+
+  DALI_TEST_CHECK( button );
+  END_TEST;
+}
+
+int UtcDaliPushButtonDownCastP(void)
+{
+  TestApplication application;
+
+  PushButton button = PushButton::New();
+
+  BaseHandle object(button);
+
+  PushButton button2 = PushButton::DownCast( object );
+  DALI_TEST_CHECK(button2);
+
+  PushButton button3 = DownCast< PushButton >(object);
+  DALI_TEST_CHECK(button3);
+  END_TEST;
+}
+
+int UtcDaliPushButtonDownCastN(void)
+{
+  TestApplication application;
+
+  BaseHandle unInitializedObject;
+
+  PushButton button1 = PushButton::DownCast( unInitializedObject );
+  DALI_TEST_CHECK( !button1 );
+
+  PushButton button2 = DownCast< PushButton >( unInitializedObject );
+  DALI_TEST_CHECK( !button2 );
+  END_TEST;
+}
+
+int UtcDaliPushButtonAutoRepeatingProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutoRepeating");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("autoRepeating"), true );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("autoRepeating")), true, TEST_LOCATION );
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("autoRepeating"), false );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("autoRepeating")), false, TEST_LOCATION );
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("autoRepeating"), true );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("autoRepeating")), true, TEST_LOCATION );
+
+    END_TEST;
+}
+
+int UtcDaliPushButtonSetAutoRepeating(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliPushButtonSetAutoRepeating\n");
+  tet_infoline("Ensure setting AutoRepeating on a SELECTED Toggle button switches off Toggle\n");
+  PushButton pushButton = PushButton::New();
+
+  const bool INITIAL_TOGGLE_VALUE = true;
+  const bool INITIAL_SELECTED_VALUE = true;
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, INITIAL_TOGGLE_VALUE);
+  pushButton.SetProperty( Button::Property::SELECTED, INITIAL_SELECTED_VALUE );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE  ), INITIAL_TOGGLE_VALUE , TEST_LOCATION );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), INITIAL_SELECTED_VALUE , TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), !INITIAL_TOGGLE_VALUE , TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonTogglableProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetTogglableButton");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), true );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("togglable")), true, TEST_LOCATION );
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), false );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("togglable")), false, TEST_LOCATION );
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), true );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("togglable")), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonAutoRepeatingPropertyAndTogglableButton(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutoRepeatingAndTogglableButton");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("togglable")), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("autoRepeating")), false, TEST_LOCATION );
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), true );
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("autoRepeating")), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("togglable")), false, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSelectedProperty01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetSelected01");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), true );
+
+  pushButton.StateChangedSignal().Connect( &PushButtonSelected );
+
+  gPushButtonSelectedState = false;
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), true , TEST_LOCATION );
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), false , TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), true , TEST_LOCATION );
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSelectedProperty02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetSelected02");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( pushButton.GetPropertyIndex("togglable"), false );
+  pushButton.StateChangedSignal().Connect( &PushButtonSelected );
+
+  gPushButtonSelectedState = false;
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), false , TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), false , TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED  ), false , TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+  END_TEST;
+}
+
+int UtcDaliPushButtonAutorepeatingDelayPropertyValues01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutorepeatingDelayValues01");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  pushButton.SetProperty( Button::Property::INITIAL_AUTO_REPEATING_DELAY, 1.f );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<float>(pushButton.GetPropertyIndex("initialAutoRepeatingDelay") ), 1.f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonAutorepeatingDelayPropertyValues02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutorepeatingDelayValues02");
+
+  PushButton pushButton = PushButton::New();
+
+  bool assert1( false );
+  bool assert2( false );
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  try
+  {
+    pushButton.SetProperty( Button::Property::INITIAL_AUTO_REPEATING_DELAY, -1.f );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "initialAutoRepeatingDelay > 0.f", TEST_LOCATION);
+    assert1 = true;
+  }
+
+  try
+  {
+    pushButton.SetProperty( Button::Property::NEXT_AUTO_REPEATING_DELAY, -1.f );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "nextAutoRepeatingDelay > 0.f", TEST_LOCATION);
+    assert2 = true;
+  }
+
+  DALI_TEST_CHECK( assert1 && assert2 );
+  END_TEST;
+}
+
+int UtcDaliPushButtonLabelProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetLabelText");
+
+  const std::string STR( "Hola!" );
+
+  PushButton pushButton = PushButton::New();
+
+  application.SendNotification();
+  application.Render();
+
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL,
+                            Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                           .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                          );
+
+
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL, STR );
+
+  DALI_TEST_EQUALS( GetButtonText( pushButton ), STR, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonPressed(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPressed");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS );
+  pushButton.SetSize( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  application.SendNotification();
+  application.Render();
+
+  gPushButtonPressed = false;
+
+  // connect to its touch signal
+  pushButton.PressedSignal().Connect( &PushButtonPressed );
+
+  Dali::Integration::TouchEvent eventDown;
+  eventDown.AddPoint( GetPointDownInside() );
+
+  // flush the queue and render once
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( eventDown );
+
+  DALI_TEST_CHECK( gPushButtonPressed );
+  END_TEST;
+}
+
+int UtcDaliPushButtonReleased(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonReleased");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS );
+  pushButton.SetSize( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its touch signal
+  pushButton.ReleasedSignal().Connect( &PushButtonReleased );
+
+  Dali::Integration::TouchEvent event;
+
+  // Test1. Touch point down and up inside the button.
+
+  gPushButtonReleased = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gPushButtonReleased );
+
+  // Test2. Touch point down and up outside the button.
+
+  gPushButtonReleased = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonReleased );
+
+  // Test3. Touch point down inside and up outside the button.
+
+  gPushButtonReleased = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointLeave() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gPushButtonReleased );
+
+  // Test4. Touch point down outside and up inside the button.
+
+  gPushButtonReleased = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointEnter() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonReleased );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSelected(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSelected");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS );
+  pushButton.SetSize( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its touch signal
+  pushButton.StateChangedSignal().Connect( &PushButtonSelected );
+
+  Dali::Integration::TouchEvent event;
+
+  // Test1. No togglable button.
+
+  gPushButtonSelectedState = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  // Set togglable property.
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true );
+
+  // Test2. Touch point down and up inside the button twice.
+  gPushButtonSelectedState = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  // Test3. Touch point down and up outside the button.
+
+  gPushButtonSelectedState = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  // Test4. Touch point down inside and up outside the button.
+  //        State changes on Button down
+  gPushButtonSelectedState = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointLeave() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpOutside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+
+  // Test5. Touch point down outside and up inside the button.
+  // Start in unselected state
+  pushButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>(pushButton.GetPropertyIndex("selected") ),false , TEST_LOCATION );
+
+  gPushButtonSelectedState = false;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownOutside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointEnter() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+  END_TEST;
+}
+
+int UtcDaliPushButtonPropertySetIconAlignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPropertySetIconAlignment");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "TOP" );
+  DALI_TEST_EQUALS( pushButton.GetProperty<std::string>( Toolkit::PushButton::Property::ICON_ALIGNMENT ), "TOP", TEST_LOCATION );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "RIGHT" );
+  DALI_TEST_EQUALS( pushButton.GetProperty<std::string>( Toolkit::PushButton::Property::ICON_ALIGNMENT ), "RIGHT", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonPropertySetLabelPadding(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPropertySetLabelPadding");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
+  DALI_TEST_EQUALS( pushButton.GetProperty<Vector4>( Toolkit::PushButton::Property::LABEL_PADDING ), Vector4( 1.0f, 1.0f, 1.0f, 1.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
+  DALI_TEST_EQUALS( pushButton.GetProperty<Vector4>( Toolkit::PushButton::Property::LABEL_PADDING ), Vector4( 10.0f, 10.0f, 10.0f, 10.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonPropertySetIconPadding(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPropertySetIconPadding");
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
+  DALI_TEST_EQUALS( pushButton.GetProperty<Vector4>( Toolkit::PushButton::Property::ICON_PADDING ), Vector4( 1.0f, 1.0f, 1.0f, 1.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
+  DALI_TEST_EQUALS( pushButton.GetProperty<Vector4>( Toolkit::PushButton::Property::ICON_PADDING ), Vector4( 10.0f, 10.0f, 10.0f, 10.0f ), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonPaddingLayout(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonPaddingLayout");
+
+  // This test creates padding for an icon and a label.
+  // The icon and label are each enabled and disabled to confirm the correct padding is used.
+  PushButton pushButton = PushButton::New();
+
+  const Vector4 TEST_ICON_PADDING( 20.0f, 20.0f, 20.0f, 20.0f );
+  const Vector4 TEST_LABEL_PADDING( 10.0f, 10.0f, 10.0f, 10.0f );
+
+  // Get actual size of test image
+  ImageDimensions testImageSize = Dali::GetClosestImageSize( TEST_IMAGE_ONE );
+  const Vector2 TEST_IMAGE_SIZE( testImageSize.GetWidth(), testImageSize.GetHeight() );
+
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( 0.0f, 0.0f );
+  pushButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  application.SendNotification();
+  application.Render();
+
+  // First test the size is zero.
+  // No padding should be added as there is no label or icon.
+  Vector2 size( Vector2::ZERO );
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button Natural Size(%f,%f)\n", pushButton.GetNaturalSize().width, pushButton.GetNaturalSize().height );
+
+  DALI_TEST_EQUALS( size, Vector2::ZERO, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check label only padding
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL, "Label" );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 sizeWithLabelWithoutPadding( Vector2::ZERO );
+  sizeWithLabelWithoutPadding.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  sizeWithLabelWithoutPadding.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  tet_printf( "Button RelayoutSize label without padding (%f,%f)\n", sizeWithLabelWithoutPadding.width, sizeWithLabelWithoutPadding.height );
+
+  // Add label padding to label
+  pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, TEST_LABEL_PADDING );
+  application.SendNotification();
+  application.Render();
+
+  Vector2 sizeLabelAndPadding( Vector2::ZERO );
+  sizeLabelAndPadding.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  sizeLabelAndPadding.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize after label padding(%f,%f)\n", sizeLabelAndPadding.width, sizeLabelAndPadding.height );
+
+  // If control size has increased beyond size of just label then padding has been applied
+  DALI_TEST_GREATER( sizeLabelAndPadding.width, sizeWithLabelWithoutPadding.width+TEST_LABEL_PADDING.x, TEST_LOCATION );
+  DALI_TEST_GREATER( sizeLabelAndPadding.height, sizeWithLabelWithoutPadding.height+TEST_LABEL_PADDING.w, TEST_LOCATION );
+
+  // Re-initialise the button so we can setup icon-only padding.
+  pushButton.Unparent();
+  pushButton = PushButton::New();
+
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( 0.0f, 0.0f );
+  pushButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "RIGHT" );
+  pushButton.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, TEST_IMAGE_ONE );
+  pushButton.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, TEST_IMAGE_ONE );
+
+  application.SendNotification();
+  application.Render();
+
+  // Size of button with just icon
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize with icon(%f,%f)\n", size.width, size.height );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, TEST_ICON_PADDING );
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( size, TEST_IMAGE_SIZE, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize after icon padding(%f,%f)\n", size.width, size.height );
+  const Vector2 expectedIconAndPaddingSize( TEST_ICON_PADDING.x+TEST_ICON_PADDING.y+TEST_IMAGE_SIZE.width, TEST_ICON_PADDING.w + TEST_ICON_PADDING.z + TEST_IMAGE_SIZE.height );
+  DALI_TEST_EQUALS( size, expectedIconAndPaddingSize, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Now test padding for both label and icon simultaneously.
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL, "Label" );
+
+  application.SendNotification();
+  application.Render();
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize after label added(%f,%f)\n", size.width, size.height );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, TEST_LABEL_PADDING );
+
+  application.SendNotification();
+  application.Render();
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize after icon and label padding(%f,%f)\n", size.width, size.height );
+
+  DALI_TEST_EQUALS( size.width, sizeLabelAndPadding.width + expectedIconAndPaddingSize.width, TEST_LOCATION );
+  // Test height of control is same as icon and padding, as Text is smaller than icon
+  DALI_TEST_EQUALS( size.height, expectedIconAndPaddingSize.height, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonAlignmentLayout(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonAlignmentLayout");
+
+  /*
+   * This test checks different alignments for the icon against the label.
+   * The icon is then moved around the label in each of it's alignments.
+   * The final relayed out size is checked to confirm the layout has been done correctly.
+   *
+   * There is an Icon which has 0 width and height, but with 75 padding on all sides.
+   *  - Therefore total width and height are both 150.
+   *
+   * There is a Label which has "an unknown" width and height, but with 30 padding on all sides.
+   *  - Therefore total width and height are 60+x and 60+y respectively.
+   *    Where x & y are the width and height of the text.
+   *
+   * The width of the button will always expand to the largest of the icon and label sizes (plus padding).
+   * So We use the padding to help us determine the orientation is correct for each alignment.
+   *
+   * |<- 150 ->|         |<-- 60+x -->|
+   *
+   * +---------+   -
+   * |         |   ^     +------------+   -
+   * |         |   |     |            |   ^
+   * |  Icon   |  150    |   Label    |  60+y
+   * |         |   |     |            |   v
+   * |         |   v     +------------+   -
+   * +---------+   -
+   */
+
+  const Vector4 TEST_ICON_PADDING( 70.0f, 70.0f, 70.0f, 70.0f );
+  const Vector4 TEST_LABEL_PADDING( 30.0f, 30.0f, 30.0f, 30.0f );
+
+  // Get actual size of test image
+  ImageDimensions testImageSize = Dali::GetClosestImageSize( TEST_IMAGE_ONE );
+  const Vector2 TEST_IMAGE_SIZE( testImageSize.GetWidth(), testImageSize.GetHeight() );
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetPosition( 0.0f, 0.0f );
+  pushButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  // Add a label and get size of control
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL, "Label" );
+  application.SendNotification();
+  application.Render();
+
+  // First get the size of control with just label
+  Vector2 justLabelSize( Vector2::ZERO );
+  justLabelSize.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  justLabelSize.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+  tet_printf( "Button RelayoutSize with just label and no padding(%f,%f)\n", justLabelSize.width, justLabelSize.height );
+
+  pushButton.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, TEST_LABEL_PADDING );
+  application.SendNotification();
+  application.Render();
+
+  // Size of Label and Padding
+  Vector2 expectedLabelAndPaddingSize( Vector2::ZERO );
+  expectedLabelAndPaddingSize.width = justLabelSize.width + TEST_LABEL_PADDING.x + TEST_LABEL_PADDING.y;
+  expectedLabelAndPaddingSize.height = justLabelSize.height + TEST_LABEL_PADDING.w + TEST_LABEL_PADDING.z;
+
+  Vector2 labelAndPaddingSize( Vector2::ZERO );
+  labelAndPaddingSize.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  labelAndPaddingSize.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  DALI_TEST_EQUALS( labelAndPaddingSize, expectedLabelAndPaddingSize , Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  const Vector2 testImageWithPaddingSize = Vector2 ( ( TEST_IMAGE_SIZE.width + TEST_ICON_PADDING.x + TEST_ICON_PADDING.y ),
+                                                     ( TEST_IMAGE_SIZE.height + TEST_ICON_PADDING.w + TEST_ICON_PADDING.z ) );
+
+  // Add Icon and set its alignment
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "RIGHT" );
+  pushButton.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, TEST_IMAGE_ONE );
+  pushButton.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, TEST_IMAGE_ONE );
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, TEST_ICON_PADDING );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 size( Vector2::ZERO );
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  /*
+   * Test Icon right alignment.
+   * Height grows to largest of Icon or Label (+ padding).
+   * Normally this will be Icons height, except with very large font sizes.
+   *
+   *  +------------+---------+
+   *  |............+         |
+   *  |            |         |
+   *  |   Label    |  Icon   |
+   *  |            |         |
+   *  |............+         |
+   *  +------------+---------+
+   */
+  DALI_TEST_EQUALS( size.width, ( testImageWithPaddingSize.width + labelAndPaddingSize.width ) , TEST_LOCATION );
+  DALI_TEST_EQUALS( size.height, ( std::max( testImageWithPaddingSize.height, labelAndPaddingSize.height) ) , Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Now test left alignment matches right for size.
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "LEFT" );
+
+  application.SendNotification();
+  application.Render();
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  /*
+   * Test Icon left alignment.
+   * Height grows to largest of Icon or Label (+ padding).
+   * Normally this will be Icons height, except with very large font sizes.
+   *
+   *  +---------+------------+
+   *  |         +............|
+   *  |         |            |
+   *  |  Icon   |   Label    |
+   *  |         |            |
+   *  |         +............|
+   *  +---------+------------+
+   */
+  DALI_TEST_EQUALS( size.width, ( testImageWithPaddingSize.width + labelAndPaddingSize.width ) , TEST_LOCATION );
+  DALI_TEST_EQUALS( size.height, ( std::max( testImageWithPaddingSize.height, labelAndPaddingSize.height) ) , Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  tet_infoline(" Test Icon TOP alignment - Width grows to largest of Icon or label (plus padding)");
+  /*
+   *
+   *  +---------+
+   *  |         |
+   *  |         |
+   *  |  Icon   |
+   *  |         |
+   *  |         |
+   *  +---------+
+   *  |         |
+   *  |  Label  |
+   *  |         |
+   *  +---------+
+   *
+   */
+
+  tet_infoline("SetProperty on ICON_ALIGNMENT should relayout the Button");
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "TOP" );
+
+  application.SendNotification();
+  application.Render();
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  tet_printf("Natural width (%f)\n",pushButton.GetNaturalSize().width);
+  tet_printf("Natural height (%f)\n",pushButton.GetNaturalSize().height);
+
+  tet_printf(" UtcDaliPushButtonAlignmentLayout Top layout - Image and Padding size (%f,%f)\n", testImageWithPaddingSize.width, testImageWithPaddingSize.height );
+  tet_printf(" UtcDaliPushButtonAlignmentLayout Top layout - Text and Padding size (%f,%f)\n", labelAndPaddingSize.width, labelAndPaddingSize.height );
+
+  DALI_TEST_EQUALS( size.width, ( std::max( testImageWithPaddingSize.width, labelAndPaddingSize.width ) ) , TEST_LOCATION );
+
+  DALI_TEST_EQUALS( size.height,( testImageWithPaddingSize.height + labelAndPaddingSize.height ) , TEST_LOCATION );
+
+  /*
+   * Test Icon bottom alignment.
+   * Width grows to largest of Icon or Label (+ padding).
+   *
+   *  +---------+
+   *  |         |
+   *  |  Label  |
+   *  |         |
+   *  +---------+
+   *  |         |
+   *  |         |
+   *  |  Icon   |
+   *  |         |
+   *  |         |
+   *  +---------+
+   */
+  tet_infoline(" Test Icon BOTTOM alignment - Width grows to largest of Icon or label (plus padding)");
+  pushButton.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "BOTTOM" );
+
+  application.SendNotification();
+  application.Render();
+
+  size.width = pushButton.GetRelayoutSize( Dimension::WIDTH );
+  size.height = pushButton.GetRelayoutSize( Dimension::HEIGHT );
+
+  DALI_TEST_EQUALS( size.width, ( std::max(testImageWithPaddingSize.width, labelAndPaddingSize.width )) , TEST_LOCATION );
+  DALI_TEST_EQUALS( size.height,( testImageWithPaddingSize.height + labelAndPaddingSize.height ) , TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetUnSelectedVisual01P(void)
+{
+  tet_infoline(" Test adding a visual for the UNSELECTED_VISUAL property, removing Button from stage and counting renderers\n");
+  ToolkitTestApplication application;
+
+  PushButton pushButton = PushButton::New();
+  pushButton.SetSize( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+
+  Stage::GetCurrent().Add( pushButton );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR, Color::BLUE);
+
+  pushButton.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, propertyMap );
+
+  tet_infoline(" UNSELECTED_VISUAL Added to button\n");
+
+  application.SendNotification();
+  application.Render(0);
+
+  unsigned int rendererCount = pushButton.GetRendererCount();
+  tet_printf("After adding UNSELECTED_BACKGROUND_VISUAL the renderer count is(%d)\n", rendererCount );
+
+  DALI_TEST_EQUALS( pushButton.GetRendererCount(), 1 , TEST_LOCATION );
+
+  tet_printf("Remove button from stage\n" );
+
+  Stage::GetCurrent().Remove( pushButton );
+
+  rendererCount = pushButton.GetRendererCount();
+  tet_printf("After removing pushbutton from stage the renderer count is(%d)\n ", rendererCount );
+
+  DALI_TEST_EQUALS( pushButton.GetRendererCount(), 0, TEST_LOCATION );
+
+  tet_printf("After removing pushbutton from stage the renderer count is(%d)\n ", rendererCount );
+
+  Property::Map propertyMap2;
+  propertyMap2.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap2.Insert(ColorVisual::Property::MIX_COLOR, Color::RED);
+  pushButton.SetProperty( Toolkit::Button::Property::UNSELECTED_VISUAL, propertyMap2 );
+
+  tet_printf("Added UNSELECTED_VISUAL and add button back to Stage\n");
+
+  Stage::GetCurrent().Add( pushButton );
+
+  tet_printf("With UNSELECTED_BACKGROUND_VISUAL and UNSELECTED_ICON the renderer count is(%d)\n", pushButton.GetRendererCount() );
+
+  DALI_TEST_EQUALS( pushButton.GetRendererCount(), 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetSelectedVisualN(void)
+{
+  tet_infoline(" Test adding a broken visual for the UNSELECTED_VISUAL property");
+
+  ToolkitTestApplication application;
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  pushButton.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  pushButton.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+  Stage::GetCurrent().Add( pushButton );
+  application.SendNotification();
+  application.Render(0);
+
+  unsigned int preRendererCount = pushButton.GetRendererCount();
+  tet_printf("RendererCount prior to adding visual(%d)\n",preRendererCount);
+  DALI_TEST_EQUALS( preRendererCount, 0, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove( pushButton );
+  application.SendNotification();
+  application.Render(0);
+
+  Property::Map colorMap;
+  const int BROKEN_VISUAL_TYPE = 999999999;
+
+  colorMap.Insert(Visual::Property::TYPE,  BROKEN_VISUAL_TYPE);
+  colorMap.Insert(BorderVisual::Property::COLOR,  Color::BLUE);
+  colorMap.Insert(BorderVisual::Property::SIZE,  5.f);
+  pushButton.SetProperty( Toolkit::Button::Property::UNSELECTED_VISUAL, colorMap );
+
+  Stage::GetCurrent().Add( pushButton );
+  application.SendNotification();
+  application.Render(0);
+
+  unsigned int postRendererCount  = pushButton.GetRendererCount();
+  tet_printf("RendererCount post broken visual (%d)\n", postRendererCount);
+  DALI_TEST_EQUALS( postRendererCount, 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonToggleSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliButtonToggleSignalP Ensure Signals emitted");
+
+  PushButton button = PushButton::New();
+  button.SetProperty( Button::Property::TOGGLABLE, true);
+
+  SetupButtonForTestTouchEvents( application, button, true );
+
+  Stage::GetCurrent().Add( button );
+
+  application.SendNotification();
+  application.Render();
+
+  // connect to its signal
+  button.ClickedSignal().Connect( &PushButtonClicked );
+  gPushButtonClicked = false;
+
+  tet_infoline(" Touch down and up within button");
+  Dali::Integration::TouchEvent event;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_EQUALS( gPushButtonClicked, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Deprecated API Tests
+
+int UtcDaliPushButtonSetGetAutoRepeating(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutoRepeating");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::AUTO_REPEATING ), true, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::AUTO_REPEATING ), false, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::AUTO_REPEATING ), true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetTogglableButton(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetTogglableButton");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), true, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), false, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), true, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetAutoRepeatingAndTogglableButton(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutoRepeatingAndTogglableButton");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true);
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::AUTO_REPEATING ), false, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true);
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::AUTO_REPEATING ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::TOGGLABLE ), false, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetSelected01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetSelected01");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::TOGGLABLE, true);
+  pushButton.StateChangedSignal().Connect( &PushButtonSelected );
+
+  gPushButtonSelectedState = false;
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED), true, TEST_LOCATION );
+  DALI_TEST_CHECK( gPushButtonSelectedState );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetSelected02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetSelected02");
+
+  PushButton pushButton = PushButton::New();
+
+  tet_infoline(" Set Toggle feature off");
+  pushButton.SetProperty( Button::Property::TOGGLABLE, false);
+  pushButton.StateChangedSignal().Connect( &PushButtonSelected );
+
+  gPushButtonSelectedState = false;
+  tet_infoline(" Try to set to selected, expecting failure as not a toggle button");
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, false );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  pushButton.SetProperty( Button::Property::SELECTED, true );
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<bool>( Button::Property::SELECTED ), false, TEST_LOCATION );
+  DALI_TEST_CHECK( !gPushButtonSelectedState );
+
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetAutorepeatingDelayValues01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutorepeatingDelayValues01");
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  pushButton.SetProperty( Button::Property::INITIAL_AUTO_REPEATING_DELAY, 1.f);
+  DALI_TEST_EQUALS( pushButton.GetProperty<float>( Button::Property::INITIAL_AUTO_REPEATING_DELAY ), 1.f, TEST_LOCATION );
+
+  pushButton.SetProperty( Button::Property::NEXT_AUTO_REPEATING_DELAY, 1.f);
+
+  DALI_TEST_EQUALS( pushButton.GetProperty<float>( Button::Property::NEXT_AUTO_REPEATING_DELAY ), 1.f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetGetAutorepeatingDelayValues02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetGetAutorepeatingDelayValues02");
+
+  PushButton pushButton = PushButton::New();
+
+  bool assert1( false );
+  bool assert2( false );
+
+  pushButton.SetProperty( Button::Property::AUTO_REPEATING, true );
+
+  try
+  {
+    pushButton.SetProperty( Button::Property::INITIAL_AUTO_REPEATING_DELAY, -1.f );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "initialAutoRepeatingDelay > 0.f", TEST_LOCATION);
+    assert1 = true;
+  }
+
+  try
+  {
+    pushButton.SetProperty( Button::Property::NEXT_AUTO_REPEATING_DELAY, -1.f );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "nextAutoRepeatingDelay > 0.f", TEST_LOCATION);
+    assert2 = true;
+  }
+
+  DALI_TEST_CHECK( assert1 && assert2 );
+  END_TEST;
+}
+
+int UtcDaliPushButtonSetLabelText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliPushButtonSetLabelText");
+
+  const std::string STR( "Hola!" );
+
+  PushButton pushButton = PushButton::New();
+
+  pushButton.SetProperty( Toolkit::Button::Property::LABEL,
+                          Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                         .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                        );
+
+  application.SendNotification();
+  application.Render();
+
+  pushButton.SetProperty( Button::Property::LABEL, STR );
+
+  DALI_TEST_EQUALS(GetButtonText( pushButton ), STR, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp
new file mode 100644 (file)
index 0000000..ce5881c
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2017 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>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_radio_button_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_radio_button_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+static std::string GetButtonText( Button button )
+{
+  Property::Value value = button.GetProperty( Toolkit::Button::Property::LABEL );
+
+  Property::Map *labelProperty = value.GetMap();
+
+  std::string textLabel;
+
+  if ( labelProperty )
+  {
+    Property::Value* value = labelProperty->Find( Toolkit::TextVisual::Property::TEXT );
+    value->Get( textLabel );
+  }
+
+  return textLabel;
+}
+
+}
+
+int UtcDaliRadioButtonConstructorP(void)
+{
+  TestApplication application;
+
+  RadioButton button;
+
+  DALI_TEST_CHECK( !button );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonCopyConstructorP(void)
+{
+  TestApplication application;
+
+  // Initialize an object, ref count == 1
+  RadioButton button = RadioButton::New();
+
+  RadioButton copy( button );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonAssignmentOperatorP(void)
+{
+  TestApplication application;
+
+  RadioButton button = RadioButton::New();
+
+  RadioButton copy( button );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( button == copy );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliRadioButtonNewP");
+
+  // Create the Slider actor
+  RadioButton radioButton;
+
+  DALI_TEST_CHECK( !radioButton );
+
+  radioButton = RadioButton::New();
+
+  DALI_TEST_CHECK( radioButton );
+
+  RadioButton radioButton2(radioButton);
+
+  DALI_TEST_CHECK( radioButton2 == radioButton );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    RadioButton radioButton = RadioButton::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonDestructorP(void)
+{
+  ToolkitTestApplication application;
+
+  RadioButton* radioButton = new RadioButton();
+  delete radioButton;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  Handle handle = RadioButton::New();
+
+  RadioButton radioButton = RadioButton::DownCast( handle );
+
+  DALI_TEST_CHECK( radioButton == handle );
+  END_TEST;
+}
+
+int UtcDaliRadioButtonLabelProperty(void)
+{
+  ToolkitTestApplication application;
+
+  const std::string labelText = "test actor 1";
+
+  RadioButton radioButton = RadioButton::New();
+
+  radioButton.SetProperty( Toolkit::Button::Property::LABEL,
+                          Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                                         .Add( Toolkit::TextVisual::Property::POINT_SIZE, 15.0f )
+                        );
+
+  radioButton.SetProperty( Toolkit::Button::Property::LABEL, labelText );
+  DALI_TEST_EQUALS( GetButtonText( radioButton ), labelText, TEST_LOCATION );
+
+
+  std::string labelText2 = "test actor 2";
+  radioButton.SetProperty( Toolkit::Button::Property::LABEL, labelText2 );
+
+  DALI_TEST_EQUALS( GetButtonText( radioButton ), labelText2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliRadioButtonSelectedProperty(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliRadioButtonSelectedProperty");
+
+  // Create the RadioButton actor
+  RadioButton radioButton = RadioButton::New();
+  Stage::GetCurrent().Add( radioButton );
+  radioButton.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  radioButton.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  radioButton.SetPosition( 0.0f, 0.0f );
+
+  // Default selected
+  DALI_TEST_CHECK( radioButton.GetProperty<bool>( Button::Property::SELECTED ) == false );
+
+  // Setting false selected
+  radioButton.SetProperty( Button::Property::SELECTED, false );
+  DALI_TEST_CHECK( radioButton.GetProperty<bool>( Button::Property::SELECTED ) == false );
+
+  // Setting true selected
+  radioButton.SetProperty( Button::Property::SELECTED, true );
+  DALI_TEST_CHECK( radioButton.GetProperty<bool>( Button::Property::SELECTED ) == true );
+
+  // Setting false again
+  radioButton.SetProperty( Button::Property::SELECTED, false );
+  DALI_TEST_CHECK( radioButton.GetProperty<bool>( Button::Property::SELECTED ) == false );
+
+  // Test selecting radio buttons
+  RadioButton radioButton2 = RadioButton::New( "label" );
+  radioButton2.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  radioButton2.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  radioButton2.SetPosition( 0.0f, 0.0f );
+
+  RadioButton radioButton3 = RadioButton::New( "label" );
+  radioButton3.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  radioButton3.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  radioButton3.SetPosition( 0.0f, 40.0f );
+
+  Actor radioGroup = Actor::New();
+  Stage::GetCurrent().Add( radioGroup );
+  radioGroup.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  radioGroup.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  radioGroup.SetPosition( 0.0f, 0.0f );
+  radioGroup.SetSize( 400.0f, 400.0 );
+
+  radioGroup.Add( radioButton2 );
+  radioGroup.Add( radioButton3 );
+
+  application.SendNotification();
+  application.Render();
+
+  // Simulate touch events
+  DALI_TEST_CHECK( radioButton2.GetProperty<bool>( Button::Property::SELECTED ) == false );
+  DALI_TEST_CHECK( radioButton3.GetProperty<bool>( Button::Property::SELECTED ) == false );
+
+  // Select first radio
+  {
+    Dali::Integration::TouchEvent event1 = Dali::Integration::TouchEvent();
+    Dali::Integration::TouchEvent event2 = Dali::Integration::TouchEvent();
+
+    Dali::Integration::Point pointDown;
+    pointDown.SetState( PointState::DOWN );
+    pointDown.SetScreenPosition( Vector2( 1.0f, 1.0f ) );
+
+    Dali::Integration::Point pointUp( pointDown );
+    pointUp.SetState( PointState::UP );
+
+    event1.AddPoint( pointDown );
+    application.ProcessEvent( event1 );
+
+    event2.AddPoint( pointUp );
+    application.ProcessEvent( event2 );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK( radioButton2.GetProperty<bool>( Button::Property::SELECTED ) == true );
+    DALI_TEST_CHECK( radioButton3.GetProperty<bool>( Button::Property::SELECTED ) == false );
+  }
+
+  // Select an already selected radio
+  {
+    Dali::Integration::TouchEvent event1 = Dali::Integration::TouchEvent();
+    Dali::Integration::TouchEvent event2 = Dali::Integration::TouchEvent();
+
+    Dali::Integration::Point pointDown;
+    pointDown.SetState( PointState::DOWN );
+    pointDown.SetScreenPosition( Vector2( 1.0f, 1.0f ) );
+
+    Dali::Integration::Point pointUp( pointDown );
+    pointUp.SetState( PointState::UP );
+
+    event1.AddPoint( pointDown );
+    application.ProcessEvent( event1 );
+
+    event2.AddPoint( pointUp );
+    application.ProcessEvent( event2 );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK( radioButton2.GetProperty<bool>( Button::Property::SELECTED ) == true );
+    DALI_TEST_CHECK( radioButton3.GetProperty<bool>( Button::Property::SELECTED ) == false );
+  }
+
+  // Select second radio
+  {
+    Dali::Integration::TouchEvent event1 = Dali::Integration::TouchEvent();
+    Dali::Integration::TouchEvent event2 = Dali::Integration::TouchEvent();
+
+    Dali::Integration::Point pointDown;
+    pointDown.SetState( PointState::DOWN );
+    pointDown.SetScreenPosition( Vector2( 1.0f, 41.0f ) );
+
+    Dali::Integration::Point pointUp( pointDown );
+    pointUp.SetState( PointState::UP );
+
+    event1.AddPoint( pointDown );
+    application.ProcessEvent( event1 );
+
+    event2.AddPoint( pointUp );
+    application.ProcessEvent( event2 );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK( radioButton2.GetProperty<bool>( Button::Property::SELECTED ) == false );
+    DALI_TEST_CHECK( radioButton3.GetProperty<bool>( Button::Property::SELECTED ) == true );
+  }
+
+  // Select outside radio group
+  {
+    Dali::Integration::TouchEvent event1 = Dali::Integration::TouchEvent();
+    Dali::Integration::TouchEvent event2 = Dali::Integration::TouchEvent();
+
+    Dali::Integration::Point pointDown;
+    pointDown.SetState( PointState::DOWN );
+    pointDown.SetScreenPosition( Vector2( 1.0f, 500.0f ) );
+
+    Dali::Integration::Point pointUp( pointDown );
+    pointUp.SetState( PointState::UP );
+
+    event1.AddPoint( pointDown );
+    application.ProcessEvent( event1 );
+
+    event2.AddPoint( pointUp );
+    application.ProcessEvent( event2 );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_CHECK( radioButton2.GetProperty<bool>( Button::Property::SELECTED ) == false );
+    DALI_TEST_CHECK( radioButton3.GetProperty<bool>( Button::Property::SELECTED ) == true );
+  }
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp
new file mode 100644 (file)
index 0000000..7c8dad4
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2018 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-toolkit/devel-api/controls/scene3d-view/scene3d-view.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_scene_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_scene_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+/**
+ * For the AnimatedCube.gltf and its Assets
+ * Donated by Norbert Nopper for glTF testing.
+ * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnimatedCube
+ */
+const char* TEST_GLTF_FILE_NAME = TEST_RESOURCE_DIR "/AnimatedCube.gltf";
+/**
+ * For the diffuse and specular cube map texture.
+ * These textures are based off version of Wave engine sample
+ * Take from https://github.com/WaveEngine/Samples
+ *
+ * Copyright (c) 2016 Wave Coorporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+const char* TEST_DIFFUSE_TEXTURE = TEST_RESOURCE_DIR "/forest_diffuse_cubemap.png";
+const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_specular_cubemap.png";
+}
+
+int UtcDaliScene3dViewConstructorP(void)
+{
+  TestApplication application;
+
+  Scene3dView scene3dView;
+
+  DALI_TEST_CHECK( !scene3dView );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewCopyConstructorP(void)
+{
+  TestApplication application;
+
+  // Initialize an object, ref count == 1
+  Scene3dView scene3dView = Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  Scene3dView copy( scene3dView );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewCopyConstructor2P(void)
+{
+  TestApplication application;
+
+  // Initialize an object, ref count == 1
+  Toolkit::Scene3dView scene3dView = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME, TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE, Vector4::ONE );
+
+  Scene3dView copy( scene3dView );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewAssignmentOperatorP(void)
+{
+  TestApplication application;
+
+  Scene3dView scene3dView = Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  Scene3dView copy( scene3dView );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( scene3dView == copy );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewNewP");
+
+  // Create the Slider actor
+  Scene3dView scene3dView;
+  DALI_TEST_CHECK( !scene3dView );
+
+  scene3dView = Scene3dView::New( TEST_GLTF_FILE_NAME );
+  DALI_TEST_CHECK( scene3dView );
+
+  END_TEST;
+}
+
+int UtcDaliScene3dViewDestructorP(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3dView* scene3dView = new Scene3dView();
+  delete scene3dView;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewDownCast");
+
+  Toolkit::Scene3dView view = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME );
+  BaseHandle handle(view);
+
+  Toolkit::Scene3dView scene3dView = Toolkit::Scene3dView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( scene3dView );
+  DALI_TEST_CHECK( scene3dView == view );
+  END_TEST;
+}
+
+int UtcDaliScene3dViewSetLight(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewSetLight");
+
+  Toolkit::Scene3dView view = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  bool lightSet = view.SetLight( Scene3dView::LightType::DIRECTIONAL_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) );
+  DALI_TEST_CHECK( lightSet );
+  bool lightSet2 = view.SetLight( Scene3dView::LightType::POINT_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) );
+  DALI_TEST_CHECK( lightSet2 );
+
+  END_TEST;
+}
+
+int UtcDaliScene3dViewGetCamera(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewGetCamera");
+
+  Toolkit::Scene3dView view = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  CameraActor camera = view.GetDefaultCamera();
+  DALI_TEST_CHECK( camera );
+
+  CameraActor camera2 = view.GetCamera( -1 );
+  DALI_TEST_CHECK( !camera2 );
+
+  CameraActor camera3 = view.GetCamera( 0 );
+  DALI_TEST_CHECK( camera3 );
+
+  CameraActor camera4 = view.GetCamera( view.GetCameraCount() - 1 );
+  DALI_TEST_CHECK( camera4 );
+
+  END_TEST;
+}
+
+int UtcDaliScene3dViewAnimations(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewAnimations");
+
+  Toolkit::Scene3dView view = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  bool playAnimation = view.PlayAnimations();
+  DALI_TEST_CHECK( playAnimation );
+
+  END_TEST;
+}
+
+int UtcDaliScene3dViewAnimations2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScene3dViewAnimations2");
+
+  Toolkit::Scene3dView view = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME );
+
+  bool animated = true;
+  unsigned int animationCount = view.GetAnimationCount();
+  for( unsigned int i = 0; i < animationCount; ++i )
+  {
+    animated = ( animated && view.PlayAnimation( i ) );
+  }
+  DALI_TEST_CHECK( animated );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ScrollBar.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ScrollBar.cpp
new file mode 100644 (file)
index 0000000..ff46053
--- /dev/null
@@ -0,0 +1,1993 @@
+/*
+ * Copyright (c) 2019 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 <string>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_scrollbar_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_scrollbar_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const int RENDER_FRAME_INTERVAL = 16;                       ///< Duration of each frame in ms. (at approx 60FPS)
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+// Callback probes.
+
+static bool gOnPanFinishedCalled;                         ///< Whether the PanFinished signal was invoked.
+static bool gOnScrollPositionIntervalReachedSignalCalled;        ///< Whether the ScrollPositionIntervalReached signal was invoked.
+
+/**
+ * Invoked when pan gesture is finished on the scroll indicator.
+ */
+static void OnPanFinished()
+{
+  gOnPanFinishedCalled = true;
+}
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+/**
+ * Invoked when the current scroll position of the scrollable content goes above or below the values
+ * specified by SCROLL_POSITION_INTERVALS property.
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollPositionIntervalReached( float position )
+{
+  gOnScrollPositionIntervalReachedSignalCalled = true;
+}
+
+static Vector2 PerformGestureSwipe(ToolkitTestApplication& application, Vector2 start, Vector2 direction, int frames, uint32_t start_time)
+{
+  gOnPanFinishedCalled = false;
+
+  // Now do a pan starting from (start) and heading (direction)
+  Vector2 pos( start + ( direction * 15 ) );
+  uint32_t time = start_time;
+
+  TestStartPan( application, start, pos, time );
+
+  Wait(application);
+
+  for(int i = 0; i < frames; i++)
+  {
+    pos += direction; // Move in this direction
+    time += RENDER_FRAME_INTERVAL;
+    TestMovePan( application, pos, time);
+    Wait(application);
+  }
+
+  pos += direction; // Move in this direction.
+  time += RENDER_FRAME_INTERVAL;
+  TestEndPan(application, pos, time );
+  Wait(application);
+
+  return pos;
+}
+
+} // namespace
+
+int UtcDaliToolkitScrollBarConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar scrollBar;
+  DALI_TEST_CHECK( !scrollBar );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar scrollBar = ScrollBar::New();
+  scrollBar.SetProperty( ScrollBar::Property::INDICATOR_FIXED_HEIGHT, 38.2f );
+
+  ScrollBar copy( scrollBar );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<float>( ScrollBar::Property::INDICATOR_FIXED_HEIGHT ) == scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_FIXED_HEIGHT ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar scrollBar = ScrollBar::New();
+  scrollBar.SetProperty( ScrollBar::Property::INDICATOR_FIXED_HEIGHT, 38.2f );
+
+  ScrollBar copy = scrollBar;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<float>( ScrollBar::Property::INDICATOR_FIXED_HEIGHT ) == scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_FIXED_HEIGHT ) );
+  END_TEST;
+}
+
+int UtcDaliScrollBarDestructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar* scrollBar = new ScrollBar();
+  delete scrollBar;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarNewP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+  END_TEST;
+
+  ScrollBar vertical = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( vertical );
+  DALI_TEST_CHECK( vertical.GetScrollDirection() == ScrollBar::Vertical );
+
+  Property::Value value = vertical.GetProperty(ScrollBar::Property::SCROLL_DIRECTION);
+  std::string scrollDirection = value.Get<std::string>();
+  DALI_TEST_EQUALS( scrollDirection, "Vertical", TEST_LOCATION );
+
+  ScrollBar horizontal = ScrollBar::New(ScrollBar::Horizontal);
+  DALI_TEST_CHECK( horizontal );
+  DALI_TEST_CHECK( horizontal.GetScrollDirection() == ScrollBar::Horizontal );
+  value = vertical.GetProperty(ScrollBar::Property::SCROLL_DIRECTION);
+  scrollDirection = value.Get<std::string>();
+  DALI_TEST_EQUALS( scrollDirection, "Horizontal", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarCreateP(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "ScrollBar" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  ScrollBar scrollBar = ScrollBar::DownCast( handle );
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetProperty(ScrollBar::Property::SCROLL_DIRECTION, "Vertical");
+  scrollBar.SetProperty(ScrollBar::Property::INDICATOR_HEIGHT_POLICY, "Fixed");
+
+  DALI_TEST_EQUALS( scrollBar.GetScrollDirection(), Toolkit::ScrollBar::Vertical, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHeightPolicy(), Toolkit::ScrollBar::Fixed, TEST_LOCATION );
+
+  scrollBar.SetProperty(ScrollBar::Property::SCROLL_DIRECTION, "Horizontal");
+  scrollBar.SetProperty(ScrollBar::Property::INDICATOR_HEIGHT_POLICY, "Variable");
+
+  DALI_TEST_EQUALS( scrollBar.GetScrollDirection(), Toolkit::ScrollBar::Horizontal, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHeightPolicy(), Toolkit::ScrollBar::Variable, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarDownCastP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollBar scrollBar1 = ScrollBar::New();
+  BaseHandle object( scrollBar1 );
+
+  ScrollBar scrollBar2 = ScrollBar::DownCast( object );
+  DALI_TEST_CHECK( scrollBar2 );
+
+  ScrollBar scrollBar3 = DownCast< ScrollBar >( object );
+  DALI_TEST_CHECK( scrollBar3 );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarDownCastN(void)
+{
+  ToolkitTestApplication application;
+
+  BaseHandle uninitializedObject;
+  ScrollBar scrollBar1 = ScrollBar::DownCast( uninitializedObject );
+  DALI_TEST_CHECK( !scrollBar1 );
+
+  ScrollBar scrollBar2 = DownCast< ScrollBar >( uninitializedObject );
+  DALI_TEST_CHECK( !scrollBar2 );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetScrollPropertySourceP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+  DALI_TEST_CHECK( scrollBar.GetScrollDirection() == ScrollBar::Vertical );
+
+  float scrollBarHeight = 100.0f;
+  scrollBar.SetSize(20.0f, scrollBarHeight, 0.0f);
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   100.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   500.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Check that the indicator size should be: scroll bar size * (scroll bar size / content size).
+  // i.e. The bigger the content size, the smaller the indicator size
+  float indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, scrollBarHeight * scrollBarHeight / 500.0f, TEST_LOCATION );
+
+  // Decrease the content length
+  sourceActor.SetProperty( propertyScrollContentSize, 250.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size is changed accordingly
+  indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, scrollBarHeight * scrollBarHeight / 250.0f, TEST_LOCATION );
+
+  // As scroll position is 0, check that the indicator position should be 0.0f.
+  float indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, 0.0f, TEST_LOCATION );
+
+  // Set the scroll position to the middle
+  sourceActor.SetProperty( propertyScrollPosition, -50.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator should be in the middle of the scroll bar
+  indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, (scrollBarHeight - indicatorHeight) * 0.5f, TEST_LOCATION );
+
+  // Set the scroll position to the maximum
+  sourceActor.SetProperty( propertyScrollPosition, -100.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator should be in the end of the scroll bar
+  indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, scrollBarHeight - indicatorHeight, TEST_LOCATION );
+
+  // Increase the maximum scroll position to double
+  sourceActor.SetProperty( propertyMaxScrollPosition, 200.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator should be now in the middle of the scroll bar
+  indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, (scrollBarHeight - indicatorHeight) * 0.5f, TEST_LOCATION );
+
+  // Create another source actor
+  Actor newSourceActor = Actor::New();
+  Stage::GetCurrent().Add( newSourceActor );
+
+  // Register the scroll properties
+  Property::Index newPropertyScrollPosition = newSourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index newPropertyMinScrollPosition = newSourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index newPropertyMaxScrollPosition = newSourceActor.RegisterProperty( "sourcePositionMax",   200.0f );
+  Property::Index newPropertyScrollContentSize = newSourceActor.RegisterProperty( "sourceContentSize",   400.0f );
+
+  DALI_TEST_EQUALS( newSourceActor.GetPropertyIndex( "sourcePosition" ), newPropertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( newSourceActor.GetPropertyIndex( "sourcePositionMin" ), newPropertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( newSourceActor.GetPropertyIndex( "sourcePositionMax" ), newPropertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( newSourceActor.GetPropertyIndex( "sourceContentSize" ), newPropertyScrollContentSize, TEST_LOCATION );
+
+  // Change the source of the scroll position properties to be the new source actor.
+  scrollBar.SetScrollPropertySource(newSourceActor, newPropertyScrollPosition, newPropertyMinScrollPosition, newPropertyMaxScrollPosition, newPropertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size is changed accordingly
+  indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, scrollBarHeight * scrollBarHeight / 400.0f, TEST_LOCATION );
+
+  // Check that the indicator position goes back to the beginning of the scroll bar
+  indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, 0.0f, TEST_LOCATION );
+
+  // Set the scroll position to one fifth of the maximum
+  newSourceActor.SetProperty( propertyScrollPosition, -40.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator should be in one fifth from the beginning of the scroll bar
+  indicatorPosition = indicator.GetCurrentPosition().y;
+  DALI_TEST_EQUALS( indicatorPosition, (scrollBarHeight - indicatorHeight) * 0.2f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetScrollPropertySourceN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set empty handle of source object and invalid source property index.
+  Actor sourceActor;
+  scrollBar.SetScrollPropertySource(sourceActor, Property::INVALID_INDEX, Property::INVALID_INDEX, Property::INVALID_INDEX, Property::INVALID_INDEX);
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetScrollIndicatorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Set a new indicator
+  Actor newIndicator = Actor::New();
+  scrollBar.SetScrollIndicator(newIndicator);
+
+  // Check that the new indicator is successfully set
+  DALI_TEST_CHECK( indicator != scrollBar.GetScrollIndicator() );
+  DALI_TEST_CHECK( newIndicator == scrollBar.GetScrollIndicator() );
+
+  // Check that the new control indicator is successfully set
+  Control controlIndicator = Control::New();
+  scrollBar.SetScrollIndicator(controlIndicator);
+
+  DALI_TEST_CHECK( controlIndicator == Control::DownCast( scrollBar.GetScrollIndicator() ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetScrollIndicatorN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Try to set an uninitialized actor as the indicator
+  Actor uninitializedIndicator;
+  scrollBar.SetScrollIndicator(uninitializedIndicator);
+
+  // Check that the uninitialized actor can not be set as the indicator
+  DALI_TEST_CHECK( indicator == scrollBar.GetScrollIndicator() );
+  DALI_TEST_CHECK( uninitializedIndicator != scrollBar.GetScrollIndicator() );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetScrollIndicatorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Set a new indicator
+  Actor newIndicator = Actor::New();
+  scrollBar.SetScrollIndicator(newIndicator);
+
+  // Check that the new indicator is successfully set
+  DALI_TEST_CHECK( scrollBar.GetScrollIndicator() );
+  DALI_TEST_CHECK( indicator != scrollBar.GetScrollIndicator() );
+  DALI_TEST_CHECK( newIndicator == scrollBar.GetScrollIndicator() );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetScrollIndicatorN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Try to set an uninitialized actor as the indicator
+  Actor uninitializedIndicator;
+  scrollBar.SetScrollIndicator(uninitializedIndicator);
+
+  // Check that the indicator has not been changed
+  DALI_TEST_CHECK( indicator == scrollBar.GetScrollIndicator() );
+  DALI_TEST_CHECK( uninitializedIndicator != scrollBar.GetScrollIndicator() );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetScrollPositionIntervalsP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollBar.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollBar.SetSize(20.0f, 800.0f, 0.0f);
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Connect to the ScrollPositionIntervalReached signal
+  scrollBar.ScrollPositionIntervalReachedSignal().Connect( &OnScrollPositionIntervalReached );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   800.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   2000.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set the values to get notified when the scroll positions of the source actor goes above or below these values
+  Dali::Vector<float> positionIntervals;
+  for( size_t i = 0; i != 10; ++i )
+  {
+    positionIntervals.PushBack( -80.0f * i ); // should get notified for each 80 pixels
+  }
+  scrollBar.SetScrollPositionIntervals(positionIntervals);
+
+  // Get the list of scroll position intervals for notification
+  Dali::Vector<float> results = scrollBar.GetScrollPositionIntervals();
+
+  // Check that the result is the same as the list previously set.
+  DALI_TEST_EQUALS( positionIntervals.Count(), results.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[0], results[0], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[1], results[1], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[2], results[2], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[3], results[3], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[4], results[4], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[5], results[5], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[6], results[6], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[7], results[7], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[8], results[8], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[9], results[9], TEST_LOCATION );
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+
+  // Animate the scroll position to cross the specified value
+  Animation animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -85.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+
+  // Rest and clear the animation
+  animation.Clear();
+  animation.Reset();
+
+  // Animate the scroll position to cross another specified value
+  animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -170.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+
+  // Rest and clear the animation
+  animation.Clear();
+  animation.Reset();
+
+  // Animate the scroll position back to the previous value
+  animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -85.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetScrollPositionIntervalsP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set the values to get notified when the scroll positions of the source actor goes above or below these values
+  Dali::Vector<float> positionIntervals;
+  for( size_t i = 0; i != 10; ++i )
+  {
+    positionIntervals.PushBack( -80.0f * i ); // should get notified for each 80 pixels
+  }
+  scrollBar.SetScrollPositionIntervals(positionIntervals);
+
+  // Get the list of scroll position intervals for notification
+  Dali::Vector<float> results = scrollBar.GetScrollPositionIntervals();
+
+  // Check that the result is the same as the list previously set.
+  DALI_TEST_EQUALS( positionIntervals.Count(), results.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[0], results[0], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[1], results[1], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[2], results[2], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[3], results[3], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[4], results[4], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[5], results[5], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[6], results[6], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[7], results[7], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[8], results[8], TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[9], results[9], TEST_LOCATION );
+
+  Property::Array resultArray = scrollBar.GetProperty<Property::Array>(Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS);
+
+  DALI_TEST_EQUALS( positionIntervals.Count(), resultArray.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[0], resultArray[0].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[1], resultArray[1].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[2], resultArray[2].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[3], resultArray[3].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[4], resultArray[4].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[5], resultArray[5].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[6], resultArray[6].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[7], resultArray[7].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[8], resultArray[8].Get<float>(), TEST_LOCATION );
+  DALI_TEST_EQUALS( positionIntervals[9], resultArray[9].Get<float>(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetScrollDirectionP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+  DALI_TEST_CHECK( scrollBar.GetScrollDirection() == ScrollBar::Vertical );
+
+  // Change the direction of scroll bar to horizontal
+  scrollBar.SetScrollDirection(ScrollBar::Horizontal);
+  DALI_TEST_CHECK( scrollBar.GetScrollDirection() == ScrollBar::Horizontal );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorHeightPolicyP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  float scrollBarHeight = 100.0f;
+  scrollBar.SetSize(20.0f, scrollBarHeight, 0.0f);
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   100.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   500.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Check that the indicator size should be: scroll bar size * (scroll bar size / content size).
+  // i.e. The bigger the content size, the smaller the indicator size
+  float indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, scrollBarHeight * scrollBarHeight / 500.0f, TEST_LOCATION );
+
+  // Set the indicator height to be fixed to 50.0f
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  scrollBar.SetIndicatorFixedHeight(50.0f);
+
+  Property::Value value = scrollBar.GetProperty(ScrollBar::Property::INDICATOR_HEIGHT_POLICY);
+  DALI_TEST_EQUALS(value.Get<std::string>(), "Fixed", TEST_LOCATION );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size should be 50.0f
+  indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, 50.0f, TEST_LOCATION );
+
+  // Set the indicator height to be variable
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Variable);
+  value = scrollBar.GetProperty(ScrollBar::Property::INDICATOR_HEIGHT_POLICY);
+  DALI_TEST_EQUALS(value.Get<std::string>(), "Variable", TEST_LOCATION );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size should be: scroll bar size * (scroll bar size / content size).
+  indicatorHeight = indicator.GetCurrentSize().y;
+  DALI_TEST_EQUALS( indicatorHeight, scrollBarHeight * scrollBarHeight / 500.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetIndicatorHeightPolicyP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set the indicator height to be fixed
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHeightPolicy(), Toolkit::ScrollBar::Fixed, TEST_LOCATION );
+
+  // Set the indicator height to be variable
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Variable);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHeightPolicy(), Toolkit::ScrollBar::Variable, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorFixedHeightP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  float scrollBarHeight = 100.0f;
+  scrollBar.SetSize(20.0f, scrollBarHeight, 0.0f);
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Set the indicator height to be fixed to 50.0f
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  scrollBar.SetIndicatorFixedHeight(50.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size should be 50.0f
+  DALI_TEST_EQUALS( indicator.GetCurrentSize().y, 50.0f, TEST_LOCATION );
+
+  // Set the indicator height to be fixed to 25.0f
+  scrollBar.SetIndicatorFixedHeight(25.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator size should be 25.0f
+  DALI_TEST_EQUALS( indicator.GetCurrentSize().y, 25.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetIndicatorFixedHeightP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set the fixed indicator height to be 50.0f
+  scrollBar.SetIndicatorFixedHeight(50.0f);
+
+  // Check that the indicator size should be 50.0f
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorFixedHeight(), 50.0f, TEST_LOCATION );
+
+  // Set the indicator height to be fixed to 25.0f
+  scrollBar.SetIndicatorFixedHeight(25.0f);
+
+  // Check that the indicator size should be 50.0f
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorFixedHeight(), 25.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorShowDurationP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Set the duration to show the indicator to be 0.35 second
+  scrollBar.SetIndicatorShowDuration(0.35);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorShowDuration(), 0.35f, TEST_LOCATION );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Wait for 0.35 second
+  Wait(application, 350);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Set the duration to show the indicator to be 0.75 second
+  scrollBar.SetIndicatorShowDuration(0.75);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorShowDuration(), 0.75f, TEST_LOCATION );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Wait for 0.35 second first
+  Wait(application, 350);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is not fully visible yet
+  DALI_TEST_CHECK( indicator.GetCurrentOpacity() != 1.0f );
+
+  // Wait for another 0.4 second
+  Wait(application, 400);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now fully visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorShowDurationN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to show the indicator
+  float duration = scrollBar.GetIndicatorShowDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Now set the duration to show the indicator to be a negative value (which should be ignored and therefore means instant)
+  scrollBar.SetIndicatorShowDuration(-0.25f);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorShowDuration(), -0.25f, TEST_LOCATION );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator becomes instantly visible in the next frame
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetIndicatorShowDurationP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set the duration to show the indicator to be 0.35 second
+  scrollBar.SetIndicatorShowDuration(0.35f);
+
+  // Check that the duration to show the indicator is 0.35 second
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorShowDuration(), 0.35f, TEST_LOCATION );
+
+  // Set the duration to show the indicator to be 0.75 second
+  scrollBar.SetIndicatorShowDuration(0.75f);
+
+  // Check that the duration to show the indicator is 0.75 second
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorShowDuration(), 0.75f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorHideDurationP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Set the duration to hide the indicator to be 0.15 second
+  scrollBar.SetIndicatorHideDuration(0.15f);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHideDuration(), 0.15f, TEST_LOCATION );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Wait for 0.15 second
+  Wait(application, 150);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Set the duration to hide the indicator to be 0.65 second
+  scrollBar.SetIndicatorHideDuration(0.65f);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHideDuration(), 0.65f, TEST_LOCATION );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Wait for 0.15 second first
+  Wait(application, 150);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is not fully invisible yet
+  DALI_TEST_CHECK( indicator.GetCurrentOpacity() != 0.0f );
+
+  // Wait for another 0.5 second
+  Wait(application, 500);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now fully invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarSetIndicatorHideDurationN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetIndicatorHideDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Now set the duration to hide the indicator to be a negative value (which should be ignored and therefore means instant)
+  scrollBar.SetIndicatorHideDuration(-0.25f);
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHideDuration(), -0.25f, TEST_LOCATION );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator becomes instantly invisible in the next frame
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarGetIndicatorHideDurationP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  // Set the duration to hide the indicator to be 0.15 second
+  scrollBar.SetIndicatorHideDuration(0.15f);
+
+  // Check that the duration to hide the indicator is 0.15 second
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHideDuration(), 0.15f, TEST_LOCATION );
+
+  // Set the duration to hide the indicator to be 0.65 second
+  scrollBar.SetIndicatorHideDuration(0.65f);
+
+  // Check that the duration to hide the indicator is 0.65 second
+  DALI_TEST_EQUALS( scrollBar.GetIndicatorHideDuration(), 0.65f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarShowIndicatorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to show the indicator
+  float duration = scrollBar.GetIndicatorShowDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarShowIndicatorN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Make the indicator initially visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is initially visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Get the default duration to show the indicator
+  float duration = scrollBar.GetIndicatorShowDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Show the indicator
+  scrollBar.ShowIndicator();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is still visible in the very next frame
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarHideIndicatorP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetIndicatorHideDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarHideIndicatorN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Make the indicator initially invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is initially invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetIndicatorHideDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is still invisible in the very next frame
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarActionShowIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_SHOW_DURATION );
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Do the "ShowIndicator" action
+  Property::Map emptyMap;
+  scrollBar.DoAction( "ShowIndicator", emptyMap );
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarActionHideIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_HIDE_DURATION );
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Do the "HideIndicator" action
+  Property::Map emptyMap;
+  scrollBar.DoAction( "HideIndicator", emptyMap );
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarActionShowTransientIndicator(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_SHOW_DURATION );
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  // Do the "ShowIndicator" action
+  Property::Map emptyMap;
+  scrollBar.DoAction( "ShowTransientIndicator", emptyMap );
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Get the default duration to hide the indicator
+  float hideDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_HIDE_DURATION );
+  float transientDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_TRANSIENT_DURATION );
+  float totalVisibleDuration = hideDuration + transientDuration;
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( totalVisibleDuration > 0.0f );
+
+  // Wait for the specified duration
+  Wait(application, totalVisibleDuration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarActionShowTransientIndicatorImmediate(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Make the indicator invisible
+  indicator.SetOpacity(0.0f);
+
+  // Don't use a show animation; the indicator should appear immediately
+  scrollBar.SetProperty( ScrollBar::Property::INDICATOR_SHOW_DURATION, 0.0f );
+  float duration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_SHOW_DURATION );
+  DALI_TEST_EQUALS( duration, 0.0f, TEST_LOCATION );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Do the "ShowIndicator" action
+  Property::Map emptyMap;
+  scrollBar.DoAction( "ShowTransientIndicator", emptyMap );
+
+  // Wait for the specified duration
+  Wait(application);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Get the default duration to hide the indicator
+  float hideDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_HIDE_DURATION );
+  float transientDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_TRANSIENT_DURATION );
+  float totalVisibleDuration = hideDuration + transientDuration;
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( totalVisibleDuration > 0.0f );
+
+  // Wait for the specified duration
+  Wait(application, totalVisibleDuration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarActionShowTransientIndicatorDuringHide(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a scroll bar
+  ScrollBar scrollBar = ScrollBar::New();
+  DALI_TEST_CHECK( scrollBar );
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  Actor indicator = scrollBar.GetScrollIndicator();
+  DALI_TEST_CHECK( indicator );
+
+  // Get the default duration to hide the indicator
+  float duration = scrollBar.GetIndicatorHideDuration();
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Make the indicator visible
+  indicator.SetOpacity(1.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Hide the indicator
+  scrollBar.HideIndicator();
+
+  // Wait for half the specified duration
+  Wait(application, duration * 0.5f * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now partially hidden
+  DALI_TEST_CHECK( indicator.GetCurrentOpacity() < 1.0f );
+
+  // Now interrupt the Hide with a DoAction( "ShowTransientIndicator" )
+
+  // Get the default duration to hide the indicator
+  duration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_SHOW_DURATION );
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( duration > 0.0f );
+
+  // Do the "ShowIndicator" action
+  Property::Map emptyMap;
+  scrollBar.DoAction( "ShowTransientIndicator", emptyMap );
+
+  // Wait for the specified duration
+  Wait(application, duration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now visible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 1.0f, TEST_LOCATION );
+
+  // Get the default duration to hide the indicator
+  float hideDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_HIDE_DURATION );
+  float transientDuration = scrollBar.GetProperty<float>( ScrollBar::Property::INDICATOR_TRANSIENT_DURATION );
+  float totalVisibleDuration = hideDuration + transientDuration;
+
+  // Check that the default duration is greater than 0
+  DALI_TEST_CHECK( totalVisibleDuration > 0.0f );
+
+  // Wait for the specified duration
+  Wait(application, totalVisibleDuration * 1000);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check that the indicator is now invisible
+  DALI_TEST_EQUALS( indicator.GetCurrentOpacity(), 0.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarPanFinishedSignalP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollBar.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollBar.SetSize(20.0f, 800.0f, 0.0f);
+
+  // Set the indicator height to be fixed to 50.0f
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  scrollBar.SetIndicatorFixedHeight(50.0f);
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Connect the pan finished signal
+  ConnectionTracker connectionTracker;
+  bool panFinished = false;
+  scrollBar.PanFinishedSignal().Connect( &OnPanFinished );
+  scrollBar.ConnectSignal( &connectionTracker, "panFinished", CallbackFunctor(&panFinished));
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   100.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   500.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Perform a swipe gesture on the indicator
+  PerformGestureSwipe(application, Vector2(1.0f, 1.0f), Vector2(Vector2::YAXIS * 1.0f), 1, 500);
+  DALI_TEST_EQUALS( gOnPanFinishedCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( panFinished, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarPanFinishedSignalN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollBar.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollBar.SetSize(20.0f, 800.0f, 0.0f);
+
+  // Set the indicator height to be fixed to 50.0f
+  scrollBar.SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  scrollBar.SetIndicatorFixedHeight(50.0f);
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Connect the pan finished signal
+  ConnectionTracker connectionTracker;
+  bool panFinished = false;
+  scrollBar.PanFinishedSignal().Connect( &OnPanFinished );
+  scrollBar.ConnectSignal( &connectionTracker, "panFinished", CallbackFunctor(&panFinished));
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Perform a vertical swipe gesture on the indicator when there is no source object set on the scroll bar
+  PerformGestureSwipe(application, Vector2(1.0f, 1.0f), Vector2(Vector2::YAXIS * 1.0f), 20, 500);
+  DALI_TEST_EQUALS( gOnPanFinishedCalled, false, TEST_LOCATION );
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   100.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   500.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Perform a swipe gesture on the scroll bar but not on the indicator
+  PerformGestureSwipe(application, Vector2(1.0f, 780.0f), Vector2(Vector2::YAXIS * -1.0f), 20, 2000);
+  DALI_TEST_EQUALS( gOnPanFinishedCalled, false, TEST_LOCATION );
+  DALI_TEST_EQUALS( panFinished, false, TEST_LOCATION );
+
+  // Perform a swipe gesture on the indicator
+  PerformGestureSwipe(application, Vector2(1.0f, 1.0f), Vector2(Vector2::YAXIS * 1.0f), 20, 4000);
+  DALI_TEST_EQUALS( gOnPanFinishedCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( panFinished, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarScrollPositionIntervalReachedSignalP(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollBar.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollBar.SetSize(20.0f, 800.0f, 0.0f);
+
+  Stage::GetCurrent().Add( scrollBar );
+  ConnectionTracker connectionTracker;
+
+  // Connect to the ScrollPositionIntervalReached signal
+  bool intervalReached = false;
+  scrollBar.ScrollPositionIntervalReachedSignal().Connect( &OnScrollPositionIntervalReached );
+  scrollBar.ConnectSignal( &connectionTracker, "scrollPositionIntervalReached", CallbackFunctor(&intervalReached));
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   800.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   2000.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set the values to get notified when the scroll positions of the source actor goes above or below these values
+  Dali::Vector<float> positionIntervals;
+  for( size_t i = 0; i != 10; ++i )
+  {
+    positionIntervals.PushBack( -80.0f * i ); // should get notified for each 80 pixels
+  }
+  scrollBar.SetScrollPositionIntervals(positionIntervals);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+
+  // Animate the scroll position to cross the specified value
+  Animation animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -85.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( intervalReached, true, TEST_LOCATION );
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+  intervalReached = false;
+
+  // Rest and clear the animation
+  animation.Clear();
+  animation.Reset();
+
+  // Animate the scroll position to cross another specified value
+  animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -170.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( intervalReached, true, TEST_LOCATION );
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+  intervalReached = false;
+
+  // Rest and clear the animation
+  animation.Clear();
+  animation.Reset();
+
+  // Animate the scroll position back to the previous value
+  animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -85.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( intervalReached, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollBarScrollPositionIntervalReachedSignalN(void)
+{
+  ToolkitTestApplication application;
+
+  // Create a vertical scroll bar
+  ScrollBar scrollBar = ScrollBar::New(ScrollBar::Vertical);
+  DALI_TEST_CHECK( scrollBar );
+
+  scrollBar.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollBar.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollBar.SetSize(20.0f, 800.0f, 0.0f);
+
+  Stage::GetCurrent().Add( scrollBar );
+
+  // Connect to the ScrollPositionIntervalReached signal
+  scrollBar.ScrollPositionIntervalReachedSignal().Connect( &OnScrollPositionIntervalReached );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a source actor that owns the scroll properties required by the scroll bar
+  Actor sourceActor = Actor::New();
+  Stage::GetCurrent().Add( sourceActor );
+
+  // Register the scroll properties
+  Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition",  0.0f );
+  Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin",   0.0f );
+  Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax",   800.0f );
+  Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize",   2000.0f );
+
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePosition" ), propertyScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMin" ), propertyMinScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourcePositionMax" ), propertyMaxScrollPosition, TEST_LOCATION );
+  DALI_TEST_EQUALS( sourceActor.GetPropertyIndex( "sourceContentSize" ), propertyScrollContentSize, TEST_LOCATION );
+
+  // Set the source of the scroll position properties.
+  scrollBar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set the values to get notified when the scroll positions of the source actor goes above or below these values
+  Dali::Vector<float> positionIntervals;
+  for( size_t i = 0; i != 10; ++i )
+  {
+    positionIntervals.PushBack( -80.0f * i ); // should get notified for each 80 pixels
+  }
+  scrollBar.SetScrollPositionIntervals(positionIntervals);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Reset the flag
+  gOnScrollPositionIntervalReachedSignalCalled = false;
+
+  // Animate the scroll position not to cross the specified value
+  Animation animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -70.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is not called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, false, TEST_LOCATION );
+
+  // Rest and clear the animation
+  animation.Clear();
+  animation.Reset();
+
+  // Animate the scroll position to cross another specified value
+  animation = Animation::New(0.1f);
+  animation.AnimateTo( Property( sourceActor, propertyScrollPosition ), -85.0f );
+  animation.Play();
+
+  // Wait for 0.1 second
+  Wait(application, 100);
+
+  // Check that the signal callback is called
+  DALI_TEST_EQUALS( gOnScrollPositionIntervalReachedSignalCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ScrollView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ScrollView.cpp
new file mode 100644 (file)
index 0000000..7b6a1f0
--- /dev/null
@@ -0,0 +1,2957 @@
+/*
+ * Copyright (c) 2019 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>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void scroll_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void scroll_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+const int RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
+
+const int RENDER_DELAY_SCROLL = 1000;                           ///< duration to wait for any scroll to complete.
+
+// For Clamp Signal testing...
+const float CLAMP_EXCESS_WIDTH = 200.0f;                        ///< Amount of width that can be panned outside scrollview
+const float CLAMP_EXCESS_HEIGHT = 200.0f;                       ///< Amount of height that can be panned outside scrollview
+const Vector2 CLAMP_START_SCROLL_POSITION(30.0f, 100.0f);       ///< Scroll start position for the Clamping tests.
+const Vector2 CLAMP_TOUCH_START( 100.0f, 100.0f );              ///< Start point to touch from for the Clamping tests.
+const Vector2 CLAMP_TOUCH_MOVEMENT( 5.0f, -5.0f );              ///< Amount to move touch for each frame for the Clamping tests.
+const int CLAMP_GESTURE_FRAMES = 100;                           ///< Number of Frames to synthesize a gesture for the Clamping tests.
+const Vector3 TEST_ACTOR_POSITION(100.0f, 100.0f, 0.0f);        ///< A Test actor position offset (arbitrary value)
+const Vector3 TEST_CONSTRAINT_OFFSET(1.0f, 2.0f, 0.0f);         ///< A Test constraint offset (arbitrary value to test effects)
+
+const float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);                  ///< Default overshoot snapping animation time.
+const float DEFAULT_MAX_OVERSHOOT(100.0f);                          ///< Default maximum allowed overshoot in pixels
+
+const int MAX_FRAMES_TO_TEST_OVERSHOOT = 600;                       ///< 10 seconds (at 60 frames per second).
+const Vector2 OVERSHOOT_START_SCROLL_POSITION(100.0f, 100.0f);       ///< Scroll start position for the Overshoot tests.
+const float SCROLL_ANIMATION_DURATION(0.33f);                       ///< Duration of scroll animation in Overshoot tests (i.e. 100 pixels of overshoot in the speed of 500 pixels per 100 frames, 100/(500/(100/60)) = 0.33)
+const Vector2 SNAP_POSITION_WITH_DECELERATED_VELOCITY(74.0f, 74.0f); ///< the snap position for Overshoot tests with the decelerated velocity (i.e. Decelerated from 500 pixels per 100 frames).
+const float TEST_CUSTOM1_SNAP_OVERSHOOT_DURATION = 0.05f;           ///< a Test duration
+const float TEST_CUSTOM2_SNAP_OVERSHOOT_DURATION = 1.5f;            ///< another Test duration
+const float TEST_CUSTOM3_SNAP_OVERSHOOT_DURATION = TEST_CUSTOM2_SNAP_OVERSHOOT_DURATION * 0.5f; // Same as above, but different alpha function.
+const float TIME_TOLERANCE = 0.05f;                                 ///< Allow testing tolerance between a 10th of second (+/- 3 frames)
+
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+// Callback probes.
+
+static bool gOnScrollStartCalled;                       ///< Whether the OnScrollStart signal was invoked.
+static bool gOnScrollUpdateCalled;                      ///< Whether the OnScrollUpdate signal was invoked.
+static bool gOnScrollCompleteCalled;                    ///< Whether the OnScrollComplete signal was invoked.
+static bool gOnSnapStartCalled;                         ///< Whether the OnSnapStart signal was invoked.
+static SnapType gLastSnapType;                          ///< Snaping information from SnapEvent.
+static Vector3 gConstraintResult;                       ///< Result from constraint.
+
+/**
+ * Invoked when scrolling starts.
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollStart( const Vector2& position )
+{
+  gOnScrollStartCalled = true;
+}
+
+/**
+ * Invoked when scrolling updates (via dragging)
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollUpdate( const Vector2& position )
+{
+  gOnScrollUpdateCalled = true;
+}
+
+/**
+ * Invoked when scrolling finishes
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollComplete( const Vector2& position )
+{
+  gOnScrollCompleteCalled = true;
+}
+
+/**
+ * Invoked when a snap or flick started.
+ *
+ * @param[in] event The type of snap and the target position/scale/rotation.
+ */
+static void OnSnapStart( const ScrollView::SnapEvent& event )
+{
+  gOnSnapStartCalled = true;
+  gLastSnapType = event.type;
+}
+
+/**
+ * TestSumConstraint
+ *
+ * Summation of current value, property, and offset.
+ *
+ * current' = current + mOffset + property;
+ */
+struct TestSumConstraint
+{
+  /**
+   * @param[in] offset The offset to be added to current.
+   */
+  TestSumConstraint(const Vector3& offset)
+  :mOffset(offset)
+  {
+  }
+
+  /**
+   * @param[in] current The current base value
+   * @param[in] inputs Contains the property to be added to current.
+   * @return The new current Vector.
+   */
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    gConstraintResult = current + Vector3(inputs[0]->GetVector2()) + mOffset;
+    current = gConstraintResult;
+  }
+
+  Vector3 mOffset;
+
+};
+
+/**
+ * @param[in] application The application instance
+ * @param[in] scrollView The scrollView instance
+ * @return The time taken for the overshoot to reach origin (zero)
+ */
+static float TestOvershootSnapDuration(ToolkitTestApplication &application, ScrollView scrollView)
+{
+  int timeToReachOrigin = -1;
+  for(int i = 0;i<MAX_FRAMES_TO_TEST_OVERSHOOT;i++)
+  {
+    float overshootXValue = scrollView.GetCurrentProperty<float>( ScrollView::Property::OVERSHOOT_X );
+    float overshootYValue = scrollView.GetCurrentProperty<float>( ScrollView::Property::OVERSHOOT_Y );
+    if(overshootXValue == 0.0f && overshootYValue == 0.0f)
+    {
+      break;
+    }
+
+    timeToReachOrigin += Wait(application);
+  }
+
+  return static_cast<float>(timeToReachOrigin) * 0.001f; // return in seconds not ms.
+}
+
+/**
+ * y = 2x alpha function, which is clamped between 0.0f - 1.0f
+ *
+ * Animations should appear to finish (reach 100% point)
+ * at just half the time of a regular Linear AlphaFunction.
+ *
+ * @param[in] progress value (ranges from 0.0f - 1.0f)
+ * @return interpolation value (ranges from 0.0f - 1.0f)
+ */
+float TestAlphaFunction(float progress)
+{
+  return std::min( progress * 2.0f, 1.0f );
+}
+
+/**
+ * Generate a complete pan gesture
+ * Note: To initiate the gesture it will go from start, diagonally SE on the screen, then continue in the direction for frames touches
+ */
+static Vector2 PerformGestureSwipe(ToolkitTestApplication& application, Vector2 start, Vector2 direction, int frames, uint32_t& time, bool finish = true)
+{
+  gOnScrollStartCalled = false;
+  gOnScrollUpdateCalled = false;
+  gOnScrollCompleteCalled = false;
+  gOnSnapStartCalled = false;
+
+  Vector2 pos( start );
+
+  // This is created to ensure a pan is started
+  Vector2 pos_start_jump( start + Vector2(11.0f, 11.0f) );
+  TestStartPan( application, start, pos_start_jump, time );
+  pos = pos_start_jump;
+
+  Wait(application);
+
+  for(int i = 0;i<frames;i++)
+  {
+    pos += direction; // Move in this direction
+    TestMovePan(application, pos, time );
+    time += Wait(application);
+  }
+
+  if(finish)
+  {
+    pos += direction; // Move in this direction.
+    TestEndPan(application, pos, time );
+    time += Wait(application, RENDER_DELAY_SCROLL);
+  }
+
+  return pos;
+}
+
+
+} // unnamed namespace
+
+
+int UtcDaliToolkitScrollViewConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollView scrollView;
+  DALI_TEST_CHECK( !scrollView );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetProperty( ScrollView::Property::SCROLL_POSITION, Vector2(10.0f, 10.0f) );
+
+  ScrollView copy( scrollView );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<Vector2>( ScrollView::Property::SCROLL_POSITION ) == scrollView.GetProperty<Vector2>( ScrollView::Property::SCROLL_POSITION ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetProperty( ScrollView::Property::SCROLL_POSITION, Vector2(10.0f, 10.0f) );
+
+  ScrollView copy = scrollView;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<Vector2>( ScrollView::Property::SCROLL_POSITION ) == scrollView.GetProperty<Vector2>( ScrollView::Property::SCROLL_POSITION ) );
+  END_TEST;
+}
+
+int UtcDaliScrollViewDestructorP(void)
+{
+  ToolkitTestApplication application;
+
+  ScrollView* scrollView = new ScrollView();
+  delete scrollView;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewNewP1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewNewP1");
+
+  ScrollView scrollView;
+
+  DALI_TEST_CHECK( !scrollView );
+
+  scrollView = ScrollView::New();
+
+  DALI_TEST_CHECK( scrollView );
+
+  ScrollView scrollView2(scrollView);
+
+  DALI_TEST_CHECK( scrollView2 == scrollView );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    ScrollView scrollView = ScrollView::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewNewP2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewNewP2 - create thru type registry");
+
+  ScrollView scrollView;
+  DALI_TEST_CHECK( !scrollView );
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  TypeInfo scrollViewType = typeRegistry.GetTypeInfo("ScrollView");
+  BaseHandle handle = scrollViewType.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  scrollView = ScrollView::DownCast(handle);
+  DALI_TEST_CHECK( scrollView );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDownCastP");
+
+  ScrollView scrollView = ScrollView::New();
+  BaseHandle handle(scrollView);
+
+  ScrollView newScrollView = ScrollView::DownCast( handle );
+  DALI_TEST_CHECK( scrollView );
+  DALI_TEST_CHECK( newScrollView == scrollView );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPositionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPositionP");
+
+  // Create the ScrollView actor
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  const Vector2 target = Vector2(100.0f, 200.0f);
+  const Vector2 target2 = Vector2(300.0f, 100.0f);
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+  scrollView.ScrollTo( target2 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPositionWithDirectionBiasP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPositionWithDirectionBiasP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.SetWrapMode(true);
+
+  Property::Value wrapMode = scrollView.GetProperty( Toolkit::ScrollView::Property::WRAP_ENABLED );
+  DALI_TEST_EQUALS( wrapMode.Get<bool>(), true, TEST_LOCATION );
+
+  const Vector2 target = Vector2(50.0f, 50.0f);
+  const Vector2 target2 = Vector2(150.0f, 150.0f);
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.25f, Dali::Toolkit::DirectionBiasLeft, Dali::Toolkit::DirectionBiasLeft );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.25f, Dali::Toolkit::DirectionBiasRight, Dali::Toolkit::DirectionBiasRight );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPositionWithAlphaFunctionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPositionWithAlphaFunctionP");
+
+  // Create the ScrollView actor
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  const Vector2 target = Vector2(100.0f, 200.0f);
+  const Vector2 target2 = Vector2(300.0f, 100.0f);
+
+  scrollView.ScrollTo( target, 0.5f, TestAlphaFunction );
+  Wait(application, 250);
+  // Check that the scroll animation should finish within just half of the specified duration with the above alpha function
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.5f, AlphaFunction::LINEAR );
+  Wait(application, 250);
+  // Check that the scroll animation has not finished within half of the specified duration with the linear alpha function
+  DALI_TEST_CHECK( scrollView.GetCurrentScrollPosition() != target2 );
+
+  // Wait till the end of the specified duration
+  Wait(application, 250);
+  // Check that the scroll animation has finished
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPositionWithAlphaFunctionAndDirectionBiasP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPositionWithAlphaFunctionAndDirectionBiasP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.SetWrapMode(true);
+
+  const Vector2 target = Vector2(50.0f, 50.0f);
+  const Vector2 target2 = Vector2(150.0f, 150.0f);
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.25f, AlphaFunction::LINEAR, Dali::Toolkit::DirectionBiasLeft, Dali::Toolkit::DirectionBiasLeft );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.25f, AlphaFunction::LINEAR, Dali::Toolkit::DirectionBiasRight, Dali::Toolkit::DirectionBiasRight );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+
+  scrollView.ScrollTo( target2, 0.25f, TestAlphaFunction, Dali::Toolkit::DirectionBiasRight, Dali::Toolkit::DirectionBiasRight );
+  Wait(application, 125);
+  // Check that the scroll animation should finish within just half of the specified duration with the above alpha function
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPageP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPageP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.ScrollTo( 1, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(100.0f, 0.0f), TEST_LOCATION );
+
+  scrollView.ScrollTo( 5, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(500.0f, 0.0f), TEST_LOCATION );
+
+  scrollView.ScrollTo( 10, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(200.0f, 100.0f), TEST_LOCATION );
+
+  scrollView.ScrollTo( 15, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(700.0f, 100.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 15, TEST_LOCATION );
+
+  scrollView.ScrollTo( 3 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(300.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 3, TEST_LOCATION );
+
+  scrollView.ScrollTo( 9 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(100.0f, 100.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 9, TEST_LOCATION );
+
+  // Apply DefaultRulers instead and see what happens.
+  rulerX = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+  rulerY = new DefaultRuler();
+  rulerY->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  // This time should always scroll to origin (0.0f, 0.0f)
+  scrollView.ScrollTo( 1, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliToolkitScrollModeP1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollView ScrollMode property" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 viewPageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( viewPageSize );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers.
+  Property::Map rulerMap;
+  rulerMap.Add( ScrollMode::X_AXIS_SCROLL_ENABLED, true );
+  rulerMap.Add( ScrollMode::X_AXIS_SNAP_TO_INTERVAL, viewPageSize.width );
+  rulerMap.Add( ScrollMode::X_AXIS_SCROLL_BOUNDARY, viewPageSize.width*3 );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_ENABLED, false );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_MODE, rulerMap);
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  // Set up a gesture to perform.
+  Vector2 startPos( 50.0f, 0.0f );
+  Vector2 direction( -5.0f, 0.0f );
+  int frames = 200;
+  uint32_t time = 0;
+
+  // Force starting position.
+  scrollView.ScrollTo( startPos, 0.0f );
+  time += Wait( application );
+
+  // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+  Vector2 currentPos( PerformGestureSwipe( application, startPos, direction, frames - 1, time, false ) );
+
+  // Confirm the final X coord has not moved more than one page from the start X position.
+  DALI_TEST_GREATER( ( startPos.x + viewPageSize.width ), scrollView.GetCurrentScrollPosition().x, TEST_LOCATION );
+
+  // Finish the gesture and wait for the snap.
+  currentPos += direction;
+  TestEndPan( application, currentPos, time );
+  // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+  time += Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+  // Confirm the final X coord has snapped to exactly one page ahead of the start page.
+  DALI_TEST_EQUALS( viewPageSize.width, scrollView.GetCurrentScrollPosition().x, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollModeP2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollView ScrollMode property" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 viewPageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( viewPageSize );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers.
+  Property::Map rulerMap;
+  rulerMap.Add( ScrollMode::X_AXIS_SCROLL_ENABLED, false );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_ENABLED, true );
+  rulerMap.Add( ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, viewPageSize.height );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_BOUNDARY, viewPageSize.height*3 );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_MODE, rulerMap);
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  // Set up a gesture to perform.
+  Vector2 startPos( 0.0f, 50.0f );
+  Vector2 direction( 0.0f, -6.0f );
+  int frames = 200;
+  uint32_t time = 0;
+
+  // Force starting position.
+  scrollView.ScrollTo( startPos, 0.0f );
+  time += Wait( application );
+
+  // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+  Vector2 currentPos( PerformGestureSwipe( application, startPos, direction, frames - 1, time, false ) );
+
+  // Confirm the final X coord has not moved more than one page from the start X position.
+  DALI_TEST_GREATER( ( startPos.y + viewPageSize.height ), scrollView.GetCurrentScrollPosition().y, TEST_LOCATION );
+
+  // Finish the gesture and wait for the snap.
+  currentPos += direction;
+  time += Wait( application );
+  TestEndPan( application, currentPos, time );
+  // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+  Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+  // Confirm the final Y coord has snapped to exactly one page ahead of the start page.
+  DALI_TEST_EQUALS( viewPageSize.height, scrollView.GetCurrentScrollPosition().y, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollModeP3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollView ScrollMode property" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 viewPageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( viewPageSize );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers.
+  Property::Map rulerMap;
+  rulerMap.Add( ScrollMode::X_AXIS_SCROLL_ENABLED, false );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_ENABLED, true );
+  rulerMap.Add( ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, viewPageSize.height );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_BOUNDARY, viewPageSize.height*3 );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_MODE, rulerMap);
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  // Set up a gesture to perform.
+  Vector2 startPos( 0.0f, 50.0f );
+  Vector2 direction( 0.0f, -6.0f );
+  int frames = 200;
+  uint32_t time  = 0;
+
+  // Force starting position.
+  scrollView.ScrollTo( startPos, 0.0f );
+  time += Wait( application );
+
+  // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+  Vector2 currentPos( PerformGestureSwipe( application, startPos, direction, frames - 1, time, false ) );
+
+  // Confirm the final X coord has not moved more than one page from the start X position.
+  DALI_TEST_GREATER( ( startPos.y + viewPageSize.height ), scrollView.GetCurrentScrollPosition().y, TEST_LOCATION );
+
+  // Finish the gesture and wait for the snap.
+  currentPos += direction;
+  TestEndPan( application, currentPos, time );
+  // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+  Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+  // Confirm the final Y coord has snapped to exactly one page ahead of the start page.
+  DALI_TEST_EQUALS( viewPageSize.height, scrollView.GetCurrentScrollPosition().y, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollModeP4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollView ScrollMode property, DefaultRulers" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 viewPageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( viewPageSize );
+  scrollView.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  scrollView.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers - expect Default rulers to be used which don't snap
+  Property::Map rulerMap;
+  rulerMap.Add( ScrollMode::X_AXIS_SCROLL_ENABLED, true );
+  rulerMap.Add( ScrollMode::Y_AXIS_SCROLL_ENABLED, true );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_MODE, rulerMap);
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  Vector2 START_POSITION = Vector2(10.0f, 10.0f);
+
+  uint32_t time = 0;
+  scrollView.ScrollTo(START_POSITION, 0.0f);
+  time += Wait(application);
+
+  // Try a vertical swipe.
+  // PerformGestureSwipe not used as a different initial direction was required
+  Vector2 pos( START_POSITION + Vector2(0.0f, 15.0f) );
+  Vector2 dir( 0.0f, 1.0f );
+
+  TestStartPan( application, START_POSITION, pos, time );
+
+  Wait(application);
+
+  for( int i = 0; i<45; i++ )
+  {
+    pos += dir;
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+
+  pos += dir;
+
+  TestEndPan( application, pos, time );
+  Wait( application, RENDER_DELAY_SCROLL );
+
+  // Take into account resampling done when prediction is off.
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToPageWithDirectionBiasP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToPageWithDirectionBiasP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.SetWrapMode(true);
+
+  scrollView.ScrollTo( 0, 0.25, Dali::Toolkit::DirectionBiasLeft );
+
+  Wait(application, RENDER_FRAME_INTERVAL); // Wait for one frame
+  // Check that the scroll position remains the same
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 0.0f), TEST_LOCATION );
+
+  Wait(application, RENDER_DELAY_SCROLL); // Wait for one second
+  // Check that it stays at the same page (i.e. the same scroll position)
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 0.0f), TEST_LOCATION );
+
+  scrollView.ScrollTo( 0, 0.25, Dali::Toolkit::DirectionBiasRight );
+
+  Wait(application, RENDER_FRAME_INTERVAL); // Wait for one frame
+  // Check that it scrolls towards the right
+  DALI_TEST_CHECK( scrollView.GetCurrentScrollPosition().x > 0.0f );
+
+  Wait(application, RENDER_DELAY_SCROLL); // Wait for one second
+  // Check that it scrolls back to the same page (i.e. the same scroll position)
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 0.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToActorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToActorP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  Actor actorA = Actor::New();
+  const Vector3 positionA = Vector3(100.0f, 400.0f, 0.0f);
+  actorA.SetPosition(positionA);
+  scrollView.Add(actorA);
+
+  Actor actorB = Actor::New();
+  const Vector3 positionB = Vector3(500.0f, 200.0f, 0.0f);
+  actorB.SetPosition(positionB);
+  scrollView.Add(actorB);
+
+  Wait(application);
+
+  scrollView.ScrollTo(actorA, 0.0f);
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), positionA.GetVectorXY(), TEST_LOCATION );
+
+  Wait(application);
+  scrollView.ScrollTo(actorB, 0.0f);
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), positionB.GetVectorXY(), TEST_LOCATION );
+
+  scrollView.ScrollTo(actorA);
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), positionA.GetVectorXY(), TEST_LOCATION );
+
+  scrollView.ScrollTo(actorB);
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), positionB.GetVectorXY(), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollToSnapPointP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollToSnapPointP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.ScrollTo( Vector2(120.0f, 190.0f), 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(120.0f, 190.0f), TEST_LOCATION );
+
+  scrollView.ScrollToSnapPoint();
+
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(100.0f, 200.0f), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetScrollUpdateDistanceP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetScrollUpdateDistanceP");
+
+  ScrollView scrollView = ScrollView::New();
+
+  scrollView.SetScrollUpdateDistance(0);
+  DALI_TEST_EQUALS( scrollView.GetScrollUpdateDistance(), 0, TEST_LOCATION);
+  scrollView.SetScrollUpdateDistance(10);
+  DALI_TEST_EQUALS( scrollView.GetScrollUpdateDistance(), 10, TEST_LOCATION);
+  scrollView.SetScrollUpdateDistance(1000);
+  DALI_TEST_EQUALS( scrollView.GetScrollUpdateDistance(), 1000, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetWrapModeP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetWrapModeP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  Actor actor = Actor::New();
+  scrollView.Add( actor );
+
+  // Position rulers. 4x4 grid.
+  RulerPtr rulerX = new FixedRuler(50.0f);
+  RulerPtr rulerY = new FixedRuler(50.0f);
+  rulerX->SetDomain( RulerDomain(0.0f, 200.0f, false) );
+  rulerY->SetDomain( RulerDomain(0.0f, 200.0f, false) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  scrollView.SetWrapMode(false);
+  scrollView.ScrollTo(Vector2(225.0f, 125.0f), 0.0f); // 5th (1st) page across, and 3rd (3rd) page down. (wrapped)
+  Wait(application);
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 17, TEST_LOCATION );
+
+  scrollView.SetWrapMode(true);
+  scrollView.ScrollTo(Vector2(230.0f, 130.0f), 0.0f); // 5th (1st) page across, and 3rd (3rd) page down. (wrapped)
+  Wait(application);
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 13, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewActorAutoSnap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewActorAutoSnap");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  rulerY->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  const Vector3 aPosition = Vector3(200.0f, 50.0f, 0.0f);
+  Actor a = Actor::New();
+  scrollView.Add(a);
+  a.SetPosition(aPosition);
+
+  const Vector3 bPosition = Vector3(600.0f, 600.0f, 0.0f);
+  Actor b = Actor::New();
+  scrollView.Add(b);
+  b.SetPosition(bPosition);
+
+  // Goto a random position, and execute snap (should not move)
+  Vector2 targetScroll = Vector2(500.0f, 500.0f);
+  scrollView.ScrollTo(targetScroll, 0.0f);
+  Wait(application);
+  scrollView.ScrollToSnapPoint();
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), targetScroll, TEST_LOCATION );
+
+  // Enable ActorAutoSnap, and now try snapping.
+  scrollView.SetActorAutoSnap(true);
+  scrollView.ScrollToSnapPoint();
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), bPosition.GetVectorXY(), TEST_LOCATION );
+
+  scrollView.ScrollTo(Vector2(0.0f, 0.0f), 0.0f);
+  Wait(application);
+  scrollView.ScrollToSnapPoint();
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), aPosition.GetVectorXY(), TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSignalsStartComplete(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSignalsStartComplete");
+
+  gOnScrollStartCalled = false;
+  gOnScrollCompleteCalled = false;
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  rulerY->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+  scrollView.ScrollTo( Vector2(100.0f, 100.0f) );
+  Wait(application, RENDER_DELAY_SCROLL);
+
+  DALI_TEST_CHECK(gOnScrollStartCalled);
+  DALI_TEST_CHECK(gOnScrollCompleteCalled);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSignalsUpdate01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSignalsUpdate");
+
+  gOnScrollStartCalled = false;
+  gOnScrollUpdateCalled = false;
+  gOnScrollCompleteCalled = false;
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  rulerY->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+
+  Actor image = Actor::New();
+  image.SetSize(stageSize);
+  image.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  image.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollView.Add(image);
+
+  Wait(application);
+
+  // Do a pan starting from 100,100 and moving down diagonally.
+  Vector2 pos(100.0f, 100.0f);
+  uint32_t time = 100;
+  TestStartPan( application, pos, pos, time );
+  pos.x += 5.0f;
+  pos.y += 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<20;i++)
+  {
+    time += RENDER_FRAME_INTERVAL;
+    TestMovePan( application, pos, time);
+    pos.x += 5.0f;
+    pos.y += 5.0f;
+    Wait(application);
+  }
+
+  time += RENDER_FRAME_INTERVAL;
+  TestEndPan(application, pos, time );
+  Wait(application, RENDER_DELAY_SCROLL);
+
+  DALI_TEST_CHECK(gOnScrollStartCalled);
+  DALI_TEST_CHECK(gOnScrollUpdateCalled);
+  DALI_TEST_CHECK(gOnScrollCompleteCalled);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSignalsUpdate02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSignalsUpdate");
+
+  gOnScrollStartCalled = false;
+  gOnScrollUpdateCalled = false;
+  gOnScrollCompleteCalled = false;
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  rulerY->SetDomain( RulerDomain(0.0f, 1000.0f, false) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  Dali::ConnectionTracker tracker;
+  bool scrollStarted=false;
+  bool scrollUpdated=false;
+  bool scrollCompleted=false;
+  DALI_TEST_CHECK(scrollView.ConnectSignal( &tracker, "scrollStarted", CallbackFunctor(&scrollStarted) ));
+  DALI_TEST_CHECK(scrollView.ConnectSignal( &tracker, "scrollUpdated", CallbackFunctor(&scrollUpdated) ));
+  DALI_TEST_CHECK(scrollView.ConnectSignal( &tracker, "scrollCompleted", CallbackFunctor(&scrollCompleted) ));
+
+  Actor image = Actor::New();
+  image.SetSize(stageSize);
+  image.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  image.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  scrollView.Add(image);
+
+  Wait(application);
+
+  // Do a pan starting from 100,100 and moving down diagonally.
+  Vector2 pos(100.0f, 100.0f);
+  uint32_t time = 100;
+  TestStartPan( application, pos, pos, time );
+  pos.x += 5.0f;
+  pos.y += 5.0f;
+  Wait(application, 100);
+
+  for(int i = 0;i<20;i++)
+  {
+    time += RENDER_FRAME_INTERVAL;
+    TestMovePan( application, pos, time);
+    pos.x += 5.0f;
+    pos.y += 5.0f;
+    Wait(application);
+  }
+
+  time += RENDER_FRAME_INTERVAL;
+  TestEndPan(application, pos, time );
+  Wait(application, RENDER_DELAY_SCROLL);
+
+  DALI_TEST_CHECK(scrollStarted);
+  DALI_TEST_CHECK(scrollUpdated);
+  DALI_TEST_CHECK(scrollCompleted);
+
+  Stage::GetCurrent().Remove( scrollView );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewScrollSensitive(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewScrollSensitive");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetOvershootEnabled(true);
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+  scrollView.SnapStartedSignal().Connect( &OnSnapStart );
+
+  scrollView.ScrollTo(CLAMP_START_SCROLL_POSITION, 0.0f); // move in a little.
+  uint32_t time = 0;
+  time +=Wait(application);
+
+  // First try insensitive swipe.
+  scrollView.SetScrollSensitive(false);
+  PerformGestureSwipe(application, CLAMP_TOUCH_START, CLAMP_TOUCH_MOVEMENT, CLAMP_GESTURE_FRAMES, time, true);
+
+  DALI_TEST_CHECK( !gOnScrollStartCalled );
+  DALI_TEST_CHECK( !gOnScrollCompleteCalled );
+  DALI_TEST_CHECK( !gOnSnapStartCalled );
+
+  // Second try sensitive swipe.
+  scrollView.SetScrollSensitive(true);
+  PerformGestureSwipe(application, CLAMP_TOUCH_START, CLAMP_TOUCH_MOVEMENT, CLAMP_GESTURE_FRAMES, time, true);
+
+  DALI_TEST_CHECK( gOnScrollStartCalled );
+  DALI_TEST_CHECK( gOnScrollCompleteCalled );
+  DALI_TEST_CHECK( gOnSnapStartCalled );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewAxisAutoLock(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewAxisAutoLock");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+
+  // Normal
+  scrollView.ScrollTo(Vector2(100.0f, 100.0f), 0.0f); // move in a little.
+  uint32_t time = 0;
+  time += Wait(application);
+
+  Vector2 startPosition = scrollView.GetCurrentScrollPosition();
+  Vector2 dir(5.0f, 1.0f);
+
+  // PerformGestureSwipe not used as a different initial direction was required
+
+  Vector2 pos( CLAMP_TOUCH_START + Vector2(15.0f, 3.0f) );
+
+  TestStartPan( application, CLAMP_TOUCH_START, pos, time );
+
+  time += Wait(application);
+
+  for( int i = 0; i<47; i++ )
+  {
+    pos += dir;
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+
+  pos += dir;
+
+  TestEndPan( application, pos, time );
+
+  const Vector2 positionAfterNormal = scrollView.GetCurrentScrollPosition();
+
+  // Autolock
+  scrollView.SetAxisAutoLock(true);
+  DALI_TEST_CHECK(scrollView.GetAxisAutoLock());
+
+  scrollView.ScrollTo(Vector2(100.0f, 100.0f), 0.0f); // move in a little.
+  time += Wait(application);
+
+  Vector2 pos2( CLAMP_TOUCH_START + Vector2(15.0f, 3.0f) );
+
+  TestStartPan( application, CLAMP_TOUCH_START, pos2, time );
+
+  time += Wait(application);
+
+  for( int i = 0; i<47; i++ )
+  {
+    pos2 += dir;
+    TestMovePan( application, pos2, time );
+    time += Wait( application );
+  }
+
+  pos2 += dir;
+
+  TestEndPan( application, pos2, time );
+
+  const Vector2 positionAfterAutoLock = scrollView.GetCurrentScrollPosition();
+
+  // compare how much the Y position has deviated for normal and autolock.
+  const float devianceNormal = fabsf(startPosition.y - positionAfterNormal.y);
+  const float devianceAutoLock = fabsf(startPosition.y - positionAfterAutoLock.y);
+
+  // in auto-lock it should be a mostly horizontal pan (thus deviance should be much lower)
+  DALI_TEST_CHECK(devianceAutoLock < devianceNormal);
+
+  scrollView.SetAxisAutoLock(false);
+  DALI_TEST_CHECK(!scrollView.GetAxisAutoLock());
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewAxisAutoLockGradient(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewAxisAutoLockGradient");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetAxisAutoLockGradient(0.5f);
+  DALI_TEST_EQUALS(scrollView.GetAxisAutoLockGradient(), 0.5f, TEST_LOCATION);
+  scrollView.SetAxisAutoLockGradient(1.0f);
+  DALI_TEST_EQUALS(scrollView.GetAxisAutoLockGradient(), 1.0f, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewConstraints(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewConstraints");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  // Add an Actor to ScrollView,
+  // Apply TestSumConstraint to ScrollView's children (includes this Actor)
+  gConstraintResult = Vector3::ZERO;
+  Actor a = Actor::New();
+  scrollView.Add(a);
+  a.SetPosition( TEST_ACTOR_POSITION );
+  Wait(application);
+
+  Constraint constraint = Constraint::New<Vector3>( scrollView, Actor::Property::POSITION, TestSumConstraint( TEST_CONSTRAINT_OFFSET ) );
+  constraint.AddSource( Source(scrollView, ScrollView::Property::SCROLL_POSITION) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  scrollView.ApplyConstraintToChildren(constraint);
+  Wait(application);
+
+  DALI_TEST_EQUALS( gConstraintResult, TEST_ACTOR_POSITION + TEST_CONSTRAINT_OFFSET, TEST_LOCATION );
+
+  gConstraintResult = Vector3::ZERO;
+  scrollView.RemoveConstraintsFromChildren();
+  Wait(application);
+
+  DALI_TEST_EQUALS( gConstraintResult, Vector3::ZERO, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewBind(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewBind");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  // Add an Actor to ScrollView,
+  // Apply TestSumConstraint to ScrollView's children (includes this Actor)
+
+  gConstraintResult = Vector3::ZERO;
+  Actor a = Actor::New();
+  scrollView.Add(a);
+  a.SetPosition( TEST_ACTOR_POSITION );
+  Wait(application);
+
+  // apply this constraint to scrollview
+  Constraint constraint = Constraint::New<Vector3>( scrollView, Actor::Property::POSITION, TestSumConstraint( TEST_CONSTRAINT_OFFSET ) );
+  constraint.AddSource( Source(scrollView, ScrollView::Property::SCROLL_POSITION) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  scrollView.ApplyConstraintToChildren(constraint);
+
+  Wait(application);
+  // Defaulty Bound.
+  DALI_TEST_EQUALS( gConstraintResult, TEST_ACTOR_POSITION + TEST_CONSTRAINT_OFFSET, TEST_LOCATION );
+
+  // UnBind
+  gConstraintResult = Vector3::ZERO;
+  scrollView.UnbindActor( a );
+  Wait(application);
+  DALI_TEST_EQUALS( gConstraintResult, Vector3::ZERO, TEST_LOCATION );
+
+  // Bind
+  gConstraintResult = Vector3::ZERO;
+  scrollView.BindActor( a );
+  Wait(application);
+  DALI_TEST_EQUALS( gConstraintResult, TEST_ACTOR_POSITION + TEST_CONSTRAINT_OFFSET, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewOvershoot(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewOvershoot");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetOvershootEnabled(true);
+
+  uint32_t time = 0;
+  Vector2 overshootSize = Vector2(100.0f,100.0f);
+  scrollView.SetProperty( Scrollable::Property::OVERSHOOT_SIZE, overshootSize );
+  DALI_TEST_EQUALS( scrollView.GetProperty(Scrollable::Property::OVERSHOOT_SIZE).Get<Vector2>(), overshootSize, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+
+  scrollView.ScrollTo(OVERSHOOT_START_SCROLL_POSITION, 0.0f); // move in a little.
+  time += Wait(application);
+
+  // 1. Scroll page in NW (-500,-500 pixels), then inspect overshoot. (don't release touch)
+  Vector2 currentPos = Vector2(100.0f, 100.0f);
+  currentPos = PerformGestureSwipe(application, currentPos, Vector2(5.0f, 5.0f), 100, time, false);
+  float overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  float overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  Vector2 positionValue = scrollView.GetCurrentProperty< Vector2 >( ScrollView::Property::SCROLL_POSITION );
+  DALI_TEST_EQUALS(overshootXValue, 1.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(overshootYValue, 1.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(positionValue, Vector2::ZERO, TEST_LOCATION);
+
+  float timeToReachOrigin;
+
+  // Now release touch. Overshoot should snap back to zero.
+  TestEndPan(application, currentPos, time);
+
+  timeToReachOrigin = TestOvershootSnapDuration(application, scrollView);
+
+  float minTimeToReachOrigin = SCROLL_ANIMATION_DURATION + DEFAULT_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) - TIME_TOLERANCE;
+  float maxTimeToReachOrigin = SCROLL_ANIMATION_DURATION + DEFAULT_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) + TIME_TOLERANCE;
+
+  DALI_TEST_CHECK( (timeToReachOrigin > minTimeToReachOrigin) &&
+                   (timeToReachOrigin < maxTimeToReachOrigin) );
+
+  // 2. Repeat Scroll, but this time change overshoot snap duration to shorter time
+  scrollView.SetSnapOvershootDuration(TEST_CUSTOM1_SNAP_OVERSHOOT_DURATION);
+
+  currentPos = PerformGestureSwipe(application, Vector2(100.0f, 100.0f), Vector2(5.0f, 5.0f), 100, time, false);
+  // Now release touch. Overshoot should snap back to zero.
+  TestEndPan(application, currentPos, time);
+  timeToReachOrigin = TestOvershootSnapDuration(application, scrollView);
+
+  minTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM1_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) - TIME_TOLERANCE;
+  maxTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM1_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) + TIME_TOLERANCE;
+
+  DALI_TEST_CHECK( (timeToReachOrigin > minTimeToReachOrigin) &&
+                   (timeToReachOrigin < maxTimeToReachOrigin) );
+
+  // 3. Repeat Scroll, but this time change overshoot snap duration to longer time.
+  scrollView.SetSnapOvershootDuration(TEST_CUSTOM2_SNAP_OVERSHOOT_DURATION);
+
+  currentPos = PerformGestureSwipe(application, Vector2(100.0f, 100.0f), Vector2(5.0f, 5.0f), 100, time, false);
+  // Now release touch. Overshoot should snap back to zero.
+  TestEndPan(application, currentPos, time);
+  timeToReachOrigin = TestOvershootSnapDuration(application, scrollView);
+
+  minTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM2_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) - TIME_TOLERANCE;
+  maxTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM2_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) + TIME_TOLERANCE;
+
+  DALI_TEST_CHECK( (timeToReachOrigin > minTimeToReachOrigin) &&
+                   (timeToReachOrigin < maxTimeToReachOrigin) );
+
+  // 4. Repeat Scroll, but this time change overshoot function.
+  scrollView.SetSnapOvershootDuration(TEST_CUSTOM3_SNAP_OVERSHOOT_DURATION);
+  scrollView.SetSnapOvershootAlphaFunction(TestAlphaFunction);
+
+  currentPos = PerformGestureSwipe(application, Vector2(100.0f, 100.0f), Vector2(5.0f, 5.0f), 100, time, false);
+  // Now release touch. Overshoot should snap back to zero.
+  TestEndPan(application, currentPos, time);
+  timeToReachOrigin = TestOvershootSnapDuration(application, scrollView);
+
+  minTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM3_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) - TIME_TOLERANCE;
+  maxTimeToReachOrigin = SCROLL_ANIMATION_DURATION + TEST_CUSTOM3_SNAP_OVERSHOOT_DURATION * (SNAP_POSITION_WITH_DECELERATED_VELOCITY.x / DEFAULT_MAX_OVERSHOOT) + TIME_TOLERANCE;
+
+  DALI_TEST_CHECK( (timeToReachOrigin > minTimeToReachOrigin) &&
+                   (timeToReachOrigin < maxTimeToReachOrigin) );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSnapAlphaFunction(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSnapAlphaFunction");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetScrollSnapAlphaFunction( AlphaFunction::EASE_IN );
+  DALI_TEST_CHECK( scrollView.GetScrollSnapAlphaFunction().GetBuiltinFunction() == AlphaFunction::EASE_IN );
+  scrollView.SetScrollSnapAlphaFunction( AlphaFunction::EASE_OUT );
+  DALI_TEST_CHECK( scrollView.GetScrollSnapAlphaFunction().GetBuiltinFunction() == AlphaFunction::EASE_OUT );
+
+  scrollView.SetScrollFlickAlphaFunction( AlphaFunction::BOUNCE );
+  DALI_TEST_CHECK( scrollView.GetScrollFlickAlphaFunction().GetBuiltinFunction() == AlphaFunction::BOUNCE );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSnapDuration(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSnapDuration");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetScrollSnapDuration( 1.0f );
+  DALI_TEST_EQUALS( scrollView.GetScrollSnapDuration(), 1.0f, TEST_LOCATION );
+  scrollView.SetScrollSnapDuration( 0.5f );
+  DALI_TEST_EQUALS( scrollView.GetScrollSnapDuration(), 0.5f, TEST_LOCATION );
+
+  scrollView.SetScrollFlickDuration( 2.0f );
+  DALI_TEST_EQUALS( scrollView.GetScrollFlickDuration(), 2.0f, TEST_LOCATION );
+  scrollView.SetScrollFlickDuration( 1.5f );
+  DALI_TEST_EQUALS( scrollView.GetScrollFlickDuration(), 1.5f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSnapStartedSignalP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSnapStartedSignalP");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+  scrollView.SnapStartedSignal().Connect( &OnSnapStart );
+
+  scrollView.ScrollTo(CLAMP_START_SCROLL_POSITION, 0.0f); // move in a little.
+  uint32_t time = 0;
+  time += Wait(application);
+
+  // First try a snap.
+  PerformGestureSwipe(application, CLAMP_TOUCH_START, Vector2(0.5f, 0.0f), 60, time, true);
+
+  DALI_TEST_CHECK( gOnSnapStartCalled );
+  DALI_TEST_CHECK( gLastSnapType == Toolkit::Snap );
+
+  // Second try a swipe.
+  PerformGestureSwipe(application, CLAMP_TOUCH_START, Vector2(20.0f, 0.0f), 60, time, true);
+
+  DALI_TEST_CHECK( gOnSnapStartCalled );
+  DALI_TEST_CHECK( gLastSnapType == Toolkit::Flick );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewGetCurrentPageP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewGetCurrentPageP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+  RulerPtr rulerY = new FixedRuler( 100.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.ScrollTo( 15 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 15, TEST_LOCATION );
+
+  scrollView.ScrollTo( 3 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 3, TEST_LOCATION );
+
+  scrollView.ScrollTo( 9 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( static_cast<int>(scrollView.GetCurrentPage()), 9, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetMaxOvershootP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetMaxOvershootP");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  // Set the max overshoot to be 50 pixels in both X axis and Y axis
+  scrollView.SetMaxOvershoot(50.0f, 50.0f);
+
+  scrollView.ScrollTo(OVERSHOOT_START_SCROLL_POSITION, 0.0f); // move in a little.
+  uint32_t time = 0;
+  time += Wait(application);
+
+  // Scroll page in NW (-20,-20 pixels), then check that overshoot should be 0. (don't release touch)
+  Vector2 currentPos = PerformGestureSwipe(application, OVERSHOOT_START_SCROLL_POSITION, Vector2(1.0f, 1.0f), 10, time, false);
+  float overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  float overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  DALI_TEST_EQUALS(overshootXValue, 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(overshootYValue, 0.0f, TEST_LOCATION);
+
+  time += Wait(application);
+  // Scroll page further in NW (-105,-105 pixels), then check that overshoot should be around 0.5. (don't release touch)
+  for(int i = 0; i<106; i++)
+  {
+    TestMovePan(application, currentPos, time );
+    currentPos += Vector2(1.0f, 1.0f);
+    time += Wait(application);
+  }
+
+  overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  // The overshoot value is a 0.0f - 1.0f ranged value of the amount overshot related to the maximum overshoot.
+  // EG. If we move 105, max overshoot is 50, then we overshot 50 / 105.
+  float correctOvershootValue = 0.508f;   // This was measured and then set as the limit
+  DALI_TEST_EQUALS( overshootXValue, correctOvershootValue, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( overshootYValue, correctOvershootValue, 0.001f, TEST_LOCATION );
+
+  // Scroll page further in NW (-25,-25 pixels), then check that overshoot should be now 1.0. (don't release touch)
+  for(int i = 0;i<25;i++)
+  {
+    TestMovePan(application, currentPos, time );
+    currentPos += Vector2(1.0f, 1.0f); // Move in this direction
+    time += Wait(application);
+  }
+
+  overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  DALI_TEST_EQUALS(overshootXValue, 1.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(overshootYValue, 1.0f, TEST_LOCATION);
+
+  // Change the max overshoot to be 250 pixels in both X axis and Y axis
+  scrollView.SetMaxOvershoot(250.0f, 250.0f);
+  time += Wait(application);
+
+  // Check that overshoot should be now around 0.8.
+  overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  DALI_TEST_CHECK(overshootXValue > 0.79f && overshootXValue < 0.81f);
+  DALI_TEST_CHECK(overshootYValue > 0.79f && overshootYValue < 0.81f);
+
+  // Scroll page further in NW (-50,-50 pixels), then check that overshoot should be now 1.0. (don't release touch)
+  for(int i = 0;i<50;i++)
+  {
+    TestMovePan(application, currentPos, time );
+    currentPos += Vector2(1.0f, 1.0f); // Move in this direction
+    time += Wait(application);
+  }
+
+  overshootXValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_X );
+  overshootYValue = scrollView.GetCurrentProperty< float >( ScrollView::Property::OVERSHOOT_Y );
+  DALI_TEST_EQUALS(overshootXValue, 1.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(overshootYValue, 1.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetScrollingDirectionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetScrollingDirectionP");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  Vector2 START_POSITION = Vector2(10.0f, 10.0f);
+
+  scrollView.ScrollTo(START_POSITION, 0.0f);
+  uint32_t time = 0;
+  time += Wait(application);
+
+  // Try a vertical swipe.
+  // PerformGestureSwipe not used as a different initial direction was required
+
+  Vector2 pos( START_POSITION + Vector2(0.0f, 15.0f) );
+  TestStartPan( application, START_POSITION, pos, time );
+  time += Wait(application);
+  for( int i = 0; i<45; i++ )
+  {
+    pos += Vector2(0.0f, 1.0f);
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+  pos += Vector2(0.0f, 1.0f);
+  TestEndPan( application, pos, time );
+  time += Wait( application );
+
+  // Take into account resampling done when prediction is off.
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  scrollView.SetScrollingDirection(Dali::PanGestureDetector::DIRECTION_VERTICAL);
+
+  scrollView.ScrollTo(START_POSITION, 0.0f);
+  time += Wait(application);
+
+  // Try a vertical swipe.
+  // PerformGestureSwipe not used as a different initial direction was required
+  pos = ( START_POSITION + Vector2(0.0f, 15.0f) );
+  TestStartPan( application, START_POSITION, pos, time );
+  time += Wait(application);
+  for( int i = 0; i<45; i++ )
+  {
+    pos += Vector2(0.0f, 1.0f);
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+  pos += Vector2(0.0f, 1.0f);
+  TestEndPan( application, pos, time );
+  time += Wait( application );
+
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  scrollView.RemoveScrollingDirection(Dali::PanGestureDetector::DIRECTION_VERTICAL);
+
+  scrollView.ScrollTo(START_POSITION, 0.0f);
+
+  time += Wait(application);
+
+  // Try a vertical swipe.
+  // PerformGestureSwipe not used as a different initial direction was required
+  pos = ( START_POSITION + Vector2(0.0f, 15.0f) );
+  TestStartPan( application, START_POSITION, pos, time );
+  time += Wait(application);
+  for( int i = 0; i<45; i++ )
+  {
+    pos += Vector2(0.0f, 1.0f);
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+  pos += Vector2(0.0f, 1.0f);
+  TestEndPan( application, pos, time );
+  time += Wait( application );
+
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRemoveScrollingDirectionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRemoveScrollingDirectionP");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  Vector2 START_POSITION = Vector2(10.0f, 10.0f);
+  uint32_t time = 0;
+
+  scrollView.SetScrollingDirection(Dali::PanGestureDetector::DIRECTION_VERTICAL);
+
+  scrollView.ScrollTo(START_POSITION, 0.0f);
+
+  time += Wait(application);
+
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), START_POSITION, TEST_LOCATION );
+
+  // Try a vertical swipe.
+  // PerformGestureSwipe not used as a different initial direction was required
+  Vector2 pos( START_POSITION + Vector2(0.0f, 15.0f) );
+  TestStartPan( application, START_POSITION, pos, time );
+  time += Wait(application);
+  for( int i = 0; i<45; i++ )
+  {
+    pos += Vector2(0.0f, 1.0f);
+    TestMovePan( application, pos, time );
+    time += Wait( application );
+  }
+  pos += Vector2(0.0f, 1.0f);
+  TestEndPan( application, pos, time );
+  time += Wait( application );
+
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  scrollView.RemoveScrollingDirection(Dali::PanGestureDetector::DIRECTION_VERTICAL);
+  // When the horizontal direction is removed, there are no directions set and therefore all will work
+  scrollView.SetScrollingDirection(Dali::PanGestureDetector::DIRECTION_HORIZONTAL);
+
+  time += Wait(application);
+  // Try a vertical swipe.
+  Vector2 pos2( pos + Vector2(0.0f, 15.0f) );
+  TestStartPan( application, pos, pos2, time );
+  time += Wait(application);
+  for( int i = 0; i<45; i++ )
+  {
+    pos2 += Vector2(0.0f, 1.0f);
+    TestMovePan( application, pos2, time );
+    time += Wait( application );
+  }
+  pos2 += Vector2(0.0f, 1.0f);
+  TestEndPan( application, pos2, time );
+
+  // The previous scroll should not have had any effect
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition() - Vector2(0.0f, 0.5f), Vector2(10.0f, -50.0f), 0.25f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetRulerXP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetRulerXP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = new FixedRuler( 100.0f );
+  rulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+
+  scrollView.SetRulerX( rulerX );
+
+  scrollView.ScrollTo( 1, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(100.0f, 0.0f), TEST_LOCATION );
+
+  RulerPtr newRulerX = new FixedRuler( 200.0f );
+  newRulerX->SetDomain( RulerDomain(0.0f, 800.0f, true) );
+
+  scrollView.SetRulerX( newRulerX );
+
+  scrollView.ScrollTo( 1, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(200.0f, 0.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetRulerYP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetRulerYP");
+
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+
+  RulerPtr rulerY = new FixedRuler( 200.0f );
+  rulerY->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.ScrollTo( Vector2(0.0f, 350.0f), 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 350.0f), TEST_LOCATION );
+
+  RulerPtr newRulerY = new FixedRuler( 100.0f );
+  newRulerY->SetDomain( RulerDomain(0.0f, 200.0f, true) );
+  scrollView.SetRulerY( newRulerY );
+
+  scrollView.ScrollTo( Vector2(0.0f, 350.0f), 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), Vector2(0.0f, 200.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetMinimumSpeedForFlickP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetMinimumSpeedForFlickP");
+
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetMinimumSpeedForFlick(25.0f);
+  DALI_TEST_EQUALS( scrollView.GetMinimumSpeedForFlick(), 25.0f, TEST_LOCATION );
+  scrollView.SetMinimumSpeedForFlick(60.0f);
+  DALI_TEST_EQUALS( scrollView.GetMinimumSpeedForFlick(), 60.0f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetMinimumDistanceForFlickP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetMinimumDistanceForFlick");
+
+  ScrollView scrollView = ScrollView::New();
+
+  scrollView.SetMinimumDistanceForFlick(Vector2(30.0f, 15.0f));
+  DALI_TEST_EQUALS( scrollView.GetMinimumDistanceForFlick(), Vector2(30.0f, 15.0f), TEST_LOCATION );
+  scrollView.SetMinimumDistanceForFlick(Vector2(60.0f, 30.0f));
+  DALI_TEST_EQUALS( scrollView.GetMinimumDistanceForFlick(), Vector2(60.0f, 30.0f), TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetWheelScrollDistanceStepP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetWheelScrollDistanceStepP");
+
+  ScrollView scrollView = ScrollView::New();
+  // Disable Refresh signal (TET environment cannot use adaptor's Timer)
+  scrollView.SetWheelScrollDistanceStep(Vector2(30.0f, 15.0f));
+  DALI_TEST_EQUALS( scrollView.GetWheelScrollDistanceStep(), Vector2(30.0f, 15.0f), TEST_LOCATION );
+  scrollView.SetWheelScrollDistanceStep(Vector2(60.0f, 30.0f));
+  DALI_TEST_EQUALS( scrollView.GetWheelScrollDistanceStep(), Vector2(60.0f, 30.0f), TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewApplyEffectP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewApplyEffectP");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Create two scroll view effects
+  Dali::Path path = Dali::Path::New();
+  ScrollViewEffect effect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 0.0f, 0.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(100.0f, 100.0f, 0.0f), 2);
+  ScrollViewEffect newEffect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 1.0f, 1.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(200.0f, 150.0f, 0.0f), 5);
+
+  // Apply both effects
+  scrollView.ApplyEffect(effect);
+  scrollView.ApplyEffect(newEffect);
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewApplyEffectN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewApplyEffectN");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Create two scroll view effects
+  Dali::Path path = Dali::Path::New();
+  ScrollViewEffect effect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 0.0f, 0.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(100.0f, 100.0f, 0.0f), 2);
+  ScrollViewEffect newEffect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 1.0f, 1.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(200.0f, 150.0f, 0.0f), 5);
+
+  // Apply both effects
+  scrollView.ApplyEffect(effect);
+  scrollView.ApplyEffect(newEffect);
+
+  // Attempt to apply the same effect again
+  try
+  {
+    scrollView.ApplyEffect(newEffect);
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "!effectAlreadyExistsInScrollView", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRemoveEffectP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRemoveEffectP");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Create two scroll view effects
+  Dali::Path path = Dali::Path::New();
+  ScrollViewEffect effect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 0.0f, 0.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(100.0f, 100.0f, 0.0f), 2);
+  ScrollViewEffect newEffect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 1.0f, 1.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(200.0f, 150.0f, 0.0f), 5);
+
+  // Apply both effects
+  scrollView.ApplyEffect(effect);
+  scrollView.ApplyEffect(newEffect);
+
+  // Remove both effects
+  scrollView.RemoveEffect(effect);
+  scrollView.RemoveEffect(newEffect);
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRemoveEffectN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRemoveEffectN");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Create two scroll view effects
+  Dali::Path path = Dali::Path::New();
+  ScrollViewEffect effect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 0.0f, 0.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(100.0f, 100.0f, 0.0f), 2);
+  ScrollViewEffect newEffect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 1.0f, 1.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(200.0f, 150.0f, 0.0f), 5);
+
+  // Apply the first effect
+  scrollView.ApplyEffect(effect);
+
+  // Attempt to remove the second effect which has not been applied to scroll view
+  try
+  {
+    scrollView.RemoveEffect(newEffect);
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "effectExistedInScrollView", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRemoveAllEffectsP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRemoveAllEffectsP");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Create two scroll view effects
+  Dali::Path path = Dali::Path::New();
+  ScrollViewEffect effect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 0.0f, 0.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(100.0f, 100.0f, 0.0f), 2);
+  ScrollViewEffect newEffect = ScrollViewPagePathEffect::New(path, Vector3(-1.0f, 1.0f, 1.0f), Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3(200.0f, 150.0f, 0.0f), 5);
+
+  // Apply both effects
+  scrollView.ApplyEffect(effect);
+  scrollView.ApplyEffect(newEffect);
+
+  // Attempt to apply the same first effect again
+  try
+  {
+    scrollView.ApplyEffect(effect);
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "!effectAlreadyExistsInScrollView", TEST_LOCATION );
+  }
+
+  // Remove both effects
+  scrollView.RemoveAllEffects();
+
+  // Apply both effects again
+  scrollView.ApplyEffect(effect);
+  scrollView.ApplyEffect(newEffect);
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRemoveAllEffectsN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRemoveAllEffectsN");
+
+  // Create a ScrollView
+  ScrollView scrollView = ScrollView::New();
+
+  // Remove effects when there is no effect applied previously
+  scrollView.RemoveAllEffects();
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetOvershootEnabledP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetOvershootEnabledP");
+
+  ScrollView scrollView = ScrollView::New();
+
+  scrollView.SetOvershootEnabled(true);
+  DALI_TEST_CHECK(scrollView.IsOvershootEnabled());
+
+  scrollView.SetOvershootEnabled(false);
+  DALI_TEST_CHECK(!scrollView.IsOvershootEnabled());
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetOvershootEffectColorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetOvershootEffectColorP");
+
+  ScrollView scrollView = ScrollView::New();
+
+  scrollView.SetOvershootEffectColor(Dali::Color::RED);
+  DALI_TEST_EQUALS(scrollView.GetOvershootEffectColor(), Dali::Color::RED, TEST_LOCATION);
+
+  scrollView.SetOvershootEffectColor(Dali::Color::YELLOW);
+  DALI_TEST_EQUALS(scrollView.GetOvershootEffectColor(), Dali::Color::YELLOW, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewSetOvershootAnimationSpeedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewSetOvershootAnimationSpeedP");
+
+  ScrollView scrollView = ScrollView::New();
+
+  scrollView.SetOvershootAnimationSpeed(55.0f);
+  DALI_TEST_EQUALS(scrollView.GetOvershootAnimationSpeed(), 55.0f, TEST_LOCATION);
+
+  scrollView.SetOvershootAnimationSpeed(120.0f);
+  DALI_TEST_EQUALS(scrollView.GetOvershootAnimationSpeed(), 120.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewGetSet(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewGetSet");
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetMaxFlickSpeed(0.5f);
+  DALI_TEST_EQUALS(scrollView.GetMaxFlickSpeed(), 0.5f, Math::MACHINE_EPSILON_0, TEST_LOCATION);
+  scrollView.SetFrictionCoefficient(0.6f);
+  DALI_TEST_EQUALS(scrollView.GetFrictionCoefficient(), 0.6f, Math::MACHINE_EPSILON_0, TEST_LOCATION);
+  scrollView.SetFlickSpeedCoefficient(0.7f);
+  DALI_TEST_EQUALS(scrollView.GetFlickSpeedCoefficient(), 0.7f, Math::MACHINE_EPSILON_0, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerDomainConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  RulerDomain domainX = RulerDomain(0.0f, 200.0f, true);
+  DALI_TEST_EQUALS( domainX.min, 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( domainX.max, 200.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( domainX.enabled, true, TEST_LOCATION);
+
+  RulerDomain domainY = RulerDomain(100.0f, 500.0f, false);
+  DALI_TEST_EQUALS( domainY.min, 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( domainY.max, 500.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( domainY.enabled, false, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerDomainGetSizeP(void)
+{
+  ToolkitTestApplication application;
+
+  RulerDomain domainX = RulerDomain(0.0f, 200.0f, true);
+  DALI_TEST_EQUALS( domainX.GetSize(), 200.0f, TEST_LOCATION);
+
+  RulerDomain domainY = RulerDomain(100.0f, 500.0f, false);
+  DALI_TEST_EQUALS( domainY.GetSize(), 400.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerDomainClampP(void)
+{
+  ToolkitTestApplication application;
+
+  RulerDomain domainX = RulerDomain(0.0f, 200.0f, true);
+
+  float value = domainX.Clamp(50.0f, 100.0f, 1.0f);
+  DALI_TEST_EQUALS( value, 50.0f, TEST_LOCATION);
+
+  value = domainX.Clamp(300.0f, 20.0f, 1.0f);
+  DALI_TEST_EQUALS( value, 180.0f, TEST_LOCATION);
+
+  value = domainX.Clamp(300.0f, 20.0f, 0.5f);
+  DALI_TEST_EQUALS( value, 80.0f, TEST_LOCATION);
+
+  value = domainX.Clamp(250.0f, 200.0f, 2.0f);
+  DALI_TEST_EQUALS( value, 200.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerDomainClampWithStateP(void)
+{
+  ToolkitTestApplication application;
+
+  RulerDomain domainX = RulerDomain(0.0f, 200.0f, true);
+
+  ClampState clamped;
+  float value = domainX.Clamp(50.0f, 100.0f, 1.0f, clamped);
+  DALI_TEST_EQUALS( value, 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, Dali::Toolkit::NotClamped, TEST_LOCATION);
+
+  value = domainX.Clamp(-100.0f, 200.0f, 1.0f, clamped);
+  DALI_TEST_EQUALS( value, 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, Dali::Toolkit::ClampedToMin, TEST_LOCATION);
+
+  value = domainX.Clamp(300.0f, 20.0f, 1.0f, clamped);
+  DALI_TEST_EQUALS( value, 180.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, Dali::Toolkit::ClampedToMax, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerConstructorP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerDestructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerDestructorP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerConstructorP");
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  DALI_TEST_CHECK( fixedRuler );
+
+  fixedRuler = new FixedRuler( 0.0f );
+  DALI_TEST_CHECK( fixedRuler );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerDestructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerDestructorP");
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerGetTypeP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRulerGetTypeP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+  DALI_TEST_EQUALS( defaultRuler->GetType(), Dali::Toolkit::Ruler::Free, TEST_LOCATION);
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  DALI_TEST_CHECK( fixedRuler );
+  DALI_TEST_EQUALS( fixedRuler->GetType(), Dali::Toolkit::Ruler::Fixed, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerGetExtensionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRulerGetExtensionP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+  DALI_TEST_CHECK( !defaultRuler->GetExtension() );
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  DALI_TEST_CHECK( fixedRuler );
+  DALI_TEST_CHECK( !fixedRuler->GetExtension() );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerEnableDisable(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRulerEnableDisable");
+
+  RulerPtr ruler = new DefaultRuler();
+
+  DALI_TEST_CHECK( ruler->IsEnabled() );
+  ruler->Disable();
+  DALI_TEST_CHECK( !ruler->IsEnabled() );
+  ruler->Enable();
+  DALI_TEST_CHECK( ruler->IsEnabled() );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerDomainEnableDisable(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRulerDomainEnableDisable");
+
+  RulerPtr ruler = new DefaultRuler();
+  DALI_TEST_EQUALS( ruler->GetDomain().GetSize(), 1.0f, TEST_LOCATION );
+
+  ruler->SetDomain( RulerDomain(0.0f, 100.0f, true) );
+  DALI_TEST_EQUALS( ruler->GetDomain().GetSize(), 100.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->Clamp(-200.0f), 0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->Clamp(200.0f), 100.0f, TEST_LOCATION );
+
+  ruler->DisableDomain();
+  DALI_TEST_EQUALS( ruler->GetDomain().GetSize(), 1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->Clamp(-200.0f), -200.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->Clamp(200.0f), 200.0f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewRulerSnapAndClamp(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewRulerSnapAndClamp");
+
+  RulerPtr ruler = new FixedRuler( 50.0f );
+  ruler->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  // default testing. (snap and clamp)
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(50.0f), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(30.0f), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(10.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(-40.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(390.0f), 400.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(430.0f), 400.0f, TEST_LOCATION);
+
+  // bias testing.
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(40.0f, 0.0f), 0.0f, TEST_LOCATION); // Flick Left
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(40.0f, 0.5f), 50.0f, TEST_LOCATION); // No Flick
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(40.0f, 1.0f), 50.0f, TEST_LOCATION); // Flick Right
+
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(20.0f, 0.0f), 0.0f, TEST_LOCATION); // Flick Left
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(20.0f, 0.5f), 0.0f, TEST_LOCATION); // No Flick
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(20.0f, 1.0f), 50.0f, TEST_LOCATION); // Flick Right
+
+  // length testing.
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(-10.0f, 0.5f, 10.0f), 0.0f, TEST_LOCATION); // 10 units long (over left boundary)
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(-5.0f, 0.5f, 10.0f), 0.0f, TEST_LOCATION); // 10 units long (slightly ovr left boundary)
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(300.0f, 0.5f, 10.0f), 300.0f, TEST_LOCATION); // 10 units long (not over a boundary)
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(395.0f, 0.5f, 10.0f), 390.0f, TEST_LOCATION); // 10 units long (slightly over right boundary)
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(500.0f, 0.5f, 10.0f), 390.0f, TEST_LOCATION); // 10 units long (over right boundary)
+
+  // scale testing.
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(-100.0f, 0.5f, 0.0f, 2.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(50.0f, 0.5f, 0.0f, 2.0f), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(700.0f, 0.5f, 0.0f, 2.0f), 700.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(850.0f, 0.5f, 0.0f, 2.0f), 800.0f, TEST_LOCATION);
+
+  // clamp state testing.
+  ClampState clamped;
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(50.0f, 0.5f, 0.0f, 1.0f, clamped), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, NotClamped, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(30.0f, 0.5f, 0.0f, 1.0f, clamped), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, NotClamped, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(10.0f, 0.5f, 0.0f, 1.0f, clamped), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, NotClamped, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(-40.0f, 0.5f, 0.0f, 1.0f, clamped), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, ClampedToMin, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(390.0f, 0.5f, 0.0f, 1.0f, clamped), 400.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, NotClamped, TEST_LOCATION );
+  DALI_TEST_EQUALS( ruler->SnapAndClamp(430.0f, 0.5f, 0.0f, 1.0f, clamped), 400.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( clamped, ClampedToMax, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerGetPositionFromPageP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerGetPositionFromPageP");
+
+  RulerPtr rulerNormal = new FixedRuler( 25.0f );
+  rulerNormal->SetDomain( RulerDomain(10.0f, 90.0f, true) );
+
+  unsigned int volume;
+  float position;
+
+  position = rulerNormal->GetPositionFromPage(1, volume, true);
+  DALI_TEST_EQUALS( position, 35.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( volume, 0u, TEST_LOCATION );
+
+  position = rulerNormal->GetPositionFromPage(2, volume, true);
+  DALI_TEST_EQUALS( position, 60.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( volume, 0u, TEST_LOCATION );
+
+  // Disable the ruler
+  rulerNormal->Disable();
+
+  position = rulerNormal->GetPositionFromPage(1, volume, true);
+  DALI_TEST_EQUALS( position, 10.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( volume, 1u, TEST_LOCATION );
+
+  position = rulerNormal->GetPositionFromPage(2, volume, true);
+  DALI_TEST_EQUALS( position, 10.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( volume, 2u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerGetTotalPagesP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerGetTotalPagesP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+  DALI_TEST_EQUALS( defaultRuler->GetTotalPages(), 1u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerGetPageFromPositionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerGetPageFromPositionP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+  DALI_TEST_EQUALS( defaultRuler->GetPageFromPosition(100.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( defaultRuler->GetPageFromPosition(-300.0f, false), 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerGetPositionFromPageP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerGetPositionFromPageP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+
+  unsigned int volume;
+  DALI_TEST_EQUALS( defaultRuler->GetPositionFromPage(0, volume, true), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( volume, 0u, TEST_LOCATION);
+
+  DALI_TEST_EQUALS( defaultRuler->GetPositionFromPage(3, volume, false), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( volume, 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewDefaultRulerSnapP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewDefaultRulerSnapP");
+
+  RulerPtr defaultRuler = new DefaultRuler();
+  DALI_TEST_CHECK( defaultRuler );
+
+  DALI_TEST_EQUALS( defaultRuler->Snap(50.0f, 0.5f), 50.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( defaultRuler->Snap(-120.0f, 1.0f), -120.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerGetTotalPagesP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerGetTotalPagesP");
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  fixedRuler->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  fixedRuler->Enable();
+  DALI_TEST_EQUALS( fixedRuler->GetTotalPages(), 4u, TEST_LOCATION);
+
+  fixedRuler->Disable();
+  DALI_TEST_EQUALS( fixedRuler->GetTotalPages(), 1u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerGetPageFromPositionP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerGetPageFromPositionP");
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  fixedRuler->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  fixedRuler->Enable();
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, true), 3u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, false), 3u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, true), 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, false), 0u, TEST_LOCATION);
+
+  fixedRuler->Disable();
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, false), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, false), 0u, TEST_LOCATION);
+
+  // Set domain size to be smaller than the ruler space
+  fixedRuler->SetDomain( RulerDomain(0.0f, 50.0f, true) );
+
+  fixedRuler->Enable();
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, false), 3u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, false), 0u, TEST_LOCATION);
+
+  fixedRuler->Disable();
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(250.0f, false), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, true), 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->GetPageFromPosition(-350.0f, false), 0u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewFixedRulerSnapP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewFixedRulerSnapP");
+
+  RulerPtr fixedRuler = new FixedRuler( 100.0f );
+  fixedRuler->SetDomain( RulerDomain(0.0f, 400.0f, true) );
+
+  DALI_TEST_EQUALS( fixedRuler->Snap(-30.0f, 0.0f), -100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-70.0f, 0.0f), -100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-120.0f, 0.0f), -200.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-480.0f, 0.0f), -500.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(20.0f, 0.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(50.0f, 0.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(80.0f, 0.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(100.0f, 0.0f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(120.0f, 0.0f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(250.0f, 0.0f), 200.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(620.0f, 0.0f), 600.0f, TEST_LOCATION);
+
+  DALI_TEST_EQUALS( fixedRuler->Snap(-30.0f, 0.5f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-70.0f, 0.5f), -100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-120.0f, 0.5f), -100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-480.0f, 0.5f), -500.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(20.0f, 0.5f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(50.0f, 0.5f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(80.0f, 0.5f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(100.0f, 0.5f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(120.0f, 0.5f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(250.0f, 0.5f), 300.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(620.0f, 0.5f), 600.0f, TEST_LOCATION);
+
+  DALI_TEST_EQUALS( fixedRuler->Snap(-30.0f, 1.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-70.0f, 1.0f), 0.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-120.0f, 1.0f), -100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(-480.0f, 1.0f), -400.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(20.0f, 1.0f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(50.0f, 1.0f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(80.0f, 1.0f), 100.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(100.0f, 1.0f), 200.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(120.0f, 1.0f), 200.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(250.0f, 1.0f), 300.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS( fixedRuler->Snap(620.0f, 1.0f), 700.0f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewConstraintsMove(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewConstraintsMove");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  // Add an Actor to ScrollView,
+  Actor a = Actor::New();
+  scrollView.Add(a);
+  a.SetPosition( TEST_ACTOR_POSITION );
+  Wait(application);
+
+  const Vector2 target = Vector2(100.0f, 100.0f);
+  const Vector2 target2 = Vector2(200.0f, 200.0f);
+
+  Constraint constraint = Constraint::New<Vector3>( scrollView, Actor::Property::POSITION, MoveActorConstraint );
+  constraint.AddSource( Source(scrollView, ScrollView::Property::SCROLL_POSITION) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  scrollView.ApplyConstraintToChildren(constraint);
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+  scrollView.ScrollTo( target2 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitScrollViewConstraintsWrap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitScrollViewConstraintsWrap");
+
+  // Set up a scrollView...
+  ScrollView scrollView = ScrollView::New();
+  Stage::GetCurrent().Add( scrollView );
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  scrollView.SetSize(stageSize);
+  scrollView.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  scrollView.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+
+  // Position rulers.
+  RulerPtr rulerX = new DefaultRuler();
+  RulerPtr rulerY = new DefaultRuler();
+  rulerX->SetDomain( RulerDomain(0.0f, stageSize.width + CLAMP_EXCESS_WIDTH, true) );
+  rulerY->SetDomain( RulerDomain(0.0f, stageSize.height + CLAMP_EXCESS_HEIGHT, true) );
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+
+  // Add an Actor to ScrollView,
+  Actor a = Actor::New();
+  scrollView.Add(a);
+  a.SetPosition( TEST_ACTOR_POSITION );
+  Wait(application);
+
+  const Vector2 target = Vector2(100.0f, 100.0f);
+  const Vector2 target2 = Vector2(200.0f, 200.0f);
+
+  Constraint constraint = Constraint::New<Vector3>( scrollView, Actor::Property::POSITION, WrapActorConstraint );
+  constraint.AddSource( LocalSource( Actor::Property::SCALE ) );
+  constraint.AddSource( LocalSource( Actor::Property::ANCHOR_POINT ) );
+  constraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+  constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
+  constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  constraint.AddSource( Source( scrollView, Toolkit::ScrollView::Property::WRAP ) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  scrollView.ApplyConstraintToChildren(constraint);
+
+  scrollView.ScrollTo( target, 0.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target, TEST_LOCATION );
+  scrollView.ScrollTo( target2 );
+  Wait(application, RENDER_DELAY_SCROLL);
+  DALI_TEST_EQUALS( scrollView.GetCurrentScrollPosition(), target2, TEST_LOCATION );
+
+  scrollView.Remove(a);
+  Wait(application);
+
+  END_TEST;
+}
+
+// Non-API test (so no P or N variant).
+int UtcDaliToolkitScrollViewGesturePageLimit(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( " UtcDaliToolkitScrollViewGesturePageLimit" );
+
+  // Set up a scrollView.
+  ScrollView scrollView = ScrollView::New();
+
+  // Do not rely on stage size for UTC tests.
+  Vector2 viewPageSize( 720.0f, 1280.0f );
+  scrollView.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  scrollView.SetSize( viewPageSize );
+  scrollView.SetParentOrigin( ParentOrigin::CENTER );
+  scrollView.SetAnchorPoint( AnchorPoint::CENTER );
+  scrollView.SetPosition( 0.0f, 0.0f, 0.0f );
+
+  // Position rulers.
+  // We set the X ruler to fixed to give us pages to snap to.
+  Dali::Toolkit::FixedRuler* rulerX = new Dali::Toolkit::FixedRuler( viewPageSize.width );
+  // Note: The 3x page width is arbitary, but we need enough to show that we are
+  // capping page movement by the page limiter, and not the domain.
+  rulerX->SetDomain( Dali::Toolkit::RulerDomain( 0.0f, viewPageSize.width * 3.0f, false ) );
+  Dali::Toolkit::RulerPtr rulerY = new Dali::Toolkit::DefaultRuler();
+  rulerY->Disable();
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+
+  scrollView.SetWrapMode( false );
+  scrollView.SetScrollSensitive( true );
+
+  Stage::GetCurrent().Add( scrollView );
+
+  // Set up a gesture to perform.
+  Vector2 startPos( 50.0f, 0.0f );
+  Vector2 direction( -5.0f, 0.0f );
+  int frames = 200;
+
+  // Force starting position.
+  scrollView.ScrollTo( startPos, 0.0f );
+  uint32_t time = 0;
+  time += Wait( application );
+
+  // Deliberately skip the "Finished" part of the gesture, so we can read the coordinates before the snap begins.
+  Vector2 currentPos( PerformGestureSwipe( application, startPos, direction, frames - 1, time, false ) );
+
+  // Confirm the final X coord has not moved more than one page from the start X position.
+  DALI_TEST_GREATER( ( startPos.x + viewPageSize.width ), scrollView.GetCurrentScrollPosition().x, TEST_LOCATION );
+
+  // Finish the gesture and wait for the snap.
+  currentPos += direction;
+  TestEndPan(application, currentPos, time);
+  // We add RENDER_FRAME_INTERVAL on to wait for an extra frame (for the last "finished" gesture to complete first.
+  time += Wait( application, RENDER_DELAY_SCROLL + RENDER_FRAME_INTERVAL );
+
+  // Confirm the final X coord has snapped to exactly one page ahead of the start page.
+  DALI_TEST_EQUALS( viewPageSize.width, scrollView.GetCurrentScrollPosition().x, Math::MACHINE_EPSILON_0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliScrollViewSetGetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  // Create the ScrollView actor
+  ScrollView scrollView = ScrollView::New();
+  DALI_TEST_CHECK(scrollView);
+
+  // Event side properties
+
+  // Test "wrapEnabled" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("wrapEnabled") == ScrollView::Property::WRAP_ENABLED );
+  scrollView.SetProperty( ScrollView::Property::WRAP_ENABLED, true );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::WRAP_ENABLED).Get<bool>(), true, TEST_LOCATION );
+
+  // Test "panningEnabled" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("panningEnabled") == ScrollView::Property::PANNING_ENABLED );
+  scrollView.SetProperty( ScrollView::Property::PANNING_ENABLED, false );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::PANNING_ENABLED).Get<bool>(), false, TEST_LOCATION );
+
+  // Test "axisAutoLockEnabled" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("axisAutoLockEnabled") == ScrollView::Property::AXIS_AUTO_LOCK_ENABLED );
+  scrollView.SetProperty( ScrollView::Property::AXIS_AUTO_LOCK_ENABLED, false );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::AXIS_AUTO_LOCK_ENABLED).Get<bool>(), false, TEST_LOCATION );
+
+  // Test "wheelScrollDistanceStep" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("wheelScrollDistanceStep") == ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP );
+  scrollView.SetProperty( ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP, Vector2(100.0f, 50.0f) );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP).Get<Vector2>(), Vector2(100.0f, 50.0f), TEST_LOCATION );
+
+  // Test "overshootEnabled" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("overshootEnabled") == Scrollable::Property::OVERSHOOT_ENABLED  );
+  DALI_TEST_EQUALS( scrollView.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), scrollView.IsOvershootEnabled(), TEST_LOCATION );
+  scrollView.SetProperty( Scrollable::Property::OVERSHOOT_ENABLED, false );
+  DALI_TEST_EQUALS( scrollView.GetProperty(Scrollable::Property::OVERSHOOT_ENABLED).Get<bool>(), false, TEST_LOCATION );
+
+  // Animatable properties
+
+  // Test "scrollPosition" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPosition") == ScrollView::Property::SCROLL_POSITION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_POSITION, Vector2(320.0f, 550.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_POSITION).Get<Vector2>(), Vector2(320.0f, 550.0f), TEST_LOCATION );
+
+  // Test "scrollPrePosition", "scrollPrePositionX" and "scrollPrePositionY" properties
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePosition") == ScrollView::Property::SCROLL_PRE_POSITION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION, Vector2(300.0f, 500.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION).Get<Vector2>(), Vector2(300.0f, 500.0f), TEST_LOCATION );
+
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePositionX") == ScrollView::Property::SCROLL_PRE_POSITION_X );
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePositionY") == ScrollView::Property::SCROLL_PRE_POSITION_Y );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_X).Get<float>(), 300.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_Y).Get<float>(), 500.0f, TEST_LOCATION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION_X, 400.0f );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION_Y, 600.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_X).Get<float>(), 400.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_Y).Get<float>(), 600.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION).Get<Vector2>(), Vector2(400.0f, 600.0f), TEST_LOCATION );
+
+  // Test "scrollPrePositionMax", "scrollPrePositionMaxX" and "scrollPrePositionMaxY" properties
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePositionMax") == ScrollView::Property::SCROLL_PRE_POSITION_MAX );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION_MAX, Vector2(100.0f, 200.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX).Get<Vector2>(), Vector2(100.0f, 200.0f), TEST_LOCATION );
+
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePositionMaxX") == ScrollView::Property::SCROLL_PRE_POSITION_MAX_X );
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPrePositionMaxY") == ScrollView::Property::SCROLL_PRE_POSITION_MAX_Y );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX_X).Get<float>(), 100.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX_Y).Get<float>(), 200.0f, TEST_LOCATION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION_MAX_X, 300.0f );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_PRE_POSITION_MAX_Y, 400.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX_X).Get<float>(), 300.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX_Y).Get<float>(), 400.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_PRE_POSITION_MAX).Get<Vector2>(), Vector2(300.0f, 400.0f), TEST_LOCATION );
+
+  // Test "overshootX" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("overshootX") == ScrollView::Property::OVERSHOOT_X );
+  scrollView.SetProperty( ScrollView::Property::OVERSHOOT_X, 0.8f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::OVERSHOOT_X).Get<float>(), 0.8f, TEST_LOCATION );
+
+  // Test "overshootY" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("overshootY") == ScrollView::Property::OVERSHOOT_Y );
+  scrollView.SetProperty( ScrollView::Property::OVERSHOOT_Y, 0.8f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::OVERSHOOT_Y).Get<float>(), 0.8f, TEST_LOCATION );
+
+  // Test "scrollFinal", "scrollFinalX" and "scrollFinalY" properties
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollFinal") == ScrollView::Property::SCROLL_FINAL );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_FINAL, Vector2(200.0f, 300.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL).Get<Vector2>(), Vector2(200.0f, 300.0f), TEST_LOCATION );
+
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollFinalX") == ScrollView::Property::SCROLL_FINAL_X );
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollFinalY") == ScrollView::Property::SCROLL_FINAL_Y );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL_X).Get<float>(), 200.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL_Y).Get<float>(), 300.0f, TEST_LOCATION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_FINAL_X, 500.0f );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_FINAL_Y, 600.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL_X).Get<float>(), 500.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL_Y).Get<float>(), 600.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_FINAL).Get<Vector2>(), Vector2(500.0f, 600.0f), TEST_LOCATION );
+
+  // Test "wrap" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("wrap") == ScrollView::Property::WRAP );
+  scrollView.SetProperty( ScrollView::Property::WRAP, false );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::WRAP).Get<bool>(), false, TEST_LOCATION );
+
+  // Test "panning" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("panning") == ScrollView::Property::PANNING );
+  scrollView.SetProperty( ScrollView::Property::PANNING, true );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::PANNING).Get<bool>(), true, TEST_LOCATION );
+
+  // Test "scrolling" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrolling") == ScrollView::Property::SCROLLING );
+  scrollView.SetProperty( ScrollView::Property::SCROLLING, false );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLLING).Get<bool>(), false, TEST_LOCATION );
+
+  // Test "scrollDomainSize", "scrollDomainSizeX" and "scrollDomainSizeY" properties
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollDomainSize") == ScrollView::Property::SCROLL_DOMAIN_SIZE );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_DOMAIN_SIZE, Vector2(1200.0f, 1300.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE).Get<Vector2>(), Vector2(1200.0f, 1300.0f), TEST_LOCATION );
+
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollDomainSizeX") == ScrollView::Property::SCROLL_DOMAIN_SIZE_X );
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollDomainSizeY") == ScrollView::Property::SCROLL_DOMAIN_SIZE_Y );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE_X).Get<float>(), 1200.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE_Y).Get<float>(), 1300.0f, TEST_LOCATION );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_DOMAIN_SIZE_X, 1500.0f );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_DOMAIN_SIZE_Y, 1600.0f );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE_X).Get<float>(), 1500.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE_Y).Get<float>(), 1600.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_SIZE).Get<Vector2>(), Vector2(1500.0f, 1600.0f), TEST_LOCATION );
+
+  // Test "scrollDomainOffset" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollDomainOffset") == ScrollView::Property::SCROLL_DOMAIN_OFFSET );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_DOMAIN_OFFSET, Vector2(500.0f, 200.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_DOMAIN_OFFSET).Get<Vector2>(), Vector2(500.0f, 200.0f), TEST_LOCATION );
+
+  // Test "scrollPositionDelta" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("scrollPositionDelta") == ScrollView::Property::SCROLL_POSITION_DELTA );
+  scrollView.SetProperty( ScrollView::Property::SCROLL_POSITION_DELTA, Vector2(10.0f, 30.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::SCROLL_POSITION_DELTA).Get<Vector2>(), Vector2(10.0f, 30.0f), TEST_LOCATION );
+
+  // Test "startPagePosition" property
+  DALI_TEST_CHECK( scrollView.GetPropertyIndex("startPagePosition") == ScrollView::Property::START_PAGE_POSITION );
+  scrollView.SetProperty( ScrollView::Property::START_PAGE_POSITION, Vector3(50.0f, 100.0f, 20.0f) );
+  Wait(application);
+  DALI_TEST_EQUALS( scrollView.GetProperty(ScrollView::Property::START_PAGE_POSITION).Get<Vector3>(), Vector3(50.0f, 100.0f, 20.0f), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ScrollViewEffect.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ScrollViewEffect.cpp
new file mode 100644 (file)
index 0000000..f15a256
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2019 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void utc_dali_toolkit_scroll_view_effect_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_scroll_view_effect_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const int RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+/**
+ * Creates a Ruler that snaps to a specified grid size.
+ * If that grid size is 0.0 then this ruler does not
+ * snap.
+ *
+ * @param[in] gridSize (optional) The grid size for the ruler,
+ * (Default = 0.0 i.e. no snapping)
+ * @return The ruler is returned.
+ */
+RulerPtr CreateRuler(float gridSize = 0.0f)
+{
+  if(gridSize <= Math::MACHINE_EPSILON_0)
+  {
+      return new DefaultRuler();
+  }
+  return new FixedRuler(gridSize);
+}
+
+// Callback probes.
+
+static bool gOnScrollStartCalled;                       ///< Whether the OnScrollStart signal was invoked.
+static bool gOnScrollUpdateCalled;                      ///< Whether the OnScrollUpdate signal was invoked.
+static bool gOnScrollCompleteCalled;                    ///< Whether the OnScrollComplete signal was invoked.
+static Vector3 gConstraintResult;                       ///< Result from constraint.
+
+static std::vector< Actor > gPages;                                ///< Keeps track of all the pages for applying effects.
+typedef std::vector< Actor >::iterator ActorIter;
+
+static void ResetScrollCallbackResults()
+{
+  gOnScrollStartCalled = false;
+  gOnScrollUpdateCalled = false;
+  gOnScrollCompleteCalled = false;
+}
+
+/**
+ * Invoked when scrolling starts.
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollStart( const Vector2& position )
+{
+  gOnScrollStartCalled = true;
+}
+
+/**
+ * Invoked when scrolling updates (via dragging)
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollUpdate( const Vector2& position )
+{
+  gOnScrollUpdateCalled = true;
+}
+
+/**
+ * Invoked when scrolling finishes
+ *
+ * @param[in] position The current scroll position.
+ */
+static void OnScrollComplete( const Vector2& position )
+{
+  gOnScrollCompleteCalled = true;
+}
+
+ScrollView SetupTestScrollView(int rows, int columns, Vector2 size)
+{
+  Constraint constraint;
+
+  ScrollView scrollView = ScrollView::New();
+  scrollView.SetSize(size);
+  scrollView.SetAnchorPoint(AnchorPoint::CENTER);
+  scrollView.SetParentOrigin(ParentOrigin::CENTER);
+
+  constraint = Constraint::New<Dali::Vector3>( scrollView, Dali::Actor::Property::SIZE, Dali::EqualToConstraint() );
+  constraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
+  constraint.Apply();
+
+  scrollView.SetWrapMode(false);
+  scrollView.ScrollStartedSignal().Connect( &OnScrollStart );
+  scrollView.ScrollUpdatedSignal().Connect( &OnScrollUpdate );
+  scrollView.ScrollCompletedSignal().Connect( &OnScrollComplete );
+  Stage::GetCurrent().Add( scrollView );
+  RulerPtr rulerX = CreateRuler(size.width);
+  RulerPtr rulerY = CreateRuler(size.height);
+  if(columns > 1)
+  {
+    rulerX->SetDomain(RulerDomain(0.0f, size.width * columns));
+  }
+  else
+  {
+    rulerX->Disable();
+  }
+  if(rows > 1)
+  {
+    rulerY->SetDomain(RulerDomain(0.0f, size.width * rows));
+  }
+  else
+  {
+    rulerY->Disable();
+  }
+
+  scrollView.SetRulerX( rulerX );
+  scrollView.SetRulerY( rulerY );
+  Stage::GetCurrent().Add( scrollView );
+
+  Actor container = Actor::New();
+  container.SetParentOrigin(ParentOrigin::CENTER);
+  container.SetAnchorPoint(AnchorPoint::CENTER);
+  container.SetSize( size );
+  scrollView.Add( container );
+
+  constraint = Constraint::New<Vector3>( container, Actor::Property::SIZE, EqualToConstraint() );
+  constraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
+  constraint.Apply();
+
+  gPages.clear();
+  for(int row = 0;row<rows;row++)
+  {
+    for(int column = 0;column<columns;column++)
+    {
+      Actor page = Actor::New();
+
+      constraint = Constraint::New<Vector3>( page, Actor::Property::SIZE, EqualToConstraint() );
+      constraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
+      constraint.Apply();
+      page.SetParentOrigin( ParentOrigin::CENTER );
+      page.SetAnchorPoint( AnchorPoint::CENTER );
+      page.SetPosition( column * size.x, row * size.y );
+      container.Add(page);
+
+      gPages.push_back(page);
+    }
+  }
+
+  ResetScrollCallbackResults();
+  return scrollView;
+}
+
+void CleanupTest()
+{
+  gPages.clear();
+  ResetScrollCallbackResults();
+}
+
+} // unnamed namespace
+
+int UtcDaliScrollViewPagePathEffectSetup(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScrollViewPagePathEffectSetup");
+
+  ScrollViewPagePathEffect effect;
+
+  DALI_TEST_CHECK( !effect );
+
+  BaseHandle handle = ScrollViewPagePathEffect::New(Dali::Path::New(), Vector3::ZERO,Toolkit::ScrollView::Property::SCROLL_FINAL_X, Vector3::ZERO,0);
+
+  DALI_TEST_CHECK( handle );
+
+  effect = ScrollViewPagePathEffect::DownCast(handle);
+
+  DALI_TEST_CHECK( effect );
+  END_TEST;
+}
+
+int UtcDaliScrollViewPagePathEffectTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliScrollViewPagePathEffectTest");
+
+  Vector2 size = Stage::GetCurrent().GetSize();
+
+  ScrollView scrollView = SetupTestScrollView(1, 3, size);
+  Actor testPage = gPages[2];
+  Wait(application, 500);
+
+  //Create path
+  float xHalfSize( size.x * 0.5f);
+
+  Dali::Path path = Dali::Path::New();
+  Dali::Property::Array points;
+  points.Resize(3);
+  points[0] = Vector3( xHalfSize, 0.0f,  -xHalfSize);
+  points[1] = Vector3( 0.0f, 0.0f, 0.0f );
+  points[2] = Vector3( -xHalfSize, 0.0f,  -xHalfSize);
+  path.SetProperty( Path::Property::POINTS, points );
+
+  Dali::Property::Array controlPoints;
+  controlPoints.Resize(4);
+  controlPoints[0] = Vector3( xHalfSize, 0.0f, 0.0f );
+  controlPoints[1] = Vector3( xHalfSize, 0.0f, 0.0f );
+  controlPoints[2] = Vector3(-xHalfSize, 0.0f, 0.0f );
+  controlPoints[3] = Vector3(-xHalfSize, 0.0f, 0.0f );
+  path.SetProperty( Path::Property::CONTROL_POINTS, controlPoints );
+
+  ScrollViewPagePathEffect effect = ScrollViewPagePathEffect::New(path,
+                                                                  Vector3::ZERO,
+                                                                  Toolkit::ScrollView::Property::SCROLL_FINAL_X,
+                                                                  Vector3(size.x,size.y,0.0f),
+                                                                  3);
+  scrollView.ApplyEffect(effect);
+
+  unsigned int pageCounter(0);
+  for(ActorIter pageIter = gPages.begin(); pageIter != gPages.end(); ++pageIter)
+  {
+    Actor page = *pageIter;
+    page.RemoveConstraints();
+    Constraint constraint = Constraint::New<Vector3>( page, Actor::Property::SIZE, EqualToConstraint() );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.Apply();
+    effect.ApplyToPage(page, pageCounter++);
+  }
+  Wait(application);
+
+  scrollView.ScrollTo(1);
+  while(!gOnScrollCompleteCalled)
+  {
+    Wait(application);
+  }
+
+  // test that the test page has reached centre of screen
+  Vector3 pagePos = testPage.GetCurrentPosition();
+  DALI_TEST_EQUALS(pagePos, Vector3::ZERO, Math::MACHINE_EPSILON_0, TEST_LOCATION);
+
+  CleanupTest();
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ShaderEffects.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ShaderEffects.cpp
new file mode 100644 (file)
index 0000000..336efb5
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2017 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-toolkit/devel-api/shader-effects/alpha-discard-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/dissolve-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/distance-field-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/image-region-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/motion-blur-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/motion-stretch-effect.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+int UtcDaliCreateAlphaDiscardEffect(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateAlphaDiscardEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( !vertexShaderValue );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( !gridXValue );
+
+  Property::Value* gridYValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_Y );
+  DALI_TEST_CHECK( !gridYValue );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( !hintsValue );
+
+  END_TEST;
+}
+
+int UtcDaliCreateDissolveEffect( bool highPrecision )
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateDissolveEffect( highPrecision );
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( gridXValue );
+
+  int gridX = 0;
+  DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+  DALI_TEST_CHECK( gridX > 1 );
+
+  Property::Value* gridYValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_Y );
+  DALI_TEST_CHECK( gridYValue );
+
+  int gridY = 0;
+  DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+  DALI_TEST_CHECK( gridY > 1 );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( hintsValue );
+
+  int hints;;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == Shader::Hint::OUTPUT_IS_TRANSPARENT );
+
+  Actor actor = Actor::New();
+  Toolkit::DissolveEffectSetCentralLine( actor, Vector2::ONE, Vector2::ONE, 0.0f );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uPercentage" ) != Property::INVALID_INDEX );
+
+  END_TEST;
+}
+
+int UtcDaliCreateDissolveEffectHighPrecision(void)
+{
+  return UtcDaliCreateDissolveEffect(true);
+}
+
+int UtcDaliCreateDissolveEffectMediumPrecision(void)
+{
+  return UtcDaliCreateDissolveEffect(false);
+}
+
+int UtcDaliCreateDissolveEffect(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateDistanceFieldEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( !vertexShaderValue );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( !gridXValue );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( hintsValue );
+
+  int hints;;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == Shader::Hint::OUTPUT_IS_TRANSPARENT );
+
+  END_TEST;
+}
+
+int UtcDaliCreateImageRegionEffect(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateImageRegionEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( !fragmentShaderValue );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( !gridXValue );
+
+  Property::Value* gridYValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_Y );
+  DALI_TEST_CHECK( !gridYValue );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( !hintsValue );
+
+  END_TEST;
+}
+
+int UtcDaliCreateMotionBlurEffect(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateMotionBlurEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( gridXValue );
+
+  int gridX = 0;
+  DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+  DALI_TEST_CHECK( gridX > 1 );
+
+  Property::Value* gridYValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_Y );
+  DALI_TEST_CHECK( gridYValue );
+
+  int gridY = 0;
+  DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+  DALI_TEST_CHECK( gridY > 1 );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( hintsValue );
+
+  int hints;;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == Shader::Hint::OUTPUT_IS_TRANSPARENT );
+
+  unsigned int sampleCount( 4 );
+  Actor actor = Actor::New();
+  Toolkit::SetMotionBlurProperties( actor, sampleCount );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uBlurTexCoordScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uGeometryStretchFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uSpeedScalingFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeStart" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeEnd" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uAlphaScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uNumSamples" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uModelLastFrame" ) != Property::INVALID_INDEX );
+
+  END_TEST;
+}
+
+int UtcDaliCreateMotionStretchEffect(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map effect = Toolkit::CreateMotionStretchEffect();
+  DALI_TEST_CHECK( !effect.Empty() );
+
+  Property::Value* customShaderValue = effect.Find( Toolkit::Visual::Property::SHADER );
+  DALI_TEST_CHECK( customShaderValue );
+
+  Property::Map customShader;
+  DALI_TEST_CHECK( customShaderValue->Get( customShader ) );
+
+  Property::Value* vertexShaderValue = customShader.Find( Visual::Shader::Property::VERTEX_SHADER );
+  DALI_TEST_CHECK( vertexShaderValue );
+
+  std::string vertexShader;
+  DALI_TEST_CHECK( vertexShaderValue->Get( vertexShader ) );
+  DALI_TEST_CHECK( !vertexShader.empty() );
+
+  Property::Value* fragmentShaderValue = customShader.Find( Visual::Shader::Property::FRAGMENT_SHADER );
+  DALI_TEST_CHECK( fragmentShaderValue );
+
+  std::string fragmentShader;
+  DALI_TEST_CHECK( fragmentShaderValue->Get( fragmentShader ) );
+  DALI_TEST_CHECK( !fragmentShader.empty() );
+
+  Property::Value* gridXValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_X );
+  DALI_TEST_CHECK( gridXValue );
+
+  int gridX = 0;
+  DALI_TEST_CHECK( gridXValue->Get( gridX ) );
+  DALI_TEST_CHECK( gridX > 1 );
+
+  Property::Value* gridYValue = customShader.Find( Visual::Shader::Property::SUBDIVIDE_GRID_Y );
+  DALI_TEST_CHECK( gridYValue );
+
+  int gridY = 0;
+  DALI_TEST_CHECK( gridYValue->Get( gridY ) );
+  DALI_TEST_CHECK( gridY > 1 );
+
+  Property::Value* hintsValue = customShader.Find( Visual::Shader::Property::HINTS );
+  DALI_TEST_CHECK( hintsValue );
+
+  int hints;;
+  DALI_TEST_CHECK( hintsValue->Get( hints ) );
+  DALI_TEST_CHECK( hints == Shader::Hint::OUTPUT_IS_TRANSPARENT );
+
+  Actor actor = Actor::New();
+  Toolkit::SetMotionStretchProperties( actor );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uGeometryStretchFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uSpeedScalingFactor" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeStart" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uObjectFadeEnd" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uAlphaScale" ) != Property::INVALID_INDEX );
+  DALI_TEST_CHECK( actor.GetPropertyIndex( "uModelLastFrame" ) != Property::INVALID_INDEX );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ShadowView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ShadowView.cpp
new file mode 100644 (file)
index 0000000..78ff25f
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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-toolkit/devel-api/controls/shadow-view/shadow-view.h>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void shadow_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void shadow_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+// Negative test case for a method
+int UtcDaliShadowViewUninitialized(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewUninitialized");
+
+  Toolkit::ShadowView view;
+  try
+  {
+    // New() must be called to create a GaussianBlurView or it wont be valid.
+    Actor a = Actor::New();
+    view.Add( a );
+    DALI_TEST_CHECK( false );
+  }
+  catch (Dali::DaliException& e)
+  {
+    // Tests that a negative test of an assertion succeeds
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_CHECK(!view);
+  }
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliShadowViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewNew");
+
+  Toolkit::ShadowView view = Toolkit::ShadowView::New();
+  DALI_TEST_CHECK( view );
+
+  Toolkit::ShadowView view2 = Toolkit::ShadowView::New(1.0f, 1.0f);
+  DALI_TEST_CHECK( view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliShadowViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewDownCast");
+
+  Toolkit::ShadowView view = Toolkit::ShadowView::New();
+  BaseHandle handle(view);
+
+  Toolkit::ShadowView shadowView = Toolkit::ShadowView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( shadowView );
+  DALI_TEST_CHECK( shadowView == view );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliShadowViewPropertyNames(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewPropertyNames");
+
+  Toolkit::ShadowView view = Toolkit::ShadowView::New();
+  DALI_TEST_CHECK( view );
+
+  // Check the names, this names are used in the shader code,
+  // if they change in the shader code, then it has to be updated here.
+  DALI_TEST_EQUALS( view.GetBlurStrengthPropertyIndex(), view.GetPropertyIndex("BlurStrengthProperty"), TEST_LOCATION );
+  DALI_TEST_EQUALS( view.GetShadowColorPropertyIndex(), view.GetPropertyIndex("ShadowColorProperty"), TEST_LOCATION );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliShadowViewAddRemove(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewAddRemove");
+
+  Toolkit::ShadowView view = Toolkit::ShadowView::New();
+  DALI_TEST_CHECK( view );
+
+  Actor actor = Actor::New();
+  DALI_TEST_CHECK( !actor.OnStage() );
+
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(actor);
+  Stage::GetCurrent().Add(view);
+
+  DALI_TEST_CHECK( actor.OnStage() );
+
+  view.Remove(actor);
+
+  DALI_TEST_CHECK( !actor.OnStage() );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliShadowViewActivateDeactivate(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliShadowViewActivateDeactivate");
+
+  Toolkit::ShadowView view = Toolkit::ShadowView::New();
+  DALI_TEST_CHECK( view );
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList.GetTaskCount() );
+
+  view.SetParentOrigin(ParentOrigin::CENTER);
+  view.SetSize(Stage::GetCurrent().GetSize());
+  view.Add(Actor::New());
+  Stage::GetCurrent().Add(view);
+  view.Activate();
+
+  RenderTaskList taskList2 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u != taskList2.GetTaskCount() );
+
+  view.Deactivate();
+
+  RenderTaskList taskList3 = Stage::GetCurrent().GetRenderTaskList();
+  DALI_TEST_CHECK( 1u == taskList3.GetTaskCount() );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Slider.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Slider.cpp
new file mode 100644 (file)
index 0000000..d7adf0e
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2019 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>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_slider_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_slider_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+}
+
+int UtcDaliSliderNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliSliderNew");
+
+  // Create the Slider actor
+  Slider slider;
+
+  DALI_TEST_CHECK( !slider );
+
+  slider = Slider::New();
+
+  DALI_TEST_CHECK( slider );
+
+  Slider slider2(slider);
+
+  DALI_TEST_CHECK( slider2 == slider );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    Slider slider = Slider::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliSliderDestructor(void)
+{
+  ToolkitTestApplication application;
+
+  Slider* slider = new Slider();
+  delete slider;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliSliderDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  Handle handle = Slider::New();
+
+  Slider slider = Slider::DownCast( handle );
+
+  DALI_TEST_CHECK( slider == handle );
+  END_TEST;
+}
+
+static bool gSliderValueChangedCallBackCalled=false;
+static bool OnSliderValueChanged( Slider slider, float value )
+{
+  gSliderValueChangedCallBackCalled = true;
+  return true;
+}
+
+static bool gSliderMarkCallBackCalled=false;
+static bool OnSliderMark( Slider slider, int value )
+{
+  gSliderMarkCallBackCalled = true;
+  return true;
+}
+
+static bool gSliderSlidingFinishedCallBackCalled=false;
+static bool OnSlidingFinished( Slider slider, float value )
+{
+  gSliderSlidingFinishedCallBackCalled = true;
+  return true;
+}
+
+int UtcDaliSliderSignals1(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliSliderSignals1");
+
+  // Create the Popup actor
+  Slider slider = Slider::New();
+  Stage::GetCurrent().Add( slider );
+  slider.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  slider.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  slider.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  slider.SetPosition( 0.0f, 0.0f );
+
+  const float MIN_BOUND = 0.0f;
+  const float MAX_BOUND = 1.0f;
+  const int NUM_MARKS = 5;
+  Property::Array marks;
+  for( int i = 0; i < NUM_MARKS; ++i )
+  {
+    marks.PushBack( MIN_BOUND + ( static_cast<float>(i) / ( NUM_MARKS - 1) ) * ( MAX_BOUND - MIN_BOUND ) );
+  }
+  slider.SetProperty( Slider::Property::MARKS, marks );
+  slider.SetProperty( Slider::Property::MARK_TOLERANCE, 0.1f );
+
+  slider.ValueChangedSignal().Connect( &OnSliderValueChanged );
+  slider.MarkReachedSignal().Connect( &OnSliderMark );
+  slider.SlidingFinishedSignal().Connect( &OnSlidingFinished );
+
+  application.SendNotification();
+  application.Render();
+
+  gSliderValueChangedCallBackCalled = false;
+  gSliderMarkCallBackCalled = false;
+  gSliderSlidingFinishedCallBackCalled = false;
+
+  {
+    Dali::Integration::TouchEvent event = Dali::Integration::TouchEvent();
+    Integration::Point pointDown;
+    pointDown.SetState( PointState::DOWN );
+    pointDown.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+    event.AddPoint( pointDown );
+
+    application.ProcessEvent( event );
+    application.SendNotification();
+    application.Render();
+  }
+
+  for( int i = 0; i < 5; ++i )
+  {
+    Dali::Integration::TouchEvent event = Dali::Integration::TouchEvent();
+    Integration::Point pointMotion;
+    pointMotion.SetState( PointState::MOTION );
+    pointMotion.SetScreenPosition( Vector2( 10.0f + i * 10.0f, 10.0f ) );
+    event.AddPoint( pointMotion );
+
+    application.ProcessEvent( event );
+    application.SendNotification();
+    application.Render();
+  }
+
+  {
+    Dali::Integration::TouchEvent event = Dali::Integration::TouchEvent();
+    Integration::Point pointUp;
+    pointUp.SetState( PointState::UP );
+    pointUp.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+    event.AddPoint( pointUp );
+
+    application.ProcessEvent( event );
+    application.SendNotification();
+    application.Render();
+  }
+
+  DALI_TEST_CHECK(gSliderValueChangedCallBackCalled);
+  DALI_TEST_CHECK(gSliderMarkCallBackCalled);
+  DALI_TEST_CHECK(gSliderSlidingFinishedCallBackCalled);
+  END_TEST;
+}
+
+
+namespace
+{
+bool gSliderSignal=false;
+struct SliderSignalFunctor
+{
+  SliderSignalFunctor()
+  {
+  }
+
+  void operator()()
+  {
+    gSliderSignal = true;
+  }
+};
+} // anonymous
+
+
+
+int UtcDaliSliderSignals2(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliSliderSignals1");
+
+  // Create the Popup actor
+  Slider slider = Slider::New();
+  Stage::GetCurrent().Add( slider );
+  slider.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  slider.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  slider.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  slider.SetPosition( 0.0f, 0.0f );
+
+  const float MIN_BOUND = 0.0f;
+  const float MAX_BOUND = 1.0f;
+  const int NUM_MARKS = 5;
+  Property::Array marks;
+  for( int i = 0; i < NUM_MARKS; ++i )
+  {
+    marks.PushBack( MIN_BOUND + ( static_cast<float>(i) / ( NUM_MARKS - 1) ) * ( MAX_BOUND - MIN_BOUND ) );
+  }
+  slider.SetProperty( Slider::Property::MARKS, marks );
+  slider.SetProperty( Slider::Property::MARK_TOLERANCE, 0.1f );
+
+  gSliderSignal = false;
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  slider.ConnectSignal( testTracker, "valueChanged",   SliderSignalFunctor() );
+
+  application.SendNotification();
+  application.Render();
+
+  gSliderValueChangedCallBackCalled = false;
+  gSliderMarkCallBackCalled = false;
+
+  Dali::Integration::TouchEvent event;
+
+  event = Dali::Integration::TouchEvent();
+
+  Integration::Point pointDown;
+  pointDown.SetState( PointState::DOWN );
+  pointDown.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  event.AddPoint( pointDown );
+
+  for( int i = 0; i < 5; ++i )
+  {
+    Integration::Point pointMotion;
+    pointMotion.SetState( PointState::MOTION );
+    pointMotion.SetScreenPosition( Vector2( 10.0f + i * 10.0f, 10.0f ) );
+    event.AddPoint( pointMotion );
+  }
+
+  Integration::Point pointUp;
+  pointUp.SetState( PointState::UP );
+  pointUp.SetScreenPosition( Vector2( 10.0f, 10.0f ) );
+  event.AddPoint( pointUp );
+
+  application.ProcessEvent( event );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK(gSliderSignal);
+  END_TEST;
+}
+
+int UtcDaliSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliSetPropertyP" );
+
+  Slider slider = Slider::New();
+  slider.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  slider.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  slider.SetSize( Vector2( Stage::GetCurrent().GetSize().x, 20.0f ) );
+  slider.SetPosition( 0.0f, 0.0f );
+
+  Stage::GetCurrent().Add(slider);
+  application.SendNotification();
+  application.Render();
+
+  slider.SetProperty(Slider::Property::LOWER_BOUND,        1.0f);
+  slider.SetProperty(Slider::Property::UPPER_BOUND,        5.0f);
+  slider.SetProperty(Slider::Property::VALUE,              3.0f);
+  slider.SetProperty(Slider::Property::DISABLED_COLOR,     Color::BLACK);
+  slider.SetProperty(Slider::Property::VALUE_PRECISION,    4);
+  slider.SetProperty(Slider::Property::SHOW_POPUP,         true);
+  slider.SetProperty(Slider::Property::SHOW_VALUE,         true);
+  slider.SetProperty(Slider::Property::MARKS,              false);
+  slider.SetProperty(Slider::Property::SNAP_TO_MARKS,      false);
+  slider.SetProperty(Slider::Property::MARK_TOLERANCE,     0.5f);
+
+  float lb = slider.GetProperty<float>(Slider::Property::LOWER_BOUND);
+  DALI_TEST_EQUALS(lb, 1.0f, TEST_LOCATION);
+  float ub = slider.GetProperty<float>(Slider::Property::UPPER_BOUND);
+  DALI_TEST_EQUALS(ub, 5.0f, TEST_LOCATION);
+  float val = slider.GetProperty<float>(Slider::Property::VALUE);
+  DALI_TEST_EQUALS(val, 3.0f, TEST_LOCATION);
+  Vector4 color = slider.GetProperty<Vector4>(Slider::Property::DISABLED_COLOR);
+  DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+  int precision = slider.GetProperty<int>(Slider::Property::VALUE_PRECISION);
+  DALI_TEST_EQUALS( precision, 4, TEST_LOCATION);
+  bool showPopup = slider.GetProperty<bool>(Slider::Property::SHOW_POPUP);
+  DALI_TEST_EQUALS( showPopup, true , TEST_LOCATION);
+  bool showValue = slider.GetProperty<bool>(Slider::Property::SHOW_VALUE);
+  DALI_TEST_EQUALS( showValue, true, TEST_LOCATION );
+  bool marks = slider.GetProperty<bool>(Slider::Property::MARKS);
+  DALI_TEST_EQUALS( marks, false, TEST_LOCATION );
+  bool snapToMarks = slider.GetProperty<bool>(Slider::Property::SNAP_TO_MARKS);
+  DALI_TEST_EQUALS( snapToMarks, false, TEST_LOCATION );
+  float tolerance = slider.GetProperty<float>(Slider::Property::MARK_TOLERANCE);
+  DALI_TEST_EQUALS( tolerance, 0.5f, TEST_LOCATION );
+
+  {
+    Property::Map map;
+    map["visualType"] = "IMAGE";
+    map["size"] = Vector2(200, 200);
+    map["url"] = "track2.png";
+    slider.SetProperty(Slider::Property::TRACK_VISUAL,       map);
+    map["url"] = "handle2.png";
+    slider.SetProperty(Slider::Property::HANDLE_VISUAL,      map);
+    map["url"] = "progress2.png";
+    slider.SetProperty(Slider::Property::PROGRESS_VISUAL,    map);
+    map["url"] = "popup2.png";
+    slider.SetProperty(Slider::Property::POPUP_VISUAL,       map);
+    map["url"] = "popupArrow2.png";
+    slider.SetProperty(Slider::Property::POPUP_ARROW_VISUAL, map);
+
+    Property::Value value = slider.GetProperty(Slider::Property::TRACK_VISUAL);
+    Property::Map* resultMap = value.GetMap();
+    DALI_TEST_CHECK( resultMap );
+    Property::Value* url = resultMap->Find("url");
+    DALI_TEST_CHECK( url ) ;
+    DALI_TEST_EQUALS( *url, "track2.png", TEST_LOCATION );
+
+    value = slider.GetProperty(Slider::Property::HANDLE_VISUAL);
+    resultMap = value.GetMap();
+    DALI_TEST_CHECK( resultMap );
+    url = resultMap->Find("url");
+    DALI_TEST_CHECK( url ) ;
+    DALI_TEST_EQUALS( *url, "handle2.png", TEST_LOCATION );
+
+    value = slider.GetProperty(Slider::Property::PROGRESS_VISUAL);
+    resultMap = value.GetMap();
+    DALI_TEST_CHECK( resultMap );
+    url = resultMap->Find("url");
+    DALI_TEST_CHECK( url ) ;
+    DALI_TEST_EQUALS( *url, "progress2.png", TEST_LOCATION );
+
+    value = slider.GetProperty(Slider::Property::POPUP_VISUAL);
+    resultMap = value.GetMap();
+    DALI_TEST_CHECK( resultMap );
+    url = resultMap->Find("url");
+    DALI_TEST_CHECK( url ) ;
+    DALI_TEST_EQUALS( *url, "popup2.png", TEST_LOCATION );
+
+    value = slider.GetProperty(Slider::Property::POPUP_ARROW_VISUAL);
+    resultMap = value.GetMap();
+    DALI_TEST_CHECK( resultMap );
+    url = resultMap->Find("url");
+    DALI_TEST_CHECK( url ) ;
+    DALI_TEST_EQUALS( *url, "popupArrow2.png", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+
+// DestroyHandleVisualDisplay
+// CreateValueDisplay
+// SlidingFinishedSignal()
+// UpdateSkin disabled
+// AddPopup
+// RemovePopup
+// SnapToMark
+// HideValueView
+// GetDisabledColor
+// GetShowPopup
+// GetShowVisual
+// DisplayPopup (with set valueText label)
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-SuperBlurView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-SuperBlurView.cpp
new file mode 100644 (file)
index 0000000..664c2a8
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void utc_dali_toolkit_super_blur_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_super_blur_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+namespace
+{
+const int BLUR_LEVELS = 3;
+const int RENDER_FRAME_INTERVAL = 16;
+static const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+static bool gObjectCreatedCallBackCalled;
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+Texture CreateSolidColorTexture( ToolkitTestApplication& application, const Vector4& color, unsigned int width, unsigned int height )
+{
+  unsigned int size = width * height;
+  uint8_t* pixbuf = new uint8_t[size*4];
+
+  for( size_t i = 0; i < size; i++ )
+  {
+    pixbuf[i*4+0] = 0xFF * color.r;
+    pixbuf[i*4+1] = 0xFF * color.g;
+    pixbuf[i*4+2] = 0xFF * color.b;
+    pixbuf[i*4+3] = 0xFF * color.a;
+  }
+
+  PixelData pixels = PixelData::New( pixbuf, size, width, height, Pixel::RGBA8888, PixelData::ReleaseFunction::DELETE_ARRAY );
+
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
+  texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
+
+  return texture;
+}
+
+class SignalHandler : public Dali::ConnectionTracker
+{
+public:
+  SignalHandler() :
+    mCalls( 0 )
+  {
+  }
+
+  void Callback( SuperBlurView handle )
+  {
+    mCalls++;
+    tet_infoline( "Signal called" );
+  }
+
+  unsigned int GetCalls() const
+  {
+    return mCalls;
+  }
+
+private:
+  unsigned int mCalls;  ///< Keeps track of how many times the signal has been called.
+};
+
+}//namespace
+
+
+int UtcDaliSuperBlurViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewNew ");
+
+  // Test default constructor.
+  SuperBlurView blurView;
+  DALI_TEST_CHECK( !blurView );
+
+  // Test object creation
+  blurView = SuperBlurView::New( BLUR_LEVELS );
+  DALI_TEST_CHECK( blurView );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+
+  // Test copy constructor
+  SuperBlurView blurViewCopy2( blurView );
+  DALI_TEST_CHECK( blurViewCopy2 );
+
+  // Test down cast
+  Actor actorView;
+  actorView = blurView;
+  SuperBlurView downCastView = SuperBlurView::DownCast( actorView );
+  DALI_TEST_CHECK( downCastView );
+  END_TEST;
+}
+
+int UtcDaliSuperBlurViewCreate(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewNew ");
+
+  // Test default constructor.
+  SuperBlurView blurView;
+  DALI_TEST_CHECK( !blurView );
+
+  // Test object creation
+  TypeInfo type = TypeRegistry::Get().GetTypeInfo("SuperBlurView");
+  if( type )
+  {
+    Dali::BaseHandle handle = type.CreateInstance();
+    if( handle )
+    {
+      blurView = Dali::Toolkit::SuperBlurView::DownCast( handle );
+    }
+  }
+
+  DALI_TEST_CHECK( blurView );
+
+  END_TEST;
+}
+
+
+int UtcDaliSuperBlurViewSetTexture(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewSetTexture ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  blurView.SetSize( 100.f, 100.f );
+
+  Texture inputTexture = CreateSolidColorTexture( application, Color::GREEN, 50, 50 );
+  blurView.SetTexture( inputTexture );
+  // start multiple guassian blur call, each guassian blur creates two render tasks
+  DALI_TEST_CHECK( Stage::GetCurrent().GetRenderTaskList().GetTaskCount() == 1+BLUR_LEVELS*2);
+
+  {
+    // create renderers for the original image and each blurred image
+    Stage::GetCurrent().Add( blurView );
+    Wait(application);
+    DALI_TEST_EQUALS(blurView.GetRendererCount(), BLUR_LEVELS+1, TEST_LOCATION );
+
+    Wait(application);
+    Stage::GetCurrent().Remove( blurView );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSuperBlurViewSetTexture2(void)
+{
+  ToolkitTestApplication application;
+  Stage stage = Stage::GetCurrent();
+
+  tet_infoline(" UtcDaliSuperBlurViewSetTexture2 - test setting a second texture ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  blurView.SetSize( 100.f, 100.f );
+
+  tet_infoline("Call SetTexture and add blurview to stage");
+  Texture inputTexture = CreateSolidColorTexture( application, Color::GREEN, 50, 50 );
+  blurView.SetTexture( inputTexture );
+
+  // start multiple guassian blur call, each guassian blur creates two render tasks
+  DALI_TEST_CHECK( Stage::GetCurrent().GetRenderTaskList().GetTaskCount() == 1+BLUR_LEVELS*2);
+  {
+    // create renderers for the original image and each blurred image
+    stage.Add( blurView );
+    Wait(application);
+    DALI_TEST_EQUALS(blurView.GetRendererCount(), BLUR_LEVELS+1, TEST_LOCATION );
+
+    tet_infoline("Wait for a second to allow blur to finish");
+    Wait(application, 1000);
+
+    tet_infoline("Remove from stage");
+    Stage::GetCurrent().Remove( blurView );
+  }
+
+  tet_infoline("Test that there are no render tasks remaining");
+  DALI_TEST_EQUALS(blurView.GetRendererCount(), 0, TEST_LOCATION );
+
+  tet_infoline("Call SetTexture a second time and add blurview back to stage");
+  Texture inputTexture2 = CreateSolidColorTexture( application, Color::CYAN, 50, 50 );
+  blurView.SetTexture( inputTexture2 );
+  // start multiple guassian blur call, each guassian blur creates two render tasks
+  DALI_TEST_CHECK( Stage::GetCurrent().GetRenderTaskList().GetTaskCount() == 1+BLUR_LEVELS*2);
+
+  {
+    // create renderers for the original image and each blurred image
+    Stage::GetCurrent().Add( blurView );
+    Wait(application);
+    DALI_TEST_EQUALS(blurView.GetRendererCount(), BLUR_LEVELS+1, TEST_LOCATION );
+
+    tet_infoline("Wait for a second to allow blur to finish");
+    Wait(application, 1000);
+
+    tet_infoline("Remove from stage");
+    Stage::GetCurrent().Remove( blurView );
+  }
+
+  tet_infoline("Test that there are no render tasks remaining");
+  DALI_TEST_EQUALS(blurView.GetRendererCount(), 0, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliSuperBlurViewSetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewSetProperty ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  // create renderers for the original image and each blurred image
+  Stage::GetCurrent().Add( blurView );
+  blurView.SetSize( 100.f, 100.f );
+
+  // Will create ResourceImage
+  blurView.SetProperty(SuperBlurView::Property::IMAGE_URL, TEST_IMAGE_FILE_NAME);
+  Wait(application);
+
+  // start multiple guassian blur call, each guassian blur creates two render tasks
+
+  unsigned int count = Stage::GetCurrent().GetRenderTaskList().GetTaskCount();
+  DALI_TEST_CHECK( count == 1+BLUR_LEVELS*2 );
+
+  Wait(application);
+
+  END_TEST;
+}
+
+
+int UtcDaliSuperBlurViewGetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewSetProperty ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  blurView.SetSize( 100.f, 100.f );
+
+  blurView.SetProperty(SuperBlurView::Property::IMAGE_URL, TEST_IMAGE_FILE_NAME);
+  Wait(application);
+
+  // create renderers for the original image and each blurred image
+  Stage::GetCurrent().Add( blurView );
+
+  std::string imageUrl = blurView.GetProperty<std::string>( SuperBlurView::Property::IMAGE_URL );
+  DALI_TEST_EQUALS( imageUrl, TEST_IMAGE_FILE_NAME, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliSuperBlurViewSetGetBlurStrength(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewSetGetBlurStrength ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  DALI_TEST_EQUALS(blurView.GetCurrentBlurStrength(), 0.f, TEST_LOCATION );
+
+  blurView.SetBlurStrength( 0.65f );
+  Wait(application);
+  DALI_TEST_EQUALS(blurView.GetCurrentBlurStrength(), 0.65f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliSuperBlurViewGetBlurStrengthPropertyIndex(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewGetBlurStrengthPropertyIndex ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  Property::Index blurPropertyIdx = blurView.GetBlurStrengthPropertyIndex();
+
+  float blurStrength;
+  (blurView.GetProperty( blurPropertyIdx )).Get(blurStrength);
+  DALI_TEST_EQUALS(blurStrength, 0.f, TEST_LOCATION );
+
+  blurView.SetBlurStrength( 0.65f );
+  Wait(application);
+  (blurView.GetProperty( blurPropertyIdx )).Get(blurStrength);
+  DALI_TEST_EQUALS(blurStrength, 0.65f, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliSuperBlurViewGetBlurredTexture(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliSuperBlurViewGetBlurredTexture" );
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  blurView.SetSize( 100.f,100.f );
+  Texture inputTexture = CreateSolidColorTexture( application, Color::GREEN, 100, 100 );
+  blurView.SetTexture( inputTexture );
+
+  Wait(application, 200); // Make sure all the gaussian blur finished
+
+  Texture texture1 = blurView.GetBlurredTexture( 1 );
+  DALI_TEST_CHECK( texture1 );
+
+  Texture texture2 = blurView.GetBlurredTexture( 2 );
+  DALI_TEST_EQUALS( texture2.GetWidth(), 25u, TEST_LOCATION );
+  DALI_TEST_EQUALS( texture2.GetHeight(), 25u, TEST_LOCATION );
+
+  Texture texture3 = blurView.GetBlurredTexture( 3 );
+  DALI_TEST_CHECK( texture3 );
+
+  END_TEST;
+}
+
+int UtcDaliSuperBlurViewBlurSignal(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliSuperBlurViewSignal ");
+
+  SuperBlurView blurView = SuperBlurView::New( BLUR_LEVELS );
+  blurView.SetSize( 100.f, 100.f );
+
+  Texture inputTexture = CreateSolidColorTexture( application, Color::GREEN, 50, 50 );
+  blurView.SetTexture( inputTexture );
+  // start multiple guassian blur call, each guassian blur creates two render tasks
+  DALI_TEST_CHECK( Stage::GetCurrent().GetRenderTaskList().GetTaskCount() == 1+BLUR_LEVELS*2);
+
+  SignalHandler signalHandler;
+  blurView.BlurFinishedSignal().Connect(&signalHandler, &SignalHandler::Callback);
+
+  // create renderers for the original image and each blurred image
+  Stage::GetCurrent().Add( blurView );
+  Wait(application, 1000);
+
+  DALI_TEST_EQUALS(blurView.GetRendererCount(), BLUR_LEVELS+1, TEST_LOCATION );
+  //DALI_TEST_EQUALS(signalHandler.GetCalls(), 1, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp b/automated-tests/src/dali-toolkit/utc-Dali-SyncImageLoader.cpp
new file mode 100644 (file)
index 0000000..d37c5fc
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <dali/dali.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+
+// Resolution: 50*50, pixel format: RGBA8888
+static const char* gImage_50_RGBA = TEST_RESOURCE_DIR "/icon-delete.png";
+
+// Resolution: 128*128, pixel format: RGB888
+static const char* gImage_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+
+void VerifyLoad( PixelData pixelData, uint32_t width, uint32_t height )
+{
+  DALI_TEST_CHECK( pixelData );
+  DALI_TEST_EQUALS<unsigned int>( pixelData.GetWidth(), width, TEST_LOCATION );
+  DALI_TEST_EQUALS<unsigned int>( pixelData.GetHeight(), height, TEST_LOCATION );
+}
+
+} // anonymous namespace
+
+
+int UtcDaliSyncImageLoaderLoad(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_50_RGBA );
+
+  DALI_TEST_EQUALS<bool>( pixelData, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliSyncImageLoaderLoadWithDimensions(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_50_RGBA, ImageDimensions( 25, 25 ) );
+
+  VerifyLoad( pixelData, 25u, 25u );
+
+  END_TEST;
+}
+
+int UtcDaliSyncImageLoaderLoadWithAllOptions(void)
+{
+  PixelData pixelData = Toolkit::SyncImageLoader::Load( gImage_128_RGB, ImageDimensions( 100, 100 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, true );
+
+  VerifyLoad( pixelData, 100u, 100u );
+
+  END_TEST;
+}
+
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp
new file mode 100644 (file)
index 0000000..3a8ce20
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+ * 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 <sstream>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_tableview_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_tableview_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* const PROPERTY_NAME_ROWS = "rows";
+const char* const PROPERTY_NAME_COLUMNS = "columns";
+const char* const PROPERTY_NAME_CELL_PADDING = "cellPadding";
+const char* const PROPERTY_NAME_LAYOUT_ROWS = "layoutRows";
+const char* const PROPERTY_NAME_LAYOUT_COLUMNS = "layoutColumns";
+const Vector2 CELL_SIZE( 10, 10 );
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+struct Constraint100
+{
+  Constraint100( )
+  {
+  }
+
+  /**
+   * function operator to apply the parent size
+   */
+  void operator()( Dali::Vector3& current, const PropertyInputContainer& /* inputs */ )
+  {
+    current.x = current.y = current.z = 100.0f;
+  }
+};
+
+// Convenience function to quickly set up a 10x10 table with each cell being 10x10 pixels in size by default.
+static void SetupTableViewAndActors(TableView& tableView, Actor& actor1, Actor& actor2, Actor& actor3)
+{
+  tableView = TableView::New( 10, 10 ); // 10 by 10 grid.
+  DALI_TEST_CHECK( tableView );
+
+  Stage::GetCurrent().Add( tableView );
+  tableView.SetSize( Dali::Vector2( 100.0f, 100.0f ) );
+
+  actor1 = Actor::New();
+  actor2 = Actor::New();
+  actor3 = Actor::New();
+
+  actor1.SetSize( CELL_SIZE );
+  actor2.SetSize( CELL_SIZE );
+  actor3.SetSize( CELL_SIZE );
+
+  tableView.AddChild( actor1, TableView::CellPosition( 0, 0 ) );
+  tableView.AddChild( actor2, TableView::CellPosition( 0, 1 ) );
+  tableView.AddChild( actor3, TableView::CellPosition( 1, 0 ) );
+}
+
+} // namespace
+
+int UtcDaliTableViewCtorCopyP(void)
+{
+  TestApplication application;
+
+  TableView actor1 = TableView::New(10,10);
+  TableView actor2( actor1 );
+
+  DALI_TEST_EQUALS( actor1, actor2, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliTableViewNew(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK(tableView);
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect(&TestCallback);
+  {
+    TableView tableView = TableView::New(10,10);
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+// Test adjusting the metric values for the cell.
+int UtcDaliTableViewMetricsPadding(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewMetricsPadding");
+
+  TableView tableView;
+  Actor actor1;
+  Actor actor2;
+  Actor actor3;
+
+  SetupTableViewAndActors(tableView, actor1, actor2, actor3);
+
+  // 1. check that padding works. no padding:
+  tableView.SetCellPadding(Size(0.0f, 0.0f));
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( tableView.GetCellPadding(), Size(0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  // 1. check that padding works. some padding:
+  tableView.SetCellPadding(Size(5.0f, 10.0f));
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( tableView.GetCellPadding(), Size(5.0f, 10.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(5.0f, 10.0f, 0.0f), TEST_LOCATION );
+  END_TEST;
+}
+
+// Test adjusting the metric values for the cell.
+int UtcDaliTableViewMetricsFit(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewMetricsFit");
+
+  TableView tableView;
+  Actor actor1;
+  Actor actor2;
+  Actor actor3;
+
+  SetupTableViewAndActors(tableView, actor1, actor2, actor3);
+  application.SendNotification();
+  application.Render();
+
+  // 1. check that with no fixed width/heights, actors are in default position.
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  // 2. check that with a fixed width & height, actors to the right and below are offsetted.
+  tableView.SetFitHeight(0);
+  tableView.SetFitWidth(0);
+  DALI_TEST_EQUALS( tableView.IsFitHeight(0), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.IsFitWidth(0), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  tableView.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,  Dali::LayoutDirection::RIGHT_TO_LEFT );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(90.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(80.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(90.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  tableView.SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,  Dali::LayoutDirection::LEFT_TO_RIGHT );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+// Test adjusting the metric values for the cell.
+int UtcDaliTableViewMetricsFixed(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewMetricsFixed");
+
+  TableView tableView;
+  Actor actor1;
+  Actor actor2;
+  Actor actor3;
+
+  SetupTableViewAndActors(tableView, actor1, actor2, actor3);
+  application.SendNotification();
+  application.Render();
+
+  // 1. check that with no fixed width/heights, actors are in default position.
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  // 2. check that with a fixed width & height, actors to the right and below are offsetted.
+  tableView.SetFixedWidth(0, 20.0f);
+  tableView.SetFixedHeight(0, 50.0f);
+  DALI_TEST_EQUALS( tableView.GetFixedWidth(0), 20.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.GetFixedHeight(0), 50.0f, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(20.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 50.0f, 0.0f), TEST_LOCATION );
+  END_TEST;
+}
+
+// Test adjusting the metric values for the cell.
+int UtcDaliTableViewMetricsRelative(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewMetricsRelative");
+
+  TableView tableView;
+  Actor actor1;
+  Actor actor2;
+  Actor actor3;
+
+  SetupTableViewAndActors(tableView, actor1, actor2, actor3);
+  application.SendNotification();
+  application.Render();
+
+  // 1. check that with no relative width/heights, actors are in default position.
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(10.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 10.0f, 0.0f), TEST_LOCATION );
+
+  // 2. check that with a relative width & height, actors to the right and below are offsetted.
+  tableView.SetRelativeWidth(0, 0.3f); // cell 0,0 occupies 30%x50% of the grid (i.e. 30x50 pixels)
+  tableView.SetRelativeHeight(0, 0.5f);
+  DALI_TEST_EQUALS( tableView.GetRelativeWidth(0), 0.3f, TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.GetRelativeHeight(0), 0.5f, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor1.GetCurrentPosition(), Vector3(0.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor2.GetCurrentPosition(), Vector3(30.0f, 0.0f, 0.0f), TEST_LOCATION );
+  DALI_TEST_EQUALS( actor3.GetCurrentPosition(), Vector3(0.0f, 50.0f, 0.0f), TEST_LOCATION );
+  END_TEST;
+}
+
+
+// Test Adding/Removing/Finding Children.
+int UtcDaliTableViewChild(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewChild");
+
+  // Create a 10x10 table-view
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView );
+
+  // Check if actor doesn't exist.
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(0,0)) );
+
+  // Add an actor to it at 0,0
+  Actor actor = Actor::New();
+  tableView.AddChild(actor, TableView::CellPosition());
+
+  // Check if exists.
+  DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(0,0)) );
+
+  // Remove this actor
+  tableView.RemoveChildAt(TableView::CellPosition());
+
+  // Check if actor no longer exists.
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(0,0)) );
+
+  // Add actor to it again, but at 2,5
+  tableView.AddChild(actor, TableView::CellPosition(2,5));
+
+  // Add another actor somewhere else 7,8
+  Actor actor2 = Actor::New();
+  tableView.AddChild(actor2, TableView::CellPosition(7,8));
+
+  Actor searchActor;
+
+  // Check that no actor exists in a few random places.
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(0,0)) );
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(2,1)) );
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(6,3)) );
+  DALI_TEST_CHECK( !tableView.GetChildAt(TableView::CellPosition(9,5)) );
+
+  // Check for actors at actual positions.
+  searchActor = tableView.GetChildAt(TableView::CellPosition(2,5));
+  DALI_TEST_CHECK( searchActor == actor);
+
+  searchActor = tableView.GetChildAt(TableView::CellPosition(7,8));
+  DALI_TEST_CHECK( searchActor == actor2);
+
+  // Create a second table, and add already added Child to new one.
+  TableView tableView2 = TableView::New(5,5);
+  tableView2.AddChild(actor, TableView::CellPosition(2,2));
+  DALI_TEST_CHECK( tableView2.GetChildAt(TableView::CellPosition(2,2)) );
+  END_TEST;
+}
+
+// Test calling Add on it's own (to invoke the OnChildAdd)
+int UtcDaliTableViewAdd(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliTableViewAdd");
+
+  // Create a 4x1 table-view, and just keep adding.
+  TableView tableView = TableView::New(1,4);
+  DALI_TEST_CHECK( tableView );
+
+  for(unsigned int i = 0;i<16;i++)
+  {
+    Actor currentActor = Actor::New();
+    TableView::CellPosition position = TableView::CellPosition();
+    tableView.Add( currentActor );
+    tableView.FindChildPosition(currentActor, position);
+    tet_printf("%dx%d (%d,%d)\n", tableView.GetColumns(), tableView.GetRows(), position.columnIndex, position.rowIndex);
+
+    DALI_TEST_EQUALS((position.rowIndex * 4 + position.columnIndex), i, TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+// Test cell modification.
+int UtcDaliTableViewCells(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTableViewCells");
+
+  // Create a 10x10 table-view
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView );
+
+  // Add a few actors to the table.
+  Actor actor1 = Actor::New();
+  Actor actor2 = Actor::New();
+  Actor actor3 = Actor::New();
+  actor1.SetName("Actor1");
+  actor2.SetName("Actor2");
+  actor3.SetName("Actor3");
+
+  // note: positions are specified in reversed cartesian coords - row,col (i.e. y,x)
+  tableView.AddChild(actor1, TableView::CellPosition(0,0));
+  tableView.AddChild(actor2, TableView::CellPosition(5,5));
+  tableView.AddChild(actor3, TableView::CellPosition(7,2));
+
+  DALI_TEST_CHECK( tableView.GetRows() == 10 && tableView.GetColumns() == 10 );
+
+  // Add a row between actor1 and actor2 | insert column on actor1 and see what happens...
+  tableView.InsertRow(3);
+  tableView.InsertColumn(0);
+  DALI_TEST_CHECK( tableView.GetRows() == 11 && tableView.GetColumns() == 11 );
+
+  TableView::CellPosition cellPosition;
+  bool result;
+
+  result = tableView.FindChildPosition(actor1, cellPosition);
+  DALI_TEST_CHECK( result && cellPosition.rowIndex == 0 && cellPosition.columnIndex == 1);
+  result = tableView.FindChildPosition(actor2, cellPosition);
+  DALI_TEST_CHECK( result && cellPosition.rowIndex == 6 && cellPosition.columnIndex == 6);
+  result = tableView.FindChildPosition(actor3, cellPosition);
+  DALI_TEST_CHECK( result && cellPosition.rowIndex == 8 && cellPosition.columnIndex == 3);
+
+  // Delete a row between actor2 and actor3 | delete column on actor2 and see what happens...
+  tableView.DeleteRow(7);
+  tableView.DeleteColumn(6);
+  DALI_TEST_CHECK( tableView.GetRows() == 10 && tableView.GetColumns() == 10 );
+
+  result = tableView.FindChildPosition(actor1, cellPosition);
+  DALI_TEST_CHECK( result && cellPosition.rowIndex == 0 && cellPosition.columnIndex == 1);
+  result = tableView.FindChildPosition(actor2, cellPosition);
+  DALI_TEST_CHECK( !result );
+  result = tableView.FindChildPosition(actor3, cellPosition);
+  DALI_TEST_CHECK( result && cellPosition.rowIndex == 7 && cellPosition.columnIndex == 3);
+
+  // Delete the other two remaining actors by a row delete and a column delete.
+  std::vector<Actor> actorsRemoved;
+  tableView.DeleteRow(0, actorsRemoved);
+  tet_printf("Row Delete >> Actors Removed: %d {", actorsRemoved.size());
+  for(size_t i = 0;i<actorsRemoved.size();i++) tet_printf("%d => %s, ", i, actorsRemoved[i].GetName().c_str());
+  tet_printf("}\n");
+  DALI_TEST_EQUALS( static_cast<int>(actorsRemoved.size()), 1, TEST_LOCATION );
+  DALI_TEST_CHECK( actorsRemoved[0] == actor1 );
+
+  actorsRemoved.clear();
+  tableView.DeleteColumn(3, actorsRemoved);
+  tet_printf("Column Delete >> Actors Removed: %d {", actorsRemoved.size());
+  for(size_t i = 0;i<actorsRemoved.size();i++) tet_printf("%d => %s, ", i, actorsRemoved[i].GetName().c_str());
+  tet_printf("}\n");
+  DALI_TEST_EQUALS( static_cast<int>(actorsRemoved.size()), 1, TEST_LOCATION );
+  DALI_TEST_CHECK( actorsRemoved[0] == actor3 );
+
+  DALI_TEST_CHECK( tableView.GetRows() == 9 && tableView.GetColumns() == 9 );
+
+  tableView.AddChild(actor1, TableView::CellPosition(5,8));
+  tableView.Resize(100,100);
+  DALI_TEST_CHECK( tableView.GetRows() == 100 && tableView.GetColumns() == 100 );
+
+  tableView.AddChild(actor2, TableView::CellPosition(69,57));
+  DALI_TEST_CHECK( tableView.FindChildPosition(actor1, cellPosition) && tableView.FindChildPosition(actor2, cellPosition) );
+
+  tableView.Resize(20,20);
+  DALI_TEST_CHECK( tableView.FindChildPosition(actor1, cellPosition) && !tableView.FindChildPosition(actor2, cellPosition) );
+
+  actorsRemoved.clear();
+  tableView.Resize(1,1, actorsRemoved);
+  DALI_TEST_CHECK( !tableView.FindChildPosition(actor1, cellPosition) && !tableView.FindChildPosition(actor2, cellPosition) );
+  DALI_TEST_EQUALS( static_cast<int>(actorsRemoved.size()), 1, TEST_LOCATION );
+  DALI_TEST_CHECK( actorsRemoved[0] == actor1 );
+
+  // Add child outside table size, forcing a resize.
+  tableView.AddChild(actor1, TableView::CellPosition(100, 100, 1, 1));
+  DALI_TEST_CHECK( tableView.GetRows() == 101 && tableView.GetColumns() == 101 );
+
+  // Add child outside table size, forcing a resize.
+  tableView.AddChild(actor1, TableView::CellPosition(110, 110, 5, 5));
+  DALI_TEST_CHECK( tableView.GetRows() == 115 && tableView.GetColumns() == 115 );
+
+  // Set the alignment of the cell
+  tableView.SetCellAlignment( TableView::CellPosition(100, 100, 1, 1), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
+  tableView.SetCellAlignment( TableView::CellPosition(110, 110, 5, 5), HorizontalAlignment::LEFT, VerticalAlignment::TOP );
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliTableViewChildAssert(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTableViewChildAssert");
+
+  // Create a 10x10 table-view
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView );
+  Actor childActor;
+
+  try
+  {
+    tableView.AddChild( childActor, TableView::CellPosition(0,0,5,5) );
+    // should assert
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "child", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTableViewMetricsAssert(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTableViewChildAssert");
+
+  // Create a 10x10 table-view
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView );
+
+  // fixeds...
+
+  try
+  {
+    tableView.SetFixedHeight( 10, 1.0f );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "rowIndex < mRowData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.GetFixedHeight( 10 );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "rowIndex < mRowData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.SetFixedWidth( 10, 1.0f );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "columnIndex < mColumnData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.GetFixedWidth( 10 );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "columnIndex < mColumnData.Size()", TEST_LOCATION);
+  }
+
+  // relatives...
+
+  try
+  {
+    tableView.SetRelativeHeight( 10, 0.1f );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "rowIndex < mRowData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.GetRelativeHeight( 10 );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "rowIndex < mRowData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.SetRelativeWidth( 10, 0.1f );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "columnIndex < mColumnData.Size()", TEST_LOCATION);
+  }
+
+  try
+  {
+    tableView.GetRelativeWidth( 10 );
+
+    tet_result(TET_FAIL);
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "columnIndex < mColumnData.Size()", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTableViewSetGetProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTableViewSetGetProperty");
+
+  // Create a 1x1 table-view
+  TableView tableView = TableView::New(1,1);
+  tableView.SetSize( Vector2( 100.0f, 100.0f ) );
+  DALI_TEST_CHECK( tableView );
+
+  // Test "rows" property
+  DALI_TEST_CHECK( tableView.GetPropertyIndex( PROPERTY_NAME_ROWS ) == TableView::Property::ROWS );
+
+  tableView.SetProperty( TableView::Property::ROWS, 4 );
+
+  DALI_TEST_CHECK( tableView.GetRows() == 4u );
+  DALI_TEST_CHECK( tableView.GetProperty(TableView::Property::ROWS).Get<int>() == 4 );
+
+  // Test "columns" property
+  DALI_TEST_CHECK( tableView.GetPropertyIndex( PROPERTY_NAME_COLUMNS ) == TableView::Property::COLUMNS );
+
+  tableView.SetProperty( TableView::Property::COLUMNS, 5 );
+
+  DALI_TEST_CHECK( tableView.GetColumns() == 5u );
+  DALI_TEST_CHECK( tableView.GetProperty(TableView::Property::COLUMNS).Get<int>() == 5 );
+
+  // Test "cellPadding" property
+  DALI_TEST_CHECK( tableView.GetPropertyIndex( PROPERTY_NAME_CELL_PADDING ) == TableView::Property::CELL_PADDING );
+
+  tableView.SetProperty( TableView::Property::CELL_PADDING, Size( 6.f, 8.f ) );
+
+  DALI_TEST_EQUALS( tableView.GetCellPadding(), Size(6.f, 8.f), TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.GetProperty(TableView::Property::CELL_PADDING).Get<Vector2>(), Vector2(6.f,8.f), TEST_LOCATION );
+
+  //{ "policy": "fixed", "value": 30.0 },
+  Property::Map item1;
+  item1[ "policy" ] = "fixed";
+  item1[ "value" ] = 30.f;
+  //{ "policy": "relative", "value": 0.2 },
+  Property::Map item2;
+  item2[ "policy" ] = "relative";
+  item2[ "value" ] = 0.2f;
+
+  // Test "layoutRows" property
+  DALI_TEST_CHECK( tableView.GetPropertyIndex(PROPERTY_NAME_LAYOUT_ROWS) == TableView::Property::LAYOUT_ROWS );
+
+  /*
+   * "layoutRows":
+   *  {
+   *    "1": { "policy": "fixed", "value": 30 },
+   *    "3": { "policy": "relative", "value": 0.2 }
+   *   }
+   */
+  Property::Map layoutRows;
+  layoutRows[ "1" ] = item1;
+  layoutRows[ "3" ] = item2;
+  tableView.SetProperty( TableView::Property::LAYOUT_ROWS, layoutRows );
+
+  DALI_TEST_EQUALS( tableView.GetFixedHeight( 1u ), 30.f, TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.GetRelativeHeight( 3u ), 0.2f, TEST_LOCATION );
+
+  Property::Map layoutRowsGet = tableView.GetProperty(TableView::Property::LAYOUT_ROWS).Get<Property::Map>();
+
+  DALI_TEST_EQUALS( layoutRowsGet.GetKey(1).compare(layoutRows.GetKey(0)), 0, TEST_LOCATION );
+  Property::Map* childMap =layoutRowsGet.GetValue(1).GetMap();
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("fixed") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 30.f, TEST_LOCATION );
+
+  childMap =layoutRowsGet.GetValue(3).GetMap();
+  DALI_TEST_CHECK( layoutRowsGet.GetKey(3).compare(layoutRows.GetKey(1)) == 0 );
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("relative") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 0.2f, TEST_LOCATION );
+
+  // Test "layoutColumns" property
+  DALI_TEST_CHECK( tableView.GetPropertyIndex( PROPERTY_NAME_LAYOUT_COLUMNS ) == TableView::Property::LAYOUT_COLUMNS );
+
+  /*
+   * "layoutColumns":
+   *  {
+   *    "2": { "policy": "relative", "value": 0.2 },
+   *    "3": { "policy": "fixed", "value": 30 }
+   *   }
+   */
+  Property::Map layoutColumns;
+  layoutColumns[ "2" ] = item2;
+  layoutColumns[ "3" ] = item1;
+  tableView.SetProperty( TableView::Property::LAYOUT_COLUMNS, layoutColumns );
+
+  DALI_TEST_EQUALS( tableView.GetRelativeWidth( 2u ), 0.2f, TEST_LOCATION );
+  DALI_TEST_EQUALS( tableView.GetFixedWidth( 3u ), 30.f, TEST_LOCATION );
+
+  Property::Map layoutColumnsGet = tableView.GetProperty(TableView::Property::LAYOUT_COLUMNS).Get<Property::Map>();
+  DALI_TEST_CHECK( layoutColumnsGet.GetKey(2).compare(layoutColumns.GetKey(0)) == 0 );
+  childMap =layoutColumnsGet.GetValue(2).GetMap();
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("relative") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(), 0.2f, TEST_LOCATION );
+  childMap =layoutColumnsGet.GetValue(3).GetMap();
+  DALI_TEST_CHECK( layoutColumnsGet.GetKey(3).compare(layoutColumns.GetKey(1)) == 0 );
+  DALI_TEST_CHECK( childMap->Find( "policy" )->Get<std::string>().compare("fixed") == 0 );
+  DALI_TEST_EQUALS( childMap->Find( "value" )->Get<float>(),30.f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewChildProperties(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTableViewChildProperties");
+
+  // Create a 10x10 table-view
+  TableView tableView = TableView::New(10,10);
+  Stage::GetCurrent().Add( tableView );
+  tableView.SetSize( Dali::Vector2( 100.0f, 100.0f ) );
+
+  DALI_TEST_CHECK( tableView );
+
+  // Create a child actor with the custom properties
+  Actor child1 = Actor::New();
+  child1.SetProperty( TableView::ChildProperty::CELL_INDEX, Vector2( 3, 4 ) );
+  tableView.Add( child1 );
+  // Check for actors at actual positions.
+  DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(3,4)) == child1);
+
+  // Create a second child actor with the custom properties
+  Actor child2 = Actor::New();
+  float rowSpan = 3.f;
+  float columnSpan = 2.f;
+  child2.SetProperty( TableView::ChildProperty::CELL_INDEX, Vector2( 6, 1 ) );
+  child2.SetProperty( TableView::ChildProperty::ROW_SPAN, rowSpan );
+  child2.SetProperty( TableView::ChildProperty::COLUMN_SPAN, columnSpan );
+  tableView.Add( child2 );
+  // Check for actors at actual positions.
+  for( int i=0; i<rowSpan; i++ )
+  {
+    for(int j=0; j<columnSpan; j++)
+    {
+      DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(6+i,1+j)) == child2);
+    }
+  }
+
+  // Create a third child actor with the cell alignment properties
+  Actor child3 = Actor::New();
+  child3.SetSize( 5.f,5.f );
+  child3.SetProperty( TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT, "center" );
+  child3.SetProperty( TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT,   "bottom" );
+  tableView.Add( child3 );
+
+  // store the actor in the first available cell
+  DALI_TEST_CHECK( tableView.GetChildAt(TableView::CellPosition(0,0)) == child3)
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( child3.GetCurrentAnchorPoint(), AnchorPoint::TOP_LEFT, TEST_LOCATION );
+  DALI_TEST_EQUALS( child3.GetCurrentParentOrigin(), ParentOrigin::TOP_LEFT, TEST_LOCATION );
+  DALI_TEST_EQUALS( child3.GetCurrentPosition(), Vector3(2.5f, 5.0f, 0.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewGetChildAtN(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+
+  Actor actor = tableView.GetChildAt( TableView::CellPosition( 200, 200 ) );
+  DALI_TEST_CHECK( !actor );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewAddChildN(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 ) ) );
+  DALI_TEST_CHECK( ! tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 ) ) );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewInsertRowAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.InsertRow(0);
+
+  DALI_TEST_CHECK( tableView.GetRows() == 11 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewDeleteRowAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.DeleteRow(0);
+
+  DALI_TEST_CHECK( tableView.GetRows() == 9 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewInsertColumnAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.InsertColumn(0);
+
+  DALI_TEST_CHECK( tableView.GetColumns() == 11 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewDeleteColumnAtZero(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(10,10);
+  DALI_TEST_CHECK( tableView.AddChild( Actor::New(), TableView::CellPosition( 0, 0 , 10, 10 ) ) );
+  tableView.DeleteColumn(0);
+
+  DALI_TEST_CHECK( tableView.GetColumns() == 9 );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "TableView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  TableView view = TableView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewKeyboardFocus(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(4,4);
+  tableView.SetKeyboardFocusable( true );
+  tableView.SetName( "TableView");
+
+  for ( int row = 0; row < 4; ++row )
+  {
+    for ( int col = 0; col < 4; ++col )
+    {
+      Control control = Control::New();
+      std::ostringstream str;
+      str << row << "-" << col;
+      control.SetName( str.str() );
+      control.SetKeyboardFocusable( true );
+      tableView.AddChild( control, TableView::CellPosition( row, col ) );
+    }
+  }
+
+  Stage::GetCurrent().Add( tableView );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor firstFocusActor = Toolkit::Internal::GetImplementation( tableView ).GetNextKeyboardFocusableActor( Actor(), Control::KeyboardFocus::RIGHT, true );
+  DALI_TEST_CHECK( firstFocusActor );
+  DALI_TEST_CHECK( firstFocusActor.GetName() == "0-0" );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  manager.SetFocusGroupLoop( true );
+  manager.SetCurrentFocusActor( firstFocusActor );
+
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-3" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-0" );
+
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-3" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-3" );
+
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "3-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  END_TEST;
+}
+
+int UtcDaliTableViewKeyboardFocusInNestedTableView(void)
+{
+  ToolkitTestApplication application;
+
+  TableView tableView = TableView::New(3, 3);
+  tableView.SetKeyboardFocusable( true );
+  tableView.SetName( "TableView");
+
+  for ( int row = 0; row < 3; ++row )
+  {
+    for ( int col = 0; col < 3; ++col )
+    {
+      std::ostringstream str;
+      str << row << "-" << col;
+
+      if (row == 1 && col ==1)
+      {
+        // Add a nested 2x2 table view in the middle cell of the parent table view
+        TableView childTableView = TableView::New(2, 2);
+        childTableView.SetName( str.str() );
+
+        for(int childRow = 0; childRow < 2; childRow++)
+        {
+          for(int childCol = 0; childCol < 2; childCol++)
+          {
+            Control control = Control::New();
+            std::ostringstream nameStr;
+            nameStr << row << "-" << col << "-" << childRow << "-" << childCol;
+            control.SetName( nameStr.str() );
+            control.SetKeyboardFocusable( true );
+            childTableView.AddChild( control, TableView::CellPosition( childRow, childCol ) );
+          }
+        }
+        tableView.AddChild( childTableView, TableView::CellPosition( row, col ) );
+      }
+      else
+      {
+        Control control = Control::New();
+        control.SetName( str.str() );
+        control.SetKeyboardFocusable( true );
+        tableView.AddChild( control, TableView::CellPosition( row, col ) );
+      }
+    }
+  }
+
+  Stage::GetCurrent().Add( tableView );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor firstFocusActor = Toolkit::Internal::GetImplementation( tableView ).GetNextKeyboardFocusableActor( Actor(), Control::KeyboardFocus::RIGHT, true );
+  DALI_TEST_CHECK( firstFocusActor );
+  DALI_TEST_CHECK( firstFocusActor.GetName() == "0-0" );
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  manager.SetFocusGroupLoop( false );
+  manager.SetCurrentFocusActor( firstFocusActor );
+
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-2" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-0" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-2" );
+
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-2" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-0" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-2" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::LEFT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-0" );
+
+  manager.MoveFocus( Control::KeyboardFocus::RIGHT );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-0" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-0" );
+  manager.MoveFocus( Control::KeyboardFocus::DOWN );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "2-1" );
+
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-1-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "1-1-0-1" );
+  manager.MoveFocus( Control::KeyboardFocus::UP );
+  DALI_TEST_CHECK( manager.GetCurrentFocusActor().GetName() == "0-1" );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
new file mode 100755 (executable)
index 0000000..91c9a79
--- /dev/null
@@ -0,0 +1,2755 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/adaptor-framework/clipboard.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_texteditor_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_texteditor_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* const PROPERTY_NAME_RENDERING_BACKEND                    = "renderingBackend";
+const char* const PROPERTY_NAME_TEXT                                 = "text";
+const char* const PROPERTY_NAME_TEXT_COLOR                           = "textColor";
+const char* const PROPERTY_NAME_FONT_FAMILY                          = "fontFamily";
+const char* const PROPERTY_NAME_FONT_STYLE                           = "fontStyle";
+const char* const PROPERTY_NAME_POINT_SIZE                           = "pointSize";
+const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT                 = "horizontalAlignment";
+const char* const PROPERTY_NAME_SCROLL_THRESHOLD                     = "scrollThreshold";
+const char* const PROPERTY_NAME_SCROLL_SPEED                         = "scrollSpeed";
+const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR                 = "primaryCursorColor";
+const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR               = "secondaryCursorColor";
+const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK                  = "enableCursorBlink";
+const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL                = "cursorBlinkInterval";
+const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION                = "cursorBlinkDuration";
+const char* const PROPERTY_NAME_CURSOR_WIDTH                         = "cursorWidth";
+const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE                    = "grabHandleImage";
+const char* const PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE            = "grabHandlePressedImage";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT          = "selectionHandleImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT         = "selectionHandleImageRight";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT  = "selectionHandlePressedImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = "selectionHandlePressedImageRight";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT   = "selectionHandleMarkerImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT  = "selectionHandleMarkerImageRight";
+const char* const PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR            = "selectionHighlightColor";
+const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX              = "decorationBoundingBox";
+const char* const PROPERTY_NAME_ENABLE_MARKUP                        = "enableMarkup";
+const char* const PROPERTY_NAME_INPUT_COLOR                          = "inputColor";
+const char* const PROPERTY_NAME_INPUT_FONT_FAMILY                    = "inputFontFamily";
+const char* const PROPERTY_NAME_INPUT_FONT_STYLE                     = "inputFontStyle";
+const char* const PROPERTY_NAME_INPUT_POINT_SIZE                     = "inputPointSize";
+
+const char* const PROPERTY_NAME_LINE_SPACING                         = "lineSpacing";
+const char* const PROPERTY_NAME_INPUT_LINE_SPACING                   = "inputLineSpacing";
+const char* const PROPERTY_NAME_UNDERLINE                            = "underline";
+const char* const PROPERTY_NAME_INPUT_UNDERLINE                      = "inputUnderline";
+const char* const PROPERTY_NAME_SHADOW                               = "shadow";
+const char* const PROPERTY_NAME_INPUT_SHADOW                         = "inputShadow";
+const char* const PROPERTY_NAME_EMBOSS                               = "emboss";
+const char* const PROPERTY_NAME_INPUT_EMBOSS                         = "inputEmboss";
+const char* const PROPERTY_NAME_OUTLINE                              = "outline";
+const char* const PROPERTY_NAME_INPUT_OUTLINE                        = "inputOutline";
+
+const char* const PROPERTY_NAME_SMOOTH_SCROLL                        = "smoothScroll";
+const char* const PROPERTY_NAME_SMOOTH_SCROLL_DURATION               = "smoothScrollDuration";
+const char* const PROPERTY_NAME_ENABLE_SCROLL_BAR                    = "enableScrollBar";
+const char* const PROPERTY_NAME_SCROLL_BAR_SHOW_DURATION             = "scrollBarShowDuration";
+const char* const PROPERTY_NAME_SCROLL_BAR_FADE_DURATION             = "scrollBarFadeDuration";
+const char* const PROPERTY_NAME_PIXEL_SIZE                           = "pixelSize";
+const char* const PROPERTY_NAME_LINE_COUNT                           = "lineCount";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT                     = "placeholderText";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR               = "placeholderTextColor";
+const char* const PROPERTY_NAME_ENABLE_SELECTION                     = "enableSelection";
+const char* const PROPERTY_NAME_PLACEHOLDER                          = "placeholder";
+const char* const PROPERTY_NAME_ENABLE_SHIFT_SELECTION               = "enableShiftSelection";
+const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE                   = "enableGrabHandle";
+const char* const PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION      = "matchSystemLanguageDirection";
+
+
+const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
+const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
+
+const float RENDER_FRAME_INTERVAL = 16.66f;
+
+const unsigned int DEFAULT_FONT_SIZE = 1152u;
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+const int KEY_A_CODE = 38;
+const int KEY_D_CODE = 40;
+const int KEY_C_CODE = 54;
+const int KEY_V_CODE = 55;
+const int KEY_X_CODE = 53;
+const int KEY_WHITE_SPACE_CODE = 65;
+
+const int KEY_SHIFT_MODIFIER = 257;
+const int KEY_CONTROL_MODIFIER = 258;
+
+const char* HANDLE_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insertpoint-icon.png";
+
+const std::string DEFAULT_DEVICE_NAME("hwKeyboard");
+
+static bool gTextChangedCallBackCalled;
+static bool gInputStyleChangedCallbackCalled;
+static Dali::Toolkit::TextEditor::InputStyle::Mask gInputStyleMask;
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+static void TestTextChangedCallback( TextEditor control )
+{
+  tet_infoline(" TestTextChangedCallback");
+
+  gTextChangedCallBackCalled = true;
+}
+
+static void TestInputStyleChangedCallback( TextEditor control, TextEditor::InputStyle::Mask mask )
+{
+  tet_infoline(" TestInputStyleChangedCallback");
+
+  gInputStyleChangedCallbackCalled = true;
+  gInputStyleMask = mask;
+}
+
+// Generate a KeyEvent to send to Core.
+Integration::KeyEvent GenerateKey( const std::string& keyName,
+                                   const std::string& logicalKey,
+                                   const std::string& keyString,
+                                   int keyCode,
+                                   int keyModifier,
+                                   unsigned long timeStamp,
+                                   const Integration::KeyEvent::State& keyState,
+                                   const std::string& compose = "",
+                                   const std::string& deviceName = DEFAULT_DEVICE_NAME,
+                                   const Device::Class::Type& deviceClass = Device::Class::NONE,
+                                   const Device::Subclass::Type& deviceSubclass = Device::Subclass::NONE )
+{
+  return Integration::KeyEvent( keyName,
+                                logicalKey,
+                                keyString,
+                                keyCode,
+                                keyModifier,
+                                timeStamp,
+                                keyState,
+                                compose,
+                                deviceName,
+                                deviceClass,
+                                deviceSubclass );
+}
+
+Dali::Integration::Point GetPointDownInside( Vector2& pos )
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( pos );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpInside( Vector2& pos )
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( pos );
+  return point;
+}
+
+bool DaliTestCheckMaps( const Property::Map& fontStyleMapGet, const Property::Map& fontStyleMapSet )
+{
+  if( fontStyleMapGet.Count() == fontStyleMapSet.Count() )
+  {
+    for( unsigned int index = 0u; index < fontStyleMapGet.Count(); ++index )
+    {
+      const KeyValuePair& valueGet = fontStyleMapGet.GetKeyValue( index );
+
+      Property::Value* valueSet = NULL;
+      if ( valueGet.first.type == Property::Key::INDEX )
+      {
+        valueSet = fontStyleMapSet.Find( valueGet.first.indexKey );
+      }
+      else
+      {
+        // Get Key is a string so searching Set Map for a string key
+        valueSet = fontStyleMapSet.Find( valueGet.first.stringKey );
+      }
+
+      if( NULL != valueSet )
+      {
+        if( valueSet->GetType() == Dali::Property::STRING && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
+        {
+          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::BOOLEAN && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::INTEGER && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::FLOAT && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
+        {
+          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR2 && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
+        {
+          Vector2 vector2Get = valueGet.second.Get<Vector2>();
+          Vector2 vector2Set = valueSet->Get<Vector2>();
+          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR4 && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
+        {
+          Vector4 vector4Get = valueGet.second.Get<Vector4>();
+          Vector4 vector4Set = valueSet->Get<Vector4>();
+          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
+          return false;
+        }
+      }
+      else
+      {
+        if ( valueGet.first.type == Property::Key::INDEX )
+        {
+          tet_printf( "  The key %d doesn't exist.", valueGet.first.indexKey );
+        }
+        else
+        {
+          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
+        }
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+class ScrollStateChangeCallback : public Dali::ConnectionTracker
+{
+public:
+  ScrollStateChangeCallback(bool& startedCalled, bool& finishedCalled)
+  : mStartedCalled( startedCalled ),
+    mFinishedCalled( finishedCalled )
+  {
+  }
+
+  void Callback( TextEditor editor, TextEditor::Scroll::Type type )
+  {
+    if( type == TextEditor::Scroll::STARTED )
+    {
+      mStartedCalled = true;
+    }
+    else if( type == TextEditor::Scroll::FINISHED )
+    {
+      mFinishedCalled = true;
+    }
+  }
+
+  bool& mStartedCalled;
+  bool& mFinishedCalled;
+};
+
+} // namespace
+
+int UtcDaliToolkitTextEditorConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorConstructorP");
+  TextEditor textEditor;
+  DALI_TEST_CHECK( !textEditor );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorNewP");
+  TextEditor textEditor = TextEditor::New();
+  DALI_TEST_CHECK( textEditor );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorDownCastP");
+  TextEditor textEditor1 = TextEditor::New();
+  BaseHandle object( textEditor1 );
+
+  TextEditor textEditor2 = TextEditor::DownCast( object );
+  DALI_TEST_CHECK( textEditor2 );
+
+  TextEditor textEditor3 = DownCast< TextEditor >( object );
+  DALI_TEST_CHECK( textEditor3 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorDownCastN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorDownCastN");
+  BaseHandle uninitializedObject;
+  TextEditor textEditor1 = TextEditor::DownCast( uninitializedObject );
+  DALI_TEST_CHECK( !textEditor1 );
+
+  TextEditor textEditor2 = DownCast< TextEditor >( uninitializedObject );
+  DALI_TEST_CHECK( !textEditor2 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorCopyConstructorP");
+  TextEditor textEditor = TextEditor::New();
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Test" );
+
+  TextEditor copy( textEditor );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextEditor::Property::TEXT ) == textEditor.GetProperty<std::string>( TextEditor::Property::TEXT ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorAssignmentOperatorP");
+  TextEditor textEditor = TextEditor::New();
+  textEditor.SetProperty( TextEditor::Property::TEXT, "Test" );
+
+  TextEditor copy = textEditor;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextEditor::Property::TEXT ) == textEditor.GetProperty<std::string>( TextEditor::Property::TEXT ) );
+  END_TEST;
+}
+
+int UtcDaliTextEditorNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorNewP");
+  TextEditor textEditor = TextEditor::New();
+  DALI_TEST_CHECK( textEditor );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliTextEditorGetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorGetPropertyP");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  // Check Property Indices are correct
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_RENDERING_BACKEND ) == TextEditor::Property::RENDERING_BACKEND );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_TEXT ) == TextEditor::Property::TEXT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_TEXT_COLOR ) == TextEditor::Property::TEXT_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_FONT_FAMILY ) == TextEditor::Property::FONT_FAMILY );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_FONT_STYLE ) == TextEditor::Property::FONT_STYLE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_POINT_SIZE ) == TextEditor::Property::POINT_SIZE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextEditor::Property::HORIZONTAL_ALIGNMENT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_THRESHOLD ) == TextEditor::Property::SCROLL_THRESHOLD );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_SPEED ) == TextEditor::Property::SCROLL_SPEED );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PRIMARY_CURSOR_COLOR ) == TextEditor::Property::PRIMARY_CURSOR_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SECONDARY_CURSOR_COLOR ) == TextEditor::Property::SECONDARY_CURSOR_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_CURSOR_BLINK ) == TextEditor::Property::ENABLE_CURSOR_BLINK );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_INTERVAL ) == TextEditor::Property::CURSOR_BLINK_INTERVAL );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_DURATION ) == TextEditor::Property::CURSOR_BLINK_DURATION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_CURSOR_WIDTH ) == TextEditor::Property::CURSOR_WIDTH );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_IMAGE ) == TextEditor::Property::GRAB_HANDLE_IMAGE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE ) == TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT ) == TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT ) == TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR ) == TextEditor::Property::SELECTION_HIGHLIGHT_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_DECORATION_BOUNDING_BOX ) == TextEditor::Property::DECORATION_BOUNDING_BOX );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_MARKUP ) == TextEditor::Property::ENABLE_MARKUP );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_COLOR ) == TextEditor::Property::INPUT_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_FAMILY ) == TextEditor::Property::INPUT_FONT_FAMILY );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_STYLE ) == TextEditor::Property::INPUT_FONT_STYLE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_POINT_SIZE ) == TextEditor::Property::INPUT_POINT_SIZE );
+
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_LINE_SPACING ) == TextEditor::Property::LINE_SPACING );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_LINE_SPACING ) == TextEditor::Property::INPUT_LINE_SPACING );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_UNDERLINE ) == TextEditor::Property::UNDERLINE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_UNDERLINE ) == TextEditor::Property::INPUT_UNDERLINE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SHADOW ) == TextEditor::Property::SHADOW );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_SHADOW ) == TextEditor::Property::INPUT_SHADOW );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_EMBOSS ) == TextEditor::Property::EMBOSS );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_EMBOSS ) == TextEditor::Property::INPUT_EMBOSS );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_OUTLINE ) == TextEditor::Property::OUTLINE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_INPUT_OUTLINE ) == TextEditor::Property::INPUT_OUTLINE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SMOOTH_SCROLL ) == TextEditor::Property::SMOOTH_SCROLL );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SMOOTH_SCROLL_DURATION ) == TextEditor::Property::SMOOTH_SCROLL_DURATION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_SCROLL_BAR ) == TextEditor::Property::ENABLE_SCROLL_BAR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_BAR_SHOW_DURATION ) == TextEditor::Property::SCROLL_BAR_SHOW_DURATION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_SCROLL_BAR_FADE_DURATION ) == TextEditor::Property::SCROLL_BAR_FADE_DURATION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PIXEL_SIZE ) == TextEditor::Property::PIXEL_SIZE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_LINE_COUNT) == TextEditor::Property::LINE_COUNT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_SELECTION ) == TextEditor::Property::ENABLE_SELECTION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER ) == TextEditor::Property::PLACEHOLDER );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT ) == DevelTextEditor::Property::PLACEHOLDER_TEXT );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR ) == DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_SHIFT_SELECTION ) == DevelTextEditor::Property::ENABLE_SHIFT_SELECTION );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE ) == DevelTextEditor::Property::ENABLE_GRAB_HANDLE );
+  DALI_TEST_CHECK( editor.GetPropertyIndex( PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION ) == DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION );
+
+  END_TEST;
+}
+
+bool SetPropertyMapRetrieved( TextEditor& editor, const Property::Index property, const std::string mapKey, const std::string mapValue )
+{
+  bool result = false;
+  Property::Map imageMap;
+  imageMap[mapKey] =mapValue;
+
+  editor.SetProperty( property , imageMap );
+  Property::Value propValue = editor.GetProperty( property );
+  Property::Map* resultMap = propValue.GetMap();
+
+  if ( resultMap->Find( mapKey )->Get< std::string>() == mapValue )
+  {
+    result = true;
+  }
+
+  return result;
+}
+
+// Positive test case for a method
+int UtcDaliTextEditorSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorSetPropertyP");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+  Stage::GetCurrent().Add( editor );
+
+  // Note - we can't check the defaults since the stylesheets are platform-specific
+
+  // Check the render backend property.
+  editor.SetProperty( TextEditor::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+  DALI_TEST_EQUALS( (Text::RenderingType)editor.GetProperty<int>( TextEditor::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION );
+
+  // Check text property.
+  editor.SetProperty( TextEditor::Property::TEXT, "Setting Text" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
+
+  // Check text's color property
+  editor.SetProperty( TextEditor::Property::TEXT_COLOR, Color::WHITE );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( TextEditor::Property::TEXT_COLOR ), Color::WHITE, TEST_LOCATION );
+
+  // Check font properties.
+  editor.SetProperty( TextEditor::Property::FONT_FAMILY, "Setting font family" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
+
+  Property::Map fontStyleMapSet;
+  Property::Map fontStyleMapGet;
+  Property::Value* slantValue = NULL;
+
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Reset font style.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "normal" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "slant", "roman" );
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::FONT_STYLE );
+
+  // Replace 'roman' for 'normal'.
+  slantValue = fontStyleMapGet.Find( "slant" );
+  if( NULL != slantValue )
+  {
+    if( "normal" == slantValue->Get<std::string>() )
+    {
+      fontStyleMapGet["slant"] = "roman";
+    }
+  }
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Check that the Alignment properties can be correctly set
+  editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "END" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::HORIZONTAL_ALIGNMENT ), "END", TEST_LOCATION );
+
+  // Check scroll properties.
+  editor.SetProperty( TextEditor::Property::SCROLL_THRESHOLD, 1.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_THRESHOLD ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::SCROLL_SPEED, 100.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_SPEED ), 100.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check cursor properties
+  editor.SetProperty( TextEditor::Property::PRIMARY_CURSOR_COLOR, Color::RED );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( TextEditor::Property::PRIMARY_CURSOR_COLOR ), Color::RED, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::SECONDARY_CURSOR_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( TextEditor::Property::SECONDARY_CURSOR_COLOR ), Color::BLUE, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::ENABLE_CURSOR_BLINK, false );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::ENABLE_CURSOR_BLINK ), false, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::CURSOR_BLINK_INTERVAL, 1.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::CURSOR_BLINK_INTERVAL ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::CURSOR_BLINK_DURATION, 10.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::CURSOR_BLINK_DURATION ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::CURSOR_WIDTH, 1 );
+  DALI_TEST_EQUALS( editor.GetProperty<int>( TextEditor::Property::CURSOR_WIDTH ), 1, TEST_LOCATION );
+
+  // Check handle images
+  editor.SetProperty( TextEditor::Property::GRAB_HANDLE_IMAGE, "image1" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::GRAB_HANDLE_IMAGE ), "image1", TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE, "image2" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE ), "image2", TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT, "image3" );
+
+  // Check handle images
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT, "filename", "leftHandleImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT, "filename", "rightHandleImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, "filename", "leftHandleImagePressed" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, "filename", "rightHandleImagePressed" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT, "filename", "leftHandleMarkerImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( editor, TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT, "filename", "rightHandleMarkerImage" )  );
+
+  // Check the highlight color
+  editor.SetProperty( TextEditor::Property::SELECTION_HIGHLIGHT_COLOR, Color::GREEN );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( TextEditor::Property::SELECTION_HIGHLIGHT_COLOR ), Color::GREEN, TEST_LOCATION );
+
+  // Decoration bounding box
+  editor.SetProperty( TextEditor::Property::DECORATION_BOUNDING_BOX, Rect<int>( 0, 0, 1, 1 ) );
+  DALI_TEST_EQUALS( editor.GetProperty<Rect <int > >( TextEditor::Property::DECORATION_BOUNDING_BOX ), Rect<int>( 0, 0, 1, 1 ), TEST_LOCATION );
+
+  // Check the enable markup property.
+  DALI_TEST_CHECK( !editor.GetProperty<bool>( TextEditor::Property::ENABLE_MARKUP ) );
+  editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true );
+  DALI_TEST_CHECK( editor.GetProperty<bool>( TextEditor::Property::ENABLE_MARKUP ) );
+
+  // Check input color property.
+  editor.SetProperty( TextEditor::Property::INPUT_COLOR, Color::YELLOW );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( TextEditor::Property::INPUT_COLOR ), Color::YELLOW, TEST_LOCATION );
+
+  // Check input font properties.
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_FAMILY, "Setting input font family" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_FONT_FAMILY ), "Setting input font family", TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::INPUT_POINT_SIZE, 12.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::INPUT_POINT_SIZE ), 12.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Reset input font style.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "normal" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "slant", "roman" );
+
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+
+  // Replace 'roman' for 'normal'.
+  slantValue = fontStyleMapGet.Find( "slant" );
+  if( NULL != slantValue )
+  {
+    if( "normal" == slantValue->Get<std::string>() )
+    {
+      fontStyleMapGet["slant"] = "roman";
+    }
+  }
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Check the line spacing property
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::LINE_SPACING ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::LINE_SPACING, 10.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::LINE_SPACING ), 10.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the input line spacing property
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::INPUT_LINE_SPACING ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::INPUT_LINE_SPACING, 20.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::INPUT_LINE_SPACING ), 20.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the underline property
+
+  Property::Map underlineMapSet;
+  Property::Map underlineMapGet;
+
+  underlineMapSet.Insert( "enable", true );
+  underlineMapSet.Insert( "color", Color::RED );
+  underlineMapSet.Insert( "height", 1 );
+
+  editor.SetProperty( TextEditor::Property::UNDERLINE, underlineMapSet );
+
+  underlineMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
+
+  // Check the input underline property
+  editor.SetProperty( TextEditor::Property::INPUT_UNDERLINE, "Underline input properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_UNDERLINE ), std::string("Underline input properties"), TEST_LOCATION );
+
+  // Check the shadow property
+  Property::Map shadowMapSet;
+  Property::Map shadowMapGet;
+
+  shadowMapSet.Insert( "color", Color::GREEN );
+  shadowMapSet.Insert( "offset", Vector2(2.0f, 2.0f) );
+  shadowMapSet.Insert( "blurRadius", 3.0f );
+
+  editor.SetProperty( TextEditor::Property::SHADOW, shadowMapSet );
+
+  shadowMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::SHADOW );
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowMapSet ), true, TEST_LOCATION );
+
+  // Check the input shadow property
+  editor.SetProperty( TextEditor::Property::INPUT_SHADOW, "Shadow input properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_SHADOW ), std::string("Shadow input properties"), TEST_LOCATION );
+
+  // Check the emboss property
+  editor.SetProperty( TextEditor::Property::EMBOSS, "Emboss properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::EMBOSS ), std::string("Emboss properties"), TEST_LOCATION );
+
+  // Check the input emboss property
+  editor.SetProperty( TextEditor::Property::INPUT_EMBOSS, "Emboss input properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_EMBOSS ), std::string("Emboss input properties"), TEST_LOCATION );
+
+  // Check the outline property
+
+  // Test string type first
+  // This is purely to maintain backward compatibility, but we don't support string as the outline property type.
+  editor.SetProperty( TextEditor::Property::OUTLINE, "Outline properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::OUTLINE ), std::string("Outline properties"), TEST_LOCATION );
+
+  // Then test the property map type
+  Property::Map outlineMapSet;
+  Property::Map outlineMapGet;
+
+  outlineMapSet["color"] = Color::RED;
+  outlineMapSet["width"] = 2.0f;
+
+  editor.SetProperty( TextEditor::Property::OUTLINE, outlineMapSet );
+
+  outlineMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::OUTLINE );
+  DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
+
+  // Check the input outline property
+  editor.SetProperty( TextEditor::Property::INPUT_OUTLINE, "Outline input properties" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::INPUT_OUTLINE ), std::string("Outline input properties"), TEST_LOCATION );
+
+  // Check the smooth scroll property
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::SMOOTH_SCROLL ), false, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL, true );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::SMOOTH_SCROLL ), true, TEST_LOCATION );
+
+  // Check the smooth scroll duration property
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL_DURATION, 0.2f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SMOOTH_SCROLL_DURATION ), 0.2f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the scroll bar property
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::ENABLE_SCROLL_BAR ), false, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::ENABLE_SCROLL_BAR, true );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::ENABLE_SCROLL_BAR ), true, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::SCROLL_BAR_SHOW_DURATION, 0.3f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_BAR_SHOW_DURATION ), 0.3f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  editor.SetProperty( TextEditor::Property::SCROLL_BAR_FADE_DURATION, 0.2f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_BAR_FADE_DURATION ), 0.2f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the pixel size of font
+  editor.SetProperty( TextEditor::Property::PIXEL_SIZE, 20.f );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::PIXEL_SIZE ), 20.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check placeholder text properties.
+  editor.SetProperty( DevelTextEditor::Property::PLACEHOLDER_TEXT, "Setting Placeholder Text" );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( DevelTextEditor::Property::PLACEHOLDER_TEXT ), std::string("Setting Placeholder Text"), TEST_LOCATION );
+
+  // Check placeholder text's color property.
+  editor.SetProperty( DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR, Color::RED );
+  DALI_TEST_EQUALS( editor.GetProperty<Vector4>( DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR ), Color::RED, TEST_LOCATION );
+
+  // Check the enable selection property
+  editor.SetProperty( TextEditor::Property::ENABLE_SELECTION, false );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::ENABLE_SELECTION ), false, TEST_LOCATION );
+
+  // Check the placeholder property with pixel size
+  Property::Map placeholderPixelSizeMapSet;
+  Property::Map placeholderPixelSizeMapGet;
+  Property::Map placeholderFontstyleMap;
+  placeholderPixelSizeMapSet["text"] = "Setting Placeholder Text";
+  placeholderPixelSizeMapSet["textFocused"] = "Setting Placeholder Text Focused";
+  placeholderPixelSizeMapSet["color"] = Color::BLUE;
+  placeholderPixelSizeMapSet["fontFamily"] = "Arial";
+  placeholderPixelSizeMapSet["pixelSize"] = 15.0f;
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderPixelSizeMapSet["fontStyle"] = placeholderFontstyleMap;
+  editor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderPixelSizeMapSet );
+
+  placeholderPixelSizeMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderPixelSizeMapGet.Count(), placeholderPixelSizeMapSet.Count(), TEST_LOCATION );
+
+  tet_infoline("Test Placeholder settings set as strings is converted correctly to Property Index key and holds set value");
+  Property::Map placeholderConversionMap;
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT ] = placeholderPixelSizeMapSet["text"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = placeholderPixelSizeMapSet["textFocused"] ;
+  placeholderConversionMap[ Text::PlaceHolder::Property::COLOR ] = placeholderPixelSizeMapSet["color"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_FAMILY ] = placeholderPixelSizeMapSet["fontFamily"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::PIXEL_SIZE ] = placeholderPixelSizeMapSet["pixelSize"];
+
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderPixelSizeMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  // Check the placeholder property with point size
+  Property::Map placeholderMapSet;
+  Property::Map placeholderMapGet;
+  placeholderMapSet["text"] = "Setting Placeholder Text";
+  placeholderMapSet["textFocused"] = "Setting Placeholder Text Focused";
+  placeholderMapSet["color"] = Color::RED;
+  placeholderMapSet["fontFamily"] = "Arial";
+  placeholderMapSet["pointSize"] = 12.0f;
+  // Check the placeholder font style property
+  placeholderFontstyleMap.Clear();
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderFontstyleMap.Insert( "width", "condensed" );
+  placeholderFontstyleMap.Insert( "slant", "italic" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  editor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+
+  tet_infoline("Test Placeholder settings set as strings is converted correctly to Property Index key and holds set value");
+  placeholderConversionMap.Clear();
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT ] = placeholderMapSet["text"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = placeholderMapSet["textFocused"] ;
+  placeholderConversionMap[ Text::PlaceHolder::Property::COLOR ] = placeholderMapSet["color"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_FAMILY ] = placeholderMapSet["fontFamily"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::POINT_SIZE ] = placeholderMapSet["pointSize"];
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  // Reset font style.
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "weight", "normal" );
+  placeholderFontstyleMap.Insert( "slant", "oblique" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  editor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderMapSet["fontStyle"];
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "slant", "roman" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  editor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::PLACEHOLDER );
+
+  placeholderFontstyleMap.Clear();
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+
+  editor.SetProperty( TextEditor::Property::PLACEHOLDER, placeholderMapSet );
+  placeholderMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderMapSet["fontStyle"];
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  editor.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT );
+  DALI_TEST_EQUALS( editor.GetProperty<int>( Actor::Property::LAYOUT_DIRECTION ), static_cast<int>( LayoutDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+// Positive Atlas Text Renderer test
+int utcDaliTextEditorAtlasRenderP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorAtlasRenderP");
+  StyleManager styleManager = StyleManager::Get();
+  styleManager.ApplyDefaultTheme();
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( editor );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    editor.SetProperty( TextEditor::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+  END_TEST;
+}
+
+// Positive test for the textChanged signal.
+int utcDaliTextEditorTextChangedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorTextChangedP");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  editor.TextChangedSignal().Connect( &TestTextChangedCallback );
+  bool textChangedSignal = false;
+  editor.ConnectSignal( testTracker, "textChanged",   CallbackFunctor(&textChangedSignal) );
+
+  gTextChangedCallBackCalled = false;
+  editor.SetProperty( TextEditor::Property::TEXT, "ABC" );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_CHECK( textChangedSignal );
+
+  application.SendNotification();
+
+  editor.SetKeyInputFocus();
+
+  gTextChangedCallBackCalled = false;
+  application.ProcessEvent( GenerateKey( "D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorInputStyleChanged01(void)
+{
+  // The text-editor emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  // The ToolkitTestApplication creates an implementation of the adaptor stub and a queue of idle callbacks.
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorInputStyleChanged01");
+
+  // Load some fonts.
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE );
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true );
+  editor.SetProperty( TextEditor::Property::TEXT, "<font family='DejaVuSerif' size='18'>He<color value='green'>llo</color> <font weight='bold'>world</font> demo</font>" );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  editor.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback );
+  bool inputStyleChangedSignal = false;
+  editor.ConnectSignal( testTracker, "inputStyleChanged",   CallbackFunctor(&inputStyleChangedSignal) );
+
+  Stage::GetCurrent().Add( editor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 18.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextEditor::InputStyle::FONT_FAMILY | TextEditor::InputStyle::POINT_SIZE ), TEST_LOCATION );
+
+    const std::string fontFamily = editor.GetProperty( TextEditor::Property::INPUT_FONT_FAMILY ).Get<std::string>();
+    DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION );
+
+    const float pointSize = editor.GetProperty( TextEditor::Property::INPUT_POINT_SIZE ).Get<float>();
+    DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 30.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 43.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextEditor::InputStyle::COLOR ), TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 88.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextEditor::InputStyle::COLOR | TextEditor::InputStyle::FONT_STYLE ), TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+
+    Property::Map fontStyleMapSet;
+    Property::Map fontStyleMapGet;
+
+    fontStyleMapSet.Insert( "weight", "bold" );
+
+    fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+    DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+    DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 115.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 164.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextEditor::InputStyle::FONT_STYLE ), TEST_LOCATION );
+
+    Property::Map fontStyleMapSet;
+    Property::Map fontStyleMapGet;
+
+    fontStyleMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::INPUT_FONT_STYLE );
+    DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+    DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 191.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorInputStyleChanged02(void)
+{
+  // The text-editor emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  // The ToolkitTestApplication creates an implementation of the adaptor stub and a queue of idle callbacks.
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorInputStyleChanged02");
+
+  // Load some fonts.
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE );
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  editor.SetProperty( TextEditor::Property::ENABLE_MARKUP, true );
+  editor.SetProperty( TextEditor::Property::TEXT, "<font family='DejaVuSerif' size='18'>He<color value='blue'> l</color><color value='green'>lo</color> <font weight='bold'>world</font> demo</font>" );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  editor.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback );
+  bool inputStyleChangedSignal = false;
+  editor.ConnectSignal( testTracker, "inputStyleChanged",   CallbackFunctor(&inputStyleChangedSignal) );
+
+  Stage::GetCurrent().Add( editor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 53.0f, 25.0f, 100 );
+  TestGenerateTap( application, 53.0f, 25.0f, 200 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextEditor::InputStyle::FONT_FAMILY |
+                                                 TextEditor::InputStyle::POINT_SIZE  |
+                                                 TextEditor::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION );
+
+    const std::string fontFamily = editor.GetProperty( TextEditor::Property::INPUT_FONT_FAMILY ).Get<std::string>();
+    DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION );
+
+    const float pointSize = editor.GetProperty( TextEditor::Property::INPUT_POINT_SIZE ).Get<float>();
+    DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextEditor::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLUE, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextEditor::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  editor.SetProperty( TextEditor::Property::INPUT_COLOR, Color::YELLOW );
+
+  Property::Map fontStyleMapSet;
+  fontStyleMapSet.Insert( "weight", "thin" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  editor.SetProperty( TextEditor::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  editor.SetProperty( TextEditor::Property::INPUT_POINT_SIZE, 20.f );
+  editor.SetProperty( TextEditor::Property::INPUT_LINE_SPACING, 5.f );
+
+  editor.SetProperty( TextEditor::Property::INPUT_UNDERLINE, "underline" );
+  editor.SetProperty( TextEditor::Property::INPUT_SHADOW, "shadow" );
+  editor.SetProperty( TextEditor::Property::INPUT_EMBOSS, "emboss" );
+  editor.SetProperty( TextEditor::Property::INPUT_OUTLINE, "outline" );
+
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 63.0f, 25.0f, 900 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextEditor::InputStyle::COLOR |
+                                                 TextEditor::InputStyle::POINT_SIZE |
+                                                 TextEditor::InputStyle::FONT_STYLE |
+                                                 TextEditor::InputStyle::LINE_SPACING |
+                                                 TextEditor::InputStyle::UNDERLINE |
+                                                 TextEditor::InputStyle::SHADOW |
+                                                 TextEditor::InputStyle::EMBOSS |
+                                                 TextEditor::InputStyle::OUTLINE ),
+                      TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextEditor::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  editor.SetProperty( TextEditor::Property::FONT_FAMILY, "DejaVuSerif" );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "black" );
+  fontStyleMapSet.Insert( "width", "expanded" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, fontStyleMapSet );
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 30.0f, 25.0f, 1500 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextEditor::InputStyle::COLOR |
+                                                 TextEditor::InputStyle::POINT_SIZE |
+                                                 TextEditor::InputStyle::FONT_STYLE ),
+                      TEST_LOCATION );
+
+    const Vector4 color = editor.GetProperty( TextEditor::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::YELLOW, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent01");
+
+  // Creates a tap event. After creating a tap event the text editor should
+  // have the focus and add text with key events should be possible.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a key event but as the text editor has not the focus it should do nothing.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string(""), TEST_LOCATION );
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Now the text editor has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  // Create a second text editor and send key events to it.
+  TextEditor editor2 = TextEditor::New();
+
+  editor2.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor2.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  editor2.SetSize( 100.f, 100.f );
+  editor2.SetPosition( 100.f, 100.f );
+
+  Stage::GetCurrent().Add( editor2 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event on the second text editor.
+  TestGenerateTap( application, 150.0f, 125.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The second text editor has the focus. It should handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check the text has been added to the second text editor.
+  DALI_TEST_EQUALS( editor2.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent02");
+
+  // Checks if the right number of actors are created.
+
+  TextEditor editor = TextEditor::New();
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check there are the expected number of children (the stencil).
+  DALI_TEST_EQUALS( editor.GetChildCount(), 1u, TEST_LOCATION );
+
+  Actor stencil = editor.GetChildAt( 0u );
+
+  // Create a tap event to touch the text editor.
+  TestGenerateTap( application, 150.0f, 25.0f, 100 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor layer = editor.GetChildAt( 1u );
+  DALI_TEST_CHECK( layer.IsLayer() );
+
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 0u, TEST_LOCATION );
+
+  // Now the text editor has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Checks the cursor and the renderer have been created.
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 1u, TEST_LOCATION ); // The renderer
+
+  Control cursor = Control::DownCast( layer.GetChildAt( 0u ) );
+  DALI_TEST_CHECK( cursor );
+
+  // The stencil actor has a container with all the actors which contain the text renderers.
+  Actor container = stencil.GetChildAt( 0u );
+  for( unsigned int index = 0; index < container.GetChildCount(); ++index )
+  {
+    Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
+    DALI_TEST_CHECK( renderer );
+  }
+
+  // Move the cursor and check the position changes.
+  Vector3 position1 = cursor.GetCurrentPosition();
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position2 = cursor.GetCurrentPosition();
+
+  DALI_TEST_CHECK( position2.x < position1.x );
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position3 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position1, position3, TEST_LOCATION ); // Should be in the same position1.
+
+  // Send some taps and check the cursor positions.
+
+  // Try to tap at the beginning.
+  TestGenerateTap( application, 1.0f, 25.0f, 700 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position1.
+  Vector3 position4 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position2, position4, TEST_LOCATION ); // Should be in the same position2.
+
+  // Tap away from the start position.
+  TestGenerateTap( application, 16.0f, 25.0f, 1400 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position5 = cursor.GetCurrentPosition();
+
+  DALI_TEST_CHECK( position5.x > position4.x );
+
+  // Remove all the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  editor.SetProperty( TextEditor::Property::TEXT, "" );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position2.
+  Vector3 position6 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position2, position6, TEST_LOCATION );// Should be in the same position2.
+
+  // Should not be a renderer.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent03");
+
+  // Checks if the highlight actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "This is a long text for the size of the text-editor." );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 30.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Send some taps and check text controller with clipboard window
+  Dali::Clipboard clipboard = Clipboard::Get();
+  clipboard.ShowClipboard();
+  TestGenerateTap( application, 3.0f, 25.0f, 100 );
+  clipboard.HideClipboard();
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 3.0f, 25.0f, 1000 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 3.0f, 25.0f, 1100 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The stencil actor should have two actors: the renderer and the highlight actor.
+  Actor stencil = editor.GetChildAt( 0u );
+
+  // Highlight needs to be drawn before text, so should come first in child order
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
+  // The stencil actor has a container with all the actors which contain the text renderers.
+  Actor container = stencil.GetChildAt( 1u );
+  for( unsigned int index = 0; index < container.GetChildCount(); ++index )
+  {
+    Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
+    DALI_TEST_CHECK( renderer );
+  }
+
+  // Double tap out of bounds
+  TestGenerateTap( application, 29.0f, 25.0f, 1700 );
+  TestGenerateTap( application, 29.0f, 25.0f, 1800 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The stencil actor should have one actors: the renderer actor.
+  stencil = editor.GetChildAt( 0u );
+
+  // The stencil actor has a container with all the actors which contain the text renderers.
+  container = stencil.GetChildAt( 0u );
+  for( unsigned int index = 0; index < container.GetChildCount(); ++index )
+  {
+    Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
+    DALI_TEST_CHECK( renderer );
+  }
+
+  // Long Press
+  TestGenerateLongPress(application, 1.0f, 25.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent04");
+
+  // Checks if the highlight actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Hello\nworl" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 100.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move at the end of the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  for( unsigned int index = 0u; index < 10u; ++index )
+  {
+    application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+    application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+  }
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "Hello\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Add some key events
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_UP, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_UP, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  for( unsigned int index = 0u; index < 10u; ++index )
+  {
+    application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+    application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+  }
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( " ", "", " ", KEY_WHITE_SPACE_CODE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( " Hello\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent05");
+
+  // Checks if the highlight actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Hello\nworl" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 50.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL, true );
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL_DURATION, 0.2f );
+  editor.SetProperty( TextEditor::Property::ENABLE_SCROLL_BAR, true );
+  editor.SetProperty( TextEditor::Property::SCROLL_BAR_SHOW_DURATION, 0.3f );
+  editor.SetProperty( TextEditor::Property::SCROLL_BAR_FADE_DURATION, 0.2f );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move at the end of the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  for( unsigned int index = 0u; index < 10u; ++index )
+  {
+    // Add a character
+    application.ProcessEvent( GenerateKey( "d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+  }
+  // Modify duration after scroll is enabled
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL_DURATION, 0.1f );
+
+  // Continuous scroll left to increase coverage
+  for( unsigned int index = 0u; index < 10u; ++index )
+  {
+    application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+  }
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SMOOTH_SCROLL_DURATION ), 0.1f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::SMOOTH_SCROLL ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( TextEditor::Property::ENABLE_SCROLL_BAR ), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_BAR_SHOW_DURATION ), 0.3f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( editor.GetProperty<float>( TextEditor::Property::SCROLL_BAR_FADE_DURATION ), 0.2f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Press Escape to increase coverage
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Up, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( !editor.HasKeyInputFocus() );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent06");
+
+  // Checks if the highlight actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Hello\nworld\nHello world" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 100.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move to seconds line of the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  float layoutHeight = editor.GetHeightForWidth( 100.f );
+
+
+  // Add  another script characters ( glyph height is defferent )
+  application.ProcessEvent( GenerateKey( "d", "", "ㅁ", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "ㅁ", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "d", "", "ኢ", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "ኢ", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Delete characters
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  DALI_TEST_EQUALS( layoutHeight, editor.GetHeightForWidth( 100.f ), TEST_LOCATION );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "Hello\nworld\nHello world", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // For coverage
+  application.ProcessEvent( GenerateKey( "", "", "", 0, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_VOLUME_UP, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_VOLUME_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent07(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent07");
+
+  // Checks if the highlight actor is created.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Hello\nworld\nHello world" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 100.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move to second line of the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Select some text in the right of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cut the selected text
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "x", "", "x", KEY_X_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, "x", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "Hello\nld\nHello world", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Select some text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down,  "",DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Copy the selected text
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Move the cursor to the third line
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_DOWN, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Paste the selected text at the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "v", "", "v", KEY_V_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, "v", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+
+  // Disable Shift Selection
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false );
+
+  // Test to select some text in the right of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cut the selected text
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "x", "", "x", KEY_X_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, "x", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The text isn't selected and not changed because of 'SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false )'
+  DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Test to select some text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Copy the selected text
+  application.ProcessEvent( GenerateKey( "", "", "", Dali::DevelKey::DALI_KEY_CONTROL_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, KEY_CONTROL_MODIFIER, 0, Integration::KeyEvent::Down, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The text is not selected and not changed because of 'SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false )'
+  DALI_TEST_EQUALS( "Hello\nld\nHello lo\nworld", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorEvent08(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorEvent08");
+
+  // Checks if the highlight actor is released correctly.
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "DALi" );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 100.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap on the text editor
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // When the left selection handle and the right selection handle are at the same position, the highlight box should be deactivated.
+  // Test to select some text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test to the left selection handle position and the right selection handle position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test to select full text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test to release the current full text selection
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test to move the current cursor position correctly
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "DdALi", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Test to select some text in the right of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test the cursor position with right arrow key
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, 0, 0, Integration::KeyEvent::Down, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "DdALci", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Test to select some text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test the cursor position with left arrow key
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, 0, 0, Integration::KeyEvent::Down, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "DcdALci", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Test to select some text in the right of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test the cursor position with left arrow key
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "x", "", "x", KEY_X_CODE, 0, 0, Integration::KeyEvent::Down, "x", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "DcxdALci", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  // Test to select some text in the left of the current cursor position
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_SHIFT_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, KEY_SHIFT_MODIFIER, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Test the cursor position with right arrow key
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a character
+  application.ProcessEvent( GenerateKey( "c", "", "c", KEY_C_CODE, 0, 0, Integration::KeyEvent::Down, "c", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( "DcxcdALci", editor.GetProperty<std::string>( TextEditor::Property::TEXT ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorHandles(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorHandles");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::TEXT, "This is a long text for the size of the text-editor." );
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetProperty( TextEditor::Property::GRAB_HANDLE_IMAGE, HANDLE_IMAGE_FILE_NAME );
+  editor.SetProperty( TextEditor::Property::SMOOTH_SCROLL, true );
+
+  Property::Map imagePropertyMap;
+  imagePropertyMap["type"] = "BufferImage";
+  imagePropertyMap["width"] = 40;
+  imagePropertyMap["height"] = 40;
+
+  editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT, imagePropertyMap );
+  editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT, imagePropertyMap );
+  editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, imagePropertyMap );
+  editor.SetProperty( TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, imagePropertyMap );
+
+  editor.SetSize( 30.f, 500.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 3.0f, 25.0f, 100 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap to create the grab handle.
+  TestGenerateTap( application, 3.0f, 25.0f, 700 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Get the active layer where the text's decoration is added.
+  Actor activeLayer = editor.GetChildAt( 1u );
+
+  // Get the handle's actor.
+  Actor handle = activeLayer.GetChildAt( 1u );
+  handle.SetSize( 100.f, 100.f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Touch the grab handle to set it as pressed.
+  Vector2 touchPos( 10.0f, 50.0f );
+  Dali::Integration::TouchEvent event;
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside( touchPos ) );
+  application.ProcessEvent( event );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Release the grab handle.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside( touchPos ) );
+  application.ProcessEvent( event );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 3.0f, 25.0f, 1400 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word and create the selection handles.
+  TestGenerateTap( application, 3.0f, 25.0f, 1500 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  touchPos = Vector2( 10.0f, 50.0f );
+
+  // Touch the left selection handle to set it as pressed.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside( touchPos ) );
+  application.ProcessEvent( event );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Release the left selection handle.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside( touchPos ) );
+  application.ProcessEvent( event );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextEditorUnderPropertyStringP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorUnderPropertyStringP");
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  std::string underlineSettings1( "{\"enable\":\"true\",\"color\":\"red\",\"height\":\"1\"}" );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::UNDERLINE, underlineSettings1 );
+  DALI_TEST_EQUALS( editor.GetProperty<std::string>( TextEditor::Property::UNDERLINE ), underlineSettings1, TEST_LOCATION );
+
+  tet_infoline("Set underline settings with a map");
+  // Check the input underline property
+  Property::Map underlineMapSet;
+  Property::Map underlineMapGet;
+  underlineMapSet.Insert( "enable", true );
+  underlineMapSet.Insert( "color", Color::BLUE );
+  underlineMapSet.Insert( "height", 2 );
+
+  editor.SetProperty( TextEditor::Property::UNDERLINE, underlineMapSet );
+  underlineMapGet = editor.GetProperty<Property::Map>( TextEditor::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapSet, underlineMapGet ), true,  TEST_LOCATION );
+
+  tet_infoline("Set underline settings with a string");
+  editor.SetProperty( TextEditor::Property::UNDERLINE, underlineSettings1 );
+  Property::Value value = editor.GetProperty( TextEditor::Property::UNDERLINE );
+  std::string result;
+  value.Get(result);
+  DALI_TEST_EQUALS( result , underlineSettings1, TEST_LOCATION  );
+
+  tet_infoline("Trying to set invalid underline settings, should not update and stay at previous settings");
+  std::string underlineSettingsVoid( "{\"enable\":\"true\",\"coooolor\":\"blue\",\"heeeight\":\"4\"}" );
+  editor.SetProperty( TextEditor::Property::UNDERLINE, underlineSettingsVoid );
+  value = editor.GetProperty( TextEditor::Property::UNDERLINE );
+  value.Get(result);
+  DALI_TEST_EQUALS( result , underlineSettings1, TEST_LOCATION  );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorShadowPropertyStringP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorUnderPropertyStringP Setting Shadow propeties by string");
+
+  TextEditor editor = TextEditor::New();
+
+  std::string shadowSettings( "{\"color\":\"green\",\"offset\":\"2 2\",\"blurRadius\":\"0\"}" );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::SHADOW, "{\"color\":\"green\",\"offset\":\"2 2\",\"blurRadius\":\"0\"}" );
+
+  Property::Value value = editor.GetProperty<std::string>( TextEditor::Property::SHADOW );
+  std::string result;
+  value.Get(result);
+
+  DALI_TEST_EQUALS( result, shadowSettings, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorFontStylePropertyStringP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextEditorFontStylePropertyStringP Setting FontStyle propeties by string");
+
+  TextEditor editor = TextEditor::New();
+
+  std::string fontStyleSettings( "{\"weight\":\"bold\",\"width\":\"condensed\",\"slant\":\"italic\"}" );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::FONT_STYLE, "{\"weight\":\"bold\",\"width\":\"condensed\",\"slant\":\"italic\"}" );
+
+  Property::Value value = editor.GetProperty<std::string>( TextEditor::Property::FONT_STYLE );
+  std::string result;
+  value.Get(result);
+
+  DALI_TEST_EQUALS( result, fontStyleSettings, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorGetPropertyLinecountP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" utcDaliTextEditorGetPropertyLinecount getting line count property");
+
+  int lineCount =0 ;
+
+  TextEditor editor = TextEditor::New();
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10) ;
+  editor.SetProperty( TextEditor::Property::TEXT,
+                       "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ");
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetSize( 100.0f, 100.0f );
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 14, TEST_LOCATION );
+
+  editor.SetSize( 50.0f, 100.0f );
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 28, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextEditorScrollStateChangedSignalTest(void)
+{
+
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorScrollStateChangedSignalTest");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::POINT_SIZE, 10.f );
+  editor.SetSize( 50.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  editor.SetProperty( TextEditor::Property::ENABLE_SCROLL_BAR, true );
+  editor.SetKeyboardFocusable(true);
+
+  bool startedCalled = false;
+  bool finishedCalled = false;
+
+  ScrollStateChangeCallback callback( startedCalled, finishedCalled );
+  editor.ScrollStateChangedSignal().Connect( &callback, &ScrollStateChangeCallback::Callback );
+
+  KeyboardFocusManager::Get().SetCurrentFocusActor( editor );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  editor.SetProperty( TextEditor::Property::TEXT, "Long enough message for TextEditor!");
+  application.SendNotification();
+  application.Render(6000);
+
+  application.SendNotification();
+  DALI_TEST_EQUALS( startedCalled, true, TEST_LOCATION );
+  DALI_TEST_EQUALS( finishedCalled, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextEditorTextWrapMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextEditorTextWarpMode");
+
+  int lineCount =0 ;
+
+  TextEditor editor = TextEditor::New();
+  editor.SetSize( 150.0f, 300.f );
+  editor.SetProperty( TextEditor::Property::TEXT, "Hello world Hello world" );
+
+  Stage::GetCurrent().Add( editor );
+
+  editor.SetProperty( TextEditor::Property::LINE_WRAP_MODE, "WORD" );
+  DALI_TEST_EQUALS( editor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::WORD ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 4, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::LINE_WRAP_MODE, "CHARACTER" );
+  DALI_TEST_EQUALS( editor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::CHARACTER ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::LINE_WRAP_MODE, Text::LineWrap::WORD );
+  DALI_TEST_EQUALS( editor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::WORD ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 4, TEST_LOCATION );
+
+  editor.SetProperty( TextEditor::Property::LINE_WRAP_MODE, Text::LineWrap::CHARACTER );
+  DALI_TEST_EQUALS( editor.GetProperty< int >( TextEditor::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::CHARACTER ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  editor.GetProperty<int>( TextEditor::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 3, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorSetPaddingProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorSetPaddingProperty\n");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( editor );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 originalSize = editor.GetNaturalSize();
+
+  editor.SetProperty( Toolkit::Control::Property::PADDING, Extents( 10, 10, 10, 10 ) );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( editor.GetProperty<Extents>( Toolkit::Control::Property::PADDING ), Extents( 10, 10, 10, 10 ), TEST_LOCATION );
+
+  Vector3 paddingAddedSize = editor.GetNaturalSize();
+
+  DALI_TEST_EQUALS( originalSize.width + 10 + 10 , paddingAddedSize.width, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( originalSize.height + 10 + 10 , paddingAddedSize.height, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorEnableShiftSelectionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorEnableShiftSelectionProperty");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( editor );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of ENABLE_SHIFT_SELECTION is 'true'.
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION ), true, TEST_LOCATION );
+
+  // Check the enable shift selection property
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION, false );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_SHIFT_SELECTION ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorEnableGrabHandleProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorEnableGrabHandleProperty");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( editor );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of ENABLE_GRAB_HANDLE is 'true'.
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_GRAB_HANDLE ), true, TEST_LOCATION );
+
+  // Check the enable grab handle property
+  editor.SetProperty( DevelTextEditor::Property::ENABLE_GRAB_HANDLE, false );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::ENABLE_GRAB_HANDLE ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorMatchSystemLanguageDirectionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorMatchSystemLanguageDirectionProperty");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+  editor.SetSize( 300.f, 50.f );
+  editor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  editor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( editor );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of MATCH_SYSTEM_LANGUAGE_DIRECTION is 'false'.
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION ), false, TEST_LOCATION );
+
+  // Check the enable match system language direction property
+  editor.SetProperty( DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, true );
+  DALI_TEST_EQUALS( editor.GetProperty<bool>( DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorGetInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorGetInputMethodContext");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( DevelTextEditor::GetInputMethodContext( editor ) );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
new file mode 100755 (executable)
index 0000000..7e050ff
--- /dev/null
@@ -0,0 +1,2874 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
+#include "toolkit-clipboard.h"
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_textfield_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_textfield_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* const PROPERTY_NAME_RENDERING_BACKEND                    = "renderingBackend";
+const char* const PROPERTY_NAME_TEXT                                 = "text";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT                     = "placeholderText";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_FOCUSED             = "placeholderTextFocused";
+const char* const PROPERTY_NAME_FONT_FAMILY                          = "fontFamily";
+const char* const PROPERTY_NAME_FONT_STYLE                           = "fontStyle";
+const char* const PROPERTY_NAME_POINT_SIZE                           = "pointSize";
+const char* const PROPERTY_NAME_MAX_LENGTH                           = "maxLength";
+const char* const PROPERTY_NAME_EXCEED_POLICY                        = "exceedPolicy";
+const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT                 = "horizontalAlignment";
+const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT                   = "verticalAlignment";
+const char* const PROPERTY_NAME_TEXT_COLOR                           = "textColor";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR               = "placeholderTextColor";
+const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR                 = "primaryCursorColor";
+const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR               = "secondaryCursorColor";
+const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK                  = "enableCursorBlink";
+const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL                = "cursorBlinkInterval";
+const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION                = "cursorBlinkDuration";
+const char* const PROPERTY_NAME_CURSOR_WIDTH                         = "cursorWidth";
+const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE                    = "grabHandleImage";
+const char* const PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE            = "grabHandlePressedImage";
+const char* const PROPERTY_NAME_SCROLL_THRESHOLD                     = "scrollThreshold";
+const char* const PROPERTY_NAME_SCROLL_SPEED                         = "scrollSpeed";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT          = "selectionHandleImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT         = "selectionHandleImageRight";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT  = "selectionHandlePressedImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = "selectionHandlePressedImageRight";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT   = "selectionHandleMarkerImageLeft";
+const char* const PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT  = "selectionHandleMarkerImageRight";
+const char* const PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR            = "selectionHighlightColor";
+const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX              = "decorationBoundingBox";
+const char* const PROPERTY_NAME_INPUT_METHOD_SETTINGS                = "inputMethodSettings";
+const char* const PROPERTY_NAME_INPUT_COLOR                          = "inputColor";
+const char* const PROPERTY_NAME_ENABLE_MARKUP                        = "enableMarkup";
+const char* const PROPERTY_NAME_INPUT_FONT_FAMILY                    = "inputFontFamily";
+const char* const PROPERTY_NAME_INPUT_FONT_STYLE                     = "inputFontStyle";
+const char* const PROPERTY_NAME_INPUT_POINT_SIZE                     = "inputPointSize";
+
+const char* const PROPERTY_NAME_UNDERLINE                            = "underline";
+const char* const PROPERTY_NAME_INPUT_UNDERLINE                      = "inputUnderline";
+const char* const PROPERTY_NAME_SHADOW                               = "shadow";
+const char* const PROPERTY_NAME_INPUT_SHADOW                         = "inputShadow";
+const char* const PROPERTY_NAME_EMBOSS                               = "emboss";
+const char* const PROPERTY_NAME_INPUT_EMBOSS                         = "inputEmboss";
+const char* const PROPERTY_NAME_OUTLINE                              = "outline";
+const char* const PROPERTY_NAME_INPUT_OUTLINE                        = "inputOutline";
+
+const char* const PROPERTY_NAME_HIDDEN_INPUT_SETTINGS                = "hiddenInputSettings";
+const char* const PROPERTY_NAME_PIXEL_SIZE                           = "pixelSize";
+const char* const PROPERTY_NAME_ENABLE_SELECTION                     = "enableSelection";
+const char* const PROPERTY_NAME_PLACEHOLDER                          = "placeholder";
+const char* const PROPERTY_NAME_ELLIPSIS                             = "ellipsis";
+const char* const PROPERTY_NAME_ENABLE_SHIFT_SELECTION               = "enableShiftSelection";
+const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE                   = "enableGrabHandle";
+const char* const PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION      = "matchSystemLanguageDirection";
+const char* const PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP             = "enableGrabHandlePopup";
+const char* const PROPERTY_NAME_BACKGROUND                           = "textBackground";
+
+const Vector4 PLACEHOLDER_TEXT_COLOR( 0.8f, 0.8f, 0.8f, 0.8f );
+const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color.
+
+const float RENDER_FRAME_INTERVAL = 16.66f;
+
+const unsigned int DEFAULT_FONT_SIZE = 1152u;
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+const int KEY_RETURN_CODE = 36;
+const int KEY_A_CODE = 38;
+const int KEY_D_CODE = 40;
+
+const std::string DEFAULT_DEVICE_NAME("hwKeyboard");
+
+static bool gTextChangedCallBackCalled;
+static bool gMaxCharactersCallBackCalled;
+static bool gInputStyleChangedCallbackCalled;
+static Dali::Toolkit::TextField::InputStyle::Mask gInputStyleMask;
+
+static void LoadBitmapResource(TestPlatformAbstraction& platform, int width, int height)
+{
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+  Integration::ResourcePointer resource(bitmap);
+  bitmap->GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGBA8888, width, height, width, height);
+}
+
+static void LoadMarkerImages(ToolkitTestApplication& app, TextField textField)
+{
+  int width(40);
+  int height(40);
+  LoadBitmapResource( app.GetPlatform(), width, height );
+
+  Property::Map propertyMap;
+  propertyMap["filename"] = "image.png";
+  propertyMap["width"] = width;
+  propertyMap["height"] = height;
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::GRAB_HANDLE_IMAGE, propertyMap );
+  textField.SetProperty( Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE, propertyMap );
+}
+
+/*
+ * Simulate time passed by.
+ *
+ * @note this will always process at least 1 frame (1/60 sec)
+ *
+ * @param application Test application instance
+ * @param duration Time to pass in milliseconds.
+ * @return The actual time passed in milliseconds
+ */
+static int Wait(ToolkitTestApplication& application, int duration = 0)
+{
+  int time = 0;
+
+  for(int i = 0; i <= ( duration / RENDER_FRAME_INTERVAL); i++)
+  {
+    application.SendNotification();
+    application.Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+
+  return time;
+}
+
+Dali::Integration::Point GetPointDownInside( Vector2& pos )
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( pos );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpInside( Vector2& pos )
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( pos );
+  return point;
+}
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+static void TestTextChangedCallback( TextField control )
+{
+  tet_infoline(" TestTextChangedCallback");
+
+  gTextChangedCallBackCalled = true;
+}
+
+static void TestMaxLengthReachedCallback( TextField control )
+{
+  tet_infoline(" TestMaxLengthReachedCallback");
+
+  gMaxCharactersCallBackCalled = true;
+}
+
+static void TestInputStyleChangedCallback( TextField control, TextField::InputStyle::Mask mask )
+{
+  tet_infoline(" TestInputStyleChangedCallback");
+
+  gInputStyleChangedCallbackCalled = true;
+  gInputStyleMask = mask;
+}
+
+// Generate a KeyEvent to send to Core.
+Integration::KeyEvent GenerateKey( const std::string& keyName,
+                                   const std::string& logicalKey,
+                                   const std::string& keyString,
+                                   int keyCode,
+                                   int keyModifier,
+                                   unsigned long timeStamp,
+                                   const Integration::KeyEvent::State& keyState,
+                                   const std::string& compose = "",
+                                   const std::string& deviceName = DEFAULT_DEVICE_NAME,
+                                   const Device::Class::Type& deviceClass = Device::Class::NONE,
+                                   const Device::Subclass::Type& deviceSubclass = Device::Subclass::NONE )
+{
+  return Integration::KeyEvent( keyName,
+                                logicalKey,
+                                keyString,
+                                keyCode,
+                                keyModifier,
+                                timeStamp,
+                                keyState,
+                                compose,
+                                deviceName,
+                                deviceClass,
+                                deviceSubclass );
+}
+
+bool DaliTestCheckMaps( const Property::Map& fontStyleMapGet, const Property::Map& fontStyleMapSet )
+{
+  if( fontStyleMapGet.Count() == fontStyleMapSet.Count() )
+  {
+    for( unsigned int index = 0u; index < fontStyleMapGet.Count(); ++index )
+    {
+      const KeyValuePair& valueGet = fontStyleMapGet.GetKeyValue( index );
+
+      Property::Value* valueSet = NULL;
+      if ( valueGet.first.type == Property::Key::INDEX )
+      {
+        valueSet = fontStyleMapSet.Find( valueGet.first.indexKey );
+      }
+      else
+      {
+        // Get Key is a string so searching Set Map for a string key
+        valueSet = fontStyleMapSet.Find( valueGet.first.stringKey );
+      }
+
+      if( NULL != valueSet )
+      {
+        if( valueSet->GetType() == Dali::Property::STRING && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
+        {
+          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::BOOLEAN && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::INTEGER && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::FLOAT && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
+        {
+          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR2 && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
+        {
+          Vector2 vector2Get = valueGet.second.Get<Vector2>();
+          Vector2 vector2Set = valueSet->Get<Vector2>();
+          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR4 && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
+        {
+          Vector4 vector4Get = valueGet.second.Get<Vector4>();
+          Vector4 vector4Set = valueSet->Get<Vector4>();
+          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
+          return false;
+        }
+      }
+      else
+      {
+        if ( valueGet.first.type == Property::Key::INDEX )
+        {
+          tet_printf( "  The key %d doesn't exist.", valueGet.first.indexKey );
+        }
+        else
+        {
+          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
+        }
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+int UtcDaliToolkitTextFieldConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldConstructorP");
+  TextField textField;
+  DALI_TEST_CHECK( !textField );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextFieldNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldNewP");
+  TextField textField = TextField::New();
+  DALI_TEST_CHECK( textField );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextFieldDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldDownCastP");
+  TextField textField1 = TextField::New();
+  BaseHandle object( textField1 );
+
+  TextField textField2 = TextField::DownCast( object );
+  DALI_TEST_CHECK( textField2 );
+
+  TextField textField3 = DownCast< TextField >( object );
+  DALI_TEST_CHECK( textField3 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextFieldDownCastN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldDownCastN");
+  BaseHandle uninitializedObject;
+  TextField textField1 = TextField::DownCast( uninitializedObject );
+  DALI_TEST_CHECK( !textField1 );
+
+  TextField textField2 = DownCast< TextField >( uninitializedObject );
+  DALI_TEST_CHECK( !textField2 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextFieldCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldCopyConstructorP");
+  TextField textField = TextField::New();
+  textField.SetProperty( TextField::Property::TEXT, "Test" );
+
+  TextField copy( textField );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextLabel::Property::TEXT ) == textField.GetProperty<std::string>( TextLabel::Property::TEXT ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextFieldAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldAssignmentOperatorP");
+  TextField textField = TextField::New();
+  textField.SetProperty( TextField::Property::TEXT, "Test" );
+
+  TextField copy = textField;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<std::string>( TextField::Property::TEXT ) == textField.GetProperty<std::string>( TextField::Property::TEXT ) );
+  END_TEST;
+}
+
+int UtcDaliTextFieldNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldNewP");
+  TextField textField = TextField::New();
+  DALI_TEST_CHECK( textField );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliTextFieldGetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldGetPropertyP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  // Check Property Indices are correct
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_RENDERING_BACKEND ) == TextField::Property::RENDERING_BACKEND );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_TEXT ) == TextField::Property::TEXT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT ) == TextField::Property::PLACEHOLDER_TEXT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_FOCUSED ) == TextField::Property::PLACEHOLDER_TEXT_FOCUSED );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_FONT_FAMILY ) == TextField::Property::FONT_FAMILY );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_FONT_STYLE ) == TextField::Property::FONT_STYLE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_POINT_SIZE ) == TextField::Property::POINT_SIZE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_MAX_LENGTH ) == TextField::Property::MAX_LENGTH );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_EXCEED_POLICY ) == TextField::Property::EXCEED_POLICY );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextField::Property::HORIZONTAL_ALIGNMENT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_VERTICAL_ALIGNMENT ) == TextField::Property::VERTICAL_ALIGNMENT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_TEXT_COLOR ) == TextField::Property::TEXT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER_TEXT_COLOR ) == TextField::Property::PLACEHOLDER_TEXT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PRIMARY_CURSOR_COLOR ) == TextField::Property::PRIMARY_CURSOR_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SECONDARY_CURSOR_COLOR ) == TextField::Property::SECONDARY_CURSOR_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_CURSOR_BLINK ) == TextField::Property::ENABLE_CURSOR_BLINK );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_INTERVAL ) == TextField::Property::CURSOR_BLINK_INTERVAL );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_CURSOR_BLINK_DURATION ) == TextField::Property::CURSOR_BLINK_DURATION );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_CURSOR_WIDTH ) == TextField::Property::CURSOR_WIDTH );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_IMAGE ) == TextField::Property::GRAB_HANDLE_IMAGE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_GRAB_HANDLE_PRESSED_IMAGE ) == TextField::Property::GRAB_HANDLE_PRESSED_IMAGE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SCROLL_THRESHOLD ) == TextField::Property::SCROLL_THRESHOLD );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SCROLL_SPEED ) == TextField::Property::SCROLL_SPEED );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_LEFT ) == TextField::Property::SELECTION_HANDLE_IMAGE_LEFT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_IMAGE_RIGHT ) == TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_LEFT ) == TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_PRESSED_IMAGE_RIGHT ) == TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_LEFT ) == TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HANDLE_MARKER_IMAGE_RIGHT ) == TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SELECTION_HIGHLIGHT_COLOR ) == TextField::Property::SELECTION_HIGHLIGHT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_DECORATION_BOUNDING_BOX ) == TextField::Property::DECORATION_BOUNDING_BOX );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_METHOD_SETTINGS ) == TextField::Property::INPUT_METHOD_SETTINGS );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_COLOR ) == TextField::Property::INPUT_COLOR );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_MARKUP ) == TextField::Property::ENABLE_MARKUP );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_FAMILY ) == TextField::Property::INPUT_FONT_FAMILY );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_FONT_STYLE ) == TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_POINT_SIZE ) == TextField::Property::INPUT_POINT_SIZE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_UNDERLINE ) == TextField::Property::UNDERLINE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_UNDERLINE ) == TextField::Property::INPUT_UNDERLINE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_SHADOW ) == TextField::Property::SHADOW );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_SHADOW ) == TextField::Property::INPUT_SHADOW );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_EMBOSS ) == TextField::Property::EMBOSS );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_EMBOSS ) == TextField::Property::INPUT_EMBOSS );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_OUTLINE ) == TextField::Property::OUTLINE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_INPUT_OUTLINE ) == TextField::Property::INPUT_OUTLINE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_HIDDEN_INPUT_SETTINGS ) == TextField::Property::HIDDEN_INPUT_SETTINGS );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PIXEL_SIZE ) == TextField::Property::PIXEL_SIZE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_SELECTION ) == TextField::Property::ENABLE_SELECTION );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_PLACEHOLDER ) == TextField::Property::PLACEHOLDER );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS ) == TextField::Property::ELLIPSIS );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_SHIFT_SELECTION ) == DevelTextField::Property::ENABLE_SHIFT_SELECTION );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE ) == DevelTextField::Property::ENABLE_GRAB_HANDLE );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_MATCH_SYSTEM_LANGUAGE_DIRECTION ) == DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_ENABLE_GRAB_HANDLE_POPUP ) == DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP );
+  DALI_TEST_CHECK( field.GetPropertyIndex( PROPERTY_NAME_BACKGROUND ) == DevelTextField::Property::BACKGROUND );
+
+  END_TEST;
+}
+
+bool SetPropertyMapRetrieved( TextField& field, const Property::Index property, const std::string mapKey, const std::string mapValue )
+{
+  bool result = false;
+  Property::Map imageMap;
+  imageMap[mapKey] =mapValue;
+
+  field.SetProperty( property , imageMap );
+  Property::Value propValue = field.GetProperty( property );
+  Property::Map* resultMap = propValue.GetMap();
+
+  if ( resultMap->Find( mapKey )->Get< std::string>() == mapValue )
+  {
+    result = true;
+  }
+
+  return result;
+}
+
+// Positive test case for a method
+int UtcDaliTextFieldSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldSetPropertyP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+
+  // Note - we can't check the defaults since the stylesheets are platform-specific
+
+  // Check the render backend property.
+  field.SetProperty( TextField::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+  DALI_TEST_EQUALS( (Text::RenderingType)field.GetProperty<int>( TextField::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION );
+
+  // Check text property.
+  field.SetProperty( TextField::Property::TEXT, "Setting Text" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
+
+  // Check placeholder text properties.
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Setting Placeholder Text" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT ), std::string("Setting Placeholder Text"), TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_FOCUSED, "Setting Placeholder Text Focused" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::PLACEHOLDER_TEXT_FOCUSED ), std::string("Setting Placeholder Text Focused"), TEST_LOCATION );
+
+  // Check font properties.
+  field.SetProperty( TextField::Property::FONT_FAMILY, "Setting font family" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
+
+  Property::Map fontStyleMapSet;
+  Property::Map fontStyleMapGet;
+  Property::Value* slantValue = NULL;
+
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Reset font style.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "normal" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "slant", "roman" );
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+
+  // Replace 'roman' for 'normal'.
+  slantValue = fontStyleMapGet.Find( "slant" );
+  if( NULL != slantValue )
+  {
+    if( "normal" == slantValue->Get<std::string>() )
+    {
+      fontStyleMapGet["slant"] = "roman";
+    }
+  }
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Check that the MAX_LENGTH property can be correctly set
+  const int maxNumberOfCharacters = 20;
+  field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
+  DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::MAX_LENGTH ), maxNumberOfCharacters, TEST_LOCATION );
+
+  // Check exceed policy
+  field.SetProperty( TextField::Property::EXCEED_POLICY, Dali::Toolkit::TextField::EXCEED_POLICY_CLIP );
+  DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::EXCEED_POLICY ), static_cast<int>( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP ), TEST_LOCATION );
+  field.SetProperty( TextField::Property::EXCEED_POLICY, Dali::Toolkit::TextField::EXCEED_POLICY_ORIGINAL );
+  DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::EXCEED_POLICY ), static_cast<int>( Dali::Toolkit::TextField::EXCEED_POLICY_ORIGINAL ), TEST_LOCATION );
+
+  // Check that the Alignment properties can be correctly set
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "END" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::HORIZONTAL_ALIGNMENT ), "END", TEST_LOCATION );
+  field.SetProperty( TextField::Property::VERTICAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::VERTICAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+
+  // Check text's color property
+  field.SetProperty( TextField::Property::TEXT_COLOR, Color::WHITE );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::TEXT_COLOR ), Color::WHITE, TEST_LOCATION );
+
+  // Check placeholder text's color property.
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_COLOR, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PLACEHOLDER_TEXT_COLOR ), Color::RED, TEST_LOCATION );
+
+  // Check cursor properties
+  field.SetProperty( TextField::Property::PRIMARY_CURSOR_COLOR, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::PRIMARY_CURSOR_COLOR ), Color::RED, TEST_LOCATION );
+  field.SetProperty( TextField::Property::SECONDARY_CURSOR_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SECONDARY_CURSOR_COLOR ), Color::BLUE, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::ENABLE_CURSOR_BLINK, false );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( TextField::Property::ENABLE_CURSOR_BLINK ), false, TEST_LOCATION );
+  field.SetProperty( TextField::Property::CURSOR_BLINK_INTERVAL, 1.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_INTERVAL ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  field.SetProperty( TextField::Property::CURSOR_BLINK_DURATION, 10.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::CURSOR_BLINK_DURATION ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  field.SetProperty( TextField::Property::CURSOR_WIDTH, 1 );
+  DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::CURSOR_WIDTH ), 1, TEST_LOCATION );
+
+  // Check scroll properties.
+  field.SetProperty( TextField::Property::SCROLL_THRESHOLD, 1.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_THRESHOLD ), 1.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  field.SetProperty( TextField::Property::SCROLL_SPEED, 100.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::SCROLL_SPEED ), 100.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check handle images
+  field.SetProperty( TextField::Property::GRAB_HANDLE_IMAGE, "image1" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::GRAB_HANDLE_IMAGE ), "image1", TEST_LOCATION );
+  field.SetProperty( TextField::Property::GRAB_HANDLE_PRESSED_IMAGE, "image2" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::GRAB_HANDLE_PRESSED_IMAGE ), "image2", TEST_LOCATION );
+  field.SetProperty( TextField::Property::SELECTION_HANDLE_IMAGE_LEFT, "image3" );
+
+  // Check handle images
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_IMAGE_LEFT, "filename", "leftHandleImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT, "filename", "rightHandleImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT, "filename", "leftHandleImagePressed" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, "filename", "rightHandleImagePressed" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT, "filename", "leftHandleMarkerImage" )  );
+  DALI_TEST_CHECK( SetPropertyMapRetrieved( field, TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT, "filename", "rightHandleMarkerImage" )  );
+
+  // Check the highlight color
+  field.SetProperty( TextField::Property::SELECTION_HIGHLIGHT_COLOR, Color::GREEN );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::SELECTION_HIGHLIGHT_COLOR ), Color::GREEN, TEST_LOCATION );
+
+  // Decoration bounding box
+  field.SetProperty( TextField::Property::DECORATION_BOUNDING_BOX, Rect<int>( 0, 0, 1, 1 ) );
+  DALI_TEST_EQUALS( field.GetProperty<Rect <int > >( TextField::Property::DECORATION_BOUNDING_BOX ), Rect<int>( 0, 0, 1, 1 ), TEST_LOCATION );
+
+  // Check the input method setting
+  Property::Map propertyMap;
+  InputMethod::PanelLayout::Type panelLayout = InputMethod::PanelLayout::NUMBER;
+  InputMethod::AutoCapital::Type autoCapital = InputMethod::AutoCapital::WORD;
+  InputMethod::ButtonAction::Type buttonAction = InputMethod::ButtonAction::GO;
+  int inputVariation = 1;
+  propertyMap["PANEL_LAYOUT"] = panelLayout;
+  propertyMap["AUTO_CAPITALIZE"] = autoCapital;
+  propertyMap["BUTTON_ACTION"] = buttonAction;
+  propertyMap["VARIATION"] = inputVariation;
+  field.SetProperty( TextField::Property::INPUT_METHOD_SETTINGS, propertyMap );
+
+  Property::Value value = field.GetProperty( TextField::Property::INPUT_METHOD_SETTINGS );
+  Property::Map map;
+  DALI_TEST_CHECK( value.Get( map ) );
+
+  int layout = 0;
+  DALI_TEST_CHECK( map[ "PANEL_LAYOUT" ].Get( layout ) );
+  DALI_TEST_EQUALS( static_cast<int>(panelLayout), layout, TEST_LOCATION );
+
+  int capital = 0;
+  DALI_TEST_CHECK( map[ "AUTO_CAPITALIZE" ].Get( capital ) );
+  DALI_TEST_EQUALS( static_cast<int>(autoCapital), capital, TEST_LOCATION );
+
+  int action = 0;
+  DALI_TEST_CHECK( map[ "BUTTON_ACTION" ].Get( action ) );
+  DALI_TEST_EQUALS( static_cast<int>(buttonAction), action, TEST_LOCATION );
+
+  int variation = 0;
+  DALI_TEST_CHECK( map[ "VARIATION" ].Get( variation ) );
+  DALI_TEST_EQUALS( inputVariation, variation, TEST_LOCATION );
+
+  // Check input color property.
+  field.SetProperty( TextField::Property::INPUT_COLOR, Color::YELLOW );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::INPUT_COLOR ), Color::YELLOW, TEST_LOCATION );
+
+  // Check the enable markup property.
+  DALI_TEST_CHECK( !field.GetProperty<bool>( TextField::Property::ENABLE_MARKUP ) );
+  field.SetProperty( TextField::Property::ENABLE_MARKUP, true );
+  DALI_TEST_CHECK( field.GetProperty<bool>( TextField::Property::ENABLE_MARKUP ) );
+
+  // Check input font properties.
+  field.SetProperty( TextField::Property::INPUT_FONT_FAMILY, "Setting input font family" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_FONT_FAMILY ), "Setting input font family", TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::INPUT_POINT_SIZE, 12.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::INPUT_POINT_SIZE ), 12.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Reset input font style.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "normal" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "slant", "roman" );
+
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+
+  // Replace 'roman' for 'normal'.
+  slantValue = fontStyleMapGet.Find( "slant" );
+  if( NULL != slantValue )
+  {
+    if( "normal" == slantValue->Get<std::string>() )
+    {
+      fontStyleMapGet["slant"] = "roman";
+    }
+  }
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  Property::Map underlineMapSet;
+  Property::Map underlineMapGet;
+
+  underlineMapSet.Insert( "enable", true );
+  underlineMapSet.Insert( "color", Color::RED );
+  underlineMapSet.Insert( "height", 1 );
+
+  // Check the underline property
+  field.SetProperty( TextField::Property::UNDERLINE, underlineMapSet );
+
+  underlineMapGet = field.GetProperty<Property::Map>( TextField::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
+
+  // Check the input underline property
+  field.SetProperty( TextField::Property::INPUT_UNDERLINE, "Underline input properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_UNDERLINE ), std::string("Underline input properties"), TEST_LOCATION );
+
+  // Check the shadow property
+  Property::Map shadowMapSet;
+  Property::Map shadowMapGet;
+
+  shadowMapSet.Insert( "color", Color::GREEN );
+  shadowMapSet.Insert( "offset", Vector2(2.0f, 2.0f) );
+  shadowMapSet.Insert( "blurRadius", 3.0f );
+
+  field.SetProperty( TextField::Property::SHADOW, shadowMapSet );
+
+  shadowMapGet = field.GetProperty<Property::Map>( TextField::Property::SHADOW );
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowMapSet ), true, TEST_LOCATION );
+
+  // Check the input shadow property
+  field.SetProperty( TextField::Property::INPUT_SHADOW, "Shadow input properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_SHADOW ), std::string("Shadow input properties"), TEST_LOCATION );
+
+  // Check the emboss property
+  field.SetProperty( TextField::Property::EMBOSS, "Emboss properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::EMBOSS ), std::string("Emboss properties"), TEST_LOCATION );
+
+  // Check the input emboss property
+  field.SetProperty( TextField::Property::INPUT_EMBOSS, "Emboss input properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_EMBOSS ), std::string("Emboss input properties"), TEST_LOCATION );
+
+  // Check the outline property
+
+  // Test string type first
+  // This is purely to maintain backward compatibility, but we don't support string as the outline property type.
+  field.SetProperty( TextField::Property::OUTLINE, "Outline properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::OUTLINE ), std::string("Outline properties"), TEST_LOCATION );
+
+  // Then test the property map type
+  Property::Map outlineMapSet;
+  Property::Map outlineMapGet;
+
+  outlineMapSet["color"] = Color::RED;
+  outlineMapSet["width"] = 2.0f;
+
+  field.SetProperty( TextField::Property::OUTLINE, outlineMapSet );
+
+  outlineMapGet = field.GetProperty<Property::Map>( TextField::Property::OUTLINE );
+  DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
+
+  // Check the input outline property
+  field.SetProperty( TextField::Property::INPUT_OUTLINE, "Outline input properties" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_OUTLINE ), std::string("Outline input properties"), TEST_LOCATION );
+
+  // Check the hidden input settings property
+  Property::Map hiddenMapSet;
+  Property::Map hiddenMapGet;
+  hiddenMapSet[ HiddenInput::Property::MODE ] = HiddenInput::Mode::HIDE_ALL;
+  hiddenMapSet[ HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION ] = 2;
+  hiddenMapSet[ HiddenInput::Property::SUBSTITUTE_COUNT ] = 4;
+  hiddenMapSet[ HiddenInput::Property::SUBSTITUTE_CHARACTER ] = 0x23;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, hiddenMapSet );
+
+  hiddenMapGet = field.GetProperty<Property::Map>( TextField::Property::HIDDEN_INPUT_SETTINGS );
+  DALI_TEST_EQUALS( hiddenMapSet.Count(), hiddenMapGet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( hiddenMapSet, hiddenMapGet ), true, TEST_LOCATION );
+
+  // Check the pixel size of font
+  field.SetProperty( TextField::Property::PIXEL_SIZE, 20.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::PIXEL_SIZE ), 20.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the enable selection property
+  field.SetProperty( TextField::Property::ENABLE_SELECTION, false );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( TextField::Property::ENABLE_SELECTION ), false, TEST_LOCATION );
+
+  // Check the placeholder property with pixel size
+  Property::Map placeholderPixelSizeMapSet;
+  Property::Map placeholderPixelSizeMapGet;
+  Property::Map placeholderFontstyleMap;
+  placeholderPixelSizeMapSet["text"] = "Setting Placeholder Text";
+  placeholderPixelSizeMapSet["textFocused"] = "Setting Placeholder Text Focused";
+  placeholderPixelSizeMapSet["color"] = Color::BLUE;
+  placeholderPixelSizeMapSet["fontFamily"] = "Arial";
+  placeholderPixelSizeMapSet["pixelSize"] = 15.0f;
+  placeholderPixelSizeMapSet["ellipsis"] = true;
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderPixelSizeMapSet["placeholderFontStyle"] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderPixelSizeMapSet );
+
+  placeholderPixelSizeMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderPixelSizeMapGet.Count(), placeholderPixelSizeMapSet.Count(), TEST_LOCATION );
+
+  tet_infoline("Test Placeholder settings set as strings is converted correctly to Property Index key and holds set value");
+  Property::Map placeholderConversionMap;
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT ] = placeholderPixelSizeMapSet["text"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = placeholderPixelSizeMapSet["textFocused"] ;
+  placeholderConversionMap[ Text::PlaceHolder::Property::COLOR ] = placeholderPixelSizeMapSet["color"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_FAMILY ] = placeholderPixelSizeMapSet["fontFamily"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::PIXEL_SIZE ] = placeholderPixelSizeMapSet["pixelSize"];
+
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderPixelSizeMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  // Check the placeholder property with point size
+  Property::Map placeholderMapSet;
+  Property::Map placeholderMapGet;
+  placeholderMapSet["text"] = "Setting Placeholder Text";
+  placeholderMapSet["textFocused"] = "Setting Placeholder Text Focused";
+  placeholderMapSet["color"] = Color::RED;
+  placeholderMapSet["fontFamily"] = "Arial";
+  placeholderMapSet["pointSize"] = 12.0f;
+  placeholderMapSet["ellipsis"] = false;
+
+  // Check the placeholder font style property
+  placeholderFontstyleMap.Clear();
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderFontstyleMap.Insert( "width", "condensed" );
+  placeholderFontstyleMap.Insert( "slant", "italic" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+
+  placeholderConversionMap.Clear();
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT ] = placeholderPixelSizeMapSet["text"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = placeholderPixelSizeMapSet["textFocused"] ;
+  placeholderConversionMap[ Text::PlaceHolder::Property::COLOR ] = placeholderPixelSizeMapSet["color"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_FAMILY ] = placeholderPixelSizeMapSet["fontFamily"];
+  placeholderConversionMap[ Text::PlaceHolder::Property::POINT_SIZE ] = placeholderPixelSizeMapSet["pointSize"];
+
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  // Reset font style.
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "weight", "normal" );
+  placeholderFontstyleMap.Insert( "slant", "oblique" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "slant", "roman" );
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+
+  placeholderFontstyleMap.Clear();
+  placeholderMapSet["fontStyle"] = placeholderFontstyleMap;
+  placeholderConversionMap[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderPixelSizeMapSet["fontStyle"];
+
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderConversionMap ), true, TEST_LOCATION );
+
+  // Check the ellipsis property
+  DALI_TEST_CHECK( !field.GetProperty<bool>( TextField::Property::ELLIPSIS ) );
+  field.SetProperty( TextField::Property::ELLIPSIS, true );
+  DALI_TEST_CHECK( field.GetProperty<bool>( TextField::Property::ELLIPSIS ) );
+
+  field.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT );
+  DALI_TEST_EQUALS( field.GetProperty<int>( Actor::Property::LAYOUT_DIRECTION ), static_cast<int>( LayoutDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  // Test the ENABLE_GRAB_HANDLE_POPUP property
+  DALI_TEST_CHECK( field.GetProperty<bool>( DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP ) );
+  field.SetProperty( DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP, false );
+  DALI_TEST_CHECK( !field.GetProperty<bool>( DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP ) );
+
+  // Check the background property
+  field.SetProperty( DevelTextField::Property::BACKGROUND, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( DevelTextField::Property::BACKGROUND ), Color::RED, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+// Positive Atlas Text Renderer test
+int utcDaliTextFieldAtlasRenderP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextFieldAtlasRenderP");
+  StyleManager styleManager = StyleManager::Get();
+  styleManager.ApplyDefaultTheme();
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( field );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    field.SetProperty( TextField::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+  END_TEST;
+}
+
+// Positive test for the textChanged signal.
+int utcDaliTextFieldTextChangedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+  bool textChangedSignal = false;
+  field.ConnectSignal( testTracker, "textChanged",   CallbackFunctor(&textChangedSignal) );
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::TEXT, "ABC" );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+  DALI_TEST_CHECK( textChangedSignal );
+
+  application.SendNotification();
+
+  field.SetKeyInputFocus();
+
+  gTextChangedCallBackCalled = false;
+  application.ProcessEvent( GenerateKey( "D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  DALI_TEST_CHECK( gTextChangedCallBackCalled );
+
+  END_TEST;
+}
+
+// Negative test for the textChanged signal.
+int utcDaliTextFieldTextChangedN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldTextChangedN");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.TextChangedSignal().Connect(&TestTextChangedCallback);
+  bool textChangedSignal = false;
+  field.ConnectSignal( testTracker, "textChanged",   CallbackFunctor(&textChangedSignal) );
+
+  gTextChangedCallBackCalled = false;
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "ABC" ); // Setting placeholder, not TEXT
+  DALI_TEST_CHECK( !gTextChangedCallBackCalled );
+  DALI_TEST_CHECK( !textChangedSignal );
+
+  END_TEST;
+}
+
+// Positive test for Max Characters reached signal.
+int utcDaliTextFieldMaxCharactersReachedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldMaxCharactersReachedP");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  const int maxNumberOfCharacters = 1;
+  field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
+
+  field.SetKeyInputFocus();
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback);
+  bool maxLengthReachedSignal = false;
+  field.ConnectSignal( testTracker, "maxLengthReached",   CallbackFunctor(&maxLengthReachedSignal) );
+
+  gMaxCharactersCallBackCalled = false;
+
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  DALI_TEST_CHECK( gMaxCharactersCallBackCalled );
+  DALI_TEST_CHECK( maxLengthReachedSignal );
+
+  END_TEST;
+}
+
+// Negative test for Max Characters reached signal.
+int utcDaliTextFieldMaxCharactersReachedN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldMaxCharactersReachedN");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  const int maxNumberOfCharacters = 3;
+  field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
+
+  field.SetKeyInputFocus();
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.MaxLengthReachedSignal().Connect(&TestMaxLengthReachedCallback);
+  bool maxLengthReachedSignal = false;
+  field.ConnectSignal( testTracker, "maxLengthReached",   CallbackFunctor(&maxLengthReachedSignal) );
+
+  gMaxCharactersCallBackCalled = false;
+
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  DALI_TEST_CHECK( !gMaxCharactersCallBackCalled );
+  DALI_TEST_CHECK( !maxLengthReachedSignal );
+
+  application.ProcessEvent( GenerateKey( "Return", "", "\r", KEY_RETURN_CODE, 0, 0, Integration::KeyEvent::Down, "\r", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  DALI_TEST_CHECK( !gMaxCharactersCallBackCalled );
+  DALI_TEST_CHECK( !maxLengthReachedSignal );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldInputStyleChanged01(void)
+{
+  // The text-field emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  // The ToolkitTestApplication creates an implementation of the adaptor stub and a queue of idle callbacks.
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldInputStyleChanged01");
+
+  // Load some fonts.
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE );
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  field.SetProperty( TextField::Property::ENABLE_MARKUP, true );
+  field.SetProperty( TextField::Property::TEXT, "<font family='DejaVuSerif' size='18'>He<color value='green'>llo</color> <font weight='bold'>world</font> demo</font>" );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback );
+  bool inputStyleChangedSignal = false;
+  field.ConnectSignal( testTracker, "inputStyleChanged",   CallbackFunctor(&inputStyleChangedSignal) );
+
+  Stage::GetCurrent().Add( field );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 18.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextField::InputStyle::FONT_FAMILY | TextField::InputStyle::POINT_SIZE ), TEST_LOCATION );
+
+    const std::string fontFamily = field.GetProperty( TextField::Property::INPUT_FONT_FAMILY ).Get<std::string>();
+    DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION );
+
+    const float pointSize = field.GetProperty( TextField::Property::INPUT_POINT_SIZE ).Get<float>();
+    DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 30.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 43.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextField::InputStyle::COLOR ), TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 88.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextField::InputStyle::COLOR | TextField::InputStyle::FONT_STYLE ), TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+
+    const Property::Map fontStyleMapGet = field.GetProperty( TextField::Property::INPUT_FONT_STYLE ).Get<Property::Map>();
+
+    Property::Map fontStyleMapSet;
+    fontStyleMapSet.Insert( "weight", "bold" );
+
+    DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+    DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 115.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 164.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ), static_cast<unsigned int>( TextField::InputStyle::FONT_STYLE ), TEST_LOCATION );
+
+    const std::string style = field.GetProperty( TextField::Property::INPUT_FONT_STYLE ).Get<std::string>();
+    DALI_TEST_CHECK( style.empty() );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 191.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldInputStyleChanged02(void)
+{
+  // The text-field emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  // The ToolkitTestApplication creates an implementation of the adaptor stub and a queue of idle callbacks.
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldInputStyleChanged02");
+
+  // Load some fonts.
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 93u, 93u );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif.ttf", DEFAULT_FONT_SIZE );
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSerif-Bold.ttf", DEFAULT_FONT_SIZE );
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  field.SetProperty( TextField::Property::ENABLE_MARKUP, true );
+  field.SetProperty( TextField::Property::TEXT, "<font family='DejaVuSerif' size='18'>He<color value='blue'> l</color><color value='green'>lo</color> <font weight='bold'>world</font> demo</font>" );
+
+  // connect to the text changed signal.
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  field.InputStyleChangedSignal().Connect( &TestInputStyleChangedCallback );
+  bool inputStyleChangedSignal = false;
+  field.ConnectSignal( testTracker, "inputStyleChanged",   CallbackFunctor(&inputStyleChangedSignal) );
+
+  Stage::GetCurrent().Add( field );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 53.0f, 25.0f, 100 );
+  TestGenerateTap( application, 53.0f, 25.0f, 200 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextField::InputStyle::FONT_FAMILY |
+                                                 TextField::InputStyle::POINT_SIZE  |
+                                                 TextField::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::GREEN, TEST_LOCATION );
+
+    const std::string fontFamily = field.GetProperty( TextField::Property::INPUT_FONT_FAMILY ).Get<std::string>();
+    DALI_TEST_EQUALS( fontFamily, "DejaVuSerif", TEST_LOCATION );
+
+    const float pointSize = field.GetProperty( TextField::Property::INPUT_POINT_SIZE ).Get<float>();
+    DALI_TEST_EQUALS( pointSize, 18.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextField::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLUE, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextField::InputStyle::COLOR ),
+                      TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  gInputStyleChangedCallbackCalled = false;
+  gInputStyleMask = TextField::InputStyle::NONE;
+  inputStyleChangedSignal = false;
+
+  field.SetProperty( TextField::Property::INPUT_COLOR, Color::YELLOW );
+
+  Property::Map fontStyleMapSet;
+  fontStyleMapSet.Insert( "weight", "thin" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+  field.SetProperty( TextField::Property::INPUT_POINT_SIZE, 20.f );
+
+  field.SetProperty( TextField::Property::INPUT_UNDERLINE, "underline" );
+  field.SetProperty( TextField::Property::INPUT_SHADOW, "shadow" );
+  field.SetProperty( TextField::Property::INPUT_EMBOSS, "emboss" );
+  field.SetProperty( TextField::Property::INPUT_OUTLINE, "outline" );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( !gInputStyleChangedCallbackCalled );
+  DALI_TEST_CHECK( !inputStyleChangedSignal );
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 63.0f, 25.0f, 300 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Executes the idle callbacks added by the text control on the change of input style.
+  application.RunIdles();
+
+  DALI_TEST_CHECK( gInputStyleChangedCallbackCalled );
+  if( gInputStyleChangedCallbackCalled )
+  {
+    DALI_TEST_EQUALS( static_cast<unsigned int>( gInputStyleMask ),
+                      static_cast<unsigned int>( TextField::InputStyle::COLOR |
+                                                 TextField::InputStyle::POINT_SIZE |
+                                                 TextField::InputStyle::FONT_STYLE |
+                                                 TextField::InputStyle::UNDERLINE |
+                                                 TextField::InputStyle::SHADOW |
+                                                 TextField::InputStyle::EMBOSS |
+                                                 TextField::InputStyle::OUTLINE ),
+                      TEST_LOCATION );
+
+    const Vector4 color = field.GetProperty( TextField::Property::INPUT_COLOR ).Get<Vector4>();
+    DALI_TEST_EQUALS( color, Color::BLACK, TEST_LOCATION );
+  }
+  DALI_TEST_CHECK( inputStyleChangedSignal );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent01");
+
+  // Creates a tap event. After creating a tap event the text field should
+  // have the focus and add text with key events should be possible.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a key event but as the text field has not the focus it should do nothing.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string(""), TEST_LOCATION );
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Pressing delete key should be fine even if there is no text in TextField.
+  application.ProcessEvent( GenerateKey( "Delete", "", "Delete", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::Down, "Delete", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Now the text field has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  // Create a second text field and send key events to it.
+  TextField field2 = TextField::New();
+
+  field2.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field2.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  field2.SetSize( 100.f, 100.0f );
+  field2.SetPosition( 100.0f, 100.0f );
+
+  Stage::GetCurrent().Add( field2 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event on the second text field.
+  TestGenerateTap( application, 150.0f, 125.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The second text field has the focus. It should handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check the text has been added to the second text field.
+  DALI_TEST_EQUALS( field2.GetProperty<std::string>( TextField::Property::TEXT ), std::string("aa"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent02");
+
+  // Checks if the right number of actors are created.
+
+  TextField field = TextField::New();
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  DALI_TEST_CHECK( field );
+  LoadMarkerImages(application, field);
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.0f, 50.0f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Check there are the expected number of children ( stencil ).
+  DALI_TEST_EQUALS( field.GetChildCount(), 1u, TEST_LOCATION );
+
+  Actor stencil = field.GetChildAt( 0u );
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 0u, TEST_LOCATION );
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f, 300 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor layer = field.GetChildAt( 1u );
+  DALI_TEST_CHECK( layer.IsLayer() );
+
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 0u, TEST_LOCATION );
+
+  // Now the text field has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Checks the cursor and the renderer have been created.
+  DALI_TEST_EQUALS( layer.GetChildCount(), 1u, TEST_LOCATION ); // The cursor.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 1u, TEST_LOCATION ); // The renderer
+
+  Control cursor = Control::DownCast( layer.GetChildAt( 0u ) );
+  DALI_TEST_CHECK( cursor );
+
+  // The offscreen root actor has a container with all the actors which contain the text renderers.
+  Actor container = stencil.GetChildAt( 0u );
+  for( unsigned int index = 0; index < container.GetChildCount(); ++index )
+  {
+    Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
+    DALI_TEST_CHECK( renderer );
+  }
+
+  // Move the cursor and check the position changes.
+  Vector3 position1 = cursor.GetCurrentPosition();
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position2 = cursor.GetCurrentPosition();
+  DALI_TEST_CHECK( position2.x < position1.x );
+
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_RIGHT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position3 = cursor.GetCurrentPosition();
+  DALI_TEST_EQUALS( position1, position3, TEST_LOCATION ); // Should be in the same position1.
+
+
+  // Move the cursor to the first position.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_CURSOR_LEFT, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position4 = cursor.GetCurrentPosition();
+
+  // Send some taps and check the cursor positions.
+
+  // Try to tap at the beginning.
+  TestGenerateTap( application, 1.0f, 25.0f, 900 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position1.
+  Vector3 position5 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position4, position5, TEST_LOCATION ); // Should be in the same position2.
+
+  // Tap away from the start position.
+  TestGenerateTap( application, 16.0f, 25.0f, 1500 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Vector3 position6 = cursor.GetCurrentPosition();
+
+  DALI_TEST_CHECK( position6.x > position5.x );
+
+  // Remove all the text.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  field.SetProperty( TextField::Property::TEXT, "" );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Cursor position should be the same than position2.
+  Vector3 position7 = cursor.GetCurrentPosition();
+
+  DALI_TEST_EQUALS( position4, position7, TEST_LOCATION );// Should be in the same position2.
+
+  // Should not be a renderer.
+  DALI_TEST_EQUALS( stencil.GetChildCount(), 0u, TEST_LOCATION );
+
+  // Chanege exceed policy (EXCEED_POLICY_ORIGINAL doesn't use stencil )
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetProperty( TextField::Property::EXCEED_POLICY, Dali::Toolkit::TextField::EXCEED_POLICY_ORIGINAL );
+
+  application.SendNotification();
+  application.Render();
+
+  // There are renderer and decorator layer
+  DALI_TEST_EQUALS( field.GetChildCount(), 2u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent03");
+
+  // Checks if the highlight actor is created.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 30.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  LoadMarkerImages(application, field);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 3.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The offscreen root actor should have two actors: the renderer and the highlight actor.
+  Actor stencil = field.GetChildAt( 0u );
+
+  // The highlight actor is drawn first, so is the first actor in the list
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
+  // The offscreen root actor has a container with all the actors which contain the text renderers.
+  Actor container = stencil.GetChildAt( 1u );
+  for( unsigned int index = 0; index < container.GetChildCount(); ++index )
+  {
+    Renderer renderer = container.GetChildAt( index ).GetRendererAt( 0u );
+    DALI_TEST_CHECK( renderer );
+  }
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent04(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent04");
+
+  // Checks if the highlight actor is created.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap grab handle
+  TestGenerateTap( application, 0.0f, 40.0f );
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent05(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent05");
+
+  // Checks dragging of cursor/grab handle
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor stencil = field.GetChildAt( 1u );
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent06(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent06");
+
+  // Checks Longpress when in edit mode
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "Thisisalongtextforthesizeofthetextfield." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Long Press
+  TestGenerateLongPress(application, 1.0f, 25.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent07(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent07");
+
+  // Checks Longpress to start edit mode
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "Thisisalongtextforthesizeofthetextfield." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Property::Map propertyMap;
+  propertyMap["PANEL_LAYOUT"] = InputMethod::PanelLayout::PASSWORD;
+  field.SetProperty( TextField::Property::INPUT_METHOD_SETTINGS, propertyMap );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Long Press
+  TestGenerateLongPress(application, 1.0f, 25.0f);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent08(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent08");
+
+  Dali::Clipboard clipboard = Clipboard::Get();
+  clipboard.SetItem("testTextFieldEvent");
+
+  // Checks Longpress when only place holder text
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Setting Placeholder Text" );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Long Press
+  TestGenerateLongPress( application, 1.0f, 25.0f, 20 );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Wait(application, 500);
+
+  TestEndLongPress( application, 1.0f, 25.0f, 520 );
+
+  // Long Press
+  TestGenerateLongPress( application, 1.0f, 25.0f, 600 );
+
+  // Render and notify
+  application.Render();
+
+  Wait(application, 500);
+
+  Stage stage = Stage::GetCurrent();
+  Layer layer = stage.GetRootLayer();
+  Actor actor = layer.FindChildByName("optionPaste");
+
+  if (actor)
+  {
+    Vector3 worldPosition = actor.GetCurrentWorldPosition();
+    Vector2 halfStageSize = stage.GetSize() / 2.0f;
+    Vector2 position(worldPosition.x + halfStageSize.width, worldPosition.y + halfStageSize.height);
+
+    Dali::Integration::TouchEvent event;
+    event = Dali::Integration::TouchEvent();
+    event.AddPoint( GetPointDownInside( position ) );
+    application.ProcessEvent( event );
+
+    event = Dali::Integration::TouchEvent();
+    event.AddPoint( GetPointUpInside( position ) );
+    application.ProcessEvent( event );
+  }
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextEditor::Property::TEXT ), std::string("testTextFieldEvent"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEvent09(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEvent09");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "Hello" );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+  application.SendNotification();
+  application.Render();
+
+  Property::Map map;
+  map[ HiddenInput::Property::MODE ] = HiddenInput::Mode::HIDE_NONE;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  map[ HiddenInput::Property::MODE ] = HiddenInput::Mode::HIDE_ALL;
+  map[ HiddenInput::Property::SUBSTITUTE_CHARACTER ] = 0x23;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  map[ HiddenInput::Property::MODE ] = HiddenInput::Mode::HIDE_COUNT;
+  map[ HiddenInput::Property::SUBSTITUTE_COUNT ] = 2;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  for( unsigned int index = 0u; index < 5u; ++index )
+  {
+    application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+    application.SendNotification();
+    application.Render();
+  }
+
+  map[ HiddenInput::Property::MODE ] = HiddenInput::Mode::SHOW_COUNT;
+  map[ HiddenInput::Property::SUBSTITUTE_COUNT ] = 2;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  for( unsigned int index = 0u; index < 5u; ++index )
+  {
+    application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+    application.SendNotification();
+    application.Render();
+  }
+
+  map[ HiddenInput::Property::MODE ] = HiddenInput::Mode::SHOW_LAST_CHARACTER;
+  map[ HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION ] = 0;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+  application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  map[ HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION ] = 100;
+  field.SetProperty( TextField::Property::HIDDEN_INPUT_SETTINGS, map );
+  application.ProcessEvent( GenerateKey( "d", "", "d", 0, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  Property::Map mapGet;
+  mapGet = field.GetProperty<Property::Map>( TextField::Property::HIDDEN_INPUT_SETTINGS );
+  DALI_TEST_EQUALS( map.Count(), mapGet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( map, mapGet ), true, TEST_LOCATION );
+  END_TEST;
+}
+
+
+int utcDaliTextFieldStyleWhilstSelected(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldStyleWhilstSelected");
+
+  // Change font and styles whilst text is selected whilst word selected
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::TEXT, "This is a long text for the size of the text-field." );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  field.SetProperty( TextField::Property::INPUT_FONT_FAMILY, "Setting input font family" );
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::INPUT_FONT_FAMILY ), "Setting input font family", TEST_LOCATION );
+
+  Property::Map fontStyleMapSet;
+  Property::Map fontStyleMapGet;
+
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "width", "expanded" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+  field.SetProperty( TextField::Property::INPUT_FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::INPUT_FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::INPUT_POINT_SIZE, 12.f );
+  DALI_TEST_EQUALS( field.GetProperty<float>( TextField::Property::INPUT_POINT_SIZE ), 12.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  field.SetProperty( TextField::Property::TEXT_COLOR, Color::RED );
+  DALI_TEST_EQUALS( field.GetProperty<Vector4>( TextField::Property::TEXT_COLOR ), Color::RED, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "width", "expanded" );
+
+  field.SetProperty( TextField::Property::FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Press Escape to increase coverage
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Up, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( !field.HasKeyInputFocus() );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldEscKeyLoseFocus(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldEscKeyLoseFocus");
+
+  // Creates a tap event. After creating a tap event the text field should
+  // have the focus and add text with key events should be possible.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Add a key event but as the text field has not the focus it should do nothing.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Up, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string(""), TEST_LOCATION );
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Now the text field has the focus, so it can handle the key events.
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Up, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::Down, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "d", "", "d", KEY_D_CODE, 0, 0, Integration::KeyEvent::Up, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("ad"), TEST_LOCATION );
+
+  // Generate a Esc key event. The text field should lose the focus.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Up, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( false, field.HasKeyInputFocus(), TEST_LOCATION );
+
+  // No more text should be introduced
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "a", "", "a", KEY_A_CODE, 0, 0, Integration::KeyEvent::Up, "a", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), std::string("ad"), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldSomeSpecialKeys(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldSomeSpecialKeys");
+
+  // Checks some special keys when the text is selected.
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+  LoadMarkerImages(application, field);
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  const std::string longText( "This is a long text for the size of the text-field." );
+
+  field.SetProperty( TextField::Property::TEXT, longText );
+  field.SetProperty( TextField::Property::POINT_SIZE, 10.f );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Tap first to get the focus.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Double tap to select a word.
+  TestGenerateTap( application, 1.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Generate a Esc key event. The text field should lose the focus.
+  application.ProcessEvent( GenerateKey( "XF86PowerOff", "", "XF86PowerOff", DALI_KEY_POWER, 0, 0, Integration::KeyEvent::Down, "XF86PowerOff", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "XF86PowerOff", "", "XF86PowerOff", DALI_KEY_POWER, 0, 0, Integration::KeyEvent::Up, "XF86PowerOff", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Generate a Esc key event. The text field should lose the focus.
+  application.ProcessEvent( GenerateKey( "XF86Menu", "", "XF86Menu", DALI_KEY_MENU, 0, 0, Integration::KeyEvent::Down, "XF86Menu", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "XF86Menu", "", "XF86Menu", DALI_KEY_MENU, 0, 0, Integration::KeyEvent::Up, "XF86Menu", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Generate a Esc key event. The text field should lose the focus.
+  application.ProcessEvent( GenerateKey( "XF86Home", "", "XF86Home", DALI_KEY_HOME, 0, 0, Integration::KeyEvent::Down, "XF86Home", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "XF86Home", "", "XF86Home", DALI_KEY_HOME, 0, 0, Integration::KeyEvent::Up, "XF86Home", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // The text shouldn't be deleted.
+  DALI_TEST_EQUALS( field.GetProperty<std::string>( TextField::Property::TEXT ), longText, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldSizeUpdate(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("utcDaliTextFieldSizeUpdate");
+
+  // Checks some special keys when the text is selected.
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+
+  float previousHeight = 0.0f;
+  float currentHeight = 0.0f;
+  const float fieldWidth = 1920.0f;
+
+
+  // "ㅁ" is bigger then "ኢ"
+  field.SetSize( Vector2( fieldWidth ,10.0f ) );
+  field.SetResizePolicy( ResizePolicy::FIXED , Dimension::WIDTH );
+  field.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY , Dimension::HEIGHT );
+
+  field.SetProperty( TextField::Property::TEXT, "ኢ");
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  field.SetKeyboardFocusable(true);
+  KeyboardFocusManager::Get().SetCurrentFocusActor( field );
+
+  application.SendNotification();
+  application.Render();
+
+  previousHeight = field.GetHeightForWidth( fieldWidth );
+  DALI_TEST_EQUALS( previousHeight, field.GetProperty<float>( Actor::Property::SIZE_HEIGHT ) , TEST_LOCATION );
+
+  // Add  another script characters ( glyph height is defferent )
+  application.ProcessEvent( GenerateKey( "ㅁ", "", "ㅁ", KEY_A_CODE, 0, 0, Integration::KeyEvent::Down, "ㅁ", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "ㅁ", "", "ㅁ", KEY_A_CODE, 0, 0, Integration::KeyEvent::Up, "ㅁ", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  application.SendNotification();
+  application.Render();
+
+  currentHeight = field.GetHeightForWidth( fieldWidth );
+  DALI_TEST_EQUALS( currentHeight, field.GetProperty<float>( Actor::Property::SIZE_HEIGHT ), TEST_LOCATION );
+  DALI_TEST_EQUALS( (previousHeight < currentHeight), true , TEST_LOCATION );
+
+  END_TEST;
+}
+
+int utcDaliTextFieldExtremlyLargePointSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldExtremlyLargePointSize");
+
+  TextField field = TextField::New();
+
+  field.SetProperty( TextField::Property::TEXT, "Text" );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( field );
+
+  try
+  {
+    field.SetProperty( TextField::Property::POINT_SIZE, 160.0f );
+    application.SendNotification();
+    DALI_TEST_CHECK( field );
+  }
+  catch (...)
+  {
+    tet_result(TET_FAIL);
+  }
+  END_TEST;
+}
+
+int UtcDaliTextFieldDefaultFontStylePropertyCoverage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldFontStylePorpertyCoverage");
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+
+  Property::Map fontStyleMapGet;
+
+  fontStyleMapGet = field.GetProperty<Property::Map>( TextField::Property::FONT_STYLE );
+
+  Property::Value* weightValue = NULL;
+  Property::Value* widthValue = NULL;
+  Property::Value* slantValue = NULL;
+  weightValue = fontStyleMapGet.Find( "weight" );
+  widthValue = fontStyleMapGet.Find( "width" );
+  slantValue = fontStyleMapGet.Find( "slant" );
+  DALI_TEST_CHECK( !weightValue );
+  DALI_TEST_CHECK( !widthValue );
+  DALI_TEST_CHECK( !slantValue );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldSettingPlaceholder(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldSettingPlaceholder");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  Stage::GetCurrent().Add( field );
+
+  // Check the placeholder property with pixel size
+  Property::Map placeholderPixelSizeMapSet;
+  Property::Map placeholderPixelSizeMapGet;
+  Property::Map placeholderFontstyleMap;
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::TEXT ] = "Setting Placeholder Text";
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = "Setting Placeholder Text Focused";
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::COLOR ] = Color::BLUE;
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::FONT_FAMILY ] = "Arial";
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::PIXEL_SIZE ] = 15.0f;
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::ELLIPSIS ] = true;
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderPixelSizeMapSet[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderPixelSizeMapSet );
+
+  placeholderPixelSizeMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderPixelSizeMapGet.Count(), placeholderPixelSizeMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderPixelSizeMapGet, placeholderPixelSizeMapSet ), true, TEST_LOCATION );
+
+  // Check the placeholder property with point size
+  Property::Map placeholderMapSet;
+  Property::Map placeholderMapGet;
+  placeholderMapSet[ Text::PlaceHolder::Property::TEXT ] = "Setting Placeholder Text";
+  placeholderMapSet[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = "Setting Placeholder Text Focused";
+  placeholderMapSet[ Text::PlaceHolder::Property::COLOR ] = Color::RED;
+  placeholderMapSet[ Text::PlaceHolder::Property::FONT_FAMILY ] = "Arial";
+  placeholderMapSet[ Text::PlaceHolder::Property::POINT_SIZE ] = 12.0f;
+  placeholderMapSet[ Text::PlaceHolder::Property::ELLIPSIS ] = false;
+
+  // Check the placeholder font style property
+  placeholderFontstyleMap.Clear();
+
+  placeholderFontstyleMap.Insert( "weight", "bold" );
+  placeholderFontstyleMap.Insert( "width", "condensed" );
+  placeholderFontstyleMap.Insert( "slant", "italic" );
+  placeholderMapSet[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderMapSet ), true, TEST_LOCATION );
+
+  // Reset font style.
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "weight", "normal" );
+  placeholderFontstyleMap.Insert( "slant", "oblique" );
+  placeholderMapSet[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderMapSet ), true, TEST_LOCATION );
+
+  placeholderFontstyleMap.Clear();
+  placeholderFontstyleMap.Insert( "slant", "roman" );
+  placeholderMapSet[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderFontstyleMap;
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+
+  placeholderFontstyleMap.Clear();
+  placeholderMapSet[ Text::PlaceHolder::Property::FONT_STYLE ] = placeholderFontstyleMap;
+
+  field.SetProperty( TextField::Property::PLACEHOLDER, placeholderMapSet );
+  placeholderMapGet = field.GetProperty<Property::Map>( TextField::Property::PLACEHOLDER );
+  DALI_TEST_EQUALS( placeholderMapGet.Count(), placeholderMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( placeholderMapGet, placeholderMapSet ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldSetPaddingProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldSetPaddingProperty\n");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  field.SetSize( 300.f, 50.f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( field );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector3 originalSize = field.GetNaturalSize();
+
+  field.SetProperty( Toolkit::Control::Property::PADDING, Extents( 10, 10, 10, 10 ) );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( field.GetProperty<Extents>( Toolkit::Control::Property::PADDING ), Extents( 10, 10, 10, 10 ), TEST_LOCATION );
+
+  Vector3 paddingAddedSize = field.GetNaturalSize();
+
+  DALI_TEST_EQUALS( originalSize.width + 10 + 10 , paddingAddedSize.width, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( originalSize.height + 10 + 10 , paddingAddedSize.height, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldEnableShiftSelectionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldEnableShiftSelectionProperty");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  field.SetSize( 300.0f, 50.0f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( field );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of ENABLE_SHIFT_SELECTION is 'true'.
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_SHIFT_SELECTION ), true, TEST_LOCATION );
+
+  // Check the enable shift selection property
+  field.SetProperty( DevelTextField::Property::ENABLE_SHIFT_SELECTION, false );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_SHIFT_SELECTION ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldEnableGrabHandleProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldEnableGrabHandleProperty");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  field.SetSize( 300.0f, 50.0f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( field );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of ENABLE_GRAB_HANDLE is 'true'.
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_GRAB_HANDLE ), true, TEST_LOCATION );
+
+  // Check the enable grab handle property
+  field.SetProperty( DevelTextField::Property::ENABLE_GRAB_HANDLE, false );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::ENABLE_GRAB_HANDLE ), false, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldMatchSystemLanguageDirectionProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldMatchSystemLanguageDirectionProperty");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+  field.SetSize( 300.0f, 50.0f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  Stage::GetCurrent().Add( field );
+
+  application.SendNotification();
+  application.Render();
+
+  // The default value of MATCH_SYSTEM_LANGUAGE_DIRECTION is 'false'.
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION ), false, TEST_LOCATION );
+
+  // Check the match system language direction property
+  field.SetProperty( DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, true );
+  DALI_TEST_EQUALS( field.GetProperty<bool>( DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int utcDaliTextFieldLayoutDirectionCoverage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" utcDaliTextFieldLayoutDirectionCoverage");
+
+  // Creates a tap event. After creating a tap event the text field should
+  // have the focus and add text with key events should be possible.
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  Stage::GetCurrent().Add( field );
+
+  field.SetSize( 300.0f, 50.0f );
+  field.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // init direction for coverage
+  // Set horizontal alignment END
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "END");
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set MATCH_SYSTEM_LANGUAGE_DIRECTION to true to use the layout direction.
+  field.SetProperty( DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, true );
+  field.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT );
+
+  // Set horizontal alignment BEGIN
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "BEGIN");
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set horizontal alignment CENTER
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "CENTER");
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Set horizontal alignment END
+  field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "END");
+
+  // Create a tap event to touch the text field.
+  TestGenerateTap( application, 150.0f, 25.0f );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Generate a Esc key event. The text field should lose the focus.
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Down, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+  application.ProcessEvent( GenerateKey( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Up, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE ) );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( false, field.HasKeyInputFocus(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldGetInputMethodContext(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldGetInputMethodContext");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( DevelTextField::GetInputMethodContext( field ) );
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldSelectWholeText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldSelectWholeText ");
+
+  TextField textField = TextField::New();
+
+  Stage::GetCurrent().Add( textField );
+
+  textField.SetSize( 300.f, 50.f );
+  textField.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  textField.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( 1u, textField.GetChildCount(), TEST_LOCATION );
+
+  DevelTextField::SelectWholeText( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  // Nothing should have been selected. The number of children is still 1
+  DALI_TEST_EQUALS( 1u, textField.GetChildCount(), TEST_LOCATION );
+
+  textField.SetProperty( TextField::Property::TEXT, "Hello world" );
+
+  application.SendNotification();
+  application.Render();
+
+  DevelTextField::SelectWholeText( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  // Should be 2 children, the stencil and the layer
+  DALI_TEST_EQUALS( 2u, textField.GetChildCount(), TEST_LOCATION );
+
+  // The offscreen root actor should have two actors: the renderer and the highlight actor.
+  Actor stencil = textField.GetChildAt( 0u );
+
+  // The highlight actor is drawn first, so is the first actor in the list
+  Renderer highlight = stencil.GetChildAt( 0u ).GetRendererAt( 0u );
+  DALI_TEST_CHECK( highlight );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
new file mode 100755 (executable)
index 0000000..d8c5f70
--- /dev/null
@@ -0,0 +1,1537 @@
+/*
+ * Copyright (c) 2019 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 <unistd.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_textlabel_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_textlabel_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+const char* const PROPERTY_NAME_RENDERING_BACKEND = "renderingBackend";
+const char* const PROPERTY_NAME_TEXT = "text";
+const char* const PROPERTY_NAME_FONT_FAMILY = "fontFamily";
+const char* const PROPERTY_NAME_FONT_STYLE = "fontStyle";
+const char* const PROPERTY_NAME_POINT_SIZE = "pointSize";
+const char* const PROPERTY_NAME_MULTI_LINE =  "multiLine";
+const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT = "horizontalAlignment";
+const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT = "verticalAlignment";
+const char* const PROPERTY_NAME_TEXT_COLOR = "textColor";
+const char* const PROPERTY_NAME_ENABLE_MARKUP = "enableMarkup";
+const char* const PROPERTY_NAME_ENABLE_AUTO_SCROLL = "enableAutoScroll";
+const char* const PROPERTY_NAME_ENABLE_AUTO_SCROLL_SPEED = "autoScrollSpeed";
+const char* const PROPERTY_NAME_ENABLE_AUTO_SCROLL_LOOPS = "autoScrollLoopCount";
+const char* const PROPERTY_NAME_ENABLE_AUTO_SCROLL_GAP = "autoScrollGap";
+
+const char* const PROPERTY_NAME_LINE_SPACING = "lineSpacing";
+const char* const PROPERTY_NAME_UNDERLINE = "underline";
+const char* const PROPERTY_NAME_SHADOW = "shadow";
+const char* const PROPERTY_NAME_EMBOSS = "emboss";
+const char* const PROPERTY_NAME_OUTLINE = "outline";
+const char* const PROPERTY_NAME_BACKGROUND = "textBackground";
+
+const char* const PROPERTY_NAME_PIXEL_SIZE = "pixelSize";
+const char* const PROPERTY_NAME_ELLIPSIS = "ellipsis";
+const char* const PROPERTY_NAME_AUTO_SCROLL_LOOP_DELAY = "autoScrollLoopDelay";
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+const unsigned int EMOJI_FONT_SIZE = 3840u; // 60 * 64
+
+bool DaliTestCheckMaps( const Property::Map& mapGet, const Property::Map& mapSet, const std::vector<std::string>& indexConversionTable = std::vector<std::string>() )
+{
+  const Property::Map::SizeType size = mapGet.Count();
+
+  if( size == mapSet.Count() )
+  {
+    for( unsigned int index = 0u; index < size; ++index )
+    {
+      const KeyValuePair& valueGet = mapGet.GetKeyValue( index );
+
+      // Find the keys of the 'get' map
+      Property::Index indexKey = valueGet.first.indexKey;
+      std::string stringKey = valueGet.first.stringKey;
+
+      if( !indexConversionTable.empty() )
+      {
+        if( stringKey.empty() )
+        {
+          stringKey = indexConversionTable[ indexKey ];
+        }
+
+        if( ( indexKey == Property::INVALID_INDEX ) && !stringKey.empty() )
+        {
+          Property::Index index = 0u;
+          for( auto key : indexConversionTable )
+          {
+            if( key == stringKey )
+            {
+              indexKey = index;
+              break;
+            }
+            ++index;
+          }
+        }
+      }
+
+      const Property::Value* const valueSet = mapSet.Find( indexKey, stringKey );
+
+      if( nullptr != valueSet )
+      {
+        if( ( valueSet->GetType() == Dali::Property::STRING ) && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
+        {
+          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
+          return false;
+        }
+        else if( ( valueSet->GetType() == Dali::Property::BOOLEAN ) && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
+          return false;
+        }
+        else if( ( valueSet->GetType() == Dali::Property::INTEGER ) && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
+          return false;
+        }
+        else if( ( valueSet->GetType() == Dali::Property::FLOAT ) && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
+        {
+          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
+          return false;
+        }
+        else if( ( valueSet->GetType() == Dali::Property::VECTOR2 ) && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
+        {
+          Vector2 vector2Get = valueGet.second.Get<Vector2>();
+          Vector2 vector2Set = valueSet->Get<Vector2>();
+          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
+          return false;
+        }
+        else if( ( valueSet->GetType() == Dali::Property::VECTOR4 ) && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
+        {
+          Vector4 vector4Get = valueGet.second.Get<Vector4>();
+          Vector4 vector4Set = valueSet->Get<Vector4>();
+          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
+          return false;
+        }
+      }
+      else
+      {
+        if ( valueGet.first.type == Property::Key::INDEX )
+        {
+          tet_printf( "  The key %d doesn't exist.", valueGet.first.indexKey );
+        }
+        else
+        {
+          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
+        }
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace
+
+int UtcDaliToolkitTextLabelConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelConstructorP");
+  TextLabel textLabel;
+  DALI_TEST_CHECK( !textLabel );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelNewP");
+  TextLabel textLabel = TextLabel::New( "Test Text" );
+  DALI_TEST_CHECK( textLabel );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelDownCastP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelDownCastP");
+  TextLabel textLabel1 = TextLabel::New();
+  BaseHandle object( textLabel1 );
+
+  TextLabel textLabel2 = TextLabel::DownCast( object );
+  DALI_TEST_CHECK( textLabel2 );
+
+  TextLabel textLabel3 = DownCast< TextLabel >( object );
+  DALI_TEST_CHECK( textLabel3 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelDownCastN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelDownCastN");
+  BaseHandle uninitializedObject;
+  TextLabel textLabel1 = TextLabel::DownCast( uninitializedObject );
+  DALI_TEST_CHECK( !textLabel1 );
+
+  TextLabel textLabel2 = DownCast< TextLabel >( uninitializedObject );
+  DALI_TEST_CHECK( !textLabel2 );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelCopyConstructorP");
+  TextLabel textLabel = TextLabel::New();
+  textLabel.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+
+  TextLabel copy( textLabel );
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ) == textLabel.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ) );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelAssingmentOperatorP");
+  TextLabel textLabel = TextLabel::New();
+  textLabel.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+
+  TextLabel copy = textLabel;
+  DALI_TEST_CHECK( copy );
+  DALI_TEST_CHECK( copy.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ) == textLabel.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ) );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliToolkitTextLabelGetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelGetPropertyP");
+  TextLabel label = TextLabel::New("Test Text");
+  DALI_TEST_CHECK( label );
+
+  // Check Property Indices are correct
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_RENDERING_BACKEND ) == TextLabel::Property::RENDERING_BACKEND );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_TEXT ) == TextLabel::Property::TEXT );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_FONT_FAMILY ) == TextLabel::Property::FONT_FAMILY );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_FONT_STYLE ) == TextLabel::Property::FONT_STYLE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_POINT_SIZE ) == TextLabel::Property::POINT_SIZE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_MULTI_LINE ) == TextLabel::Property::MULTI_LINE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_HORIZONTAL_ALIGNMENT ) == TextLabel::Property::HORIZONTAL_ALIGNMENT );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_VERTICAL_ALIGNMENT ) == TextLabel::Property::VERTICAL_ALIGNMENT );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_TEXT_COLOR ) == TextLabel::Property::TEXT_COLOR );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ENABLE_MARKUP) == TextLabel::Property::ENABLE_MARKUP );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ENABLE_AUTO_SCROLL ) == TextLabel::Property::ENABLE_AUTO_SCROLL );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ENABLE_AUTO_SCROLL_SPEED ) == TextLabel::Property::AUTO_SCROLL_SPEED );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ENABLE_AUTO_SCROLL_LOOPS ) == TextLabel::Property::AUTO_SCROLL_LOOP_COUNT );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ENABLE_AUTO_SCROLL_GAP ) == TextLabel::Property::AUTO_SCROLL_GAP );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_LINE_SPACING ) == TextLabel::Property::LINE_SPACING );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_UNDERLINE ) == TextLabel::Property::UNDERLINE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_SHADOW ) == TextLabel::Property::SHADOW );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_EMBOSS ) == TextLabel::Property::EMBOSS );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_OUTLINE ) == TextLabel::Property::OUTLINE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_BACKGROUND ) == DevelTextLabel::Property::BACKGROUND );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_PIXEL_SIZE ) == TextLabel::Property::PIXEL_SIZE );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_ELLIPSIS ) == TextLabel::Property::ELLIPSIS );
+  DALI_TEST_CHECK( label.GetPropertyIndex( PROPERTY_NAME_AUTO_SCROLL_LOOP_DELAY ) == TextLabel::Property::AUTO_SCROLL_LOOP_DELAY );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelSetPropertyP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelSetPropertyP");
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK( label );
+
+  Stage::GetCurrent().Add( label );
+
+  // Note - we can't check the defaults since the stylesheets are platform-specific
+  label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+  DALI_TEST_EQUALS( (Text::RenderingType)label.GetProperty<int>( TextLabel::Property::RENDERING_BACKEND ), Text::RENDERING_SHARED_ATLAS, TEST_LOCATION );
+
+  // Check that text can be correctly reset
+  label.SetProperty( TextLabel::Property::TEXT, "Setting Text" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("Setting Text"), TEST_LOCATION );
+
+  // Check font properties.
+  label.SetProperty( TextLabel::Property::FONT_FAMILY, "Setting font family" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::FONT_FAMILY ), std::string("Setting font family"), TEST_LOCATION );
+
+  Property::Map fontStyleMapSet;
+  Property::Map fontStyleMapGet;
+
+  fontStyleMapSet.Insert( "weight", "bold" );
+  fontStyleMapSet.Insert( "width", "condensed" );
+  fontStyleMapSet.Insert( "slant", "italic" );
+  label.SetProperty( TextLabel::Property::FONT_STYLE, fontStyleMapSet );
+
+  fontStyleMapGet = label.GetProperty<Property::Map>( TextLabel::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Check the old font style format.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "thin" );
+  fontStyleMapSet.Insert( "width", "expanded" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+  const std::string strFontStyle = "{\"weight\":\"thin\",\"width\":\"expanded\",\"slant\":\"oblique\"}";
+
+  label.SetProperty( TextLabel::Property::FONT_STYLE, "{\"weight\":\"thin\",\"width\":\"expanded\",\"slant\":\"oblique\"}" );
+  std::string getFontStyle = label.GetProperty<std::string>( TextLabel::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( getFontStyle, strFontStyle, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 10.f );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::POINT_SIZE ), 10.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Reset font style.
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "weight", "normal" );
+  fontStyleMapSet.Insert( "slant", "oblique" );
+
+  label.SetProperty( TextLabel::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = label.GetProperty<Property::Map>( TextLabel::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+  fontStyleMapSet.Insert( "slant", "roman" );
+
+  label.SetProperty( TextLabel::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = label.GetProperty<Property::Map>( TextLabel::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+
+  // Replace 'roman' for 'normal'.
+  Property::Value* slantValue = fontStyleMapGet.Find( "slant" );
+  if( NULL != slantValue )
+  {
+    if( "normal" == slantValue->Get<std::string>() )
+    {
+      fontStyleMapGet["slant"] = "roman";
+    }
+  }
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  fontStyleMapSet.Clear();
+
+  label.SetProperty( TextLabel::Property::FONT_STYLE, fontStyleMapSet );
+  fontStyleMapGet = label.GetProperty<Property::Map>( TextLabel::Property::FONT_STYLE );
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  // Toggle multi-line
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+  DALI_TEST_EQUALS( label.GetProperty<bool>( TextLabel::Property::MULTI_LINE ), true, TEST_LOCATION );
+
+  // Check that the Alignment properties can be correctly set
+  label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::HORIZONTAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::VERTICAL_ALIGNMENT ), "CENTER", TEST_LOCATION );
+
+  // Check that text color can be properly set
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( label.GetProperty<Vector4>( TextLabel::Property::TEXT_COLOR ), Color::BLUE, TEST_LOCATION );
+
+  Property::Map underlineMapSet;
+  Property::Map underlineMapGet;
+
+  underlineMapSet.Insert( "enable", false );
+  underlineMapSet.Insert( "color", Color::BLUE );
+  underlineMapSet.Insert( "height", 0 );
+
+  underlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
+
+  TextLabel label2 = TextLabel::New( "New text" );
+  DALI_TEST_CHECK( label2 );
+  DALI_TEST_EQUALS( label2.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("New text"), TEST_LOCATION );
+
+  // Check the enable markup property.
+  DALI_TEST_CHECK( !label.GetProperty<bool>( TextLabel::Property::ENABLE_MARKUP ) );
+  label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
+  DALI_TEST_CHECK( label.GetProperty<bool>( TextLabel::Property::ENABLE_MARKUP ) );
+
+  // Check the text property when markup is enabled
+  label.SetProperty( TextLabel::Property::TEXT, "<color value='white'>Markup</color><color value='cyan'>Text</color>" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("MarkupText"), TEST_LOCATION );
+
+  // Check for incomplete marks.
+  label.SetProperty( TextLabel::Property::TEXT, "<color='white'><i>Markup</i><b>Text</b></color>" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), std::string("MarkupText"), TEST_LOCATION );
+  try
+  {
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  // Check autoscroll properties
+  const int SCROLL_SPEED = 80;
+  const int SCROLL_LOOPS = 4;
+  const float SCROLL_GAP = 50.0f;
+  const float SCROLL_LOOP_DELAY = 0.3f;
+  const std::string STOP_IMMEDIATE = std::string( "IMMEDIATE" );
+  const std::string STOP_FINISH_LOOP = std::string( "FINISH_LOOP" );
+
+  label.SetProperty( TextLabel::Property::MULTI_LINE, false ); // Autoscroll only supported in single line
+  DALI_TEST_CHECK( !label.GetProperty<bool>( TextLabel::Property::ENABLE_AUTO_SCROLL ) );
+  label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+  DALI_TEST_CHECK( label.GetProperty<bool>( TextLabel::Property::ENABLE_AUTO_SCROLL ) );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, SCROLL_SPEED );
+  DALI_TEST_EQUALS( SCROLL_SPEED, label.GetProperty<int>( TextLabel::Property::AUTO_SCROLL_SPEED ), TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, SCROLL_LOOPS );
+  DALI_TEST_EQUALS( SCROLL_LOOPS, label.GetProperty<int>( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT ), TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, SCROLL_GAP );
+  DALI_TEST_EQUALS( SCROLL_GAP, label.GetProperty<float>( TextLabel::Property::AUTO_SCROLL_GAP ), TEST_LOCATION );
+  label.SetProperty(TextLabel::Property::AUTO_SCROLL_LOOP_DELAY, SCROLL_LOOP_DELAY );
+  DALI_TEST_EQUALS( SCROLL_LOOP_DELAY, label.GetProperty<float>( TextLabel::Property::AUTO_SCROLL_LOOP_DELAY ), TEST_LOCATION );
+
+  //Check autoscroll stop type property
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+  DALI_TEST_EQUALS( STOP_IMMEDIATE, label.GetProperty<std::string>( TextLabel::Property::AUTO_SCROLL_STOP_MODE ), TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+  DALI_TEST_EQUALS( STOP_FINISH_LOOP, label.GetProperty<std::string>( TextLabel::Property::AUTO_SCROLL_STOP_MODE ), TEST_LOCATION );
+
+  // test natural size with multi-line and line spacing
+  {
+    TextLabel label3 = TextLabel::New("Some text here\nend there\nend here");
+    Vector3 oneLineNaturalSize = label3.GetNaturalSize();
+    label3.SetProperty(TextLabel::Property::MULTI_LINE, true);
+    label3.SetProperty(TextLabel::Property::LINE_SPACING, 0);
+    Vector3 multiLineNaturalSize = label3.GetNaturalSize();
+
+    // The width of the text when multi-line is enabled will be smaller (lines separated on '\n')
+    // The height of the text when multi-line is enabled will be larger
+    DALI_TEST_CHECK( oneLineNaturalSize.width > multiLineNaturalSize.width );
+    DALI_TEST_CHECK( oneLineNaturalSize.height < multiLineNaturalSize.height );
+
+    // Change line spacing, meaning height will increase by 3 times the amount specified as we have three lines
+    // Everything else will remain the same
+    int lineSpacing = 20;
+    label3.SetProperty( TextLabel::Property::LINE_SPACING, lineSpacing );
+    Vector3 expectedAfterLineSpacingApplied( multiLineNaturalSize );
+    expectedAfterLineSpacingApplied.height += 3 * lineSpacing;
+    DALI_TEST_EQUALS( expectedAfterLineSpacingApplied, label3.GetNaturalSize(), TEST_LOCATION );
+  }
+
+  // single line, line spacing must not affect natural size of the text, only add the spacing to the height
+  {
+    TextLabel label3 = TextLabel::New("Some text here end there end here");
+    label3.SetProperty(TextLabel::Property::MULTI_LINE, false);
+    label3.SetProperty(TextLabel::Property::LINE_SPACING, 0);
+    Vector3 textNaturalSize = label3.GetNaturalSize();
+    int lineSpacing = 20;
+    label3.SetProperty( TextLabel::Property::LINE_SPACING, lineSpacing );
+    Vector3 expectedNaturalSizeWithLineSpacing( textNaturalSize );
+    expectedNaturalSizeWithLineSpacing.height += lineSpacing;
+    DALI_TEST_EQUALS( expectedNaturalSizeWithLineSpacing, label3.GetNaturalSize(), TEST_LOCATION );
+  }
+  // Check the line spacing property
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::LINE_SPACING ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+  label.SetProperty( TextLabel::Property::LINE_SPACING, 10.f );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::LINE_SPACING ), 10.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the underline property
+  underlineMapSet.Clear();
+  underlineMapSet.Insert( "enable", true );
+  underlineMapSet.Insert( "color", Color::RED );
+  underlineMapSet.Insert( "height", 1 );
+
+  label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  underlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
+
+  underlineMapSet.Clear();
+  underlineMapSet.Insert( Toolkit::DevelText::Underline::Property::ENABLE, true );
+  underlineMapSet.Insert( Toolkit::DevelText::Underline::Property::COLOR, Color::GREEN );
+  underlineMapSet.Insert( Toolkit::DevelText::Underline::Property::HEIGHT, 2 );
+
+  label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  underlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  std::vector<std::string> underlineIndicesConversionTable = { "enable", "color", "height" };
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet, underlineIndicesConversionTable ), true, TEST_LOCATION );
+
+  underlineMapSet.Clear();
+
+  Property::Map underlineDisabledMapGet;
+  underlineDisabledMapGet.Insert( "enable", false );
+  underlineDisabledMapGet.Insert( "color", Color::GREEN );
+  underlineDisabledMapGet.Insert( "height", 2 );
+
+  label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  underlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::UNDERLINE );
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineDisabledMapGet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineDisabledMapGet ), true, TEST_LOCATION );
+
+  // Check the shadow property
+
+  Property::Map shadowMapSet;
+  Property::Map shadowMapGet;
+
+  shadowMapSet.Insert( "color", Color::GREEN );
+  shadowMapSet.Insert( "offset", Vector2(2.0f, 2.0f) );
+  shadowMapSet.Insert( "blurRadius", 5.0f );
+
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMapSet );
+
+  shadowMapGet = label.GetProperty<Property::Map>( TextLabel::Property::SHADOW );
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowMapSet ), true, TEST_LOCATION );
+
+  shadowMapSet.Clear();
+
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::COLOR, Color::BLUE );
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::OFFSET, "3.0 3.0" );
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::BLUR_RADIUS, 3.0f );
+
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMapSet );
+
+  // Replace the offset (string) by a vector2
+  shadowMapSet.Clear();
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::COLOR, Color::BLUE );
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::OFFSET, Vector2( 3.0, 3.0 ) );
+  shadowMapSet.Insert( Toolkit::DevelText::Shadow::Property::BLUR_RADIUS, 3.0f );
+
+  shadowMapGet = label.GetProperty<Property::Map>( TextLabel::Property::SHADOW );
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowMapSet.Count(), TEST_LOCATION );
+  std::vector<std::string> shadowIndicesConversionTable = { "color", "offset", "blurRadius" };
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowMapSet, shadowIndicesConversionTable ), true, TEST_LOCATION );
+
+  shadowMapSet.Clear();
+  Property::Map shadowDisabledMapGet;
+  shadowDisabledMapGet.Insert( "color", Color::BLUE );
+  shadowDisabledMapGet.Insert( "offset", Vector2(0.0f, 0.0f) );
+  shadowDisabledMapGet.Insert( "blurRadius", 3.0f );
+
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMapSet );
+
+  shadowMapGet = label.GetProperty<Property::Map>( TextLabel::Property::SHADOW );
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowDisabledMapGet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowDisabledMapGet ), true, TEST_LOCATION );
+
+  // Check the emboss property
+  label.SetProperty( TextLabel::Property::EMBOSS, "Emboss properties" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::EMBOSS ), std::string("Emboss properties"), TEST_LOCATION );
+
+  // Check the outline property
+
+  // Test string type first
+  // This is purely to maintain backward compatibility, but we don't support string as the outline property type.
+  label.SetProperty( TextLabel::Property::OUTLINE, "Outline properties" );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::OUTLINE ), std::string("Outline properties"), TEST_LOCATION );
+
+  // Then test the property map type
+  Property::Map outlineMapSet;
+  Property::Map outlineMapGet;
+
+  outlineMapSet["color"] = Color::RED;
+  outlineMapSet["width"] = 2.0f;
+  label.SetProperty( TextLabel::Property::OUTLINE, outlineMapSet );
+
+  outlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::OUTLINE );
+  DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
+
+  outlineMapSet.Clear();
+  outlineMapSet[Toolkit::DevelText::Outline::Property::COLOR] = Color::BLUE;
+  outlineMapSet[Toolkit::DevelText::Outline::Property::WIDTH] = 3.0f;
+  label.SetProperty( TextLabel::Property::OUTLINE, outlineMapSet );
+
+  outlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::OUTLINE );
+  DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
+  std::vector<std::string> outlineIndicesConversionTable = { "color", "width" };
+  DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet, outlineIndicesConversionTable ), true, TEST_LOCATION );
+
+  // Check the background property
+  Property::Map backgroundMapSet;
+  Property::Map backgroundMapGet;
+
+  backgroundMapSet["enable"] = true;
+  backgroundMapSet["color"] = Color::RED;
+  label.SetProperty( DevelTextLabel::Property::BACKGROUND, backgroundMapSet );
+
+  backgroundMapGet = label.GetProperty<Property::Map>( DevelTextLabel::Property::BACKGROUND );
+  DALI_TEST_EQUALS( backgroundMapGet.Count(), backgroundMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( backgroundMapGet, backgroundMapSet ), true, TEST_LOCATION );
+
+  backgroundMapSet.Clear();
+  backgroundMapSet[Toolkit::DevelText::Background::Property::ENABLE] = true;
+  backgroundMapSet[Toolkit::DevelText::Background::Property::COLOR] = Color::GREEN;
+  label.SetProperty( DevelTextLabel::Property::BACKGROUND, backgroundMapSet );
+
+  backgroundMapGet = label.GetProperty<Property::Map>( DevelTextLabel::Property::BACKGROUND );
+  DALI_TEST_EQUALS( backgroundMapGet.Count(), backgroundMapSet.Count(), TEST_LOCATION );
+  std::vector<std::string> backgroundIndicesConversionTable = { "enable", "color" };
+  DALI_TEST_EQUALS( DaliTestCheckMaps( backgroundMapGet, backgroundMapSet, backgroundIndicesConversionTable ), true, TEST_LOCATION );
+
+  // Check the pixel size of font
+  label.SetProperty( TextLabel::Property::PIXEL_SIZE, 20.f );
+  DALI_TEST_EQUALS( label.GetProperty<float>( TextLabel::Property::PIXEL_SIZE ), 20.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  // Check the ellipsis property
+  DALI_TEST_CHECK( label.GetProperty<bool>( TextLabel::Property::ELLIPSIS ) );
+  label.SetProperty( TextLabel::Property::ELLIPSIS, false );
+  DALI_TEST_CHECK( !label.GetProperty<bool>( TextLabel::Property::ELLIPSIS ) );
+
+  // Check the layout direction property
+  label.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT );
+  DALI_TEST_EQUALS( label.GetProperty< int >( Actor::Property::LAYOUT_DIRECTION ), static_cast< int >( LayoutDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelAtlasRenderP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelAtlasRenderP");
+  TextLabel label = TextLabel::New("Test Text");
+  DALI_TEST_CHECK( label );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( label );
+
+  // Turn on all the effects
+  label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+
+  Property::Map underlineMap;
+  underlineMap.Insert( "enable", true );
+  underlineMap.Insert( "color", Color::RED );
+  label.SetProperty( TextLabel::Property::UNDERLINE, underlineMap );
+
+  Property::Map shadowMap;
+  shadowMap.Insert( "color", Color::BLUE );
+  shadowMap.Insert( "offset", Vector2( 1.0f, 1.0f ) );
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMap );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Text::RENDERING_SHARED_ATLAS );
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    label.SetProperty( TextLabel::Property::RENDERING_BACKEND, Text::RENDERING_VECTOR_BASED );
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelLanguagesP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelLanguagesP");
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK( label );
+
+  Stage::GetCurrent().Add( label );
+
+  const std::string scripts( " привет мир, γειά σου Κόσμε, Hello world, مرحبا بالعالم, שלום עולם, "
+                             "բարեւ աշխարհը, მსოფლიოში, 안녕하세요, 你好世界, ひらがな, カタカナ, "
+                             "ওহে বিশ্ব, မင်္ဂလာပါကမ္ဘာလောက, हैलो वर्ल्ड, હેલો વર્લ્ડ, ਸਤਿ ਸ੍ਰੀ ਅਕਾਲ ਦੁਨਿਆ, ಹಲೋ ವರ್ಲ್ಡ್, "
+                             "ഹലോ വേൾഡ്, ଓଡ଼ିଆ, හෙලෝ වර්ල්ඩ්, ஹலோ உலகம், హలో వరల్డ్, "
+                             "ສະບາຍດີໂລກ, สวัสดีโลก, ជំរាបសួរពិភពលោក, "
+                             "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84." ); // these characters on the last line are emojis.
+
+  label.SetProperty( TextLabel::Property::TEXT, scripts );
+  DALI_TEST_EQUALS( label.GetProperty<std::string>( TextLabel::Property::TEXT ), scripts, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelEmojisP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelLanguagesP");
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK( label );
+
+  Stage::GetCurrent().Add( label );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  TextAbstraction::FontDescription fontDescription;
+  fontDescription.path = pathName + DEFAULT_FONT_DIR + "/tizen/BreezeColorEmoji.ttf";
+  fontDescription.family = "BreezeColorEmoji";
+  fontDescription.width = TextAbstraction::FontWidth::NONE;
+  fontDescription.weight = TextAbstraction::FontWeight::NORMAL;
+  fontDescription.slant = TextAbstraction::FontSlant::NONE;
+
+  fontClient.GetFontId( fontDescription, EMOJI_FONT_SIZE );
+
+  const std::string emojis = "<font family='BreezeColorEmoji' size='60'>\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84</font>";
+  label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
+  label.SetProperty( TextLabel::Property::TEXT, emojis );
+
+  Property::Map shadowMap;
+  shadowMap.Insert( "color", "green" );
+  shadowMap.Insert( "offset", "2 2" );
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMap );
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelScrollingP");
+  TextLabel labelImmediate = TextLabel::New("Some text to scroll");
+  TextLabel labelFinished = TextLabel::New("مرحبا بالعالم");
+
+  DALI_TEST_CHECK( labelImmediate );
+  DALI_TEST_CHECK( labelFinished );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( labelImmediate );
+  // Turn on all the effects
+  labelImmediate.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelImmediate.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelImmediate.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelImmediate.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelImmediate.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+
+  Stage::GetCurrent().Add( labelFinished );
+  // Turn on all the effects
+  labelFinished.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelFinished.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelFinished.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelFinished.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelFinished.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+
+
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    labelImmediate.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelFinished.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+
+    labelImmediate.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelFinished.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+
+    labelImmediate.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelFinished.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render();
+
+    labelImmediate.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelFinished.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    application.SendNotification();
+    application.Render();
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingCenterAlignP(void)
+{
+  ToolkitTestApplication application;
+  TextLabel labelShort = TextLabel::New("Some text to scroll");
+  TextLabel labelLong = TextLabel::New("Some text to scroll that is greater than the width of the text. The quick brown fox jumps over the lazy dog. Hello World, we meet again!");
+
+  DALI_TEST_CHECK( labelShort );
+  DALI_TEST_CHECK( labelLong );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( labelShort );
+  // Turn on all the effects
+  labelShort.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelShort.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+
+  Stage::GetCurrent().Add( labelLong );
+  // Turn on all the effects
+  labelLong.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelLong.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render();
+
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    application.SendNotification();
+    application.Render();
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingCenterAlignRTLP(void)
+{
+  ToolkitTestApplication application;
+  TextLabel labelShort = TextLabel::New("مرحبا بالعالم");
+  TextLabel labelLong = TextLabel::New("لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار  النشوة وتمجيد الألم نشأت بالفعل، وسأعرض لك التفاصيل لتكتشف حقيقة وأساس تلك السعادة البشرية، فلا أحد يرفض أو يكره أو يتجنب الشعور بالسعادة، ولكن بفضل هؤلاء الأشخاص الذين لا يدركون بأن السعادة لا بد أن نستشعرها بصورة أكثر عقلانية ومنطقية فيعرضهم هذا لمواجهة الظروف الأليمة، وأكرر بأنه لا يوجد من يرغب في الحب ونيل المنال ويتلذذ بالآلام، الألم هو الألم ولكن نتيجة لظروف ما قد تكمن السعاده فيما نتحمله من كد وأسي");
+
+  DALI_TEST_CHECK( labelShort );
+  DALI_TEST_CHECK( labelLong );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( labelShort );
+  // Turn on all the effects
+  labelShort.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelShort.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+
+  Stage::GetCurrent().Add( labelLong );
+  // Turn on all the effects
+  labelLong.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelLong.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render();
+
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    application.SendNotification();
+    application.Render();
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingEndAlignP(void)
+{
+  ToolkitTestApplication application;
+  TextLabel labelShort = TextLabel::New("Some text to scroll");
+  TextLabel labelLong = TextLabel::New("Some text to scroll that is greater than the width of the text. The quick brown fox jumps over the lazy dog. Hello World, we meet again!");
+
+  DALI_TEST_CHECK( labelShort );
+  DALI_TEST_CHECK( labelLong );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( labelShort );
+  // Turn on all the effects
+  labelShort.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelShort.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "END" );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+
+  Stage::GetCurrent().Add( labelLong );
+  // Turn on all the effects
+  labelLong.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelLong.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "END" );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render();
+
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    application.SendNotification();
+    application.Render();
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingEndAlignRTLP(void)
+{
+  ToolkitTestApplication application;
+  TextLabel labelShort = TextLabel::New("مرحبا بالعالم");
+  TextLabel labelLong = TextLabel::New("لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار  النشوة وتمجيد الألم نشأت بالفعل، وسأعرض لك التفاصيل لتكتشف حقيقة وأساس تلك السعادة البشرية، فلا أحد يرفض أو يكره أو يتجنب الشعور بالسعادة، ولكن بفضل هؤلاء الأشخاص الذين لا يدركون بأن السعادة لا بد أن نستشعرها بصورة أكثر عقلانية ومنطقية فيعرضهم هذا لمواجهة الظروف الأليمة، وأكرر بأنه لا يوجد من يرغب في الحب ونيل المنال ويتلذذ بالآلام، الألم هو الألم ولكن نتيجة لظروف ما قد تكمن السعاده فيما نتحمله من كد وأسي");
+
+  DALI_TEST_CHECK( labelShort );
+  DALI_TEST_CHECK( labelLong );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( labelShort );
+  // Turn on all the effects
+  labelShort.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelShort.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "END" );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelShort.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::IMMEDIATE );
+
+  Stage::GetCurrent().Add( labelLong );
+  // Turn on all the effects
+  labelLong.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  labelLong.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "END" );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+  labelLong.SetProperty( TextLabel::Property::AUTO_SCROLL_STOP_MODE, TextLabel::AutoScrollStopMode::FINISH_LOOP );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render();
+
+    labelShort.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    labelLong.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false );
+    application.SendNotification();
+    application.Render();
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingInterruptedP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelScrollingInterruptedP");
+  TextLabel label = TextLabel::New("Some text to scroll");
+  DALI_TEST_CHECK( label );
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+  Stage::GetCurrent().Add( label );
+  label.SetSize( 360.0f, 20.f );
+  // Turn on all the effects
+  label.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+
+  // Render the text.
+  application.SendNotification();
+  application.Render();
+
+  unsigned int actorCount1 = label.GetChildCount();
+  tet_printf("Initial actor count is(%d)\n", actorCount1 );
+
+  try
+  {
+    // Render some text with the shared atlas backend
+    label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+    application.SendNotification();
+    application.Render(2000);
+
+    unsigned int actorCount1 = label.GetChildCount();
+    tet_printf("Actor count after scrolling is(%d)\n", actorCount1 );
+
+    label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+
+    // Render the text.
+    application.SendNotification();
+    application.Render();
+
+    unsigned int actorCount2 = label.GetChildCount();
+    tet_printf("After changing color the actor count is(%d)\n", actorCount2 );
+
+    DALI_TEST_EQUALS( actorCount1, actorCount2, TEST_LOCATION );
+
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelScrollingN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelScrollingN");
+
+  TextLabel label = TextLabel::New("Some text to scroll");
+  DALI_TEST_CHECK( label );
+
+  Stage::GetCurrent().Add( label );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  // The text scrolling works only on single line text.
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+
+  // Turn on all the effects.
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_GAP, 50.0f );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3 );
+  label.SetProperty( TextLabel::Property::AUTO_SCROLL_SPEED, 80.0f );
+
+  // Enable the auto scrolling effect.
+  label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true );
+
+  // The auto scrolling shouldn't be enabled.
+  const bool enabled = label.GetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL ).Get<bool>();
+  DALI_TEST_CHECK( !enabled );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelEllipsis(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelEllipsis");
+
+  TextLabel label = TextLabel::New("Hello world");
+  DALI_TEST_CHECK( label );
+
+  // Avoid a crash when core load gl resources.
+  application.GetGlAbstraction().SetCheckFramebufferStatusResult( GL_FRAMEBUFFER_COMPLETE );
+
+  Stage::GetCurrent().Add( label );
+
+  // Turn on all the effects
+  label.SetAnchorPoint( AnchorPoint::CENTER );
+  label.SetParentOrigin( ParentOrigin::CENTER );
+  label.SetSize( 360.0f, 10.f );
+
+  try
+  {
+    // Render the text.
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world                                        " );
+  label.SetProperty( DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT, false );
+  label.SetSize( 400.0f, 10.f );
+
+  try
+  {
+    // Render the text.
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
+  label.SetProperty( DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, true );
+  label.SetSize( 400.0f, 10.f );
+
+  try
+  {
+    // Render the text.
+    application.SendNotification();
+    application.Render();
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelTextWrapMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelTextWarpMode");
+
+  int lineCount =0 ;
+
+  TextLabel label = TextLabel::New();
+  label.SetSize( 300.0f, 300.f );
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world Hello world" );
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+
+
+
+  //label.SetProperty( TextLabel::Property::POINT_SIZE, 18 );
+  Stage::GetCurrent().Add( label );
+
+  label.SetProperty( TextLabel::Property::LINE_WRAP_MODE, "WORD" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::WORD ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::LINE_WRAP_MODE, "CHARACTER" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::CHARACTER ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  label.SetProperty( TextLabel::Property::LINE_WRAP_MODE, Text::LineWrap::WORD );
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::WORD ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::LINE_WRAP_MODE, Text::LineWrap::CHARACTER );
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::CHARACTER ), TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 2, TEST_LOCATION );
+
+  tet_infoline( "Ensure invalid string does not change wrapping mode" );
+  label.SetProperty( TextLabel::Property::LINE_WRAP_MODE, "InvalidWrapMode" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( TextLabel::Property::LINE_WRAP_MODE ), static_cast< int >( Text::LineWrap::CHARACTER ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelColorComponents(void)
+{
+  ToolkitTestApplication application;
+
+  TextLabel label = TextLabel::New();
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_RED ),   1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_GREEN ), 0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_BLUE ),  0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_ALPHA ), 1.0f, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::GREEN );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_RED ),   0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_GREEN ), 1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_BLUE ),  0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_ALPHA ), 1.0f, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLUE );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_RED ),   0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_GREEN ), 0.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_BLUE ),  1.0f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_ALPHA ), 1.0f, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::TEXT_COLOR_ALPHA, 0.6f );
+  DALI_TEST_EQUALS( label.GetProperty< float >( TextLabel::Property::TEXT_COLOR_ALPHA ), 0.6f, TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< Vector4 >( TextLabel::Property::TEXT_COLOR ), Vector4( 0.0f, 0.0f, 1.0f, 0.6f ), TEST_LOCATION );
+  DALI_TEST_EQUALS( label.GetProperty< Vector4 >( TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR ), Vector4( 0.0f, 0.0f, 1.0f, 0.6f ), TEST_LOCATION );
+
+  // Test a transparent text - Rendering should be skipped.
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world Hello world" );
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLUE );
+
+  Stage::GetCurrent().Add( label );
+
+  TraceCallStack& drawTrace = application.GetGlAbstraction().GetDrawTrace();
+  drawTrace.Enable( true );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( drawTrace.FindMethod( "DrawArrays" ), true, TEST_LOCATION );  // Should be rendered
+
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::TRANSPARENT );
+
+  drawTrace.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( drawTrace.FindMethod( "DrawArrays" ), false, TEST_LOCATION ); // Rendering should be skipped
+
+  label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+
+  drawTrace.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( drawTrace.FindMethod( "DrawArrays" ), true, TEST_LOCATION ); // Should be rendered again
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelTextStyle01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelTextStyle Setting Outline after Shadow");
+
+  TextLabel label = TextLabel::New();
+  label.SetSize( 300.0f, 300.f );
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world Hello world" );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 12 );
+  Stage::GetCurrent().Add( label );
+
+  Property::Map outlineMapSet;
+  Property::Map outlineMapGet;
+
+  outlineMapSet["color"] = Color::BLUE;
+  outlineMapSet["width"] = 2.0f;
+  label.SetProperty( TextLabel::Property::OUTLINE, outlineMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map shadowMapSet;
+  shadowMapSet.Insert( "color", "green" );
+  shadowMapSet.Insert( "offset", "2 2" );
+  shadowMapSet.Insert( "blurRadius", "3" );
+  label.SetProperty( TextLabel::Property::SHADOW, shadowMapSet );
+
+  outlineMapSet["color"] = Color::RED;
+  outlineMapSet["width"] = 0.0f;
+  label.SetProperty( TextLabel::Property::OUTLINE, outlineMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  outlineMapGet = label.GetProperty<Property::Map>( TextLabel::Property::OUTLINE );
+
+  Property::Value* colorValue = outlineMapGet.Find("color");
+
+  bool colorMatched( false );
+
+  if ( colorValue )
+  {
+     Property::Type valueType = colorValue->GetType();
+
+     if ( Property::STRING == valueType )
+     {
+       std::string stringValue;
+       colorValue->Get( stringValue );
+       if (  stringValue == "red" )
+       {
+         colorMatched = true;
+       }
+     }
+     else if ( Property::VECTOR4 == valueType )
+     {
+       Vector4 colorVector4;
+       colorValue->Get( colorVector4 );
+       if (  colorVector4 == Color::RED )
+       {
+         colorMatched = true;
+       }
+     }
+  }
+
+  DALI_TEST_EQUALS( colorMatched, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelMultiline(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelMultiline");
+
+  TextLabel label = TextLabel::New();
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world Hello world Hello world Hello world Hello world Hello world" );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 20 );
+  label.SetProperty( TextLabel::Property::MULTI_LINE, false );
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  int lineCount =  label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( lineCount, 1, TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+
+  application.SendNotification();
+  application.Render();
+
+  lineCount =  label.GetProperty<int>( TextLabel::Property::LINE_COUNT );
+  DALI_TEST_EQUALS( true, (lineCount > 1) , TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelTextDirection(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelTextDirection");
+
+  TextLabel label = TextLabel::New();
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ), TEST_LOCATION );
+
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 20 );
+  Stage::GetCurrent().Add( label );
+
+  // Test LTR text
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ), TEST_LOCATION );
+
+  // Test RTL text
+  label.SetProperty( TextLabel::Property::TEXT, "ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  // Test RTL text starting with weak character
+  label.SetProperty( TextLabel::Property::TEXT, "()ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  // Test RTL text string with emoji and weak character
+  label.SetProperty( TextLabel::Property::TEXT, "\xF0\x9F\x98\x81 () ﻡﺮﺤﺑﺍ ﺏﺎﻠﻋﺎﻠﻣ ﻡﺮﺤﺑﺍ" );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::TEXT_DIRECTION ), static_cast< int >( Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextlabelVerticalLineAlignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelVerticalLineAlignment");
+
+  TextLabel label = TextLabel::New();
+
+  label.SetProperty( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT, DevelText::VerticalLineAlignment::TOP  );
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 15 );
+  label.SetProperty( TextLabel::Property::LINE_SPACING, 12 );
+  Stage::GetCurrent().Add( label );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT ), static_cast< int >( Toolkit::DevelText::VerticalLineAlignment::TOP ), TEST_LOCATION );
+
+  label.SetProperty( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT, DevelText::VerticalLineAlignment::MIDDLE  );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT ), static_cast< int >( Toolkit::DevelText::VerticalLineAlignment::MIDDLE ), TEST_LOCATION );
+
+  label.SetProperty( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT, DevelText::VerticalLineAlignment::BOTTOM  );
+  DALI_TEST_EQUALS( label.GetProperty< int >( DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT ), static_cast< int >( Toolkit::DevelText::VerticalLineAlignment::BOTTOM ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextLabelBitmapFont(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextLabelBitmapFont");
+
+  DevelText::BitmapFontDescription fontDescription;
+  fontDescription.name = "Digits";
+  fontDescription.underlinePosition = 0.f;
+  fontDescription.underlineThickness = 0.f;
+
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0030.png", ":", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0031.png", "0", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0032.png", "1", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0033.png", "2", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0034.png", "3", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0035.png", "4", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0036.png", "5", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0037.png", "6", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0038.png", "7", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0039.png", "8", 34.f, 0.f } );
+  fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u003a.png", "9", 34.f, 0.f } );
+
+  TextAbstraction::BitmapFont bitmapFont;
+  DevelText::CreateBitmapFont( fontDescription, bitmapFont );
+
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetFontId( bitmapFont );
+
+  TextLabel label = TextLabel::New();
+
+  label.SetProperty( TextLabel::Property::TEXT, "0123456789:" );
+  label.SetProperty( TextLabel::Property::FONT_FAMILY, "Digits" );
+
+  // The text has been laid out with the bitmap font if the natural size is the sum of all the width (322) and 34 height.
+  DALI_TEST_EQUALS( label.GetNaturalSize(), Vector3(322.f, 34.f, 0.f), Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  // The text has been rendered if the height of the text-label is the height of the line.
+  DALI_TEST_EQUALS( label.GetCurrentSize().height, 34.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int ConvertPointToPixel( float point )
+{
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+  return ( point * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
+int UtcDaliToolkitTextlabelTextFit(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolkitTextlabelTextFit");
+  TextLabel label = TextLabel::New();
+  Vector2 size( 460.0f, 100.0f );
+  label.SetSize( size );
+  label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
+
+  // check point size
+  Property::Map textFitMapSet;
+  textFitMapSet["enable"] = true;
+  textFitMapSet["minSize"] = 10.f;
+  textFitMapSet["maxSize"] = 100.f;
+  textFitMapSet["stepSize"] = -1.f;
+  textFitMapSet["fontSizeType"] = "pointSize";
+
+  label.SetProperty( Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMapSet );
+  label.SetProperty( TextLabel::Property::POINT_SIZE, 120.f);
+
+  Stage::GetCurrent().Add( label );
+
+  application.SendNotification();
+  application.Render();
+
+  const Vector3 EXPECTED_NATURAL_SIZE( 460.0f, 98.0f, 0.0f );
+  DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION );
+
+  // check pixel size
+  textFitMapSet.Clear();
+  textFitMapSet["enable"] = true;
+  textFitMapSet["minSize"] = ConvertPointToPixel( 10.f );
+  textFitMapSet["maxSize"] = ConvertPointToPixel( 100.f );
+  textFitMapSet["stepSize"] = ConvertPointToPixel ( 1.f );
+  textFitMapSet["fontSizeType"] = "pixelSize";
+
+  label.SetProperty( Toolkit::DevelTextLabel::Property::TEXT_FIT, textFitMapSet );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopup.cpp
new file mode 100644 (file)
index 0000000..dc7fcc7
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+const char* TEST_IMAGE_FILE_NAME = "selection-popup-border.9.png";
+
+}
+
+void dali_textselectionpopup_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_textselectionpopup_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliToolkitTextSelectionPopupNewP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup textSelectionPopup;
+
+  DALI_TEST_CHECK( !textSelectionPopup );
+
+  textSelectionPopup = TextSelectionPopup::New( NULL );
+
+  DALI_TEST_CHECK( textSelectionPopup );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupConstructorP(void)
+{
+  TextSelectionPopup textSelectionPopup;
+
+  DALI_TEST_CHECK( !textSelectionPopup );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupCopyConstructorP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup textSelectionPopup;
+
+  textSelectionPopup = TextSelectionPopup::New( NULL );
+  TextSelectionPopup copy( textSelectionPopup );
+
+  DALI_TEST_CHECK( copy == textSelectionPopup );
+
+  END_TEST;
+}
+
+
+int UtcDaliToolkitTextSelectionPopupDestructorP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup* textSelectionPopup = new TextSelectionPopup;
+  delete textSelectionPopup;
+
+  DALI_TEST_CHECK( true );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupAssignmentOperatorP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup textSelectionPopup;
+  textSelectionPopup = TextSelectionPopup::New(  NULL );
+  TextSelectionPopup copy;
+  copy = textSelectionPopup;
+
+  DALI_TEST_CHECK( copy == textSelectionPopup );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupDownCastP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup textSelectionPopup;
+  textSelectionPopup = TextSelectionPopup::New( NULL );
+
+  TextSelectionPopup cast = TextSelectionPopup::DownCast( textSelectionPopup );
+
+  DALI_TEST_CHECK( cast );
+
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionPopupBackgroundBorderP(void)
+{
+  ToolkitTestApplication application;
+  TextSelectionPopup textSelectionPopup;
+  textSelectionPopup = TextSelectionPopup::New( NULL );
+
+  textSelectionPopup.SetProperty( TextSelectionPopup::Property::BACKGROUND_BORDER,
+                                  Property::Map().Add( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ) );
+
+  Property::Value value = textSelectionPopup.GetProperty( TextSelectionPopup::Property::BACKGROUND_BORDER );
+
+  Property::Map map;
+  value.Get( map );
+
+  Property::Value* returnValue = map.Find( Dali::Toolkit::ImageVisual::Property::URL );
+  DALI_TEST_CHECK( NULL != returnValue );
+
+  if( returnValue )
+  {
+    std::string url;
+    returnValue->Get( url );
+    DALI_TEST_EQUALS( TEST_IMAGE_FILE_NAME, url, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+// TextSelectionToolBar is used TextSelectionPopup, below tests it individually
+
+int UtcDaliToolkitTextSelectionToolBarP(void)
+{
+  // Creates Toolbar, adds 2 options and a divider then resizes divider
+  ToolkitTestApplication application;
+
+  TextSelectionToolbar toolbar = TextSelectionToolbar::New();
+
+  toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, Size( 100.0f, 60.0f) );
+
+  Toolkit::PushButton option = Toolkit::PushButton::New();
+  option.SetName( "test-option" );
+  option.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+  toolbar.AddOption( option );
+
+  Toolkit::Control divider = Toolkit::Control::New();
+  divider.SetSize( 2.0f, 0.0f );
+  divider.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
+  toolbar.AddDivider( divider );
+
+  Toolkit::PushButton option2 = Toolkit::PushButton::New();
+  option2.SetName( "test-option-2" );
+  option2.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+  toolbar.AddOption( option2 );
+
+  Size newSize =  Size(3.0f, 0.0f);
+  toolbar.ResizeDividers( newSize );
+
+  DALI_TEST_CHECK( toolbar );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionToolBarScrollBarP(void)
+{
+  // Creates Toolbar, adds 2 options and a divider then resizes divider
+  ToolkitTestApplication application;
+
+  TextSelectionToolbar toolbar = TextSelectionToolbar::New();
+
+  toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, Size( 100.0f, 60.0f) );
+
+  Toolkit::PushButton option = Toolkit::PushButton::New();
+  option.SetName( "test-option" );
+  option.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+  toolbar.AddOption( option );
+
+  // Add a scroll-bar
+  toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR, true );
+
+  bool enabled = toolbar.GetProperty<bool>( Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR );
+  DALI_TEST_CHECK( enabled );
+
+  DALI_TEST_CHECK( toolbar );
+  END_TEST;
+}
+
+int UtcDaliToolkitTextSelectionToolBarScrollView(void)
+{
+  // Configures the ScrollView within the TextSelectionToolbar
+  ToolkitTestApplication application;
+
+  TextSelectionToolbar toolbar = TextSelectionToolbar::New();
+  DALI_TEST_CHECK( toolbar );
+  Stage::GetCurrent().Add( toolbar );
+
+  Property::Map map;
+  map["overshootEffectColor"] = Color::RED;
+  map["overshootSize"] = Vector2(50.0f, 50.f);
+  toolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::SCROLL_VIEW, map );
+
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = toolbar.FindChildByName("TextSelectionScrollView");
+  DALI_TEST_CHECK( actor );
+
+  ScrollView scrollView = ScrollView::DownCast( actor );
+  DALI_TEST_CHECK( scrollView );
+
+  Vector4 color = scrollView.GetProperty<Vector4>( Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR );
+  DALI_TEST_EQUALS( color, Color::RED, TEST_LOCATION );
+
+  Vector2 size = scrollView.GetProperty<Vector2>( Toolkit::Scrollable::Property::OVERSHOOT_SIZE );
+  DALI_TEST_EQUALS( size, Vector2(50.0f, 50.f), TEST_LOCATION );
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringLTR.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringLTR.cpp
new file mode 100644 (file)
index 0000000..6a4bfa8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 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 <fstream>
+#include <stdlib.h>
+#include <locale.h>
+#include <libintl.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+const char* DEFAULT_LOCALE_DIR = "/tmp/locale/";
+static std::string gLocaleLang;
+static std::string gLocaleLanguage;
+
+}
+
+void dali_textselectionpopupmirroringltr_startup(void)
+{
+  // Keep the current locale environment.
+  char* langPtr = getenv( "LANG" );
+  gLocaleLang = std::string( langPtr );
+
+  char* languagePtr = getenv( "LANGUAGE" );
+  gLocaleLanguage = std::string( languagePtr );
+
+  // Set the locale environment to Arabic.
+  setenv( "LANG", "en_GB.UTF-8", 1 );
+  setenv( "LANGUAGE", "en_GB:en", 1 );
+
+  test_return_value = TET_UNDEF;
+}
+
+void dali_textselectionpopupmirroringltr_cleanup(void)
+{
+  // Restore the locale environment.
+  setenv( "LANG", gLocaleLang.c_str(), 1 );
+  setenv( "LANGUAGE", gLocaleLanguage.c_str(), 1 );
+
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliToolkitTextSelectionPopupMirroringLTR(void)
+{
+  // Test the popup mirroring.
+  const std::string CUT( "optionCut" );
+  const std::string COPY( "optionCopy" );
+  const std::string PASTE( "optionPaste" );
+
+  ToolkitTestApplication application;
+
+  setlocale( LC_ALL, "en_GB.UTF-8" );
+  textdomain("dali-toolkit");
+  bindtextdomain("dali-toolkit", DEFAULT_LOCALE_DIR );
+
+  TextSelectionPopup textSelectionPopup = TextSelectionPopup::New( NULL );
+
+  // Enable some buttons.
+  TextSelectionPopup::Buttons buttons = static_cast<TextSelectionPopup::Buttons>( TextSelectionPopup::COPY | TextSelectionPopup::CUT | TextSelectionPopup::PASTE );
+  textSelectionPopup.EnableButtons( buttons );
+
+  // Show the popup.
+  textSelectionPopup.ShowPopup();
+
+  Actor cutActor = textSelectionPopup.FindChildByName( CUT );
+  if( !cutActor )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  Actor tableOfButtons = cutActor.GetParent();
+  if( !tableOfButtons )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  // The order should be COPY, CUT, PASTE
+  DALI_TEST_EQUALS( COPY, tableOfButtons.GetChildAt( 0 ).GetName(), TEST_LOCATION );
+  DALI_TEST_EQUALS( CUT, tableOfButtons.GetChildAt( 2 ).GetName(), TEST_LOCATION );
+  DALI_TEST_EQUALS( PASTE, tableOfButtons.GetChildAt( 4 ).GetName(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringRTL.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextSelectionPopupMirroringRTL.cpp
new file mode 100644 (file)
index 0000000..930e85e
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 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 <fstream>
+#include <stdlib.h>
+#include <locale.h>
+#include <libintl.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+const char* DEFAULT_LOCALE_DIR = "/tmp/locale/";
+static std::string gLocaleLang;
+static std::string gLocaleLanguage;
+
+}
+
+void dali_textselectionpopupmirroringrtl_startup(void)
+{
+  // Keep the current locale environment.
+  char* langPtr = getenv( "LANG" );
+  gLocaleLang = std::string( langPtr );
+
+  char* languagePtr = getenv( "LANGUAGE" );
+  gLocaleLanguage = std::string( languagePtr );
+
+  // Set the locale environment to Arabic.
+  setenv( "LANG", "ar_AE.UTF-8", 1 );
+  setenv( "LANGUAGE", "ar_AE:ar", 1 );
+
+  test_return_value = TET_UNDEF;
+}
+
+void dali_textselectionpopupmirroringrtl_cleanup(void)
+{
+  // Restore the locale environment.
+  setenv( "LANG", gLocaleLang.c_str(), 1 );
+  setenv( "LANGUAGE", gLocaleLanguage.c_str(), 1 );
+
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliToolkitTextSelectionPopupMirroringRTL(void)
+{
+  // Test the popup mirroring.
+  const std::string CUT( "optionCut" );
+  const std::string COPY( "optionCopy" );
+  const std::string PASTE( "optionPaste" );
+
+  ToolkitTestApplication application;
+
+  setlocale( LC_ALL, "ar_AE.UTF-8" );
+  textdomain("dali-toolkit");
+  bindtextdomain("dali-toolkit", DEFAULT_LOCALE_DIR );
+
+  TextSelectionPopup textSelectionPopup = TextSelectionPopup::New( NULL );
+
+  // Enable some buttons.
+  TextSelectionPopup::Buttons buttons = static_cast<TextSelectionPopup::Buttons>( TextSelectionPopup::COPY | TextSelectionPopup::CUT | TextSelectionPopup::PASTE );
+  textSelectionPopup.EnableButtons( buttons );
+
+  // Show the popup.
+  textSelectionPopup.ShowPopup();
+
+  Actor cutActor = textSelectionPopup.FindChildByName( CUT );
+  if( !cutActor )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  Actor tableOfButtons = cutActor.GetParent();
+  if( !tableOfButtons )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  // The order should be PASTE, CUT, COPY
+  DALI_TEST_EQUALS( PASTE, tableOfButtons.GetChildAt( 0 ).GetName(), TEST_LOCATION );
+  DALI_TEST_EQUALS( CUT, tableOfButtons.GetChildAt( 2 ).GetName(), TEST_LOCATION );
+  DALI_TEST_EQUALS( COPY, tableOfButtons.GetChildAt( 4 ).GetName(), TEST_LOCATION );
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextureManager.cpp
new file mode 100644 (file)
index 0000000..72370db
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2019 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/public-api/rendering/texture-set.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+} // namespace
+
+
+void dali_texture_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_texture_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliTextureManagerAddRemoveP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  std::string url;
+  std::string url2;
+  std::string url3;
+  std::string url4;
+  // scope to ensure texturesets are kept alive by texture manager
+  {
+    auto texture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, 88, 99 );
+    url = TextureManager::AddTexture( texture );
+    DALI_TEST_CHECK( url.size() > 0u );
+
+    auto textureSet = TextureSet::New();
+    textureSet.SetTexture( 0u, texture );
+    url2 = TextureManager::AddTexture( textureSet );
+    DALI_TEST_CHECK( url2.size() > 0u );
+    DALI_TEST_CHECK( url2 != url );
+
+    // add same texture again, should give new Url
+    url3 = TextureManager::AddTexture( texture );
+    DALI_TEST_CHECK( url3.size() > 0u );
+    DALI_TEST_CHECK( url3 != url );
+    DALI_TEST_CHECK( url3 != url2 );
+
+    textureSet = TextureSet::New();
+    url4 = TextureManager::AddTexture( textureSet );
+    DALI_TEST_CHECK( url4.size() > 0u );
+    DALI_TEST_CHECK( url4 != url );
+    DALI_TEST_CHECK( url4 != url2 );
+    DALI_TEST_CHECK( url4 != url3 );
+  }
+
+  auto textureSet = TextureManager::RemoveTexture( url );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  auto texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url2 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url2 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url3 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  texture = textureSet.GetTexture( 0u );
+  DALI_TEST_EQUAL( texture.GetWidth(), 88u );
+  DALI_TEST_EQUAL( texture.GetHeight(), 99u );
+  textureSet = TextureManager::RemoveTexture( url3 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  textureSet = TextureManager::RemoveTexture( url4 );
+  DALI_TEST_CHECK( textureSet && "Texture needs to be non empty handle" );
+  textureSet = TextureManager::RemoveTexture( url4 );
+  DALI_TEST_CHECK( !textureSet && "Texture needs to be removed from texture manager" );
+
+  END_TEST;
+}
+
+int UtcDaliTextureManagerAddN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  // empty texture is ok, though pointless from app point of view
+  TextureSet empty;
+  std::string url = TextureManager::AddTexture( empty );
+  DALI_TEST_CHECK( url.size() > 0u );
+
+  END_TEST;
+}
+
+int UtcDaliTextureManagerRemoveN(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextureManager" );
+
+  // removing empty texture returns empty handle
+  auto texture = TextureManager::RemoveTexture( "" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // removing empty texture returns empty handle
+  texture = TextureManager::RemoveTexture( "dali://" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // empty texture is ok, though pointless from app point of view
+  TextureSet empty;
+  std::string url = TextureManager::AddTexture( empty );
+  DALI_TEST_CHECK( url.size() > 0u );
+  // removing texture with wrong URL returns empty handle
+  texture = TextureManager::RemoveTexture( "dali://" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // removing ftp texture returns empty handle
+  texture = TextureManager::RemoveTexture( "ftp://foobar" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  // add a texture
+  url = TextureManager::AddTexture( texture );
+  texture = TextureManager::RemoveTexture( url + "foo" );
+  DALI_TEST_CHECK( !texture && "Texture should not be found" );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp
new file mode 100755 (executable)
index 0000000..2f75b37
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2017 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/controls/buttons/toggle-button.h>
+
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void dali_toggle_button_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_toggle_button_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+static const char* TEST_IMAGE_ONE   = TEST_RESOURCE_DIR "/icon-delete.png";
+static const char* TEST_IMAGE_TWO   = TEST_RESOURCE_DIR "/icon-edit.png";
+static const char* TEST_IMAGE_THREE = TEST_RESOURCE_DIR "/popup_tail_down.png";
+static const char* TEST_IMAGE_FOUR  = TEST_RESOURCE_DIR "/popup_tail_up.png";
+
+static const Vector2 INSIDE_TOUCH_POINT_POSITON  = Vector2( 240, 400 );
+static const Vector3 BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS  = Vector3( 200, 360, 0 );
+static const Size BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS  = Size( 100, 100 );
+
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+Dali::Integration::Point GetPointDownInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::DOWN );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+Dali::Integration::Point GetPointUpInside()
+{
+  Dali::Integration::Point point;
+  point.SetState( PointState::UP );
+  point.SetScreenPosition( INSIDE_TOUCH_POINT_POSITON );
+  return point;
+}
+
+}
+
+int UtcDaliToggleButtonConstructorP(void)
+{
+  TestApplication application;
+  tet_infoline(" UtcDaliToggleButtonConstructorP");
+
+  ToggleButton button;
+  DALI_TEST_CHECK( !button );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonCopyConstructorP(void)
+{
+  TestApplication application;
+  tet_infoline(" UtcDaliToggleButtonCopyConstructorP");
+
+  // Initialize an object, ref count == 1
+  ToggleButton button = ToggleButton::New();
+
+  ToggleButton copy( button );
+  DALI_TEST_CHECK( copy );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonAssignmentOperatorP(void)
+{
+  TestApplication application;
+  tet_infoline(" UtcDaliToggleButtonAssignmentOperatorP");
+
+  ToggleButton button = ToggleButton::New();
+
+  ToggleButton copy( button );
+  DALI_TEST_CHECK( copy );
+
+  DALI_TEST_CHECK( button == copy );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonNewP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToggleButtonNewP");
+
+  // Create the Slider actor
+  ToggleButton toggleButton;
+
+  DALI_TEST_CHECK( !toggleButton );
+
+  toggleButton = ToggleButton::New();
+
+  DALI_TEST_CHECK( toggleButton );
+
+  ToggleButton toggleButton2(toggleButton);
+
+  DALI_TEST_CHECK( toggleButton2 == toggleButton );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect( &TestCallback );
+  {
+    ToggleButton toggleButton = ToggleButton::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonDestructorP(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToggleButtonDestructorP");
+
+  ToggleButton* toggleButton = new ToggleButton();
+  delete toggleButton;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliToggleButtonDownCast");
+
+  Handle handle = ToggleButton::New();
+  ToggleButton toggleButton = ToggleButton::DownCast( handle );
+
+  DALI_TEST_CHECK( toggleButton == handle );
+  END_TEST;
+}
+
+int UtcDaliToggleButtonToggleStatesProperty(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliToggleButtonToggleStatesProperty");
+
+  // Create the ToggleButton actor
+  ToggleButton toggleButton = ToggleButton::New();
+  Stage::GetCurrent().Add( toggleButton );
+  toggleButton.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  toggleButton.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  toggleButton.SetPosition( 0.0f, 0.0f );
+
+  {// Check empty array
+    Property::Array toggleIcons;
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleIcons );
+
+    application.SendNotification();
+    application.Render();
+
+    Property::Array resultIcons;
+    resultIcons = toggleButton.GetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS ).Get<Property::Array>();
+    DALI_TEST_CHECK( resultIcons.Count() == 0 );
+  }
+
+  {// Check non-empty Array
+    Property::Array toggleIcons;
+    toggleIcons.PushBack( TEST_IMAGE_ONE ); //Icons path
+    toggleIcons.PushBack( TEST_IMAGE_TWO );
+    toggleIcons.PushBack( TEST_IMAGE_THREE );
+    toggleIcons.PushBack( TEST_IMAGE_FOUR );
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleIcons );
+
+    application.SendNotification();
+    application.Render();
+
+    Property::Array resultIcons;
+    resultIcons = toggleButton.GetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS ).Get<Property::Array>();
+
+    // Check that the result is the same as
+    DALI_TEST_EQUALS( toggleIcons.Count(), resultIcons.Count(), TEST_LOCATION );
+    DALI_TEST_CHECK( toggleIcons[0].Get<std::string>() == resultIcons[0].Get<std::string>() );
+    DALI_TEST_CHECK( toggleIcons[1].Get<std::string>() == resultIcons[1].Get<std::string>() );
+    DALI_TEST_CHECK( toggleIcons[2].Get<std::string>() == resultIcons[2].Get<std::string>() );
+    DALI_TEST_CHECK( toggleIcons[3].Get<std::string>() == resultIcons[3].Get<std::string>() );
+  }
+
+  {// Check property::map
+    Property::Map propertyMap1;
+    Vector4 testColor1( 1.f, 0.5f, 0.3f, 0.2f );
+    propertyMap1.Insert( Toolkit::Visual::Property::TYPE,  Toolkit::Visual::COLOR);
+    propertyMap1.Insert(Toolkit::ColorVisual::Property::MIX_COLOR,  testColor1);
+
+    Property::Map propertyMap2;
+    Vector4 testColor2( 0.5f, 1.f, 0.3f, 0.2f );
+    propertyMap2.Insert(Toolkit::Visual::Property::TYPE,  Toolkit::Visual::COLOR);
+    propertyMap2.Insert(Toolkit::ColorVisual::Property::MIX_COLOR,  testColor2);
+
+    Property::Map propertyMap3;
+    Vector4 testColor3( 1.f, 0.5f, 1.f, 0.2f );
+    propertyMap3.Insert(Toolkit::Visual::Property::TYPE,  Toolkit::Visual::COLOR);
+    propertyMap3.Insert(Toolkit::ColorVisual::Property::MIX_COLOR,  testColor3);
+
+    Property::Array toggleMaps;
+    toggleMaps.Add( propertyMap1 );
+    toggleMaps.Add( propertyMap2 );
+    toggleMaps.Add( propertyMap3 );
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleMaps );
+
+    application.SendNotification();
+    application.Render();
+
+    Property::Array resultMaps;
+    resultMaps = toggleButton.GetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS ).Get<Property::Array>();
+
+    // Check that the result
+    DALI_TEST_EQUALS( toggleMaps.Count(), resultMaps.Count(), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliToggleButtonToggleTipsProperty( void )
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliToggleButtonToggleTipsProperty");
+
+  // Create the ToggleButton actor
+  ToggleButton toggleButton = ToggleButton::New();
+  Stage::GetCurrent().Add( toggleButton );
+  toggleButton.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  toggleButton.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  toggleButton.SetPosition( 0.0f, 0.0f );
+
+  { // Check empty tip array
+    Property::Array toggleIcons;
+    toggleIcons.PushBack( TEST_IMAGE_ONE ); //Icons path
+    toggleIcons.PushBack( TEST_IMAGE_TWO );
+    toggleIcons.PushBack( TEST_IMAGE_THREE );
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleIcons );
+
+    Property::Array toggleTips;
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::TOOLTIPS, toggleTips );
+
+    application.SendNotification();
+    application.Render();
+
+    Property::Array resultTips;
+    resultTips = toggleButton.GetProperty( Toolkit::ToggleButton::Property::TOOLTIPS ).Get<Property::Array>();
+    DALI_TEST_CHECK( resultTips.Count() == 0 );
+  }
+
+  { // Check non-empty tip array
+    Property::Array toggleIcons;
+    toggleIcons.PushBack( TEST_IMAGE_ONE ); //Icons path
+    toggleIcons.PushBack( TEST_IMAGE_TWO );
+    toggleIcons.PushBack( TEST_IMAGE_THREE );
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleIcons );
+
+    Property::Array toggleTips;
+    toggleTips.PushBack( "Button State A" ); //Tooltip string
+    toggleTips.PushBack( "Button State B" );
+    toggleTips.PushBack( "Button State C" );
+    toggleButton.SetProperty( Toolkit::ToggleButton::Property::TOOLTIPS, toggleTips );
+
+    application.SendNotification();
+    application.Render();
+
+    Property::Array resultTips;
+    resultTips = toggleButton.GetProperty( Toolkit::ToggleButton::Property::TOOLTIPS ).Get<Property::Array>();
+
+    //Check that the result is the same as
+    DALI_TEST_EQUALS( toggleTips.Count(), resultTips.Count(), TEST_LOCATION );
+    DALI_TEST_CHECK( toggleTips[0].Get<std::string>() == resultTips[0].Get<std::string>() );
+    DALI_TEST_CHECK( toggleTips[1].Get<std::string>() == resultTips[1].Get<std::string>() );
+    DALI_TEST_CHECK( toggleTips[2].Get<std::string>() == resultTips[2].Get<std::string>() );
+    DALI_TEST_CHECK( toggleTips[3].Get<std::string>() == resultTips[3].Get<std::string>() );
+  }
+  END_TEST;
+}
+
+int UtcDaliToggleButtonStateChange(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+  tet_infoline(" UtcDaliToggleButtonStateChange");
+
+  // Create the ToggleButton actor
+  ToggleButton toggleButton = ToggleButton::New();
+  Stage::GetCurrent().Add( toggleButton );
+  toggleButton.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  toggleButton.SetAnchorPoint(ParentOrigin::TOP_LEFT);
+  toggleButton.SetPosition( BUTTON_POSITON_TO_GET_INSIDE_TOUCH_EVENTS );
+  toggleButton.SetSize( BUTTON_SIZE_TO_GET_INSIDE_TOUCH_EVENTS );
+
+  Property::Array toggleIcons;
+  toggleIcons.PushBack( TEST_IMAGE_ONE ); //Icons path
+  toggleIcons.PushBack( TEST_IMAGE_TWO );
+  toggleIcons.PushBack( TEST_IMAGE_THREE );
+  toggleButton.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, toggleIcons );
+
+  Property::Array toggleTips;
+  toggleTips.PushBack( "Button State A" ); //Tooltip string
+  toggleTips.PushBack( "Button State B" );
+  toggleTips.PushBack( "Button State C" );
+  toggleButton.SetProperty( Toolkit::ToggleButton::Property::TOOLTIPS, toggleTips );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Array resultIcons;
+  resultIcons = toggleButton.GetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS ).Get<Property::Array>();
+  DALI_TEST_EQUALS( toggleIcons.Count(), resultIcons.Count(), TEST_LOCATION );
+
+  Property::Array resultTips;
+  resultTips = toggleButton.GetProperty( Toolkit::ToggleButton::Property::TOOLTIPS ).Get<Property::Array>();
+  DALI_TEST_EQUALS( toggleTips.Count(), resultTips.Count(), TEST_LOCATION );
+
+  int index;
+  DALI_TEST_CHECK( toggleButton.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ).Get( index ) );
+  DALI_TEST_EQUALS( index, 0, TEST_LOCATION );
+
+  Dali::Integration::TouchEvent event;
+
+  // Touch point down and up inside the button 3 times.
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( toggleButton.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ).Get( index ) );
+  DALI_TEST_EQUALS( index, 1, TEST_LOCATION );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( toggleButton.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ).Get( index ) );
+  DALI_TEST_EQUALS( index, 2, TEST_LOCATION );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointDownInside() );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  event.AddPoint( GetPointUpInside() );
+  application.ProcessEvent( event );
+
+  DALI_TEST_CHECK( toggleButton.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ).Get( index ) );
+  DALI_TEST_EQUALS( index, 0, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ToolBar.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ToolBar.cpp
new file mode 100644 (file)
index 0000000..a9cf36b
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2019 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/controls/tool-bar/tool-bar.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+static bool gObjectCreatedCallBackCalled;
+
+static void TestCallback(BaseHandle handle)
+{
+  gObjectCreatedCallBackCalled = true;
+}
+
+Actor CreateColorActor( const Vector4& color )
+{
+  DummyControl solidColorActor = DummyControl::New();
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(solidColorActor.GetImplementation());
+
+  VisualFactory factory = VisualFactory::Get();
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::COLOR;
+  map[ ColorVisual::Property::MIX_COLOR ] = color;
+  Visual::Base colorVisual = factory.CreateVisual( map );
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, colorVisual );
+
+  return solidColorActor;
+}
+
+} // namespace
+
+void dali_toolbar_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_toolbar_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+int UtcDaliToolBarNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolBarNew");
+
+  ToolBar toolbar;
+
+  DALI_TEST_CHECK( !toolbar );
+
+  toolbar = ToolBar::New();
+
+  DALI_TEST_CHECK( toolbar );
+
+  ToolBar toolbar2(toolbar);
+
+  DALI_TEST_CHECK( toolbar2 == toolbar );
+
+  //Additional check to ensure object is created by checking if it's registered
+  ObjectRegistry registry = Stage::GetCurrent().GetObjectRegistry();
+  DALI_TEST_CHECK( registry );
+
+  gObjectCreatedCallBackCalled = false;
+  registry.ObjectCreatedSignal().Connect(&TestCallback);
+  {
+    ToolBar toolbar = ToolBar::New();
+  }
+  DALI_TEST_CHECK( gObjectCreatedCallBackCalled );
+
+  Actor actor = toolbar;
+  toolbar = ToolBar::DownCast( actor );
+
+  DALI_TEST_CHECK( toolbar );
+  END_TEST;
+}
+
+int UtcDaliToolBarAddControl01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolBarAddControl01");
+
+  try
+  {
+    Actor control1 = CreateColorActor( Color::RED );
+    control1.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control2 = CreateColorActor( Color::RED );
+    control2.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control3 = CreateColorActor( Color::RED );
+    control3.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control4 = CreateColorActor( Color::RED );
+    control4.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control5 = CreateColorActor( Color::RED );
+    control5.SetSize( Vector2( 100.f, 100.f ) );
+
+    ToolBar toolbar = ToolBar::New();
+    toolbar.SetSize( Vector2( 600.f, 100.f ) );
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    toolbar.Add( control1 );
+    toolbar.AddControl( control2, 0.1f, Alignment::HorizontalLeft, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+    toolbar.AddControl( control3, 0.1f, Alignment::HorizontalCenter, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+    toolbar.AddControl( control4, 0.1f, Alignment::HorizontalCenter, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+    toolbar.AddControl( control5, 0.1f, Alignment::HorizontalRight, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+
+    Actor control6 = CreateColorActor( Color::RED );
+    control6.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control7 = CreateColorActor( Color::RED );
+    control7.SetSize( Vector2( 100.f, 100.f ) );
+    Actor control8 = CreateColorActor( Color::RED );
+    control8.SetSize( Vector2( 100.f, 100.f ) );
+
+    application.Render();
+    application.SendNotification();
+    application.Render();
+    application.SendNotification();
+
+    toolbar.AddControl( control6, 0.4f, Alignment::HorizontalLeft, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+    toolbar.AddControl( control7, 0.2f, Alignment::HorizontalCenter, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+    toolbar.AddControl( control8, 0.2f, Alignment::HorizontalRight, Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliToolBarAddControl02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolBarAddControl02");
+
+  bool daliAssert = false;
+
+  try
+  {
+    Actor control = CreateColorActor( Color::RED );
+
+    ToolBar toolbar = ToolBar::New();
+
+    toolbar.AddControl( control, 0.1f, static_cast<Alignment::Type>( 99 ), Alignment::Padding( 1.f, 1.f, 1.f, 1.f ) );
+  }
+  catch( DaliException e )
+  {
+    daliAssert = true;
+    tet_result(TET_PASS);
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  if( !daliAssert )
+  {
+    tet_result(TET_FAIL);
+  }
+  END_TEST;
+}
+
+int UtcDaliToolBarRemoveControl01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolBarRemoveControl01");
+
+  try
+  {
+    Actor control = CreateColorActor( Color::RED );
+
+    ToolBar toolbar = ToolBar::New();
+    toolbar.AddControl( control, 0.1f, Alignment::HorizontalLeft );
+
+    toolbar.RemoveControl( control );
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
+
+int UtcDaliToolBarRemoveControl02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliToolBarRemoveControl02");
+
+  try
+  {
+    Actor control01 = CreateColorActor( Color::RED );
+    Actor control02 = CreateColorActor( Color::RED );
+
+    ToolBar toolbar01 = ToolBar::New();
+    ToolBar toolbar02 = ToolBar::New();
+    toolbar01.AddControl( control01, 0.1f, Alignment::HorizontalLeft );
+    toolbar02.AddControl( control02, 0.1f, Alignment::HorizontalLeft );
+
+    toolbar02.RemoveControl( control01 );
+  }
+  catch( Dali::DaliException& e )
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_EQUALS(e.condition, "false", TEST_LOCATION);
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  try
+  {
+    Actor control = CreateColorActor( Color::RED );
+
+    ToolBar toolbar = ToolBar::New();
+    toolbar.AddControl( control, 0.1f, Alignment::HorizontalLeft );
+
+    toolbar.RemoveControl( control );
+    toolbar.RemoveControl( control );
+  }
+  catch( ... )
+  {
+    tet_result(TET_FAIL);
+  }
+
+  tet_result(TET_PASS);
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Toolkit.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Toolkit.cpp
new file mode 100644 (file)
index 0000000..bf75f39
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using namespace Toolkit;
+
+void dali_toolkit_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_toolkit_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcToolkitIsVertical(void)
+{
+  ToolkitTestApplication application;
+
+  bool bRet = false;
+
+  tet_infoline(" UtcToolkitIsVertical");
+  bRet = IsVertical(ControlOrientation::Up);
+  DALI_TEST_EQUALS( bRet, true, TEST_LOCATION );
+
+  bRet = IsVertical(ControlOrientation::Down);
+  DALI_TEST_EQUALS( bRet, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcToolkitIsHorizontal(void)
+{
+  ToolkitTestApplication application;
+
+  bool bRet = false;
+
+  tet_infoline(" UtcToolkitIsHorizontal");
+  bRet = IsHorizontal(ControlOrientation::Left);
+  DALI_TEST_EQUALS( bRet, true, TEST_LOCATION );
+
+  bRet = IsHorizontal(ControlOrientation::Right);
+  DALI_TEST_EQUALS( bRet, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Tooltip.cpp
new file mode 100644 (file)
index 0000000..3dfaec2
--- /dev/null
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (c) 2017 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>
+
+// Need to override adaptor classes for toolkit test harness, so include
+// test harness headers before dali headers.
+#include <dali-toolkit-test-suite-utils.h>
+#include <toolkit-timer.h>
+
+#include <dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void utc_dali_toolkit_tooltip_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_tooltip_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+
+Integration::HoverEvent GenerateSingleHover( TouchPoint::State state, const Vector2& screenPosition )
+{
+  Integration::HoverEvent hoverEvent;
+  Integration::Point point;
+  point.SetState( static_cast< PointState::Type >( state ) );
+  point.SetScreenPosition( screenPosition );
+  hoverEvent.points.push_back( point );
+  return hoverEvent;
+}
+
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+int UtcDaliTooltipGetWithoutSetting(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map is empty" );
+  DALI_TEST_EQUALS( true, map->Empty(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithString(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Hello Test" );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the text item" );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "Hello Test", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent valid text, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTextVisualMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::TEXT )
+                                                           .Add( TextVisual::Property::TEXT, "Hello TextVisual Test" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the text item" );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "Hello TextVisual Test", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual with TEXT property set, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTextVisualMapWithoutString(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::TEXT )
+                                                           .Add( TextVisual::Property::POINT_SIZE, 20 ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the point-size item" );
+  Property::Value* pointSizeValue = contentMap->Find( TextVisual::Property::POINT_SIZE );
+  DALI_TEST_CHECK( pointSizeValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( 20, pointSizeValue->Get< int >(), TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual without a TEXT property set, so ensure the hover signal has NOT been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithImageVisualMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+                                                           .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property map" );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check that the map contains the url item" );
+  Property::Value* urlValue = contentMap->Find( ImageVisual::Property::URL );
+  DALI_TEST_CHECK( urlValue );
+
+  tet_infoline( "Ensure it matches what we set" );
+  DALI_TEST_EQUALS( "dummy-url.png", urlValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent an ImageVisual, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithArray(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Array().Add( Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+                                                             .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                                        .Add( Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::TEXT )
+                                                             .Add( TextVisual::Property::TEXT, "Hello Array Test" ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Ensure map contains the content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+
+  tet_infoline( "Check content is a property array" );
+  Property::Array* contentArray = contentValue->GetArray();
+  DALI_TEST_CHECK( contentArray );
+
+  tet_infoline( "Ensure the array contains two items" );
+  DALI_TEST_EQUALS( 2u, contentArray->Count(), TEST_LOCATION );
+
+  tet_infoline( "Ensure first value is a map and contains the right item" );
+  const Property::Value mapValue1 = contentArray->GetElementAt( 0 );
+  Property::Map* map1 = mapValue1.GetMap();
+  DALI_TEST_CHECK( map1 );
+  Property::Value* urlValue = map1->Find( ImageVisual::Property::URL );
+  DALI_TEST_CHECK( urlValue );
+  DALI_TEST_EQUALS( "dummy-url.png", urlValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Ensure second value is a map and contains the right item" );
+  const Property::Value mapValue2 = contentArray->GetElementAt( 1 );
+  Property::Map* map2 = mapValue2.GetMap();
+  DALI_TEST_CHECK( map2 );
+  Property::Value* textValue = map2->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textValue );
+  DALI_TEST_EQUALS( "Hello Array Test", textValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "We sent an array, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithFullMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::TEXT )
+                                                           .Add( TextVisual::Property::TEXT, "Hello TextVisual Test" ) )
+                                      .Add( Tooltip::Property::LAYOUT, Vector2( 1.0f, 2.0f ) )
+                                      .Add( Tooltip::Property::WAIT_TIME, 2.5f )
+                                      .Add( Tooltip::Property::BACKGROUND, "tooltip-background.png" )
+                                      .Add( Tooltip::Property::TAIL, true )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::HOVER_POINT )
+                                      .Add( Tooltip::Property::HOVER_POINT_OFFSET, Vector2( 100.0f, 50.f ) )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 50 )
+                                      .Add( Tooltip::Property::DISAPPEAR_ON_MOVEMENT, true )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check content" );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+
+  tet_infoline( "Check layout" );
+  Property::Value* layoutValue = map->Find( Tooltip::Property::LAYOUT );
+  DALI_TEST_CHECK( layoutValue );
+  DALI_TEST_EQUALS( layoutValue->Get< Vector2 >(), Vector2( 1.0f, 2.0f ), TEST_LOCATION );
+
+  tet_infoline( "Check wait time" );
+  Property::Value* waitTimeValue = map->Find( Tooltip::Property::WAIT_TIME );
+  DALI_TEST_CHECK( waitTimeValue );
+  DALI_TEST_EQUALS( waitTimeValue->Get< float >(), 2.5f, TEST_LOCATION );
+
+  tet_infoline( "Check background" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check Tail" );
+  Property::Value* tailMapValue = map->Find( Tooltip::Property::TAIL );
+  DALI_TEST_CHECK( tailMapValue );
+  Property::Map* tailMap = tailMapValue->GetMap();
+  DALI_TEST_CHECK( tailMap );
+  Property::Value* tailVisibilityValue = tailMap->Find( Tooltip::Tail::Property::VISIBILITY );
+  DALI_TEST_CHECK( tailVisibilityValue );
+  DALI_TEST_EQUALS( tailVisibilityValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "Check position" );
+  Property::Value* positionValue = map->Find( Tooltip::Property::POSITION );
+  DALI_TEST_CHECK( positionValue );
+  DALI_TEST_EQUALS( positionValue->Get< int >(), static_cast< int >( Tooltip::Position::HOVER_POINT ), TEST_LOCATION );
+
+  tet_infoline( "Check hover point offset" );
+  Property::Value* hoverPointOffsetValue = map->Find( Tooltip::Property::HOVER_POINT_OFFSET );
+  DALI_TEST_CHECK( hoverPointOffsetValue );
+  DALI_TEST_EQUALS( hoverPointOffsetValue->Get< Vector2 >(), Vector2( 100.0f, 50.f ), TEST_LOCATION );
+
+  tet_infoline( "Check movement threshold" );
+  Property::Value* movementThresholdValue = map->Find( Tooltip::Property::MOVEMENT_THRESHOLD );
+  DALI_TEST_CHECK( movementThresholdValue );
+  DALI_TEST_EQUALS( movementThresholdValue->Get< int >(), 50, TEST_LOCATION );
+
+  tet_infoline( "Check disappear on movement" );
+  Property::Value* disappearOnMovementValue = map->Find( Tooltip::Property::DISAPPEAR_ON_MOVEMENT );
+  DALI_TEST_CHECK( disappearOnMovementValue );
+  DALI_TEST_EQUALS( disappearOnMovementValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "We sent a text visual with TEXT property set, so ensure the hover signal has been connected to" );
+  DALI_TEST_EQUALS( control.HoveredSignal().GetConnectionCount(), 1u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithBackgroundMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::BACKGROUND,
+                                            Property::Map().Add( Tooltip::Background::Property::VISUAL, "tooltip-background.png" )
+                                                           .Add( Tooltip::Background::Property::BORDER, Rect< int >( 10, 20, 30, 40 ) ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check background map" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+
+  tet_infoline( "Check visual" );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check border" );
+  Property::Value* borderValue = backgroundMap->Find( Tooltip::Background::Property::BORDER );
+  DALI_TEST_CHECK( borderValue );
+  DALI_TEST_EQUALS( borderValue->Get< Rect< int > >(), Rect< int >( 10, 20, 30, 40 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithBackgroundMapVector4(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::BACKGROUND,
+                                            Property::Map().Add( Tooltip::Background::Property::VISUAL, "tooltip-background.png" )
+                                                           .Add( Tooltip::Background::Property::BORDER, Vector4( 40.0f, 30.0f, 20.0f, 10.0f ) ) )
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check background map" );
+  Property::Value* backgroundMapValue = map->Find( Tooltip::Property::BACKGROUND );
+  DALI_TEST_CHECK( backgroundMapValue );
+  Property::Map* backgroundMap = backgroundMapValue->GetMap();
+  DALI_TEST_CHECK( backgroundMap );
+
+  tet_infoline( "Check visual" );
+  Property::Value* backgroundStringValue = backgroundMap->Find( Tooltip::Background::Property::VISUAL );
+  DALI_TEST_CHECK( backgroundStringValue );
+  DALI_TEST_EQUALS( backgroundStringValue->Get< std::string >(), "tooltip-background.png", TEST_LOCATION );
+
+  tet_infoline( "Check border" );
+  Property::Value* borderValue = backgroundMap->Find( Tooltip::Background::Property::BORDER );
+  DALI_TEST_CHECK( borderValue );
+  DALI_TEST_EQUALS( borderValue->Get< Rect< int > >(), Rect< int >( 40, 30, 20, 10 ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipCreateWithTailMap(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Hello TextVisual Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  tet_infoline( "Check if Property::MAP is returned" );
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+
+  tet_infoline( "Ensure map is valid" );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  tet_infoline( "Check Tail" );
+  Property::Value* tailMapValue = map->Find( Tooltip::Property::TAIL );
+  DALI_TEST_CHECK( tailMapValue );
+  Property::Map* tailMap = tailMapValue->GetMap();
+  DALI_TEST_CHECK( tailMap );
+
+  tet_infoline( "Check visibility" );
+  Property::Value* tailVisibilityValue = tailMap->Find( Tooltip::Tail::Property::VISIBILITY );
+  DALI_TEST_CHECK( tailVisibilityValue );
+  DALI_TEST_EQUALS( tailVisibilityValue->Get< bool >(), true, TEST_LOCATION );
+
+  tet_infoline( "Check above visual" );
+  Property::Value* aboveVisualValue = tailMap->Find( Tooltip::Tail::Property::ABOVE_VISUAL );
+  DALI_TEST_CHECK( aboveVisualValue );
+  DALI_TEST_EQUALS( aboveVisualValue->Get< std::string >(), "above-visual.png", TEST_LOCATION );
+
+  tet_infoline( "Check below visual" );
+  Property::Value* belowVisualValue = tailMap->Find( Tooltip::Tail::Property::BELOW_VISUAL );
+  DALI_TEST_CHECK( belowVisualValue );
+  DALI_TEST_EQUALS( belowVisualValue->Get< std::string >(), "below-visual.png", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplay(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Stationary, centerPoint ) ); // Emit for code coverage, will have no effect
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayWithTail(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayWithContentArray(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT,
+                                            Property::Array().Add( Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+                                                                                  .Add( ImageVisual::Property::URL, "dummy-url.png" ) )
+                                                             .Add( Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::TEXT )
+                                                                                  .Add( TextVisual::Property::TEXT, "Hello Array Test" ) ))
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ))
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayBelow(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is below control" );
+  DALI_TEST_CHECK( ( control.GetCurrentWorldPosition().y + 50.0f /* Half Size */) < tooltip.GetCurrentWorldPosition().y );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayAbove(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::ABOVE )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is above control" );
+  DALI_TEST_CHECK( ( control.GetCurrentWorldPosition().y - 50.0f /* Half Size */) >= ( tooltip.GetCurrentWorldPosition().y + 0.5f * tooltip.GetCurrentSize().height ) );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipDisplayAtHoverPoint(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::HOVER_POINT )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  const Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 hoverPoint = stageSize * 0.5f;
+  hoverPoint.x -= 10.0f;
+  hoverPoint.y -= 10.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+
+  tet_infoline( "Ensure tooltip is below and to the right of control" );
+  DALI_TEST_CHECK( ( hoverPoint.y - stageSize.height * 0.5f ) < tooltip.GetCurrentWorldPosition().y );
+  DALI_TEST_CHECK( ( hoverPoint.x - stageSize.width  * 0.5f ) < tooltip.GetCurrentWorldPosition().x );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipExceedThreshold(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 5 )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  tet_infoline( "Start hover" );
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit a value which exceeds threshold, timer should start again" );
+  hoverPoint.x += 10.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit Timer signal - timeout at new point which is still within bounds" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipGoOutOfBounds(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  tet_infoline( "Start hover" );
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit a value which goes out of bounds" );
+  hoverPoint.x += 100.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Emit Timer signal - nothing should happen" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be the same as before" );
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipHideTooltipWhenOutOfBounds(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  hoverPoint.x += 100.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be back to what was there before the tooltip was shown" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipHideTooltipWhenSetToDisapperOnMovement(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::DISAPPEAR_ON_MOVEMENT, true )
+                                      .Add( Tooltip::Property::MOVEMENT_THRESHOLD, 5 )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 hoverPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, hoverPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  hoverPoint.x += 10.0f; // Stay within bounds but exceed threshold
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, hoverPoint ) );
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should be back to what was there before the tooltip was shown" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipChangeContent(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Control control = Control::New();
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Test" );
+  control.SetAnchorPoint( AnchorPoint::CENTER );
+  control.SetParentOrigin( ParentOrigin::CENTER );
+  control.SetSize( 100.0f, 100.0f );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  int rootChildCount = rootActor.GetChildCount();
+
+  Vector2 centerPoint = Stage::GetCurrent().GetSize() * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  tet_infoline( "Change content while timer is running and ensure it matches the new value" );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Second Value" );
+
+  Property::Value value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  Property::Value* contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  Property::Map* contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+  Property::Value* textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+  DALI_TEST_EQUALS( "Second Value", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Emit signal, nothing should happen as everything has been reset" );
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, there should NOT be any new actors" );
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  tet_infoline( "More movement at same point, and emit signal, we should get the tooltip" );
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Motion, centerPoint ) );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, they should have incremented by one" );
+  ++rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  tet_infoline( "Change content while tooltip is showing, current one should be removed from the stage and ensure it matches new value" );
+  control.SetProperty( DevelControl::Property::TOOLTIP, "Third Value" );
+
+  value = control.GetProperty( DevelControl::Property::TOOLTIP );
+  DALI_TEST_EQUALS( value.GetType(), Property::MAP, TEST_LOCATION );
+  map = value.GetMap();
+  DALI_TEST_CHECK( map );
+  contentValue = map->Find( Tooltip::Property::CONTENT );
+  DALI_TEST_CHECK( contentValue );
+  contentMap = contentValue->GetMap();
+  DALI_TEST_CHECK( contentMap );
+  textStringValue = contentMap->Find( TextVisual::Property::TEXT );
+  DALI_TEST_CHECK( textStringValue );
+  DALI_TEST_EQUALS( "Third Value", textStringValue->Get< std::string >(), TEST_LOCATION );
+
+  tet_infoline( "Emit signal, nothing should happen as everything has been reset" );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Get number of actors on the Stage, there should be one less actor on the stage" );
+  --rootChildCount;
+  DALI_TEST_EQUALS( rootActor.GetChildCount(), rootChildCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage1(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  tet_infoline( "Create a control and place it at the bottom of the screen, setting the tooltip to appear below" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = stageSize * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().y + tooltip.GetCurrentSize().height * 0.5f ) <= centerPoint.height );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage2(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+
+  tet_infoline( "Create a control and place it at the top of the screen, setting the tooltip to appear above" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  control.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::ABOVE )
+                     );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 centerPoint = stageSize * 0.5f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().y - tooltip.GetCurrentSize().height * 0.5f ) >= -centerPoint.height );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage3(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 centerPoint = stageSize * 0.5f;
+
+  tet_infoline( "Create a control and adjust it's position so that the tooltip will attempt to appear to the left of the screen" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+  control.SetX( -centerPoint.x );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 hoverPoint( centerPoint );
+  hoverPoint.x = 1.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().x - tooltip.GetCurrentSize().width * 0.5f ) >= -centerPoint.width );
+
+  END_TEST;
+}
+
+int UtcDaliTooltipEnsureRemainsOnStage4(void)
+{
+  ToolkitTestApplication application;  // Exceptions require ToolkitTestApplication
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  Vector2 centerPoint = stageSize * 0.5f;
+
+  tet_infoline( "Create a control and adjust it's position so that the tooltip will attempt to appear to the right of the screen" );
+  Control control = Control::New();
+  control.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  control.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  control.SetSize( stageSize );
+  control.SetProperty( DevelControl::Property::TOOLTIP,
+                       Property::Map().Add( Tooltip::Property::CONTENT, "Test" )
+                                      .Add( Tooltip::Property::TAIL,
+                                            Property::Map().Add( Tooltip::Tail::Property::VISIBILITY, true )
+                                                           .Add( Tooltip::Tail::Property::ABOVE_VISUAL, "above-visual.png" )
+                                                           .Add( Tooltip::Tail::Property::BELOW_VISUAL, "below-visual.png" ) )
+                                      .Add( Tooltip::Property::POSITION, Tooltip::Position::BELOW )
+                     );
+  control.SetX( centerPoint.x );
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  rootActor.Add( control );
+
+  application.SendNotification();
+  application.Render();
+
+  Vector2 hoverPoint( centerPoint );
+  hoverPoint.x = 1.0f;
+  application.ProcessEvent( GenerateSingleHover( TouchPoint::Started, centerPoint ) );
+
+  Dali::Timer timer = Timer::New( 1u );
+  timer.MockEmitSignal();
+
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline( "Ensure tooltip is still on the screen" );
+  Actor tooltip = rootActor.GetChildAt( rootActor.GetChildCount() - 1 ); // Last actor added will be our tooltip
+  DALI_TEST_CHECK( ( tooltip.GetCurrentWorldPosition().x + tooltip.GetCurrentSize().width * 0.5f ) <= centerPoint.width );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TransitionData.cpp
new file mode 100644 (file)
index 0000000..1db1bc5
--- /dev/null
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 2019 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.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Toolkit;
+
+
+void utc_dali_toolkit_transition_data_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_toolkit_transition_data_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+Property::Map CreateMap()
+{
+  Property::Map map;
+
+  map["target"] = "Actor1";
+  map["property"] = "color";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT_BACK")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+  return map;
+}
+
+void CHECK_ARRAY_EQUALS( Property::Array test, Property::Value result )
+{
+  if( result.GetType() == Property::ARRAY )
+  {
+    // Compare arrays
+    Property::Array *resultArray = result.GetArray();
+    DALI_TEST_EQUALS( test.Count(), resultArray->Count(), TEST_LOCATION );
+    for( size_t i=0; i < std::min(test.Count(), resultArray->Count()); ++i )
+    {
+      Property::Value a = test.GetElementAt(i);
+      Property::Value b = resultArray->GetElementAt(i);
+      DALI_TEST_EQUALS( a.GetType(), b.GetType(), TEST_LOCATION );
+      DALI_TEST_EQUALS( a, b, 0.001, TEST_LOCATION );
+    }
+  }
+  else if( result.GetType() == Property::VECTOR4 )
+  {
+    Vector4 value = result.Get<Vector4>();
+    DALI_TEST_CHECK( test.Count() >= 4 );
+    for( size_t i=0; i < 4; ++i )
+    {
+      Property::Value a = test.GetElementAt(i);
+      DALI_TEST_EQUALS( a.GetType(), Property::FLOAT, TEST_LOCATION );
+      DALI_TEST_EQUALS( a.Get<float>(), value[i], 0.001, TEST_LOCATION );
+    }
+  }
+  else
+  {
+    DALI_TEST_CHECK( 0 );
+  }
+}
+
+void CHECK_MAP_EQUALS( Property::Map test, Property::Map result )
+{
+  DALI_TEST_EQUALS(test.Count(), result.Count(), TEST_LOCATION);
+
+  for( unsigned int i=0; i< test.Count(); ++i )
+  {
+    KeyValuePair keyValue = test.GetKeyValue(i);
+    Property::Value* value;
+
+    if( keyValue.first.type == Property::Key::STRING )
+    {
+      value = result.Find(keyValue.first.stringKey);
+    }
+    else
+    {
+      value = result.Find(keyValue.first.indexKey);
+    }
+
+    DALI_TEST_CHECK( value != NULL );
+    if( value != NULL )
+    {
+      if( keyValue.second.GetType() == Property::MAP )
+      {
+        DALI_TEST_EQUALS( keyValue.second.GetType(), value->GetType(), TEST_LOCATION );
+        CHECK_MAP_EQUALS( *(keyValue.second.GetMap()), *(value->GetMap()) );
+      }
+      else if( keyValue.second.GetType() == Property::ARRAY )
+      {
+        CHECK_ARRAY_EQUALS( *(keyValue.second.GetArray()), *value );
+      }
+      else if( keyValue.second.GetType() == Property::STRING )
+      {
+        DALI_TEST_EQUALS( keyValue.second.GetType(), value->GetType(), TEST_LOCATION );
+        std::string str;
+        value->Get(str);
+        DALI_TEST_EQUALS( keyValue.second, str.c_str(), TEST_LOCATION );
+      }
+      else
+      {
+        DALI_TEST_EQUALS( keyValue.second.GetType(), value->GetType(), TEST_LOCATION );
+        DALI_TEST_EQUALS( keyValue.second, *value, 0.001f, TEST_LOCATION );
+      }
+    }
+  }
+}
+
+
+int UtcDaliTransitionDataNew(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map = CreateMap();
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+  DALI_TEST_CHECK( transition );
+
+  END_TEST;
+}
+
+int UtcDaliTransitionDataDownCast(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map = CreateMap();
+
+  BaseHandle handle = TransitionData::New( map );
+  DALI_TEST_CHECK( handle );
+
+  TransitionData transitionData = TransitionData::DownCast( handle );
+  DALI_TEST_CHECK( transitionData );
+  END_TEST;
+}
+
+int UtcDaliTransitionDataCopyConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map = CreateMap();
+
+  TransitionData transitionData = TransitionData::New( map );
+  DALI_TEST_CHECK( transitionData );
+
+  TransitionData td2( transitionData );
+  DALI_TEST_CHECK( td2 );
+  DALI_TEST_EQUALS( td2.Count(), 1, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliTransitionDataAssignmentOperator(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map = CreateMap();
+
+  TransitionData transitionData = TransitionData::New( map );
+  DALI_TEST_CHECK( transitionData );
+
+  TransitionData td2;
+  DALI_TEST_CHECK( !td2 );
+
+  td2 = transitionData;
+  DALI_TEST_CHECK( td2 );
+
+  DALI_TEST_EQUALS( td2.Count(), 1, TEST_LOCATION );
+  END_TEST;
+}
+
+int UtcDaliTransitionDataCount(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map = CreateMap();
+  TransitionData transitionData = TransitionData::New( map );
+  DALI_TEST_CHECK( transitionData );
+  DALI_TEST_EQUALS( transitionData.Count(), 1, TEST_LOCATION );
+
+  Property::Array array;
+  array.PushBack( map );
+  array.PushBack( map );
+  array.PushBack( map );
+
+  TransitionData transitionData2 = TransitionData::New( array );
+  DALI_TEST_CHECK( transitionData2 );
+  DALI_TEST_EQUALS( transitionData2.Count(), 3, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTransitionDataMap1P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation of a visual property using stylesheet equivalent maps\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "mixColor";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector3>(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  application.Render(500); // End of anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::RED), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+int UtcDaliTransitionDataMap2P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation of a visual property using programmatic maps\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = ColorVisual::Property::MIX_COLOR;
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector3>(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION);
+
+  application.Render(500); // End of anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::RED), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMap2Pb(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation of a visual property using programmatic maps\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = PrimitiveVisual::Property::MIX_COLOR;
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::PRIMITIVE;
+  visualMap[PrimitiveVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  visualMap[ PrimitiveVisual::Property::SHAPE  ] = PrimitiveVisual::Shape::SPHERE;
+  visualMap[ PrimitiveVisual::Property::SLICES ] = 10;
+  visualMap[ PrimitiveVisual::Property::STACKS ] = 10;
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, PrimitiveVisual::Property::MIX_COLOR );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector3>(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION);
+
+  application.Render(500); // End of anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::RED), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMap3P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation of an actor's position property using bezier curve\n");
+
+  Property::Map map;
+  map["target"] = "Actor1";
+  map["property"] = "position";
+  map["initialValue"] = Vector3(0, 0, 0);
+  map["targetValue"] = Vector3(100, 100, 0);
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", Vector4(0.71, -0.57, 0.42, 1.38) )
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(0,0,0), 0.001f, TEST_LOCATION);
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(0);
+
+  application.Render(250); // 25%
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(-10,-10,0), 1.0, TEST_LOCATION); // High epsilon as we don't have exact figure for bezier curve at 50%
+
+  application.Render(250); // Halfway thru map1 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(24,24,0), 1.0, TEST_LOCATION); // High epsilon as we don't have exact figure for bezier curve at 50%
+
+  application.Render(250); // End of map1 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(100,100,0), 1.0, TEST_LOCATION); // High epsilon as we don't have exact figure for bezier curve
+
+  application.Render(250); // End of map1 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(100,100,0), TEST_LOCATION );
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMap4P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation of a visual's transform property using programmatic maps\n");
+
+  Property::Map map1;
+  map1["target"] = "testVisual";
+  map1["property"] = "offset";
+  map1["initialValue"] = Vector2(0.0f, 0.0f);
+  map1["targetValue"] = Vector2(100.0f, 100.0f);
+  map1["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Property::Map map2;
+  map2["target"] = "testVisual";
+  map2["property"] = "size";
+  map2["initialValue"] = Vector2(10.0f, 10.0f);
+  map2["targetValue"] = Vector2(110.0f, 110.0f);
+  map2["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( Property::Array().Add(map1).Add(map2) );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+
+  visual.SetName( "testVisual" );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index sizeIndex = renderer.GetPropertyIndex( "size" );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector2>(sizeIndex), Vector2(10.0f, 10.0f), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector2 >( sizeIndex ), Vector2(10.0f, 10.0f), TEST_LOCATION);
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector2 >( sizeIndex ), Vector2(60.0f, 60.0f), TEST_LOCATION);
+
+  application.Render(500); // End of anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector2 >( sizeIndex ), Vector2(110.0f, 110.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliTransitionDataMap5P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation visual opacity using stylesheet equivalent maps\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "opacity";
+  map["initialValue"] = 0.0f;
+  map["targetValue"] = 1.0f;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector3>(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 0.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetProperty<int>(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 0.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::ON, TEST_LOCATION );
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 0.5f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::ON, TEST_LOCATION );
+
+  application.Render(501); // End of anim
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMap6P(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing animation visual opacity using stylesheet equivalent maps\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "opacity";
+  map["targetValue"] = 0.0f;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+  application.SendNotification();
+  application.Render(0);
+
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector3>(mixColorIndex), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 1.0f, 0.001f, TEST_LOCATION );
+
+  // Note, This should be testing for AUTO
+  // this is the same problem as C# target value being set before Play is called.
+  // @todo How was this solved?
+  DALI_TEST_EQUALS( renderer.GetProperty<int>(Renderer::Property::BLEND_MODE), (int)BlendMode::ON, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::ON, TEST_LOCATION );
+
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(500); // Start animation
+  application.Render(500); // Halfway thru anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION);
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 0.5f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::ON, TEST_LOCATION );
+
+  application.Render(500); // End of anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< Vector3 >( mixColorIndex ), Vector3(Color::MAGENTA), TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< float >( DevelRenderer::Property::OPACITY ), 0.0f, 0.001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( renderer.GetCurrentProperty< int >( Renderer::Property::BLEND_MODE ), (int)BlendMode::ON, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMap1N(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map;
+  map["target"] = "Actor1";
+  map["property"] = "randomProperty";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( ! anim );
+
+  CHECK_MAP_EQUALS( map, transition.GetAnimatorAt(0) );
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMapN3(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing visual lookup with no renderers\n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "mixColor";
+  map["initialValue"] = Vector3(Color::MAGENTA);
+  map["targetValue"] = Vector3(Color::RED);
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_OUT_BACK")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+  CHECK_MAP_EQUALS( map, transition.GetAnimatorAt(0) );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  // Don't stage actor
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Vector3(Color::MAGENTA);
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( !anim );
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataMapN4(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing visual doesn't animate with duff bezier data \n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "mixColor";
+  map["initialValue"] = Vector3(Color::MAGENTA);
+  map["targetValue"] = Vector3(Color::RED);
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", Vector3(.1f,1.0f,0.5f))
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( !anim );
+
+  application.SendNotification();
+  application.Render(0);
+  application.SendNotification();
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+
+  tet_printf( "Test that the property has been set to target value\n");
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionDataMapN5(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing visual doesn't animate with duff bezier data \n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "mixColor";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", Property::Array().Add(.1f).Add(1.0f).Add(0.5f))
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( !anim );
+
+  application.SendNotification();
+  application.Render(0);
+  application.SendNotification();
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+
+  tet_printf( "Test that the property has been set to target value\n");
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTransitionDataMapN6(void)
+{
+  ToolkitTestApplication application;
+
+  tet_printf("Testing visual doesn't animate with duff bezier data \n");
+
+  Property::Map map;
+  map["target"] = "visual1";
+  map["property"] = "mixColor";
+  map["initialValue"] = Color::MAGENTA;
+  map["targetValue"] = Color::RED;
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", Property::Array().Add("1").Add("Two").Add("3").Add("4"))
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Property::Map visualMap;
+  visualMap[Visual::Property::TYPE] = Visual::COLOR;
+  visualMap[ColorVisual::Property::MIX_COLOR] = Color::MAGENTA;
+  Visual::Base visual = VisualFactory::Get().CreateVisual( visualMap );
+  visual.SetName( "visual1" );
+
+  Property::Index visualIndex = Control::CONTROL_PROPERTY_END_INDEX + 1;
+  dummyImpl.RegisterVisual( visualIndex, visual );
+
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( !anim );
+
+  application.SendNotification();
+  application.Render(0);
+  application.SendNotification();
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIdx = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+
+  tet_printf( "Test that the property has been set to target value\n");
+  DALI_TEST_EQUALS(renderer.GetProperty<Vector3>(mixColorIdx), Vector3(Color::RED), 0.001, TEST_LOCATION);
+  DALI_TEST_EQUALS(renderer.GetProperty<float>( DevelRenderer::Property::OPACITY ), 1.0f, 0.001, TEST_LOCATION);
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataArrayP(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map1;
+  map1["target"] = "Actor1";
+  map1["property"] = "color";
+  map1["initialValue"] = Color::MAGENTA;
+  map1["targetValue"] = Color::RED;
+  map1["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 1.0f));
+
+  Property::Map map2;
+  map2["target"] = "Actor1";
+  map2["property"] = "position";
+  map2["initialValue"] = Vector3(100,0,0);
+  map2["targetValue"] = Vector3(0,100,0);
+  map2["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Property::Map map3;
+  map3["target"] = "Actor1";
+  map3["property"] = "orientation";
+  map3["targetValue"] = Quaternion( Radian(Math::PI_2), Vector3::ZAXIS );
+
+  Property::Array array;
+  array.PushBack(map1);
+  array.PushBack(map2);
+  array.PushBack(map3);
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( array );
+
+  DummyControl actor = DummyControl::New();
+  actor.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  actor.SetName("Actor1");
+  actor.SetColor(Color::CYAN);
+  Stage::GetCurrent().Add(actor);
+  DALI_TEST_EQUALS( actor.GetCurrentOrientation(), Quaternion(Radian(0), Vector3::ZAXIS), TEST_LOCATION);
+
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  Animation anim = dummyImpl.CreateTransition( transition );
+  DALI_TEST_CHECK( anim );
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::MAGENTA, TEST_LOCATION);
+  DALI_TEST_EQUALS( actor.GetCurrentOrientation(), Quaternion(Radian(Math::PI_2), Vector3::ZAXIS), TEST_LOCATION);
+  anim.Play();
+
+  application.SendNotification();
+  application.Render(0);   // start map2 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(100,0,0), TEST_LOCATION);
+
+  application.Render(500); // Start map1 animation, halfway thru map2 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(50,50,0), TEST_LOCATION);
+
+  application.Render(500); // Halfway thru map1 anim, end of map2 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3(0,100,0), TEST_LOCATION);
+  DALI_TEST_EQUALS( actor.GetCurrentColor(), (Color::MAGENTA+Color::RED)*0.5f, TEST_LOCATION);
+
+  application.Render(500); // End of map1 anim
+  application.SendNotification();
+  DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::RED, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTransitionDataGetAnimatorP(void)
+{
+  ToolkitTestApplication application;
+
+  Property::Map map1;
+  map1["target"] = "Actor1";
+  map1["property"] = "color";
+  map1["initialValue"] = Color::MAGENTA;
+  map1["targetValue"] = Color::RED;
+  map1["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_SQUARE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 0.5f));
+
+  Property::Map map2;
+  map2["target"] = "Actor1";
+  map2["property"] = "position";
+  map2["initialValue"] = Vector3(100,0,0);
+  map2["targetValue"] = Vector3(0,100,0);
+  map2["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_OUT_SQUARE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.2f)
+         .Add("duration", 2.0f));
+
+  Property::Map map3;
+  map3["target"] = "Actor1";
+  map3["property"] = "size";
+  map3["initialValue"] = Vector2(10,10);
+  map3["targetValue"] = Vector2(100,100);
+  map3["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_OUT_SINE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.4f)
+         .Add("duration", 3.0f));
+
+  Property::Map map4;
+  map4["target"] = "Actor2";
+  map4["property"] = "color";
+  map4["initialValue"] = Color::BLACK;
+  map4["targetValue"] = Color::GREEN;
+  map4["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_OUT_SINE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.5f)
+         .Add("duration", 0.5f));
+
+  Property::Map map5;
+  map5["target"] = "Actor2";
+  map5["property"] = "position";
+  map5["initialValue"] = Vector3(100,0,0);
+  map5["targetValue"] = Vector3(0,100,0);
+  map5["animator"] = Property::Map()
+    .Add("alphaFunction", "BOUNCE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.2f)
+         .Add("duration", 2.0f));
+
+  Property::Map map6;
+  map6["target"] = "Actor2";
+  map6["property"] = "size";
+  map6["initialValue"] = Vector2(10,10);
+  map6["targetValue"] = Vector2(100,100);
+  map6["animator"] = Property::Map()
+    .Add("alphaFunction", "SIN")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.4f)
+         .Add("duration", 3.0f));
+
+  Property::Map map7;
+  map7["target"] = "Actor4";
+  map7["property"] = "sizeModeFactor";
+  map7["initialValue"] = Vector3(1,1,1);
+  map7["targetValue"] = Vector3(2,2,2);
+  map7["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN_SINE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Property::Map map8;
+  map8["target"] = "Visual1";
+  map8["property"] = "opacity";
+  map8["initialValue"] = 0.0f;
+  map8["targetValue"] = 1.0f;
+  map8["animator"] = Property::Map()
+    .Add("alphaFunction", "EASE_IN")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.3f)
+         .Add("duration", 9.0f));
+
+  Property::Map map9;
+  map9["target"] = "Actor2";
+  map9["property"] = "scale";
+  map9["initialValue"] = Vector3(0,0,0);
+  map9["targetValue"] = Vector3(1,1,1);
+  map9["animator"] = Property::Map()
+    .Add("alphaFunction", "REVERSE")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Property::Map map10;
+  map10["target"] = "Actor2";
+  map10["property"] = "scale";
+  map10["initialValue"] = Vector3(0,0,0);
+  map10["targetValue"] = Vector3(1,1,1);
+  map10["animator"] = Property::Map()
+    .Add("alphaFunction", Vector4(.23,.4,.8,1.2))
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Property::Map map11;
+  map11["target"] = "Actor2";
+  map11["property"] = "scale";
+  map11["initialValue"] = Vector3(0,0,0);
+  map11["targetValue"] = Vector3(1,1,1);
+  map11["animator"] = Property::Map()
+    .Add("alphaFunction", Property::Array().Add(.23f).Add(.4f).Add(.8f).Add(.2f))
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 1.0f));
+
+  Property::Map map12;
+  map12["target"] = "Actor1";
+  map12["property"] = "orientation";
+  map12["targetValue"] = Quaternion( Radian(Math::PI_2), Vector3::ZAXIS );
+
+  Property::Array array;
+  array.PushBack(map1);
+  array.PushBack(map2);
+  array.PushBack(map3);
+  array.PushBack(map4);
+  array.PushBack(map5);
+  array.PushBack(map6);
+  array.PushBack(map7);
+  array.PushBack(map8);
+  array.PushBack(map9);
+  array.PushBack(map10);
+  array.PushBack(map11);
+  array.PushBack(map12);
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( array );
+
+  DALI_TEST_EQUALS( transition.Count(), array.Count(), TEST_LOCATION );
+
+  for( unsigned int i=0; i < array.Count(); ++i )
+  {
+    Property::Map animatorMap = transition.GetAnimatorAt(i);
+    Property::Value& value = array.GetElementAt(i);
+    Property::Map* inputMap = value.GetMap();
+    DALI_TEST_CHECK( inputMap );
+    CHECK_MAP_EQUALS( *inputMap, animatorMap );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VideoView.cpp
new file mode 100755 (executable)
index 0000000..a38ec18
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>
+#include <dali-toolkit/devel-api/controls/video-view/video-view-devel.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* const TEST_FILE( "test.mp4" );
+const char* const VOLUME_LEFT( "volumeLeft" );
+const char* const VOLUME_RIGHT( "volumeRight" );
+const char* const RENDERING_TYPE( "renderingTarget" );
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = aPosition + vec2(0.5);\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* fragmentShaderPrefix( "#extension GL_OES_EGL_image_external:require\n" );
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform samplerExternalOES sTexture;\n
+  uniform lowp vec4 uColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+  }\n
+);
+
+}
+
+void video_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void video_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Negative test case for a method
+int UtcDaliVideoViewUninitialized(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewUninitialized");
+
+  Toolkit::VideoView view;
+
+  try
+  {
+    // New() must be called to create a VideoView or it wont be valid.
+    Actor a = Actor::New();
+    view.Add( a );
+    DALI_TEST_CHECK( false );
+  }
+  catch (Dali::DaliException& e)
+  {
+    // Tests that a negative test of an assertion succeeds
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_CHECK(!view);
+  }
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliVideoViewNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewNew");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  Toolkit::VideoView view2 = Toolkit::VideoView::New( "" );
+  DALI_TEST_CHECK( view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliVideoViewDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewDownCast");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  BaseHandle handle(view);
+
+  Toolkit::VideoView view2 = Toolkit::VideoView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( view2 );
+  DALI_TEST_CHECK( view == view2 );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliVideoViewProperty1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewProperty1");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  std::string file;
+  view.SetProperty( VideoView::Property::VIDEO, TEST_FILE );
+  Property::Value val = view.GetProperty( VideoView::Property::VIDEO );
+  DALI_TEST_CHECK( val.Get( file ) );
+  DALI_TEST_CHECK( file == TEST_FILE );
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliVideoViewProperty1b(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewProperty1");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+  Stage stage = Stage::GetCurrent();
+
+  std::string file;
+  Property::Map map;
+
+  view.SetProperty( VideoView::Property::VIDEO, Property::Map()
+                    .Add("rendererType", "IMAGE")
+                    .Add("url", "video.mpg") // Note, videoView doesn't use this url
+                    .Add("RENDERING_TARGET", "windowSurfaceTarget" )
+                    .Add("width", 100)
+                    .Add("height", 100) );
+
+  stage.Add( view );
+
+  Property::Value val = view.GetProperty( VideoView::Property::VIDEO );
+  Property::Map* resultMap = val.GetMap();
+
+  DALI_TEST_CHECK( resultMap );
+  Property::Value* value = resultMap->Find("url");
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), "video.mpg", TEST_LOCATION );
+
+  stage.Remove( view );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewProperty2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewProperty2");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  bool looping;
+  Property::Value val = view.GetProperty( VideoView::Property::LOOPING );
+  DALI_TEST_CHECK( val.Get( looping ) );
+  DALI_TEST_CHECK( !looping );
+
+  view.SetProperty( VideoView::Property::LOOPING, true );
+  val = view.GetProperty( VideoView::Property::LOOPING );
+  DALI_TEST_CHECK( val.Get( looping ) );
+  DALI_TEST_CHECK( looping );
+  END_TEST;
+}
+
+int UtcDaliVideoViewProperty3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewProperty3");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  bool muted;
+  Property::Value val = view.GetProperty( VideoView::Property::MUTED );
+  DALI_TEST_CHECK( val.Get( muted ) );
+  DALI_TEST_CHECK( !muted );
+
+  view.SetProperty( VideoView::Property::MUTED, true );
+  val = view.GetProperty( VideoView::Property::MUTED );
+  DALI_TEST_CHECK( val.Get( muted ) );
+  DALI_TEST_CHECK( muted );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewProperty4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliVideoViewProperty4");
+
+  Toolkit::VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  float left, right;
+  left = right = 0.f;
+
+  Property::Map map;
+  map.Insert( VOLUME_LEFT, 0.5f );
+  map.Insert( VOLUME_RIGHT, 0.5f );
+
+  view.SetProperty( VideoView::Property::VOLUME, map );
+  Property::Value val = view.GetProperty( VideoView::Property::VOLUME );
+
+  Property::Map map2;
+  DALI_TEST_CHECK( val.Get( map2 ) );
+
+  Property::Value* volumeLeft = map2.Find( VOLUME_LEFT );
+  Property::Value* volumeRight = map2.Find( VOLUME_RIGHT );
+
+  DALI_TEST_CHECK( volumeLeft && volumeLeft->Get( left ) );
+  DALI_TEST_CHECK( volumeRight && volumeRight->Get( right ) );
+  DALI_TEST_CHECK( left == 0.5f );
+  DALI_TEST_CHECK( right == 0.5f );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  VideoView view = Toolkit::VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  VideoView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  VideoView assign;
+  DALI_TEST_CHECK( !assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "VideoView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  VideoView view = VideoView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewMethodsForCoverage(void)
+{
+  ToolkitTestApplication application;
+
+  VideoView videoView = VideoView::New();
+  DALI_TEST_CHECK( videoView );
+
+  videoView.Play();
+  videoView.Pause();
+  videoView.Stop();
+  videoView.Forward(10);
+  videoView.Backward(10);
+
+  Toolkit::DevelVideoView::GetMediaPlayer( videoView );
+
+  VideoView::VideoViewSignalType& signal = videoView.FinishedSignal();
+  DALI_TEST_EQUALS( 0, signal.GetConnectionCount(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewMethodsForRenderType(void)
+{
+  ToolkitTestApplication application;
+  VideoView videoView = VideoView::New();
+  DALI_TEST_CHECK( videoView );
+
+  Property::Map windowSurfaceTarget;
+  Property::Map nativeImageTarget;
+
+  windowSurfaceTarget.Insert( RENDERING_TYPE, "windowSurfaceTarget" );
+  nativeImageTarget.Insert( RENDERING_TYPE, "nativeImageTarget" );
+
+  Property::Map map;
+  Property::Value value;
+  videoView.SetProperty( VideoView::Property::VIDEO, windowSurfaceTarget );
+
+  value = videoView.GetProperty( VideoView::Property::VIDEO );
+  DALI_TEST_CHECK( value.Get( map ) );
+
+  Property::Value* type = map.Find( RENDERING_TYPE );
+  DALI_TEST_CHECK( type );
+  DALI_TEST_EQUALS( "windowSurfaceTarget", type->Get<std::string>(), TEST_LOCATION );
+
+  videoView.SetProperty( VideoView::Property::VIDEO, nativeImageTarget );
+
+  value = videoView.GetProperty( VideoView::Property::VIDEO );
+  DALI_TEST_CHECK( value.Get( map ) );
+  type = map.Find( RENDERING_TYPE );
+
+  DALI_TEST_CHECK( type );
+  DALI_TEST_EQUALS( "nativeImageTarget", type->Get<std::string>(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewCustomShaderForCoverage(void)
+{
+  ToolkitTestApplication application;
+  VideoView videoView = VideoView::New();
+  DALI_TEST_CHECK( videoView );
+
+  ToolkitApplication::DECODED_IMAGES_SUPPORTED = true;
+
+  videoView.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+  bool isUnderlay = videoView.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( !isUnderlay );
+
+  Stage::GetCurrent().Add( videoView );
+  videoView.SetProperty( VideoView::Property::VIDEO, "testvideo" );
+
+  Property::Map customShader;
+  customShader.Insert( "vertexShader", VERTEX_SHADER );
+  customShader.Insert( "fragmentShader", FRAGMENT_SHADER );
+
+  Property::Map map;
+  map.Insert( "shader", customShader );
+
+  videoView.SetProperty( VideoView::Property::VIDEO, map );
+
+  Property::Map map2;
+  Property::Value value = videoView.GetProperty( VideoView::Property::VIDEO );
+
+  DALI_TEST_CHECK( !value.Get( map2 ) );
+  END_TEST;
+}
+
+int UtcDaliVideoViewMethodsForCoverage2(void)
+{
+  ToolkitTestApplication application;
+  VideoView videoView = VideoView::New();
+  DALI_TEST_CHECK( videoView );
+
+  Property::Map windowSurfaceTarget;
+
+  windowSurfaceTarget.Insert( RENDERING_TYPE, "windowSurfaceTarget" );
+
+  Stage::GetCurrent().Add( videoView );
+
+  application.SendNotification();
+  application.Render();
+
+  Property::Map map;
+  Property::Value value;
+  videoView.SetProperty( VideoView::Property::VIDEO, windowSurfaceTarget );
+
+  value = videoView.GetProperty( VideoView::Property::VIDEO );
+  DALI_TEST_CHECK( value.Get( map ) );
+
+  Property::Value* type = map.Find( RENDERING_TYPE );
+  DALI_TEST_CHECK( type );
+  DALI_TEST_EQUALS( "windowSurfaceTarget", type->Get<std::string>(), TEST_LOCATION );
+
+  Vector3 vector(100.0f, 100.0f, 0.0f);
+
+  DALI_TEST_CHECK(vector != videoView.GetCurrentSize());
+  videoView.SetSize( vector );
+
+  application.SendNotification();
+  application.Render();
+
+  // Check the size in the new frame
+  DALI_TEST_CHECK(vector == videoView.GetCurrentSize());
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewPropertyUnderlay(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVideoViewPropertyUnderlay");
+  ToolkitApplication::DECODED_IMAGES_SUPPORTED = true;
+
+  VideoView view = VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+  view.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  bool isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( isUnderlay );
+
+  view.Play();
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+  isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( !isUnderlay );
+
+  view.Play();
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, true );
+  isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( isUnderlay );
+
+  // If platform api doesn't provide any API or feature for decoded images of video,
+  // UNDERLAY should be true
+  ToolkitApplication::DECODED_IMAGES_SUPPORTED = false;
+
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+  isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( isUnderlay );
+
+  // For coverage
+  ToolkitApplication::DECODED_IMAGES_SUPPORTED = true;
+
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, true );
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+  isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( !isUnderlay );
+
+  view.Stop();
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewPropertyPlayPosition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVideoViewPropertyPlayPosition");
+
+  VideoView view = VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+  view.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  int playPos = view.GetProperty( Toolkit::VideoView::Property::PLAY_POSITION ).Get< int >();
+  DALI_TEST_CHECK( playPos == 0 );
+
+  view.SetProperty( Toolkit::VideoView::Property::PLAY_POSITION, 10 );
+  playPos = view.GetProperty( Toolkit::VideoView::Property::PLAY_POSITION ).Get< int >();
+  // Actually setting play position will be async
+  // Actual platform result may be different.
+  DALI_TEST_CHECK( playPos == 10 );
+
+  END_TEST;
+}
+
+// For coverage.
+int UtcDaliVideoViewNew2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVideoViewNew2");
+
+  VideoView view = VideoView::New( true );
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+  view.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  VideoView view2 = VideoView::New( "", false );
+  DALI_TEST_CHECK( view2 );
+
+  Stage::GetCurrent().Add( view2 );
+  view2.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
+int UtcDaliVideoViewPropertyDisplayMode(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVideoViewPropertyDisplayMode");
+
+  VideoView view = VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  Stage::GetCurrent().Add( view );
+  view.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  view.SetProperty( Toolkit::VideoView::Property::DISPLAY_MODE, Toolkit::VideoView::DisplayMode::DST_ROI );
+  int displayMode = view.GetProperty( Toolkit::VideoView::Property::DISPLAY_MODE ).Get< int >();
+  DALI_TEST_CHECK( displayMode == Toolkit::VideoView::DisplayMode::DST_ROI );
+
+  END_TEST;
+}
+
+
+int UtcDaliVideoViewCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "VideoView with custom shader" );
+
+  VideoView view = VideoView::New();
+  DALI_TEST_CHECK( view );
+
+  ToolkitApplication::DECODED_IMAGES_SUPPORTED = true;
+
+  view.SetProperty( Toolkit::VideoView::Property::UNDERLAY, false );
+  bool isUnderlay = view.GetProperty( Toolkit::VideoView::Property::UNDERLAY ).Get< bool >();
+  DALI_TEST_CHECK( !isUnderlay );
+
+  Stage::GetCurrent().Add( view );
+  view.SetProperty( VideoView::Property::VIDEO, "testvideo" );
+
+  /* insert custom shader */
+  Property::Map customShader;
+  std::string fragmentShaderString;
+  fragmentShaderString.reserve( strlen( fragmentShaderPrefix ) + strlen( FRAGMENT_SHADER ) );
+  fragmentShaderString.append( fragmentShaderPrefix );
+  fragmentShaderString.append( FRAGMENT_SHADER );
+  customShader.Insert( "vertexShader", VERTEX_SHADER );
+  customShader.Insert( "fragmentShader", fragmentShaderString );
+
+  Property::Map map;
+  map.Insert( "shader", customShader );
+
+  view.SetProperty( VideoView::Property::VIDEO, map );
+
+  /* do render for check custom shader */
+  Stage::GetCurrent().Add( view );
+  view.Play();
+
+  application.SendNotification();
+  application.Render();
+
+  /* get renderer */
+  DALI_TEST_CHECK( view.GetRendererCount() == 1u );
+  Renderer renderer = view.GetRendererAt( 0 );
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK( shader );
+
+  Property::Value value = shader.GetProperty(Shader::Property::PROGRAM);
+  Property::Map* shaderMap = value.GetMap();
+  DALI_TEST_CHECK( shaderMap );
+
+  Property::Value* fragment = shaderMap->Find( "fragment" ); // fragment key name from shader-impl.cpp
+  DALI_TEST_EQUALS( fragmentShaderString, fragment->Get<std::string>(), TEST_LOCATION );
+
+  Property::Value* vertex = shaderMap->Find( "vertex" ); // vertex key name from shader-impl.cpp
+  DALI_TEST_EQUALS( VERTEX_SHADER, vertex->Get<std::string>(), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Visual.cpp
new file mode 100644 (file)
index 0000000..0a86423
--- /dev/null
@@ -0,0 +1,3728 @@
+/*
+ * Copyright (c) 2020 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 <unistd.h>
+
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+#include "dummy-control.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+const char* TEST_NPATCH_FILE_NAME =  TEST_RESOURCE_DIR "/button-up.9.png";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
+const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_RESOURCE_LOCATION = TEST_RESOURCE_DIR "/";
+
+
+const std::string DEFAULT_FONT_DIR( "/resources/fonts" );
+
+Property::Map DefaultTransform()
+{
+  Property::Map transformMap;
+  transformMap
+    .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2(0.0f, 0.0f) )
+    .Add( Toolkit::Visual::Transform::Property::SIZE, Vector2(1.0f, 1.0f) )
+    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN )
+    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) )
+    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+  return transformMap;
+}
+
+bool DaliTestCheckMaps( const Property::Map& fontStyleMapGet, const Property::Map& fontStyleMapSet )
+{
+  if( fontStyleMapGet.Count() == fontStyleMapSet.Count() )
+  {
+    for( unsigned int index = 0u; index < fontStyleMapGet.Count(); ++index )
+    {
+      const KeyValuePair& valueGet = fontStyleMapGet.GetKeyValue( index );
+
+      Property::Value* valueSet = NULL;
+      if ( valueGet.first.type == Property::Key::INDEX )
+      {
+        valueSet = fontStyleMapSet.Find( valueGet.first.indexKey );
+      }
+      else
+      {
+        // Get Key is a string so searching Set Map for a string key
+        valueSet = fontStyleMapSet.Find( valueGet.first.stringKey );
+      }
+
+      if( NULL != valueSet )
+      {
+        if( valueSet->GetType() == Dali::Property::STRING && ( valueGet.second.Get<std::string>() != valueSet->Get<std::string>() ) )
+        {
+          tet_printf( "Value got : [%s], expected : [%s]", valueGet.second.Get<std::string>().c_str(), valueSet->Get<std::string>().c_str() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::BOOLEAN && ( valueGet.second.Get<bool>() != valueSet->Get<bool>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<bool>(), valueSet->Get<bool>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::INTEGER && ( valueGet.second.Get<int>() != valueSet->Get<int>() ) )
+        {
+          tet_printf( "Value got : [%d], expected : [%d]", valueGet.second.Get<int>(), valueSet->Get<int>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::FLOAT && ( valueGet.second.Get<float>() != valueSet->Get<float>() ) )
+        {
+          tet_printf( "Value got : [%f], expected : [%f]", valueGet.second.Get<float>(), valueSet->Get<float>() );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR2 && ( valueGet.second.Get<Vector2>() != valueSet->Get<Vector2>() ) )
+        {
+          Vector2 vector2Get = valueGet.second.Get<Vector2>();
+          Vector2 vector2Set = valueSet->Get<Vector2>();
+          tet_printf( "Value got : [%f, %f], expected : [%f, %f]", vector2Get.x, vector2Get.y, vector2Set.x, vector2Set.y );
+          return false;
+        }
+        else if( valueSet->GetType() == Dali::Property::VECTOR4 && ( valueGet.second.Get<Vector4>() != valueSet->Get<Vector4>() ) )
+        {
+          Vector4 vector4Get = valueGet.second.Get<Vector4>();
+          Vector4 vector4Set = valueSet->Get<Vector4>();
+          tet_printf( "Value got : [%f, %f, %f, %f], expected : [%f, %f, %f, %f]", vector4Get.r, vector4Get.g, vector4Get.b, vector4Get.a, vector4Set.r, vector4Set.g, vector4Set.b, vector4Set.a );
+          return false;
+        }
+      }
+      else
+      {
+        if ( valueGet.first.type == Property::Key::INDEX )
+        {
+          tet_printf( "  The key %d doesn't exist.", valueGet.first.indexKey );
+        }
+        else
+        {
+          tet_printf( "  The key %s doesn't exist.", valueGet.first.stringKey.c_str() );
+        }
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+void PrepareResourceImage( ToolkitTestApplication& application, unsigned int imageWidth, unsigned int imageHeight, Pixel::Format pixelFormat )
+{
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetClosestImageSize(Vector2( imageWidth, imageHeight));
+
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
+  Integration::PixelBuffer* pixbuffer = bitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, imageWidth, imageHeight, imageWidth, imageHeight );
+  unsigned int bytesPerPixel = GetBytesPerPixel(  pixelFormat );
+  unsigned int initialColor = 0xFF;
+  memset( pixbuffer, initialColor, imageHeight*imageWidth*bytesPerPixel);
+
+  Integration::ResourcePointer resourcePtr(bitmap);
+  platform.SetSynchronouslyLoadedResource( resourcePtr );
+}
+} //namespace
+
+void dali_visual_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_visual_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+static void TestMixColor( Visual::Base visual, Property::Index mixColorIndex, const Vector4& testColor )
+{
+  Property::Map map;
+  visual.CreatePropertyMap(map);
+  Property::Value* value = map.Find( mixColorIndex );
+  DALI_TEST_CHECK( value );
+  Vector3 mixColor1;
+  DALI_TEST_CHECK( value->Get( mixColor1 ) );
+  DALI_TEST_EQUALS( mixColor1, Vector3(testColor), 0.001, TEST_LOCATION );
+
+  value = map.Find( Visual::Property::MIX_COLOR );
+  DALI_TEST_CHECK( value );
+  Vector4 mixColor2;
+  DALI_TEST_CHECK( value->Get( mixColor2 ) );
+  DALI_TEST_EQUALS( mixColor2, testColor, 0.001, TEST_LOCATION );
+
+  value = map.Find( Visual::Property::OPACITY );
+  DALI_TEST_CHECK( value );
+  float opacity;
+  DALI_TEST_CHECK( value->Get( opacity ) );
+  DALI_TEST_EQUALS( opacity, testColor.a, 0.001, TEST_LOCATION );
+}
+
+
+int UtcDaliVisualCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualCopyAndAssignment" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  Visual::Base visualCopy( visual );
+  DALI_TEST_CHECK(visual == visualCopy);
+
+  Visual::Base emptyVisual;
+  Visual::Base emptyVisualCopy( emptyVisual );
+  DALI_TEST_CHECK(emptyVisual == emptyVisualCopy);
+
+  Visual::Base visualEquals;
+  visualEquals = visual;
+  DALI_TEST_CHECK(visual == visualEquals);
+
+  Visual::Base emptyVisualEquals;
+  emptyVisualEquals = emptyVisual;
+  DALI_TEST_CHECK( emptyVisual == emptyVisualEquals );
+
+  //self assignment
+  visual = visual;
+  DALI_TEST_CHECK( visual = visualCopy );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetName01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetName" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  const char* visualName = "backgroundVisual";
+  visual.SetName( visualName );
+
+  DALI_TEST_EQUALS( visual.GetName(), visualName, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetGetDepthIndex(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetDepthIndex" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  visual.SetDepthIndex( 1 );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+
+  int depthIndex = dummyControl.GetRendererAt(0u).GetProperty<int>( Renderer::Property::DEPTH_INDEX );
+  DALI_TEST_EQUALS( depthIndex, 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( visual.GetDepthIndex(), 1, TEST_LOCATION );
+
+  visual.SetDepthIndex( -1 );
+  depthIndex = dummyControl.GetRendererAt(0u).GetProperty<int>( Renderer::Property::DEPTH_INDEX );
+  DALI_TEST_EQUALS( depthIndex, -1, TEST_LOCATION );
+  DALI_TEST_EQUALS( visual.GetDepthIndex(), -1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSize" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Vector2 controlSize( 20.f, 30.f );
+  Vector2 naturalSize;
+
+  // color colorVisual
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::COLOR;
+  map[ ColorVisual::Property::MIX_COLOR ] = Color::MAGENTA;
+
+  Visual::Base colorVisual = factory.CreateVisual( map );
+  colorVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+
+  colorVisual.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS( naturalSize, Vector2::ZERO, TEST_LOCATION );
+
+  // image visual
+  PrepareResourceImage( application, 100u, 200u, Pixel::RGBA8888 );
+  Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME, ImageDimensions(100, 200));
+  Visual::Base imageVisual = factory.CreateVisual( image );
+  imageVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+
+  imageVisual.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS( naturalSize, Vector2(100.f, 200.f), TEST_LOCATION );
+
+  // n patch visual is tested in the utc-Dali-VisualFactory.cpp
+
+  // border visual
+  float borderSize = 5.f;
+  map.Clear();
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::BORDER;
+  map[ BorderVisual::Property::COLOR  ] = Color::RED;
+  map[ BorderVisual::Property::SIZE   ] = borderSize;
+  Visual::Base borderVisual = factory.CreateVisual( map );
+  borderVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+  borderVisual.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS( naturalSize, Vector2::ZERO, TEST_LOCATION );
+
+  // gradient gradientVisual
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+  Vector2 start(-1.f, -1.f);
+  Vector2 end(1.f, 1.f);
+  propertyMap.Insert( "mixColor", Color::MAGENTA );
+  propertyMap.Insert( GradientVisual::Property::START_POSITION,   start) ;
+  propertyMap.Insert( GradientVisual::Property::END_POSITION,   end );
+  propertyMap.Insert( GradientVisual::Property::STOP_OFFSET,   Vector2(0.f, 1.f) );
+  propertyMap.Insert( GradientVisual::Property::SPREAD_METHOD, GradientVisual::SpreadMethod::REPEAT) ;
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
+  Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
+  gradientVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+  gradientVisual.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS( naturalSize, Vector2::ZERO,TEST_LOCATION );
+
+  // animated gradient visual
+  Vector2 animated_gradient_visual_size(10.f, 10.f);
+  propertyMap.Clear();
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_GRADIENT );
+  Visual::Base animatedGradientVisual = factory.CreateVisual( propertyMap );
+  animatedGradientVisual.GetNaturalSize(naturalSize);
+  animatedGradientVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+  DALI_TEST_EQUALS( naturalSize, Vector2::ZERO, TEST_LOCATION );
+
+  // svg visual
+  Visual::Base svgVisual = factory.CreateVisual( TEST_SVG_FILE_NAME, ImageDimensions() );
+  svgVisual.GetNaturalSize(naturalSize);
+  // TEST_SVG_FILE:
+  //  <svg width="100" height="100">
+  //  <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
+  //  </svg>
+  DALI_TEST_EQUALS( naturalSize, Vector2(100.f, 100.f), TEST_LOCATION );
+
+  // svg visual with a size
+  Visual::Base svgVisual2 = factory.CreateVisual( TEST_SVG_FILE_NAME, ImageDimensions(200, 200) );
+  svgVisual2.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS( naturalSize, Vector2(100.f, 100.f), TEST_LOCATION ); // Natural size should still be 100, 100
+
+  // Text visual.
+
+  // Load some fonts to get the same metrics on different platforms.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+  fontClient.SetDpi( 96u, 96u );
+
+  char* pathNamePtr = get_current_dir_name();
+  const std::string pathName( pathNamePtr );
+  free( pathNamePtr );
+
+  fontClient.GetFontId( pathName + DEFAULT_FONT_DIR + "/tizen/TizenSansRegular.ttf" );
+
+  // Create a TextVisual with a font size of 12 first
+  propertyMap.Clear();
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap.Insert( TextVisual::Property::ENABLE_MARKUP, true );
+  propertyMap.Insert( TextVisual::Property::TEXT, "<font family='TizenSans' size='12'>Hello world</font>" );
+  propertyMap.Insert( TextVisual::Property::MULTI_LINE, true );
+
+  Visual::Base smallTextVisual = factory.CreateVisual( propertyMap );
+  Vector2 smallTextVisualNaturalSize;
+  smallTextVisual.GetNaturalSize( smallTextVisualNaturalSize );
+
+  // Then create a TextVisual with a font size of 20
+  propertyMap[ TextVisual::Property::TEXT ] = "<font family='TizenSans' size='20'>Hello world</font>";
+  Visual::Base largeTextVisual = factory.CreateVisual( propertyMap );
+  Vector2 largeTextVisualNaturalSize;
+  largeTextVisual.GetNaturalSize( largeTextVisualNaturalSize );
+
+  // Compare the sizes of the two text visuals, the second one should be bigger as it has a larger point size in the markup.
+  DALI_TEST_CHECK( smallTextVisualNaturalSize.width < largeTextVisualNaturalSize.width &&
+                   smallTextVisualNaturalSize.height < largeTextVisualNaturalSize.height );
+
+  // The height returned for a particular width should also be greater for the large text visual
+  DALI_TEST_CHECK( smallTextVisual.GetHeightForWidth( 40.f ) < largeTextVisual.GetHeightForWidth( 40.f ) );
+
+  //AnimatedImageVisual
+  Visual::Base animatedImageVisual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  animatedImageVisual.SetTransformAndSize(DefaultTransform(), controlSize );
+  animatedImageVisual.GetNaturalSize(naturalSize);
+  // TEST_GIF_FILE: anim.gif
+  // resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+  DALI_TEST_EQUALS( naturalSize, Vector2(50.f, 50.f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetOnOffStage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetOnOffStage" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  Stage::GetCurrent().Remove( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetOnOffStage2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetOnOffStage2" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::SVG );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_SVG_FILE_NAME );
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize(200.f, 200.f);
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  // First on/off
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0 );
+  auto textures = renderer.GetTextures();
+  DALI_TEST_CHECK( textures.GetTextureCount() != 0u );
+
+  Stage::GetCurrent().Remove( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  // Second on/off
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  renderer = actor.GetRendererAt( 0 );
+  textures = renderer.GetTextures();
+  DALI_TEST_CHECK( textures.GetTextureCount() != 0u );
+
+  Stage::GetCurrent().Remove( actor );
+
+  application.SendNotification();
+  application.Render(0);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap1: ColorVisual (With base MixColor" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(Visual::Property::MIX_COLOR,  Color::BLUE);
+  propertyMap.Insert( DevelVisual::Property::CORNER_RADIUS, 10.0f );
+  propertyMap.Insert( DevelColorVisual::Property::BLUR_RADIUS, 20.0f );
+  Visual::Base colorVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  colorVisual.CreatePropertyMap( resultMap );
+
+  Property::Value* typeValue = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( typeValue );
+  DALI_TEST_CHECK( typeValue->Get<int>() == Visual::COLOR );
+
+  Property::Value* colorValue = resultMap.Find( ColorVisual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLUE );
+
+  Property::Value* cornerRadiusValue = resultMap.Find( DevelVisual::Property::CORNER_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( cornerRadiusValue );
+  DALI_TEST_CHECK( cornerRadiusValue->Get< float >() == 10.0f );
+
+  Property::Value* blurRadiusValue = resultMap.Find( DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( blurRadiusValue );
+  DALI_TEST_CHECK( blurRadiusValue->Get< float >() == 20.0f );
+
+  // change the blend color
+  propertyMap[ColorVisual::Property::MIX_COLOR] = Color::CYAN;
+  colorVisual = factory.CreateVisual( propertyMap  );
+  colorVisual.CreatePropertyMap( resultMap );
+
+  colorValue = resultMap.Find( ColorVisual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
+
+  // Test wrong values
+  propertyMap[DevelColorVisual::Property::BLUR_RADIUS] = "3.0f";
+
+  colorVisual = factory.CreateVisual( propertyMap  );
+  colorVisual.CreatePropertyMap( resultMap );
+
+  blurRadiusValue = resultMap.Find( DevelColorVisual::Property::BLUR_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( blurRadiusValue );
+  DALI_TEST_CHECK( blurRadiusValue->Get< float >() == 0.0f );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap2: BorderVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  propertyMap.Insert("mixColor", Vector4(1.0f, 0.0f, 1.0f, 0.5f) );
+  propertyMap.Insert("borderColor",  Color::BLUE);
+  propertyMap.Insert("borderSize",  5.f);
+  propertyMap.Insert("antiAliasing",  true);
+  Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  borderVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* typeValue = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( typeValue );
+  DALI_TEST_CHECK( typeValue->Get<int>() == Visual::BORDER );
+
+  Property::Value* colorValue = resultMap.Find( BorderVisual::Property::COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::BLUE );
+
+  Property::Value* sizeValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  DALI_TEST_CHECK( sizeValue );
+  DALI_TEST_CHECK( sizeValue->Get<float>() == 5.f );
+
+  Property::Value* AAValue = resultMap.Find( BorderVisual::Property::ANTI_ALIASING, Property::BOOLEAN );
+  DALI_TEST_CHECK( AAValue );
+  DALI_TEST_CHECK( AAValue->Get<bool>() == true );
+
+  Property::Map propertyMap1;
+  propertyMap1[ Toolkit::Visual::Property::TYPE ] = Visual::BORDER;
+  propertyMap1[ BorderVisual::Property::COLOR  ] = Color::CYAN;
+  propertyMap1[ BorderVisual::Property::SIZE   ] = 10.0f;
+  borderVisual = factory.CreateVisual( propertyMap1 );
+  borderVisual.CreatePropertyMap( resultMap );
+
+  typeValue = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( typeValue );
+  DALI_TEST_CHECK( typeValue->Get<int>() == Visual::BORDER );
+
+  colorValue = resultMap.Find( BorderVisual::Property::COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
+
+  colorValue = resultMap.Find( BorderVisual::Property::SIZE,  Property::FLOAT );
+  DALI_TEST_CHECK( colorValue );
+  DALI_TEST_CHECK( colorValue->Get<float>() == 10.f );
+
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap2N(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap2N: BorderVisual with no setup properties" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+  tet_infoline( "Test that the visual is created, with a default renderer" );
+  DALI_TEST_CHECK( borderVisual );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, borderVisual );
+  Stage::GetCurrent().Add( dummyControl );
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualGetPropertyMap3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap3: linear GradientVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+
+  Vector2 start(-1.f, -1.f);
+  Vector2 end(1.f, 1.f);
+  propertyMap.Insert( "startPosition", start);
+  propertyMap.Insert( "endPosition", end);
+  propertyMap.Insert( "spreadMethod", GradientVisual::SpreadMethod::REPEAT);
+
+  propertyMap.Insert(GradientVisual::Property::STOP_OFFSET,   Vector2(0.2f, 0.8f));
+
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
+
+  Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
+
+  Property::Map resultMap;
+  gradientVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::GRADIENT );
+
+  value = resultMap.Find( GradientVisual::Property::UNITS,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == GradientVisual::Units::OBJECT_BOUNDING_BOX );
+
+  value = resultMap.Find( GradientVisual::Property::SPREAD_METHOD,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == GradientVisual::SpreadMethod::REPEAT );
+
+  value = resultMap.Find( GradientVisual::Property::START_POSITION,   Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), start , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::END_POSITION,   Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), end , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
+  DALI_TEST_CHECK( value );
+  Property::Array* offsetArray = value->GetArray();
+  DALI_TEST_CHECK( offsetArray->Count() == 2 );
+  DALI_TEST_EQUALS( offsetArray->GetElementAt(0).Get<float>(), 0.2f , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( offsetArray->GetElementAt(1).Get<float>(), 0.8f , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::STOP_COLOR,   Property::ARRAY );
+  DALI_TEST_CHECK( value );
+  Property::Array* colorArray = value->GetArray();
+  DALI_TEST_CHECK( colorArray->Count() == 2 );
+  DALI_TEST_EQUALS( colorArray->GetElementAt(0).Get<Vector4>(), Color::RED , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( colorArray->GetElementAt(1).Get<Vector4>(), Color::GREEN , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap4: radial GradientVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+
+  Vector2 center(100.f, 100.f);
+  float radius = 100.f;
+  propertyMap.Insert(GradientVisual::Property::UNITS,  GradientVisual::Units::USER_SPACE);
+  propertyMap.Insert(GradientVisual::Property::CENTER,  center);
+  propertyMap.Insert(GradientVisual::Property::RADIUS,  radius);
+  propertyMap.Insert(GradientVisual::Property::STOP_OFFSET,   Vector3(0.1f, 0.3f, 1.1f));
+
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::BLACK );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
+
+  Visual::Base gradientVisual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( gradientVisual );
+
+  Property::Map resultMap;
+  gradientVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::GRADIENT );
+
+  value = resultMap.Find( GradientVisual::Property::UNITS,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == GradientVisual::Units::USER_SPACE );
+
+  value = resultMap.Find( GradientVisual::Property::SPREAD_METHOD,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == GradientVisual::SpreadMethod::PAD );
+
+  value = resultMap.Find( GradientVisual::Property::CENTER,  Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), center , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::RADIUS,  Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), radius , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::STOP_OFFSET,   Property::ARRAY );
+  DALI_TEST_CHECK( value );
+  Property::Array* offsetArray = value->GetArray();
+  DALI_TEST_CHECK( offsetArray->Count() == 3 );
+  DALI_TEST_EQUALS( offsetArray->GetElementAt(0).Get<float>(), 0.1f , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( offsetArray->GetElementAt(1).Get<float>(), 0.3f , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  // any stop value will be clamped to [0.0, 1.0];
+  DALI_TEST_EQUALS( offsetArray->GetElementAt(2).Get<float>(), 1.0f , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( GradientVisual::Property::STOP_COLOR,   Property::ARRAY );
+  DALI_TEST_CHECK( value );
+  Property::Array* colorArray = value->GetArray();
+  DALI_TEST_CHECK( colorArray->Count() == 3 );
+  DALI_TEST_EQUALS( colorArray->GetElementAt(0).Get<Vector4>(), Color::RED , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( colorArray->GetElementAt(1).Get<Vector4>(), Color::BLACK , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( colorArray->GetElementAt(2).Get<Vector4>(), Color::GREEN , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap5(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap5: ImageVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::IMAGE );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::MAGENTA );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_WIDTH,   20 );
+  propertyMap.Insert( ImageVisual::Property::DESIRED_HEIGHT,   30 );
+  propertyMap.Insert( "fittingMode",   FittingMode::FIT_HEIGHT );
+  propertyMap.Insert( "samplingMode",   SamplingMode::BOX_THEN_NEAREST );
+  propertyMap.Insert( "pixelArea", Vector4( 0.25f, 0.25f, 0.5f, 0.5f ) );
+  propertyMap.Insert( "wrapModeU", WrapMode::REPEAT );
+  propertyMap.Insert( "wrapModeV", WrapMode::MIRRORED_REPEAT );
+  propertyMap.Insert( "synchronousLoading",   true );
+
+  Visual::Base imageVisual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( imageVisual );
+
+  Property::Map resultMap;
+  imageVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_IMAGE_FILE_NAME );
+
+  value = resultMap.Find( Visual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<Vector4>() == Color::MAGENTA );
+
+  value = resultMap.Find( ImageVisual::Property::FITTING_MODE,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == FittingMode::FIT_HEIGHT );
+
+  value = resultMap.Find( ImageVisual::Property::SAMPLING_MODE,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == SamplingMode::BOX_THEN_NEAREST );
+
+  value = resultMap.Find( ImageVisual::Property::DESIRED_WIDTH,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 20 );
+
+  value = resultMap.Find( ImageVisual::Property::DESIRED_HEIGHT,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 30 );
+
+  value = resultMap.Find( ImageVisual::Property::PIXEL_AREA, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4( 0.25f, 0.25f, 0.5f, 0.5f ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_U, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::REPEAT);
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_V, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::MIRRORED_REPEAT);
+
+  value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == true );
+
+  // Get an image visual with an image handle, and test the default property values
+  PrepareResourceImage( application, 100u, 200u, Pixel::RGBA8888 );
+  Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME, ImageDimensions(100, 200));
+  imageVisual = factory.CreateVisual(image);
+  imageVisual.CreatePropertyMap( resultMap );
+
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::IMAGE );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_IMAGE_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::FITTING_MODE,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == FittingMode::SHRINK_TO_FIT );
+
+  value = resultMap.Find( ImageVisual::Property::SAMPLING_MODE,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == SamplingMode::BOX );
+
+  value = resultMap.Find( ImageVisual::Property::DESIRED_WIDTH,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 100 );
+
+  value = resultMap.Find( ImageVisual::Property::DESIRED_HEIGHT,   Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == 200 );
+
+  value = resultMap.Find( ImageVisual::Property::PIXEL_AREA, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Vector4( 0.f, 0.f, 1.f, 1.f ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_U, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::DEFAULT);
+
+  value = resultMap.Find( ImageVisual::Property::WRAP_MODE_V, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK(  value->Get<int>() == WrapMode::DEFAULT);
+
+  value = resultMap.Find( "synchronousLoading",   Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == false );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap6(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap6: NPatchVisual" );
+
+  Rect< int > border( 1, 1, 1, 1 );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( "mixColor",  Color::MAGENTA );
+  propertyMap.Insert( ImageVisual::Property::URL,  TEST_NPATCH_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  propertyMap.Insert( ImageVisual::Property::BORDER, border );
+  propertyMap.Insert( DevelImageVisual::Property::AUXILIARY_IMAGE, "application-icon-30.png" );
+  propertyMap.Insert( DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, 0.9f );
+  Visual::Base nPatchVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  nPatchVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::N_PATCH );
+
+  value = resultMap.Find( Visual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<Vector4>() == Color::MAGENTA );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_NPATCH_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::BORDER_ONLY,  Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() );
+
+  value = resultMap.Find( ImageVisual::Property::BORDER,  Property::RECTANGLE );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< Rect< int > >() == border );
+
+  value = resultMap.Find( DevelImageVisual::Property::AUXILIARY_IMAGE, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == "application-icon-30.png" );
+
+  value = resultMap.Find( DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<float>() == 0.9f );
+
+  Vector4 border1( 1.0f, 1.0f, 1.0f, 1.0f );
+
+  Property::Map propertyMap1;
+  propertyMap1.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap1.Insert( "mixColor",  Color::MAGENTA );
+  propertyMap1.Insert( ImageVisual::Property::URL,  TEST_NPATCH_FILE_NAME );
+  propertyMap1.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  propertyMap1.Insert( ImageVisual::Property::BORDER, border1 );
+  nPatchVisual = factory.CreateVisual( propertyMap1 );
+
+  nPatchVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::N_PATCH );
+
+  value = resultMap.Find( Visual::Property::MIX_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<Vector4>() == Color::MAGENTA );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_NPATCH_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::BORDER_ONLY,  Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() );
+
+  value = resultMap.Find( ImageVisual::Property::BORDER,  Property::RECTANGLE );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get< Rect< int > >() == border );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap7(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap7: SvgVisual" );
+
+  // request SvgVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::SVG );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::WHITE );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_SVG_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ATLASING, false );
+  Visual::Base svgVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  svgVisual.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::SVG );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_SVG_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::ATLASING, Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == false );
+
+  // request SvgVisual with a property map 2
+  propertyMap.Clear();
+  propertyMap[ "visualType" ] = Visual::SVG;
+  propertyMap[ "mixColor" ] = Color::WHITE;
+  propertyMap[ "url" ] = TEST_SVG_FILE_NAME;
+  propertyMap[ "atlasing" ] = true;
+  Visual::Base svgVisual1 = factory.CreateVisual( propertyMap );
+
+  resultMap.Clear();
+  svgVisual1.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::SVG );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_SVG_FILE_NAME );
+
+  value = resultMap.Find( ImageVisual::Property::ATLASING, Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() == true );
+
+  // request SvgVisual with an URL
+  Visual::Base svgVisual2 = factory.CreateVisual( TEST_SVG_FILE_NAME, ImageDimensions() );
+  resultMap.Clear();
+  svgVisual2.CreatePropertyMap( resultMap );
+  // check the property values from the returned map from a visual
+  value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::SVG );
+
+  value = resultMap.Find( ImageVisual::Property::URL,  Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<std::string>() == TEST_SVG_FILE_NAME );
+
+  END_TEST;
+}
+
+//Mesh visual
+int UtcDaliVisualGetPropertyMap8(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap8: MeshVisual" );
+
+  //Request MeshVisual using a property map.
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::BLUE );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_LOCATION );
+  propertyMap.Insert( MeshVisual::Property::SHADING_MODE, MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, Vector3( 5.0f, 10.0f, 15.0f) );
+  Visual::Base meshVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  meshVisual.CreatePropertyMap( resultMap );
+  TestMixColor( meshVisual, Visual::Property::MIX_COLOR, Color::BLUE );
+
+  //Check values in the result map are identical to the initial map's values.
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)Visual::MESH, TEST_LOCATION );
+
+  value = resultMap.Find( MeshVisual::Property::OBJECT_URL, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), TEST_OBJ_FILE_NAME, TEST_LOCATION );
+
+  value = resultMap.Find( MeshVisual::Property::MATERIAL_URL, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), TEST_MTL_FILE_NAME, TEST_LOCATION );
+
+  value = resultMap.Find( MeshVisual::Property::TEXTURES_PATH, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), TEST_RESOURCE_LOCATION, TEST_LOCATION );
+
+  value = resultMap.Find( MeshVisual::Property::SHADING_MODE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING, TEST_LOCATION );
+
+  value = resultMap.Find( MeshVisual::Property::LIGHT_POSITION, Property::VECTOR3 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector3>(), Vector3( 5.0f, 10.0f, 15.0f), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ END_TEST;
+}
+
+//Primitive shape visual
+int UtcDaliVisualGetPropertyMap9(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap9: PrimitiveVisual" );
+
+  Vector4 color = Vector4( 1.0, 0.8, 0.6, 1.0);
+  Vector3 dimensions = Vector3( 1.0, 2.0, 3.0 );
+
+  //Request PrimitiveVisual using a property map.
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CUBE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, color );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::STACKS, 20 );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_TOP_RADIUS, 30.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, 40.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_HEIGHT, 50.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_RADIUS, 60.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_DIMENSIONS, dimensions );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_PERCENTAGE, 0.3f );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_SMOOTHNESS, 0.6f );
+  propertyMap.Insert( PrimitiveVisual::Property::LIGHT_POSITION, Vector3( 5.0f, 10.0f, 15.0f) );
+  Visual::Base primitiveVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  primitiveVisual.CreatePropertyMap( resultMap );
+
+  //Check values in the result map are identical to the initial map's values.
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)Visual::PRIMITIVE, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SHAPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)PrimitiveVisual::Shape::CUBE, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::MIX_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<Vector4>() == color );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), color, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SLICES, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 10, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::STACKS, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), 20, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SCALE_TOP_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 30.0f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 40.0f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SCALE_HEIGHT, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 50.0f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SCALE_RADIUS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 60.0f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::SCALE_DIMENSIONS, Property::VECTOR3 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector3>(), dimensions, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::BEVEL_PERCENTAGE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.3f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::BEVEL_SMOOTHNESS, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 0.6f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( PrimitiveVisual::Property::LIGHT_POSITION, Property::VECTOR3 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector3>(), Vector3( 5.0f, 10.0f, 15.0f), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  END_TEST;
+}
+
+//Text shape visual
+int UtcDaliVisualGetPropertyMap10(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap10: TextVisual" );
+
+  //Request PrimitiveVisual using a property map.
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::BLACK );
+  propertyMap.Insert( "renderingBackend", static_cast<int>( Toolkit::Text::DEFAULT_RENDERING_BACKEND ) );
+  propertyMap.Insert( "enableMarkup", false );
+  propertyMap.Insert( "text", "Hello world" );
+  propertyMap.Insert( "fontFamily", "TizenSans" );
+
+  Property::Map fontStyleMapSet;
+  fontStyleMapSet.Insert( "weight", "bold" );
+  propertyMap.Insert( "fontStyle", fontStyleMapSet );
+
+  propertyMap.Insert( "pointSize", 12.f );
+  propertyMap.Insert( "multiLine", true );
+  propertyMap.Insert( "horizontalAlignment", "CENTER" );
+  propertyMap.Insert( "verticalAlignment", "CENTER" );
+  propertyMap.Insert( "textColor", Color::RED );
+
+  Property::Map shadowMapSet;
+  propertyMap.Insert( "shadow", shadowMapSet.Add("color", Color::RED).Add("offset", Vector2(2.0f, 2.0f)).Add("blurRadius", 3.0f) );
+
+  Property::Map underlineMapSet;
+  propertyMap.Insert( "underline", underlineMapSet.Add("enable", true).Add("color", Color::GREEN).Add("height", 1) );
+
+  Property::Map outlineMapSet;
+  propertyMap.Insert( "outline", outlineMapSet.Add("color", Color::YELLOW).Add("width", 1) );
+
+  Property::Map backgroundMapSet;
+  propertyMap.Insert( "textBackground", backgroundMapSet.Add("enable", true).Add("color", Color::CYAN) );
+
+  Visual::Base textVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map resultMap;
+  textVisual.CreatePropertyMap( resultMap );
+
+  //Check values in the result map are identical to the initial map's values.
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)Visual::TEXT, TEST_LOCATION );
+
+  value = resultMap.Find( Visual::Property::MIX_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::BLACK, 0.001f, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::TEXT, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), "Hello world", TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::FONT_FAMILY, Property::STRING );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<std::string>(), "TizenSans", TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::FONT_STYLE, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  Property::Map fontStyleMapGet = value->Get<Property::Map>();
+  DALI_TEST_EQUALS( fontStyleMapGet.Count(), fontStyleMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( fontStyleMapGet, fontStyleMapSet ), true, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::POINT_SIZE, Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), 12.f, Math::MACHINE_EPSILON_1000, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::MULTI_LINE, Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<bool>() );
+
+  value = resultMap.Find( TextVisual::Property::HORIZONTAL_ALIGNMENT, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)Text::HorizontalAlignment::CENTER, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::VERTICAL_ALIGNMENT, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<int>(), (int)Text::VerticalAlignment::CENTER, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::TEXT_COLOR, Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), Color::RED, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::ENABLE_MARKUP, Property::BOOLEAN );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( !value->Get<bool>() );
+
+  value = resultMap.Find( TextVisual::Property::SHADOW, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  Property::Map shadowMapGet = value->Get<Property::Map>();
+  DALI_TEST_EQUALS( shadowMapGet.Count(), shadowMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( shadowMapGet, shadowMapSet ), true, TEST_LOCATION );
+
+  value = resultMap.Find( TextVisual::Property::UNDERLINE, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  Property::Map underlineMapGet = value->Get<Property::Map>();
+  DALI_TEST_EQUALS( underlineMapGet.Count(), underlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( underlineMapGet, underlineMapSet ), true, TEST_LOCATION );
+
+  value = resultMap.Find( DevelTextVisual::Property::OUTLINE, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  Property::Map outlineMapGet = value->Get<Property::Map>();
+  DALI_TEST_EQUALS( outlineMapGet.Count(), outlineMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( outlineMapGet, outlineMapSet ), true, TEST_LOCATION );
+
+  value = resultMap.Find( DevelTextVisual::Property::BACKGROUND, Property::MAP );
+  DALI_TEST_CHECK( value );
+
+  Property::Map backgroundMapGet = value->Get<Property::Map>();
+  DALI_TEST_EQUALS( backgroundMapGet.Count(), backgroundMapSet.Count(), TEST_LOCATION );
+  DALI_TEST_EQUALS( DaliTestCheckMaps( backgroundMapGet, backgroundMapSet ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap11(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap11: AnimatedGradientVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+
+  Vector2 start(-0.5f, 0.5f);
+  Vector2 end  (0.5f, -0.0f);
+  Vector4 start_color(1.0f, 0.7f, 0.5f, 1.0f);
+  Vector4 end_color  (0.7f, 0.5f, 1.0f, 1.0f);
+  Vector2 rotate_center(0.0f, 0.4f);
+  float rotate_amount = 1.57f;
+  float offset = 100.f;
+
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  DevelAnimatedGradientVisual::GradientType::RADIAL);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::UNIT_TYPE,  DevelAnimatedGradientVisual::UnitType::USER_SPACE);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  DevelAnimatedGradientVisual::SpreadType::CLAMP);
+
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_POSITION,  start);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_POSITION,  end);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_COLOR,  start_color);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_COLOR,  end_color);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  rotate_center);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  rotate_amount);
+  propertyMap.Insert(DevelAnimatedGradientVisual::Property::OFFSET,  offset);
+
+  Visual::Base animatedGradientVisual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( animatedGradientVisual );
+
+  Property::Map resultMap;
+  animatedGradientVisual.CreatePropertyMap( resultMap );
+
+  // check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == DevelVisual::ANIMATED_GRADIENT );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::GradientType::RADIAL );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::UNIT_TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::UnitType::USER_SPACE );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::SpreadType::CLAMP );
+
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::START_POSITION,  Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), start , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::END_POSITION,  Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), end , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::START_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), start_color , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::END_COLOR,  Property::VECTOR4 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector4>(), end_color , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  Property::VECTOR2 );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<Vector2>(), rotate_center , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), rotate_amount , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  value = resultMap.Find( DevelAnimatedGradientVisual::Property::OFFSET,  Property::FLOAT );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_EQUALS( value->Get<float>(), offset , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetPropertyMap12(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap12: AnimatedGradientVisual with animation param" );
+
+  // Case 1 : Set values by index
+  {
+    tet_printf( " - Set Values by Index\n" );
+    // NOTE : PropertyMap doesn't optimized even delay < -loop_count * (duration + repeat_delay) so this animation will not run
+    // _delay = -10.0f is this case. It will progress (10.0f / 1.5f) amount. and 10.0f / 1.5f > 5.
+    for(float _delay = -10.0f; _delay <= 5.0f; _delay += 5.0f)
+    {
+      tet_printf( "test with delay [%f]\n", _delay );
+      VisualFactory factory = VisualFactory::Get();
+      DALI_TEST_CHECK( factory );
+
+      Property::Map propertyMap;
+      Property::Map animationMap;
+      propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+
+      float duration = 1.1f;
+      float delay = _delay;
+      float repeat_delay = 0.4f;
+
+      int direction = DevelAnimatedGradientVisual::AnimationParameter::DirectionType::BACKWARD;
+      int loop_count = 5;
+      int motion = DevelAnimatedGradientVisual::AnimationParameter::MotionType::MIRROR;
+      int easing = DevelAnimatedGradientVisual::AnimationParameter::EasingType::OUT;
+
+      auto buildAnimatedMap = [&animationMap, &direction, &duration, &delay, &loop_count, &repeat_delay, &motion, &easing](const Property::Value &start, const Property::Value &target)->Property::Map&
+      {
+        animationMap.Clear();
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::START, start);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET, target);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, direction);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION, duration);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY, delay);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT, loop_count);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY, repeat_delay);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE, motion);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, easing);
+
+        return animationMap;
+      };
+
+      Vector2 start1(-0.5f, 0.5f);
+      Vector2 end1  (0.5f, -0.5f);
+      Vector4 start_color1(1.0f, 0.7f, 0.5f, 1.0f);
+      Vector4 end_color1  (0.7f, 0.5f, 1.0f, 1.0f);
+      Vector2 rotate_center1(0.0f, 0.4f);
+      float rotate_amount1 = 0.0f;
+      float offset1 = 0.f;
+
+      Vector2 start2(-0.5f, -0.5f);
+      Vector2 end2  (0.5f, 0.5f);
+      Vector4 start_color2(0.0f, 0.1f, 0.8f, 1.0f);
+      Vector4 end_color2  (0.3f, 1.0f, 0.1f, 0.0f);
+      Vector2 rotate_center2(0.0f, -0.4f);
+      float rotate_amount2 = 6.2832f;
+      float offset2 = 2.f;
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  DevelAnimatedGradientVisual::GradientType::LINEAR);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::UNIT_TYPE,  DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  DevelAnimatedGradientVisual::SpreadType::REPEAT);
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_POSITION, buildAnimatedMap(start1        , start2        ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_POSITION,   buildAnimatedMap(end1          , end2          ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_COLOR,    buildAnimatedMap(start_color1  , start_color2  ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_COLOR,      buildAnimatedMap(end_color1    , end_color2    ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  buildAnimatedMap(rotate_center1, rotate_center2));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  buildAnimatedMap(rotate_amount1, rotate_amount2));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::OFFSET,         buildAnimatedMap(offset1       , offset2       ));
+
+      Visual::Base animatedGradientVisual = factory.CreateVisual(propertyMap);
+      DALI_TEST_CHECK( animatedGradientVisual );
+
+      Property::Map resultMap;
+      animatedGradientVisual.CreatePropertyMap( resultMap );
+
+      // check the property values from the returned map from visual
+      Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelVisual::ANIMATED_GRADIENT );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::GradientType::LINEAR );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::UNIT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::SpreadType::REPEAT );
+
+      auto checkAnimatedMap = [&value, &resultMap, &direction, &duration, &delay, &loop_count, &repeat_delay, &motion, &easing](const Property::Index &index, const Property::Value &start, const Property::Value &target, int line_num)->void
+      {
+        tet_printf("Check value at %d\n", line_num);
+        value = resultMap.Find( index, Property::MAP );
+        DALI_TEST_CHECK( value );
+        DALI_TEST_CHECK( value->GetType() == Property::MAP );
+        Property::Map *temp_map = value->GetMap();
+        DALI_TEST_CHECK( temp_map );
+
+        auto checkMapValue = [&temp_map](const Property::Index index)->Property::Value
+        {
+          Property::Value *res = temp_map->Find( index );
+          DALI_TEST_CHECK( res );
+          return *res;
+        };
+
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::START)       , start, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET)      , target, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION)   , Property::Value( direction ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION)    , Property::Value( duration ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY)       , Property::Value( delay ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT)      , Property::Value( loop_count ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY), Property::Value( repeat_delay ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE) , Property::Value( motion ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE) , Property::Value( easing ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+      };
+
+      // check the animation map data is good
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::START_POSITION, start1        , start2        , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::END_POSITION  , end1          , end2          , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::START_COLOR   , start_color1  , start_color2  , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::END_COLOR     , end_color1    , end_color2    , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::ROTATE_CENTER , rotate_center1, rotate_center2, __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT , rotate_amount1, rotate_amount2, __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::OFFSET        , offset1       , offset2       , __LINE__);
+    }
+  }
+
+  // Case 2 : Set values by string
+  {
+    tet_printf( " - Set Values by String\n" );
+    // NOTE : PropertyMap doesn't optimized even delay < -loop_count * (duration + repeat_delay) so this animation will not run
+    // _delay = -10.0f is this case. It will progress (10.0f / 1.5f) amount. and 10.0f / 1.5f > 5.
+    for(float _delay = -10.0f; _delay <= 5.0f; _delay += 5.0f)
+    {
+      tet_printf( "test with delay [%f]\n", _delay );
+      VisualFactory factory = VisualFactory::Get();
+      DALI_TEST_CHECK( factory );
+
+      Property::Map propertyMap;
+      Property::Map animationMap;
+      propertyMap.Insert("visualType", "ANIMATED_GRADIENT");
+
+      float duration = 1.1f;
+      float delay = _delay;
+      float repeat_delay = 0.4f;
+
+      int direction = DevelAnimatedGradientVisual::AnimationParameter::DirectionType::BACKWARD;
+      int loop_count = 5;
+      int motion = DevelAnimatedGradientVisual::AnimationParameter::MotionType::MIRROR;
+      int easing = DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN_OUT;
+
+      auto buildAnimatedMap = [&animationMap, &duration, &delay, &loop_count, &repeat_delay](const Property::Value &start, const Property::Value &target)->Property::Map&
+      {
+        animationMap.Clear();
+        animationMap.Insert("startValue"   , start);
+        animationMap.Insert("targetValue"  , target);
+        animationMap.Insert("directionType", "BACKWARD");
+        animationMap.Insert("duration"     , duration);
+        animationMap.Insert("delay"        , delay);
+        animationMap.Insert("repeat"       , loop_count);
+        animationMap.Insert("repeatDelay"  , repeat_delay);
+        animationMap.Insert("motionType"   , "MIRROR");
+        animationMap.Insert("easingType"   , "IN_OUT");
+
+        return animationMap;
+      };
+
+      Vector2 start1(-0.5f, 0.5f);
+      Vector2 end1  (0.5f, -0.5f);
+      Vector4 start_color1(1.0f, 0.7f, 0.5f, 1.0f);
+      Vector4 end_color1  (0.7f, 0.5f, 1.0f, 1.0f);
+      Vector2 rotate_center1(0.0f, 0.4f);
+      float rotate_amount1 = 0.0f;
+      float offset1 = 0.f;
+
+      Vector2 start2(-0.5f, -0.5f);
+      Vector2 end2  (0.5f, 0.5f);
+      Vector4 start_color2(0.0f, 0.1f, 0.8f, 1.0f);
+      Vector4 end_color2  (0.3f, 1.0f, 0.1f, 0.0f);
+      Vector2 rotate_center2(0.0f, -0.4f);
+      float rotate_amount2 = 6.2832f;
+      float offset2 = 2.f;
+
+      // For test mix the type string/index key and string/index value works well.
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  "RADIAL");
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::UNIT_TYPE,  DevelAnimatedGradientVisual::UnitType::USER_SPACE);
+      propertyMap.Insert("spreadType"  , DevelAnimatedGradientVisual::SpreadType::REFLECT);
+
+      propertyMap.Insert("startPosition", buildAnimatedMap(start1        , start2        ));
+      propertyMap.Insert("endPosition"  , buildAnimatedMap(end1          , end2          ));
+      propertyMap.Insert("startColor"   , buildAnimatedMap(start_color1  , start_color2  ));
+      propertyMap.Insert("endColor"     , buildAnimatedMap(end_color1    , end_color2    ));
+      propertyMap.Insert("rotateCenter" , buildAnimatedMap(rotate_center1, rotate_center2));
+      propertyMap.Insert("rotateAmount" , buildAnimatedMap(rotate_amount1, rotate_amount2));
+      propertyMap.Insert("offset"       , buildAnimatedMap(offset1       , offset2       ));
+
+      Visual::Base animatedGradientVisual = factory.CreateVisual(propertyMap);
+      DALI_TEST_CHECK( animatedGradientVisual );
+
+      Property::Map resultMap;
+      animatedGradientVisual.CreatePropertyMap( resultMap );
+
+      // check the property values from the returned map from visual
+      // Note : resultMap from CreatePropertyMap only contain indexKey
+      Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelVisual::ANIMATED_GRADIENT );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::GradientType::RADIAL );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::UNIT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::UnitType::USER_SPACE );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::SpreadType::REFLECT );
+
+      auto checkAnimatedMap = [&value, &resultMap, &direction, &duration, &delay, &loop_count, &repeat_delay, &motion, &easing](const Property::Index &index, const Property::Value &start, const Property::Value &target, int line_num)->void
+      {
+        tet_printf("Check value at %d\n", line_num);
+        value = resultMap.Find( index, Property::MAP );
+        DALI_TEST_CHECK( value );
+        DALI_TEST_CHECK( value->GetType() == Property::MAP );
+        Property::Map *temp_map = value->GetMap();
+        DALI_TEST_CHECK( temp_map );
+
+        auto checkMapValue = [&temp_map](const Property::Index index)->Property::Value
+        {
+          Property::Value *res = temp_map->Find( index );
+          DALI_TEST_CHECK( res );
+          return *res;
+        };
+
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::START)       , start, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET)      , target, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION)   , Property::Value( direction ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION)    , Property::Value( duration ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY)       , Property::Value( delay ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT)      , Property::Value( loop_count ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY), Property::Value( repeat_delay ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE) , Property::Value( motion ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        DALI_TEST_EQUALS( checkMapValue(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE) , Property::Value( easing ), Math::MACHINE_EPSILON_100, TEST_LOCATION );
+      };
+
+      // check the animation map data is good
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::START_POSITION, start1        , start2        , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::END_POSITION  , end1          , end2          , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::START_COLOR   , start_color1  , start_color2  , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::END_COLOR     , end_color1    , end_color2    , __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::ROTATE_CENTER , rotate_center1, rotate_center2, __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT , rotate_amount1, rotate_amount2, __LINE__);
+      checkAnimatedMap(DevelAnimatedGradientVisual::Property::OFFSET        , offset1       , offset2       , __LINE__);
+    }
+  }
+
+  END_TEST;
+}
+int UtcDaliVisualGetPropertyMap13(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetPropertyMap13: AnimatedGradientVisual when repeat = 0" );
+
+  for(int _direction = 0; _direction <= 1; ++_direction)
+  {
+    for(float _delay = -10.0f; _delay <= 10.0f; _delay += 10.0f)
+    {
+      tet_printf( ((_direction == 0) ? "Forward test with delay [%f]\n" : "Backward test with delay [%f]\n") , _delay );
+      VisualFactory factory = VisualFactory::Get();
+      DALI_TEST_CHECK( factory );
+
+      Property::Map propertyMap;
+      Property::Map animationMap;
+      propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+
+      float duration = 1.0f;
+      float delay = _delay;
+      float repeat_delay = 0.5f;
+
+      int direction = _direction;
+      int loop_count = 0; // When loop_count is 0, Animation will not be created.
+      int motion = DevelAnimatedGradientVisual::AnimationParameter::MotionType::LOOP;
+      int easing = DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN;
+
+      auto buildAnimatedMap = [&animationMap, &direction, &duration, &delay, &loop_count, &repeat_delay, &motion, &easing](const Property::Value &start, const Property::Value &target)->Property::Map&
+      {
+        animationMap.Clear();
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::START, start);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET, target);
+        if(direction == 0)animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, DevelAnimatedGradientVisual::AnimationParameter::DirectionType::FORWARD);
+        else animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, DevelAnimatedGradientVisual::AnimationParameter::DirectionType::BACKWARD);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, direction);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION, duration);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY, delay);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT, loop_count);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY, repeat_delay);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE, motion);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, easing);
+
+        return animationMap;
+      };
+
+      Vector2 start1(-0.5f, 0.5f);
+      Vector2 end1  (0.5f, -0.5f);
+      Vector4 start_color1(1.0f, 0.7f, 0.5f, 1.0f);
+      Vector4 end_color1  (0.7f, 0.5f, 1.0f, 1.0f);
+      Vector2 rotate_center1(1.0f, 0.4f);
+      float rotate_amount1 = 2.0f;
+      float offset1 = 1.f;
+
+      Vector2 start2(-0.5f, -0.5f);
+      Vector2 end2  (0.5f, 0.5f);
+      Vector4 start_color2(0.0f, 0.1f, 0.8f, 1.0f);
+      Vector4 end_color2  (0.3f, 1.0f, 0.1f, 0.0f);
+      Vector2 rotate_center2(1.0f, -0.4f);
+      float rotate_amount2 = 1.0f;
+      float offset2 = 3.f;
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  DevelAnimatedGradientVisual::GradientType::LINEAR);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::UNIT_TYPE,  DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  DevelAnimatedGradientVisual::SpreadType::REFLECT);
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_POSITION, buildAnimatedMap(start1        , start2        ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_POSITION,   buildAnimatedMap(end1          , end2          ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_COLOR,    buildAnimatedMap(start_color1  , start_color2  ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_COLOR,      buildAnimatedMap(end_color1    , end_color2    ));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  buildAnimatedMap(rotate_center1, rotate_center2));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  buildAnimatedMap(rotate_amount1, rotate_amount2));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::OFFSET,         buildAnimatedMap(offset1       , offset2       ));
+
+      Visual::Base animatedGradientVisual = factory.CreateVisual(propertyMap);
+      DALI_TEST_CHECK( animatedGradientVisual );
+
+      Property::Map resultMap;
+      animatedGradientVisual.CreatePropertyMap( resultMap );
+
+      // check the property values from the returned map from visual
+      Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelVisual::ANIMATED_GRADIENT );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::GRADIENT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::GradientType::LINEAR );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::UNIT_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::SPREAD_TYPE,  Property::INTEGER );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_CHECK( value->Get<int>() == DevelAnimatedGradientVisual::SpreadType::REFLECT );
+
+      // If loop_count = 0, Animation doesn't created.
+      // Optimized resultMap only have one value, which is target value
+      // Note: target value will be changed by direction option.
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::START_POSITION,  Property::VECTOR2 );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<Vector2>(), direction ? start1 : start2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::END_POSITION,  Property::VECTOR2 );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<Vector2>(), direction ? end1 : end2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::START_COLOR,  Property::VECTOR4 );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<Vector4>(), direction ? start_color1 : start_color2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::END_COLOR,  Property::VECTOR4 );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<Vector4>(), direction ? end_color1 : end_color2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  Property::VECTOR2 );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<Vector2>(), direction ? rotate_center1 : rotate_center2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  Property::FLOAT );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<float>(), direction ? rotate_amount1 : rotate_amount2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+      value = resultMap.Find( DevelAnimatedGradientVisual::Property::OFFSET,  Property::FLOAT );
+      DALI_TEST_CHECK( value );
+      DALI_TEST_EQUALS( value->Get<float>(), direction ? offset1 : offset2 , Math::MACHINE_EPSILON_100, TEST_LOCATION );
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimateBorderVisual01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimateBorderVisual Color" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  propertyMap.Insert(Visual::Property::MIX_COLOR, Vector4(1, 1, 1, 0.8f));
+  propertyMap.Insert(BorderVisual::Property::COLOR,  Color::BLUE);
+  propertyMap.Insert(BorderVisual::Property::SIZE,  5.f);
+  Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+  Property::Map map;
+  map["target"] = "testVisual";
+  map["property"] = "mixColor";
+  map["targetValue"] = Vector4(1,1,1,0.1);
+  map["animator"] = Property::Map()
+    .Add("alphaFunction", "LINEAR")
+    .Add("timePeriod", Property::Map()
+         .Add("delay", 0.0f)
+         .Add("duration", 4.0f));
+
+  Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, borderVisual );
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index borderColorIndex = DevelHandle::GetPropertyIndex( renderer, BorderVisual::Property::COLOR );
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, Visual::Property::MIX_COLOR );
+
+  Animation animation = dummyImpl.CreateTransition( transition );
+
+  // Animate the mix color through the transition, and the border color through
+  // programmatic method.
+  animation.AnimateTo( Property(renderer, borderColorIndex), Color::WHITE );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(2000u); // halfway point between blue and white
+
+  Vector4 color = renderer.GetCurrentProperty< Vector4 >( borderColorIndex );
+  Vector4 testColor = (Color::BLUE + Color::WHITE)*0.5f;
+  DALI_TEST_EQUALS( color, testColor, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("borderColor", testColor ), true, TEST_LOCATION );
+
+  color = renderer.GetCurrentProperty< Vector3 >( mixColorIndex );
+  testColor = Vector4( 1,1,1,0.45f );
+  DALI_TEST_EQUALS( Vector3(color), Vector3(testColor), 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(testColor) ), true, TEST_LOCATION );
+
+  Vector4 uColor;
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", uColor ) );
+  DALI_TEST_EQUALS( uColor.a, testColor.a, TEST_LOCATION );
+
+  application.Render(2000u);
+
+  color = renderer.GetCurrentProperty< Vector4 >( borderColorIndex );
+  DALI_TEST_EQUALS( color, Color::WHITE, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("borderColor", Color::WHITE ), true, TEST_LOCATION );
+
+  color = renderer.GetCurrentProperty< Vector3 >( mixColorIndex );
+  testColor = Vector4(1,1,1,0.1);
+  DALI_TEST_EQUALS( Vector3(color), Vector3(testColor), TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(testColor) ), true, TEST_LOCATION );
+
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue< Vector4 >( "uColor", uColor ) );
+  DALI_TEST_EQUALS( uColor.a, testColor.a, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualAnimateBorderVisual02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimateBorderVisual Size" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  propertyMap.Insert(BorderVisual::Property::COLOR,  Color::BLUE);
+  propertyMap.Insert(BorderVisual::Property::SIZE,  5.f);
+  Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, borderVisual );
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index index = DevelHandle::GetPropertyIndex( renderer, BorderVisual::Property::SIZE );
+
+  Animation animation = Animation::New(4.0f);
+  animation.AnimateTo( Property(renderer, index), 9.0f );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(2000u); // halfway point
+
+  float size = renderer.GetCurrentProperty< float >( index );
+  DALI_TEST_EQUALS( size, 7.0f, 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("borderSize", 7.0f ), true, TEST_LOCATION );
+
+  application.Render(2000u); // halfway point between blue and white
+
+  size = renderer.GetCurrentProperty< float >( index );
+  DALI_TEST_EQUALS( size, 9.0f, 0.0001f, TEST_LOCATION );
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>("borderSize", 9.0f ), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimateColorVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimateColorVisual mixColor" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR, Color::BLUE);
+  Visual::Base borderVisual = factory.CreateVisual( propertyMap );
+
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, borderVisual );
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(actor);
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+  Renderer renderer = actor.GetRendererAt(0);
+  Property::Index mixColorIndex = DevelHandle::GetPropertyIndex( renderer, ColorVisual::Property::MIX_COLOR );
+
+  Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  Animation animation = Animation::New(4.0f);
+  animation.AnimateTo( Property(renderer, mixColorIndex), Vector3(Color::WHITE) );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(0);
+  application.Render(2000u); // halfway point
+
+  Vector3 color = renderer.GetCurrentProperty< Vector3 >( mixColorIndex );
+  Vector3 testColor = Vector3(Color::BLUE + Color::WHITE)*0.5f;
+  DALI_TEST_EQUALS( color, testColor, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", testColor ), true, TEST_LOCATION );
+
+  application.Render(2000u); // halfway point between blue and white
+
+  color = renderer.GetCurrentProperty< Vector3 >( mixColorIndex );
+  DALI_TEST_EQUALS( color, Vector3(Color::WHITE), TEST_LOCATION );
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(Color::WHITE) ), true, TEST_LOCATION );
+
+  blendModeValue = renderer.GetCurrentProperty( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimatePrimitiveVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatePrimitiveVisual color" );
+
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE,  Visual::PRIMITIVE);
+    propertyMap.Insert(PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CUBE);
+    propertyMap.Insert(PrimitiveVisual::Property::MIX_COLOR, Color::BLUE);
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+    actor.SetSize(2000, 2000);
+    actor.SetParentOrigin(ParentOrigin::CENTER);
+    actor.SetColor(Color::BLACK);
+    Stage::GetCurrent().Add(actor);
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    Renderer renderer = actor.GetRendererAt(0);
+    Property::Index index = DevelHandle::GetPropertyIndex( renderer, PrimitiveVisual::Property::MIX_COLOR );
+
+    tet_infoline("Test that the renderer has the Primitive mix color");
+    DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+
+    const Vector4 INITIAL_MIX_COLOR( 1.0f,0.0f,1.0f,0.5f ); // Magenta with half alpha
+    const Vector4 TARGET_MIX_COLOR( Color::RED );
+
+    Property::Map map;
+    map["target"] = "testVisual";
+    map["property"] = "mixColor";
+    map["initialValue"] = INITIAL_MIX_COLOR;
+    map["targetValue"] = TARGET_MIX_COLOR;
+    map["animator"] = Property::Map()
+      .Add("alphaFunction", "LINEAR")
+      .Add("timePeriod", Property::Map()
+           .Add("delay", 0.0f)
+           .Add("duration", 4.0f));
+
+    Dali::Toolkit::TransitionData transition = TransitionData::New( map );
+
+    Animation animation = dummyImpl.CreateTransition( transition );
+    Property::Value blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::ON, TEST_LOCATION );
+
+    animation.AnimateTo( Property(actor, Actor::Property::COLOR), Color::WHITE );
+    animation.Play();
+
+    application.SendNotification();
+    application.Render(0);
+    application.Render(2000u); // halfway point
+    application.SendNotification();
+
+    Vector4 halfwayColor = (INITIAL_MIX_COLOR + TARGET_MIX_COLOR)*0.5;
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Vector4(0.5f, 0.5f, 0.5f, halfwayColor.a )), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(halfwayColor) ), true, TEST_LOCATION );
+
+    application.Render(2001u); // go past end
+    application.SendNotification(); // Trigger signals
+
+    DALI_TEST_EQUALS( actor.GetCurrentColor(), Color::WHITE, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>("uColor", Vector4( 1.0f, 1.0f, 1.0f, TARGET_MIX_COLOR.a ) ), true, TEST_LOCATION );
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector3>("mixColor", Vector3(TARGET_MIX_COLOR) ), true, TEST_LOCATION );
+
+    blendModeValue = renderer.GetProperty( Renderer::Property::BLEND_MODE );
+    DALI_TEST_EQUALS( blendModeValue.Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+    actor.Unparent();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimatedGradientVisual01(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedGradientVisual with default" );
+
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map propertyMap;
+    propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+
+    DummyControl actor = DummyControl::New(true);
+    Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+    actor.SetSize(2000, 2000);
+    actor.SetParentOrigin(ParentOrigin::CENTER);
+    actor.SetColor(Color::BLACK);
+    Stage::GetCurrent().Add(actor);
+
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+    for(int step_iter = 0; step_iter < 3; step_iter++)
+    {
+      application.SendNotification();
+      application.Render(0);
+      application.Render(750u); // step i/4
+      application.SendNotification();
+
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector2>( "start_point"  , Vector2( -0.5f, 0.0f ) ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector2>( "end_point"    , Vector2( 0.5f, 0.0f ) ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>( "start_color"  , Vector4( 143.0f, 170.0f, 220.0f, 255.0f ) / 255.0f ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector4>( "end_color"    , Vector4( 255.0f, 163.0f, 163.0f, 255.0f ) / 255.0f ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<Vector2>( "rotate_center", Vector2( 0.0f, 0.0f ) ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>( "rotate_angle"   , 0.0f ), true, TEST_LOCATION );
+      DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue<float>( "gradient_offset", 0.5f * step_iter + 0.5f ), true, TEST_LOCATION );
+    }
+
+    //Not check here. cause gradient_offset value can be 2.0f or 0.0f
+    application.Render(750u); // go to end
+    application.SendNotification();
+
+    application.Render(10u); // finish
+    application.SendNotification();
+
+    actor.Unparent();
+    application.SendNotification();
+    application.Render(0u);
+    application.SendNotification();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimatedGradientVisual02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedGradientVisual with full-option" );
+
+  {
+    float _delay[4] = {0.0f, -1.35f, 0.15f, -0.4f}; // fract(_delay) must NOT be 1/4, 2/4, 3/4. cause we don't know progress is 1.0f or 0.0f
+    int _direction[2] = {0, 1};
+    int _loop_count[3] = {-1, 0, 1};
+    int _motion[2] = {0, 1};
+    int _easing[4] = {0, 1, 2, 3};
+
+    int test_case_max = 4 * 2 * 3 * 2 * 4;
+    int test_case = 0;
+    int test_case_d = 7; // 7 is the number of animated properties.
+
+    float _duration = 0.4f;
+    float _repeat_delay = _duration * 0.25f; // < _duration. cause real_duration = _duration - _repeat_delay;
+    float noise_maker = 0.0f;
+    // total testing time = ceil((4*2*3*2*4) / 7) * (_duration(=0.4) * 2 + 0.01) = 22.68 seconds
+    for( test_case = 0; test_case < test_case_max + test_case_d; test_case += test_case_d )
+    {
+      tet_printf( "test [%d ~ %d / %d]\n" , test_case, test_case + test_case_d - 1, test_case_max);
+
+      VisualFactory factory = VisualFactory::Get();
+      Property::Map propertyMap;
+      Property::Map animationMap;
+      propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+
+      int gradient_type = DevelAnimatedGradientVisual::GradientType::LINEAR;
+      int unit_type = DevelAnimatedGradientVisual::UnitType::USER_SPACE;
+      int spread_type = DevelAnimatedGradientVisual::SpreadType::REPEAT;
+
+      auto buildAnimatedMap = [&animationMap, &_direction, &_duration, &_delay, &_loop_count, &_repeat_delay, &_motion, &_easing, &test_case](const Property::Value &start, const Property::Value &target, int tc_offset)->Property::Map&
+      {
+        int tc = (test_case + tc_offset);
+        int idx_easing = tc % 4; tc /= 4;
+        int idx_motion = tc % 2; tc /= 2;
+        int idx_loop_count = tc % 3; tc /= 3;
+        int idx_direction = tc % 2; tc /= 2;
+        int idx_delay = tc % 4; tc /= 4;
+
+        float duration = _duration - _repeat_delay;
+        float repeat_delay = _repeat_delay;
+        float delay = _delay[idx_delay] * _duration;
+        int direction = _direction[idx_direction];
+        int loop_count = _loop_count[idx_loop_count];
+        int motion = _motion[idx_motion];
+        int easing = _easing[idx_easing];
+
+        animationMap.Clear();
+        animationMap.Insert( DevelAnimatedGradientVisual::AnimationParameter::Property::START, start );
+        animationMap.Insert( DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET, target );
+        if( direction == 0 )
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, DevelAnimatedGradientVisual::AnimationParameter::DirectionType::FORWARD);
+        }
+        else
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, DevelAnimatedGradientVisual::AnimationParameter::DirectionType::BACKWARD);
+        }
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION, duration);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY, delay);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT, loop_count);
+        animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY, repeat_delay);
+        if( motion == 0 )
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE, DevelAnimatedGradientVisual::AnimationParameter::MotionType::LOOP);
+        }
+        else
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE, DevelAnimatedGradientVisual::AnimationParameter::MotionType::MIRROR);
+        }
+        if( easing == 0 )
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, DevelAnimatedGradientVisual::AnimationParameter::EasingType::LINEAR);
+        }
+        else if( easing == 1 )
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN);
+        }
+        else if( easing == 2 )
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, DevelAnimatedGradientVisual::AnimationParameter::EasingType::OUT);
+        }
+        else
+        {
+          animationMap.Insert(DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN_OUT);
+        }
+
+        return animationMap;
+      };
+
+      // Give different values for debuging
+      noise_maker += 1.0f;
+      Vector2 start1(-0.5f + noise_maker * 0.1f, 0.5f + noise_maker * 0.1f);
+      Vector2 end1  (0.5f + noise_maker * 0.1f, -0.5f + noise_maker * 0.1f);
+      Vector4 start_color1(1.0f, 0.7f, 0.5f, 1.0f);
+      Vector4 end_color1  (0.7f, 0.5f, 1.0f, 1.0f);
+      Vector2 rotate_center1(0.0f + noise_maker * 0.1f, 0.4f + noise_maker * 0.1f);
+      float rotate_amount1 = 0.0f + noise_maker * 0.1f;
+      float offset1 = 0.f + noise_maker * 0.1f;
+
+      Vector2 start2(0.2f + noise_maker * 0.1f, -0.7f + noise_maker * 0.1f);
+      Vector2 end2  (0.5f + noise_maker * 0.1f, 0.5f + noise_maker * 0.1f);
+      Vector4 start_color2(0.0f, 0.1f, 0.8f, 1.0f);
+      Vector4 end_color2  (0.3f, 1.0f, 0.1f, 0.0f);
+      Vector2 rotate_center2(0.0f + noise_maker * 0.1f, -0.4f + noise_maker * 0.1f);
+      float rotate_amount2 = 7.0f + noise_maker * 0.1f;
+      float offset2 = 2.f + noise_maker * 0.1f;
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::GRADIENT_TYPE, gradient_type);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::UNIT_TYPE,     unit_type);
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::SPREAD_TYPE,   spread_type);
+
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_POSITION, buildAnimatedMap(start1        , start2        ,0));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_POSITION,   buildAnimatedMap(end1          , end2          ,1));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::START_COLOR,    buildAnimatedMap(start_color1  , start_color2  ,2));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::END_COLOR,      buildAnimatedMap(end_color1    , end_color2    ,3));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_CENTER,  buildAnimatedMap(rotate_center1, rotate_center2,4));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT,  buildAnimatedMap(rotate_amount1, rotate_amount2,5));
+      propertyMap.Insert(DevelAnimatedGradientVisual::Property::OFFSET,         buildAnimatedMap(offset1       , offset2       ,6));
+
+      Visual::Base visual = factory.CreateVisual( propertyMap );
+
+      DummyControl actor = DummyControl::New( true );
+      Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>( actor.GetImplementation() );
+      dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+      actor.SetSize( 2000, 2000 );
+      actor.SetParentOrigin(ParentOrigin::CENTER);
+      actor.SetColor(Color::BLACK);
+      Stage::GetCurrent().Add(actor);
+
+      application.SendNotification();
+      application.Render( 0 );
+      application.SendNotification();
+
+      DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+      application.SendNotification();
+
+      //Compare between CPU calculated value and Shader Visual calculated value
+      auto testProperty = [&application, &_direction, &_duration, &_delay, &_loop_count, &_repeat_delay, &_motion, &_easing, &test_case](const char* name, const Property::Value& start, const Property::Value& target, int tc_offset, int value_type, float progress)->void
+      {
+        int tc = (test_case + tc_offset);
+        int idx_easing = tc % 4; tc /= 4;
+        int idx_motion = tc % 2; tc /= 2;
+        int idx_loop_count = tc % 3; tc /= 3;
+        int idx_direction = tc % 2; tc /= 2;
+        int idx_delay = tc % 4; tc /= 4;
+
+        float duration = _duration - _repeat_delay;
+        float repeat_delay = _repeat_delay;
+        float delay = _delay[idx_delay] * _duration;
+        int direction = _direction[idx_direction];
+        int loop_count = _loop_count[idx_loop_count];
+        int motion = _motion[idx_motion];
+        int easing = _easing[idx_easing];
+
+        progress -= delay / _duration;
+
+        Property::Value s = start;
+        Property::Value t = target;
+        if( direction == 1 )
+        {
+          s = target;
+          t = start;
+        }
+        float x; ///< Animator progress value
+        if( loop_count == 0 )
+        {
+          x = 1.0f;
+        }
+        else if( loop_count > 0 && progress + 0.01f > loop_count )
+        {
+          x = ( motion == 0 ) ? 1.0f : 0.0f;
+        }
+        else
+        {
+          if( progress < 0.0f )
+          {
+            progress = 0.0f;
+          }
+          progress = fmodf( progress, 1.0f );
+          progress = Dali::Clamp( (progress * (duration + repeat_delay) - repeat_delay) / duration, 0.0f, 1.0f );
+
+          x = progress;
+          if( motion == 1 )
+          {
+            x = progress * 2.0f;
+            if( x > 1.0f )
+            {
+              x = 2.0f - x;
+            }
+          }
+
+          if( easing == 1 ) // EASE_IN
+          {
+            x = x*x;
+          }
+          else if( easing == 2 ) // EASE_OUT
+          {
+            x = 2.0f*x - x*x;
+          }
+          else if( easing == 3 ) // EASE_IN_OUT
+          {
+            x = x * x * (3.0f - 2.0f * x);
+          }
+        }
+        if( value_type == 0 ) // result type is Float
+        {
+          float res;
+          float cur;
+          res = s.Get<float>() * (1.0f - x) + t.Get<float>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<float>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else if( value_type == 1 ) // result type is Vector2
+        {
+          Vector2 res;
+          Vector2 cur;
+          res = s.Get<Vector2>() * (1.0f - x) + t.Get<Vector2>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector2>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else if( value_type == 2 ) // result type is Vector3
+        {
+          Vector3 res;
+          Vector3 cur;
+          res = s.Get<Vector3>() * (1.0f - x) + t.Get<Vector3>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector3>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else // result type is Vector4
+        {
+          Vector4 res;
+          Vector4 cur;
+          res = s.Get<Vector4>() * (1.0f - x) + t.Get<Vector4>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector4>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+      };
+
+      float step = 0.0f;
+      for( int iter = 0; iter < 2; iter++ ) // test 2*duration seconds
+      {
+        for( int step_iter = 0; step_iter < 3; step_iter++ )
+        {
+          application.SendNotification();
+          application.Render( _duration * 250.f );  // step i/4
+          application.SendNotification();
+          step += 0.25f;
+
+          testProperty( "start_point"    , Property::Value( start1 )        , Property::Value( start2 )        , 0, 1, step );
+          testProperty( "end_point"      , Property::Value( end1 )          , Property::Value( end2 )          , 1, 1, step );
+          testProperty( "start_color"    , Property::Value( start_color1 )  , Property::Value( start_color2 )  , 2, 3, step );
+          testProperty( "end_color"      , Property::Value( end_color1 )    , Property::Value( end_color2 )    , 3, 3, step );
+          testProperty( "rotate_center"  , Property::Value( rotate_center1 ), Property::Value( rotate_center2 ), 4, 1, step );
+          testProperty( "rotate_angle"   , Property::Value( rotate_amount1 ), Property::Value( rotate_amount2 ), 5, 0, step );
+          testProperty( "gradient_offset", Property::Value( offset1 )       , Property::Value( offset2 )       , 6, 0, step );
+        }
+        application.SendNotification();
+        application.Render(_duration * 250.f);  // step 4/4 will not test
+        application.SendNotification();
+        step += 0.25f;
+      }
+
+      application.SendNotification();
+      actor.Unparent();
+      application.SendNotification();
+      application.Render(10.f);  // tempral time
+      application.SendNotification();
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualAnimatedGradientVisual03(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliAnimatedGradientVisual with full-option use string key" );
+
+  {
+    float _delay[4] = {0.0f, -1.35f, 0.15f, -0.4f}; // fract(_delay) must NOT be 1/4, 2/4, 3/4. cause we don't know progress is 1.0f or 0.0f
+    int _direction[2] = {0, 1};
+    int _loop_count[3] = {-1, 0, 1};
+    int _motion[2] = {0, 1};
+    int _easing[4] = {0, 1, 2, 3};
+
+    int test_case_max = 4 * 2 * 3 * 2 * 4;
+    int test_case = 0;
+    int test_case_d = 7; // 7 is the number of animated properties.
+
+    float _duration = 0.4f;
+    float _repeat_delay = _duration * 0.25f; // < _duration. cause real_duration = _duration - _repeat_delay;
+    float noise_maker = 0.2f;
+    // total testing time = ceil((4*2*3*2*4) / 7) * (_duration(=0.4) * 2 + 0.01) = 22.68 seconds
+    for( test_case = 0; test_case < test_case_max + test_case_d; test_case += test_case_d )
+    {
+      tet_printf( "test [%d ~ %d / %d]\n" , test_case, test_case + test_case_d - 1, test_case_max);
+
+      VisualFactory factory = VisualFactory::Get();
+      Property::Map propertyMap;
+      Property::Map animationMap;
+      propertyMap.Insert(Visual::Property::TYPE,  DevelVisual::ANIMATED_GRADIENT);
+
+      auto buildAnimatedMap = [&animationMap, &_direction, &_duration, &_delay, &_loop_count, &_repeat_delay, &_motion, &_easing, &test_case](const Property::Value &start, const Property::Value &target, int tc_offset)->Property::Map&
+      {
+        int tc = (test_case + tc_offset);
+        int idx_easing = tc % 4; tc /= 4;
+        int idx_motion = tc % 2; tc /= 2;
+        int idx_loop_count = tc % 3; tc /= 3;
+        int idx_direction = tc % 2; tc /= 2;
+        int idx_delay = tc % 4; tc /= 4;
+
+        float duration = _duration - _repeat_delay;
+        float repeat_delay = _repeat_delay;
+        float delay = _delay[idx_delay] * _duration;
+        int direction = _direction[idx_direction];
+        int loop_count = _loop_count[idx_loop_count];
+        int motion = _motion[idx_motion];
+        int easing = _easing[idx_easing];
+
+        animationMap.Clear();
+        animationMap.Insert( "startValue", start );
+        animationMap.Insert( "targetValue", target );
+        if( direction == 0 )
+        {
+          animationMap.Insert("directionType", "FORWARD");
+        }
+        else
+        {
+          animationMap.Insert("directionType", "BACKWARD");
+        }
+        animationMap.Insert("duration", duration);
+        animationMap.Insert("delay", delay);
+        animationMap.Insert("repeat", loop_count);
+        animationMap.Insert("repeatDelay", repeat_delay);
+        if( motion == 0 )
+        {
+          animationMap.Insert("motionType", "LOOP");
+        }
+        else
+        {
+          animationMap.Insert("motionType", "MIRROR");
+        }
+        if( easing == 0 )
+        {
+          animationMap.Insert("easingType", "LINEAR");
+        }
+        else if( easing == 1 )
+        {
+          animationMap.Insert("easingType", "IN");
+        }
+        else if( easing == 2 )
+        {
+          animationMap.Insert("easingType", "OUT");
+        }
+        else
+        {
+          animationMap.Insert("easingType", "IN_OUT");
+        }
+
+        return animationMap;
+      };
+
+      // Give different values for debuging
+      noise_maker += 0.8f;
+      Vector2 start1(-0.5f + noise_maker * 0.1f, 0.5f + noise_maker * 0.1f);
+      Vector2 end1  (0.5f + noise_maker * 0.1f, -0.5f + noise_maker * 0.1f);
+      Vector4 start_color1(1.0f, 0.7f, 0.5f, 1.0f);
+      Vector4 end_color1  (0.7f, 0.5f, 1.0f, 1.0f);
+      Vector2 rotate_center1(0.0f + noise_maker * 0.1f, 0.4f + noise_maker * 0.1f);
+      float rotate_amount1 = 0.0f + noise_maker * 0.1f;
+      float offset1 = 0.f + noise_maker * 0.1f;
+
+      Vector2 start2(0.2f + noise_maker * 0.1f, -0.7f + noise_maker * 0.1f);
+      Vector2 end2  (0.5f + noise_maker * 0.1f, 0.5f + noise_maker * 0.1f);
+      Vector4 start_color2(0.0f, 0.1f, 0.8f, 1.0f);
+      Vector4 end_color2  (0.3f, 1.0f, 0.1f, 0.0f);
+      Vector2 rotate_center2(0.0f + noise_maker * 0.1f, -0.4f + noise_maker * 0.1f);
+      float rotate_amount2 = 7.0f + noise_maker * 0.1f;
+      float offset2 = 2.f + noise_maker * 0.1f;
+
+      propertyMap.Insert("gradientType", "LINEAR");
+      propertyMap.Insert("unitType",     "USER_SPACE");
+      propertyMap.Insert("spreadType",   "CLAMP");
+
+      propertyMap.Insert("startPosition", buildAnimatedMap(start1        , start2        ,0));
+      propertyMap.Insert("endPosition",   buildAnimatedMap(end1          , end2          ,1));
+      propertyMap.Insert("startColor",    buildAnimatedMap(start_color1  , start_color2  ,2));
+      propertyMap.Insert("endColor",      buildAnimatedMap(end_color1    , end_color2    ,3));
+      propertyMap.Insert("rotateCenter",  buildAnimatedMap(rotate_center1, rotate_center2,4));
+      propertyMap.Insert("rotateAmount",  buildAnimatedMap(rotate_amount1, rotate_amount2,5));
+      propertyMap.Insert("offset",        buildAnimatedMap(offset1       , offset2       ,6));
+
+      Visual::Base visual = factory.CreateVisual( propertyMap );
+
+      DummyControl actor = DummyControl::New( true );
+      Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>( actor.GetImplementation() );
+      dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+      actor.SetSize( 2000, 2000 );
+      actor.SetParentOrigin(ParentOrigin::CENTER);
+      actor.SetColor(Color::BLACK);
+      Stage::GetCurrent().Add(actor);
+
+      application.SendNotification();
+      application.Render( 0 );
+      application.SendNotification();
+
+      DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION);
+
+      application.SendNotification();
+
+      //Compare between CPU calculated value and Shader Visual calculated value
+      auto testProperty = [&application, &_direction, &_duration, &_delay, &_loop_count, &_repeat_delay, &_motion, &_easing, &test_case](const char* name, const Property::Value& start, const Property::Value& target, int tc_offset, int value_type, float progress)->void
+      {
+        int tc = (test_case + tc_offset);
+        int idx_easing = tc % 4; tc /= 4;
+        int idx_motion = tc % 2; tc /= 2;
+        int idx_loop_count = tc % 3; tc /= 3;
+        int idx_direction = tc % 2; tc /= 2;
+        int idx_delay = tc % 4; tc /= 4;
+
+        float duration = _duration - _repeat_delay;
+        float repeat_delay = _repeat_delay;
+        float delay = _delay[idx_delay] * _duration;
+        int direction = _direction[idx_direction];
+        int loop_count = _loop_count[idx_loop_count];
+        int motion = _motion[idx_motion];
+        int easing = _easing[idx_easing];
+
+        progress -= delay / _duration;
+
+        Property::Value s = start;
+        Property::Value t = target;
+        if( direction == 1 )
+        {
+          s = target;
+          t = start;
+        }
+        float x; ///< Animator progress value
+        if( loop_count == 0 )
+        {
+          x = 1.0f;
+        }
+        else if( loop_count > 0 && progress + 0.01f > loop_count )
+        {
+          x = ( motion == 0 ) ? 1.0f : 0.0f;
+        }
+        else
+        {
+          if( progress < 0.0f )
+          {
+            progress = 0.0f;
+          }
+          progress = fmodf( progress, 1.0f );
+          progress = Dali::Clamp( (progress * (duration + repeat_delay) - repeat_delay) / duration, 0.0f, 1.0f );
+
+          x = progress;
+          if( motion == 1 )
+          {
+            x = progress * 2.0f;
+            if( x > 1.0f )
+            {
+              x = 2.0f - x;
+            }
+          }
+
+          if( easing == 1 ) // EASE_IN
+          {
+            x = x*x;
+          }
+          else if( easing == 2 ) // EASE_OUT
+          {
+            x = 2.0f*x - x*x;
+          }
+          else if( easing == 3 ) // EASE_IN_OUT
+          {
+            x = x * x * (3.0f - 2.0f * x);
+          }
+        }
+        if( value_type == 0 ) // result type is Float
+        {
+          float res;
+          float cur;
+          res = s.Get<float>() * (1.0f - x) + t.Get<float>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<float>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else if( value_type == 1 ) // result type is Vector2
+        {
+          Vector2 res;
+          Vector2 cur;
+          res = s.Get<Vector2>() * (1.0f - x) + t.Get<Vector2>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector2>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else if( value_type == 2 ) // result type is Vector3
+        {
+          Vector3 res;
+          Vector3 cur;
+          res = s.Get<Vector3>() * (1.0f - x) + t.Get<Vector3>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector3>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+        else // result type is Vector4
+        {
+          Vector4 res;
+          Vector4 cur;
+          res = s.Get<Vector4>() * (1.0f - x) + t.Get<Vector4>() * (x);
+          DALI_TEST_EQUALS( application.GetGlAbstraction().GetUniformValue<Vector4>(name, cur), true, TEST_LOCATION );
+          DALI_TEST_EQUALS( res, cur, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+        }
+      };
+
+      float step = 0.0f;
+      for( int iter = 0; iter < 2; iter++ ) // test 2*duration seconds
+      {
+        for( int step_iter = 0; step_iter < 3; step_iter++ )
+        {
+          application.SendNotification();
+          application.Render( _duration * 250.f );  // step i/4
+          application.SendNotification();
+          step += 0.25f;
+
+          testProperty( "start_point"    , Property::Value( start1 )        , Property::Value( start2 )        , 0, 1, step );
+          testProperty( "end_point"      , Property::Value( end1 )          , Property::Value( end2 )          , 1, 1, step );
+          testProperty( "start_color"    , Property::Value( start_color1 )  , Property::Value( start_color2 )  , 2, 3, step );
+          testProperty( "end_color"      , Property::Value( end_color1 )    , Property::Value( end_color2 )    , 3, 3, step );
+          testProperty( "rotate_center"  , Property::Value( rotate_center1 ), Property::Value( rotate_center2 ), 4, 1, step );
+          testProperty( "rotate_angle"   , Property::Value( rotate_amount1 ), Property::Value( rotate_amount2 ), 5, 0, step );
+          testProperty( "gradient_offset", Property::Value( offset1 )       , Property::Value( offset2 )       , 6, 0, step );
+        }
+        application.SendNotification();
+        application.Render(_duration * 250.f);  // step 4/4 will not test
+        application.SendNotification();
+        step += 0.25f;
+      }
+
+      application.SendNotification();
+      actor.Unparent();
+      application.SendNotification();
+      application.Render(10.f);  // tempral time
+      application.SendNotification();
+    }
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualWireframeVisual(void)
+{
+  ToolkitTestApplication application;
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::WIREFRAME );
+
+  // Create the visual.
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  DALI_TEST_CHECK( visual );
+
+  Property::Map resultMap;
+  visual.CreatePropertyMap( resultMap );
+
+  // Check the property values from the returned map from visual
+  Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
+  DALI_TEST_CHECK( value );
+  DALI_TEST_CHECK( value->Get<int>() == Visual::WIREFRAME );
+
+  END_TEST;
+}
+
+int UtcDaliVisualGetTransform(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualGetTransform: ColorVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base colorVisual = factory.CreateVisual( propertyMap );
+
+  Dali::Property::Map visualMap;
+  colorVisual.CreatePropertyMap( visualMap );
+  Property::Value* value = visualMap.Find( Dali::Toolkit::Visual::Property::TRANSFORM );
+  Dali::Property::Map* map = value->GetMap();
+  DALI_TEST_CHECK( map );
+
+  //Test default values
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::OFFSET );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( typeValue->Get<Vector2>() == Vector2(0.0f,0.0f) );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::SIZE );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( typeValue->Get<Vector2>() == Vector2(1.0f,1.0f) );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::OFFSET_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( typeValue->Get< Vector2 >() == Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::SIZE_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( typeValue->Get< Vector2 >() == Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::ORIGIN );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( (Toolkit::Align::Type)typeValue->Get<int>() == Toolkit::Align::TOP_BEGIN );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::ANCHOR_POINT );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( (Toolkit::Align::Type)typeValue->Get<int>() == Toolkit::Align::TOP_BEGIN );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_CHECK( typeValue->Get<Vector2>() == Vector2(0.0f,0.0f) );
+  }
+
+  END_TEST;
+}
+
+static void TestTransform( ToolkitTestApplication& application, Visual::Base visual )
+{
+  Property::Map transform;
+  transform.Insert( Visual::Transform::Property::OFFSET, Vector2(10.0f, 10.0f) );
+  transform.Insert( Visual::Transform::Property::SIZE, Vector2(0.2f, 0.2f) );
+  transform.Insert( Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+  transform.Insert( Visual::Transform::Property::ORIGIN, "CENTER" );
+  transform.Insert( Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::BOTTOM_END );
+  transform.Insert( DevelVisual::Transform::Property::EXTRA_SIZE, Vector2(50.0f, 50.0f) );
+
+  visual.SetTransformAndSize( transform, Vector2(100, 100) );
+
+  Dali::Property::Map visualMap;
+  visual.CreatePropertyMap( visualMap );
+  Property::Value* value = visualMap.Find( Dali::Toolkit::Visual::Property::TRANSFORM );
+  Dali::Property::Map* map = value->GetMap();
+  DALI_TEST_CHECK( map );
+
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::OFFSET );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get<Vector2>(),Vector2(10.0f,10.0f), TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::SIZE );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get<Vector2>(), Vector2(0.2f,0.2f), TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::OFFSET_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get< Vector2 >(), Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ), TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::SIZE_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get< Vector2 >(), Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ), TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::ORIGIN );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( (Toolkit::Align::Type)typeValue->Get<int>(), Toolkit::Align::CENTER, TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::ANCHOR_POINT );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( (Toolkit::Align::Type)typeValue->Get<int>(), Toolkit::Align::BOTTOM_END, TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get<Vector2>(),Vector2(50.0f,50.0f), TEST_LOCATION );
+  }
+
+  //Put the visual on the stage
+  DummyControl actor = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(actor.GetImplementation());
+  actor.SetSize(2000, 2000);
+  actor.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(actor);
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  dummyImpl.SetLayout( DummyControl::Property::TEST_VISUAL, transform );
+
+  application.SendNotification();
+  application.Render(0);
+  Renderer renderer( actor.GetRendererAt(0) );
+
+  //Check that the properties have been registered on the Renderer
+  Property::Index index = renderer.GetPropertyIndex( "offset" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector2 offset = renderer.GetProperty<Vector2>( index );
+  DALI_TEST_EQUALS( offset, Vector2(10.0f,10.0f), TEST_LOCATION );
+
+  index = renderer.GetPropertyIndex( "size" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector2 size = renderer.GetProperty<Vector2>( index );
+  DALI_TEST_EQUALS( size, Vector2(0.2f,0.2f), TEST_LOCATION );
+
+  index = renderer.GetPropertyIndex( "offsetSizeMode" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector4 offsetSizeMode = renderer.GetProperty<Vector4>( index );
+  DALI_TEST_EQUALS( offsetSizeMode, Vector4(1.0f,1.0f,0.0f,0.0f), TEST_LOCATION );
+
+  index = renderer.GetPropertyIndex( "origin" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector2 parentOrigin = renderer.GetProperty<Vector2>( index );
+  DALI_TEST_EQUALS( parentOrigin, Vector2(0.0f,0.0f), TEST_LOCATION );
+
+  index = renderer.GetPropertyIndex( "anchorPoint" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector2 anchorPoint = renderer.GetProperty<Vector2>( index );
+  DALI_TEST_EQUALS( anchorPoint, Vector2(-0.5f,-0.5f), TEST_LOCATION );
+
+  index = renderer.GetPropertyIndex( "extraSize" );
+  DALI_TEST_CHECK( index != Property::INVALID_INDEX );
+  Vector2 extraSize = renderer.GetProperty<Vector2>( index );
+  DALI_TEST_EQUALS( extraSize, Vector2(50.0f,50.0f), TEST_LOCATION );
+
+  //Set a new transform
+  transform.Clear();
+  transform = DefaultTransform();
+  transform.Insert( Visual::Transform::Property::OFFSET, Vector2(20.0f, 20.0f) );
+  transform.Insert( Visual::Transform::Property::SIZE, Vector2(100.0f, 100.0f) );
+  transform.Insert( Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+  transform.Insert( DevelVisual::Transform::Property::EXTRA_SIZE, Vector2(0.5f, 0.5f) );
+  visual.SetTransformAndSize( transform, Vector2(100, 100) );
+  application.SendNotification();
+  application.Render(0);
+
+  //Check that the values have changed in the renderer
+  offset = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "offset" ) );
+  DALI_TEST_EQUALS( offset, Vector2(20.0f,20.0f), TEST_LOCATION );
+
+  size = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "size" ) );
+  DALI_TEST_EQUALS( size, Vector2(100.0f,100.0f), TEST_LOCATION );
+
+  offsetSizeMode = renderer.GetProperty<Vector4>( renderer.GetPropertyIndex( "offsetSizeMode" ) );
+  DALI_TEST_EQUALS( offsetSizeMode, Vector4(0.0f,0.0f,1.0f,1.0f), TEST_LOCATION );
+
+  //Parent origin and anchor point should have the default values
+  parentOrigin = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "origin" ) );
+  DALI_TEST_EQUALS( parentOrigin, Vector2(-0.5f,-0.5f), TEST_LOCATION );
+
+  anchorPoint = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "anchorPoint" ) );
+  DALI_TEST_EQUALS( anchorPoint, Vector2(0.5f,0.5f), TEST_LOCATION );
+
+  extraSize = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "extraSize" ) );
+  DALI_TEST_EQUALS( extraSize, Vector2(0.5f,0.5f), TEST_LOCATION );
+}
+
+int UtcDaliVisualSetTransform0(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: ColorVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  TestTransform( application, visual );
+  TestMixColor( visual, ColorVisual::Property::MIX_COLOR, Color::BLUE );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: PrimitiveVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap[ Toolkit::Visual::Property::TYPE           ] = Visual::PRIMITIVE;
+  propertyMap[ PrimitiveVisual::Property::MIX_COLOR ] = Color::WHITE;
+  propertyMap[ PrimitiveVisual::Property::SHAPE  ] = PrimitiveVisual::Shape::SPHERE;
+  propertyMap[ PrimitiveVisual::Property::SLICES ] = 10;
+  propertyMap[ PrimitiveVisual::Property::STACKS ] = 10;
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  TestTransform( application, visual );
+  TestMixColor( visual, PrimitiveVisual::Property::MIX_COLOR, Color::WHITE );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: GradientVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::GRADIENT );
+  propertyMap.Insert( Visual::Property::MIX_COLOR,  Color::GREEN );
+
+  Property::Array stopOffsets;
+  stopOffsets.PushBack( 0.0f );
+  stopOffsets.PushBack( 0.3f );
+  stopOffsets.PushBack( 0.6f );
+  stopOffsets.PushBack( 0.8f );
+  stopOffsets.PushBack( 1.0f );
+  propertyMap.Insert( GradientVisual::Property::STOP_OFFSET, stopOffsets );
+
+  Property::Array stopColors;
+  stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 255.f )/255.f );
+  stopColors.PushBack( Vector4( 196.f, 198.f, 71.f, 122.f )/255.f );
+  stopColors.PushBack( Vector4( 214.f, 37.f, 139.f, 191.f )/255.f );
+  stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 150.f )/255.f );
+  stopColors.PushBack( Color::YELLOW );
+  propertyMap.Insert( GradientVisual::Property::STOP_COLOR, stopColors );
+  propertyMap.Insert( GradientVisual::Property::CENTER, Vector2( 0.5f, 0.5f ) );
+  propertyMap.Insert( GradientVisual::Property::RADIUS, 1.414f );
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::GREEN );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: BorderVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::BORDER );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::MAGENTA );
+  propertyMap.Insert( BorderVisual::Property::COLOR, Vector4(0.f, 1.f, 0.f, 0.6f) );
+  propertyMap.Insert( BorderVisual::Property::SIZE, 3.0f );
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::MAGENTA );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: MeshVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( Visual::Property::MIX_COLOR, Color::CYAN );
+
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_LOCATION );
+  propertyMap.Insert( "shadingMode", MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING );
+  propertyMap.Insert( "lightPosition", Vector3( 5.0f, 10.0f, 15.0f) );
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::CYAN );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform5(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: ImageVisual from Image" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Image image = ResourceImage::New(TEST_IMAGE_FILE_NAME, ImageDimensions(100, 200));
+  Visual::Base visual = factory.CreateVisual(image);
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::WHITE );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform6(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: ImageVisual for URL " );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::IMAGE;
+  propertyMap[Visual::Property::MIX_COLOR] = Color::YELLOW;
+  propertyMap[Toolkit::ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+  propertyMap[Toolkit::ImageVisual::Property::DESIRED_WIDTH] = 100.0f;
+  propertyMap[Toolkit::ImageVisual::Property::DESIRED_HEIGHT] = 100.0f;
+  propertyMap[Toolkit::ImageVisual::Property::FITTING_MODE] = FittingMode::SCALE_TO_FILL;
+  propertyMap[Toolkit::ImageVisual::Property::SAMPLING_MODE] = SamplingMode::BOX_THEN_LINEAR;
+  propertyMap[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = true;
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::YELLOW );
+
+  END_TEST;
+}
+
+int UtcDaliVisualSetTransform7(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualSetTransform: NPatch visual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap[Toolkit::Visual::Property::TYPE] = Toolkit::Visual::IMAGE;
+  propertyMap[Toolkit::ImageVisual::Property::URL] = TEST_NPATCH_FILE_NAME;
+  propertyMap[Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING] = true;
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  TestTransform( application, visual );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::WHITE );
+
+  END_TEST;
+}
+
+int UtcDaliVisualTestTransformPoliciesAsStrings(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualTestTransformPoliciesAsStrings: Use a ColorVisual and test the offset and size policies as strings" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  Property::Map transform;
+  transform[ "offsetPolicy" ] = Property::Array().Add( "ABSOLUTE" )
+                                                 .Add( "RELATIVE" );
+  transform[ "sizePolicy"   ] = Property::Array().Add( "RELATIVE" )
+                                                 .Add( "ABSOLUTE" );
+  visual.SetTransformAndSize( transform, Vector2(100, 100) );
+
+  Dali::Property::Map visualMap;
+  visual.CreatePropertyMap( visualMap );
+  Property::Value* value = visualMap.Find( Dali::Toolkit::Visual::Property::TRANSFORM );
+  Dali::Property::Map* map = value->GetMap();
+  DALI_TEST_CHECK( map );
+
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::OFFSET_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get< Vector2 >(), Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::RELATIVE ), TEST_LOCATION );
+  }
+  {
+    Property::Value* typeValue = map->Find( Toolkit::Visual::Transform::Property::SIZE_POLICY );
+    DALI_TEST_CHECK( typeValue );
+    DALI_TEST_EQUALS( typeValue->Get< Vector2 >(), Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::ABSOLUTE ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliNPatchVisualCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "NPatchVisual with custom shader" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  Property::Map shader;
+  const std::string vertexShader = "Foobar";
+  const std::string fragmentShader = "Foobar";
+  shader[Dali::Toolkit::Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+  shader[Dali::Toolkit::Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+  Property::Map transformMap;
+  transformMap["size"] = Vector2( 0.5f, 0.5f ) ;
+  transformMap["offset"] = Vector2( 20.0f, 0.0f ) ;
+  transformMap["offsetPolicy"] = Vector2( Visual::Transform::Policy::ABSOLUTE, Visual::Transform::Policy::ABSOLUTE );
+  transformMap["anchorPoint"] = Align::CENTER;
+  transformMap["origin"] = Align::CENTER;
+  transformMap["extraSize"] = Vector2( 0.0f, 50.0f );
+  properties[Visual::Property::TRANSFORM] = transformMap;
+
+  properties[Visual::Property::TYPE] = Visual::IMAGE;
+  properties[Visual::Property::MIX_COLOR] = Color::BLUE;
+  properties[Visual::Property::SHADER]=shader;
+  properties[ImageVisual::Property::URL] = TEST_NPATCH_FILE_NAME;
+  properties[ImageVisual::Property::SYNCHRONOUS_LOADING] = true;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+  TestMixColor( visual, Visual::Property::MIX_COLOR, Color::BLUE );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  dummyImpl.SetLayout( DummyControl::Property::TEST_VISUAL, transformMap );
+  dummy.SetSize(2000, 2000);
+  dummy.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(dummy);
+  application.SendNotification();
+
+  Renderer renderer = dummy.GetRendererAt( 0 );
+  Shader shader2 = renderer.GetShader();
+  Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  Property::Index index = renderer.GetPropertyIndex("size");
+  DALI_TEST_EQUALS( renderer.GetProperty( index ), Property::Value(Vector2(0.5, 0.5)), 0.001, TEST_LOCATION );
+
+  Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+  DALI_TEST_EQUALS( fragmentShader, fragment->Get<std::string>(), TEST_LOCATION );
+
+  Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+  DALI_TEST_EQUALS( vertexShader, vertex->Get<std::string>(), TEST_LOCATION );
+
+  Vector2 extraSize = renderer.GetProperty<Vector2>( renderer.GetPropertyIndex( "extraSize" ) );
+  DALI_TEST_EQUALS( extraSize, Vector2(0.0f, 50.0f), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliGradientVisualBlendMode(void)
+{
+  ToolkitTestApplication application;
+  VisualFactory factory = VisualFactory::Get();
+
+  Visual::Base opaqueGradientVisual = factory.CreateVisual(
+      Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::GRADIENT )
+                     .Add( GradientVisual::Property::START_POSITION, Vector2( -0.5f, -0.5f ) )
+                     .Add( GradientVisual::Property::END_POSITION, Vector2( 0.5f, 0.5f ) )
+                     .Add( GradientVisual::Property::STOP_COLOR, Property::Array().Add( Color::RED )
+                                                                                  .Add( Color::GREEN ) ) );
+
+  Visual::Base alphaGradientVisual = factory.CreateVisual(
+      Property::Map().Add( Toolkit::Visual::Property::TYPE, Visual::GRADIENT )
+                     .Add( GradientVisual::Property::START_POSITION, Vector2( -0.5f, -0.5f ) )
+                     .Add( GradientVisual::Property::END_POSITION, Vector2( 0.5f, 0.5f ) )
+                     .Add( GradientVisual::Property::STOP_COLOR, Property::Array().Add( Color::RED )
+                                                                                  .Add( Vector4( 1.0f, 1.0f, 1.0f, 0.5f ) ) ) );
+
+  DummyControl control = DummyControl::New(true);
+  control.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+  Stage::GetCurrent().Add( control );
+
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>( control.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL,  opaqueGradientVisual );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, alphaGradientVisual );
+
+  application.SendNotification();
+  application.Render();
+
+  // Control should have two renderers, the first one is opaque so our blending mode should be off, the second one has some alpha so should be set to automatic
+  DALI_TEST_EQUALS( 2u, control.GetRendererCount(), TEST_LOCATION );
+  DALI_TEST_EQUALS( control.GetRendererAt( 0 ).GetProperty( Renderer::Property::BLEND_MODE ).Get<int>(), (int)BlendMode::OFF, TEST_LOCATION );
+  DALI_TEST_EQUALS( control.GetRendererAt( 1 ).GetProperty( Renderer::Property::BLEND_MODE ).Get<int>(), (int)BlendMode::AUTO, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualRendererRemovalAndReAddition(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualRendererRemoval" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+
+  visual.SetDepthIndex( 1 );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 0, TEST_LOCATION );
+
+  dummyControl.SetSize(200.f, 200.f);
+  tet_infoline( "Add control with visual to stage and check renderer count is 1" );
+
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 1, TEST_LOCATION );
+
+  tet_infoline( "Remove control with visual from stage and check renderer count is 0" );
+  Stage::GetCurrent().Remove( dummyControl );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 0, TEST_LOCATION );
+
+  tet_infoline( "Re-add control with visual to stage and check renderer count is still 1" );
+
+  Stage::GetCurrent().Add( dummyControl );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+
+int UtcDaliVisualTextVisualRender(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualTextVisualRender" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap.Insert( "mixColor", Color::WHITE );
+  propertyMap.Insert( "renderingBackend", static_cast<int>( Toolkit::Text::DEFAULT_RENDERING_BACKEND ) );
+  propertyMap.Insert( "enableMarkup", false );
+  propertyMap.Insert( "text", "Hello world" );
+  propertyMap.Insert( "fontFamily", "TizenSans" );
+
+  Property::Map fontStyleMapSet;
+  fontStyleMapSet.Insert( "weight", "bold" );
+  propertyMap.Insert( "fontStyle", fontStyleMapSet );
+
+  propertyMap.Insert( "pointSize", 12.f );
+  propertyMap.Insert( "multiLine", true );
+  propertyMap.Insert( "horizontalAlignment", "CENTER" );
+  propertyMap.Insert( "verticalAlignment", "CENTER" );
+  propertyMap.Insert( "textColor", Color::RED );
+  Visual::Base textVisual = factory.CreateVisual( propertyMap );
+  textVisual.SetDepthIndex( 1 );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, textVisual );
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 0, TEST_LOCATION );
+
+  dummyControl.SetSize(200.f, 200.f);
+  dummyControl.SetParentOrigin( ParentOrigin::CENTER );
+
+  Stage::GetCurrent().Add( dummyControl );
+  application.SendNotification();
+  application.Render();
+
+
+  // Create a texture bigger than the maximum allowed by the image atlas. Used to increase coverage.
+  propertyMap.Clear();
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap.Insert( TextVisual::Property::ENABLE_MARKUP, true );
+  propertyMap.Insert( TextVisual::Property::TEXT, "<font family='TizenSans' size='12'>Hello world</font>" );
+  propertyMap.Insert( TextVisual::Property::MULTI_LINE, true );
+
+  Property::Map transformMap;
+  transformMap.Insert( "size", Vector2( 0.5f, 0.5f ) );
+  propertyMap.Insert( Visual::Property::TRANSFORM, transformMap );
+
+  textVisual = factory.CreateVisual( propertyMap );
+  textVisual.SetDepthIndex( 1 );
+
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, textVisual );
+  dummyControl.SetSize( 720.f, 640.f );
+
+  application.SendNotification(); // force process events to ensure text visual
+  // adds renderer to the dummy control in OnRelayout
+  application.Render();
+
+  Renderer renderer = dummyControl.GetRendererAt(0u);
+  Property::Index index = renderer.GetPropertyIndex("size");
+
+  tet_infoline( "Test that the TextVisual has NOT overridden what was set by developer" );
+  DALI_TEST_EQUALS( renderer.GetProperty<Vector2>(index), Vector2( 0.5f, 0.5f ), 0.001f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualTextVisualDisableEnable(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualTextVisualDisableEnable Ensure Text visible can be re-enabled" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::TEXT );
+  propertyMap.Insert( "mixColor", Color::WHITE );
+  propertyMap.Insert( "renderingBackend", static_cast<int>( Toolkit::Text::DEFAULT_RENDERING_BACKEND ) );
+  propertyMap.Insert( "enableMarkup", false );
+  propertyMap.Insert( "text", "Hello world" );
+  propertyMap.Insert( "fontFamily", "TizenSans" );
+
+  Property::Map fontStyleMapSet;
+  fontStyleMapSet.Insert( "weight", "bold" );
+  propertyMap.Insert( "fontStyle", fontStyleMapSet );
+
+  propertyMap.Insert( "pointSize", 12.f );
+  propertyMap.Insert( "multiLine", true );
+  propertyMap.Insert( "horizontalAlignment", "CENTER" );
+  propertyMap.Insert( "verticalAlignment", "CENTER" );
+  propertyMap.Insert( "textColor", Color::RED );
+  Visual::Base textVisual = factory.CreateVisual( propertyMap );
+  textVisual.SetDepthIndex( 1 );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, textVisual );
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 0, TEST_LOCATION );
+
+  dummyControl.SetSize(200.f, 200.f);
+  dummyControl.SetParentOrigin( ParentOrigin::CENTER );
+
+  Stage::GetCurrent().Add( dummyControl );
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 1, TEST_LOCATION );
+
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, false );
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 0, TEST_LOCATION );
+
+  dummyImpl.EnableVisual( DummyControl::Property::TEST_VISUAL, true );
+
+  DALI_TEST_EQUALS( dummyControl.GetRendererCount(), 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualPremultipliedAlpha(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualPremultipliedAlpha" );
+
+  VisualFactory factory = VisualFactory::Get();
+
+  // image visual, test default value ( true )
+  {
+    Visual::Base imageVisual = factory.CreateVisual(
+          Property::Map()
+          .Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+          .Add( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME ) );
+
+    Dali::Property::Map visualMap;
+    imageVisual.CreatePropertyMap( visualMap );
+    Property::Value* value = visualMap.Find( Visual::Property::PREMULTIPLIED_ALPHA );
+
+    // test values
+    DALI_TEST_CHECK( value );
+    DALI_TEST_EQUALS( value->Get<bool>(), true, TEST_LOCATION );
+  }
+
+  // image visual, override premultiplied
+  {
+    Visual::Base imageVisual = factory.CreateVisual(
+          Property::Map()
+          .Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+          .Add( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME )
+          .Add( Visual::Property::PREMULTIPLIED_ALPHA, false ) );
+
+    Dali::Property::Map visualMap;
+    imageVisual.CreatePropertyMap( visualMap );
+    Property::Value* value = visualMap.Find( Visual::Property::PREMULTIPLIED_ALPHA );
+
+    // test values
+    DALI_TEST_CHECK( value );
+    DALI_TEST_EQUALS( value->Get<bool>(), false, TEST_LOCATION);
+  }
+
+  // svg visual ( premultiplied alpha by default is true )
+  {
+    Visual::Base imageVisual = factory.CreateVisual(
+          Property::Map()
+          .Add( Toolkit::Visual::Property::TYPE, Visual::IMAGE )
+          .Add( ImageVisual::Property::URL, TEST_SVG_FILE_NAME ) );
+
+    Dali::Property::Map visualMap;
+    imageVisual.CreatePropertyMap( visualMap );
+    Property::Value* value = visualMap.Find( Visual::Property::PREMULTIPLIED_ALPHA );
+
+    // test values
+    DALI_TEST_CHECK( value );
+    DALI_TEST_EQUALS( value->Get<bool>(), true, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliRegisterVisualOrder(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register Visual Order" );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+
+  tet_infoline( "Register visual, should have depth index of 0.0f" );
+  Visual::Base testVisual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, testVisual );
+  DALI_TEST_EQUALS( testVisual.GetDepthIndex(), 0, TEST_LOCATION );
+
+  tet_infoline( "Register more visuals, each added one should have a depth index greater than previous" );
+
+  Visual::Base testVisual2 = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, testVisual2 );
+  DALI_TEST_CHECK( testVisual2.GetDepthIndex() > testVisual.GetDepthIndex() );
+
+  Visual::Base foregroundVisual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::FOREGROUND_VISUAL, foregroundVisual );
+  DALI_TEST_CHECK( foregroundVisual.GetDepthIndex() > testVisual2.GetDepthIndex() );
+
+  Visual::Base focusVisual = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::FOCUS_VISUAL, focusVisual );
+  DALI_TEST_CHECK( focusVisual.GetDepthIndex() > foregroundVisual.GetDepthIndex() );
+
+  tet_infoline( "Set depth index on a new visual before registering, the depth index should not have been changed" );
+  Visual::Base labelVisual = factory.CreateVisual( propertyMap );
+  labelVisual.SetDepthIndex( -2000 );
+  dummyImpl.RegisterVisual( DummyControl::Property::LABEL_VISUAL, labelVisual );
+  DALI_TEST_EQUALS( labelVisual.GetDepthIndex(), -2000, TEST_LOCATION );
+
+  tet_infoline( "Replace visual, the depth index should be the same as what was previously set" );
+  const int testVisual2DepthIndex = testVisual2.GetDepthIndex();
+  Visual::Base testVisual2Replacement = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( testVisual2Replacement.GetDepthIndex() != testVisual2DepthIndex );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, testVisual2Replacement );
+  DALI_TEST_EQUALS( testVisual2Replacement.GetDepthIndex(), testVisual2DepthIndex, TEST_LOCATION );
+
+  tet_infoline( "Replace visual and set a depth index on the replacement, the depth index of the replacement should be honoured" );
+  Visual::Base anotherTestVisual2Replacement = factory.CreateVisual( propertyMap );
+  anotherTestVisual2Replacement.SetDepthIndex( 2000 );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, anotherTestVisual2Replacement );
+  DALI_TEST_EQUALS( anotherTestVisual2Replacement.GetDepthIndex(), 2000, TEST_LOCATION );
+
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  END_TEST;
+}
+
+int UtcDaliRegisterVisualOrder02(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register Visual Order with Background Set" );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  const int backgroundDepthIndex = Toolkit::DepthIndex::BACKGROUND;
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+
+  tet_printf( "Register a control background visual, should have depth index of %d\n", backgroundDepthIndex );
+
+  dummyControl.SetProperty( Control::Property::BACKGROUND, propertyMap );
+
+  const int TEST_VISUAL_1_DEPTH_INDEX = 0;
+  tet_printf( "Register visual, should have depth index of %d\n", TEST_VISUAL_1_DEPTH_INDEX );
+  Visual::Base testVisual1 = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, testVisual1 );
+  DALI_TEST_EQUALS( testVisual1.GetDepthIndex(), TEST_VISUAL_1_DEPTH_INDEX , TEST_LOCATION );
+
+  tet_printf( "Register another visual, should have a depth index greater than previous(%d)\n", TEST_VISUAL_1_DEPTH_INDEX );
+  Visual::Base testVisual2 = factory.CreateVisual( propertyMap );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL2, testVisual2 );
+  DALI_TEST_CHECK( testVisual2.GetDepthIndex() >  testVisual1.GetDepthIndex() );
+
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  END_TEST;
+}
+
+int UtcDaliRegisterVisualWithDepthIndex(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Register a Visual With Depth Index" );
+
+  DummyControl dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  Color::BLUE);
+
+  tet_infoline( "Register a visual with a depth index, it should be enabled by default too" );
+  Visual::Base testVisual = factory.CreateVisual( propertyMap );
+  DevelControl::RegisterVisual( dummyImpl, DummyControl::Property::TEST_VISUAL, testVisual, 203 );
+  DALI_TEST_EQUALS( testVisual.GetDepthIndex(), 203, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsVisualEnabled( dummyImpl, DummyControl::Property::TEST_VISUAL ), true, TEST_LOCATION );
+
+  tet_infoline( "Register another visual with a depth index and it disabled" );
+  Visual::Base testVisual2 = factory.CreateVisual( propertyMap );
+  DevelControl::RegisterVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, testVisual2, false, 450 );
+  DALI_TEST_EQUALS( testVisual2.GetDepthIndex(), 450, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsVisualEnabled( dummyImpl, DummyControl::Property::TEST_VISUAL2 ), false, TEST_LOCATION );
+
+  tet_infoline( "Register another visual with a depth index and it enabled using the enabled API" );
+  Visual::Base testVisual3 = factory.CreateVisual( propertyMap );
+  DevelControl::RegisterVisual( dummyImpl, DummyControl::Property::TEST_VISUAL2, testVisual3, true, 300 );
+  DALI_TEST_EQUALS( testVisual3.GetDepthIndex(), 300, TEST_LOCATION );
+  DALI_TEST_EQUALS( DevelControl::IsVisualEnabled( dummyImpl, DummyControl::Property::TEST_VISUAL2 ), true, TEST_LOCATION );
+
+  dummyControl.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( dummyControl );
+
+  END_TEST;
+}
+
+int UtcDaliColorVisualRenderIfTransparentProperty(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "Test the renderIfTransparent property of ColorVisual" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map propertyMap;
+  propertyMap.Insert( Visual::Property::TYPE,  Visual::COLOR );
+  propertyMap.Insert( ColorVisual::Property::MIX_COLOR, Color::BLUE );
+
+  tet_infoline( "Check default value" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+  }
+
+  propertyMap.Insert( DevelColorVisual::Property::RENDER_IF_TRANSPARENT, true );
+
+  tet_infoline( "Ensure set to value required" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), true, TEST_LOCATION );
+  }
+
+  propertyMap[ DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = Color::BLUE;
+
+  tet_infoline( "Ensure it returns default value if set to wrong type" );
+  {
+    Visual::Base testVisual = factory.CreateVisual( propertyMap );
+    Property::Map returnedMap;
+    testVisual.CreatePropertyMap( returnedMap );
+
+    Property::Value* renderIfTransparentProperty = returnedMap.Find( DevelColorVisual::Property::RENDER_IF_TRANSPARENT );
+    DALI_TEST_CHECK( renderIfTransparentProperty );
+    DALI_TEST_EQUALS( renderIfTransparentProperty->Get< bool >(), false, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliSvgVisualCustomShader(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "SvgVisual with custom shader" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  Property::Map shader;
+  const std::string vertexShader = "Foobar";
+  const std::string fragmentShader = "Foobar";
+  shader[Dali::Toolkit::Visual::Shader::Property::FRAGMENT_SHADER] = fragmentShader;
+  shader[Dali::Toolkit::Visual::Shader::Property::VERTEX_SHADER] = vertexShader;
+
+  properties[Visual::Property::TYPE] = Visual::IMAGE;
+  properties[Visual::Property::SHADER] = shader;
+  properties[ImageVisual::Property::URL] = TEST_SVG_FILE_NAME;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  dummy.SetSize( 200.f, 200.f );
+  dummy.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( dummy );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  Renderer renderer = dummy.GetRendererAt( 0 );
+  Shader shader2 = renderer.GetShader();
+  Property::Value value = shader2.GetProperty( Shader::Property::PROGRAM );
+  Property::Map* map = value.GetMap();
+  DALI_TEST_CHECK( map );
+
+  Property::Value* fragment = map->Find( "fragment" ); // fragment key name from shader-impl.cpp
+  DALI_TEST_EQUALS( fragmentShader, fragment->Get< std::string >(), TEST_LOCATION );
+
+  Property::Value* vertex = map->Find( "vertex" ); // vertex key name from shader-impl.cpp
+  DALI_TEST_EQUALS( vertexShader, vertex->Get< std::string >(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualRoundedCorner(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualRoundedCorner" );
+
+  // image visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float cornerRadius = 30.0f;
+
+    properties[Visual::Property::TYPE] = Visual::IMAGE;
+    properties[ImageVisual::Property::URL] = TEST_IMAGE_FILE_NAME;
+    properties[DevelVisual::Property::CORNER_RADIUS] = cornerRadius;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetSize( 200.f, 200.f );
+    dummy.SetParentOrigin( ParentOrigin::CENTER );
+    Stage::GetCurrent().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+  }
+
+  // color visual
+  {
+    VisualFactory factory = VisualFactory::Get();
+    Property::Map properties;
+    float cornerRadius = 30.0f;
+
+    properties[Visual::Property::TYPE] = Visual::COLOR;
+    properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+    properties["cornerRadius"] = cornerRadius;
+
+    Visual::Base visual = factory.CreateVisual( properties );
+
+    // trigger creation through setting on stage
+    DummyControl dummy = DummyControl::New( true );
+    Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    dummy.SetSize( 200.f, 200.f );
+    dummy.SetParentOrigin( ParentOrigin::CENTER );
+    Stage::GetCurrent().Add( dummy );
+
+    application.SendNotification();
+    application.Render();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "cornerRadius", cornerRadius ), true, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliColorVisualBlurRadius(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliColorVisualBlurRadius" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  float blurRadius = 20.0f;
+
+  properties[Visual::Property::TYPE] = Visual::COLOR;
+  properties[ColorVisual::Property::MIX_COLOR] = Color::BLUE;
+  properties["blurRadius"] = blurRadius;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New( true );
+  Impl::DummyControl& dummyImpl = static_cast< Impl::DummyControl& >( dummy.GetImplementation() );
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  dummy.SetSize( 200.f, 200.f );
+  dummy.SetParentOrigin( ParentOrigin::CENTER );
+  Stage::GetCurrent().Add( dummy );
+
+  application.SendNotification();
+  application.Render();
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( application.GetGlAbstraction().CheckUniformValue< float >( "blurRadius", blurRadius ), true, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp b/automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
new file mode 100644 (file)
index 0000000..c7f4282
--- /dev/null
@@ -0,0 +1,2164 @@
+/*
+ * Copyright (c) 2020 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 <toolkit-timer.h>
+#include <toolkit-event-thread-callback.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include "dummy-control.h"
+
+#include <dali/integration-api/debug.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+typedef Toolkit::Internal::NPatchLoader::StretchRanges StretchRanges;
+
+const char* TEST_9_PATCH_FILE_NAME =  TEST_RESOURCE_DIR  "/demo-tile-texture-focused.9.png";
+const char* TEST_NPATCH_FILE_NAME =  TEST_RESOURCE_DIR  "/heartsframe.9.png";
+const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
+const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
+const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj";
+const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
+const char* TEST_AUX_IMAGE = TEST_RESOURCE_DIR "/folder_appicon_empty_bg.png";
+const char* TEST_IMAGE_FILE_NAME =  TEST_RESOURCE_DIR  "/gallery-small-1.jpg";
+
+// resolution: 50*50, frame count: 4, frame delay: 0.2 second for each frame
+const char* TEST_GIF_FILE_NAME = TEST_RESOURCE_DIR "/anim.gif";
+
+// resolution: 34*34, pixel format: RGBA8888
+static const char* gImage_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+
+
+Property::Map DefaultTransform()
+{
+  Property::Map transformMap;
+  transformMap
+    .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2(0.0f, 0.0f) )
+    .Add( Toolkit::Visual::Transform::Property::SIZE, Vector2(1.0f, 1.0f) )
+    .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::CENTER )
+    .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::CENTER )
+    .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) )
+    .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+  return transformMap;
+}
+
+void TestVisualRender( ToolkitTestApplication& application,
+                       DummyControl& actor,
+                       Visual::Base& visual )
+{
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  application.Render();
+  application.SendNotification();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+}
+
+void TestVisualAsynchronousRender( ToolkitTestApplication& application,
+                                   DummyControl& actor,
+                                   Visual::Base& visual )
+{
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+}
+
+} // namespace
+
+
+void dali_visual_factory_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_visual_factory_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliVisualFactoryGet(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactory" );
+
+  //Register type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "VisualFactory" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  VisualFactory factory;
+  factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  VisualFactory newFactory = VisualFactory::Get();
+  DALI_TEST_CHECK( newFactory );
+
+  // Check that visual factory is a singleton
+  DALI_TEST_CHECK(factory == newFactory);
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryCopyAndAssignment" );
+  VisualFactory factory = VisualFactory::Get();
+
+  VisualFactory factoryCopy( factory );
+  DALI_TEST_CHECK(factory == factoryCopy);
+
+  VisualFactory emptyFactory;
+  VisualFactory emptyFactoryCopy( emptyFactory );
+  DALI_TEST_CHECK(emptyFactory == emptyFactoryCopy);
+
+  VisualFactory factoryEquals;
+  factoryEquals = factory;
+  DALI_TEST_CHECK(factory == factoryEquals);
+
+  VisualFactory emptyFactoryEquals;
+  emptyFactoryEquals = emptyFactory;
+  DALI_TEST_CHECK( emptyFactory == emptyFactoryEquals );
+
+  //self assignment
+  factory = factory;
+  DALI_TEST_CHECK( factory = factoryCopy );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetColorVisual1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetColorVisual1:  Request color visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  Vector4 testColor( 1.f, 0.5f, 0.3f, 0.2f );
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::COLOR);
+  propertyMap.Insert(ColorVisual::Property::MIX_COLOR,  testColor);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New(true);
+  TestVisualRender( application, actor, visual );
+
+  Vector3 actualValue(Vector4::ZERO);
+  Vector4 actualColor(Vector4::ZERO);
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector3>( "mixColor", actualValue ) );
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uColor", actualColor ) );
+  DALI_TEST_EQUALS( actualValue, Vector3(testColor), TEST_LOCATION );
+  DALI_TEST_EQUALS( actualColor.a, testColor.a, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetColorVisual2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetColorVisual2: Request color visual with a Vector4" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Vector4 testColor( 1.f, 0.5f, 0.3f, 0.2f );
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::COLOR;
+  map[ ColorVisual::Property::MIX_COLOR ] = testColor;
+  Visual::Base visual = factory.CreateVisual( map );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New(true);
+  TestVisualRender( application, actor, visual );
+
+  Vector3 actualValue;
+  Vector4 actualColor;
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector3>( "mixColor", actualValue ) );
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "uColor", actualColor ) );
+  DALI_TEST_EQUALS( actualValue, Vector3(testColor), TEST_LOCATION );
+  DALI_TEST_EQUALS( actualColor.a, testColor.a, TEST_LOCATION );
+
+  Stage::GetCurrent().Remove(actor);
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetBorderVisual1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetBorderVisual1:  Request border visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  Vector4 testColor( 1.f, 0.5f, 0.3f, 0.2f );
+  float testSize = 5.f;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::BORDER);
+  propertyMap.Insert(BorderVisual::Property::COLOR,  testColor);
+  propertyMap.Insert(BorderVisual::Property::SIZE,  testSize);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f));
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  int blendMode = actor.GetRendererAt(0u).GetProperty<int>( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( static_cast<BlendMode::Type>(blendMode), BlendMode::ON, TEST_LOCATION );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  application.SendNotification();
+  application.Render(0);
+
+  Vector4 actualColor(Vector4::ZERO);
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "borderColor", actualColor ) );
+  DALI_TEST_EQUALS( actualColor, testColor, TEST_LOCATION );
+
+  float actualSize = 0.f;
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "borderSize", actualSize ) );
+  DALI_TEST_EQUALS( actualSize, testSize, TEST_LOCATION );
+
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetBorderVisual2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetBorderVisual2:  Request border visual with a borderSize and a borderColor" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Vector4 testColor( 1.f, 0.5f, 0.3f, 1.f );
+  float testSize = 5.f;
+
+  Dali::Property::Map propertyMap;
+  propertyMap[ Toolkit::Visual::Property::TYPE ] = Visual::BORDER;
+  propertyMap[ BorderVisual::Property::COLOR  ] = testColor;
+  propertyMap[ BorderVisual::Property::SIZE   ] = testSize;
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize(200.f, 200.f);
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f));
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+
+  application.SendNotification();
+  application.Render(0);
+
+  int blendMode = actor.GetRendererAt(0u).GetProperty<int>( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( static_cast<BlendMode::Type>(blendMode), BlendMode::AUTO, TEST_LOCATION );
+
+  Vector4 actualColor(Vector4::ZERO);
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "borderColor", actualColor ) );
+  DALI_TEST_EQUALS( actualColor, testColor, TEST_LOCATION );
+
+  float actualSize = 0.f;
+  DALI_TEST_CHECK( gl.GetUniformValue<float>( "borderSize", actualSize ) );
+  DALI_TEST_EQUALS( actualSize, testSize, TEST_LOCATION );
+
+  actor.Unparent();
+
+  // enable the anti-aliasing
+  Dali::Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Visual::BORDER;
+  map[ BorderVisual::Property::COLOR  ] = testColor;
+  map[ BorderVisual::Property::SIZE   ] = testSize;
+  map[ BorderVisual::Property::ANTI_ALIASING   ] = true;
+  visual = factory.CreateVisual( map );
+
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  Stage::GetCurrent().Add( actor );
+
+  blendMode = actor.GetRendererAt(0u).GetProperty<int>( Renderer::Property::BLEND_MODE );
+  DALI_TEST_EQUALS( static_cast<BlendMode::Type>(blendMode), BlendMode::ON, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetLinearGradientVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVisualFactoryGetRadialGradientVisual");
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+
+  Vector2 start(-1.f, -1.f);
+  Vector2 end(1.f, 1.f);
+  propertyMap.Insert(GradientVisual::Property::START_POSITION, start);
+  propertyMap.Insert(GradientVisual::Property::END_POSITION, end);
+  propertyMap.Insert(GradientVisual::Property::SPREAD_METHOD, GradientVisual::SpreadMethod::REPEAT);
+
+  Property::Array stopOffsets;
+  stopOffsets.PushBack( 0.2f );
+  stopOffsets.PushBack( 0.8f );
+  propertyMap.Insert(GradientVisual::Property::STOP_OFFSET, stopOffsets);
+
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR, stopColors);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( visual );
+
+  // A lookup texture is generated and pass to shader as sampler
+  DummyControl actor = DummyControl::New(true);
+  TestVisualRender( application, actor, visual );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetRadialGradientVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVisualFactoryGetRadialGradientVisual");
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+
+  Vector2 center(100.f, 100.f);
+  float radius = 100.f;
+  propertyMap.Insert(GradientVisual::Property::UNITS,  GradientVisual::Units::USER_SPACE);
+  propertyMap.Insert(GradientVisual::Property::CENTER,  center);
+  propertyMap.Insert(GradientVisual::Property::RADIUS,  radius);
+
+  Property::Array stopOffsets;
+  stopOffsets.PushBack( 0.0f );
+  stopOffsets.PushBack( 1.f );
+  propertyMap.Insert(GradientVisual::Property::STOP_OFFSET,   stopOffsets);
+
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR,   stopColors);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( visual );
+
+  // A lookup texture is generated and pass to shader as sampler
+  DummyControl actor = DummyControl::New(true);
+  TestVisualRender( application, actor, visual );
+
+  Matrix3 alignMatrix( radius, 0.f, 0.f, 0.f, radius, 0.f, center.x, center.y, 1.f );
+  alignMatrix.Invert();
+
+  Matrix3 actualValue( Matrix3::IDENTITY );
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  DALI_TEST_CHECK( gl.GetUniformValue<Matrix3>( "uAlignmentMatrix", actualValue ) );
+  DALI_TEST_EQUALS( actualValue, alignMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryDefaultOffsetsGradientVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliVisualFactoryGetRadialGradientVisual");
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert(Visual::Property::TYPE,  Visual::GRADIENT);
+
+  Vector2 start(-1.f, -1.f);
+  Vector2 end(1.f, 1.f);
+  propertyMap.Insert(GradientVisual::Property::START_POSITION, start);
+  propertyMap.Insert(GradientVisual::Property::END_POSITION, end);
+  propertyMap.Insert(GradientVisual::Property::SPREAD_METHOD, GradientVisual::SpreadMethod::REPEAT);
+
+  Property::Array stopColors;
+  stopColors.PushBack( Color::RED );
+  stopColors.PushBack( Color::GREEN );
+  propertyMap.Insert(GradientVisual::Property::STOP_COLOR, stopColors);
+
+  Visual::Base visual = factory.CreateVisual(propertyMap);
+  DALI_TEST_CHECK( visual );
+
+  // A lookup texture is generated and pass to shader as sampler
+  DummyControl actor = DummyControl::New(true);
+  TestVisualRender( application, actor, visual );
+
+  Stage::GetCurrent().Remove( actor );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad1: Request 9-patch visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+  }
+
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  {
+    tet_infoline( "border only" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualSynchronousLoad2: Request 9-patch visual with a Property::Map including border" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( gImage_34_RGBA );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
+  propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 2, 2, 2, 2 ) );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  {
+    tet_infoline( "border only" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  propertyMap.Clear();
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
+  propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 1, 1, 1, 1 ) );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, true );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual1: Request 9-patch visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, false );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualAsynchronousRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+  }
+
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  {
+    tet_infoline( "border only" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual2: Request 9-patch visual with a Property::Map including border" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( gImage_34_RGBA );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
+  propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 2, 2, 2, 2 ) );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualAsynchronousRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  {
+    tet_infoline( "border only" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  propertyMap.Clear();
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
+  propertyMap.Insert( ImageVisual::Property::BORDER, Rect< int >( 1, 1, 1, 1 ) );
+  {
+    tet_infoline( "whole grid" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual3(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual3: Request n-patch visual with a Property::Map" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_NPATCH_FILE_NAME );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_NPATCH_FILE_NAME );
+  {
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualAsynchronousRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+  }
+
+  propertyMap.Insert( ImageVisual::Property::BORDER_ONLY,  true );
+  {
+    tet_infoline( "border only" );
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+    DummyControl actor = DummyControl::New(true);
+    TestVisualRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual4(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual4: Request 9-patch visual with an image url" );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Visual::Base visual = factory.CreateVisual( TEST_9_PATCH_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  DummyControl actor = DummyControl::New(true);
+  TestVisualAsynchronousRender( application, actor, visual );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Vector2 naturalSize( 0.0f, 0.0f );
+  visual.GetNaturalSize( naturalSize );
+  DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+  textureTrace.Reset();
+
+  ResourceImage image = ResourceImage::New( TEST_9_PATCH_FILE_NAME );
+  Visual::Base nPatchVisual = factory.CreateVisual( image );
+
+  DummyControl actor1 = DummyControl::New(true);
+  TestVisualRender( application, actor1, nPatchVisual );
+
+  DALI_TEST_EQUALS( textureTrace.CountMethod("BindTexture"), 0, TEST_LOCATION );  // The same texture should be used with the first visual.
+
+  naturalSize = Vector2( 0.0f, 0.0f );
+  nPatchVisual.GetNaturalSize( naturalSize );
+  DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual5(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual5: Request n-patch visual with an image url" );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_NPATCH_FILE_NAME );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Visual::Base visual = factory.CreateVisual( TEST_NPATCH_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  TestVisualAsynchronousRender( application, actor, visual );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  Vector2 naturalSize( 0.0f, 0.0f );
+  visual.GetNaturalSize( naturalSize );
+  DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual6(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual6: Request n-patch visual with a general image" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  {
+    // Get actual size of test image
+    ImageDimensions imageSize = Dali::GetClosestImageSize( gImage_34_RGBA );
+
+    Property::Map propertyMap;
+    propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+    propertyMap.Insert( ImageVisual::Property::URL, gImage_34_RGBA );
+
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualAsynchronousRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  }
+
+  {
+    // Get actual size of test image
+    ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_IMAGE_FILE_NAME );
+
+    Property::Map propertyMap;
+    propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+    propertyMap.Insert( ImageVisual::Property::URL, TEST_IMAGE_FILE_NAME );
+
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+    TestVisualAsynchronousRender( application, actor, visual );
+
+    DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth() - 2.0f, imageSize.GetHeight() - 2.0f ), TEST_LOCATION );
+
+    Stage::GetCurrent().Remove( actor );
+    DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisual7(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisual7: Add 9-patch visual on stage and instantly remove it." );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  // Get actual size of test image
+  ImageDimensions imageSize = Dali::GetClosestImageSize( TEST_9_PATCH_FILE_NAME );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_9_PATCH_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::SYNCHRONOUS_LOADING, false );
+  {
+    Visual::Base visual = factory.CreateVisual( propertyMap );
+    DALI_TEST_CHECK( visual );
+
+    Vector2 naturalSize( 0.0f, 0.0f );
+    visual.GetNaturalSize( naturalSize );
+    DALI_TEST_EQUALS( naturalSize, Vector2( imageSize.GetWidth(), imageSize.GetHeight() ), TEST_LOCATION );
+
+    TestGlAbstraction& gl = application.GetGlAbstraction();
+    TraceCallStack& textureTrace = gl.GetTextureTrace();
+    textureTrace.Enable(true);
+
+    DummyControl actor = DummyControl::New(true);
+
+    DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+    dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+    actor.SetSize( 200.f, 200.f );
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+
+    Stage::GetCurrent().Add( actor );
+    actor.Unparent();
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger(1 ), true, TEST_LOCATION );
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliNPatchVisualAuxiliaryImage(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "NPatchVisual with aux image" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Property::Map properties;
+  Property::Map shader;
+
+  Property::Map transformMap;
+  transformMap["size"] = Vector2( 0.5f, 0.5f ) ;
+  transformMap["offset"] = Vector2( 20.0f, 0.0f ) ;
+  transformMap["offsetPolicy"] = Vector2( Visual::Transform::Policy::ABSOLUTE, Visual::Transform::Policy::ABSOLUTE );
+  transformMap["anchorPoint"] = Align::CENTER;
+  transformMap["origin"] = Align::CENTER;
+  properties[Visual::Property::TRANSFORM] = transformMap;
+
+  properties[Visual::Property::TYPE] = Visual::IMAGE;
+  properties[Visual::Property::MIX_COLOR] = Color::BLUE;
+  properties[Visual::Property::SHADER]=shader;
+  properties[ImageVisual::Property::URL] = TEST_9_PATCH_FILE_NAME;
+  properties[DevelImageVisual::Property::AUXILIARY_IMAGE] = TEST_AUX_IMAGE;
+  properties[DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA] = 0.9f;
+
+  Visual::Base visual = factory.CreateVisual( properties );
+
+  // trigger creation through setting on stage
+  DummyControl dummy = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl = static_cast<Impl::DummyControl&>(dummy.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  dummyImpl.SetLayout( DummyControl::Property::TEST_VISUAL, transformMap );
+  dummy.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+  dummy.SetParentOrigin(ParentOrigin::CENTER);
+  Stage::GetCurrent().Add(dummy);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 2 ), true, TEST_LOCATION );
+
+  application.SendNotification();
+  application.Render();
+
+  Renderer renderer = dummy.GetRendererAt( 0 );
+  auto textures = renderer.GetTextures();
+  DALI_TEST_EQUALS( textures.GetTextureCount(), 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliVisualFactoryGetNPatchVisualN1(void)
+{
+  //This should still load but display an error image
+
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualN: Request n-patch visual with an invalid image url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Visual::Base visual = factory.CreateVisual( "ERROR.9.jpg", ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  TestVisualAsynchronousRender( application, actor, visual );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisualN2(void)
+{
+  //This should still load but display an error image
+
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualN: Request n-patch visual with an invalid URL" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::N_PATCH );
+  propertyMap.Insert( ImageVisual::Property::URL,  "ERROR.9.jpg" );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& drawTrace = gl.GetDrawTrace();
+  drawTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  TestVisualAsynchronousRender( application, actor, visual );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetNPatchVisualN3(void)
+{
+  // Passing in an invalid visual type so we should not get a visual
+
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetNPatchVisualN: Request n-patch visual with an invalid visual type" );
+
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  111 );
+  propertyMap.Insert( ImageVisual::Property::URL,  "ERROR.9.jpg" );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( !visual );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetSvgVisual(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetSvgVisual: Request svg visual with a svg url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_SVG_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f) );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is not added to actor until the rasterization is completed.
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  // waiting for the resource uploading
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetSvgVisualLarge(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetSvgVisual: Request svg visual with a svg url" );
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_SVG_FILE_NAME, ImageDimensions( 2000, 2000 ) );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); // Only rasterizes when it knows control size.
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is not added to actor until the rasterization is completed.
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  // waiting for the resource uploading
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetSvgVisualAtlas(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetSvgVisual: Request svg visual with enabled atlas" );
+
+  VisualFactory factory = VisualFactory::Get();
+
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::SVG );
+  propertyMap.Insert( ImageVisual::Property::URL, TEST_SVG_FILE_NAME );
+  propertyMap.Insert( ImageVisual::Property::ATLASING, true );
+
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(), Vector2(200.f, 200.f) );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is not added to actor until the rasterization is completed.
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  // waiting for the resource uploading
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+//Creates a mesh visual from the given propertyMap and tries to load it on stage in the given application.
+//This is expected to succeed, which will then pass the test.
+void MeshVisualLoadsCorrectlyTest( Property::Map& propertyMap, ToolkitTestApplication& application )
+{
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Create a mesh visual.
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  //Create an actor on stage to house the visual.
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(), Vector2( 200.f, 200.f ) );
+
+  //Ensure set on stage.
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  //Finish by setting off stage, and ensuring this was successful.
+  actor.Unparent();
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+}
+
+//Creates a mesh visual from the given propertyMap and tries to load it on stage in the given application.
+//This is expected to fail, which will then pass the test.
+void MeshVisualDoesNotLoadCorrectlyTest( Property::Map& propertyMap, ToolkitTestApplication& application )
+{
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Create a mesh visual.
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  //Create an actor on stage to house the visual.
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(),  Vector2( 200.f, 200.f ) );
+
+  //Ensure set on stage.
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+  //Attempt to render to queue resource load requests.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Render again to upload the now-loaded textures.
+  application.SendNotification();
+  application.Render( 0 );
+
+  //Test to see if the object has not been loaded, as expected.
+  Matrix scaleMatrix;
+  DALI_TEST_CHECK( !application.GetGlAbstraction().GetUniformValue<Matrix>( "uObjectMatrix", scaleMatrix ) );
+
+  //Finish by setting off stage, and ensuring this was successful.
+  actor.Unparent();
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+}
+
+//Test if mesh loads correctly when supplied with only the bare minimum requirements, an object file.
+int UtcDaliVisualFactoryGetMeshVisual1(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual1:  Request mesh visual with a valid object file only" );
+
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE,  Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+
+//Test if mesh loads correctly when supplied with an object file as well as a blank material file and images directory.
+int UtcDaliVisualFactoryGetMeshVisual2(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual2:  Request mesh visual with blank material file and images directory" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, "" );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, "" );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh loads correctly when supplied with all main parameters, an object file, a material file and a directory location, but duff optional parameters
+int UtcDaliVisualFactoryGetMeshVisual3b(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual3:  Request mesh visual with all parameters correct" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::USE_MIPMAPPING, Color::GREEN ); // Test that wrong property types don't prevent the object load
+  propertyMap.Insert( MeshVisual::Property::USE_SOFT_NORMALS, 1.0f );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, 1.0f );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh loads correctly when supplied with all main parameters, an object file, a material file and a directory location.
+int UtcDaliVisualFactoryGetMeshVisual3(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual3:  Request mesh visual with all parameters correct" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::USE_MIPMAPPING, false );
+  propertyMap.Insert( MeshVisual::Property::USE_SOFT_NORMALS, false );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, Vector3::XAXIS );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh visual can load a correctly supplied mesh without a normal map or gloss map in the material file.
+int UtcDaliVisualFactoryGetMeshVisual4(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual4:  Request mesh visual with diffuse texture but not normal or gloss." );
+
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_SIMPLE_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh visual can load when made to use diffuse textures only.
+int UtcDaliVisualFactoryGetMeshVisual5(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual5:  Request mesh visual and make it only use diffuse textures." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( "objectUrl", TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+  propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+  propertyMap.Insert( "useMipmapping", false );
+  propertyMap.Insert( "useSoftNormals", false );
+  propertyMap.Insert( "lightPosition", Vector3::ZAXIS );
+  propertyMap.Insert( "shadingMode", MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+
+  END_TEST;
+}
+
+//Test if mesh visual can load when made to not use the supplied textures.
+int UtcDaliVisualFactoryGetMeshVisual6(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual6:  Request mesh visual and make it not use any textures." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+  propertyMap.Insert( MeshVisual::Property::SHADING_MODE, MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+//Test if mesh visual loads correctly when light position is manually set.
+int UtcDaliVisualFactoryGetMeshVisual7(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual7:  Request mesh visual with custom light position." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, Vector3( 0.0, 1.0, 2.0 ) );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh visual loads correctly when supplied an object file without face normals or texture points.
+//Note that this notably tests object loader functionality.
+int UtcDaliVisualFactoryGetMeshVisual8(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisual5:  Request mesh visual with normal-less object file." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_SIMPLE_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh loads correctly.
+  MeshVisualLoadsCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if mesh visual handles the case of lacking an object file.
+int UtcDaliVisualFactoryGetMeshVisualN1(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisualN1:  Request mesh visual without object file" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh doesn't load with these properties, as expected.
+  MeshVisualDoesNotLoadCorrectlyTest( propertyMap, application );
+
+
+  END_TEST;
+}
+
+//Test if mesh visual handles the case of being passed invalid material and images urls.
+int UtcDaliVisualFactoryGetMeshVisualN2(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisualN2:  Request mesh visual with invalid material and images urls" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, TEST_OBJ_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, "invalid" );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, "also invalid" );
+
+  //Test to see if mesh doesn't load with these properties, as expected.
+  MeshVisualDoesNotLoadCorrectlyTest( propertyMap, application );
+
+
+  END_TEST;
+}
+
+//Test if mesh visual handles the case of being passed an invalid object url
+int UtcDaliVisualFactoryGetMeshVisualN3(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetMeshVisualN3:  Request mesh visual with invalid object url" );
+
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::MESH );
+  propertyMap.Insert( MeshVisual::Property::OBJECT_URL, "invalid" );
+  propertyMap.Insert( MeshVisual::Property::MATERIAL_URL, TEST_MTL_FILE_NAME );
+  propertyMap.Insert( MeshVisual::Property::TEXTURES_PATH, TEST_RESOURCE_DIR "/" );
+
+  //Test to see if mesh doesn't load with these properties, as expected.
+  MeshVisualDoesNotLoadCorrectlyTest( propertyMap, application );
+
+  END_TEST;
+}
+
+//Creates a primitive visual with the given property map and tests to see if it correctly loads in the given application.
+void TestPrimitiveVisualWithProperties( Property::Map& propertyMap, ToolkitTestApplication& application )
+{
+  VisualFactory factory = VisualFactory::Get();
+  DALI_TEST_CHECK( factory );
+
+  //Create a primitive visual.
+  Visual::Base visual = factory.CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  //Create an actor on stage to house the visual.
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+  actor.SetSize( 200.f, 200.f );
+  Stage::GetCurrent().Add( actor );
+  visual.SetTransformAndSize(DefaultTransform(),  Vector2( 200.f, 200.f ) );
+
+  //Ensure set on stage.
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 1u, TEST_LOCATION );
+
+  //Tell test application to load the visual.
+  application.SendNotification();
+  application.Render(0);
+
+  Matrix testScaleMatrix;
+  testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+  Matrix actualScaleMatrix;
+
+  //Test to see if the object has been successfully loaded.
+  DALI_TEST_CHECK( application.GetGlAbstraction().GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+  DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  //Finish by setting off stage, and ensuring this was successful.
+  actor.Unparent();
+  DALI_TEST_EQUALS( actor.GetRendererCount(), 0u, TEST_LOCATION );
+}
+
+//Test if primitive shape loads correctly when supplied with only the bare minimum requirements, the shape to use.
+int UtcDaliVisualFactoryGetPrimitiveVisual1(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual1:  Request primitive visual with a shape only" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CUBE );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when supplied with all possible parameters
+int UtcDaliVisualFactoryGetPrimitiveVisual2(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual2:  Request primitive visual with everything" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CUBE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::STACKS, 20 );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_TOP_RADIUS, 30.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, 40.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_HEIGHT, 50.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_RADIUS, 60.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_PERCENTAGE, 0.7f );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_SMOOTHNESS, 0.8f );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, Vector3( 0.9, 1.0, 1.1 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads a sphere correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual3(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual3:  Request primitive visual to display a sphere" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::STACKS, 20 );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads a conic section correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual4(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual4:  Request primitive visual to display a conic section" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CONICAL_FRUSTRUM );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_TOP_RADIUS, 30.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, 40.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_HEIGHT, 50.0f );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads a bevelled cube correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual5(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual5:  Request primitive visual to display a bevelled cube" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::BEVELLED_CUBE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_PERCENTAGE, 0.7f );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads an octahedron correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual6(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual6:  Request primitive visual to display an octahedron" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::OCTAHEDRON );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads a cone correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual7(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual7:  Request primitive visual to display a cone" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CONE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_TOP_RADIUS, 30.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_HEIGHT, 50.0f );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when light position is manually set.
+int UtcDaliVisualFactoryGetPrimitiveVisual8(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual8:  Request primitive visual with set light position" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( MeshVisual::Property::LIGHT_POSITION, Vector3( 0.0, 1.0, 2.0 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too many slices.
+int UtcDaliVisualFactoryGetPrimitiveVisual9(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual9:  Request primitive visual with above-cap slices." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, Property::Value( 1000000 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too few slices. (2 slices or less.)
+int UtcDaliVisualFactoryGetPrimitiveVisual10(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual10:  Request primitive visual with too few slices." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, Property::Value( 2 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too many stacks.
+int UtcDaliVisualFactoryGetPrimitiveVisual11(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual11:  Request primitive visual with too many stacks." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::STACKS, Property::Value( 1000000 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too few stacks. (1 stack or less.)
+int UtcDaliVisualFactoryGetPrimitiveVisual12(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual12:  Request primitive visual with too few stacks." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::STACKS, Property::Value( 1 ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use invalid (zero or negative) dimensions.
+int UtcDaliVisualFactoryGetPrimitiveVisual13(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual13:  Request primitive visual with invalid scale dimensions." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_DIMENSIONS, Vector3::ZERO );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too low a bevel percentage.
+int UtcDaliVisualFactoryGetPrimitiveVisual14(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual14:  Request primitive visual with too low a bevel percentage." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_PERCENTAGE, Property::Value( -1.0f ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too high a bevel percentage.
+int UtcDaliVisualFactoryGetPrimitiveVisual15(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual15:  Request primitive visual with too high a bevel percentage." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_PERCENTAGE, Property::Value( 2.0f ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too low a bevel smoothness.
+int UtcDaliVisualFactoryGetPrimitiveVisual16(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual16:  Request primitive visual with too low a bevel smoothness." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_SMOOTHNESS, Property::Value( -1.0f ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads correctly when told to use too high a bevel smoothness.
+int UtcDaliVisualFactoryGetPrimitiveVisual17(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual17:  Request primitive visual with too high a bevel smoothness." );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::SPHERE );
+  propertyMap.Insert( PrimitiveVisual::Property::BEVEL_SMOOTHNESS, Property::Value( 2.0f ) );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape loads a conic section correctly.
+int UtcDaliVisualFactoryGetPrimitiveVisual18(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisual18:  Request primitive visual to display a conic section" );
+
+  //Set up visual properties.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+  propertyMap.Insert( PrimitiveVisual::Property::SHAPE, PrimitiveVisual::Shape::CONICAL_FRUSTUM );
+  propertyMap.Insert( PrimitiveVisual::Property::MIX_COLOR, Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+  propertyMap.Insert( PrimitiveVisual::Property::SLICES, 10 );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_TOP_RADIUS, 30.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, 40.0f );
+  propertyMap.Insert( PrimitiveVisual::Property::SCALE_HEIGHT, 50.0f );
+
+  //Test to see if shape loads correctly.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+//Test if primitive shape visual handles the case of not being passed a specific shape to use.
+int UtcDaliVisualFactoryGetPrimitiveVisualN1(void)
+{
+  //Set up test application first, so everything else can be handled.
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliVisualFactoryGetPrimitiveVisualN1:  Request primitive visual without shape" );
+
+  //Set up visual properties, without supplying shape.
+  Property::Map propertyMap;
+  propertyMap.Insert( Toolkit::Visual::Property::TYPE, Visual::PRIMITIVE );
+
+  //Test to see if shape loads regardless of missing input.
+  TestPrimitiveVisualWithProperties( propertyMap, application );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual1: Request animated image visual with a gif url" );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  // renderer is added to actor
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // Force the timer used by the animatedImageVisual to tick,
+  Dali::Timer timer = Timer::New( 0 );
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+
+  // Force the timer used by the animatedImageVisual to tick,
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // Force the timer used by the animatedImageVisual to tick,
+  timer.MockEmitSignal();
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
+  // Test SetOffStage().
+  actor.Unparent();
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
+
+int UtcDaliVisualFactoryGetAnimatedImageVisual2(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual2: Request animated image visual with a Property::Map, test custom wrap mode and pixel area" );
+
+  const Vector4 pixelArea(-0.5f, -0.5f, 2.f, 2.f);
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE,  Visual::IMAGE  )
+             .Add( ImageVisual::Property::URL, TEST_GIF_FILE_NAME  )
+             .Add( ImageVisual::Property::PIXEL_AREA, pixelArea )
+             .Add( ImageVisual::Property::WRAP_MODE_U, WrapMode::MIRRORED_REPEAT )
+             .Add( ImageVisual::Property::WRAP_MODE_V, WrapMode::REPEAT );
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+  DALI_TEST_CHECK( visual );
+
+  TestGlAbstraction& gl = application.GetGlAbstraction();
+  TraceCallStack& textureTrace = gl.GetTextureTrace();
+  textureTrace.Enable(true);
+  TraceCallStack& texParameterTrace = gl.GetTexParameterTrace();
+  texParameterTrace.Enable( true );
+
+  DummyControl actor = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual( Control::CONTROL_PROPERTY_END_INDEX + 1, visual );
+  actor.SetSize( 200.0f, 200.0f );
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+
+  // For animated image visual, the wrapping is handled manually in shader, so the following gl function should not be called
+  std::stringstream out;
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_S << ", " << GL_MIRRORED_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+  out.str("");
+  out << GL_TEXTURE_2D << ", " << GL_TEXTURE_WRAP_T << ", " << GL_REPEAT;
+  DALI_TEST_CHECK( !texParameterTrace.FindMethodAndParams("TexParameteri", out.str()) );
+
+  // test the uniforms which used to handle the wrap mode
+  Renderer renderer = actor.GetRendererAt( 0u );
+  DALI_TEST_CHECK( renderer );
+
+  Property::Value pixelAreaValue = renderer.GetProperty( renderer.GetPropertyIndex( "pixelArea" ) );
+  DALI_TEST_EQUALS( pixelAreaValue.Get<Vector4>(), pixelArea, TEST_LOCATION );
+  Vector4 pixelAreaUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector4>( "pixelArea", pixelAreaUniform ) );
+  DALI_TEST_EQUALS( pixelArea, pixelAreaUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  Property::Value wrapModeValue = renderer.GetProperty( renderer.GetPropertyIndex( "wrapMode" ) );
+  Vector2 wrapMode( WrapMode::MIRRORED_REPEAT-1, WrapMode::REPEAT-1 );
+  DALI_TEST_EQUALS( wrapModeValue.Get<Vector2>(), wrapMode, TEST_LOCATION );
+  Vector2 wrapModeUniform;
+  DALI_TEST_CHECK( gl.GetUniformValue<Vector2>( "wrapMode", wrapModeUniform ) );
+  DALI_TEST_EQUALS( wrapMode, wrapModeUniform, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+  actor.Unparent( );
+  DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-WebView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-WebView.cpp
new file mode 100644 (file)
index 0000000..bb9e279
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2018 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-test-utils/toolkit-timer.h"
+
+#include <dali.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+#include <dali-toolkit/devel-api/controls/web-view/web-view.h>
+
+
+using namespace Dali;
+using namespace Toolkit;
+
+namespace
+{
+
+const char* const TEST_URL1( "http://www.somewhere.valid1.com" );
+const char* const TEST_URL2( "http://www.somewhere.valid2.com" );
+
+static int gPageLoadStartedCallbackCalled = 0;
+static int gPageLoadFinishedCallbackCalled = 0;
+static int gEvaluateJavaScriptCallbackCalled = 0;
+static bool gTouched = false;
+
+struct CallbackFunctor
+{
+  CallbackFunctor(bool* callbackFlag)
+  : mCallbackFlag( callbackFlag )
+  {
+  }
+
+  void operator()()
+  {
+    *mCallbackFlag = true;
+  }
+  bool* mCallbackFlag;
+};
+
+static void OnPageLoadStarted( WebView view, const std::string& url )
+{
+  gPageLoadStartedCallbackCalled++;
+}
+
+static void OnPageLoadFinished( WebView view, const std::string& url )
+{
+  gPageLoadFinishedCallbackCalled++;
+}
+
+static void OnPageLoadError( WebView view, const std::string& url, WebView::LoadErrorCode errorCode )
+{
+}
+
+static void OnEvaluateJavaScript( const std::string& result )
+{
+  gEvaluateJavaScriptCallbackCalled++;
+}
+
+static bool OnTouched( Actor actor, const Dali::TouchData& touch )
+{
+  gTouched = true;
+  return true;
+}
+
+} // namespace
+
+void web_view_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void web_view_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliWebViewBasics(void)
+{
+  ToolkitTestApplication application;
+
+  // Copy and Assignment Test
+  tet_infoline( "UtcDaliWebViewBasic Copy and Assignment Test" );
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  WebView copy( view );
+  DALI_TEST_CHECK( view == copy );
+
+  WebView assign;
+  DALI_TEST_CHECK( !assign );
+
+  assign = copy;
+  DALI_TEST_CHECK( assign == view );
+
+
+  // DownCast Test
+  tet_infoline( "UtcDaliWebViewBasic DownCast Test" );
+  BaseHandle handle(view);
+
+  WebView view2 = WebView::DownCast( handle );
+  DALI_TEST_CHECK( view );
+  DALI_TEST_CHECK( view2 );
+  DALI_TEST_CHECK( view == view2 );
+
+
+  // TypeRegistry Test
+  tet_infoline( "UtcDaliWebViewBasic TypeRegistry Test" );
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK( typeRegistry );
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo( "WebView" );
+  DALI_TEST_CHECK( typeInfo );
+
+  BaseHandle handle2 = typeInfo.CreateInstance();
+  DALI_TEST_CHECK( handle2 );
+
+  WebView view3 = WebView::DownCast( handle2 );
+  DALI_TEST_CHECK( view3 );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewPageNavigation(void)
+{
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  view.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  view.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  view.SetPosition( 0, 0 );
+  view.SetSize( 800, 600 );
+  Stage::GetCurrent().Add( view );
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_CHECK( view );
+
+  ConnectionTracker* testTracker = new ConnectionTracker();
+  view.PageLoadStartedSignal().Connect( &OnPageLoadStarted );
+  view.PageLoadFinishedSignal().Connect( &OnPageLoadFinished );
+  view.PageLoadErrorSignal().Connect( &OnPageLoadError );
+  bool signal1 = false;
+  bool signal2 = false;
+  bool signal3 = false;
+  view.ConnectSignal( testTracker, "pageLoadStarted", CallbackFunctor(&signal1) );
+  view.ConnectSignal( testTracker, "pageLoadFinished", CallbackFunctor(&signal2) );
+  view.ConnectSignal( testTracker, "invalidname", CallbackFunctor(&signal3) );
+  DALI_TEST_EQUALS( gPageLoadStartedCallbackCalled, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( gPageLoadFinishedCallbackCalled, 0, TEST_LOCATION );
+
+
+  view.LoadUrl( TEST_URL1 );
+  view.GetNaturalSize();
+  Test::EmitGlobalTimerSignal();
+  DALI_TEST_EQUALS( view.CanGoBack(), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gPageLoadStartedCallbackCalled, 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( gPageLoadFinishedCallbackCalled, 1, TEST_LOCATION );
+  DALI_TEST_CHECK( signal1 & signal2 );
+  DALI_TEST_CHECK( !signal3 );
+
+  view.LoadUrl( TEST_URL2 );
+  view.Suspend();
+  view.SetSize( 400, 300 );
+  application.SendNotification();
+  application.Render();
+  Test::EmitGlobalTimerSignal();
+  view.Resume();
+  DALI_TEST_EQUALS( view.CanGoBack(), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( view.CanGoForward(), false, TEST_LOCATION );
+  DALI_TEST_EQUALS( gPageLoadStartedCallbackCalled, 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( gPageLoadFinishedCallbackCalled, 2, TEST_LOCATION );
+
+  view.GoBack();
+  Test::EmitGlobalTimerSignal();
+  DALI_TEST_CHECK( !view.CanGoBack() );
+  DALI_TEST_CHECK( view.CanGoForward() );
+
+  view.GoForward();
+  Test::EmitGlobalTimerSignal();
+  DALI_TEST_CHECK( view.CanGoBack() );
+  DALI_TEST_CHECK( !view.CanGoForward() );
+
+  view.Reload();
+  view.StopLoading();
+  view.ClearHistory();
+  view.ClearCache();
+  view.ClearCookies();
+  Test::EmitGlobalTimerSignal();
+  DALI_TEST_CHECK( !view.CanGoBack() );
+  DALI_TEST_CHECK( !view.CanGoForward() );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewTouchAndKeys(void)
+{
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  view.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  view.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  view.SetPosition( 0, 0 );
+  view.SetSize( 800, 600 );
+
+  Stage::GetCurrent().Add( view );
+  application.SendNotification();
+  application.Render();
+
+  view.GetNaturalSize();
+  view.TouchSignal().Connect( &OnTouched );
+
+  // Touch event
+  Dali::Integration::TouchEvent event;
+  Dali::Integration::Point pointDown, pointUp;
+
+  event = Dali::Integration::TouchEvent();
+  pointDown.SetState( PointState::DOWN );
+  pointDown.SetScreenPosition( Vector2( 10, 10 ) );
+  event.AddPoint( pointDown );
+  application.ProcessEvent( event );
+
+  event = Dali::Integration::TouchEvent();
+  pointUp.SetState( PointState::UP );
+  pointUp.SetScreenPosition( Vector2( 10, 10 ) );
+  event.AddPoint( pointUp );
+  application.ProcessEvent( event );
+
+  // Key event
+  Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( view );
+  application.ProcessEvent( Integration::KeyEvent( "", "", "", DALI_KEY_ESCAPE, 0, 0, Integration::KeyEvent::Down, "", "", Device::Class::NONE, Device::Subclass::NONE ) );
+  application.SendNotification();
+
+  DALI_TEST_CHECK( gTouched );
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty1(void)
+{
+  // URL
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  std::string local;
+  view.SetProperty( WebView::Property::URL, TEST_URL1 );
+  Property::Value val = view.GetProperty( WebView::Property::URL );
+  DALI_TEST_CHECK( val.Get( local ) );
+  DALI_TEST_EQUALS( local, TEST_URL1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty2(void)
+{
+  // CACHE_MODEL
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const std::string kDefaultValue = "DOCUMENT_VIEWER";
+  const WebView::CacheModel::Type kTestEnum = WebView::CacheModel::PRIMARY_WEB_BROWSER;
+  const std::string kTestValue = "PRIMARY_WEB_BROWSER";
+
+  // Check default value
+  std::string output;
+  Property::Value value = view.GetProperty( WebView::Property::CACHE_MODEL );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::CACHE_MODEL, kTestEnum );
+  value = view.GetProperty( WebView::Property::CACHE_MODEL );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  view.SetProperty( WebView::Property::CACHE_MODEL, kTestValue );
+  value = view.GetProperty( WebView::Property::CACHE_MODEL );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty3(void)
+{
+  // COOKIE_ACCEPT_POLICY
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const std::string kDefaultValue = "NO_THIRD_PARTY";
+  const WebView::CookieAcceptPolicy::Type kTestEnum = WebView::CookieAcceptPolicy::NEVER;
+  const std::string kTestValue = "NEVER";
+
+  // Check default value
+  std::string output;
+  Property::Value value = view.GetProperty( WebView::Property::COOKIE_ACCEPT_POLICY );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::COOKIE_ACCEPT_POLICY, kTestEnum );
+  value = view.GetProperty( WebView::Property::COOKIE_ACCEPT_POLICY );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  view.SetProperty( WebView::Property::COOKIE_ACCEPT_POLICY, kTestValue );
+  value = view.GetProperty( WebView::Property::COOKIE_ACCEPT_POLICY );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty4(void)
+{
+  // USER_AGENT
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const std::string kDefaultValue;
+  const std::string kTestValue = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36";
+
+  // Check default value
+  std::string output;
+  Property::Value value = view.GetProperty( WebView::Property::USER_AGENT );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::USER_AGENT, kTestValue );
+  value = view.GetProperty( WebView::Property::USER_AGENT );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty5(void)
+{
+  // ENABLE_JAVASCRIPT
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const bool kDefaultValue = true;
+  const bool kTestValue = false;
+
+  // Check default value
+  bool output;
+  Property::Value value = view.GetProperty( WebView::Property::ENABLE_JAVASCRIPT );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::ENABLE_JAVASCRIPT, kTestValue );
+  value = view.GetProperty( WebView::Property::ENABLE_JAVASCRIPT );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty6(void)
+{
+  // LOAD_IMAGES_AUTOMATICALLY
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const bool kDefaultValue = true;
+  const bool kTestValue = false;
+
+  // Check default value
+  bool output;
+  Property::Value value = view.GetProperty( WebView::Property::LOAD_IMAGES_AUTOMATICALLY );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::LOAD_IMAGES_AUTOMATICALLY, kTestValue );
+  value = view.GetProperty( WebView::Property::LOAD_IMAGES_AUTOMATICALLY );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty7(void)
+{
+  // DEFAULT_TEXT_ENCODING_NAME
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const std::string kDefaultValue;
+  const std::string kTestValue = "UTF-8";
+
+  // Check default value
+  std::string output;
+  Property::Value value = view.GetProperty( WebView::Property::DEFAULT_TEXT_ENCODING_NAME );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::DEFAULT_TEXT_ENCODING_NAME, kTestValue );
+  value = view.GetProperty( WebView::Property::DEFAULT_TEXT_ENCODING_NAME );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewProperty8(void)
+{
+  // DEFAULT_FONT_SIZE
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New();
+  DALI_TEST_CHECK( view );
+
+  const int kDefaultValue = 16;
+  const int kTestValue = 26;
+
+  // Check default value
+  int output;
+  Property::Value value = view.GetProperty( WebView::Property::DEFAULT_FONT_SIZE );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kDefaultValue, TEST_LOCATION );
+
+  // Check Set/GetProperty
+  view.SetProperty( WebView::Property::DEFAULT_FONT_SIZE, kTestValue );
+  value = view.GetProperty( WebView::Property::DEFAULT_FONT_SIZE );
+  DALI_TEST_CHECK( value.Get( output ) );
+  DALI_TEST_EQUALS( output, kTestValue, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliWebViewEvaluteJavaScript(void)
+{
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New( "ko-KR", "Asia/Seoul" );
+
+  view.LoadHTMLString( "<body>Hello World!</body>" );
+  view.EvaluateJavaScript( "jsObject.postMessage('Hello')" );
+  view.EvaluateJavaScript( "jsObject.postMessage('World')", OnEvaluateJavaScript );
+  Test::EmitGlobalTimerSignal();
+
+  DALI_TEST_EQUALS( gEvaluateJavaScriptCallbackCalled, 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliWebViewMethodsForCoverage(void)
+{
+  ToolkitTestApplication application;
+
+  WebView view = WebView::New( "ko-KR", "Asia/Seoul" );
+
+  view.LoadHTMLString( "<body>Hello World!</body>" );
+  view.AddJavaScriptMessageHandler( "jsObject",
+    []( const std::string& arg ) {
+    }
+  );
+
+  DALI_TEST_CHECK( view );
+
+  END_TEST;
+}
diff --git a/automated-tests/tcbuild b/automated-tests/tcbuild
new file mode 120000 (symlink)
index 0000000..89c2de7
--- /dev/null
@@ -0,0 +1 @@
+scripts/tcbuild.sh
\ No newline at end of file
diff --git a/automated-tests/templates/tct-package/README b/automated-tests/templates/tct-package/README
new file mode 100644 (file)
index 0000000..0af341f
--- /dev/null
@@ -0,0 +1,43 @@
+The scripts contained in the automated-tests/scripts folder are based on
+the Web Application Security & Privacy module test suite from Intel,
+with the following license:
+
+----------------------------------------------
+License
+----------------------------------------------
+Copyright (c) 2012 Intel Corporation.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of works must retain the original copyright notice, this list
+  of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the original copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors
+  may be used to endorse or promote products derived from this work without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Authors:
+        Yue, Jianhui <jianhuix.a.yue@intel.com>
+
+Modifications to scripts:
+Added mechanism to build and execute tests with finer granularity.
+Added option to generate tests for executing on desktop
+
+Copyright (c) 2014 Samsung Electronics Co., Ltd.
+
+Authors:
+        Steele, David <david.steele@partner.samsung.com>
diff --git a/automated-tests/templates/tct-package/inst.sh b/automated-tests/templates/tct-package/inst.sh
new file mode 100755 (executable)
index 0000000..c2888df
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+NAME=$(basename $(cd $(dirname $0);pwd))
+PKG_DIR=%{PKG_DIR} # directory supplied by external script
+PKG_NAME=%{PKG_NAME} # name supplied by external script
+PKG_FULLNAME=%{PKG_FULLNAME} # name supplied by external script
+
+#parse params
+USAGE="Usage: ./inst.sh [-i] [-u]
+  -i install wgt and config environment
+  -u uninstall wgt and remove source file
+[-i] option was set as default."
+
+function installpkg(){
+    rpm -e `rpm -qa | grep $PKG_NAME`
+    rpm -ivh --quiet /$PKG_DIR/$PKG_FULLNAME
+    /tmp/add_all_smack_rule.sh
+}
+
+function uninstallpkg(){
+### remove source file ###
+if [ -d /opt/usr/media/tct/opt/$NAME ];then
+    rm -rf /opt/usr/media/tct/opt/$NAME
+    rpm -e $PKG_NAME
+else
+    echo "Remove source file fail, please check if the source file exist: /opt/usr/media/tct/opt/$NAME ..."
+fi
+}
+
+case "$1" in
+    -h|--help) echo "$USAGE"
+               exit ;;
+    ""|-i) installpkg;;
+    -u) uninstallpkg;;
+    *) echo "Unknown option: $1"
+       echo "$USAGE"
+       exit ;;
+esac
diff --git a/build/tizen/CMakeLists.txt b/build/tizen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..25edb06
--- /dev/null
@@ -0,0 +1,540 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+CMAKE_POLICY(SET CMP0012 NEW) # Prevent dereferencing of OFF/ON as variables
+
+SET(name "dali-toolkit")
+
+PROJECT(${name})
+SET(PKG_NAME ${name})
+
+SET(GCC_COMPILER_VERSION_REQUIRED "6")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS GCC_COMPILER_VERSION_REQUIRED)
+    message(FATAL_ERROR "The GCC required compiler version is " ${GCC_COMPILER_VERSION_REQUIRED})
+  endif()
+endif()
+
+# API VERSION (Not DALi release version)
+SET(${name}_VERSION_MAJOR 0)
+SET(${name}_VERSION_MINOR 0)
+SET(${name}_VERSION_PATCH 0)
+SET(${name}_VERSION ${${name}_VERSION_MAJOR}.${${name}_VERSION_MINOR}.${${name}_VERSION_PATCH} )
+
+SET(DALI_TOOLKIT_VERSION ${${name}_VERSION} )
+
+# Define options to CMake
+OPTION(ENABLE_EXPORTALL          "Enable Export all symbols" OFF)
+OPTION(ENABLE_DEBUG              "Enable Debug" OFF)
+OPTION(ENABLE_TRACE              "Enable Trace" OFF)
+OPTION(ENABLE_I18N               "Turns on internationalisation" OFF)
+OPTION(ENABLE_COVERAGE           "Coverage" OFF)
+OPTION(ENABLE_PKG_CONFIGURE      "Use pkgconfig" ON)
+OPTION(ENABLE_LINK_TEST          "Enable the link test" ON)
+OPTION(INSTALL_DOXYGEN_DOC       "Install doxygen doc" ON)
+OPTION(CONFIGURE_AUTOMATED_TESTS "Configure automated tests" ON)
+OPTION(USE_DEFAULT_RESOURCE_DIR  "Whether to use the default resource folders. Otherwise set environment variables for DALI_IMAGE_DIR, DALI_SOUND_DIR, DALI_STYLE_DIR, DALI_STYLE_IMAGE_DIR and DALI_DATA_READ_ONLY_DIR" ON)
+
+IF( ENABLE_PKG_CONFIGURE )
+  FIND_PACKAGE( PkgConfig REQUIRED )
+
+  PKG_CHECK_MODULES(DALICORE REQUIRED dali-core)
+  PKG_CHECK_MODULES(DALIADAPTOR REQUIRED dali-adaptor)
+ENDIF()
+
+IF( INSTALL_DOXYGEN_DOC )
+  FIND_PACKAGE( Doxygen QUIET )
+ENDIF()
+
+IF( WIN32 ) # WIN32 includes x64 as well according to the cmake doc.
+  FIND_PACKAGE( dali-windows-dependencies REQUIRED)
+  FIND_PACKAGE( dali-core REQUIRED)
+  FIND_PACKAGE( dali-adaptor REQUIRED)
+ENDIF()
+
+SET( VCPKG_INCLUDE_DIR "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
+
+# Define non-boolean options to CMake
+SET(WITH_STYLE               "480x800" CACHE STRING "Select the style folder to use")
+
+# from root/build/tizen, get back to root
+SET(ROOT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../)
+
+# Deployment folder should come from spec file or command line:
+SET( PREFIX ${CMAKE_INSTALL_PREFIX})
+SET( EXEC_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+# Make sure the path is absolute
+GET_FILENAME_COMPONENT(ROOT_SRC_DIR ${ROOT_SRC_DIR} ABSOLUTE)
+
+# Set DALi style
+SET( dali_style ${WITH_STYLE} )
+
+# Style folder
+SET( STYLE_BASE_DIR ${ROOT_SRC_DIR}/dali-toolkit/styles )
+SET( STYLE_DIR ${STYLE_BASE_DIR}/${dali_style} )
+
+SET( toolkit_styles_base_dir ${STYLE_BASE_DIR} )
+SET( toolkit_styles_dir ${STYLE_DIR} )
+SET( toolkit_style_images_dir ${STYLE_DIR}/images )
+
+IF( DEFINED ENV{DALI_DATA_RW_DIR} )
+  SET( dataReadWriteDir $ENV{DALI_DATA_RW_DIR} )
+ELSE()
+  SET( dataReadWriteDir ${CMAKE_INSTALL_PREFIX}/share/dali/ )
+ENDIF()
+
+IF( DEFINED ENV{DALI_DATA_RO_DIR} )
+  SET( dataReadOnlyDir $ENV{DALI_DATA_RO_DIR} )
+ELSE()
+  SET( dataReadOnlyDir ${CMAKE_INSTALL_PREFIX}/share/dali/ )
+ENDIF()
+
+# Set up compiler definitions
+
+IF(CMAKE_BUILD_TYPE MATCHES Debug)
+  SET( ENABLE_DEBUG ON )
+ENDIF()
+
+IF( ENABLE_DEBUG )
+  MESSAGE( STATUS "CMAKE_BUILD_TYPE: " Debug )
+  ADD_DEFINITIONS( "-DDEBUG_ENABLED" )
+  SET( ENABLE_EXPORTALL ON )
+ELSE()
+  MESSAGE( STATUS "CMAKE_BUILD_TYPE: " Release )
+ENDIF()
+
+IF( ENABLE_I18N )
+  ADD_DEFINITIONS( "-DDGETTEXT_ENABLED" )
+ENDIF( ENABLE_I18N )
+
+IF( WIN32 )
+  ADD_DEFINITIONS( "-DBUILDING_DALI_TOOLKIT" )
+
+  IF( USE_DEFAULT_RESOURCE_DIR )
+    SET( INSTALL_SHARE_DIR "${PREFIX}/share" )
+    IF( VCPKG_TOOLKIT_BUILD )
+      SET( INSTALL_SHARE_DIR "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share" )
+    ENDIF()
+
+    ADD_DEFINITIONS( -DDALI_IMAGE_DIR=\"${INSTALL_SHARE_DIR}/dali/toolkit/images/\"
+                     -DDALI_SOUND_DIR=\"${INSTALL_SHARE_DIR}/dali/toolkit/sounds/\"
+                     -DDALI_STYLE_DIR=\"${INSTALL_SHARE_DIR}/dali/toolkit/styles/\"
+                     -DDALI_STYLE_IMAGE_DIR=\"${INSTALL_SHARE_DIR}/dali/toolkit/styles/images/\"
+                     -DDALI_DATA_READ_ONLY_DIR=\"${INSTALL_SHARE_DIR}/\" )
+  ENDIF()
+ELSEIF( UNIX )
+  ADD_DEFINITIONS(-DPIC -DSTDC_HEADERS)
+  IF( USE_DEFAULT_RESOURCE_DIR )
+    ADD_DEFINITIONS( -DDALI_IMAGE_DIR=\"${dataReadOnlyDir}/toolkit/images/\"
+                     -DDALI_SOUND_DIR=\"${dataReadOnlyDir}/toolkit/sounds/\"
+                     -DDALI_STYLE_DIR=\"${dataReadOnlyDir}/toolkit/styles/\"
+                     -DDALI_STYLE_IMAGE_DIR=\"${dataReadOnlyDir}/toolkit/styles/images/\"
+                     -DDALI_DATA_READ_ONLY_DIR=\"${dataReadOnlyDir}\" )
+  ENDIF()
+
+  IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+  ENDIF("${ARCH}" STREQUAL "arm")
+
+  IF( NOT ${ENABLE_EXPORTALL} )
+    ADD_DEFINITIONS( "-DHIDE_DALI_INTERNALS" )
+  ENDIF( NOT ${ENABLE_EXPORTALL} )
+ENDIF()
+
+IF( NOT USE_DEFAULT_RESOURCE_DIR )
+  ADD_DEFINITIONS( -DDALI_IMAGE_DIR=0
+                   -DDALI_SOUND_DIR=0
+                   -DDALI_STYLE_DIR=0
+                   -DDALI_STYLE_IMAGE_DIR=0
+                   -DDALI_DATA_READ_ONLY_DIR=0 )
+ENDIF()
+
+IF( ENABLE_TRACE )
+  ADD_DEFINITIONS("-DTRACE_ENABLED")
+ENDIF()
+
+# Platforms with highp shader support can use vector based text
+IF( "${PROFILE}" STREQUAL "UBUNTU" )
+  SET( ENABLE_VECTOR_BASED_TEXT_RENDERING 1 )
+ENDIF()
+
+# Set paths
+SET( toolkit_images_dir  ${ROOT_SRC_DIR}/dali-toolkit/styles/images-common )
+SET( toolkit_sounds_dir  ${ROOT_SRC_DIR}/dali-toolkit/sounds )
+SET( toolkit_src_dir     ${ROOT_SRC_DIR}/dali-toolkit/internal )
+SET( public_api_src_dir  ${ROOT_SRC_DIR}/dali-toolkit/public-api )
+SET( devel_api_src_dir   ${ROOT_SRC_DIR}/dali-toolkit/devel-api )
+SET( third_party_src_dir ${ROOT_SRC_DIR}/dali-toolkit/third-party )
+SET( package_doxy_dir    ${ROOT_SRC_DIR}/doc )
+
+# Set up the include dir
+SET( INCLUDE_DIR $ENV{includedir} )
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} )
+ENDIF()
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${PREFIX}/include )
+ENDIF()
+
+# Set up the lib dir
+SET( LIB_DIR $ENV{libdir} )
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${CMAKE_INSTALL_LIBDIR} )
+ENDIF()
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${PREFIX}/lib )
+ENDIF()
+
+# Set up the bin dir
+SET( BIN_DIR $ENV{bindir} )
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${CMAKE_INSTALL_BINDIR} )
+ENDIF()
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${PREFIX}/bin )
+ENDIF()
+
+IF( ENABLE_PKG_CONFIGURE )
+  # Configure the pkg-config file
+  # Requires the following variables to be setup:
+  # @PREFIX@ @EXEC_PREFIX@ @DALI_VERSION@ @LIB_DIR@ @DEV_INCLUDE_PATH@
+  SET( DEV_INCLUDE_PATH ${INCLUDE_DIR} )
+  SET( CORE_PKG_CFG_FILE dali-toolkit.pc )
+  CONFIGURE_FILE( ${CORE_PKG_CFG_FILE}.in ${CORE_PKG_CFG_FILE} @ONLY )
+ENDIF()
+
+IF( WIN32 )
+  ADD_COMPILE_OPTIONS( /FIdali-windows-dependencies.h ) # Adds missing definitions.
+  ADD_COMPILE_OPTIONS( /vmg )                           # Avoids a 'reinterpret_cast' compile error while compiling signals and callbacks.
+  ADD_COMPILE_OPTIONS( /wd4251 )                        # Ignores warning C4251: "'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'"
+ELSE()
+  # Set up compiler flags and warnings
+  ADD_COMPILE_OPTIONS( -std=c++11 )
+  ADD_COMPILE_OPTIONS( -Wno-ignored-qualifiers )
+
+  # TODO: Clang is a lot more strict with warnings, we should address
+  # those issues at some point.
+  IF( NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
+    ADD_COMPILE_OPTIONS( -Werror )
+  ENDIF()
+
+  ADD_COMPILE_OPTIONS( -Wall -Wno-unused-parameter -Wno-float-equal -Wno-class-memaccess )
+
+  IF( ENABLE_COVERAGE OR "$ENV{CXXFLAGS}" MATCHES --coverage )
+    ADD_COMPILE_OPTIONS( --coverage )
+    SET(ENABLE_COVERAGE ON)
+    SET(COVERAGE --coverage)
+  ENDIF()
+
+  IF( NOT ${ENABLE_EXPORTALL} )
+    ADD_COMPILE_OPTIONS( "-fvisibility=hidden" )
+  ENDIF( NOT ${ENABLE_EXPORTALL} )
+ENDIF()
+
+
+INCLUDE_DIRECTORIES(
+  ${ROOT_SRC_DIR}
+  ${DALICORE_INCLUDE_DIRS}
+  ${DALIADAPTOR_INCLUDE_DIRS}
+  ${VCPKG_INCLUDE_DIR}
+  ${INCLUDE_DIR}
+)
+
+SET(SOURCE_DIR "${ROOT_SRC_DIR}/dali")
+SET(PACKAGE_DOXY_SRC_DIR "${ROOT_SRC_DIR}/doc")
+
+SET(SOURCES "")
+
+# could use INCLUDE to get the source lists a different way;
+# would then need to specify a build folder somehow...
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/sounds/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/styles/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/styles/images-common/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/internal/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/public-api/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/devel-api/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/dali-toolkit/third-party/file.list )
+INCLUDE( ${ROOT_SRC_DIR}/doc/file.list )
+
+SET(LIBTYPE SHARED)
+IF(DEFINED STATIC)
+  SET(LIBTYPE STATIC)
+ENDIF()
+
+IF( WIN32 )
+  SET( DALICORE_LDFLAGS
+        "${DALICORE_LDFLAGS}"
+        dali-core::dali-core )
+
+  FIND_PACKAGE( pthreads REQUIRED )
+  FIND_PACKAGE( curl REQUIRED )
+  FIND_LIBRARY( GETOPT_LIBRARY NAMES getopt )
+  FIND_LIBRARY( EXIF_LIBRARY NAMES libexif )
+
+  FIND_PACKAGE( png REQUIRED )
+  FIND_PACKAGE( gif REQUIRED )
+  FIND_PACKAGE( jpeg REQUIRED )
+  FIND_LIBRARY( TURBO_JPEG_LIBRARY NAMES turbojpeg )
+
+  FIND_PACKAGE( unofficial-fontconfig REQUIRED )
+  FIND_PACKAGE( freetype REQUIRED )
+  FIND_PACKAGE( harfbuzz REQUIRED )
+  FIND_LIBRARY( FRIBIDI_LIBRARY NAMES fribidi )
+
+  FIND_PACKAGE( unofficial-angle REQUIRED )
+  FIND_PACKAGE( unofficial-cairo REQUIRED )
+
+  SET( DALIADAPTOR_LDFLAGS
+       "${DALIADAPTOR_LDFLAGS}"
+       dali-adaptor::dali-adaptor )
+ENDIF()
+
+
+ADD_LIBRARY( ${name} ${LIBTYPE} ${SOURCES} )
+TARGET_LINK_LIBRARIES( ${name}
+  ${DALICORE_LDFLAGS}
+  ${DALIADAPTOR_LDFLAGS}
+  ${COVERAGE}
+)
+
+IF( ANDROID )
+  TARGET_LINK_LIBRARIES( ${name} log )
+ENDIF()
+
+SET_TARGET_PROPERTIES( ${name}
+  PROPERTIES
+  VERSION ${DALI_TOOLKIT_VERSION}
+  SOVERSION ${${name}_VERSION_MAJOR}
+  CLEAN_DIRECT_OUPUT 1
+)
+
+IF( INSTALL_CMAKE_MODULES )
+  IF( ENABLE_DEBUG )
+    SET( BIN_DIR "${BIN_DIR}/debug" )
+    SET( LIB_DIR "${LIB_DIR}/debug" )
+  ENDIF()
+
+  # Install the library files.
+  INSTALL( TARGETS ${name}
+    EXPORT ${name}-targets
+    LIBRARY DESTINATION ${LIB_DIR}
+    ARCHIVE DESTINATION ${LIB_DIR}
+    RUNTIME DESTINATION ${BIN_DIR}
+  )
+
+  # Install the cmake modules.
+  INSTALL(
+    EXPORT ${name}-targets
+    NAMESPACE ${name}::
+    FILE ${name}-targets.cmake
+    DESTINATION share/${name}
+  )
+
+  FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake "
+    include(CMakeFindDependencyMacro)
+    include(\${CMAKE_CURRENT_LIST_DIR}/${name}-targets.cmake)
+  ")
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake DESTINATION share/${name})
+
+  # Install the pdb file.
+  IF( ENABLE_DEBUG )
+    install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.pdb DESTINATION ${BIN_DIR} )
+  ENDIF()
+ELSE()
+  # Install the library so file and symlinks
+  INSTALL( TARGETS ${name} DESTINATION ${LIB_DIR} )
+ENDIF()
+
+# Install the pkg-config file
+IF( ENABLE_PKG_CONFIGURE )
+  INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/${CORE_PKG_CFG_FILE} DESTINATION ${LIB_DIR}/pkgconfig )
+ENDIF()
+
+# Glob for resources
+MACRO( COPY_RESOURCES FILE_LIST SRC_RELATIVE_DIRECTORY DESTINATION EXPLICIT_DESTINATION )
+  FOREACH( PATTERN ${FILE_LIST} )
+    FILE(GLOB FILES ${PATTERN} )
+    FOREACH( FILE ${FILES} )
+      STRING(REPLACE ${SRC_RELATIVE_DIRECTORY} ${DESTINATION} NEWFILE ${FILE} )
+      GET_FILENAME_COMPONENT(NEWDIR ${NEWFILE} DIRECTORY)
+      IF( "${EXPLICIT_DESTINATION}" STREQUAL "" )
+        STRING( REPLACE "dali-toolkit" "toolkit" NEWDIR2 ${NEWDIR} )
+        INSTALL( FILES ${FILE} DESTINATION ${NEWDIR2} )
+      ELSE()
+        INSTALL( FILES ${FILE} DESTINATION ${DESTINATION}/${EXPLICIT_DESTINATION} )
+      ENDIF()
+    ENDFOREACH()
+  ENDFOREACH()
+ENDMACRO()
+
+# macro for installing headers by replacing prefix. (TODO, investigate
+# if there is a CMAKE way of doing this automatically)
+MACRO(INSTALL_HEADERS_WITH_DIRECTORY HEADER_LIST STRIP_PREFIX REPLACE_PREFIX)
+  GET_FILENAME_COMPONENT( SPREFIX ${STRIP_PREFIX} ABSOLUTE )
+  FOREACH(HEADER ${${HEADER_LIST}})
+    STRING(REGEX MATCH "(.*)[/]" DIR ${HEADER})
+    STRING(REPLACE ${SPREFIX} ${REPLACE_PREFIX} NEWDIR ${DIR})
+    INSTALL(FILES ${HEADER} DESTINATION ${INCLUDE_DIR}/${NEWDIR})
+  ENDFOREACH(HEADER)
+ENDMACRO(INSTALL_HEADERS_WITH_DIRECTORY)
+
+# Install headers using lists defined by ADD_SUBDIRECTORY
+INSTALL_HEADERS_WITH_DIRECTORY(PUBLIC_API_HEADERS ${ROOT_SRC_DIR}/dali-toolkit "dali-toolkit")
+INSTALL_HEADERS_WITH_DIRECTORY(DEVEL_API_HEADERS ${ROOT_SRC_DIR}/dali-toolkit "dali-toolkit")
+INSTALL_HEADERS_WITH_DIRECTORY(INTEGRATION_API_HEADERS ${ROOT_SRC_DIR}/dali-toolkit "dali-toolkit")
+INSTALL_HEADERS_WITH_DIRECTORY(PACKAGE_DOXY_HEADERS ${PACKAGE_DOXY_SRC_DIR} "dali-toolkit/doc" )
+
+# Install dali-toolkit.h
+INSTALL( FILES ${ROOT_SRC_DIR}/dali-toolkit/dali-toolkit.h DESTINATION ${INCLUDE_DIR}/dali-toolkit )
+
+# package doxygen file (contains doxygen grouping information)
+INSTALL( FILES ${package_doxy_files} DESTINATION ${DEV_INCLUDE_PATH}/dali-toolkit/doc )
+
+# On some platforms we want to install the data files to different location compare to
+# the data location used runtime. For example, on Android we want the toolkit library to load
+# the files from /data/data/com.sec.dali_demo/files but to install the files into ${PREFIX}/files
+# for SDK to pick them up for the archive.
+IF( DEFINED ENV{DALI_DATA_RW_INSTALL_DIR} )
+  SET( dataReadWriteInstallDir $ENV{DALI_DATA_RW_INSTALL_DIR} )
+ELSE()
+  SET( dataReadWriteInstallDir ${dataReadWriteDir} )
+ENDIF()
+
+IF( DEFINED ENV{DALI_DATA_RO_INSTALL_DIR} )
+  SET( dataReadOnlyInstallDir $ENV{DALI_DATA_RO_INSTALL_DIR} )
+ELSE()
+  SET( dataReadOnlyInstallDir ${dataReadOnlyDir} )
+ENDIF()
+
+COPY_RESOURCES( "${dali_toolkit_style_files}" "${ROOT_SRC_DIR}" "${dataReadOnlyInstallDir}" "./toolkit/styles" )
+COPY_RESOURCES( "${dali_toolkit_image_files}" "${ROOT_SRC_DIR}" "${dataReadOnlyInstallDir}" "./toolkit/images" )
+COPY_RESOURCES( "${dali_toolkit_sound_files}" "${ROOT_SRC_DIR}" "${dataReadOnlyInstallDir}" "./toolkit/sounds" )
+COPY_RESOURCES( "${dali_toolkit_style_images}" "${ROOT_SRC_DIR}" "${dataReadOnlyInstallDir}" "./toolkit/styles/images" )
+
+# The DALI_TOOLKIT_PREFIX must be set if this CMakeLists.txt is executed
+# from the top-level CMake script using ADD_SUBDIRECTORY() to avoid
+# target names duplication with other DALi modules.
+IF( ENABLE_COVERAGE )
+  FIND_PROGRAM( LCOV_BIN "lcov" )
+  IF( LCOV_BIN )
+
+    # Define custom rules for coverage
+    SET(COVERAGE_DIR .cov)
+    SET(COVERAGE_OUTPUT_DIR doc/coverage)
+
+    # lcov prior to 1.10 doesn't have -rc option; this and subsequent version don't output
+    # branch coverage. Determine the lcov version, and enable branch coverage accordingly.
+    EXECUTE_PROCESS( COMMAND bash -c "${LCOV_BIN} --version | cut -d' ' -f4" OUTPUT_VARIABLE LCOV_VERSION )
+    STRING( REPLACE "." ";" LCOV_VLIST ${LCOV_VERSION})
+    IF( NOT $<VERSION_LESS:${LCOV_VERSION},"1.10"> )
+      SET(LCOV_OPTS --rc lcov_branch_coverage=1)
+    ENDIF()
+
+    ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}rename_cov_data ./rename-cov-data )
+
+    ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}cov_data ${LCOV_BIN} ${LCOV_OPTS} --base-directory . --directory . -c -o dali.info
+      COMMAND ${LCOV_BIN} ${LCOV_OPTS} --remove dali.info \"*/dali-env/*\" \"/usr/include/*\" "*/dali-env/*" "*solid-color-actor*" "*/dali-toolkit/third-party/*" -o dali.info )
+
+    ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}coverage genhtml ${LCOV_OPTS} -o ${COVERAGE_OUTPUT_DIR} dali.info
+      DEPENDS cov_data )
+
+    ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}reset_coverage @${LCOV_BIN} -z --directory `pwd` )
+
+    # Define custom rule for distclean
+    ADD_CUSTOM_TARGET( ${DALI_TOOLKIT_PREFIX}distclean @echo cleaning for source distribution )
+    ADD_CUSTOM_COMMAND(
+          DEPENDS ${DALI_TOOLKIT_PREFIX}clean
+          COMMENT "distribution clean"
+          COMMAND find
+          ARGS    .
+          -not -name config.cmake -and \(
+          -name tester.c -or
+          -name Testing -or
+          -name CMakeFiles -or
+          -name doc -or
+          -name cmake.depends -or
+          -name cmake.check_depends -or
+          -name CMakeCache.txt -or
+          -name cmake.check_cache -or
+          -name *.cmake -or
+          -name Makefile -or
+          -name core -or
+          -name core.* -or
+          -name gmon.out -or
+          -name install_manifest.txt -or
+          -name *.pc -or
+          -name *.gcov -or
+          -name *.gcno -or
+          -name *.gcda -or
+          -name *~ -or
+          -name libdali*.so* \)
+          | grep -v TC | xargs rm -rf
+          TARGET  ${DALI_TOOLKIT_PREFIX}distclean
+          VERBATIM
+          )
+
+  ENDIF( LCOV_BIN )
+ENDIF()
+
+# Build documentation if doxygen tool is available
+SET( doxygenEnabled OFF )
+IF( DOXYGEN_FOUND )
+  SET( doxygenEnabled ON )
+  # 'prefix' is used by doxygen in-files.
+  SET( prefix ${PREFIX} )
+  SET( DOXYGEN_DOCS_DIR ${ROOT_SRC_DIR}/docs )
+  SET( DOXYGEN_ROOT_DIR ${ROOT_SRC_DIR} )
+  SET( DOXYGEN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/docs )
+  SET( DOXYGEN_INTERNAL_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/docs-internal )
+  CONFIGURE_FILE( ${DOXYGEN_SRC_DIR}/dali.doxy.in ${DOXYGEN_SRC_DIR}/dali.doxy @ONLY )
+  CONFIGURE_FILE( ${DOXYGEN_INTERNAL_SRC_DIR}/dali-internal.doxy.in ${DOXYGEN_INTERNAL_SRC_DIR}/dali-internal.doxy @ONLY )
+  ADD_CUSTOM_TARGET( doc_doxygen ALL
+                     DEPENDS ${name}
+                     COMMAND ${DOXYGEN_EXECUTABLE} -u ${DOXYGEN_SRC_DIR}/dali.doxy
+                     COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_SRC_DIR}/dali.doxy
+                     COMMAND ${CMAKE_COMMAND} -P ${DOXYGEN_SRC_DIR}/check_for_errors.cmake
+                     COMMENT "Generating API documentation with Doxygen"
+                     WORKING_DIRECTORY ${DOXYGEN_SRC_DIR}
+                     VERBATIM )
+  ADD_CUSTOM_TARGET( doc_doxygen_internal
+                     COMMAND ${DOXYGEN_EXECUTABLE} -u ${DOXYGEN_INTERNAL_SRC_DIR}/dali-internal.doxy
+                     COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_INTERNAL_SRC_DIR}/dali-internal.doxy
+                     COMMENT "Generating Internal API documentation with Doxygen"
+                     VERBATIM )
+
+ENDIF()
+
+IF( CONFIGURE_AUTOMATED_TESTS )
+  # Configure automated tests
+  CONFIGURE_FILE( ${ROOT_SRC_DIR}/automated-tests/CMakeLists.txt.in
+                  ${ROOT_SRC_DIR}/automated-tests/CMakeLists.txt @ONLY )
+ENDIF()
+
+# Configuration Messages
+MESSAGE( STATUS "Configuration:\n" )
+MESSAGE( STATUS "Prefix:                        " ${PREFIX} )
+MESSAGE( STATUS "Lib Dir:                       " ${LIB_DIR} )
+MESSAGE( STATUS "Include Dir:                   " ${INCLUDE_DIR} )
+MESSAGE( STATUS "Debug build:                   " ${ENABLE_DEBUG} )
+MESSAGE( STATUS "Export all symbols:            " ${ENABLE_EXPORTALL} )
+MESSAGE( STATUS "Coverage:                      " ${ENABLE_COVERAGE} )
+MESSAGE( STATUS "Trace:                         " ${ENABLE_TRACE} )
+MESSAGE( STATUS "Doxygen:                       " ${doxygenEnabled} )
+MESSAGE( STATUS "Data Dir (Read/Write):         " ${dataReadWriteDir} )
+MESSAGE( STATUS "Data Dir (Read Only):          " ${dataReadOnlyDir} )
+MESSAGE( STATUS "Data Install Dir (Read/Write): " ${dataReadWriteInstallDir} )
+MESSAGE( STATUS "Data Install Dir (Read Only):  " ${dataReadOnlyInstallDir} )
+MESSAGE( STATUS "Style Dir:                     " ${STYLE_DIR} )
+MESSAGE( STATUS "Style:                         " ${dali_style} )
+MESSAGE( STATUS "i18n:                          " ${ENABLE_I18N} )
+MESSAGE( STATUS "Use pkg configure:             " ${ENABLE_PKG_CONFIGURE} )
+MESSAGE( STATUS "Enable link test:              " ${ENABLE_LINK_TEST} )
+MESSAGE( STATUS "Configure automated tests:     " ${CONFIGURE_AUTOMATED_TESTS} )
+MESSAGE( STATUS "CXXFLAGS:                      " ${CMAKE_CXX_FLAGS} )
+MESSAGE( STATUS "LDFLAGS:                       " ${CMAKE_SHARED_LINKER_FLAGS_INIT}${CMAKE_SHARED_LINKER_FLAGS} )
+
+MESSAGE( " Folder       INSTALL_SHARE_DIR : [" ${INSTALL_SHARE_DIR} "]" )
+MESSAGE( " Folder          DALI_IMAGE_DIR : [" ${DALI_IMAGE_DIR} "]" )
+MESSAGE( " Folder          DALI_STYLE_DIR : [" ${DALI_STYLE_DIR} "]" )
+MESSAGE( " Folder    DALI_STYLE_IMAGE_DIR : [" ${DALI_STYLE_IMAGE_DIR} "]" )
+MESSAGE( " Folder          DALI_SOUND_DIR : [" ${DALI_SOUND_DIR} "]" )
+MESSAGE( " Folder DALI_DATA_READ_ONLY_DIR : [" ${DALI_DATA_READ_ONLY_DIR} "]" )
diff --git a/build/tizen/dali-toolkit.pc.in b/build/tizen/dali-toolkit.pc.in
new file mode 100644 (file)
index 0000000..6e1ed27
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+apiversion=@DALI_TOOLKIT_VERSION@
+libdir=@LIB_DIR@
+includedir=@DEV_INCLUDE_PATH@
+
+Name: Dali 3D Engine Toolkit
+Description: Cross platform 3D Engine Toolkit
+Version: ${apiversion}
+Requires: dali-core
+Libs: -L${libdir} -ldali-toolkit
+Cflags: -I${includedir}
diff --git a/build/tizen/docs-internal/build.sh b/build/tizen/docs-internal/build.sh
new file mode 100755 (executable)
index 0000000..73c98bf
--- /dev/null
@@ -0,0 +1,16 @@
+# Run doxygen to generate extremely verbose documentation and print the time it took to do so.
+
+LOG_FILE="build.`date +%Y_%m_%d_%H_%M_%S`.log"
+
+export START_TIME=`date +%s`
+ionice -c 3 nice doxygen dali-internal.doxy  2>&1 | tee "$LOG_FILE"
+export END_TIME=`date +%s`
+
+let "BUILD_TIME = $END_TIME - $START_TIME"
+let "BUILD_TIME_MINS = $BUILD_TIME / 60"
+let "BUILD_TIME_EXTRA_SECONDS = $BUILD_TIME % 60"
+BUILD_TIME_MSG="Build ran from $START_TIME until $END_TIME, $BUILD_TIME_MINS minutes and $BUILD_TIME_EXTRA_SECONDS seconds, finishing: `date`."
+echo "$BUILD_TIME_MSG"
+
+WARNINGS=`egrep ": warning: " < $LOG_FILE | wc -l`
+echo -e "\nWARNING COUNT: $WARNINGS"
diff --git a/build/tizen/docs-internal/dali-internal.doxy.in b/build/tizen/docs-internal/dali-internal.doxy.in
new file mode 100644 (file)
index 0000000..3fcaf37
--- /dev/null
@@ -0,0 +1,2682 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = DALi
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @DOXYGEN_DOCS_DIR@/generated-internal
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = YES
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = .
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+# Clip alias inserts the specified file between two text markers.
+# EG: @clip{"button.h",public,private}
+# Shows all lines between public and private *inclusive*.
+ALIASES += clip{3}="\dontinclude \1 \n \skip \2 \n \until \3"
+
+# <DALi Doxygen Tagging Rule>
+#
+# Use @SINCE_1_0, @SINCE_1_1, ... instead of @since,
+# and use @DEPRECATED_1_0, @DEPRECATED_1_1, ... instead of @deprecated.
+# It enables integrated management of version tagging between
+# the open source DALi API reference and Tizen API reference.
+# Using those tags with different ALIASES settings in each doxygen config file allows us
+# to generate two versions of "Since" and "Deprecated" generated output
+# from one set of public header files.
+#
+# If you need a newer version number like @SINCE_1_5 or @SINCE_2_0, just add new ALIASES for it.
+#
+# ##################################################3
+# # Guide for Open Source DALi API Reference
+#
+# ### @SINCE example:
+#   [some-public-header.h]
+#   /**
+#    * ...
+#    * @SINCE_1_0.1
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   ...
+#   Since:
+#       1.0.1
+#
+# ### @DEPRECATED example 1:
+#   [some-public-header.h]
+#   /**
+#    * @DEPRECATED_1_0.3
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 1.0.3
+#   ...
+#
+# ### @DEPRECATED example 2:
+#   [some-public-header.h]
+#   ...
+#   /**
+#    * @DEPRECATED_1_0.3. Use SomeFunction2() instead.
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 1.0.3. Use SomeFunction2() instead.
+#   ...
+#
+# ##################################################3
+# # Guide for Tizen Native API Reference
+#
+# ### @SINCE example:
+#   [some-public-header.h]
+#   /**
+#    * ...
+#    * @SINCE_1_0.1
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   ...
+#   Since:
+#       2.4, DALi Version 1.0.1
+#
+# ### @DEPRECATED example 1:
+#   [some-public-header.h]
+#   /**
+#    * @DEPRECATED_1_0.3
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 3.0, DALi version 1.0.3
+#   ...
+#
+# ### @DEPRECATED example 2:
+#   [some-public-header.h]
+#   ...
+#   /**
+#    * @DEPRECATED_1_0.3. Use SomeFunction2() instead.
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 3.0, DALi version 1.0.3. Use SomeFunction2() instead.
+#   ...
+
+###########################################
+# For Open Source DALi API Reference
+ALIASES += SINCE_1_0="@since 1.0"
+ALIASES += SINCE_1_1="@since 1.1"
+ALIASES += SINCE_1_2="@since 1.2"
+ALIASES += SINCE_1_3="@since 1.3"
+ALIASES += SINCE_1_4="@since 1.4"
+
+# Extra tags for Tizen 3.0
+ALIASES += SINCE_1_2_2="@since 1.2.2"
+ALIASES += SINCE_1_2_4="@since 1.2.4"
+ALIASES += SINCE_1_2_5="@since 1.2.5"
+ALIASES += SINCE_1_2_10="@since 1.2.10"
+ALIASES += SINCE_1_2_14="@since 1.2.14"
+ALIASES += SINCE_1_2_32="@since 1.2.32"
+
+# Extra tags for Tizen 4.0
+ALIASES += SINCE_1_3_4="@since 1.3.4"
+ALIASES += SINCE_1_3_5="@since 1.3.5"
+ALIASES += SINCE_1_3_9="@since 1.3.9"
+ALIASES += SINCE_1_3_15="@since 1.3.15"
+
+#Extra tags for Tizen 5.5
+ALIASES += SINCE_1_3_31="@since 1.3.31"
+
+ALIASES += DEPRECATED_1_0="@deprecated Deprecated since 1.0"
+ALIASES += DEPRECATED_1_1="@deprecated Deprecated since 1.1"
+ALIASES += DEPRECATED_1_2_8="@deprecated Deprecated since 1.2.8"
+ALIASES += DEPRECATED_1_2_10="@deprecated Deprecated since 1.2.10"
+ALIASES += DEPRECATED_1_2="@deprecated Deprecated since 1.2"
+ALIASES += DEPRECATED_1_3="@deprecated Deprecated since 1.3"
+ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 1.3.39"
+ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 1.3.51"
+ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 1.4"
+
+ALIASES += PLATFORM=""
+ALIASES += PRIVLEVEL_PLATFORM=""
+ALIASES += PRIVLEVEL_PUBLIC=""
+ALIASES += PRIVILEGE_KEYGRAB=""
+ALIASES += PRIVILEGE_DISPLAY=""
+ALIASES += PRIVILEGE_WINDOW_PRIORITY=""
+ALIASES += REMARK_INTERNET=""
+ALIASES += REMARK_STORAGE=""
+ALIASES += REMARK_RAWVIDEO=""
+
+############################################
+## For Tizen Native API Reference
+#ALIASES += SINCE_1_0="\par Since:\n 2.4, DALi version 1.0"
+#ALIASES += SINCE_1_1="\par Since:\n 3.0, DALi version 1.1"
+#ALIASES += SINCE_1_2="\par Since:\n 4.0, DALi version 1.2"
+#ALIASES += SINCE_1_3="\par Since:\n 5.0, DALi version 1.3"
+#ALIASES += SINCE_1_4="\par Since:\n 5.5, DALi version 1.4"
+
+## Extra tags for Tizen 3.0
+#ALIASES += SINCE_1_2_2="\par Since:\n 3.0, DALi version 1.2.2"
+#ALIASES += SINCE_1_2_4="\par Since:\n 3.0, DALi version 1.2.4"
+#ALIASES += SINCE_1_2_5="\par Since:\n 3.0, DALi version 1.2.5"
+#ALIASES += SINCE_1_2_10="\par Since:\n 3.0, DALi version 1.2.10"
+#ALIASES += SINCE_1_2_14="\par Since:\n 3.0, DALi version 1.2.14"
+#ALIASES += SINCE_1_2_32="\par Since:\n 3.0, DALi version 1.2.32"
+
+## Extra tags for Tizen 4.0
+#ALIASES += SINCE_1_3_4="\par Since:\n 4.0, DALi version 1.3.4"
+#ALIASES += SINCE_1_3_5="\par Since:\n 4.0, DALi version 1.3.5"
+#ALIASES += SINCE_1_3_9="\par Since:\n 4.0, DALi version 1.3.9"
+#ALIASES += SINCE_1_3_15="\par Since:\n 4.0, DALi version 1.3.15"
+
+#Extra tags for Tizen 5.5
+#ALIASES += SINCE_1_3_31="\par Since:\n 5.5, DALi version 1.3.31"
+
+## DALi has no deprecated API in Tizen 2.4 because it's DALi's first release.
+## Thus deprecated APIs in DALi 1.0.xx will be deprecated in Tizen 3.0.
+#ALIASES += DEPRECATED_1_0="@deprecated Deprecated since 3.0, DALi version 1.0"
+#ALIASES += DEPRECATED_1_1="@deprecated Deprecated since 3.0, DALi version 1.1"
+#ALIASES += DEPRECATED_1_2_8="@deprecated Deprecated since 3.0, DALi version 1.2.8"
+#ALIASES += DEPRECATED_1_2_10="@deprecated Deprecated since 3.0, DALi version 1.2.10"
+#ALIASES += DEPRECATED_1_2="@deprecated Deprecated since 4.0, DALi version 1.2"
+#ALIASES += DEPRECATED_1_3="@deprecated Deprecated since 5.0, DALi version 1.3"
+#ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 5.5, DALi version 1.3.39"
+#ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 5.5, DALi version 1.3.51"
+#ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 5.5, DALi version 1.4"
+
+#ALIASES += PLATFORM="@platform"
+#ALIASES += PRIVLEVEL_PLATFORM="\par Privilege Level:\n platform"
+#ALIASES += PRIVLEVEL_PUBLIC="\par Privilege Level:\n public"
+#ALIASES += PRIVILEGE_KEYGRAB="\par Privilege:\n http://tizen.org/privilege/keygrab"
+#ALIASES += PRIVILEGE_DISPLAY="\par Privilege:\n http://tizen.org/privilege/display"
+#ALIASES += PRIVILEGE_WINDOW_PRIORITY="\par Privilege:\n http://tizen.org/privilege/window.priority.set"
+#ALIASES += REMARK_INTERNET="@remarks %http://tizen.org/privilege/internet is needed if @a url is a http or https address."
+#ALIASES += REMARK_STORAGE="@remarks %http://tizen.org/privilege/mediastorage is needed if @a url is relevant to media storage. @remarks %http://tizen.org/privilege/externalstorage is needed if @a url is relevant to external storage."
+#ALIASES += REMARK_RAWVIDEO="@remarks %http://tizen.org/feature/multimedia.raw_video is needed if UNDERLAY is false. If the feature isn't supported, UNDERLAY is always true."
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            = @DOXYGEN_DOCS_DIR@/DaliLayout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @DOXYGEN_DOCS_DIR@/content \
+                         @DOXYGEN_ROOT_DIR@/../dali-core/dali \
+                         @DOXYGEN_ROOT_DIR@/../dali-adaptor/dali \
+                         @DOXYGEN_ROOT_DIR@/../dali-adaptor/plugins \
+                         @DOXYGEN_ROOT_DIR@/dali-toolkit
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.f90 \
+                         *.f \
+                         *.vhd \
+                         *.vhdl
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = @DOXYGEN_DOCS_DIR@/../
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = @DOXYGEN_DOCS_DIR@/content/images
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = main.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = NO
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = @DOXYGEN_DOCS_DIR@/dali_doxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = YES
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = YES
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               = "Dali.qch"
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = "Dali"
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = Dali
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           = @DOXYGEN_ROOT_DIR@/../dali-core/dali \
+                         @DOXYGEN_ROOT_DIR@/../dali-adaptor/dali \
+                         @DOXYGEN_ROOT_DIR@/../dali-adaptor/plugins \
+                         @DOXYGEN_ROOT_DIR@/dali-toolkit
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = DALI_TOOLKIT_API \
+                         DALI_INTERNAL \
+                         __attribute__ \
+                         ((visibility \
+                         "(default )))" \
+                         __attribute__ \
+                         ((visibility \
+                         "(hidden )))"
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 3
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/build/tizen/docs/check_for_errors.cmake b/build/tizen/docs/check_for_errors.cmake
new file mode 100644 (file)
index 0000000..e56ca0b
--- /dev/null
@@ -0,0 +1,7 @@
+FILE(READ doxygen-errors.txt DOXY_ERROR_VALUE)
+IF( "${DOXY_ERROR_VALUE}" STREQUAL "" )
+    MESSAGE( STATUS "Doxygen complete!")
+ELSE()
+    MESSAGE( "${DOXY_ERROR_VALUE}" )
+    MESSAGE( FATAL_ERROR "Doxygen failed!")
+ENDIF()
\ No newline at end of file
diff --git a/build/tizen/docs/dali.doxy.in b/build/tizen/docs/dali.doxy.in
new file mode 100644 (file)
index 0000000..2124ce7
--- /dev/null
@@ -0,0 +1,2659 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = DALi
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = @DOXYGEN_DOCS_DIR@/generated
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        = .
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+# Clip alias inserts the specified file between two text markers.
+# EG: @clip{"button.h",public,private}
+# Shows all lines between public and private *inclusive*.
+ALIASES += clip{3}="\dontinclude \1 \n \skip \2 \n \until \3"
+
+# <DALi Doxygen Tagging Rule>
+#
+# Use @SINCE_1_0, @SINCE_1_1, ... instead of @since,
+# and use @DEPRECATED_1_0, @DEPRECATED_1_1, ... instead of @deprecated.
+# It enables integrated management of version tagging between
+# the open source DALi API reference and Tizen API reference.
+# Using those tags with different ALIASES settings in each doxygen config file allows us
+# to generate two versions of "Since" and "Deprecated" generated output
+# from one set of public header files.
+#
+# If you need a newer version number like @SINCE_1_5 or @SINCE_2_0, just add new ALIASES for it.
+#
+# ##################################################3
+# # Guide for Open Source DALi API Reference
+#
+# ### @SINCE example:
+#   [some-public-header.h]
+#   /**
+#    * ...
+#    * @SINCE_1_0.1
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   ...
+#   Since:
+#       1.0.1
+#
+# ### @DEPRECATED example 1:
+#   [some-public-header.h]
+#   /**
+#    * @DEPRECATED_1_0.3
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 1.0.3
+#   ...
+#
+# ### @DEPRECATED example 2:
+#   [some-public-header.h]
+#   ...
+#   /**
+#    * @DEPRECATED_1_0.3. Use SomeFunction2() instead.
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 1.0.3. Use SomeFunction2() instead.
+#   ...
+#
+# ##################################################3
+# # Guide for Tizen Native API Reference
+#
+# ### @SINCE example:
+#   [some-public-header.h]
+#   /**
+#    * ...
+#    * @SINCE_1_0.1
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   ...
+#   Since:
+#       2.4, DALi Version 1.0.1
+#
+# ### @DEPRECATED example 1:
+#   [some-public-header.h]
+#   /**
+#    * @DEPRECATED_1_0.3
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 3.0, DALi version 1.0.3
+#   ...
+#
+# ### @DEPRECATED example 2:
+#   [some-public-header.h]
+#   ...
+#   /**
+#    * @DEPRECATED_1_0.3. Use SomeFunction2() instead.
+#    * ...
+#    */
+#   void SomeFunction();
+#
+#   [generated html file]
+#   void SomeFunction()
+#   Deprecated:
+#       Deprecated since 3.0, DALi version 1.0.3. Use SomeFunction2() instead.
+#   ...
+
+###########################################
+# For Open Source DALi API Reference
+ALIASES += SINCE_1_0="@since 1.0"
+ALIASES += SINCE_1_1="@since 1.1"
+ALIASES += SINCE_1_2="@since 1.2"
+ALIASES += SINCE_1_3="@since 1.3"
+ALIASES += SINCE_1_4="@since 1.4"
+ALIASES += SINCE_1_9="@since 1.9"
+
+# Extra tags for Tizen 3.0
+ALIASES += SINCE_1_2_2="@since 1.2.2"
+ALIASES += SINCE_1_2_4="@since 1.2.4"
+ALIASES += SINCE_1_2_5="@since 1.2.5"
+ALIASES += SINCE_1_2_10="@since 1.2.10"
+ALIASES += SINCE_1_2_14="@since 1.2.14"
+ALIASES += SINCE_1_2_32="@since 1.2.32"
+
+# Extra tags for Tizen 4.0
+ALIASES += SINCE_1_3_4="@since 1.3.4"
+ALIASES += SINCE_1_3_5="@since 1.3.5"
+ALIASES += SINCE_1_3_9="@since 1.3.9"
+ALIASES += SINCE_1_3_15="@since 1.3.15"
+
+#Extra tags for Tizen 5.5
+ALIASES += SINCE_1_3_31="@since 1.3.31"
+
+ALIASES += DEPRECATED_1_0="@deprecated Deprecated since 1.0"
+ALIASES += DEPRECATED_1_1="@deprecated Deprecated since 1.1"
+ALIASES += DEPRECATED_1_2_8="@deprecated Deprecated since 1.2.8"
+ALIASES += DEPRECATED_1_2_10="@deprecated Deprecated since 1.2.10"
+ALIASES += DEPRECATED_1_2="@deprecated Deprecated since 1.2"
+ALIASES += DEPRECATED_1_3="@deprecated Deprecated since 1.3"
+ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 1.3.39"
+ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 1.3.51"
+ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 1.4"
+
+ALIASES += PLATFORM=""
+ALIASES += PRIVLEVEL_PLATFORM=""
+ALIASES += PRIVLEVEL_PUBLIC=""
+ALIASES += PRIVILEGE_KEYGRAB=""
+ALIASES += PRIVILEGE_DISPLAY=""
+ALIASES += PRIVILEGE_WINDOW_PRIORITY=""
+ALIASES += REMARK_INTERNET=""
+ALIASES += REMARK_STORAGE=""
+ALIASES += REMARK_RAWVIDEO=""
+
+############################################
+## For Tizen Native API Reference
+#ALIASES += SINCE_1_0="\par Since:\n 2.4, DALi version 1.0"
+#ALIASES += SINCE_1_1="\par Since:\n 3.0, DALi version 1.1"
+#ALIASES += SINCE_1_2="\par Since:\n 4.0, DALi version 1.2"
+#ALIASES += SINCE_1_3="\par Since:\n 5.0, DALi version 1.3"
+#ALIASES += SINCE_1_4="\par Since:\n 5.5, DALi version 1.4"
+#ALIASES += SINCE_1_9="\par Since:\n 6.0, DALi version 1.9"
+
+## Extra tags for Tizen 3.0
+#ALIASES += SINCE_1_2_2="\par Since:\n 3.0, DALi version 1.2.2"
+#ALIASES += SINCE_1_2_4="\par Since:\n 3.0, DALi version 1.2.4"
+#ALIASES += SINCE_1_2_5="\par Since:\n 3.0, DALi version 1.2.5"
+#ALIASES += SINCE_1_2_10="\par Since:\n 3.0, DALi version 1.2.10"
+#ALIASES += SINCE_1_2_14="\par Since:\n 3.0, DALi version 1.2.14"
+#ALIASES += SINCE_1_2_32="\par Since:\n 3.0, DALi version 1.2.32"
+
+## Extra tags for Tizen 4.0
+#ALIASES += SINCE_1_3_4="\par Since:\n 4.0, DALi version 1.3.4"
+#ALIASES += SINCE_1_3_5="\par Since:\n 4.0, DALi version 1.3.5"
+#ALIASES += SINCE_1_3_9="\par Since:\n 4.0, DALi version 1.3.9"
+#ALIASES += SINCE_1_3_15="\par Since:\n 4.0, DALi version 1.3.15"
+
+#Extra tags for Tizen 5.5
+#ALIASES += SINCE_1_3_31="\par Since:\n 5.5, DALi version 1.3.31"
+
+## DALi has no deprecated API in Tizen 2.4 because it's DALi's first release.
+## Thus deprecated APIs in DALi 1.0.xx will be deprecated in Tizen 3.0.
+#ALIASES += DEPRECATED_1_0="@deprecated Deprecated since 3.0, DALi version 1.0"
+#ALIASES += DEPRECATED_1_1="@deprecated Deprecated since 3.0, DALi version 1.1"
+#ALIASES += DEPRECATED_1_2_8="@deprecated Deprecated since 3.0, DALi version 1.2.8"
+#ALIASES += DEPRECATED_1_2_10="@deprecated Deprecated since 3.0, DALi version 1.2.10"
+#ALIASES += DEPRECATED_1_2="@deprecated Deprecated since 4.0, DALi version 1.2"
+#ALIASES += DEPRECATED_1_3="@deprecated Deprecated since 5.0, DALi version 1.3"
+#ALIASES += DEPRECATED_1_3_39="@deprecated Deprecated since 5.5, DALi version 1.3.39"
+#ALIASES += DEPRECATED_1_3_51="@deprecated Deprecated since 5.5, DALi version 1.3.51"
+#ALIASES += DEPRECATED_1_4="@deprecated Deprecated since 5.5, DALi version 1.4"
+
+#ALIASES += PLATFORM="@platform"
+#ALIASES += PRIVLEVEL_PLATFORM="\par Privilege Level:\n platform"
+#ALIASES += PRIVLEVEL_PUBLIC="\par Privilege Level:\n public"
+#ALIASES += PRIVILEGE_KEYGRAB="\par Privilege:\n http://tizen.org/privilege/keygrab"
+#ALIASES += PRIVILEGE_DISPLAY="\par Privilege:\n http://tizen.org/privilege/display"
+#ALIASES += PRIVILEGE_WINDOW_PRIORITY="\par Privilege:\n http://tizen.org/privilege/window.priority.set"
+#ALIASES += REMARK_INTERNET="@remarks %http://tizen.org/privilege/internet is needed if @a url is a http or https address."
+#ALIASES += REMARK_STORAGE="@remarks %http://tizen.org/privilege/mediastorage is needed if @a url is relevant to media storage. @remarks %http://tizen.org/privilege/externalstorage is needed if @a url is relevant to external storage."
+#ALIASES += REMARK_RAWVIDEO="@remarks %http://tizen.org/feature/multimedia.raw_video is needed if UNDERLAY is false. If the feature isn't supported, UNDERLAY is always true."
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       = show_tizen_feature
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            = @DOXYGEN_DOCS_DIR@/DaliLayout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           = doxygen-errors.txt
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @DOXYGEN_DOCS_DIR@/content \
+                         @prefix@/include/dali/doc/dali-core-doc.h \
+                         @prefix@/include/dali/doc/dali-adaptor-doc.h \
+                         ../../../doc/dali-toolkit-doc.h \
+                         @prefix@/include/dali/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
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.h \
+                         *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = dali/integration-api
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        = DaliInternal \
+                         Dali::Internal \
+                         Dali::Integration \
+                         Impl \
+                         ApplicationImpl
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           = @DOXYGEN_DOCS_DIR@/../
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = @DOXYGEN_DOCS_DIR@/content/images
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = main.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = @DOXYGEN_DOCS_DIR@/dali_doxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = YES
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               = dali.chm
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               = "Dali.qch"
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = "Dali"
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NONE
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = DALI_TOOLKIT_API \
+                         DALI_INTERNAL \
+                         __attribute__ \
+                         ((visibility \
+                         "(default )))" \
+                         __attribute__ \
+                         ((visibility \
+                         "(hidden )))"
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/build/tizen/rename-cov-data b/build/tizen/rename-cov-data
new file mode 100755 (executable)
index 0000000..a29f21b
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+COVERAGE_DIR=.cov
+[[ -d ${COVERAGE_DIR} ]] || mkdir ${COVERAGE_DIR}
+rm -f ${COVERAGE_DIR}/*
+
+COVERAGE_EXTENSIONS="
+  gcda
+  gcno
+"
+
+SOURCE_EXTENSIONS="
+ c
+ cpp
+"
+
+for covExt in $COVERAGE_EXTENSIONS
+do
+  # Move into .cov directory
+  for file in `find -name *.${covExt}`
+  do
+    cp $file ${COVERAGE_DIR}
+  done
+
+  # strip source extensions liks .cpp as that's the format expected by patch-coverage.pl
+  for srcExt in $SOURCE_EXTENSIONS
+  do
+    for file in `find ${COVERAGE_DIR} -name *.${srcExt}.${covExt}`
+    do
+      name=`echo $file | sed "s/.${srcExt}.${covExt}//g"`
+      mv $file $name.${covExt}
+    done
+  done
+
+done
diff --git a/dali-toolkit-resources.manifest b/dali-toolkit-resources.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/dali-toolkit.manifest b/dali-toolkit.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/dali-toolkit.manifest-smack b/dali-toolkit.manifest-smack
new file mode 100644 (file)
index 0000000..08561d6
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <assign>
+               <filesystem path="/usr/lib/*" label="_" />
+       </assign>
+       <request>
+               <domain name="dali"/>
+       </request>
+</manifest>
diff --git a/dali-toolkit/dali-toolkit.h b/dali-toolkit/dali-toolkit.h
new file mode 100644 (file)
index 0000000..c6fafad
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef DALI_TOOLKIT_H
+#define DALI_TOOLKIT_H
+
+/*
+ * Copyright (c) 2017 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/dali.h>
+
+#include <dali-toolkit/public-api/controls/alignment/alignment.h>
+#include <dali-toolkit/public-api/controls/buttons/button.h>
+#include <dali-toolkit/public-api/controls/buttons/check-box-button.h>
+#include <dali-toolkit/public-api/controls/buttons/push-button.h>
+#include <dali-toolkit/public-api/controls/buttons/radio-button.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/flex-container/flex-container.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+#include <dali-toolkit/public-api/controls/progress-bar/progress-bar.h>
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+#include <dali-toolkit/public-api/controls/slider/slider.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h>
+#include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>
+
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.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/text/text-enumerations.h>
+
+#include <dali-toolkit/public-api/visuals/border-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/mesh-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/dali-toolkit-version.h>
+#include <dali-toolkit/public-api/enums.h>
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+#endif // DALI_TOOLKIT_H
diff --git a/dali-toolkit/devel-api/asset-manager/asset-manager.cpp b/dali-toolkit/devel-api/asset-manager/asset-manager.cpp
new file mode 100644 (file)
index 0000000..b2427ec
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+
+namespace
+{
+
+#define TOKEN_STRING(x) #x
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+const std::string AssetManager::GetDaliImagePath()
+{
+  /**
+   * @note DALI_IMAGE_DIR is a macro that can be defined either with a file system path or zero.
+   *       If it's defined as zero then the value is retrieved from an environment variable
+   *       named DALI_IMAGE_DIR.
+   */
+  return (nullptr == DALI_IMAGE_DIR) ? EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_IMAGE_DIR)) : DALI_IMAGE_DIR;
+}
+
+const std::string AssetManager::GetDaliSoundPath()
+{
+  /**
+   * @note DALI_SOUND_DIR is a macro that can be defined either with a file system path or zero.
+   *       If it's defined as zero then the value is retrieved from an environment variable
+   *       named DALI_SOUND_DIR.
+   */
+  return (nullptr == DALI_SOUND_DIR) ? EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_SOUND_DIR)) : DALI_SOUND_DIR;
+}
+
+const std::string AssetManager::GetDaliStylePath()
+{
+  /**
+   * @note DALI_STYLE_DIR is a macro that can be defined either with a file system path or zero.
+   *       If it's defined as zero then the value is retrieved from an environment variable
+   *       named DALI_STYLE_DIR.
+   */
+  return (nullptr == DALI_STYLE_DIR) ? EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_STYLE_DIR)) : DALI_STYLE_DIR;
+}
+
+const std::string AssetManager::GetDaliStyleImagePath()
+{
+  /**
+   * @note DALI_STYLE_IMAGE_DIR is a macro that can be defined either with a file system path or zero.
+   *       If it's defined as zero then the value is retrieved from an environment variable
+   *       named DALI_STYLE_IMAGE_DIR.
+   */
+  return (nullptr == DALI_STYLE_IMAGE_DIR) ? EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_STYLE_IMAGE_DIR)) : DALI_STYLE_IMAGE_DIR;
+}
+
+const std::string AssetManager::GetDaliDataReadOnlyPath()
+{
+  /**
+   * @note DALI_DATA_READ_ONLY_DIR is a macro that can be defined either with a file system path or zero.
+   *       If it's defined as zero then the value is retrieved from an environment variable
+   *       named DALI_DATA_READ_ONLY_DIR.
+   */
+  return (nullptr == DALI_DATA_READ_ONLY_DIR) ? EnvironmentVariable::GetEnvironmentVariable(TOKEN_STRING(DALI_DATA_READ_ONLY_DIR)) : DALI_DATA_READ_ONLY_DIR;
+}
+
+} // Toolkit
+
+} // Dali
diff --git a/dali-toolkit/devel-api/asset-manager/asset-manager.h b/dali-toolkit/devel-api/asset-manager/asset-manager.h
new file mode 100644 (file)
index 0000000..cba2ffd
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DALI_TOOLKIT_ASSET_MANAGER_DEVEL_H
+#define DALI_TOOLKIT_ASSET_MANAGER_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Retrieves the file system path of the assets.
+ */
+class AssetManager
+{
+public:
+  /**
+   * @return The file system path of the images.
+   */
+  static const std::string GetDaliImagePath();
+
+  /**
+   * @return The file system path of the sounds.
+   */
+  static const std::string GetDaliSoundPath();
+
+  /**
+   * @return The file system path of the styles.
+   */
+  static const std::string GetDaliStylePath();
+
+  /**
+   * @return The file system path of the images in the styles.
+   */
+  static const std::string GetDaliStyleImagePath();
+
+  /**
+   * @return The file system path of the DALi's read only data.
+   */
+  static const std::string GetDaliDataReadOnlyPath();
+};
+
+} // Toolkit
+
+} // Dali
+
+
+#endif // DALI_TOOLKIT_ASSET_MANAGER_DEVEL_H
+
diff --git a/dali-toolkit/devel-api/builder/base64-encoding.cpp b/dali-toolkit/devel-api/builder/base64-encoding.cpp
new file mode 100644 (file)
index 0000000..2799430
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018 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 <sstream>
+#include <iterator>
+
+#include <dali/public-api/object/property-value.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali-toolkit/devel-api/builder/base64-encoding.h>
+#include <dali-toolkit/third-party/base-n/basen.hpp>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+const int MAX_PROPERTY_STRING_LENGTH(64); // Cuts larger strings into blocks of this size.
+
+bool GetStringFromProperty( const Property::Value& value, std::string& output )
+{
+  bool extracted = false;
+  if( value.Get( output ) )
+  {
+    extracted = true;
+  }
+  else
+  {
+    Property::Array* array = value.GetArray();
+    if( array )
+    {
+      const unsigned int arraySize = array->Size();
+      for( unsigned int i = 0; i < arraySize; ++i )
+      {
+        std::string element;
+        if( array->GetElementAt( i ).Get( element ) )
+        {
+          extracted = true;
+          output += element;
+        }
+        else
+        {
+          // If property in array is anything other than a string, then it is invalid so break and clear output.
+          output.clear();
+          extracted = false;
+          break;
+        }
+      }
+    }
+  }
+  return extracted;
+}
+
+}//anonymous namespace
+
+bool DecodeBase64PropertyData( const Property::Value& value, std::vector<uint32_t>& outputData )
+{
+  bool decoded = false;
+  std::string encodedString;
+
+
+  if( GetStringFromProperty( value, encodedString ) )
+  {
+    std::vector<unsigned char> outputTmpData;
+    outputTmpData.reserve( ceil( encodedString.size() * 0.75f ) );
+    bn::decode_b64( encodedString.begin(), encodedString.end(), std::back_inserter(outputTmpData) );
+
+    outputData.clear();
+    outputData.resize( outputTmpData.size() / sizeof(uint32_t) );
+    // Treat as a block of data
+    memcpy( &outputData[0], &outputTmpData[0], outputTmpData.size() );
+
+    decoded = true;
+  }
+  return decoded;
+}
+
+void EncodeBase64PropertyData( Property::Value& value, const std::vector<uint32_t>& inputData )
+{
+  std::ostringstream oss;
+
+  bn::encode_b64( reinterpret_cast<const char*>(&inputData[0]),
+                  reinterpret_cast<const char*>(&inputData[0]+inputData.size()),
+                  std::ostream_iterator<unsigned char>(oss, "") );
+
+
+  std::string encodedString = oss.str();
+  if( encodedString.length() > MAX_PROPERTY_STRING_LENGTH)
+  {
+    // cut string up into blocks of MAX_PROPERTY_STRING_LENGTH and store to an array
+    auto numStrings = encodedString.length() / MAX_PROPERTY_STRING_LENGTH +
+                      ((encodedString.length() % MAX_PROPERTY_STRING_LENGTH) != 0);
+
+    Property::Array array;
+    for(auto i=0u; i<numStrings; ++i)
+    {
+      array.PushBack( encodedString.substr( i*MAX_PROPERTY_STRING_LENGTH, MAX_PROPERTY_STRING_LENGTH));
+    }
+    value = array;
+  }
+  else
+  {
+    value = encodedString;
+  }
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/builder/base64-encoding.h b/dali-toolkit/devel-api/builder/base64-encoding.h
new file mode 100644 (file)
index 0000000..6a691a9
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef DALI_TOOLKIT_BASE64_ENCODING_H
+#define DALI_TOOLKIT_BASE64_ENCODING_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/object/property.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Parses a Property::STRING or Property::ARRAY of STRINGS to
+ * retrieve a block of uint32_t data.
+ *
+ * Data can be encoded using the base64 encoding scheme to allow it to be used
+ * in JSON (The property system maps to JSON types).
+ *
+ * @param[in] value The property value to decode
+ * @param[out] outputData The output data block
+ * @return True if a data block was decoded successfully.
+ */
+bool DecodeBase64PropertyData( const Property::Value& value, std::vector<uint32_t>& outputData );
+
+/**
+ * @brief Convert a block of uint32_t data into a Property::STRING or ARRAY of STRINGs
+ * encoded using base64. This allows the data to be mapped to JSON easily.
+ *
+ * @param[out] value The value to write data into (to avoid copying).
+ * @param[in] inputData The input
+ */
+void EncodeBase64PropertyData( Property::Value& value, const std::vector<uint32_t>& inputData );
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_BASE64_ENCODING_H
diff --git a/dali-toolkit/devel-api/builder/builder.cpp b/dali-toolkit/devel-api/builder/builder.cpp
new file mode 100644 (file)
index 0000000..b66beb0
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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 "builder.h"
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/builder/builder-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Builder::Builder()
+{
+}
+
+Builder::~Builder()
+{
+}
+
+Builder Builder::New(void)
+{
+  return Builder(new Internal::Builder());
+}
+
+Builder::Builder(Internal::Builder *impl)
+  : BaseHandle(impl)
+{
+}
+
+void Builder::LoadFromString( const std::string &data, UIFormat rep )
+{
+  GetImpl(*this).LoadFromString( data );
+}
+
+void Builder::AddConstants( const Property::Map& map )
+{
+  GetImpl(*this).AddConstants( map );
+}
+
+void Builder::AddConstant( const std::string& key, const Property::Value& value )
+{
+  GetImpl(*this).AddConstant( key, value );
+}
+
+const Property::Map& Builder::GetConfigurations() const
+{
+  return GetImpl(*this).GetConfigurations();
+}
+
+const Property::Map& Builder::GetConstants() const
+{
+  return GetImpl(*this).GetConstants();
+}
+
+const Property::Value& Builder::GetConstant( const std::string& key ) const
+{
+  return GetImpl(*this).GetConstant( key );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName )
+{
+  return GetImpl(*this).CreateAnimation( animationName );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map )
+{
+  return GetImpl(*this).CreateAnimation( animationName, map );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor )
+{
+  return GetImpl(*this).CreateAnimation( animationName, sourceActor );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor )
+{
+  return GetImpl(*this).CreateAnimation( animationName, map, sourceActor );
+}
+
+BaseHandle Builder::Create( const std::string& templateName )
+{
+  return GetImpl(*this).Create( templateName );
+}
+
+BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map )
+{
+  return GetImpl(*this).Create( templateName, map );
+}
+
+BaseHandle Builder::CreateFromJson( const std::string& json )
+{
+  return GetImpl(*this).CreateFromJson( json );
+}
+
+bool Builder::ApplyStyle( const std::string& styleName, Handle& handle )
+{
+  return GetImpl(*this).ApplyStyle( styleName, handle );
+}
+
+bool Builder::ApplyFromJson( Handle& handle, const std::string& json )
+{
+  return GetImpl(*this).ApplyFromJson( handle, json );
+}
+
+void Builder::AddActors( Actor toActor )
+{
+  GetImpl(*this).AddActors( toActor );
+}
+
+void Builder::AddActors( const std::string &sectionName, Actor toActor )
+{
+  GetImpl(*this).AddActors( sectionName, toActor );
+}
+
+void Builder::CreateRenderTask( const std::string &name )
+{
+  GetImpl(*this).CreateRenderTask( name );
+}
+
+Path Builder::GetPath( const std::string &name )
+{
+  return GetImpl(*this).GetPath( name );
+}
+
+PathConstrainer Builder::GetPathConstrainer( const std::string& pathConstrainerName )
+{
+  return GetImpl(*this).GetPathConstrainer( pathConstrainerName );
+}
+
+LinearConstrainer Builder::GetLinearConstrainer( const std::string& linearConstrainerName )
+{
+  return GetImpl(*this).GetLinearConstrainer( linearConstrainerName );
+}
+
+Builder::BuilderSignalType& Builder::QuitSignal()
+{
+  return GetImpl( *this ).QuitSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/devel-api/builder/builder.h b/dali-toolkit/devel-api/builder/builder.h
new file mode 100755 (executable)
index 0000000..1f8ea4a
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef DALI_TOOLKIT_UIBUILDER_H
+#define DALI_TOOLKIT_UIBUILDER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/linear-constrainer.h>
+#include <dali/devel-api/animation/path-constrainer.h>
+#include <dali/public-api/images/frame-buffer-image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Builder;
+}
+
+/**
+ * This class provides the ability to load and style an actor tree from a string representation.
+ *
+ * The following is an example in JSON.
+ *
+ * @code
+ *
+ *  {
+ *    "templates": // are named instantiable actor trees
+ *    {
+ *      "defaultText":
+ *      {
+ *        "type":"TextActor",
+ *        "font":"",
+ *        "parentOrigin":[0.5,0.5,0],
+ *        "scale": [50,50,1]
+ *      }
+ *    },
+ *    "styles": // are named property sets applied to actor trees
+ *    {
+ *     "myStyle":
+ *      {
+ *        "size": [10,10,1] // root properties applied to a given root actor
+ *        "actors":         // properties applied to actors found by name from root
+ *        {
+ *          "ok":           // properties for an actor named "ok"
+ *          {
+ *            "scale":[5,5,1],
+ *          },
+ *          "cancel":
+ *          {
+ *            "scale":[50,50,1],
+ *          }
+ *       },
+ *      },
+ *    },
+ *    "stage":
+ *    [
+ *      {
+ *        "type":"defaultText",
+ *        "text":"Hello World",
+ *        "position":[0,0,0]
+ *      },
+ *    ]
+ *  }
+ *
+ * @endcode
+ *
+ * The following shows a method to load the json file.
+ * @code
+ * Builder builder = Builder::New();
+ * std::string json_data(ReadFile("layout.json"));
+ * builder.LoadFromString(json_data);
+ * @endcode
+ * Examples
+ * - Load all actors in the "stage" section to the root layer
+ * @code
+ * builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+ * @endcode
+ *
+ * - Create an actor tree from the "templates" section
+ * @code
+ * TextActor actor = TextActor::DownCast( builder.Create( "defaultText" ) );
+ * @endcode
+ *
+ * - Style an actor tree from the "styles" section
+ * @code
+ * builder.ApplyStyle( "myStyle",  actor );
+ * @endcode
+ *
+ * - Create an actor tree from json
+ * @code
+ * TextActor actor = TextActor::DownCast( builder.CreateFromJson("{\"type\":\"TextActor\",\"font\":\"\",\"scale\":[50,50,1]}") );
+ * @endcode
+ *
+ * - Apply a style to an actor tree from json
+ * @code
+ * builder.ApplyFromJson( textActor, ("{\"scale\":[5,5,1]}") );
+ * @endcode
+ *
+ */
+
+class DALI_TOOLKIT_API Builder : public BaseHandle
+ {
+ public:
+   /**
+    * Create an Builder handle; this can be initialised with Builder::New()
+    * Calling member functions with an uninitialised handle is not allowed.
+    */
+  Builder();
+
+  /**
+   * Creates an Builder object.
+   * @return A handle to the Builder control.
+   */
+  static Builder New();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Builder();
+
+  /**
+   * UI string data format
+   */
+  enum UIFormat
+  {
+    JSON,                 ///< String is JSON
+  };
+
+  /**
+   * Loads a string representation of an actor tree into memory.
+   * The Actor is not automatically added to the stage.
+   * This function will raise an exception for parse and logical structure errors.
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @param data A string represenation of an Actor tree
+   * @param format The string representation format ie JSON
+   */
+  void LoadFromString( const std::string& data, UIFormat format = JSON );
+
+  /**
+   * @brief Adds user defined constants to all future style template or animation expansions
+   *
+   * e.g.
+   *   Property::Map map;
+   *   map["IMAGE_DIRECTORY"] = "/usr/share/images";
+   *   builder.AddConstants( map );
+   *
+   * @pre The Builder has been initialized.
+   * @param map The user defined constants used in template expansions.
+   */
+  void AddConstants( const Property::Map& map );
+
+  /**
+   * @brief Adds or modifies a user defined constant to all future style template or animation expansions
+   *
+   * e.g.
+   * @code
+   * builder.AddConstant( "IMAGE_DIRECTORY", "/usr/share/images" );
+   * @endcode
+   *
+   * @pre The Builder has been initialized.
+   * @param key The constant name to add or update
+   * @param value The new value for the constant.
+   */
+  void AddConstant( const std::string& key, const Property::Value& value );
+
+  /**
+   * @brief Gets all currently defined configurations.
+   *
+   * @pre The Builder has been initialized.
+   * @return A reference to the currently defined configurations.
+   */
+  const Property::Map& GetConfigurations() const;
+
+  /**
+   * @brief Gets all currently defined constants.
+   *
+   * e.g.
+   * @code
+   * Property::Map map = builder.GetConstants(); // get copy of current constants
+   * map["IMAGE_DIRECTORY"] = "/usr/share/images";  // make modification
+   * builder.AddConstants( map );                   // write back changes
+   * @endcode
+   *
+   * @pre The Builder has been initialized.
+   * @return A reference to the currently defined constants.
+   */
+  const Property::Map& GetConstants() const;
+
+  /**
+   * @brief Gets a currently defined constant, or returns Property::INVALID
+   *
+   * e.g.
+   * @code
+   * Property::Map map = builder.GetConstants(); // get copy of current constants
+   * map["IMAGE_DIRECTORY"] = "/usr/share/images";  // make modification
+   * builder.AddConstants( map );                   // write back changes
+   * @endcode
+   *
+   * @pre The Builder has been initialized.
+   * @param key The constant name to search for.
+   */
+  const Property::Value& GetConstant( const std::string& key ) const;
+
+  /**
+   * Creates an animation from the set of known animations
+   * e.g.
+   *   Animation a = builder.CreateAnimation( "wobble");
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The animationName exists in the animations section of the data representation
+   * @param animationName The animation name to create
+   * @returns The base handle of the created object
+   */
+  Animation CreateAnimation( const std::string& animationName );
+
+  /**
+   * @brief Creates an animation from the set of known animations with user defined constants
+   *
+   * e.g.
+   *   Property::Map map;
+   *   map["ACTOR"] = actor.GetName();       // replaces '{ACTOR} in the template
+   *   Animation a = builder.CreateAnimation( "wobble");
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The animationName exists in the animations section of the data representation
+   * @pre The map contains all the constant expansions in the style template
+   * @param animationName The animation name to create
+   * @param map The user defined constants used in style template expansion.
+   * @returns The base handle of the created object
+   */
+  Animation CreateAnimation( const std::string& animationName, const Property::Map& map );
+
+  /**
+   * @brief Creates an animation from the set of known animations.
+   *
+   * The animation is applied to a specific actor.
+   * e.g.
+   *   Actor myInstance = builder.Create( "templateActorTree" )
+   *   Animation a = builder.CreateAnimation( "wobble", myInstance );
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The animationName exists in the animations section of the data representation
+   * @param animationName The animation name to create
+   * @param sourceActor The starting point in an actor tree, from which to look for property owners
+   * @returns The base handle of the created object
+   */
+  Animation CreateAnimation( const std::string& animationName, Dali::Actor sourceActor );
+
+  /**
+   * @brief Creates an animation from the set of known animations with user defined constants
+   *
+   * The animation is applied to a specific actor.
+   * e.g.
+   *   Property::Map map;
+   *   map["ACTOR"] = actor.GetName();       // replaces '{ACTOR} in the template
+   *   Actor myInstance = builder.Create( "templateActorTree" )
+   *   Animation a = builder.CreateAnimation( "wobble", myInstance);
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The animationName exists in the animations section of the data representation
+   * @pre The map contains all the constant expansions in the style template
+   * @param animationName The animation name to create
+   * @param map The user defined constants used in style template expansion.
+   * @param sourceActor The starting point in an actor tree, from which to look for property owners
+   * @returns The base handle of the created object
+   */
+  Animation CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor );
+
+  /**
+   * @brief Creates an object (e.g. an actor) from the set of known style templates
+   *
+   * e.g.
+   *   mActor.Add( Actor::DownCast(builder.Create( "defaultText")) );
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The templateName exists in the templates section of the data representation
+   *      and contains 'type' property used to create the object.
+   * @param templateName The template to apply in creation.
+   * @returns The base handle of the created object
+   */
+  BaseHandle Create( const std::string& templateName );
+
+  /**
+   * @brief Creates an object from the style templates with user defined constants
+   *
+   * e.g.
+   *   Property::Map map;
+   *   map["IMAGE_DIR"] = "/usr/share/images"; // replaces '{IMAGE_DIR} in the template
+   *   mActor.Add( Actor::DownCast(builder.Create( "defaultImage",  map) ) );
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @pre The templateName exists in the templates section of the data representation
+   *      and contains 'type' property used to create the object.
+   * @param templateName The template used to create the object.
+   * @param map The user defined constants used in template expansion.
+   * @returns The base handle of the created object
+   */
+  BaseHandle Create( const std::string& templateName, const Property::Map& map );
+
+  /**
+   * @brief Creates an object (e.g. an actor) from given json snippet
+   *
+   * e.g.
+   *   Actor a = Actor::DownCast(builder.CreateFromJson( "{\"type\":\"TextActor\"}"));
+   *
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @param json The json snippet used to create the object.
+   * @returns The base handle of the created object if any
+   */
+  BaseHandle CreateFromJson( const std::string& json );
+
+  /**
+   * Apply a style (a collection of properties) to an actor.
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @param styleName The name of the set of style properties to set on the handle object.
+   * @param handle Then handle of the object on which to set the properties.
+   *
+   * @return Return true if the style was found
+   */
+  bool ApplyStyle( const std::string& styleName, Handle& handle );
+
+  /**
+   * Apply a style (a collection of properties) to an actor from the given json snippet
+   * @pre The Builder has been initialized.
+   * @pre Preconditions have been met for creating dali objects ie Images, Actors etc
+   * @param handle Then handle of the object on which to set the properties.
+   * @param json The json snippet used to create the object.
+   *
+   * @return Return true if the json snippet was parsed
+   */
+  bool ApplyFromJson(  Handle& handle, const std::string& json );
+
+
+  /**
+   * Add the actor tree in the "stage" section to the actor toActor.
+   * ie if the representation has a 'stage' section that contains a tree of
+   * actors then
+   *    builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+   * will create and add the actors to the stage root layer.
+   * @param toActor The actor to add the created actors to
+   */
+  void AddActors( Actor toActor );
+
+  /**
+   * Adds actors in the sectionName to the actor toActor.
+   * ie if the representation has a sectionName section that contains a tree of
+   * actors then
+   *    builder.AddActors( sectionName, Stage::GetCurrent().GetRootLayer() );
+   * will create and add the actors to the stage root layer.
+   * @param sectionName The section name to search for the actor tree
+   * @param toActor The actor to add the created actors to
+   */
+  void AddActors( const std::string &sectionName, Actor toActor );
+
+  /**
+   * Create a render task set.
+   * @pre The Builder has been initialized.
+   * @param name The library name of the render task set.
+   */
+  void CreateRenderTask( const std::string &name );
+
+  /**
+   * Get or create Path from the Path instance library.
+   * An empty handle is returned otherwise.
+   * @pre The Builder has been initialized.
+   * @param name The name of a Path in the loaded representation
+   * @return A handle to a Path if found, otherwise empty
+   */
+  Path GetPath( const std::string &name );
+
+  /**
+   * Get or create a PathConstrainer from the set of known PathConstrainers
+   * e.g.
+   *   PathConstrainer a = builder.GetPathConstrainer( "myPathConstrainer");
+   *
+   * @pre The Builder has been initialized.
+   * @pre The pathConstrainerName exists in the Constrainers section of the data representation
+   * @param pathConstrainerName The name of the PathConstrainer
+   * @returns A handle to a PathConstrainer if found, otherwise empty
+   */
+  PathConstrainer GetPathConstrainer( const std::string& pathConstrainerName );
+
+  /**
+   * Get or create a LinearConstrainer from the set of known LinearConstrainers
+   * e.g.
+   *   LinearConstrainer a = builder.GetLinearConstrainer( "myLinearConstrainer");
+   *
+   * @pre The Builder has been initialized.
+   * @pre The linearConstrainerName exists in the Constrainers section of the data representation
+   * @param linearConstrainerName The name of the LinearConstrainer
+   * @returns A handle to a LinearConstrainer if found, otherwise empty
+   */
+  LinearConstrainer GetLinearConstrainer( const std::string& linearConstrainerName );
+
+  // Signals
+
+  /**
+   * @brief Builder signal type
+   */
+  typedef Signal< void () > BuilderSignalType;
+
+  /**
+   * @brief Signal emitted when a quit action is requested by the builder.
+   */
+  BuilderSignalType& QuitSignal();
+
+private:
+  explicit DALI_INTERNAL Builder(Internal::Builder *impl);
+
+}; // class Builder
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_UIBUILDER_H
diff --git a/dali-toolkit/devel-api/builder/json-parser.cpp b/dali-toolkit/devel-api/builder/json-parser.cpp
new file mode 100644 (file)
index 0000000..6bcb108
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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 <dali-toolkit/devel-api/builder/json-parser.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <functional>
+#include <iostream>
+#include <cstring>
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/json-parser-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+JsonParser JsonParser::New()
+{
+  Internal::JsonParser* internal = new Internal::JsonParser();
+  return JsonParser(internal);
+}
+
+JsonParser JsonParser::New(const TreeNode& tree)
+{
+  Internal::JsonParser* internal = new Internal::JsonParser(tree);
+  return JsonParser(internal);
+}
+
+JsonParser::JsonParser()
+{
+}
+
+JsonParser::~JsonParser()
+{
+}
+
+JsonParser JsonParser::DownCast( BaseHandle handle )
+{
+  return JsonParser( dynamic_cast<Internal::JsonParser*>(handle.GetObjectPtr()) );
+}
+
+bool JsonParser::Parse(const std::string& source)
+{
+  return GetImplementation(*this).Parse(source);
+}
+
+void JsonParser::Pack(void)
+{
+  return GetImplementation(*this).Pack();
+}
+
+const TreeNode* JsonParser::GetRoot() const
+{
+  return GetImplementation(*this).GetRoot();
+}
+
+bool JsonParser::ParseError() const
+{
+  return GetImplementation(*this).ParseError();
+}
+
+int JsonParser::GetErrorPosition() const
+{
+  return GetImplementation(*this).GetErrorPosition();
+}
+
+std::string JsonParser::GetErrorDescription() const
+{
+  return GetImplementation(*this).GetErrorDescription();
+}
+
+int JsonParser::GetErrorLineNumber() const
+{
+  return GetImplementation(*this).GetErrorLineNumber();
+}
+
+int JsonParser::GetErrorColumn() const
+{
+  return GetImplementation(*this).GetErrorColumn();
+}
+
+void JsonParser::Write(std::ostream& output, int indent) const
+{
+  return GetImplementation(*this).Write(output, indent);
+}
+
+JsonParser::JsonParser(Internal::JsonParser* internal)
+  : BaseHandle(internal)
+{
+}
+
+} // namespace toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/devel-api/builder/json-parser.h b/dali-toolkit/devel-api/builder/json-parser.h
new file mode 100644 (file)
index 0000000..b4ae41b
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef DALI_JSON_PARSER_H
+#define DALI_JSON_PARSER_H
+
+/*
+ * Copyright (c) 2019 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 <list>
+#include <ostream>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class JsonParser;
+}
+
+/*
+ * Parses JSON
+ */
+class DALI_TOOLKIT_API JsonParser : public BaseHandle
+{
+public:
+
+  /*
+   * Create new parser
+   * @return JsonParser
+   */
+  static JsonParser New();
+
+  /*
+   * Create new parser from the given tree
+   * This method will deep copy the given tree.
+   * @return JsonParser
+   */
+  static JsonParser New(const TreeNode& tree);
+
+  /*
+   * Create empty handle
+   */
+  JsonParser();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~JsonParser();
+
+  /**
+   * Downcast an Object handle to JsonParser if it is a JsonParser.
+   * @param[in] handle Handle to an object
+   * @return A handle to a JsonParser or an uninitialized handle
+   */
+  static JsonParser DownCast( BaseHandle handle );
+
+  /*
+   * Parse the source and construct a node tree.
+   * Subsequent calls to this function will merge the trees.
+   * @param source The json source to parse
+   * @return true if parsed okay, otherwise an error.
+   */
+  bool Parse(const std::string& source);
+
+  /*
+   * Optimize memory usage by packing strings
+   */
+  void Pack(void);
+
+  /*
+   * Get the tree root node
+   */
+  const TreeNode* GetRoot() const;
+
+  /*
+   * Get the parser error flag
+   * @return true if there was a parse error
+   */
+  bool ParseError() const;
+
+  /*
+   * Get the last error position
+   * @return The character position of the most recent Parse() error
+   */
+  int GetErrorPosition() const;
+
+  /*
+   * Get the last error description
+   * @return A string description of the error
+   */
+  std::string GetErrorDescription() const;
+
+  /*
+   * Get the last error line number
+   * @return the line number of the most recent Parse() error.
+   */
+  int GetErrorLineNumber() const;
+
+  /*
+   * Get the last error line number
+   * @return the line number of the most recent Parse() error.
+   */
+  int GetErrorColumn() const;
+
+  /*
+   * Write to output stream with optional indent
+   * @param output The stream to write to
+   * @param indent The indent to use
+   */
+  void Write(std::ostream& output, int indent) const;
+
+public: // Not intended for application developers
+
+  /**
+   * This constructor is used by Dali New() methods
+   * @param [in] parser A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL JsonParser(Internal::JsonParser* parser);
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_JSON_PARSER_H
diff --git a/dali-toolkit/devel-api/builder/tree-node.cpp b/dali-toolkit/devel-api/builder/tree-node.cpp
new file mode 100644 (file)
index 0000000..f8473ad
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cctype>
+#include <cstring>
+#include <string>
+#include <algorithm>
+
+// INTERNAL INCLUDES
+#include "dali-toolkit/devel-api/builder/tree-node.h"
+#include "dali-toolkit/internal/builder/tree-node-manipulator.h"
+
+
+namespace Dali
+{
+
+bool CaseInsensitiveCharacterCompare( unsigned char a, unsigned char b )
+{
+  // Converts to lower case in the current locale.
+  return std::tolower( a ) == std::tolower( b );
+}
+
+/**
+ * return true if the lower cased ASCII strings are equal.
+ */
+bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b )
+{
+  bool result = false;
+  if( a.length() == b.length() )
+  {
+    result = std::equal( a.begin(), a.end(), b.begin(), CaseInsensitiveCharacterCompare );
+  }
+  return result;
+}
+
+namespace Toolkit
+{
+
+TreeNode::TreeNode()
+  : mName(NULL),
+    mParent(NULL),
+    mNextSibling(NULL),
+    mFirstChild(NULL),
+    mLastChild(NULL),
+    mStringValue(NULL),
+    mType(TreeNode::IS_NULL),
+    mSubstituion(false)
+{
+}
+
+TreeNode::~TreeNode()
+{
+
+}
+
+const char* TreeNode::GetName() const
+{
+  return mName;
+}
+
+TreeNode::NodeType TreeNode::GetType() const
+{
+  return mType;
+}
+
+const char* TreeNode::GetString() const
+{
+  return mStringValue;
+}
+
+bool TreeNode::HasSubstitution() const
+{
+  return mSubstituion;
+}
+
+float TreeNode::GetFloat() const
+{
+  return mFloatValue;
+}
+
+int TreeNode::GetInteger() const
+{
+  return mIntValue;
+}
+
+bool TreeNode::GetBoolean() const
+{
+  return mIntValue == 1 ? true : false;
+}
+
+size_t TreeNode::Size() const
+{
+  size_t c = 0;
+  TreeNode* p = mFirstChild;
+  while(p)
+  {
+    c++;
+    p = p->mNextSibling;
+  }
+  return c;
+}
+
+size_t TreeNode::Count(const std::string& childName) const
+{
+  const TreeNode* c = GetChild(childName);
+  if(c)
+  {
+    return c->Size();
+  }
+  else
+  {
+    return 0;
+  }
+}
+
+const TreeNode* TreeNode::GetChild(const std::string& childName) const
+{
+  const TreeNode* p = mFirstChild;
+  while(p)
+  {
+    if(p->mName && (std::string(p->mName) == childName) )
+    {
+      return p;
+    }
+    p = p->mNextSibling;
+  }
+  return NULL;
+}
+
+
+const TreeNode* TreeNode::GetChildIgnoreCase(const std::string& childName) const
+{
+  const TreeNode* p = mFirstChild;
+  while(p)
+  {
+    if(p->mName)
+    {
+      std::string nodeName(p->mName);
+      if( CaseInsensitiveStringCompare( nodeName, childName) )
+      {
+        return p;
+      }
+    }
+    p = p->mNextSibling;
+  }
+  return NULL;
+}
+
+const TreeNode* TreeNode::Find(const std::string& childName) const
+{
+  if(mName && std::string(mName) == childName)
+  {
+    return this;
+  }
+  else
+  {
+    return Internal::FindIt(childName, this);
+  }
+}
+
+TreeNode::ConstIterator TreeNode::CBegin() const
+{
+  return ConstIterator(mFirstChild);
+}
+
+
+TreeNode::ConstIterator TreeNode::CEnd() const
+{
+  return ConstIterator(NULL);
+}
+
+
+TreeNode::ConstIterator::ConstIterator(TreeNode* v) : mNode(v)
+{
+
+}
+
+TreeNode::ConstIterator& TreeNode::ConstIterator::operator ++()
+{
+  if(mNode)
+  {
+    mNode = mNode->mNextSibling;
+  }
+  else
+  {
+    mNode = NULL;
+  }
+  return *this;
+}
+
+TreeNode::ConstIterator TreeNode::ConstIterator::operator ++(int)
+{
+  TreeNode::ConstIterator ret(mNode);
+
+  if(mNode)
+  {
+    mNode = mNode->mNextSibling;
+  }
+  else
+  {
+    mNode = NULL;
+  }
+  return ret;
+}
+
+TreeNode::KeyNodePair TreeNode::ConstIterator::operator *()
+{
+  return KeyNodePair(mNode->mName, *mNode);
+}
+
+bool TreeNode::ConstIterator::operator!=( const TreeNode::ConstIterator& rhs ) const
+{
+  return mNode != rhs.mNode;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/builder/tree-node.h b/dali-toolkit/devel-api/builder/tree-node.h
new file mode 100644 (file)
index 0000000..e62c658
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef DALI_SCRIPT_TREE_NODE_H
+#define DALI_SCRIPT_TREE_NODE_H
+
+/*
+ * Copyright (c) 2019 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 <utility> // pair
+#include <iterator>
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class TreeNodeManipulator;
+
+} // namespace Internal
+
+
+/*
+ * TreeNode describes a tree of nodes.
+ * TreeNode does not own its string data which is held by a container eg JsonParser
+ * Modification operations should be done through a container.
+ */
+class DALI_TOOLKIT_API TreeNode
+{
+public:
+  /*
+   * enum typedef describing the node type
+   */
+  enum NodeType
+  {
+    IS_NULL,
+    OBJECT,
+    ARRAY,
+    STRING,
+    INTEGER,
+    FLOAT,
+    BOOLEAN
+  };
+
+  /*
+   * Non virtual destructor; this class should not be inherited from.
+   */
+  ~TreeNode();
+
+  typedef std::pair<const char*, const TreeNode&> KeyNodePair;
+
+  /*
+   * Iterator to iterate through children
+   */
+  class DALI_TOOLKIT_API ConstIterator
+  {
+  public:
+    typedef KeyNodePair          value_type;
+    typedef KeyNodePair          *pointer;
+    typedef const KeyNodePair    *const_pointer;
+    typedef KeyNodePair          &reference;
+    typedef const KeyNodePair    &const_reference;
+    typedef size_t               size_type;
+    typedef std::ptrdiff_t       difference_type;
+    typedef std::forward_iterator_tag iterator_category;
+
+    /*
+     * constructor
+     */
+    explicit ConstIterator(TreeNode* v);
+
+    /*
+     * pre increment
+     */
+    ConstIterator& operator ++();
+
+    /*
+     * post increment
+     */
+    ConstIterator operator ++(int);
+
+    /*
+     * != test
+     */
+    bool operator!=( const ConstIterator& rhs ) const;
+
+    /*
+     * pointer semantics
+     */
+    KeyNodePair operator*();
+  private:
+    TreeNode* mNode;
+  };
+
+  /*
+   * Iterate begin() over the nodes children
+   * @return a const interator
+   */
+  ConstIterator CBegin() const;
+
+  /*
+   * Iterate end()
+   * @return a const interator
+   */
+  ConstIterator CEnd() const;
+
+  /*
+   * Size (number of children)
+   * @return The number of children
+   */
+  size_t Size() const;
+
+  /*
+   * Count (the number of children of a sub child node)
+   * @param childName The name of the child to find
+   * @return the number of children in the found child
+   */
+  size_t Count(const std::string& childName) const;
+
+  /*
+   * Get the nodes name
+   * @return The nodes name
+   */
+  const char* GetName() const;
+
+  /*
+   * Gets the nodes type
+   * @return The nodes type
+   */
+  NodeType GetType() const;
+
+  /*
+   * Gets the nodes string value
+   * Only valid if the type == TreeNode::STRING
+   * @return The string value
+   */
+  const char* GetString() const;
+
+  /*
+   * Gets the nodes float value
+   * Only valid if the type == TreeNode::FLOAT
+   * @return The float value
+   */
+  float GetFloat() const;
+
+  /*
+   * Gets the nodes integer value
+   * Only valid if the type == TreeNode::INTEGER
+   * @return The integer value
+   */
+  int GetInteger() const;
+
+  /*
+   * Gets the nodes boolean value
+   * Only valid if the type == TreeNode::BOOLEAN
+   * @return The boolean value
+   */
+  bool GetBoolean() const;
+
+  /*
+   * Gets the substituion flag
+   * Only valid if the type == TreeNode::STRING
+   * @return The substitution flag
+   */
+  bool HasSubstitution() const;
+
+  /*
+   * Gets a child of the node (using case sensitive matching)
+   * @param name The name of the child.
+   * @return The child if found, else NULL
+   */
+  const TreeNode* GetChild(const std::string& name) const;
+
+  /*
+   * Gets a child of the node (using case insensitive matching)
+   * @param name The name of the child in lower case
+   * @return The child if found, else NULL
+   */
+  const TreeNode* GetChildIgnoreCase(const std::string& name) const;
+
+  /*
+   * Recursively search for a child of the node
+   * @param name The name of the child
+   * @return The child if found, else NULL
+   */
+  const TreeNode* Find(const std::string& name) const;
+
+private:
+  friend class Internal::TreeNodeManipulator;
+
+  /*
+   * Constructor
+   */
+  DALI_INTERNAL TreeNode();
+
+  // non copyable or assignable
+  DALI_INTERNAL TreeNode(TreeNode &);
+  DALI_INTERNAL TreeNode& operator=(const TreeNode&);
+
+  const char* mName;                   ///< The nodes name (if any)
+
+  TreeNode* mParent;                   ///< The nodes parent
+  TreeNode* mNextSibling;              ///< The nodes next sibling
+  TreeNode* mFirstChild;               ///< The nodes first child
+  TreeNode* mLastChild;                ///< The nodes last child
+
+  union
+  {
+    const char* mStringValue;          ///< The node string value
+    int mIntValue;                     ///< The node integer value
+    float mFloatValue;                 ///< The node float value
+  };
+
+  NodeType mType;                      ///< The nodes type
+  bool mSubstituion;                   ///< String substitution flag
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_SCRIPT_TREE_NODE_H
diff --git a/dali-toolkit/devel-api/controls/bloom-view/bloom-view.cpp b/dali-toolkit/devel-api/controls/bloom-view/bloom-view.cpp
new file mode 100644 (file)
index 0000000..2f71883
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/bloom-view/bloom-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/bloom-view/bloom-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+BloomView::BloomView()
+{
+}
+
+BloomView::~BloomView()
+{
+}
+
+BloomView::BloomView(const BloomView& handle)
+  : Control( handle )
+{
+}
+
+BloomView& BloomView::operator=(const BloomView& rhs)
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+BloomView BloomView::New()
+{
+  return Internal::BloomView::New();
+}
+
+BloomView BloomView::New( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                        const float downsampleWidthScale, const float downsampleHeightScale)
+{
+  return Internal::BloomView::New( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
+                                           downsampleWidthScale, downsampleHeightScale);
+}
+
+BloomView::BloomView( Internal::BloomView& implementation )
+: Control( implementation )
+{
+}
+
+BloomView::BloomView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::BloomView>(internal);
+}
+
+BloomView BloomView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<BloomView, Internal::BloomView>(handle);
+}
+
+void BloomView::Activate()
+{
+  GetImpl(*this).Activate();
+}
+
+void BloomView::Deactivate()
+{
+  GetImpl(*this).Deactivate();
+}
+
+Property::Index BloomView::GetBloomThresholdPropertyIndex() const
+{
+  return GetImpl(*this).GetBloomThresholdPropertyIndex();
+}
+
+Property::Index BloomView::GetBlurStrengthPropertyIndex() const
+{
+  return GetImpl(*this).GetBlurStrengthPropertyIndex();
+}
+
+Property::Index BloomView::GetBloomIntensityPropertyIndex() const
+{
+  return GetImpl(*this).GetBloomIntensityPropertyIndex();
+}
+
+Property::Index BloomView::GetBloomSaturationPropertyIndex() const
+{
+  return GetImpl(*this).GetBloomSaturationPropertyIndex();
+}
+
+Property::Index BloomView::GetImageIntensityPropertyIndex() const
+{
+  return GetImpl(*this).GetImageIntensityPropertyIndex();
+}
+
+Property::Index BloomView::GetImageSaturationPropertyIndex() const
+{
+  return GetImpl(*this).GetImageSaturationPropertyIndex();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/bloom-view/bloom-view.h b/dali-toolkit/devel-api/controls/bloom-view/bloom-view.h
new file mode 100644 (file)
index 0000000..8aa23da
--- /dev/null
@@ -0,0 +1,230 @@
+#ifndef DALI_TOOLKIT_BLOOM_VIEW_H
+#define DALI_TOOLKIT_BLOOM_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/images/pixel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+/**
+ * BloomView implementation class
+ */
+class BloomView;
+
+} // namespace Internal
+
+/**
+ *
+ * BloomView is a class for applying a render process that intensifies and blurs the bright parts of an image, bleeding bright areas into darker ones and making bright
+ * light look more realistic.
+ *
+ * Basic idea:-
+ *
+ * 1) The BloomView object will render all its child actors offscreen.\n
+ * 2) The BloomView object then extract the parts of that image that are brighter than the bloom threshold.\n
+ * 3) The BloomView object then blurs the result of step 2), which makes the brightness bleed into surrounding areas.\n
+ * 3) The BloomView object then composites the bloom from step 3) with the child actors image from step 1), using parameters that can be set by the user.
+ * The compositing is additive (image + bloom).\n
+ * 4) The BloomView object gets rendered automatically, either to the screen via the default render task, or via a RenderTask the user has created for
+ * e.g. further offscreen rendering.
+ *
+ * Fundamentally, the BloomView is simply an Actor in the normal actor tree that affects all of its children. It should be added to your Actor tree and manipulated in the
+ * normal ways. It can be considered a 'portal' in the sense that all child actors are clipped to the BloomView actor bounds.
+ *
+ * ************\n
+ * NB: It is essential to remove the BloomView from the stage and also to call Deactivate() on it when you are not using it. This will ensure that resources are freed and
+ * rendering stops.\n
+ * ************\n
+ *
+ *
+ * Usage example:-
+ *
+ *  // initialise\n
+ *  BloomView bloomView = BloomView::New();\n
+ *
+ *  // create and add some visible actors to the BloomView, all these child actors will therefore get bloomed\n
+ *  Image image = Image::New(...);\n
+ *  ImageView imageView = ImageView::New(image);\n
+ *  bloomView.Add(imageView);\n
+ *  ...\n
+ *
+ *  // Start rendering the BloomView\n
+ *  Stage::GetCurrent().Add(bloomView);\n
+ *  bloomView.Activate();\n
+ *  ...\n
+ *
+ *  // animate the strength of the bloom - this can fade between no bloom and your desired max bloom. See GetBloomIntensityPropertyIndex().\n
+ *  Animation blurAnimation = Animation::New( ... );\n
+ *  blurAnimation.AnimateTo( Property( bloomView, bloomView.GetBloomIntensityPropertyIndex() ), ... );\n
+ *  blurAnimation.Play();\n
+ *
+ *  ...\n
+ *  // Stop rendering the BloomView\n
+ *  Stage::GetCurrent().Remove(bloomView);\n
+ *  bloomView.Deactivate();\n
+ */
+class DALI_TOOLKIT_API BloomView : public Control
+{
+public:
+
+  /**
+   * Create an uninitialized BloomView; this can be initialized with BloomView::New()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  BloomView();
+
+  /**
+   * Copy constructor. Creates another handle that points to the same real object
+   */
+  BloomView(const BloomView& handle);
+
+  /**
+   * Assignment operator. Changes this handle to point to another real object
+   */
+  BloomView& operator=(const BloomView& ZoomView);
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~BloomView();
+
+  /**
+   * Downcast an Object handle to BloomView. If handle points to a BloomView the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a BloomView or an uninitialized handle
+   */
+  static BloomView DownCast( BaseHandle handle );
+
+  /**
+   * Create an initialized BloomView, using default settings. The default settings are:-\n
+   *
+   * numSamples = 5\n
+   * blurBellCurveWidth = 1.5\n
+   * renderTargetPixelFormat = RGB888\n
+   * downsampleWidthScale = 0.5\n
+   * downsampleHeightScale = 0.5\n
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BloomView New();
+
+ /**
+  * Create an initialized BloomView.
+  * @param numSamples The size of the Gaussian blur kernel (number of samples in horizontal / vertical blur directions) that is used to blur the bloom
+  * @param blurBellCurveWidth The constant controlling the Gaussian function, must be > 0.0. Controls the width of the bell curve, i.e. the look of the blur and also indirectly
+  * the amount of blurriness Smaller numbers for a tighter curve. Useful values in the range [0.5..3.0] - near the bottom of that range the curve is weighted heavily towards
+  * the centre pixel of the kernel (so there won't be much blur), near the top of that range the pixels have nearly equal weighting (closely approximating a box filter
+  * therefore). Values close to zero result in the bell curve lying almost entirely within a single pixel, in other words there will be basically no blur as neighbouring pixels
+  * have close to zero weights.
+  * @param renderTargetPixelFormat The pixel format of the render targets we are using to perform the bloom.
+  * @param downsampleWidthScale The width scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+  * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+  * @param downsampleHeightScale The height scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+  * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+  * @return A handle to a newly allocated Dali resource
+  */
+  static BloomView New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                              const float downsampleWidthScale, const float downsampleHeightScale);
+
+  /**
+   * Start rendering the BloomView. Must be called after you Add() it to the stage.
+   */
+  void Activate();
+
+  /**
+   * Stop rendering the BloomView. Must be called after you Remove() it from the stage.
+   */
+  void Deactivate();
+
+  /**
+   * Get the property index that controls the intensity threshold above which the pixels will be bloomed. Useful for animating this property.
+   * This property represents a value such that pixels brighter than this threshold will be bloomed. Values are normalised, i.e. RGB 0.0 = 0, 1.0 = 255.  Default 0.25.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetBloomThresholdPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the strength of the blur applied to the bloom. Useful for animating this property.
+   * This property represents a value in the range [0.0 - 1.0] where 0.0 is no blur and 1.0 is full blur. Default 1.0.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetBlurStrengthPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the intensity of the child actor render texture used during compositing. Useful for animating this property.
+   * This property represents a multiplier on the intensity of the bloom texture. Default 1.0.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetBloomIntensityPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the saturation of the child actor render texture used during compositing. Useful for animating this property.
+   * This property represents a multiplier on the saturation of the bloom texture. Default 1.0.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetBloomSaturationPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the intensity of the child actor render texture used during compositing. Useful for animating this property.
+   * This property represents a multiplier on the intensity of the image texture. Default 1.0.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetImageIntensityPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the saturation of the child actor render texture used during compositing. Useful for animating this property.
+   * This property represents a multiplier on the saturation of the image texture. Default 1.0.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetImageSaturationPropertyIndex() const;
+
+public:
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The UI Control implementation.
+   */
+  DALI_INTERNAL BloomView( Internal::BloomView& implementation );
+
+  /**
+   * Allows the creation of this UI Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL BloomView( Dali::Internal::CustomActor* internal );
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_BLOOM_VIEW_H
diff --git a/dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.cpp b/dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.cpp
new file mode 100644 (file)
index 0000000..506e12d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+BubbleEmitter::BubbleEmitter()
+{
+}
+
+BubbleEmitter::~BubbleEmitter()
+{
+}
+
+BubbleEmitter::BubbleEmitter( Internal::BubbleEmitter& implementation )
+: Control( implementation )
+{
+}
+
+BubbleEmitter::BubbleEmitter(Dali::Internal::CustomActor* internal)
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::BubbleEmitter>( internal );
+}
+
+BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
+                                  Dali::Texture shapeTexture,
+                                  unsigned int maximumNumberOfBubble,
+                                  const Vector2& bubbleSizeRange )
+{
+  return Internal::BubbleEmitter::New( winSize, shapeTexture, maximumNumberOfBubble, bubbleSizeRange );
+}
+
+BubbleEmitter::BubbleEmitter( const BubbleEmitter& handle )
+: Control( handle )
+{
+}
+
+BubbleEmitter& BubbleEmitter::operator=( const BubbleEmitter& rhs )
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+BubbleEmitter BubbleEmitter::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<BubbleEmitter, Internal::BubbleEmitter>( handle );
+}
+
+Actor BubbleEmitter::GetRootActor()
+{
+  return GetImpl(*this).GetRootActor();
+}
+
+void BubbleEmitter::SetBackground( Dali::Texture bgTexture, const Vector3& hsvDelta )
+{
+  GetImpl(*this).SetBackground( bgTexture, hsvDelta );
+}
+
+void BubbleEmitter::SetBubbleShape( Dali::Texture shapeTexture )
+{
+  GetImpl(*this).SetBubbleShape( shapeTexture );
+}
+
+void BubbleEmitter::SetBubbleScale( float scale )
+{
+  GetImpl(*this).SetBubbleScale( scale );
+}
+
+void BubbleEmitter::SetBubbleDensity( unsigned int density )
+{
+  GetImpl(*this).SetBubbleDensity( density );
+}
+
+void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
+{
+  GetImpl(*this).EmitBubble( animation, emitPosition, direction, displacement );
+}
+
+void BubbleEmitter::Restore()
+{
+  GetImpl(*this).Restore();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h b/dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h
new file mode 100644 (file)
index 0000000..8475b4d
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef DALI_TOOLKIT_BUBBLE_EMMITER_H
+#define DALI_TOOLKIT_BUBBLE_EMMITER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali/public-api/rendering/texture.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  /**
+   * @brief BubbleEmitter implementation class.
+   */
+  class BubbleEmitter;
+}
+
+/**
+ * @brief BubbleEmitter is used to display lots of moving bubbles on the stage.
+ *
+ * This is done by applying BubbleEffect to multiple specifically created meshActors.
+ */
+class DALI_TOOLKIT_API BubbleEmitter : public Control
+{
+public:
+
+  /**
+   * @brief Create an empty BubbleEmitter handle.
+   */
+  BubbleEmitter();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  ~BubbleEmitter();
+
+  /**
+   * @brief Create an initialized BubbleEmitter.
+   *
+   * @param[in] winSize The size of the bubble moving area, usually the same size as the background.
+   * @param[in] shapeTexture The alpha channnel of this texture defines the bubble shape.
+   * @param[in] maximumNumberOfBubble The maximum number of bubble needed.
+   * @param[in] bubbleSizeRange The size range of the bubbles; x component is the low bound, and y component is the up bound.
+   * @return The initialized BubbleEmitter object.
+   */
+  static BubbleEmitter New( const Vector2& winSize,
+                            Dali::Texture shapeTexture,
+                            unsigned int maximumNumberOfBubble,
+                            const Vector2& bubbleSizeRange );
+
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object
+   * @param[in] handle The handle to copy
+   */
+  BubbleEmitter( const BubbleEmitter& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object
+   * @param[in] rhs The object to point at
+   * @return A reference to this
+   */
+  BubbleEmitter& operator=( const BubbleEmitter& rhs );
+
+  /**
+   * @brief Downcast an Object handle to SuperBlurView.
+   *
+   * If handle points to a BubbleEmitter, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a BubbleEmitter or an uninitialized handle
+   */
+  static BubbleEmitter DownCast( BaseHandle handle );
+
+  /**
+   * @brief Return the root actor of all bubbles, should then be added to stage.
+   *
+   * @return The bubble root actor.
+   */
+  Actor GetRootActor();
+
+  /**
+   * @brief Set Background image.
+   *
+   * The bubbles pick color from this image with HSV values adjusted.
+   * @param[in] bgTexture The background texture which provide color to bubbles.
+   * @param[in] hsvDelta The hsv channel difference used to adjust the background image color.
+   *            If set these vector as Vector3::Zero, original colors are used.
+   */
+  void SetBackground( Dali::Texture bgTexture, const Vector3& hsvDelta );
+
+  /**
+   * @brief Set bubble shape.
+   *
+   * The bubble mesh is a rectangular patch, but its displayed shape is decided by the alpha channel of the shape texture.
+   * @param[in] shapeTexture The texture whose alpha channel defines the bubble shape.
+   */
+  void SetBubbleShape( Dali::Texture shapeTexture );
+
+  /**
+   * @brief Set the scale factor applied to all the bubbles.
+   *
+   * @param [in] scale The scale factor applied on bubbles.
+   */
+  void SetBubbleScale( float scale );
+
+  /**
+   * @brief Set the density of the bubble.
+   *
+   * Ideally every bubble's moving track is controlled by different uniforms in shader.
+   * To increase the density, 'density' number of bubbles are sharing one group of uniforms, but with random offsets between these bubbles.
+   * The available densities are one to nine only. The default value is five.
+   * By set the density bigger than one, instead of emit one bubble each time, a 'density' number of bubbles are emitted.
+   * @param[in] density The density of the bubble.
+   */
+  void SetBubbleDensity( unsigned int density );
+
+  /**
+   * @brief Add a bubble movement to the animation.
+   *
+   * @param[in] animation The animation reference.
+   * By passing the animation into BubbleEmitter, the animation's duration and how many bubbles contained within this animation are freely decided in App.
+   * @param[in] emitPosition The start position of the bubble movement.
+   * @param[in] direction The direction used to constrain the bubble to move in an adjacent direction around it.
+   * @param[in] displacement The displacement used to bound the moving distance of the bubble.
+   */
+  void EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement );
+
+  /**
+   * @brief Reset all the parameters controlling the bubbles after animation.
+   */
+  void Restore();
+
+public: // Not intended for developer use
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL BubbleEmitter(Internal::BubbleEmitter& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL BubbleEmitter(Dali::Internal::CustomActor* internal);
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_BUBBLE_EMMITER_H */
diff --git a/dali-toolkit/devel-api/controls/buttons/button-devel.h b/dali-toolkit/devel-api/controls/buttons/button-devel.h
new file mode 100644 (file)
index 0000000..fdb8888
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DALI_TOOLKIT_BUTTON_DEVEL_H
+#define DALI_TOOLKIT_BUTTON_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/button.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelButton
+{
+  namespace Property
+  {
+    enum Type
+    {
+      /**
+       * @brief name "labelRelativeAlignment", type STRING
+       * @details Sets the position of the the label in relation to the foreground/icon if both present
+       */
+      LABEL_RELATIVE_ALIGNMENT = Dali::Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL + 1,
+
+      /**
+       * @brief name "labelPadding", type Vector4
+       * @details Sets the padding around the text
+       */
+      LABEL_PADDING,
+
+      /**
+       * @brief name "visualPadding", type Vector4
+       * @details Sets the padding around the foreground visual
+       */
+      VISUAL_PADDING
+    };
+  } // namespace Property
+
+} // namespace DevelButton
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_BUTTON_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/buttons/toggle-button.cpp b/dali-toolkit/devel-api/controls/buttons/toggle-button.cpp
new file mode 100644 (file)
index 0000000..39f1845
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/devel-api/controls/buttons/toggle-button.h>
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/controls/buttons/toggle-button-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ToggleButton::ToggleButton()
+: Button()
+{
+}
+
+ToggleButton::ToggleButton( Internal::ToggleButton& implementation )
+: Button( implementation )
+{
+}
+
+ToggleButton::ToggleButton( const ToggleButton& toggleButton )
+: Button( toggleButton )
+{
+}
+
+ToggleButton& ToggleButton::operator=( const ToggleButton& toggleButton )
+{
+  if( &toggleButton != this )
+  {
+    Button::operator=( toggleButton );
+  }
+  return *this;
+}
+
+ToggleButton::ToggleButton( Dali::Internal::CustomActor* internal )
+: Button( internal )
+{
+  VerifyCustomActorPointer<Internal::ToggleButton>(internal);
+}
+
+ToggleButton::~ToggleButton()
+{
+}
+
+ToggleButton ToggleButton::New()
+{
+  return Internal::ToggleButton::New();
+}
+
+ToggleButton ToggleButton::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ToggleButton, Internal::ToggleButton>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/buttons/toggle-button.h b/dali-toolkit/devel-api/controls/buttons/toggle-button.h
new file mode 100644 (file)
index 0000000..93dace9
--- /dev/null
@@ -0,0 +1,223 @@
+#ifndef DALI_TOOLKIT_TOGGLE_BUTTON_H
+#define DALI_TOOLKIT_TOGGLE_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/button.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+
+class ToggleButton;
+}
+/**
+ * @addtogroup dali_toolkit_controls_buttons
+ * @{
+ */
+
+/**
+ * @brief A ToggleButton allows the user to change a setting between two or more states.
+ *
+ * By default a ToggleButton emits a Button::StateChangedSignal() signal when it's clicked.
+ *
+ * Usage example: -
+ *
+ * @code
+ *
+ * void ToggleButtonExample::Create( Application& application )
+ * {
+ *   ToggleButton button = ToggleButton::New();
+ *   button.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, Property::Array()
+ *                       .Add( "A.png" )
+ *                       .Add( "B.png" )
+ *                       .Add( "C.png" ));
+ *  or
+ *
+ *  Property::Map propertyMap1;
+ *  Vector4 testColor1( 1.f, 0.5f, 0.3f, 0.2f );
+ *  propertyMap1.Insert(Visual::Property::TYPE,  Visual::COLOR);
+ *  propertyMap1.Insert(ColorVisual::Property::MIX_COLOR,  testColor1);
+ *
+ *  Property::Map propertyMap2;
+ *  Vector4 testColor2( 0.5f, 1.f, 0.3f, 0.2f );
+ *  propertyMap2.Insert(Visual::Property::TYPE,  Visual::COLOR);
+ *  propertyMap2.Insert(ColorVisual::Property::MIX_COLOR,  testColor2);
+ *
+ *  Property::Map propertyMap3;
+ *  Vector4 testColor3( 1.f, 0.5f, 1.f, 0.2f );
+ *  propertyMap3.Insert(Visual::Property::TYPE,  Visual::COLOR);
+ *  propertyMap3.Insert(ColorVisual::Property::MIX_COLOR,  testColor3);
+ *
+ *  button.SetProperty( Toolkit::ToggleButton::Property::STATE_VISUALS, Property::Array()
+ *                       .Add( propertyMap1 )
+ *                       .Add( propertyMap2 )
+ *                       .Add( propertyMap3 ));
+ *
+ * button.SetProperty( Toolkit::ToggleButton::Property::TOOLTIPS, Property::Array()
+ *                       .Add( "STATE A" )
+ *                       .Add( "STATE B" )
+ *                       .Add( "STATE C" ));
+ *
+ *   Stage::GetCurrent().Add( button );
+ *
+ *   // Connect to button signals emitted by the button
+ *   button.ClickedSignal().Connect( this, &ToggleButtonExample::OnButtonClicked );
+ * }
+ *
+ * bool ToggleButtonExample::OnButtonClicked( Button button )
+ * {
+ *   // Do something when the button is clicked
+ *   return true;
+ * }
+ * @endcode
+ *
+ * See Button for more detail on signals and modifying states via properties.
+ */
+class DALI_TOOLKIT_API ToggleButton : public Button
+{
+public:
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Button::PROPERTY_END_INDEX + 1,    ///< Toggle button start index
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000        ///< Reserving 1000 property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the ToggleButton class.
+   */
+  struct Property
+  {
+    enum
+    {
+      /**
+       * @brief The state visual array of toggle button.
+       * @details Name "stateVisuals",  type Property::Array.
+       * It's a property array of property-maps or a property array of strings,
+       * property map expects a description of visual and
+       * string represents an image url.
+       * @note Mandatory
+       */
+      STATE_VISUALS = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The tooltips of toggle button.
+       * @details Name "tooltips",  type Property::Array.
+       * It's an array of toggle state tooltip strings.
+       * Each tooltip string should match a toggle state strictly.
+       * @note Mandatory
+       */
+      TOOLTIPS,
+
+      /**
+       * @brief The current state index of toggle button.
+       * @details Name "currentStateIndex",  type integer.
+       * It just provides a property to get current state index.
+       * @note Optional
+       * @note The index is automatically changed when toggle button is clicked.
+       */
+      CURRENT_STATE_INDEX
+    };
+  };
+
+public:
+
+  /**
+   * @brief Create an uninitialized ToggleButton; this can be initialized with ToggleButton::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  ToggleButton();
+
+  /**
+   * @brief Copy constructor.
+   * @param[in] toggleButton Handle to an object
+   */
+  ToggleButton( const ToggleButton& toggleButton );
+
+  /**
+   * @brief Assignment operator.
+   * @param[in] toggleButton Handle to an object
+   * @return A reference to this
+   */
+  ToggleButton& operator=( const ToggleButton& toggleButton );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ToggleButton();
+
+  /**
+   * @brief Create an initialized ToggleButton.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static ToggleButton New();
+
+  /**
+   * @brief Downcast a handle to ToggleButton handle.
+   *
+   * If handle points to a ToggleButton the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return handle to a ToggleButton or an uninitialized handle
+   */
+  static ToggleButton DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL ToggleButton( Internal::ToggleButton& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL ToggleButton( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOGGLE_BUTTON_H
diff --git a/dali-toolkit/devel-api/controls/control-depth-index-ranges.h b/dali-toolkit/devel-api/controls/control-depth-index-ranges.h
new file mode 100644 (file)
index 0000000..6c4ed30
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef DALI_TOOLKIT_DEVEL_CONTROL_DEPTH_INDEX_RANGES_H
+#define DALI_TOOLKIT_DEVEL_CONTROL_DEPTH_INDEX_RANGES_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/compile-time-assert.h>
+#include <dali/devel-api/actors/layer-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DepthIndex
+{
+
+// The negative value for background effect and background has been
+// chosen so that newer controls can have content without setting
+// depth index, and go in front of native controls with a background.
+// This backround negative value means that the highest possible value
+// is SIBLING_ORDER_MULTIPLIER-BACKGROUND_EFFECT-1.  The divisor of
+// 100 ensures the range fits within the sibling order range, and has
+// enough gaps to allow Control Authors to use other intermediate depths.
+
+enum Ranges
+{
+  BACKGROUND_EFFECT = -2 * DevelLayer::SIBLING_ORDER_MULTIPLIER/100,
+  BACKGROUND    =     -1 * DevelLayer::SIBLING_ORDER_MULTIPLIER/100,
+  CONTENT       =      0,
+  DECORATION    =      1 * DevelLayer::SIBLING_ORDER_MULTIPLIER/100,
+  FOREGROUND_EFFECT =  2 * DevelLayer::SIBLING_ORDER_MULTIPLIER/100
+};
+
+DALI_COMPILE_TIME_ASSERT( (unsigned int)DevelLayer::ACTOR_DEPTH_MULTIPLIER > (unsigned int)DevelLayer::SIBLING_ORDER_MULTIPLIER );
+DALI_COMPILE_TIME_ASSERT( BACKGROUND_EFFECT < BACKGROUND );
+DALI_COMPILE_TIME_ASSERT( BACKGROUND < CONTENT );
+DALI_COMPILE_TIME_ASSERT( CONTENT < DECORATION );
+DALI_COMPILE_TIME_ASSERT( DECORATION < FOREGROUND_EFFECT );
+
+} // namespace DepthIndex
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_CONTROL_DEPTH_INDEX_RANGES_H
diff --git a/dali-toolkit/devel-api/controls/control-devel.cpp b/dali-toolkit/devel-api/controls/control-devel.cpp
new file mode 100755 (executable)
index 0000000..04b13d3
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 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 "control-devel.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelControl
+{
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.RegisterVisual( index, visual );
+}
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.RegisterVisual( index, visual, depthIndex );
+}
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.RegisterVisual( index, visual, enabled );
+}
+
+void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.RegisterVisual( index, visual, enabled, depthIndex );
+}
+
+void UnregisterVisual( Internal::Control& control, Dali::Property::Index index )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.UnregisterVisual( index );
+}
+
+Toolkit::Visual::Base GetVisual( const Internal::Control& control, Dali::Property::Index index )
+{
+  const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  return controlDataImpl.GetVisual( index );
+}
+
+void EnableVisual( Internal::Control& control, Dali::Property::Index index, bool enable )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.EnableVisual( index, enable );
+}
+
+bool IsVisualEnabled( const Internal::Control& control, Dali::Property::Index index )
+{
+  const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  return controlDataImpl.IsVisualEnabled( index );
+}
+
+Dali::Animation CreateTransition( Internal::Control& control, const Toolkit::TransitionData& handle )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  return controlDataImpl.CreateTransition( handle );
+}
+
+
+void AddTransitions( Internal::Control& control,
+                     Dali::Animation animation,
+                     const Toolkit::TransitionData& transitionData )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( control );
+  controlDataImpl.AddTransitions( animation, transitionData );
+}
+
+void DoAction( Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
+{
+  Internal::Control& controlInternal = Toolkit::Internal::GetImplementation( control );
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlInternal );
+  controlDataImpl.DoAction( visualIndex, actionId, attributes );
+}
+
+void SetInputMethodContext( Internal::Control& control, InputMethodContext& inputMethodContext )
+{
+  Internal::Control::Impl::Get( control ).SetInputMethodContext( inputMethodContext );
+}
+
+VisualEventSignalType& VisualEventSignal( Control control )
+{
+  Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control );
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
+  return controlDataImpl.VisualEventSignal();
+}
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/control-devel.h b/dali-toolkit/devel-api/controls/control-devel.h
new file mode 100755 (executable)
index 0000000..04e8205
--- /dev/null
@@ -0,0 +1,300 @@
+#ifndef DALI_TOOLKIT_CONTROL_DEVEL_H
+#define DALI_TOOLKIT_CONTROL_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/input-method-context.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class TransitionData;
+
+namespace Visual
+{
+class Base;
+}
+
+namespace DevelControl
+{
+
+enum State
+{
+  NORMAL,
+  FOCUSED,
+  DISABLED
+};
+
+namespace Property
+{
+
+enum
+{
+  STYLE_NAME            = Control::Property::STYLE_NAME,
+  RESERVED_PROPERTY_01  = Control::Property::RESERVED_PROPERTY_01,
+  RESERVED_PROPERTY_02  = Control::Property::RESERVED_PROPERTY_02,
+  KEY_INPUT_FOCUS       = Control::Property::KEY_INPUT_FOCUS,
+  BACKGROUND            = Control::Property::BACKGROUND,
+  MARGIN                = Control::Property::MARGIN,
+  PADDING               = Control::Property::PADDING,
+
+  /**
+   * @brief Displays a tooltip when the control is hovered over.
+   * @details Name "tooltip", type Property::STRING, Property::ARRAY or Property::MAP.
+   *          If Property::STRING, then the style specified in the stylesheet is used.
+   *          If Property::ARRAY of Visuals then all are displayed in one row.
+   *          If Property::MAP, then it should be a map of Tooltip properties.
+   * @note The tooltip is only activated if display content is received, i.e. a string (text) or visual to show.
+   *       The rest is used to just build up the style of the tooltip (i.e. background, text color/point-size etc.)
+   * @note When retrieved, a Property::MAP is returned.
+   * @see Toolkit::Tooltip
+   */
+  TOOLTIP = PADDING + 1,
+
+  /**
+   * @brief The current state of the control.
+   * @details Name "state", type DevelControl::State ( Property::INTEGER ) or Property::STRING
+   *
+   * @see DevelControl::State
+   */
+  STATE = PADDING + 2,
+
+  /**
+   * @brief The current sub state of the control.
+   * @details Name "subState", type Property::INTEGER or Property::STRING. The enumeration used is dependent on the derived control.
+   *
+   * @see DevelControl::State
+   */
+  SUB_STATE = PADDING + 3,
+
+  /**
+   * @brief The actor ID of the left focusable control.
+   * @details Name "leftFocusableActorId", type Property::INTEGER.
+   *
+   */
+  LEFT_FOCUSABLE_ACTOR_ID = PADDING + 4,
+
+  /**
+   * @brief The actor ID of the right focusable control.
+   * @details Name "rightFocusableActorId", type Property::INTEGER.
+   *
+   */
+  RIGHT_FOCUSABLE_ACTOR_ID = PADDING + 5,
+
+  /**
+   * @brief The actor ID of the up focusable control.
+   * @details Name "upFocusableActorId", type Property::INTEGER.
+   *
+   */
+  UP_FOCUSABLE_ACTOR_ID = PADDING + 6,
+
+  /**
+   * @brief The actor ID of the down focusable control.
+   * @details Name "downFocusableActorId", type Property::INTEGER.
+   *
+   */
+  DOWN_FOCUSABLE_ACTOR_ID = PADDING + 7,
+
+  /**
+   * @brief The shadow of the control.
+   * @details Name "shadow", type Property::MAP.
+   */
+  SHADOW = PADDING + 8
+};
+
+} // namespace Property
+
+/**
+ * @brief Register a visual by Property Index.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ *
+ * @note Derived class should not call visual.SetOnStage(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
+ *       Use below API with enabled set to false if derived class wishes to control when visual is staged.
+ * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
+ * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ */
+DALI_TOOLKIT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual );
+
+/**
+ * @brief Register a visual by Property Index with a depth index.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ * @param[in] depthIndex The visual's depth-index is set to this
+ *
+ * @note Derived class should not call visual.SetOnStage(actor). It is the responsibility of the base class to connect/disconnect registered visual to stage.
+ *       Use below API with enabled set to false if derived class wishes to control when visual is staged.
+ *
+ * @see Visual::Base::GetDepthIndex()
+ * @see Visual::Base::SetDepthIndex()
+ */
+DALI_TOOLKIT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, int depthIndex );
+
+/**
+ * @brief Register a visual by Property Index with the option of enabling/disabling it.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ * @param[in] enabled false if derived class wants to control when visual is set on stage.
+ *
+ * @note If the depth-index is not set on the visual, then it is set to be above the currently registered visuals.
+ * @note If replacing a visual, then the depth-index of the visual being replaced is used for the visual.
+ *
+ * @see EnableVisual()
+ */
+DALI_TOOLKIT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled );
+
+/**
+ * @brief Register a visual by Property Index with a depth index with the option of enabling/disabling it.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ * @param[in] visual The visual to register
+ * @param[in] enabled false if derived class wants to control when visual is set on stage.
+ * @param[in] depthIndex The visual's depth-index is set to this
+ *
+ * @see EnableVisual()
+ * @see Visual::Base::GetDepthIndex()
+ * @see Visual::Base::SetDepthIndex()
+ */
+DALI_TOOLKIT_API void RegisterVisual( Internal::Control& control, Dali::Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex );
+
+/**
+ * @brief Erase the entry matching the given index from the list of registered visuals
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual, used to reference visual
+ */
+DALI_TOOLKIT_API void UnregisterVisual( Internal::Control& control, Dali::Property::Index index );
+
+/**
+ * @brief Retrieve the visual associated with the given property index.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual.
+ * @return The registered visual if exist, otherwise empty handle.
+ * @note For managing object life-cycle, do not store the returned visual as a member which increments its reference count.
+ */
+DALI_TOOLKIT_API Toolkit::Visual::Base GetVisual( const Internal::Control& control, Dali::Property::Index index );
+
+/**
+ * @brief Sets the given visual to be displayed or not when parent staged.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual
+ * @param[in] enable flag to set enabled or disabled.
+ */
+DALI_TOOLKIT_API void EnableVisual( Internal::Control& control, Dali::Property::Index index, bool enable );
+
+/**
+ * @brief Queries if the given visual is to be displayed when parent staged.
+ *
+ * @param[in] control The control
+ * @param[in] index The Property index of the visual
+ * @return bool whether visual is enabled or not
+ */
+DALI_TOOLKIT_API bool IsVisualEnabled( const Internal::Control& control, Dali::Property::Index index );
+
+
+/**
+ * @brief Add a transition effect on the control to the given animation
+ *
+ * Only generates an animator if the properties described in the transition
+ * data are staged (e.g. the visual is Enabled and the control is on stage).
+ * Otherwise the target values are stored, and will get set onto the properties
+ * when the visual is next staged.
+ *
+ * @param[in] control The control
+ * @param[in] animation The Animation to add valid transitions to
+ * @param[in] transitionData The transition data describing the effect to create
+ */
+DALI_TOOLKIT_API void AddTransitions( Internal::Control& control,
+                                      Dali::Animation animation,
+                                      const Toolkit::TransitionData& transitionData );
+
+/**
+ * @brief Create a transition effect on the control.
+ *
+ * Only generates an animation if the properties described in the transition
+ * data are staged (e.g. the visual is Enabled and the control is on stage).
+ * Otherwise the target values are stored, and will get set onto the properties
+ * when the visual is next staged.
+ *
+ * @param[in] control The control
+ * @param[in] transitionData The transition data describing the effect to create
+ * @return A handle to an animation defined with the given effect, or an empty
+ * handle if no properties match.
+ */
+DALI_TOOLKIT_API Dali::Animation CreateTransition( Internal::Control& control,
+                                                   const Toolkit::TransitionData& transitionData );
+
+/**
+ * @brief Perform an action on a visual registered to this control.
+ *
+ * Visuals will have actions, this API is used to perform one of these actions with the given attributes.
+ *
+ * @param[in] control The control.
+ * @param[in] visualIndex The Property index of the visual.
+ * @param[in] actionId The action to perform.  See Visual to find supported actions.
+ * @param[in] attributes Optional attributes for the action.
+ */
+DALI_TOOLKIT_API void DoAction( Control& control, Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes );
+
+/**
+ * @brief Set input method context.
+ *
+ * @param[in] control The control.
+ * @param[in] inputMethodContext The input method context.
+ */
+DALI_TOOLKIT_API void SetInputMethodContext( Internal::Control& control, InputMethodContext& inputMethodContext );
+
+/**
+ * @brief Visual Event signal type
+ */
+using VisualEventSignalType = Signal< void ( Control, Dali::Property::Index, Dali::Property::Index ) >;
+
+/**
+ * @brief This signal is emitted when a visual has an event to notify.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Control control, Dali::Property::Index visualIndex, Dali::Property::Index signalId );
+ * @endcode
+ * @return The signal to connect to
+ */
+DALI_TOOLKIT_API VisualEventSignalType& VisualEventSignal( Control control );
+
+} // namespace DevelControl
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp b/dali-toolkit/devel-api/controls/control-wrapper-impl.cpp
new file mode 100755 (executable)
index 0000000..1a2ec4b
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/actors/custom-actor-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  // empty handle as we cannot create control wrapper
+  return BaseHandle();
+}
+
+// Setup type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ControlWrapper, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+}
+
+/*
+ * Implementation.
+ */
+
+Dali::Toolkit::ControlWrapper ControlWrapper::New( const std::string& typeName, ControlWrapper* controlWrapper )
+{
+  ControlWrapperPtr wrapper( controlWrapper );
+
+  // Pass ownership to CustomActor via derived handle.
+  Dali::Toolkit::ControlWrapper handle( *wrapper );
+
+  // Second-phase initialisation of the implementation.
+  // This can only be done after the CustomActor connection has been made.
+  wrapper->Initialize();
+
+  // Different types of C# custom view registered themselves using type registry,
+  // but their type names are registered per type not per instance, so they still
+  // have the same wrong type name in native side when type registry queries the
+  // unique type name of each instance using typeid() because of the binding.
+  // Therefore, we have to link each instance with its correct type info if already
+  // pre-registered.
+
+  TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( typeName );
+  if(typeInfo)
+  {
+    Dali::DevelHandle::SetTypeInfo( handle, typeInfo );
+  }
+
+  return handle;
+}
+
+ControlWrapper::ControlWrapper( CustomControlBehaviour behaviourFlags )
+: Control( static_cast< ControlBehaviour >( behaviourFlags ) )
+{
+}
+
+ControlWrapper::~ControlWrapper()
+{
+}
+
+void ControlWrapper::RelayoutRequest()
+{
+  CustomActorImpl::RelayoutRequest();
+}
+
+float ControlWrapper::GetHeightForWidthBase( float width )
+{
+  return CustomActorImpl::GetHeightForWidthBase( width );
+}
+
+float ControlWrapper::GetWidthForHeightBase( float height )
+{
+  return CustomActorImpl::GetWidthForHeightBase( height );
+}
+
+float ControlWrapper::CalculateChildSizeBase( const Dali::Actor& child, Dimension::Type dimension )
+{
+  return CustomActorImpl::CalculateChildSizeBase( child, dimension );
+}
+
+bool ControlWrapper::RelayoutDependentOnChildrenBase( Dimension::Type dimension )
+{
+  return CustomActorImpl::RelayoutDependentOnChildrenBase( dimension );
+}
+
+void ControlWrapper::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
+{
+  DevelControl::RegisterVisual( *this, index, visual );
+}
+
+void ControlWrapper::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
+{
+  DevelControl::RegisterVisual( *this, index, visual, depthIndex );
+}
+
+void ControlWrapper::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
+{
+  DevelControl::RegisterVisual( *this, index, visual, enabled );
+}
+
+void ControlWrapper::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
+{
+  DevelControl::RegisterVisual( *this, index, visual, enabled, depthIndex );
+}
+
+void ControlWrapper::UnregisterVisual( Property::Index index )
+{
+  DevelControl::UnregisterVisual( *this, index );
+}
+
+Toolkit::Visual::Base ControlWrapper::GetVisual( Property::Index index ) const
+{
+  return DevelControl::GetVisual( *this, index );
+}
+
+void ControlWrapper::EnableVisual( Property::Index index, bool enable )
+{
+  DevelControl::EnableVisual( *this, index, enable );
+}
+
+bool ControlWrapper::IsVisualEnabled( Property::Index index ) const
+{
+  return DevelControl::IsVisualEnabled( *this, index );
+}
+
+Dali::Animation ControlWrapper::CreateTransition( const Toolkit::TransitionData& handle )
+{
+  return DevelControl::CreateTransition( *this, handle );
+}
+
+void ControlWrapper::ApplyThemeStyle()
+{
+  Toolkit::StyleManager styleManager = StyleManager::Get();
+
+  // if style manager is available
+  if( styleManager )
+  {
+    StyleManager& styleManagerImpl = GetImpl( styleManager );
+
+    // Apply the current style
+    styleManagerImpl.ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+  }
+}
+
+Dali::TypeInfo ControlWrapper::GetTypeInfo()
+{
+  return DevelCustomActor::GetTypeInfo(Self());
+}
+
+void ControlWrapper::EmitKeyInputFocusSignal( bool focusGained )
+{
+  Control::EmitKeyInputFocusSignal( focusGained );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/control-wrapper-impl.h b/dali-toolkit/devel-api/controls/control-wrapper-impl.h
new file mode 100755 (executable)
index 0000000..10130f7
--- /dev/null
@@ -0,0 +1,223 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CONTROL_WRAPPER_H
+#define DALI_TOOLKIT_INTERNAL_CONTROL_WRAPPER_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/control-wrapper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class TransitionData;
+
+namespace Visual
+{
+class Base;
+}
+
+namespace Internal
+{
+
+class ControlWrapper;
+
+typedef IntrusivePtr< ControlWrapper > ControlWrapperPtr;
+
+/**
+ * @copydoc Toolkit::ControlWrapper
+ */
+class DALI_TOOLKIT_API ControlWrapper : public Control
+{
+public:
+
+  // Flags for the constructor
+  enum CustomControlBehaviour
+  {
+    CONTROL_BEHAVIOUR_DEFAULT            = Control::CONTROL_BEHAVIOUR_DEFAULT,
+    DISABLE_SIZE_NEGOTIATION             = CustomActorImpl::DISABLE_SIZE_NEGOTIATION,
+    REQUIRES_KEYBOARD_NAVIGATION_SUPPORT = Control::REQUIRES_KEYBOARD_NAVIGATION_SUPPORT,
+    DISABLE_STYLE_CHANGE_SIGNALS         = Control::DISABLE_STYLE_CHANGE_SIGNALS,
+
+    LAST_CONTROL_BEHAVIOUR_FLAG
+  };
+
+  static const int CONTROL_BEHAVIOUR_FLAG_COUNT = Log< LAST_CONTROL_BEHAVIOUR_FLAG - 1 >::value + 1;      ///< Total count of flags
+
+  /**
+   * @brief Control constructor
+   *
+   * @param[in] behaviourFlags Behavioural flags from CustomControlBehaviour enum
+   */
+  ControlWrapper( CustomControlBehaviour behaviourFlags );
+
+  /**
+   * Create a new ControlWrapper.
+   *
+   * @param[in] typeName The name of the type that is registered with this control
+   * @param[in] controlWrapper The implementation of this control
+   *
+   * @return A public handle to the newly allocated ControlWrapper.
+   */
+  static Dali::Toolkit::ControlWrapper New( const std::string& typeName, ControlWrapper* controlWrapper );
+
+public: // From CustomActorImpl
+
+  // Size negotiation helpers
+
+  /**
+   * @copydoc Dali::CustomActorImpl::RelayoutRequest()
+   */
+  void RelayoutRequest();
+
+  /**
+   * @copydoc Dali::CustomActorImpl::GetHeightForWidthBase()
+   */
+  float GetHeightForWidthBase( float width );
+
+  /**
+   * @copydoc Dali::CustomActorImpl::GetWidthForHeightBase()
+   */
+  float GetWidthForHeightBase( float height );
+
+  /**
+   * @copydoc Dali::CustomActorImpl::CalculateChildSizeBase()
+   */
+  float CalculateChildSizeBase( const Dali::Actor& child, Dimension::Type dimension );
+
+  /**
+   * @copydoc Dali::CustomActorImpl::RelayoutDependentOnChildrenBase()
+   */
+  bool RelayoutDependentOnChildrenBase( Dimension::Type dimension = Dimension::ALL_DIMENSIONS );
+
+public: // From Control
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::UnregisterVisual()
+   */
+  void UnregisterVisual( Property::Index index );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::GetVisual()
+   */
+  Toolkit::Visual::Base GetVisual( Property::Index index ) const;
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::EnableVisual()
+   */
+  void EnableVisual( Property::Index index, bool enable );
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::IsVisualEnabled()
+   */
+  bool IsVisualEnabled( Property::Index index ) const;
+
+  /**
+   * @ref Dali::Toolkit::DevelControl::CreateTransition()
+   */
+  Dali::Animation CreateTransition( const Toolkit::TransitionData& transitionData );
+
+  /**
+   * @copydoc Dali::Toolkit::Internal::Control::EmitKeyInputFocusSignal()
+   */
+  void EmitKeyInputFocusSignal( bool focusGained );
+
+  /**
+   * @brief Apply the current style
+   *
+   * This method is called after the Control has been initialized.
+   *
+   */
+  void ApplyThemeStyle();
+
+public:
+  /**
+   * Enable access to non-native type info from native side
+   * @return The type info that was registered on this type
+   */
+  Dali::TypeInfo GetTypeInfo();
+
+protected:
+
+  /**
+   * Protected Destructor
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ControlWrapper();
+
+private:
+
+  /// @cond internal
+  /// Undefined.
+  DALI_INTERNAL ControlWrapper( const ControlWrapper& );
+
+  /// Undefined.
+  DALI_INTERNAL ControlWrapper& operator=( const ControlWrapper& rhs );
+  /// @endcond
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ControlWrapper& GetControlWrapperImpl( Toolkit::ControlWrapper& publicObject )
+{
+  DALI_ASSERT_ALWAYS( publicObject );
+
+  Dali::RefObject& handle = publicObject.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ControlWrapper&>( handle );
+}
+
+inline const Toolkit::Internal::ControlWrapper& GetControlWrapperImpl( const Toolkit::ControlWrapper& publicObject )
+{
+  DALI_ASSERT_ALWAYS( publicObject );
+
+  const Dali::RefObject& handle = publicObject.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ControlWrapper&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CONTROL_WRAPPER_H
diff --git a/dali-toolkit/devel-api/controls/control-wrapper.cpp b/dali-toolkit/devel-api/controls/control-wrapper.cpp
new file mode 100644 (file)
index 0000000..0c6be01
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/control-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ControlWrapper
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ControlWrapper ControlWrapper::New( const std::string& typeName, Internal::ControlWrapper& implementation )
+{
+  return Internal::ControlWrapper::New( typeName, &implementation );
+}
+
+ControlWrapper::ControlWrapper()
+{
+}
+
+ControlWrapper::ControlWrapper( const ControlWrapper& handle )
+: Control( handle )
+{
+}
+
+ControlWrapper& ControlWrapper::operator=( const ControlWrapper& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+ControlWrapper::ControlWrapper( Internal::ControlWrapper& implementation )
+: Control( implementation )
+{
+}
+
+ControlWrapper::ControlWrapper( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ControlWrapper>( internal );
+}
+
+ControlWrapper::~ControlWrapper()
+{
+}
+
+ControlWrapper ControlWrapper::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ControlWrapper, Internal::ControlWrapper>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/control-wrapper.h b/dali-toolkit/devel-api/controls/control-wrapper.h
new file mode 100644 (file)
index 0000000..fecab4f
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_TOOLKIT_CONTROL_WRAPPER_H
+#define DALI_TOOLKIT_CONTROL_WRAPPER_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ControlWrapper;
+}
+
+/**
+ * @brief ControlWrapper is a base class for custom UI controls developed in managed code (i.e. C#.NET).
+ *
+ * The implementation of the ControlWrapper must be supplied; see Internal::ControlWrapper for more details.
+ */
+class DALI_TOOLKIT_API ControlWrapper : public Control
+{
+
+public:
+
+  /**
+   * @brief Create a new instance of a ControlWrapper.
+   *
+   * @param[in] typeName The name of the type that is registered with this control
+   * @param[in] implementation The implementation of this control
+   *
+   * @return A handle to a new ControlWrapper.
+   */
+  static ControlWrapper New( const std::string& typeName, Internal::ControlWrapper& implementation );
+
+  /**
+   * @brief Creates an empty ControlWrapper handle.
+   */
+  ControlWrapper();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ControlWrapper();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object
+   * @param[in] handle Handle to the copied object
+   */
+  ControlWrapper( const ControlWrapper& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object
+   * @param[in] handle Handle to the object
+   * @return A reference to this
+   */
+  ControlWrapper& operator=( const ControlWrapper& handle );
+
+  /**
+   * @brief Downcast an Object handle to ControlWrapper.
+   *
+   * If handle points to a ControlWrapper the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a ControlWrapper or an uninitialized handle
+   */
+  static ControlWrapper DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  ControlWrapper( Internal::ControlWrapper& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit ControlWrapper( Dali::Internal::CustomActor* internal );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_WRAPPER_H
diff --git a/dali-toolkit/devel-api/controls/effects-view/effects-view.cpp b/dali-toolkit/devel-api/controls/effects-view/effects-view.cpp
new file mode 100644 (file)
index 0000000..2abab5a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/effects-view/effects-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/effects-view/effects-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+EffectsView EffectsView::New( EffectType type )
+{
+  EffectsView effectsView = Internal::EffectsView::New();
+  GetImpl(effectsView).SetType( type );
+  return effectsView;
+}
+
+EffectsView::EffectsView()
+{
+}
+
+EffectsView::EffectsView( const EffectsView& handle )
+: Control( handle )
+{
+}
+
+EffectsView& EffectsView::operator=( const EffectsView& rhs )
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+EffectsView EffectsView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<EffectsView, Internal::EffectsView>(handle);
+}
+
+EffectsView::~EffectsView()
+{
+}
+
+EffectsView::EffectType EffectsView::GetType() const
+{
+  return GetImpl(*this).GetType();
+}
+
+void EffectsView::Refresh()
+{
+  GetImpl(*this).Refresh();
+}
+
+void EffectsView::SetRefreshOnDemand( bool onDemand )
+{
+  GetImpl(*this).SetRefreshOnDemand( onDemand );
+}
+
+void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
+{
+  GetImpl(*this).SetPixelFormat( pixelFormat );
+}
+
+void EffectsView::SetBackgroundColor( const Vector4& color )
+{
+  GetImpl(*this).SetBackgroundColor(color);
+}
+
+Vector4 EffectsView::GetBackgroundColor() const
+{
+  return GetImpl(*this).GetBackgroundColor();
+}
+
+
+EffectsView::EffectsView( Internal::EffectsView& implementation )
+: Control( implementation )
+{
+}
+
+EffectsView::EffectsView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::EffectsView>(internal);
+}
+
+
+} //namespace Toolkit
+
+} //namespace Dali
diff --git a/dali-toolkit/devel-api/controls/effects-view/effects-view.h b/dali-toolkit/devel-api/controls/effects-view/effects-view.h
new file mode 100644 (file)
index 0000000..7079bd9
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_TOOLKIT_EFFECTS_VIEW_H
+#define DALI_TOOLKIT_EFFECTS_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/images/frame-buffer-image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class EffectsView;
+
+} // namespace Internal
+
+/**
+ * EffectsView: Applies an effect to a tree of actors
+ *
+ * Example usage: Applying an emboss effect
+ * ...
+ * EffectsView effectsView = EffectsView::New( Toolkit::EffectsView::EMBOSS );
+ *
+ * // set position and format
+ * effectsView.SetParentOrigin( ParentOrigin::CENTER );
+ * effectsView.SetSize( Vector2( width, height) );
+ * effectsView.SetPixelFormat( Pixel::RGBA8888 );
+ *
+ * // set effect type and properties
+ * effectsView.SetProperty( effectsView.GetEffectSizePropertyIndex(), static_cast< float >( shadowSize ) );
+ * effectsView.SetProperty( effectsView.GetEffectOffsetPropertyIndex(), Vector3( shadowDistance.x, shadowDistance.y, 0.0f ) );
+ * effectsView.SetProperty( effectsView.GetEffectColorPropertyIndex(), shadowColor );
+ *
+ * // Render once
+ * effectsView.SetRefreshOnDemand( true );
+ *
+ * // optionally set a clear color
+ * effectsView.SetBackgroundColor( Vector4( 0.0f, 0.0f, 0.0f, 0.0f ) );
+ */
+class DALI_TOOLKIT_API EffectsView : public Control
+{
+public:
+
+  enum EffectType
+  {
+    DROP_SHADOW,
+    EMBOSS,
+    INVALID_TYPE
+  };
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,  ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,              ///< Reserve property indices @SINCE_1_0.0
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,        ///< @SINCE_1_1.18
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000  ///< Reserve animatable property indices, @SINCE_1_1.18
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the EffectsView class.
+   */
+  struct Property
+  {
+    enum
+    {
+      // Event side properties
+      EFFECT_SIZE = PROPERTY_START_INDEX,              ///< name "effectSize", type INTEGER
+
+      // Animatable properties
+      EFFECT_OFFSET = ANIMATABLE_PROPERTY_START_INDEX, ///< name "effectOffset", type VECTOR3
+      EFFECT_COLOR,                                    ///< name "effectColor", type VECTOR4
+    };
+  };
+
+public:
+
+  /**
+   * Create an EffectsView object with default configuration
+   * @param[in] type The type of effect to be performed by the EffectView.
+   *                 A member of the EffectType enumeration.
+   */
+  static EffectsView New( EffectType type );
+
+  /**
+   * Create an uninitialized EffectsView. Only derived versions can be instantiated.
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  EffectsView();
+
+  /**
+   * Copy constructor.
+   */
+  EffectsView( const EffectsView& handle );
+
+  /**
+   * Assignment operator.
+   */
+  EffectsView& operator=( const EffectsView& rhs );
+
+  /**
+   * Downcast an Object handle to EffectsView. If handle points to a EffectsView the
+   * downcast produces a valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a EffectsView or an uninitialized handle
+   */
+  static EffectsView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~EffectsView();
+
+public:
+
+  /**
+   * Get the effect type
+   * @return The type of effect performed by the EffectView. A member of the EffectType enumeration.
+   */
+  EffectType GetType() const;
+
+  /**
+   * Refresh/Redraw the effect
+   */
+  void Refresh();
+
+  /**
+   * Set refresh mode
+   * @param[in] onDemand Set true to enable on demand rendering, call Refresh() whenever a render is required.
+   *                     Set false to render each frame. (EffectsView refresh mode is set to continuous by default).
+   */
+  void SetRefreshOnDemand( bool onDemand );
+
+   /**
+    * Set the pixel format for the output
+    * @param[in] pixelFormat The pixel format for the output
+    */
+   void SetPixelFormat( Pixel::Format pixelFormat );
+
+   /**
+    * Set background color for the view. The background will be filled with this color.
+    * @param[in] color The background color.
+    */
+   void SetBackgroundColor( const Vector4& color );
+
+   /**
+    * Get the background color.
+    * @return The background color.
+    */
+   Vector4 GetBackgroundColor() const;
+
+public: // Not intended for application developers
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL EffectsView( Internal::EffectsView& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL EffectsView( Dali::Internal::CustomActor* internal );
+
+}; // class EffectsView
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_EFFECTS_VIEW_H
diff --git a/dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.cpp b/dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.cpp
new file mode 100644 (file)
index 0000000..3d71e4b
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+GaussianBlurView::GaussianBlurView()
+{
+}
+
+GaussianBlurView::~GaussianBlurView()
+{
+}
+
+GaussianBlurView::GaussianBlurView(const GaussianBlurView& handle)
+  : Control( handle )
+{
+}
+
+GaussianBlurView& GaussianBlurView::operator=(const GaussianBlurView& rhs)
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+GaussianBlurView GaussianBlurView::New()
+{
+  return Internal::GaussianBlurView::New();
+}
+
+GaussianBlurView GaussianBlurView::New( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                        const float downsampleWidthScale, const float downsampleHeightScale,
+                                        bool blurUserImage)
+{
+  return Internal::GaussianBlurView::New( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
+                                           downsampleWidthScale, downsampleHeightScale,
+                                           blurUserImage);
+}
+
+GaussianBlurView::GaussianBlurView( Internal::GaussianBlurView& implementation )
+: Control( implementation )
+{
+}
+
+GaussianBlurView::GaussianBlurView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::GaussianBlurView>(internal);
+}
+
+GaussianBlurView GaussianBlurView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<GaussianBlurView, Internal::GaussianBlurView>(handle);
+}
+
+void GaussianBlurView::Add(Actor child)
+{
+  GetImpl(*this).Add(child);
+}
+
+void GaussianBlurView::Remove(Actor child)
+{
+  GetImpl(*this).Remove(child);
+}
+
+void GaussianBlurView::Activate()
+{
+  GetImpl(*this).Activate();
+}
+
+void GaussianBlurView::ActivateOnce()
+{
+  GetImpl(*this).ActivateOnce();
+}
+
+void GaussianBlurView::Deactivate()
+{
+  GetImpl(*this).Deactivate();
+}
+
+void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
+{
+  GetImpl(*this).SetUserImageAndOutputRenderTarget(inputImage, outputRenderTarget);
+}
+
+Property::Index GaussianBlurView::GetBlurStrengthPropertyIndex() const
+{
+  return GetImpl(*this).GetBlurStrengthPropertyIndex();
+}
+
+FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
+{
+  return GetImpl(*this).GetBlurredRenderTarget();
+}
+
+void GaussianBlurView::SetBackgroundColor( const Vector4& color )
+{
+  GetImpl(*this).SetBackgroundColor(color);
+}
+
+Vector4 GaussianBlurView::GetBackgroundColor() const
+{
+  return GetImpl(*this).GetBackgroundColor();
+}
+
+GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
+{
+  return GetImpl(*this).FinishedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h b/dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h
new file mode 100644 (file)
index 0000000..9b7824c
--- /dev/null
@@ -0,0 +1,327 @@
+#ifndef DALI_TOOLKIT_GAUSSIAN_BLUR_EFFECT_H
+#define DALI_TOOLKIT_GAUSSIAN_BLUR_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/render-tasks/render-task.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+/**
+ * GaussianBlurView implementation class
+ */
+class GaussianBlurView;
+
+/**
+ * BloomView implementation class - requires access to private methods
+ */
+class BloomView;
+
+} // namespace Internal
+/**
+ * @addtogroup dali_toolkit_controls_gaussian_blur_view
+ * @{
+ */
+
+/**
+ * @brief
+ * GaussianBlurView is a class for applying a render process that blurs an image.
+ *
+ * Basic idea:-
+ *
+ * 1) The GaussianBlurView object will render all its child actors offscreen.\n
+ * 2) The GaussianBlurView object then blurs the result of step 1), using a two pass separated Gaussian blur.\n
+ * 3) The GaussianBlurView object then composites the blur from step 2) with the child actors image from step 1). See GetBlurStrengthPropertyIndex() for more info.\n
+ * 4) The GaussianBlurView object gets rendered automatically, either to the screen via the default render task, or via a RenderTask the user has created for
+ * e.g. further offscreen rendering.
+ *
+ * Fundamentally, the GaussianBlurView is simply an Actor in the normal actor tree that affects all of its children. It should be added to your Actor tree and manipulated in the
+ * normal ways. It can be considered a 'portal' in the sense that all child actors are clipped to the GaussianBlurView actor bounds.
+ *
+ * ************\n
+ * NB: It is essential to remove the GaussianBlurView from the stage and also to call Deactivate() on it when you are not using it. This will ensure that resources are freed and
+ * rendering stops.\n
+ * ************\n
+ *
+ * Usage example:-
+ *
+ * @code
+ *  // Initialise
+ *  GaussianBlurView gaussianBlurView = GaussianBlurView::New();
+ *
+ *  // Create and add some visible actors to the GaussianBlurView, all these child actors will therefore get blurred.
+ *  Image image = Image::New(...);
+ *  ImageView imageView = ImageView::New(image);
+ *  gaussianBlurView.Add(imageView);
+ *  ...
+ *
+ *  // Start rendering the GaussianBlurView
+ *  Stage::GetCurrent().Add(gaussianBlurView);
+ *  gaussianBlurView.Activate();
+ *  ...
+ *
+ *  // Animate the strength of the blur - this can fade between no blur and full blur. See GetBlurStrengthPropertyIndex().
+ *  Animation blurAnimation = Animation::New( ... );
+ *  blurAnimation.AnimateTo( Property( gaussianBlurView, gaussianBlurView.GetBlurStrengthPropertyIndex() ), ... );
+ *  blurAnimation.Play();
+ *
+ *  ...
+ *  // Stop rendering the GaussianBlurView
+ *  Stage::GetCurrent().Remove(gaussianBlurView);
+ *  gaussianBlurView.Deactivate();
+ * @endcode
+ * @SINCE_1_0.0
+ * @remarks This is an experimental feature and might not be supported in the next release.
+ * We do recommend not to use this class.
+ */
+class DALI_TOOLKIT_API GaussianBlurView : public Control
+{
+public:
+  /**
+   * @brief Signal type for notifications
+   * @SINCE_1_0.0
+   */
+  typedef Signal< void (GaussianBlurView source) > GaussianBlurViewSignal;
+
+  /**
+   * @brief Create an uninitialized GaussianBlurView; this can be initialized with GaussianBlurView::New().
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  GaussianBlurView();
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object.
+   * @SINCE_1_0.0
+   */
+  GaussianBlurView(const GaussianBlurView& handle);
+
+  /**
+   * @brief Assignment operator. Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   */
+  GaussianBlurView& operator=(const GaussianBlurView& ZoomView);
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~GaussianBlurView();
+
+  /**
+   * @brief Downcast a handle to GaussianBlurView handle.
+   *
+   * If handle points to a GaussianBlurView the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a GaussianBlurView or an uninitialized handle
+   */
+  static GaussianBlurView DownCast( BaseHandle handle );
+
+  /**
+  * @brief Create an initialized GaussianBlurView, using default settings. The default settings are:-\n
+  *
+  * numSamples = 5\n
+  * blurBellCurveWidth = 1.5\n
+  * renderTargetPixelFormat = RGB888\n
+  * downsampleWidthScale = 0.5\n
+  * downsampleHeightScale = 0.5\n
+  * blurUserImage = false
+  * @SINCE_1_0.0
+  * @return A handle to a newly allocated Dali resource
+  */
+  static GaussianBlurView New();
+
+  /**
+  * @brief Create an initialized GaussianBlurView.
+  * @SINCE_1_0.0
+  * @param numSamples The size of the Gaussian blur kernel (number of samples in horizontal / vertical blur directions).
+  * @param blurBellCurveWidth The constant controlling the Gaussian function, must be > 0.0. Controls the width of the bell curve, i.e. the look of the blur and also indirectly
+  * the amount of blurriness Smaller numbers for a tighter curve. Useful values in the range [0.5..3.0] - near the bottom of that range the curve is weighted heavily towards
+  * the centre pixel of the kernel (so there won't be much blur), near the top of that range the pixels have nearly equal weighting (closely approximating a box filter
+  * therefore). Values close to zero result in the bell curve lying almost entirely within a single pixel, in other words there will be basically no blur as neighbouring pixels
+  * have close to zero weights.
+  * @param renderTargetPixelFormat The pixel format of the render targets we are using to perform the blur.
+  * @param downsampleWidthScale The width scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+  * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+  * @param downsampleHeightScale The height scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+  * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+  * @param blurUserImage If this is set to true, the GaussianBlurView object will operate in a special mode that allows the user to blur an image of their choice. See
+  * SetUserImageAndOutputRenderTarget().
+  * @return A handle to a newly allocated Dali resource
+  */
+  static GaussianBlurView New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                              const float downsampleWidthScale, const float downsampleHeightScale,
+                              bool blurUserImage = false);
+
+  /**
+   * @DEPRECATED_1_1.28 Use Actor::Add(Actor) instead
+   * @brief Adds a child Actor to this Actor.
+   * @SINCE_1_0.0
+   * @param [in] child The child.
+   * @pre This Actor (the parent) has been initialized.
+   * @pre The child actor has been initialized.
+   * @pre The child actor is not the same as the parent actor.
+   * @pre The actor is not the Root actor
+   * @post The child will be referenced by its parent. This means that the child will be kept alive,
+   * even if the handle passed into this method is reset or destroyed.
+   * @note If the child already has a parent, it will be removed from old parent
+   * and reparented to this actor. This may change childs position, color, shader effect,
+   * scale etc as it now inherits them from this actor.
+   */
+  void Add(Actor child);
+
+  /**
+   * @DEPRECATED_1_1.28 Use Actor::Remove(Actor) instead
+   * @brief Removes a child Actor from this Actor.
+   *
+   * If the actor was not a child of this actor, this is a no-op.
+   * @SINCE_1_0.0
+   * @param [in] child The child.
+   * @pre This Actor (the parent) has been initialized.
+   * @pre The child actor is not the same as the parent actor.
+   */
+  void Remove(Actor child);
+
+  /**
+   * @brief Start rendering the GaussianBlurView. Must be called after you Add() it to the stage.
+   * @SINCE_1_0.0
+   */
+  void Activate();
+
+  /**
+   * @brief Render the GaussianBlurView once.
+   *
+   * Must be called after you Add() it to the stage.
+   * Only works with a gaussian blur view created with blurUserImage = true.
+   * Listen to the Finished signal to determine when the rendering has completed.
+   * @SINCE_1_0.0
+   */
+  void ActivateOnce();
+
+  /**
+   * @brief Stop rendering the GaussianBlurView. Must be called after you Remove() it from the stage.
+   * @SINCE_1_0.0
+   */
+  void Deactivate();
+
+  /**
+   * @brief Sets a custom image to be blurred and a render target to receive the blurred result.
+   *
+   * If this is called the children of the GaussianBlurObject will not be rendered blurred,
+   * instead the inputImage will get blurred.
+   * To retrieve the blurred image the user can either pass a handle on a render target they own as the second parameter to SetUserImageAndOutputRenderTarget( ... ), or they
+   * can pass NULL for this parameter and instead call GetBlurredRenderTarget() which will return a handle on a render target created internally to the GaussianBlurView object.
+   * @SINCE_1_0.0
+   * @param inputImage The image that the user wishes to blur.
+   * @param outputRenderTarget A render target to receive the blurred result. Passing NULL is allowed. See also GetBlurredRenderTarget().
+   * @pre This object was created with a New( ... ) call where the blurUserImage argument was set to true. If this was not the case an exception will be thrown.
+   */
+  void SetUserImageAndOutputRenderTarget(Dali::Texture inputImage, Dali::FrameBuffer outputRenderTarget);
+
+  /**
+   * @brief Get the index of the property that can be used to fade the blur in / out.
+   *
+   * This is the overall strength of the blur.
+   * User can use this to animate the blur. A value of 0.0 is zero blur and 1.0 is full blur. Default is 1.0.
+   * Note that if you set the blur to 0.0, the result will be no blur BUT the internal rendering will still be happening. If you wish to turn the blur off, you should remove
+   * the GaussianBlurView object from the stage also.
+   * @SINCE_1_0.0
+   * @return Index of the property that can be used to fade the blur in / out
+   */
+  Dali::Property::Index GetBlurStrengthPropertyIndex() const;
+
+  /**
+   * @brief Get the final blurred image.
+   *
+   * Use can call this function to get the blurred result as an image, to use as they wish. It is not necessary to call this unless you specifically require it.
+   * @SINCE_1_0.0
+   * @return A handle on the blurred image, contained in a render target.
+   * @pre The user must call Activate() before the render target will be returned.
+   */
+  Dali::FrameBuffer GetBlurredRenderTarget() const;
+
+  /**
+  * @brief Set background color for the view. The background will be filled with this color.
+  * @SINCE_1_0.0
+  * @param[in] color The background color.
+  */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+  * @brief Get the background color.
+  * @SINCE_1_0.0
+  * @return The background color.
+  */
+  Vector4 GetBackgroundColor() const;
+
+public: // Signals
+  /**
+   * @brief If ActivateOnce has been called, then connect to this signal to be notified when the
+   * target actor has been rendered.
+   * @SINCE_1_0.0
+   * @return The Finished signal
+   */
+  GaussianBlurViewSignal& FinishedSignal();
+
+public:
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_0.0
+   * @param[in]  implementation  The UI Control implementation.
+   */
+  DALI_INTERNAL GaussianBlurView( Internal::GaussianBlurView& implementation );
+
+  /**
+   * @brief Allows the creation of this UI Control from an Internal::CustomActor pointer.
+   * @SINCE_1_0.0
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL GaussianBlurView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_GAUSSIAN_BLUR_EFFECT_H
diff --git a/dali-toolkit/devel-api/controls/magnifier/magnifier.cpp b/dali-toolkit/devel-api/controls/magnifier/magnifier.cpp
new file mode 100644 (file)
index 0000000..40da8c8
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/magnifier/magnifier.h>
+#include <dali-toolkit/internal/controls/magnifier/magnifier-impl.h>
+
+using namespace Dali;
+
+namespace
+{
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Magnifier
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Magnifier::Magnifier()
+{
+}
+
+Magnifier::Magnifier( const Magnifier& handle )
+: Control( handle )
+{
+}
+
+Magnifier& Magnifier::operator=( const Magnifier& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+Magnifier::Magnifier(Internal::Magnifier& implementation)
+: Control(implementation)
+{
+}
+
+Magnifier::Magnifier( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Magnifier>(internal);
+}
+
+Magnifier Magnifier::New()
+{
+  return Internal::Magnifier::New();
+}
+
+Magnifier::~Magnifier()
+{
+}
+
+Magnifier Magnifier::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Magnifier, Internal::Magnifier>(handle);
+}
+
+void Magnifier::SetSourceActor(Actor actor)
+{
+  GetImpl(*this).SetSourceActor( actor );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/magnifier/magnifier.h b/dali-toolkit/devel-api/controls/magnifier/magnifier.h
new file mode 100644 (file)
index 0000000..1e47446
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef DALI_TOOLKIT_MAGNIFIER_H
+#define DALI_TOOLKIT_MAGNIFIER_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Magnifier;
+}
+
+/**
+ * Magnifier control is used to apply a magnify effect to content on the stage.
+ *
+ * This is done by rendering the contents of a SourceActor at a given source position
+ * to the stage as a separate overlay. In addition to the contents, an optional frame
+ * is displayed around the magnified contents.
+ */
+class DALI_TOOLKIT_API Magnifier : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,             ///< Reserve property indices
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000              ///< Reserve animatable property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the Magnifier class.
+   */
+  struct Property
+  {
+    enum
+    {
+      // Event side properties
+      FRAME_VISIBILITY = PROPERTY_START_INDEX,           ///< name "frameVisibility",       Whether a frame is visible or not,         type boolean
+      MAGNIFICATION_FACTOR,                              ///< name "magnificationFactor",   Larger value means greater magnification,  type float
+
+      // Animatable properties
+      SOURCE_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< name "sourcePosition",  The position of the source,  type Vector3
+    };
+  };
+
+public:
+
+  /**
+   * Creates an empty Magnifier handle
+   */
+  Magnifier();
+
+  /**
+   * Copy constructor. Creates another handle that points to the same real object
+   * @param handle to copy from
+   */
+  Magnifier( const Magnifier& handle );
+
+  /**
+   * Assignment operator. Changes this handle to point to another real object
+   */
+  Magnifier& operator=( const Magnifier& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Magnifier();
+
+  /**
+   * Create the Poup control
+   * @return A handle to the Magnifier control.
+   */
+  static Magnifier New();
+
+  /**
+   * Downcast an Object handle to Magnifier. If handle points to an Magnifier the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a Magnifier or an uninitialized handle
+   */
+  static Magnifier DownCast( BaseHandle handle );
+
+public:
+
+  /**
+   * Set the actors to be rendered in magnifier.
+   * @param[in] actor This actor and its children will be rendered.
+   */
+  void SetSourceActor(Actor actor);
+
+public: // Not intended for application developers
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL Magnifier(Internal::Magnifier& implementation);
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL Magnifier(Dali::Internal::CustomActor* internal);
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_MAGNIFIER_H
diff --git a/dali-toolkit/devel-api/controls/navigation-view/navigation-view.cpp b/dali-toolkit/devel-api/controls/navigation-view/navigation-view.cpp
new file mode 100644 (file)
index 0000000..cffecf9
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/navigation-view/navigation-view.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+NavigationView::NavigationView()
+{
+}
+
+NavigationView::NavigationView( const NavigationView& handle )
+: Control(handle)
+{
+}
+
+NavigationView& NavigationView::operator=( const NavigationView& handle)
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+NavigationView::~NavigationView()
+{
+}
+
+NavigationView NavigationView::New()
+{
+  return Internal::NavigationView::New();
+}
+
+NavigationView NavigationView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<NavigationView, Internal::NavigationView>(handle);
+}
+
+NavigationView::NavigationView( Internal::NavigationView& implementation )
+: Control( implementation )
+{
+}
+
+NavigationView::NavigationView( Dali::Internal::CustomActor* internal )
+: Control( internal)
+{
+  VerifyCustomActorPointer<Internal::NavigationView>(internal);
+}
+
+
+void NavigationView::Push( Actor actor )
+{
+  GetImpl( *this ).Push( actor );
+}
+
+Actor NavigationView::Pop()
+{
+  return GetImpl( *this ).Pop();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/navigation-view/navigation-view.h b/dali-toolkit/devel-api/controls/navigation-view/navigation-view.h
new file mode 100644 (file)
index 0000000..113792f
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef DALI_TOOLKIT_NAVIGATION_VIEW_H
+#define DALI_TOOLKIT_NAVIGATION_VIEW_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+class NavigationView;
+}
+
+/**
+ * @brief NavigationView implements a view that manages the navigation of hierarchical contents.
+ *
+ * An Actor is pushed onto the NavigationView, itself and its children are added to the stage.
+ * The actors currently shown are replaced.
+ * When pop is called on the NavigationView, the current tree of Actors are removed and the previous set added back.
+ * If pop is called on the last set of Actors then they remain, nothing is popped.
+ */
+class DALI_TOOLKIT_API NavigationView : public Control
+{
+
+public:
+
+  /**
+   * @brief Create a NavigationView handle; this can be initialize with NavigationView::New().
+   *
+   * @note Calling member function with an uninitialized handle is not allowed.
+   */
+  NavigationView();
+
+  /**
+   * @brief Copy Constructor.
+   * @param[in] handle Handle to copy.
+   */
+  NavigationView( const NavigationView& handle );
+
+ /**
+  * @brief Assignment operator.
+  * @param handle The handle to copy from.
+  * @return reference to this
+  */
+  NavigationView& operator=( const NavigationView& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~NavigationView();
+
+  /**
+   * @brief  Create an initialized NavigationView.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static NavigationView New();
+
+  /**
+   * @brief Downcast an object handle to NavigationView.
+   *
+   * @details If handle points to a NavigationView, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object.
+   * @return handle to a NavigationView of an uninitialized handle.
+   */
+  static NavigationView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Push a new actor tree to the top of the NavigationView stack and show it.
+   * @param[in] item An actor tree.
+   */
+  void Push( Actor item );
+
+  /**
+   * @brief Pop the actor tree that is on the top of the NavigationView stack and make it disappear.
+   *
+   * @return The Actor tree popped out.
+   *
+   * @note It does not pop out the last item in the stack.
+   * It returns an uninitialized item handle if there is no item or only one item in the stack.
+   */
+  Actor Pop();
+
+
+public: // Not intended for application developers
+
+/// @cond internal
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL NavigationView( Internal::NavigationView& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL NavigationView( Dali::Internal::CustomActor* internal );
+/// @endcond
+}; // class NavigationView
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_NAVIGATION_VIEW_H
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-factory.h b/dali-toolkit/devel-api/controls/page-turn-view/page-factory.h
new file mode 100644 (file)
index 0000000..4768b21
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef DALI_TOOLKIT_PAGE_FACTORY_H
+#define DALI_TOOLKIT_PAGE_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief PageFactory is an abstract interface for providing textures to PageTurnView
+ * Each page is identified by a unique ID, and has a linear order from 0 to GetNumberOfPages()-1
+ *
+ * @SINCE_1_1.4
+ */
+class DALI_TOOLKIT_API PageFactory
+{
+public:
+
+  class Extension; ///< Forward declare future extension interface
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~PageFactory(){};
+
+  /**
+   * @brief Query the number of pages available from the factory.
+   *
+   * The maximum available page has an ID of GetNumberOfPages()-1.
+   * @return The page count.
+   */
+  virtual unsigned int GetNumberOfPages() = 0;
+
+  /**
+   * @brief Return the texture for the page
+   *
+   * For double-sided page( PageTurnLandscapeView ), the left half of texture is used as page front side, and the right half as page back side.
+   *
+   * @note Must return a valid texture handle!
+   *
+   * @param[in] pageId The ID of the page to create.
+   * @return An actor, or an uninitialized pointer if the ID is out of range.
+   */
+  virtual Texture NewPage( unsigned int pageId ) = 0;
+
+  /**
+   * @brief Retrieve the extension for this factory
+   *
+   * @return The extension if available, NULL otherwise.
+   */
+  virtual Extension* GetExtension()
+  {
+    return NULL;
+  }
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+#endif /* DALI_TOOLKIT_PAGE_FACTORY_H */
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.cpp b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.cpp
new file mode 100644 (file)
index 0000000..50f5d82
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+PageTurnLandscapeView::PageTurnLandscapeView()
+: PageTurnView()
+{
+}
+
+PageTurnLandscapeView::PageTurnLandscapeView( const PageTurnLandscapeView& pageTurnLandscapeView )
+: PageTurnView( pageTurnLandscapeView )
+{
+}
+
+PageTurnLandscapeView::PageTurnLandscapeView( Internal::PageTurnLandscapeView& implementation )
+: PageTurnView( implementation )
+{
+}
+
+PageTurnLandscapeView::PageTurnLandscapeView( Dali::Internal::CustomActor* internal )
+: PageTurnView( internal )
+{
+  VerifyCustomActorPointer<Internal::PageTurnLandscapeView>( internal );
+}
+
+PageTurnLandscapeView& PageTurnLandscapeView::operator=( const PageTurnLandscapeView& pageTurnLandscapeView )
+{
+  if( &pageTurnLandscapeView != this)
+  {
+    PageTurnView::operator=( pageTurnLandscapeView );
+  }
+  return *this;
+}
+
+PageTurnLandscapeView::~PageTurnLandscapeView()
+{
+}
+
+PageTurnLandscapeView PageTurnLandscapeView::New( PageFactory& pageFactory, const Vector2& viewPageSize )
+{
+  return Internal::PageTurnLandscapeView::New(pageFactory, viewPageSize);
+}
+
+PageTurnLandscapeView PageTurnLandscapeView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<PageTurnLandscapeView, Internal::PageTurnLandscapeView>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h
new file mode 100644 (file)
index 0000000..8f586f8
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef DALI_TOOLKIT_PAGE_TURN_LANDSCAPE_VIEW_H
+#define DALI_TOOLKIT_PAGE_TURN_LANDSCAPE_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+class PageTurnLandscapeView;
+}
+
+/**
+ * @brief PageTurnLandscapeView provides a page turn view in landscape mode
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API PageTurnLandscapeView : public PageTurnView
+{
+public:
+  /**
+   * @brief Create an uninitialized PageTurnLandscapeView; this can be initialized with PageTurnLandscapeView::New()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  PageTurnLandscapeView();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   */
+  PageTurnLandscapeView( const PageTurnLandscapeView& pageTurnLandscapeView );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   */
+  PageTurnLandscapeView& operator=( const PageTurnLandscapeView& pageTurnLandscapeView );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~PageTurnLandscapeView();
+
+  /**
+   * @brief Create an initialized PageTurnLandscapeView control
+   * @SINCE_1_0.0
+   * @param[in] pageFactory The factory which provides PageTurnView with pages.
+   * @param[in] viewPageSize The size of the page
+   * @return A handle to the PageTurnLandscapeView control.
+   */
+  static PageTurnLandscapeView New( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+  /**
+   * @brief Downcast an Object handle to PageTurnPortraitView. If handle points to a PageTurnLandscapeView the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return handle to a PageTurnLandscapeView or an uninitialized handle
+   */
+  static PageTurnLandscapeView DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_0.0
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL PageTurnLandscapeView( Internal::PageTurnLandscapeView& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_0.0
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL PageTurnLandscapeView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_PAGE_TURN_LANDSCAPE_VIEW_H */
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.cpp b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.cpp
new file mode 100644 (file)
index 0000000..175316e
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+PageTurnPortraitView::PageTurnPortraitView()
+: PageTurnView()
+{
+}
+
+PageTurnPortraitView::PageTurnPortraitView( const PageTurnPortraitView& pageTurnPortraitView )
+: PageTurnView( pageTurnPortraitView )
+{
+}
+
+PageTurnPortraitView::PageTurnPortraitView( Internal::PageTurnPortraitView& implementation )
+: PageTurnView( implementation )
+{
+}
+
+PageTurnPortraitView::PageTurnPortraitView( Dali::Internal::CustomActor* internal )
+: PageTurnView( internal )
+{
+  VerifyCustomActorPointer<Internal::PageTurnPortraitView>( internal );
+}
+
+PageTurnPortraitView& PageTurnPortraitView::operator=( const PageTurnPortraitView& pageTurnPortraitView )
+{
+  if( &pageTurnPortraitView != this)
+  {
+    PageTurnView::operator=( pageTurnPortraitView );
+  }
+  return *this;
+}
+
+PageTurnPortraitView::~PageTurnPortraitView()
+{
+}
+
+PageTurnPortraitView PageTurnPortraitView::New( PageFactory& pageFactory, const Vector2& viewPageSize)
+{
+  return Internal::PageTurnPortraitView::New(pageFactory, viewPageSize);
+}
+
+PageTurnPortraitView PageTurnPortraitView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<PageTurnPortraitView, Internal::PageTurnPortraitView>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h
new file mode 100644 (file)
index 0000000..9bf715c
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef DALI_TOOLKIT_PAGE_TURN_PORTRAIT_VIEW_H
+#define DALI_TOOLKIT_PAGE_TURN_PORTRAIT_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+class PageTurnPortraitView;
+}
+
+/**
+ * @brief PageTurnPortraitView provides a page turn view in portrait mode
+ *
+ * @SINCE_1_1.4
+ */
+class DALI_TOOLKIT_API PageTurnPortraitView : public PageTurnView
+{
+public:
+  /**
+   * @brief Create an uninitialized PageTurnPortraitView; this can be initialized with PageTurnPortraitView::New()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_1.4
+   */
+  PageTurnPortraitView();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_1.4
+   */
+  PageTurnPortraitView( const PageTurnPortraitView& pageTurnPortraitView );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_1.4
+   */
+  PageTurnPortraitView& operator=( const PageTurnPortraitView& pageTurnPortraitView );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.4
+   */
+  ~PageTurnPortraitView();
+
+  /**
+   * @brief Create an initialized  PageTurnPortraitView control
+   * @SINCE_1_1.4
+   * @param[in] pageFactory The factory which provides PageTurnView with pages.
+   * @param[in] viewPageSize The size of the page
+   * @return A handle to the PageTurnPortraitView control.
+   */
+  static PageTurnPortraitView New( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+  /**
+   * @brief Downcast an Object handle to PageTurnPortraitView. If handle points to a PageTurnPortraitView the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @SINCE_1_1.4
+   * @param[in] handle Handle to an object
+   * @return handle to a PageTurnPortraitView or an uninitialized handle
+   */
+  static PageTurnPortraitView DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_1.4
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL PageTurnPortraitView( Internal::PageTurnPortraitView& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_1.4
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL PageTurnPortraitView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_PAGE_TURN_PORTRAIT_VIEW_H */
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.cpp b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.cpp
new file mode 100644 (file)
index 0000000..1babe2b
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+PageTurnView::PageTurnView()
+{
+}
+
+PageTurnView::PageTurnView( const PageTurnView& handle )
+: Control( handle )
+{
+}
+
+PageTurnView& PageTurnView::operator=( const PageTurnView& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+PageTurnView::~PageTurnView()
+{
+}
+
+PageTurnView PageTurnView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<PageTurnView, Internal::PageTurnView>(handle);
+}
+
+PageTurnView::PageTurnView( Internal::PageTurnView& implementation )
+: Control( implementation )
+{
+}
+
+PageTurnView::PageTurnView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::PageTurnView>(internal);
+}
+
+PageTurnView::PageTurnSignal& PageTurnView::PageTurnStartedSignal()
+{
+  return Toolkit::GetImplementation( *this ).PageTurnStartedSignal();
+}
+
+PageTurnView::PageTurnSignal& PageTurnView::PageTurnFinishedSignal()
+{
+  return Toolkit::GetImplementation( *this ).PageTurnFinishedSignal();
+}
+
+PageTurnView::PagePanSignal& PageTurnView::PagePanStartedSignal()
+{
+  return Toolkit::GetImplementation( *this ).PagePanStartedSignal();
+}
+
+PageTurnView::PagePanSignal& PageTurnView::PagePanFinishedSignal()
+{
+  return Toolkit::GetImplementation( *this ).PagePanFinishedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h b/dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h
new file mode 100644 (file)
index 0000000..3d5df87
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef DALI_TOOLKIT_PAGE_TURN_VIEW_H
+#define DALI_TOOLKIT_PAGE_TURN_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+class PageFactory;
+
+namespace Internal DALI_INTERNAL
+{
+class PageTurnView;
+}
+
+/**
+ * @brief PageTurnView is a base class of different mode of pageTurnViews ( portrait or landscape )
+ *
+ * Page actors are provided from an external PageFactory
+ * PanGesture is used to activate the page bending, streching and tuning forward/backward
+ *
+ * Signal usage: There are four signals. Two matching pairs for panning and page turning:
+ * PagePanStarted/PagePanFinished and PageTurnStarted/PageTurnFinished. Panning relates to user interaction with
+ * the screen while page turning refers to animation of the page. There are three scenarios for these
+ * events: normal page turn (forwards or backwards), aborted page turn (forwards or backwards)
+ * and pan with no animation. The order of events is as follows:
+ * 1) Normal page turn: PagePanStarted -> PageTurnStarted direction -> PagePanFinished -> PageTurnFinished direction
+ * 2) Aborted page turn: PagePanStarted -> PageTurnStarted direction -> PageTurnStarted opposite direction
+ *                       -> PagePanFinished -> PageTurnFinished opposite direction
+ * 3) Pan with no animation: PagePanStarted -> PagePanFinished
+ * Pan with no animation will occur when the user touches the page in an area that does not start the
+ * page turning.
+ *
+ *  Signals
+ * | %Signal Name     | Method                        |
+ * |------------------|-------------------------------|
+ * | pageTurnStarted  | @ref PageTurnStartedSignal()  |
+ * | pageTurnFinished | @ref PageTurnFinishedSignal() |
+ * | pagePanStarted   | @ref PagePanStartedSignal()   |
+ * | pagePanFinished  | @ref PagePanFinishedSignal()  |
+ *
+ * @SINCE_1_1.4
+ */
+class DALI_TOOLKIT_API PageTurnView : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   * @SINCE_1_1.4
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_1.4
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices @SINCE_1_1.4
+  };
+
+  struct Property
+  {
+    enum
+    {
+      VIEW_PAGE_SIZE = PROPERTY_START_INDEX, ///< name "viewPageSize",        type Vector2 @SINCE_1_1.4
+      CURRENT_PAGE_ID,                       ///< name "currentPageId",       type Integer @SINCE_1_1.4
+
+      /**
+       * The two values are the major&minor radius (in pixels) to form an ellipse shape.
+       * The top-left quarter of this ellipse is used to calculate spine normal for simulating shadow.
+       */
+      SPINE_SHADOW,                     ///< name "spineShadow",     type Vector2 @SINCE_1_1.4
+    };
+  };
+
+  /**
+   * @brief Creates an empty PageTurnView handle. Only derived versions can be instantiated.
+   * Calling member function with an uninitialized handle is not allowed.
+   * @SINCE_1_1.4
+   */
+  PageTurnView();
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object
+   * @SINCE_1_1.4
+   * @param[in] handle Handle to copy from
+   */
+  PageTurnView( const PageTurnView& handle );
+
+  /**
+   * @brief Assignment operator. Changes this handle to point to another real object
+   * @SINCE_1_1.4
+   */
+  PageTurnView& operator=( const PageTurnView& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.4
+   */
+  ~PageTurnView();
+
+  /**
+   * @brief Downcast an Object handle to PageTurnView.
+   * If handle points to an PageTurnView the downcast produces valid handle.
+   * If not the returned handle is left uninitialized.
+   * @SINCE_1_1.4
+   * @param[in] handle Handle to an object
+   * @return handle to a PageTurnView or an uninitialized handle
+   */
+  static PageTurnView DownCast( BaseHandle handle );
+
+public: //Signal
+
+  // Page Turned signal, with page index and boolean turning direction (true = forward, false = backward)
+  typedef Signal< void ( PageTurnView, unsigned int, bool ) > PageTurnSignal;
+  typedef Signal< void ( PageTurnView ) > PagePanSignal;
+
+  /**
+   * @brief Signal emitted when a page has started to turn over.
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallBackName( PageTurnView pageTurnView, unsigned int pageIndex, bool isTurningForward );
+   * @endcode
+   * @SINCE_1_1.4
+   * @return The signal to connect to
+   */
+  PageTurnSignal& PageTurnStartedSignal();
+
+  /**
+   * @brief Signal emitted when a page has finished turning over.
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallBackName( PageTurnView pageTurnView, unsigned int pageIndex, bool isTurningForward );
+   * @endcode
+   * @SINCE_1_1.4
+   * @return The signal to connect to
+   */
+  PageTurnSignal& PageTurnFinishedSignal();
+
+  /**
+   * @brief Signal emitted when a page pan has commenced
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallBackName( PageTurnView pageTurnView );
+   * @endcode
+   * @SINCE_1_1.4
+   * @return The signal to connect to
+   */
+  PagePanSignal& PagePanStartedSignal();
+
+  /**
+   * @brief Signal emitted when a page pan has finished
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallBackName( PageTurnView pageTurnView );
+   * @endcode
+   * @SINCE_1_1.4
+   * @return The signal to connect to
+   */
+  PagePanSignal& PagePanFinishedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_1.4
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL PageTurnView(Internal::PageTurnView& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_1.4
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL PageTurnView(Dali::Internal::CustomActor* internal);
+  /// @endcond
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_PAGE_TURN_VIEW_H */
diff --git a/dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp b/dali-toolkit/devel-api/controls/popup/confirmation-popup.cpp
new file mode 100644 (file)
index 0000000..686e81a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/popup/confirmation-popup.h>
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/controls/popup/confirmation-popup-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+
+ConfirmationPopup::ConfirmationPopup()
+: Popup()
+{
+}
+
+ConfirmationPopup::ConfirmationPopup( Internal::ConfirmationPopup& implementation )
+: Popup( implementation )
+{
+}
+
+ConfirmationPopup::ConfirmationPopup( const ConfirmationPopup& confirmationPopup )
+: Popup( confirmationPopup )
+{
+}
+
+ConfirmationPopup& ConfirmationPopup::operator=( const ConfirmationPopup& confirmationPopup )
+{
+  if( &confirmationPopup != this )
+  {
+    Popup::operator=( confirmationPopup );
+  }
+  return *this;
+}
+
+ConfirmationPopup::ConfirmationPopup( Dali::Internal::CustomActor* internal )
+: Popup( internal )
+{
+  VerifyCustomActorPointer<Internal::ConfirmationPopup>( internal );
+}
+
+ConfirmationPopup::~ConfirmationPopup()
+{
+}
+
+ConfirmationPopup ConfirmationPopup::New()
+{
+  return Internal::ConfirmationPopup::New();
+}
+
+ConfirmationPopup ConfirmationPopup::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ConfirmationPopup, Internal::ConfirmationPopup>( handle );
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/popup/confirmation-popup.h b/dali-toolkit/devel-api/controls/popup/confirmation-popup.h
new file mode 100644 (file)
index 0000000..4a804cb
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_TOOLKIT_CONFIRMATION_POPUP_H
+#define DALI_TOOLKIT_CONFIRMATION_POPUP_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "popup.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+namespace Internal DALI_INTERNAL
+{
+class ConfirmationPopup;
+}
+
+/**
+ * @brief The ConfirmationPopup widget provides a simple interface to the Popup widget in which to
+ * create common use-case popups.
+ *
+ * ConfirmationPopup will automatically provide signals for 1 or 2 buttons.
+ * These signals are dynamically created. The controls (typically PushButtons) must be named as per the example below.
+ *
+ * Please see the programming guide for a detailed description of the ConfirmationPopup including examples.
+ *
+ * Signals (these are dynamically created upon connect).
+ * | %Signal Name        | Actor name to connect to | Property to set signal type (eg clicked) |
+ * |---------------------|--------------------------|------------------------------------------|
+ * | controlSignalOk     | controlOk                | connectSignalOkSelected                  |
+ * | controlSignalCancel | controlCancel            | connectSignalCancelSelected              |
+ */
+class DALI_TOOLKIT_API ConfirmationPopup : public Popup
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1 + DEFAULT_PROPERTY_MAX_COUNT_PER_DERIVATION + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the ConfirmationPopup class.
+   */
+  struct Property
+  {
+    enum
+    {
+      CONNECT_SIGNAL_OK_SELECTED = PROPERTY_START_INDEX, ///< name "connectSignalOkSelected",        type std::string
+      CONNECT_SIGNAL_CANCEL_SELECTED                     ///< name "connectSignalCancelSelected",    type std::string
+    };
+  };
+
+  /**
+   * @brief An enumeration to use as indices to reference buttons.
+   */
+  enum ControlIndex
+  {
+    CONTROL_OK = 0,    ///< Index of control 1
+    CONTROL_CANCEL,    ///< Index of control 2
+  };
+
+  /**
+   * @brief Create an uninitialized ConfirmationPopup; this can be initialized with ConfirmationPopup::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  ConfirmationPopup();
+
+  /**
+   * @brief Copy constructor.
+   */
+  ConfirmationPopup( const ConfirmationPopup& confirmationPopup );
+
+  /**
+   * @brief Assignment operator.
+   */
+  ConfirmationPopup& operator=( const ConfirmationPopup& confirmationPopup );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived types must not contain data or virtual methods.
+   */
+  ~ConfirmationPopup();
+
+  /**
+   * @brief Create an initialized ConfirmationPopup.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static ConfirmationPopup New();
+
+  /**
+   * @brief Downcast an Object handle to ConfirmationPopup.
+   *
+   * If handle points to a ConfirmationPopup the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return handle to a ConfirmationPopup or an uninitialized handle
+   */
+  static ConfirmationPopup DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL ConfirmationPopup( Internal::ConfirmationPopup& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL ConfirmationPopup( Dali::Internal::CustomActor* internal );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONFIRMATION_POPUP_H
diff --git a/dali-toolkit/devel-api/controls/popup/popup.cpp b/dali-toolkit/devel-api/controls/popup/popup.cpp
new file mode 100644 (file)
index 0000000..f3669fa
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/popup/popup.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/popup/popup-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Popup
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Popup::Popup()
+{
+}
+
+Popup::Popup( const Popup& handle )
+: Control( handle )
+{
+}
+
+Popup& Popup::operator=( const Popup& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+Popup::Popup(Internal::Popup& implementation)
+: Control(implementation)
+{
+}
+
+Popup::Popup( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Popup>(internal);
+}
+
+Popup Popup::New()
+{
+  return Internal::Popup::New();
+}
+
+Popup::~Popup()
+{
+}
+
+Popup Popup::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Popup, Internal::Popup>(handle);
+}
+
+// Properties:
+
+void Popup::SetTitle( Actor titleActor )
+{
+  GetImpl( *this ).SetTitle( titleActor );
+}
+
+Actor Popup::GetTitle() const
+{
+  return GetImpl( *this ).GetTitle();
+}
+
+void Popup::SetContent( Actor content )
+{
+  GetImpl( *this ).SetContent( content );
+}
+
+Actor Popup::GetContent() const
+{
+  return GetImpl( *this ).GetContent();
+}
+
+void Popup::SetFooter( Actor footer )
+{
+  GetImpl( *this ).SetFooter( footer );
+}
+
+Actor Popup::GetFooter() const
+{
+  return GetImpl( *this ).GetFooter();
+}
+
+void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
+{
+  GetImpl( *this ).SetDisplayState( displayState );
+}
+
+Toolkit::Popup::DisplayState Popup::GetDisplayState() const
+{
+  return GetImpl( *this ).GetDisplayState();
+}
+
+// Signals:
+
+Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
+{
+  return GetImpl( *this ).OutsideTouchedSignal();
+}
+
+Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
+{
+  return GetImpl( *this ).ShowingSignal();
+}
+
+Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
+{
+  return GetImpl( *this ).ShownSignal();
+}
+
+Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
+{
+  return GetImpl( *this ).HidingSignal();
+}
+
+Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
+{
+  return GetImpl( *this ).HiddenSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/popup/popup.h b/dali-toolkit/devel-api/controls/popup/popup.h
new file mode 100644 (file)
index 0000000..054815c
--- /dev/null
@@ -0,0 +1,312 @@
+#ifndef DALI_TOOLKIT_POPUP_H
+#define DALI_TOOLKIT_POPUP_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Popup;
+}
+
+/**
+ * @brief The Popup widget provides a configurable pop-up dialog with built-in layout of three main fields.
+ *
+ * Fields:
+ * - Background Image
+ *   - Title
+ *   - Content
+ *   - Footer
+ *
+ * Please see the programming guide for a detailed description of the Popup including examples.
+ *
+ * Signals
+ * | %Signal Name      | Method                       |
+ * |-------------------|------------------------------|
+ * | touchedOutside    | @ref OutsideTouchedSignal()  |
+ * | showing           | @ref ShowingSignal()         |
+ * | shown             | @ref ShownSignal()           |
+ * | hiding            | @ref HidingSignal()          |
+ * | hidden            | @ref HiddenSignal()          |
+ */
+class DALI_TOOLKIT_API Popup : public Control
+{
+
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the Popup class.
+   */
+  struct Property
+  {
+    enum
+    {
+      TITLE = PROPERTY_START_INDEX, ///< name "title",                  type Property::Map
+      CONTENT,                      ///< name "content",                type Property::Map
+      FOOTER,                       ///< name "footer",                 type Property::Map
+      DISPLAY_STATE,                ///< name "displayState",           type std::string
+      TOUCH_TRANSPARENT,            ///< name "touchTransparent",       type bool
+      TAIL_VISIBILITY,              ///< name "tailVisibility",         type bool
+      TAIL_POSITION,                ///< name "tailPosition",           type Vector3
+      CONTEXTUAL_MODE,              ///< name "contextualMode",         type std::string
+      ANIMATION_DURATION,           ///< name "animationDuration",      type float
+      ANIMATION_MODE,               ///< name "animationMode",          type std::string
+      ENTRY_ANIMATION,              ///< name "entryAnimation",         type Property::Map
+      EXIT_ANIMATION,               ///< name "exitAnimation",          type Property::Map
+      AUTO_HIDE_DELAY,              ///< name "autoHideDelay",          type int
+      BACKING_ENABLED,              ///< name "backingEnabled",         type bool
+      BACKING_COLOR,                ///< name "backingColor",           type Vector4
+      POPUP_BACKGROUND_IMAGE,       ///< name "popupBackgroundImage",   type std::string
+      POPUP_BACKGROUND_BORDER,      ///< name "popupBackgroundBorder",  type Rect< int >,      Values are in the order: left, right, bottom, top
+      TAIL_UP_IMAGE,                ///< name "tailUpImage",            type std::string
+      TAIL_DOWN_IMAGE,              ///< name "tailDownImage",          type std::string
+      TAIL_LEFT_IMAGE,              ///< name "tailLeftImage",          type std::string
+      TAIL_RIGHT_IMAGE,             ///< name "tailRightImage",         type std::string
+    };
+  };
+
+  /**
+   * The display states of the Popup.
+   */
+  enum DisplayState
+  {
+    SHOWING,           ///< The popup is transitioning in
+    SHOWN,             ///< The popup is fully shown
+    HIDING,            ///< The popup is transitioning out
+    HIDDEN             ///< The popup is fully hidden
+  };
+
+  /**
+   * The animation mode within popup.
+   * Choose from a predefined mode or "CUSTOM" to use the ANIMATION_IN and ANIMATION_OUT properties.
+   */
+  enum AnimationMode
+  {
+    NONE,              ///< No animation.
+    ZOOM,              ///< Popup zooms in and out animating the scale property.
+    FADE,              ///< Popup fades in and out.
+    CUSTOM             ///< Use the EntryAnimation and ExitAnimation animation properties.
+  };
+
+  /**
+   * Types of contextual layout.
+   * The Popup is positioned adjacent to it's parent in the direction specified by this mode.
+   * NON_CONTEXTUAL disables any contextual positioning.
+   */
+  enum ContextualMode
+  {
+    NON_CONTEXTUAL,
+    ABOVE,
+    RIGHT,
+    BELOW,
+    LEFT
+  };
+
+public:
+
+  /**
+   * @brief Creates an empty Popup handle.
+   */
+  Popup();
+
+  /**
+   * @brief Create the Popup control.
+   *
+   * @return A handle to the Popup control.
+   */
+  static Popup New();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Popup();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object
+   * @param[in] handle Handle to the copied object
+   */
+  Popup( const Popup& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object
+   * @param[in] handle Handle to the object
+   * @return A reference to this
+   */
+  Popup& operator=( const Popup& handle );
+
+  /**
+   * @brief Downcast an Object handle to Popup.
+   *
+   * If handle points to a Popup the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a Popup or an uninitialized handle
+   */
+  static Popup DownCast( BaseHandle handle );
+
+public:
+
+  /**
+   * @brief Sets a title for this Popup.
+   *
+   * @param[in] titleActor Any actor can be specified when using this method.
+   */
+  void SetTitle( Actor titleActor );
+
+  /**
+   * @brief Gets the title actor for this Popup.
+   *
+   * @return The actor representing the title is returned.
+   */
+  Actor GetTitle() const;
+
+  /**
+   * @brief Sets the content actor.
+   * This can any actor type or heirarchy of actors.
+   *
+   * @param[in] content The actor to use.
+   */
+  void SetContent( Actor content );
+
+  /**
+   * @brief Gets the actor currently used for the content.
+   *
+   * @return The content actor.
+   */
+  Actor GetContent() const;
+
+  /**
+   * @brief Sets the actor to use for a footer in this Popup.
+   *
+   * @param[in] footer The footer actor to be added to this Popup
+   */
+  void SetFooter( Actor footer );
+
+  /**
+   * @brief Gets the footer actor.
+   *
+   * @return The footer actor.
+   */
+  Actor GetFooter() const;
+
+  /**
+   * @brief Sets the display state of Popup.
+   *
+   * There are 4 total display states.
+   * Only 2 can be set, but all four can be read for better inspection of the current popup state.
+   *
+   * The other two states are getable, but not setable and are there for consistency.
+   *
+   * | Value    | Setting the state              | Getting the state              |
+   * |----------|--------------------------------|--------------------------------|
+   * | SHOWN    | Show the popup                 | The popup is fully shown       |
+   * | HIDDEN   | Hide the popup                 | The popup is fully hidden      |
+   * | SHOWING  |                                | The popup is transitioning in  |
+   * | HIDING   |                                | The popup is transitioning out |
+   *
+   * All 4 state changes cause notifications via 4 respective signals that can be connected to.
+   * @see GetDisplayState()
+   *
+   * @param[in] displayState The desired display state to change to.
+   */
+  void SetDisplayState( Toolkit::Popup::DisplayState displayState );
+
+  /**
+   * @brief Gets the current state of the popup.
+   *
+   * This will also show if the popup is in the process of showing or hiding.
+   *
+   * @return The current state of the popup.
+   */
+  Toolkit::Popup::DisplayState GetDisplayState() const;
+
+public:
+
+  typedef Signal< void () > TouchedOutsideSignalType;     ///< Touched outside signal type.
+  typedef Signal< void () > DisplayStateChangeSignalType; ///< Used for signals emitted when the displayed state changes.
+
+  /**
+   * @brief Signal emitted when user has touched outside of the Dialog.
+   */
+  TouchedOutsideSignalType& OutsideTouchedSignal();
+
+  /**
+   * @brief Signal emitted when the Popup is starting to be shown.
+   */
+  DisplayStateChangeSignalType& ShowingSignal();
+
+  /**
+   * @brief Signal emitted when the Popup has been fully displayed.
+   */
+  DisplayStateChangeSignalType& ShownSignal();
+
+  /**
+   * @brief Signal emitted when the Popup is starting to be hidden.
+   */
+  DisplayStateChangeSignalType& HidingSignal();
+
+  /**
+   * @brief Signal emitted when the Popup has been completely hidden.
+   */
+  DisplayStateChangeSignalType& HiddenSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL Popup( Internal::Popup& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL Popup( Dali::Internal::CustomActor* internal );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_POPUP_H
diff --git a/dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.cpp b/dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.cpp
new file mode 100644 (file)
index 0000000..605d146
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Scene3dView::Scene3dView()
+{
+}
+
+Scene3dView::~Scene3dView()
+{
+}
+
+Scene3dView::Scene3dView( const Scene3dView& handle )
+  : Control( handle )
+{
+}
+
+Scene3dView& Scene3dView::operator=( const Scene3dView& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+Scene3dView Scene3dView::New( const std::string& filePath )
+{
+  return Internal::Scene3dView::New( filePath );
+}
+
+Scene3dView Scene3dView::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor )
+{
+  return Internal::Scene3dView::New( filePath, diffuseTexturePath, specularTexturePath, scaleFactor );
+}
+
+Scene3dView::Scene3dView( Internal::Scene3dView& implementation )
+  : Control( implementation )
+{
+}
+
+Scene3dView::Scene3dView( Dali::Internal::CustomActor* internal )
+  : Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Scene3dView>( internal );
+}
+
+Scene3dView Scene3dView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Scene3dView, Internal::Scene3dView>( handle );
+}
+
+uint32_t Scene3dView::GetAnimationCount()
+{
+  return GetImpl( *this ).GetAnimationCount();
+}
+
+bool Scene3dView::PlayAnimation( uint32_t index )
+{
+  return GetImpl( *this ).PlayAnimation( index );
+}
+
+bool Scene3dView::PlayAnimations()
+{
+  return GetImpl( *this ).PlayAnimations();
+}
+
+bool Scene3dView::SetLight( LightType type, Vector3 lightVector, Vector3 lightColor )
+{
+  return GetImpl( *this ).SetLight( type, lightVector, lightColor );
+}
+
+CameraActor Scene3dView::GetDefaultCamera()
+{
+  return GetImpl( *this ).GetDefaultCamera();
+}
+
+uint32_t Scene3dView::GetCameraCount()
+{
+  return GetImpl( *this ).GetCameraCount();
+}
+
+CameraActor Scene3dView::GetCamera( uint32_t cameraIndex )
+{
+  return GetImpl( *this ).GetCamera( cameraIndex );
+}
+
+}//namespace Toolkit
+
+}//namespace Dali
+
diff --git a/dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h b/dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h
new file mode 100644 (file)
index 0000000..0e6d6b1
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef DALI_TOOLKIT_SCENE3D_VIEW_H\r
+#define DALI_TOOLKIT_SCENE3D_VIEW_H\r
+\r
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/actors/camera-actor.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/public-api/controls/control.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Toolkit\r
+{\r
+\r
+namespace Internal DALI_INTERNAL\r
+{\r
+\r
+/**\r
+ * Scene3dView implementation class\r
+ */\r
+class Scene3dView;\r
+\r
+}\r
+\r
+/**\r
+ *\r
+ * Scene3dView is a class for containing scene elements loaded from scene format file(e.g., glTF). Scene elements mean scene graph, cameras, and animations.\r
+ *\r
+ * Basic idea:-\r
+ *\r
+ * 1) The Scene3dView is initialized with diffuse and specular cube map for the Image Based Lighting.\n\r
+ *    If the Scene3dView initialized without cube map, the objects of the Scene3dView cannot be rendered with IBL.\n\r
+ * 2) The Scene3dView is loaded from each scene format file(e.g., glTF).\n\r
+ * 3) The Scene3dView can have a point light or a directional light.(optional)\n\r
+ * 4) The Scene3dView playes each actor's animation.\n\r
+ *\r
+ *\r
+ * Usage example: -\r
+ *\r
+ * @code\r
+ *\r
+ * void Scene3dViewExample::Create( Application& application )\r
+ * {\r
+ *   // Use 'Scene3dView::New( URL_SCENE_FILE )', if you don't want to render with IBL.\r
+ *   Scene3dView scene3dView = Scene3dView::New( URL_SCENE_FILE, URL_DIFFUSE_TEXTURE, URL_SPECULAR_TEXTURE );\r
+ *\r
+ *   Stage::GetCurrent().Add( scene3dView );\r
+ *   scene3dView.PlayAnimations();\r
+ *\r
+ *   scene3dView.SetLight( Scene3dView::LightType::DIRECTIONAL_LIGHT, Vector3( 1.0, 1.0, -1.0 ), Vector3( 0.3, 0.3, 0.3 ) );\r
+ * }\r
+ *\r
+ * @endcode\r
+ *\r
+ * @remarks This control makes 3D Layer internally. Therefore, if any 2D UI\r
+ * control is added as a child of this Scene3dView, the functionality of the 2D UI\r
+ * may not work well.\r
+ */\r
+\r
+class DALI_TOOLKIT_API Scene3dView : public Control\r
+{\r
+public:\r
+\r
+  enum LightType\r
+  {\r
+    // Scene doesn't use both of point and directional light\r
+    NONE = 0,\r
+    // Scene use point light\r
+    POINT_LIGHT,\r
+    // Scene use directional light\r
+    DIRECTIONAL_LIGHT,\r
+    // Scene use Image Based Lighting\r
+    IMAGE_BASED_LIGHT,\r
+    // Scene use Image Based Lighting and point light\r
+    IMAGE_BASED_LIGHT_AND_POINT_LIGHT,\r
+    // Scene use Image Based Lighting and directional light\r
+    IMAGE_BASED_LIGHT_AND_DIRECTIONAL_LIGHT\r
+  };\r
+\r
+  /**\r
+   * @brief Create an uninitialized Scene3dView; this can be initialized with Scene3dView::New()\r
+   * Calling member functions with an uninitialized Dali::Object is not allowed.\r
+   */\r
+  Scene3dView();\r
+\r
+  /**\r
+   * @brief Copy constructor. Creates another handle that points to the same real object\r
+   */\r
+  Scene3dView( const Scene3dView& handle );\r
+\r
+  /**\r
+   * @brief Assignment operator. Changes this handle to point to another real object\r
+   */\r
+  Scene3dView& operator=( const Scene3dView& handle );\r
+\r
+  /**\r
+   * @brief Destructor\r
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.\r
+   */\r
+  ~Scene3dView();\r
+\r
+  /**\r
+   * @brief Downcast an Object handle to Scene3dView. If handle points to a Scene3dView the\r
+   * downcast produces valid handle. If not the returned handle is left uninitialized.\r
+   * @param[in] handle Handle to an object\r
+   * @return handle to a Scene3dView or an uninitialized handle\r
+   */\r
+  static Scene3dView DownCast( BaseHandle handle );\r
+\r
+  /**\r
+   * @brief Create an initialized Scene3dView.\r
+   * @param[in] filePath File path of scene format file (e.g., glTF).\r
+   * @return A handle to a newly allocated Dali resource\r
+   */\r
+  static Scene3dView New( const std::string& filePath );\r
+\r
+  /**\r
+   * @brief Create an initialized Scene3dView.\r
+   * @param[in] filePath File path of scene format file (e.g., glTF).\r
+   * @param[in] diffuseTexturePath The texture path of diffuse cube map that used to render with Image Based Lighting.\r
+   * @param[in] specularTexturePath The texture path of specular cube map that used to render with Image Based Lighting.\r
+   * @param[in] scaleFactor Scaling factor for the Image Based Lighting.\r
+   * @return A handle to a newly allocated Dali resource\r
+   */\r
+  static Scene3dView New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor );\r
+\r
+  /**\r
+   * @brief Get animation count.\r
+   * @return number of animations.\r
+   */\r
+  uint32_t GetAnimationCount();\r
+\r
+  /**\r
+   * @brief Play an animation.\r
+   * @param[in] index Animation index\r
+   * @return true if animation is played.\r
+   */\r
+  bool PlayAnimation( uint32_t index );\r
+\r
+  /**\r
+   * @brief Play all animations.\r
+   * @return true if animations are played.\r
+   */\r
+  bool PlayAnimations();\r
+\r
+  /**\r
+   * @brief Set point light or directional light. If SetLight is not called, this scene doesn't use these kind of light.\r
+   * @param[in] type The light type. If the light is point light set this LightType::POINT_LIGHT,\r
+   * or if the light is directional light set this LightType::DIRECTIONAL_LIGHT.\r
+   * @param[in] lightVector The point light position when light type is LightType::POINT_LIGHT.\r
+   * The light direction when light type is LightType::DIRECTIONAL_LIGHT.\r
+   * @param[in] lightColor Vector3 value that denotes the light color of point light or directional light. Since this is the light color, we don't need to use alpha value.\r
+   * @return true if point light or directional light is set.\r
+   */\r
+  bool SetLight( LightType type, Vector3 lightVector, Vector3 lightColor );\r
+\r
+  /**\r
+   * @brief Get default CameraActor. Dali::Camera::Type = Dali::Camera::LOOK_AT_TARGET , near clipping plane = 0.1, and camera position = Vector3( 0.0, 0.0, 0.0 ).\r
+   * @return CameraActor.\r
+   */\r
+  CameraActor GetDefaultCamera();\r
+\r
+  /**\r
+   * @brief Get camera count.\r
+   * @return number of cameras.\r
+   */\r
+  uint32_t GetCameraCount();\r
+\r
+  /**\r
+   * @brief Get CameraActor. If there is no CameraActor in the list, then returns default CameraActor.\r
+   * @param[in] cameraIndex Index of CameraActor list.\r
+   * @return CameraActor.\r
+   */\r
+  CameraActor GetCamera( uint32_t cameraIndex );\r
+\r
+  // Not intended for developer use\r
+public:\r
+\r
+  /**\r
+   * @brief Creates a handle using the Toolkit::Internal implementation.\r
+   * @param[in]  implementation  The UI Control implementation.\r
+   */\r
+  DALI_INTERNAL Scene3dView( Toolkit::Internal::Scene3dView& implementation );\r
+\r
+  explicit DALI_INTERNAL Scene3dView( Dali::Internal::CustomActor* internal );\r
+};\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_SCENE3D_VIEW_H\r
diff --git a/dali-toolkit/devel-api/controls/shadow-view/shadow-view.cpp b/dali-toolkit/devel-api/controls/shadow-view/shadow-view.cpp
new file mode 100644 (file)
index 0000000..a969dc2
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/shadow-view/shadow-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
+
+namespace
+{
+
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 1.0f;
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 1.0f;
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ShadowView::ShadowView()
+{
+}
+
+ShadowView::~ShadowView()
+{
+}
+
+ShadowView::ShadowView(const ShadowView& handle)
+  : Control( handle )
+{
+}
+
+ShadowView& ShadowView::operator=(const ShadowView& rhs)
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+ShadowView ShadowView::New()
+{
+  return Internal::ShadowView::New(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE,
+                                   GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE);
+}
+
+ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
+{
+  return Internal::ShadowView::New(downsampleWidthScale, downsampleHeightScale);
+}
+
+ShadowView::ShadowView( Internal::ShadowView& implementation )
+: Control( implementation )
+{
+}
+
+ShadowView::ShadowView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ShadowView>(internal);
+}
+
+ShadowView ShadowView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ShadowView, Internal::ShadowView>(handle);
+}
+
+void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
+{
+  GetImpl(*this).SetShadowPlaneBackground(shadowPlaneBackground);
+}
+
+void ShadowView::SetPointLight(Actor pointLight)
+{
+  GetImpl(*this).SetPointLight(pointLight);
+}
+
+void ShadowView::SetPointLightFieldOfView(float fieldOfView)
+{
+  GetImpl(*this).SetPointLightFieldOfView(fieldOfView);
+}
+
+void ShadowView::SetShadowColor(Vector4 color)
+{
+  GetImpl(*this).SetShadowColor(color);
+}
+
+void ShadowView::Activate()
+{
+  GetImpl(*this).Activate();
+}
+
+void ShadowView::Deactivate()
+{
+  GetImpl(*this).Deactivate();
+}
+
+Property::Index ShadowView::GetBlurStrengthPropertyIndex() const
+{
+  return GetImpl(*this).GetBlurStrengthPropertyIndex();
+}
+
+Property::Index ShadowView::GetShadowColorPropertyIndex() const
+{
+  return GetImpl(*this).GetShadowColorPropertyIndex();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/shadow-view/shadow-view.h b/dali-toolkit/devel-api/controls/shadow-view/shadow-view.h
new file mode 100644 (file)
index 0000000..52de248
--- /dev/null
@@ -0,0 +1,233 @@
+#ifndef DALI_TOOLKIT_SHADOW_VIEW_H
+#define DALI_TOOLKIT_SHADOW_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+/**
+ * ShadowView implementation class
+ */
+class ShadowView;
+
+} // namespace Internal
+
+/**
+ *
+ * ShadowView is a class for applying shadows to objects present in the view.
+ *
+ * Basic idea:-
+ *
+ * 1) The ShadowView object will render all its child actors offscreen from the light's point of view projected on to the shadow plane in a seperate render task.\n
+ * 2) The ShadowView object then blurs the result of step 1), using a two pass separated Gaussian blur.\n
+ * 3) The ShadowView object gets rendered automatically in the default render task along with it's children.
+ *
+ * Fundamentally, the ShadowView is simply an Actor in the normal actor tree that affects all of its children. It should be added to your Actor tree and manipulated in the
+ * normal way. It can be considered a 'portal' in the sense that all child actors are clipped to the ShadowView actor bounds.
+ *
+ * LIMITATIONS:
+ * The ShadowView is intended to provide simple planar projection shadows, Which means it needs a flat plane to cast shadows. So Shadows can't be cast on other objects.
+ *
+ * ************\n
+ * NB: It is essential to remove the ShadowView from the stage and also to call Deactivate() on it when you are not using it. This will ensure that resources are freed and
+ * rendering stops.\n
+ * ************\n
+ *
+ * Usage example:-
+ *
+ *  @code
+ *  // initialise\n
+ *  ShadowView shadowView = ShadowView::New();
+ *
+ *  // create and add some visible actors to the ShadowView, all these child actors will therefore cast a shadow.
+ *  Image image = Image::New(...);
+ *  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 view.
+ *  shadowView.SetShadowPlaneBackground(ShadowPlane);
+ *
+ *  Actor pointLight = Actor::New(); // This will be the light source
+ *  pointLight.SetPosition(300.0f, 250.0f, 600.0f);
+ *  Stage::GetCurrent().Add(pointLight);
+ *  shadowView.SetPointLight(pointLight);
+ *
+ *  // Start rendering the ShadowView
+ *  Stage::GetCurrent().Add(ShadowPlane);
+ *  shadowView.Activate();
+ *  ...
+ *
+ *  // animate the strength of the blur - this can fade between no blur and full blur. See GetBlurStrengthPropertyIndex().
+ *  Animation blurAnimation = Animation::New( ... );
+ *  blurAnimation.AnimateTo( Property( shadowView, shadowView.GetBlurStrengthPropertyIndex() ), ... );
+ *  blurAnimation.Play();
+ *
+ *  ...
+ *  // Stop rendering the ShadowView
+ *  Stage::GetCurrent().Remove(shadowView);
+ *  shadowView.Deactivate();
+ *  @endcode
+ */
+class DALI_TOOLKIT_API ShadowView : public Control
+{
+public:
+
+  /**
+   * Create an uninitialized ShadowView; this can be initialized with ShadowView::New()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  ShadowView();
+
+  /**
+   * Copy constructor. Creates another handle that points to the same real object
+   */
+  ShadowView(const ShadowView& handle);
+
+  /**
+   * Assignment operator. Changes this handle to point to another real object
+   */
+  ShadowView& operator=(const ShadowView& view);
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ShadowView();
+
+  /**
+   * Downcast an Object handle to ShadowView. If handle points to a ShadowView the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a ShadowView or an uninitialized handle
+   */
+  static ShadowView DownCast( BaseHandle handle );
+
+  /**
+  * Create an initialized ShadowView. Add children and call SetShadowPlane to make shadows visible\n
+  * @return A handle to a newly allocated Dali resource
+  */
+  static ShadowView New();
+
+  /**
+   * Create an initialized ShadowView. Add children and call SetShadowPlane to make shadows visible\n
+   * @param[in] downsampleWidthScale The width scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+   * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+   * @param[in] downsampleHeightScale The height scale factor applied during the blur process, scaling the size of the source image to the size of the final blurred image output.
+   * Useful for downsampling - trades visual quality for processing speed. A value of 1.0f results in no scaling applied.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static ShadowView New(float downsampleWidthScale, float downsampleHeightScale);
+
+  /**
+   * Set the Shadow Plane Background for the shadow effect.
+   *
+   * @param[in] shadowPlaneBackground An actor representing the shadow
+   * plane. The position of the actor represents the origin of the
+   * plane, and the orientation of the actor represents the direction
+   * of the plane normal. Make the plane sufficiently large if the shadows are
+   * clipped.
+   */
+  void SetShadowPlaneBackground(Actor shadowPlaneBackground);
+
+  /**
+   * Set the Point Light for the shadow effect. This is usually NOT a renderable actor.
+   * The orientation of the actor is not considered for the shadow calculation.
+   * @param[in] pointLight An actor representing the location of the
+   * directionless light source that casts the shadow.
+   */
+  void SetPointLight(Actor pointLight);
+
+  /**
+   * Set the field of view of the point light source. This will be used by an additional
+   * internal camera to look at the scene form the light source. If you notice any aritifacts
+   * when the light position is near to the object, Increase the field of view.
+   * @param[in] fieldOfView  New field of view in radians, Typical values are  Math::PI / 4.0f,
+   *  Math::PI / 2.0f
+   */
+  void SetPointLightFieldOfView(float fieldOfView);
+
+  /**
+   * Set shadow color.
+   * @param[in] color The shadow color
+   */
+  void SetShadowColor(Vector4 color);
+
+  /**
+   * Start rendering the ShadowView. Must be called after you Add() it to the stage.
+   * @pre This Actor has been added to the stage.
+   */
+  void Activate();
+
+  /**
+   * Stop rendering the ShadowView. Must be called after you Remove() it from the stage.
+   * @pre This Actor has been removed from the stage.
+   */
+  void Deactivate();
+
+  /**
+   * Get the property index that controls the strength of the blur applied to the shadow. Useful for animating this property.
+   * This property represents a value in the range [0.0 - 1.0] where 0.0 is no blur and 1.0 is full blur. Default 0.2.
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetBlurStrengthPropertyIndex() const;
+
+  /**
+   * Get the property index that controls the color of the shadow. Useful for animating this property.
+   * This property represents a value in the Vector4 format. Default color value is Vector4(0.2f, 0.2f, 0.2f, 0.8f) (i.e grey color).
+   * @return The property index that can be used with e.g. AnimateTo( ... )
+   */
+  Dali::Property::Index GetShadowColorPropertyIndex() const;
+
+
+public:
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The UI Control implementation.
+   */
+  DALI_INTERNAL ShadowView( Internal::ShadowView& implementation );
+
+  /**
+   * Allows the creation of this UI Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL ShadowView( Dali::Internal::CustomActor* internal );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SHADOW_VIEW_H
diff --git a/dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.cpp b/dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.cpp
new file mode 100644 (file)
index 0000000..db77511
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+SuperBlurView::SuperBlurView()
+{
+}
+
+SuperBlurView SuperBlurView::New( unsigned int blurLevels )
+{
+  return Internal::SuperBlurView::New( blurLevels );
+}
+
+SuperBlurView::SuperBlurView( const SuperBlurView& handle )
+: Control( handle )
+{
+}
+
+SuperBlurView& SuperBlurView::operator=( const SuperBlurView& rhs )
+{
+  if( &rhs != this )
+  {
+    Control::operator=(rhs);
+  }
+  return *this;
+}
+
+SuperBlurView::~SuperBlurView()
+{
+}
+
+SuperBlurView SuperBlurView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<SuperBlurView, Internal::SuperBlurView>( handle );
+}
+
+SuperBlurView::SuperBlurView(Internal::SuperBlurView& implementation)
+: Control( implementation )
+{
+}
+
+SuperBlurView::SuperBlurView(Dali::Internal::CustomActor* internal)
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::SuperBlurView>( internal );
+}
+
+void SuperBlurView::SetTexture( Texture texture )
+{
+  GetImpl(*this).SetTexture( texture );
+}
+
+Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
+{
+  return GetImpl(*this).GetBlurStrengthPropertyIndex();
+}
+
+void SuperBlurView::SetBlurStrength( float blurStrength )
+{
+  GetImpl(*this).SetBlurStrength( blurStrength );
+}
+
+float SuperBlurView::GetCurrentBlurStrength() const
+{
+  return GetImpl(*this).GetCurrentBlurStrength();
+}
+
+SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
+{
+  return GetImpl(*this).BlurFinishedSignal();
+}
+
+Texture SuperBlurView::GetBlurredTexture( unsigned int level )
+{
+  return GetImpl(*this).GetBlurredTexture( level );
+}
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h b/dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h
new file mode 100644 (file)
index 0000000..fbbbf9f
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef DALI_TOOLKIT_SUPER_BLUR_VIEW_H
+#define DALI_TOOLKIT_SUPER_BLUR_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class SuperBlurView;
+}
+
+/**
+ * @brief SuperBlurView accepts an image as input, and displays/animates it with various blur strength.
+ * Usage example:-
+ *
+ *  // initialise\n
+ *  SuperBlurView blurView = SuperBlurView::New( blurLevels );\n
+ *  blurView.SetSize();  // it is important to set the display size before set the input image!!
+ *  Stage::GetCurrent().Add(blurView);\n
+ *
+ *  // Set the input image
+ *  blurView.SetProperty( SuperBlurView::Property::IMAGE_URL, url );\n
+ *
+ *  // animate the strength of the blur - this can fade between no blur and full blur. .\n
+ *  Animation blurAnimation = Animation::New( ... );\n
+ *  blurAnimation.AnimateTo( Property( blurView, blurView.GetBlurStrengthPropertyIndex() ), ... );\n
+ *  blurAnimation.Play();\n
+ */
+class DALI_TOOLKIT_API SuperBlurView : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the SuperBlurView class.
+   */
+  struct Property
+  {
+    enum
+    {
+      IMAGE_URL = PROPERTY_START_INDEX, ///< name "imageUrl",    @see SetTexture,    type String
+    };
+  };
+
+  /**
+   * @brief Signal type for notifications.
+   */
+  typedef Signal< void (SuperBlurView source) > SuperBlurViewSignal;
+
+  /**
+   * @brief Creates an empty SuperBlurView handle.
+   */
+  SuperBlurView();
+
+  /**
+   * @brief Create an initialized SuperBlurView.
+   *
+   * @param[in] blurLevels The final blur strength level. It decides how many filtering passes are used to create the group of blurred textures.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static SuperBlurView New( unsigned int blurLevels );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   * @param[in] handle the handle to copy from
+   */
+  SuperBlurView( const SuperBlurView& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @param[in] rhs the handle to copy from
+   * @return a reference to this
+   */
+  SuperBlurView& operator=( const SuperBlurView& rhs );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~SuperBlurView();
+
+  /**
+   * @brief Downcast an Object handle to SuperBlurView.
+   *
+   * If handle points to a SuperBlurView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a SuperBlurView or an uninitialized handle
+   */
+  static SuperBlurView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Sets a custom texture to be blurred.
+   *
+   * @param[in] texture The texture that the user wishes to blur
+   */
+  void SetTexture( Texture texture );
+
+  /**
+   * @brief Get the index of the property that can be used to fade the blur in / out.
+   *
+   * This is the overall strength of the blur.
+   * User can use this to animate the blur. A value of 0.0 is zero blur and 1.0 is full blur. Default is 0.0.
+   * @return Index of the property that can be used to fade the blur in / out
+   */
+  Dali::Property::Index GetBlurStrengthPropertyIndex() const;
+
+  /**
+   * @brief Set the blur strength to display the texture.
+   *
+   * @param[in] blurStrength The blur strength used to display the texture.
+   */
+  void SetBlurStrength( float blurStrength );
+
+  /**
+   * @brief Get the current blur strength.
+   *
+   * @return The current blur strength
+   */
+  float GetCurrentBlurStrength() const;
+
+  /**
+   * @brief Connect to this signal to be notified when the all the blurs have completed.
+   *
+   * @return The BlurFinished signal
+   */
+  SuperBlurViewSignal& BlurFinishedSignal();
+
+  /**
+   * @brief Get the blurred texture.
+   *
+   * Should wait for the BlurFinishedSignal before calling this method.
+   * @param[in] level Indicate which blurred texture to get, must be a value between 1 and  blurLevels
+   * @return The level-th blurred texture
+   */
+  Texture GetBlurredTexture( unsigned int level );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL SuperBlurView(Internal::SuperBlurView& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL SuperBlurView(Dali::Internal::CustomActor* internal);
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_SUPER_BLUR_VIEW_H */
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.cpp
new file mode 100755 (executable)
index 0000000..97ee0fa
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
+#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextEditor
+{
+
+InputMethodContext GetInputMethodContext( TextEditor textEditor )
+{
+  return GetImpl( textEditor ).GetInputMethodContext();
+}
+
+} // namespace DevelTextEditor
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h
new file mode 100755 (executable)
index 0000000..4d600b5
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef DALI_TOOLKIT_TEXT_EDITOR_DEVEL_H
+#define DALI_TOOLKIT_TEXT_EDITOR_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/input-method-context.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextEditor
+{
+
+namespace Property
+{
+  enum Type
+  {
+      RENDERING_BACKEND = Dali::Toolkit::TextEditor::Property::RENDERING_BACKEND,
+      TEXT = Dali::Toolkit::TextEditor::Property::TEXT,
+      TEXT_COLOR = Dali::Toolkit::TextEditor::Property::TEXT_COLOR,
+      FONT_FAMILY = Dali::Toolkit::TextEditor::Property::FONT_FAMILY,
+      FONT_STYLE = Dali::Toolkit::TextEditor::Property::FONT_STYLE,
+      POINT_SIZE = Dali::Toolkit::TextEditor::Property::POINT_SIZE,
+      HORIZONTAL_ALIGNMENT = Dali::Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT,
+      SCROLL_THRESHOLD = Dali::Toolkit::TextEditor::Property::SCROLL_THRESHOLD,
+      SCROLL_SPEED = Dali::Toolkit::TextEditor::Property::SCROLL_SPEED,
+      PRIMARY_CURSOR_COLOR = Dali::Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR,
+      SECONDARY_CURSOR_COLOR = Dali::Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR,
+      ENABLE_CURSOR_BLINK = Dali::Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK,
+      CURSOR_BLINK_INTERVAL = Dali::Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL,
+      CURSOR_BLINK_DURATION = Dali::Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION,
+      CURSOR_WIDTH = Dali::Toolkit::TextEditor::Property::CURSOR_WIDTH,
+      GRAB_HANDLE_IMAGE = Dali::Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE,
+      GRAB_HANDLE_PRESSED_IMAGE = Dali::Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE,
+      SELECTION_HANDLE_IMAGE_LEFT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT,
+      SELECTION_HANDLE_IMAGE_RIGHT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT,
+      SELECTION_HANDLE_PRESSED_IMAGE_LEFT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT,
+      SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT,
+      SELECTION_HANDLE_MARKER_IMAGE_LEFT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT,
+      SELECTION_HANDLE_MARKER_IMAGE_RIGHT = Dali::Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT,
+      SELECTION_HIGHLIGHT_COLOR = Dali::Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR,
+      DECORATION_BOUNDING_BOX = Dali::Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX,
+      ENABLE_MARKUP = Dali::Toolkit::TextEditor::Property::ENABLE_MARKUP,
+      INPUT_COLOR = Dali::Toolkit::TextEditor::Property::INPUT_COLOR,
+      INPUT_FONT_FAMILY = Dali::Toolkit::TextEditor::Property::INPUT_FONT_FAMILY,
+      INPUT_FONT_STYLE = Dali::Toolkit::TextEditor::Property::INPUT_FONT_STYLE,
+      INPUT_POINT_SIZE = Dali::Toolkit::TextEditor::Property::INPUT_POINT_SIZE,
+      LINE_SPACING = Dali::Toolkit::TextEditor::Property::LINE_SPACING,
+      INPUT_LINE_SPACING = Dali::Toolkit::TextEditor::Property::INPUT_LINE_SPACING,
+      UNDERLINE = Dali::Toolkit::TextEditor::Property::UNDERLINE,
+      INPUT_UNDERLINE = Dali::Toolkit::TextEditor::Property::INPUT_UNDERLINE,
+      SHADOW = Dali::Toolkit::TextEditor::Property::SHADOW,
+      INPUT_SHADOW = Dali::Toolkit::TextEditor::Property::INPUT_SHADOW,
+      EMBOSS = Dali::Toolkit::TextEditor::Property::EMBOSS,
+      INPUT_EMBOSS = Dali::Toolkit::TextEditor::Property::INPUT_EMBOSS,
+      OUTLINE = Dali::Toolkit::TextEditor::Property::OUTLINE,
+      INPUT_OUTLINE = Dali::Toolkit::TextEditor::Property::INPUT_OUTLINE,
+      SMOOTH_SCROLL = Dali::Toolkit::TextEditor::Property::SMOOTH_SCROLL,
+      SMOOTH_SCROLL_DURATION = Dali::Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION,
+      ENABLE_SCROLL_BAR = Dali::Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR,
+      SCROLL_BAR_SHOW_DURATION = Dali::Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION,
+      SCROLL_BAR_FADE_DURATION = Dali::Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION,
+      PIXEL_SIZE = Dali::Toolkit::TextEditor::Property::PIXEL_SIZE,
+      LINE_COUNT = Dali::Toolkit::TextEditor::Property::LINE_COUNT,
+      ENABLE_SELECTION = Dali::Toolkit::TextEditor::Property::ENABLE_SELECTION,
+      PLACEHOLDER = Dali::Toolkit::TextEditor::Property::PLACEHOLDER,
+      LINE_WRAP_MODE = Dali::Toolkit::TextEditor::Property::LINE_WRAP_MODE,
+
+      /**
+       * @brief The text to display when the TextEditor is empty and inactive.
+       * @details Name "placeholderText", type Property::STRING.
+       */
+      PLACEHOLDER_TEXT,
+
+      /**
+       * @brief The placeholder-text color.
+       * @details Name "placeholderTextColor", type Property::VECTOR4.
+       */
+      PLACEHOLDER_TEXT_COLOR,
+
+      /**
+       * @brief Enables Text selection using Shift key.
+       * @details Name "enableShiftSelection", type Property::BOOLEAN.
+       */
+      ENABLE_SHIFT_SELECTION,
+
+      /**
+       * @brief Enables the grab handles for text selection.
+       * @details Name "enableGrabHandle", type Property::BOOLEAN.
+       * @note The default value is true, which means the grab handles are enabled by default.
+       */
+      ENABLE_GRAB_HANDLE,
+
+      /**
+       * @brief Modifies the default text alignment to match the direction of the system language.
+       * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write
+       * @note The default value is false
+       */
+      MATCH_SYSTEM_LANGUAGE_DIRECTION
+  };
+
+} // namespace Property
+
+/**
+ * @brief Return the input method context of TextEditor.
+ *
+ * @param[in] textEditor The instance of TextEditor.
+ * @return InputMethodContext instance.
+ */
+DALI_TOOLKIT_API InputMethodContext GetInputMethodContext( TextEditor textEditor );
+
+} // namespace DevelTextEditor
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_EDITOR_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-field-devel.cpp b/dali-toolkit/devel-api/controls/text-controls/text-field-devel.cpp
new file mode 100755 (executable)
index 0000000..a53ef4a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextField
+{
+
+InputMethodContext GetInputMethodContext( TextField textField )
+{
+  return GetImpl( textField ).GetInputMethodContext();
+}
+
+void SelectWholeText( TextField textField )
+{
+  GetImpl( textField ).SelectWholeText();
+}
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-field-devel.h
new file mode 100755 (executable)
index 0000000..3a4864c
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef DALI_TOOLKIT_TEXT_FIELD_DEVEL_H
+#define DALI_TOOLKIT_TEXT_FIELD_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/input-method-context.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextField
+{
+
+namespace Property
+{
+  enum
+  {
+      RENDERING_BACKEND = Dali::Toolkit::TextField::Property::RENDERING_BACKEND,
+      TEXT = Dali::Toolkit::TextField::Property::TEXT,
+      PLACEHOLDER_TEXT = Dali::Toolkit::TextField::Property::PLACEHOLDER_TEXT,
+      PLACEHOLDER_TEXT_FOCUSED = Dali::Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED,
+      FONT_FAMILY = Dali::Toolkit::TextField::Property::FONT_FAMILY,
+      FONT_STYLE = Dali::Toolkit::TextField::Property::FONT_STYLE,
+      POINT_SIZE = Dali::Toolkit::TextField::Property::POINT_SIZE,
+      MAX_LENGTH = Dali::Toolkit::TextField::Property::MAX_LENGTH,
+      EXCEED_POLICY = Dali::Toolkit::TextField::Property::EXCEED_POLICY,
+      HORIZONTAL_ALIGNMENT = Dali::Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT,
+      VERTICAL_ALIGNMENT = Dali::Toolkit::TextField::Property::VERTICAL_ALIGNMENT,
+      TEXT_COLOR = Dali::Toolkit::TextField::Property::TEXT_COLOR,
+      PLACEHOLDER_TEXT_COLOR = Dali::Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR,
+      RESERVED_PROPERTY_01 = Dali::Toolkit::TextField::Property::RESERVED_PROPERTY_01,
+      RESERVED_PROPERTY_02 = Dali::Toolkit::TextField::Property::RESERVED_PROPERTY_02,
+      PRIMARY_CURSOR_COLOR = Dali::Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR,
+      SECONDARY_CURSOR_COLOR = Dali::Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR,
+      ENABLE_CURSOR_BLINK = Dali::Toolkit::TextField::Property::ENABLE_CURSOR_BLINK,
+      CURSOR_BLINK_INTERVAL = Dali::Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL,
+      CURSOR_BLINK_DURATION = Dali::Toolkit::TextField::Property::CURSOR_BLINK_DURATION,
+      CURSOR_WIDTH = Dali::Toolkit::TextField::Property::CURSOR_WIDTH,
+      GRAB_HANDLE_IMAGE = Dali::Toolkit::TextField::Property::GRAB_HANDLE_IMAGE,
+      GRAB_HANDLE_PRESSED_IMAGE = Dali::Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE,
+      SCROLL_THRESHOLD = Dali::Toolkit::TextField::Property::SCROLL_THRESHOLD,
+      SCROLL_SPEED = Dali::Toolkit::TextField::Property::SCROLL_SPEED,
+      SELECTION_HANDLE_IMAGE_LEFT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT,
+      SELECTION_HANDLE_IMAGE_RIGHT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT,
+      SELECTION_HANDLE_PRESSED_IMAGE_LEFT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT,
+      SELECTION_HANDLE_PRESSED_IMAGE_RIGHT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT,
+      SELECTION_HANDLE_MARKER_IMAGE_LEFT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT,
+      SELECTION_HANDLE_MARKER_IMAGE_RIGHT = Dali::Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT,
+      SELECTION_HIGHLIGHT_COLOR = Dali::Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR,
+      DECORATION_BOUNDING_BOX = Dali::Toolkit::TextField::Property::DECORATION_BOUNDING_BOX,
+      INPUT_METHOD_SETTINGS = Dali::Toolkit::TextField::Property::INPUT_METHOD_SETTINGS,
+      INPUT_COLOR = Dali::Toolkit::TextField::Property::INPUT_COLOR,
+      ENABLE_MARKUP = Dali::Toolkit::TextField::Property::ENABLE_MARKUP,
+      INPUT_FONT_FAMILY = Dali::Toolkit::TextField::Property::INPUT_FONT_FAMILY,
+      INPUT_FONT_STYLE = Dali::Toolkit::TextField::Property::INPUT_FONT_STYLE,
+      INPUT_POINT_SIZE = Dali::Toolkit::TextField::Property::INPUT_POINT_SIZE,
+      UNDERLINE = Dali::Toolkit::TextField::Property::UNDERLINE,
+      INPUT_UNDERLINE = Dali::Toolkit::TextField::Property::INPUT_UNDERLINE,
+      SHADOW = Dali::Toolkit::TextField::Property::SHADOW,
+      INPUT_SHADOW = Dali::Toolkit::TextField::Property::INPUT_SHADOW,
+      EMBOSS = Dali::Toolkit::TextField::Property::EMBOSS,
+      INPUT_EMBOSS = Dali::Toolkit::TextField::Property::INPUT_EMBOSS,
+      OUTLINE = Dali::Toolkit::TextField::Property::OUTLINE,
+      INPUT_OUTLINE = Dali::Toolkit::TextField::Property::INPUT_OUTLINE,
+      HIDDEN_INPUT_SETTINGS = Dali::Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS,
+      PIXEL_SIZE = Dali::Toolkit::TextField::Property::PIXEL_SIZE,
+      ENABLE_SELECTION = Dali::Toolkit::TextField::Property::ENABLE_SELECTION,
+      PLACEHOLDER = Dali::Toolkit::TextField::Property::PLACEHOLDER,
+      ELLIPSIS = Dali::Toolkit::TextField::Property::ELLIPSIS,
+
+      /**
+       * @brief Enables Text selection using Shift key.
+       * @details Name "enableShiftSelection", type Property::BOOLEAN.
+       */
+      ENABLE_SHIFT_SELECTION = ELLIPSIS + 1,
+
+      /**
+       * @brief Enables the grab handles for text selection.
+       * @details Name "enableGrabHandle", type Property::BOOLEAN.
+       * @note The default value is true, which means the grab handles are enabled by default.
+       */
+      ENABLE_GRAB_HANDLE = ELLIPSIS + 2,
+
+      /**
+       * @brief Modifies the default text alignment to match the direction of the system language.
+       * @details Name "matchSystemLanguageDirection", type (Property::BOOLEAN), Read/Write
+       * @note The default value is false
+       */
+      MATCH_SYSTEM_LANGUAGE_DIRECTION = ELLIPSIS + 3,
+
+      /**
+        * @brief Enables the grab handle popup for text selection.
+        * @details Name "enableGrabHandlePopup", type Property::BOOLEAN.
+        * @note The default value is true, which means the grab handle popup is enabled by default.
+        */
+      ENABLE_GRAB_HANDLE_POPUP = ELLIPSIS + 4,
+
+      /**
+       * @brief The default text background parameters.
+       * @details Name "textBackground", type Property::VECTOR4.
+       * @note Use "textBackground" as property name to avoid conflict with Control's "background" property.
+       * @note The default value is Color::TRANSPARENT.
+       */
+      BACKGROUND = ELLIPSIS + 5
+
+  };
+} // namespace Property
+
+/**
+ * @brief Return the input method context of TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return InputMethodContext instance.
+ */
+DALI_TOOLKIT_API InputMethodContext GetInputMethodContext( TextField textField );
+
+/**
+ * @brief Select the whole text of TextField.
+ *
+ * @param[in] textField The instance of TextField.
+ * @return InputMethodContext instance.
+ */
+DALI_TOOLKIT_API void SelectWholeText( TextField textField );
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_FIELD_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h
new file mode 100755 (executable)
index 0000000..72ad6f8
--- /dev/null
@@ -0,0 +1,153 @@
+#ifndef DALI_TOOLKIT_TEXT_LABEL_DEVEL_H
+#define DALI_TOOLKIT_TEXT_LABEL_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextLabel
+{
+
+namespace Property
+{
+  enum Type
+  {
+    RENDERING_BACKEND = Dali::Toolkit::TextLabel::Property::RENDERING_BACKEND,
+    TEXT = Dali::Toolkit::TextLabel::Property::TEXT,
+    FONT_FAMILY = Dali::Toolkit::TextLabel::Property::FONT_FAMILY,
+    FONT_STYLE = Dali::Toolkit::TextLabel::Property::FONT_STYLE,
+    POINT_SIZE = Dali::Toolkit::TextLabel::Property::POINT_SIZE,
+    MULTI_LINE = Dali::Toolkit::TextLabel::Property::MULTI_LINE,
+    HORIZONTAL_ALIGNMENT = Dali::Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT,
+    VERTICAL_ALIGNMENT = Dali::Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT,
+    UNUSED_PROPERTY_TEXT_COLOR = Dali::Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR,
+    RESERVED_PROPERTY_01 = Dali::Toolkit::TextLabel::Property::RESERVED_PROPERTY_01,
+    RESERVED_PROPERTY_02 = Dali::Toolkit::TextLabel::Property::RESERVED_PROPERTY_02,
+    RESERVED_PROPERTY_03 = Dali::Toolkit::TextLabel::Property::RESERVED_PROPERTY_03,
+    RESERVED_PROPERTY_04 = Dali::Toolkit::TextLabel::Property::RESERVED_PROPERTY_04,
+    RESERVED_PROPERTY_05 = Dali::Toolkit::TextLabel::Property::RESERVED_PROPERTY_05,
+    ENABLE_MARKUP = Dali::Toolkit::TextLabel::Property::ENABLE_MARKUP,
+    ENABLE_AUTO_SCROLL = Dali::Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL,
+    AUTO_SCROLL_SPEED = Dali::Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED,
+    AUTO_SCROLL_LOOP_COUNT = Dali::Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT,
+    AUTO_SCROLL_GAP = Dali::Toolkit::TextLabel::Property::AUTO_SCROLL_GAP,
+    LINE_SPACING = Dali::Toolkit::TextLabel::Property::LINE_SPACING,
+    UNDERLINE = Dali::Toolkit::TextLabel::Property::UNDERLINE,
+    SHADOW = Dali::Toolkit::TextLabel::Property::SHADOW,
+    EMBOSS = Dali::Toolkit::TextLabel::Property::EMBOSS,
+    OUTLINE = Dali::Toolkit::TextLabel::Property::OUTLINE,
+    PIXEL_SIZE = Dali::Toolkit::TextLabel::Property::PIXEL_SIZE,
+    ELLIPSIS = Dali::Toolkit::TextLabel::Property::ELLIPSIS,
+    AUTO_SCROLL_LOOP_DELAY = Dali::Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY,
+    AUTO_SCROLL_STOP_MODE = Dali::Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE,
+    LINE_COUNT = Dali::Toolkit::TextLabel::Property::LINE_COUNT,
+    LINE_WRAP_MODE = Dali::Toolkit::TextLabel::Property::LINE_WRAP_MODE,
+
+    /**
+     * @brief The direction of the layout.
+     * @details Name "textDirection", type [Type](@ref Dali::Toolkit::DevelText::TextDirection::Type) (Property::INTEGER), Read/Write
+     * @note The text direction can be changed only by replacing the text itself.
+     * @see TextDirection::Type for supported values.
+     */
+    TEXT_DIRECTION,
+
+    /**
+     * @brief Alignment of text within area of single line
+     * @details Name "verticalLineAlignment", type [Type](@ref Dali::Toolkit::DevelText::VerticalLineAlignment::Type) (Property::INTEGER), Read/Write
+     * @note The default value is TOP
+     * @see VerticalLineAlignment::Type for supported values
+     */
+    VERTICAL_LINE_ALIGNMENT,
+
+    /**
+     * @brief The default text background parameters.
+     * @details Name "textBackground", type Property::MAP.
+     * @note Use "textBackground" as property name to avoid conflict with Control's "background" property
+     *
+     * The background map contains the following keys:
+     *
+     * | %Property Name       | Type     | Required | Description                                                                                                        |
+     * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+     * | enable               | BOOLEAN  | No       | True to enable the background or false to disable (the default value is false)                                     |
+     * | color                | VECTOR4  | No       | The color of the background (the default value is Color::CYAN)                                                     |
+     */
+    BACKGROUND,
+
+    /**
+     * @brief Ignore spaces after text.
+     * @details Name "ignoreSpacesAfterText", type (Property::BOLEAN), Read/Write
+     * @note The default value is true
+     */
+    IGNORE_SPACES_AFTER_TEXT,
+
+    /**
+     * @brief Modifies the default text alignment to match the direction of the system language.
+     * @details Name "matchSystemLanguageDirection", type (Property::BOLEAN), Read/Write
+     * @note The default value is false
+     *
+     * If MATCH_SYSTEM_LANGUAGE_DIRECTION property set true, the default text alignment to match the direction of the system language.
+     *
+     * ex) Current system language direction LTR.
+     *     TextLabel::New("Hello world \n  ﻡﺮﺤﺑﺍ. ");
+     *     TextLabel::Property::HORIZONTAL_ALIGNMENT, "END"
+     *
+     * | TextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION                 |
+     * |-----------------------------------------------------------------------
+     * |        false (default)            |                true              |
+     * |-----------------------------------|----------------------------------|
+     * |                     Hello world   |                  Hello world     |
+     * |   ﻡﺮﺤﺑﺍ.                          |                      ﻡﺮﺤﺑﺍ.      |
+     *
+     */
+    MATCH_SYSTEM_LANGUAGE_DIRECTION,
+
+    /**
+     * @brief The text fit parameters.
+     * @details Name "textFit", type Property::MAP.
+     * @note The default value is false
+     *
+     * The textFit map contains the following keys:
+     *
+     * | %Property Name       | Type     | Required | Description                                                                                                        |
+     * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+     * | enable               | BOOLEAN  | No       | True to enable the text fit or false to disable (the default value is false)                                     |
+     * | minSize              | FLOAT    | No       | Minimum Size for text fit (the default value is 10.f)                                                     |
+     * | maxSize              | FLOAT    | No       | Maximum Size for text fit (the default value is 100.f)                                                     |
+     * | stepSize             | FLOAT    | No       | Step Size for font increase (the default value is 1.f)                                                     |
+     * | fontSizeType         | STRING   | No       | The size type of font, You can choose between "pointSize" or "pixelSize". (the default value is "pointSize")                                                     |
+     */
+    TEXT_FIT,
+
+  };
+
+} // namespace Property
+
+} // namespace DevelTextLabel
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LABEL_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h
new file mode 100644 (file)
index 0000000..49cacd5
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Interface used to receive the TextSelectionPopup's button callbacks.
+ */
+class TextSelectionPopupCallbackInterface
+{
+public:
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~TextSelectionPopupCallbackInterface()
+  {}
+
+  /**
+   * @brief Called when a button is touched.
+   *
+   * @param[in] button The button identifier.
+   */
+  virtual void TextPopupButtonTouched( TextSelectionPopup::Buttons button ) = 0;
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_TEXT_SELECTION_POPUP_CALLBACK_INTERFACE_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.cpp b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.cpp
new file mode 100644 (file)
index 0000000..28a5819
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextSelectionPopup TextSelectionPopup::New( TextSelectionPopupCallbackInterface* callbackInterface )
+{
+  return Internal::TextSelectionPopup::New( callbackInterface );
+}
+
+TextSelectionPopup::TextSelectionPopup()
+{
+}
+
+TextSelectionPopup::TextSelectionPopup( const TextSelectionPopup& handle )
+: Control( handle )
+{
+}
+
+TextSelectionPopup& TextSelectionPopup::operator=( const TextSelectionPopup& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextSelectionPopup::~TextSelectionPopup()
+{
+}
+
+TextSelectionPopup TextSelectionPopup::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextSelectionPopup, Internal::TextSelectionPopup>(handle);
+}
+
+void TextSelectionPopup::EnableButtons( Toolkit::TextSelectionPopup::Buttons buttonsToEnable )
+{
+  GetImpl(*this).EnableButtons( buttonsToEnable );
+}
+
+void TextSelectionPopup::RaiseAbove( Layer target )
+{
+  GetImpl(*this).RaiseAbove( target );
+}
+
+void TextSelectionPopup::ShowPopup()
+{
+  GetImpl(*this).ShowPopup();
+}
+
+void TextSelectionPopup::HidePopup()
+{
+  GetImpl(*this).HidePopup();
+}
+
+TextSelectionPopup::TextSelectionPopup( Internal::TextSelectionPopup& implementation )
+: Control(implementation)
+{
+}
+
+TextSelectionPopup::TextSelectionPopup( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextSelectionPopup>( internal );
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h
new file mode 100644 (file)
index 0000000..ccc25cc
--- /dev/null
@@ -0,0 +1,279 @@
+#ifndef DALI_TOOLKIT_TEXT_SELECTION_POPUP_H
+#define DALI_TOOLKIT_TEXT_SELECTION_POPUP_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class TextSelectionPopupCallbackInterface;
+
+namespace Internal DALI_INTERNAL
+{
+class TextSelectionPopup;
+}
+
+/**
+ * @brief A control which provides a Popup with a number of buttons
+ *
+ * The style of the pop can be set through style sheets, this includes the images for the buttons
+ * A Show and Hide API is provided.
+ *
+ * If the buttons exceed the size constraints of the popup then it will offer scrolling.
+ *
+ *
+ */
+class DALI_TOOLKIT_API TextSelectionPopup : public Control
+{
+public:
+
+  enum Buttons
+  {
+    CUT = 1u << 0,
+    COPY = 1u << 1,
+    PASTE = 1u << 2,
+    SELECT = 1u << 3,
+    SELECT_ALL = 1u << 4,
+    CLIPBOARD = 1u << 5,
+    NONE = 1u << 6,
+  };
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the TextSelectionPopup class.
+   */
+  struct Property
+  {
+    enum
+    {
+      /**
+       * @brief The maximum size the Popup can be.
+       * @details Name "popupMaxSize", type Vector2.
+       */
+      POPUP_MAX_SIZE =  PROPERTY_START_INDEX,
+
+      /**
+       * @brief The minimum size the Popup can be.
+       * @details Name "popupMinSize", type Vector2.
+       */
+      POPUP_MIN_SIZE,
+
+      /**
+       * @brief The maximum size an option can be.
+       * @details Name "optionMaxSize", type Vector2.
+       */
+      OPTION_MAX_SIZE,
+
+      /**
+       * @brief The minimum size an option can be.
+       * @details Name "optionMinSize", type Vector2.
+       */
+      OPTION_MIN_SIZE,
+
+      /**
+       * @brief The size of the divider between options.
+       * @details Name "optionDividerSize", type Vector2.
+       */
+      OPTION_DIVIDER_SIZE,
+
+      /**
+       * @brief The image to use as the popup clipboard icon.
+       * @details Name "popupClipboardButtonImage", type string.
+       */
+      POPUP_CLIPBOARD_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The image to use as the popup cut icon.
+       * @details Name "popupCutButtonImage", type string.
+       */
+      POPUP_CUT_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The image to use as the popup copy icon.
+       * @details Name "popupCopyButtonImage", type string.
+       */
+      POPUP_COPY_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The image to use as the popup paste icon.
+       * @details Name "popupPasteButtonImage", type string.
+       */
+      POPUP_PASTE_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The image to use as the popup select icon.
+       * @details Name "popupSelectButtonImage", type string.
+       */
+      POPUP_SELECT_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The image to use as the popup select all icon.
+       * @details Name "popupSelectAllButtonImage", type string.
+       */
+      POPUP_SELECT_ALL_BUTTON_ICON_IMAGE,
+
+      /**
+       * @brief The color of the divider between options.
+       * @details Name "popupDividerColor", type Vector4.
+       */
+      POPUP_DIVIDER_COLOR,
+
+      /**
+       * @brief The color of the icons (if supplied).
+       * @details Name "popupIconColor", type Vector4.
+       */
+      POPUP_ICON_COLOR,
+
+      /**
+       * @brief The color of the option when pressed.
+       * @details Name "popupPressedColor", type Vector4.
+       */
+      POPUP_PRESSED_COLOR,
+
+      /**
+       * @brief The image to use for the option when pressed.
+       * @details Name "popupPressedImage", type string.
+       */
+      POPUP_PRESSED_IMAGE,
+
+      /**
+       * @brief The duration of the fade-in animation.
+       * @details Name "popupFadeInDuration", type float.
+       */
+      POPUP_FADE_IN_DURATION,
+
+      /**
+       * @brief The duration of the fade-out animation.
+       * @details Name "popupFadeOutDuration", type float.
+       */
+      POPUP_FADE_OUT_DURATION,
+
+      /**
+       * @brief The popup background can have a separate border with a different color.
+       * @details Name "backgroundBorder", type Property::Map.
+       * @note Optional.
+       */
+      BACKGROUND_BORDER
+    };
+  };
+
+  /**
+   * Create the TextSelectionPopup control.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   * @return A handle to the TextSelectionPopup control.
+   */
+  static TextSelectionPopup New( TextSelectionPopupCallbackInterface* callbackInterface );
+
+  /**
+   * @brief Creates an empty handle.
+   */
+  TextSelectionPopup();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] handle The handle to copy from.
+   */
+  TextSelectionPopup( const TextSelectionPopup& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] handle The handle to copy from.
+   * @return A reference to this.
+   */
+  TextSelectionPopup& operator=( const TextSelectionPopup& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TextSelectionPopup();
+
+  /**
+   * @brief Downcast a handle to TextSelectionPopup.
+   *
+   * If the BaseHandle points is a TextSelectionPopup the downcast returns a valid handle.
+   * If not the returned handle is left empty.
+   *
+   * @param[in] handle Handle to an object
+   * @return handle to a TextSelectionPopup or an empty handle
+   */
+  static TextSelectionPopup DownCast( BaseHandle handle );
+
+  /**
+   * @brief Specify which buttons to show in Popup
+   * @param[in] buttonsToEnable Buttons to enable
+   */
+  void EnableButtons( Toolkit::TextSelectionPopup::Buttons buttonsToEnable );
+
+  /**
+   * @brief Raises the toolbar's layer above the given @e target layer.
+   *
+   * @param[in] target The layer to get above of.
+   */
+  void RaiseAbove( Layer target );
+
+  /**
+   * @brief Show the Popup if not being shown
+   */
+  void ShowPopup();
+
+  /**
+   * @brief Hide the Popup if shown
+   */
+  void HidePopup();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in] implementation The Control implementation.
+   */
+  DALI_INTERNAL TextSelectionPopup( Internal::TextSelectionPopup& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL TextSelectionPopup( Dali::Internal::CustomActor* internal );
+
+}; // Class TextSelectionPopup
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SELECTION_POPUP_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp b/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.cpp
new file mode 100644 (file)
index 0000000..84bd8db
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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 <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextSelectionToolbar TextSelectionToolbar::New()
+{
+  return Internal::TextSelectionToolbar::New();
+}
+
+TextSelectionToolbar::TextSelectionToolbar()
+{
+}
+
+TextSelectionToolbar::TextSelectionToolbar( const TextSelectionToolbar& handle )
+: Control( handle )
+{
+}
+
+TextSelectionToolbar& TextSelectionToolbar::operator=( const TextSelectionToolbar& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextSelectionToolbar::~TextSelectionToolbar()
+{
+}
+
+void TextSelectionToolbar::AddOption( Actor& option )
+{
+  GetImpl(*this).AddOption(option);
+}
+
+void TextSelectionToolbar::AddDivider( Actor& divider )
+{
+  GetImpl(*this).AddDivider( divider );
+}
+
+void TextSelectionToolbar::ResizeDividers( Size& size )
+{
+  GetImpl(*this).ResizeDividers( size );
+}
+
+void TextSelectionToolbar::RaiseAbove( Layer target )
+{
+  GetImpl(*this).RaiseAbove( target );
+}
+
+void TextSelectionToolbar::ScrollTo( const Vector2& position )
+{
+  GetImpl(*this).ScrollTo( position );
+}
+
+TextSelectionToolbar TextSelectionToolbar::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextSelectionToolbar, Internal::TextSelectionToolbar>(handle);
+}
+
+TextSelectionToolbar::TextSelectionToolbar( Internal::TextSelectionToolbar& implementation )
+: Control(implementation)
+{
+}
+
+TextSelectionToolbar::TextSelectionToolbar( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextSelectionToolbar>( internal );
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h b/dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h
new file mode 100644 (file)
index 0000000..e8adee9
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H
+#define DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TextSelectionToolbar;
+}
+
+/**
+ * @brief A control which provides a Popup with a number of buttons
+ *
+ * The style of the pop can be set through style sheets, this includes the images for the buttons
+ * A Show and Hide API is provided.
+ *
+ * If the buttons exceed the size constraints of the popup then it will offer scrolling.
+ *
+ *
+ */
+class DALI_TOOLKIT_API TextSelectionToolbar : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the TextSelectionToolbar class.
+   */
+  struct Property
+  {
+    enum
+    {
+      MAX_SIZE =  PROPERTY_START_INDEX, ///< name "maxSize",                 The maximum size the Popup can be,              type VECTOR2
+      ENABLE_OVERSHOOT,                 ///< name "enableOvershoot",         Whether the overshoot image is enabled,         type BOOLEAN
+      ENABLE_SCROLL_BAR,                ///< name "enableScrollBar",         Whether the scroll-bar is enabled,              type BOOLEAN
+      SCROLL_BAR_PADDING,               ///< name "scrollBarPadding",        The padding used to position the scroll bar,    type VECTOR2
+      SCROLL_VIEW,                      ///< name "scrollView",              Properties to set on scroll view                type Property::Map
+    };
+  };
+
+  /**
+   * Create the TextSelectionToolbar control.
+   * @return A handle to the TextSelectionToolbar control.
+   */
+  static TextSelectionToolbar New();
+
+  /**
+   * @brief Creates an empty handle.
+   */
+  TextSelectionToolbar();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] handle The handle to copy from.
+   */
+  TextSelectionToolbar( const TextSelectionToolbar& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] handle The handle to copy from.
+   * @return A reference to this.
+   */
+  TextSelectionToolbar& operator=( const TextSelectionToolbar& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TextSelectionToolbar();
+
+
+  /**
+   * @brief Add a option to the the Tool bar
+   * @param[in] option Option actor to add
+   */
+  void AddOption( Actor& option );
+
+  /**
+   * @brief Add a divider to the the Tool bar
+   * @param[in] divider Actor to be used as divider
+   */
+  void AddDivider( Actor& divider );
+
+  /**
+   *  @brief ResizeDividers
+   *  @param[in] size New size of dividers, provide 0 for height to automatically set height
+   */
+  void ResizeDividers( Size& size );
+
+  /**
+   * @brief Raises the layer above the given @e target layer.
+   *
+   * @param[in] target The layer to get above of.
+   */
+  void RaiseAbove( Layer target );
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(const Vector2&)
+   */
+  void ScrollTo( const Vector2& position );
+
+  /**
+   * @brief Downcast a handle to TextSelectionToolbar.
+   *
+   * If the BaseHandle points is a TextSelectionToolbar the downcast returns a valid handle.
+   * If not the returned handle is left empty.
+   *
+   * @param[in] handle Handle to an object
+   * @return handle to a TextSelectionToolbar or an empty handle
+   */
+  static TextSelectionToolbar DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in] implementation The Control implementation.
+   */
+  DALI_INTERNAL TextSelectionToolbar( Internal::TextSelectionToolbar& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL TextSelectionToolbar( Dali::Internal::CustomActor* internal );
+
+}; // Class TextSelectionToolbar
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SELECTION_TOOLBAR_H
diff --git a/dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h
new file mode 100644 (file)
index 0000000..b663105
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef DALI_TOOLKIT_TEXT_STYLE_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_TEXT_STYLE_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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
+{
+
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+namespace DevelText
+{
+
+namespace Shadow
+{
+
+/**
+ * @brief Used by Text controls to show different styles of text.
+ *
+ */
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The color of the shadow.
+   * @details Name "color", type Property::STRING or Property::VECTOR4.
+   * @note Optional. If not provided the default color (BLACK) is used.
+   */
+  COLOR,
+
+  /**
+   * @brief The offset in pixels of the shadow.
+   * @details Name "offset", type Property::STRING or Property::VECTOR2. i.e "3.0 3.0" or Vector2( 3.f, 3.f )
+   * @note Optional. If not provided then the shadow is not enabled.
+   */
+  OFFSET,
+
+  /**
+   * @brief The radius of the Gaussian blur for the soft shadow.
+   * @details Name "blurRadius", type Property::STRING or Property::FLOAT. i.e "5.0" or 5.f
+   * @note Optional. If not provided then the soft shadow is not enabled.
+   */
+  BLUR_RADIUS
+};
+
+} // namespace Property
+
+} // namespace Shadow
+
+namespace Underline
+{
+
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief Whether the underline is enabled.
+   * @details Name "enable", type Property::STRING or Property::BOOLEAN. i.e. "true", "false", true or false
+   * @note Optional. By default is disabled.
+   */
+  ENABLE,
+
+  /**
+   * @brief The color of the underline.
+   * @details Name "color", type Property::STRING or Property::VECTOR4
+   * @note Optional. If not provided then the color of the text is used.
+   */
+  COLOR,
+
+  /**
+   * @brief The height in pixels of the underline.
+   * @details Name "height", type Property::STRING or Property::FLOAT. i.e. "1.0" or 1.f
+   * @note Optional. If not provided then the default height is used (1 pixel).
+   */
+  HEIGHT
+};
+
+} // namespace Property
+
+} // namespace Underline
+
+namespace Outline
+{
+
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The color of the outline.
+   * @details Name "color", type Property::STRING or Property::VECTOR4
+   * @note Optional. If not provided the default color (WHITE) is used.
+   */
+  COLOR,
+
+  /**
+   * @brief The width in pixels of the outline.
+   * @details Name "width", type Property::STRING or Property::FLOAT i.e. "1.0" or 1.f
+   * @note Optional. If not provided then the outline is not enabled.
+   */
+  WIDTH
+};
+
+} // namespace Property
+
+} // namespace Outline
+
+namespace Background
+{
+
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief Whether to paint the text's background.
+   * @details Name "enable", type Property::STRING or Property::BOOLEAN i.e. "true", "false", true or false
+   * @note Optional. By default is disabled.
+   */
+  ENABLE,
+
+  /**
+   * @brief The color of the background.
+   * @details Name "color", type Property::STRING or Property::VECTOR4
+   * @note Optional. If not provided the default color (CYAN) is used.
+   */
+  COLOR
+};
+
+} // namespace Property
+
+} // namespace Background
+
+} // namespace DevelText
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_STYLE_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/devel-api/controls/tool-bar/tool-bar.cpp b/dali-toolkit/devel-api/controls/tool-bar/tool-bar.cpp
new file mode 100644 (file)
index 0000000..5618410
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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 "tool-bar.h"
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/internal/controls/tool-bar/tool-bar-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+const Toolkit::Alignment::Padding ToolBar::DEFAULT_PADDING( 0.f, 0.f, 0.f, 0.f );
+
+ToolBar::ToolBar()
+{
+}
+
+ToolBar::ToolBar( const ToolBar& handle )
+: Control( handle )
+{
+}
+
+ToolBar& ToolBar::operator=( const ToolBar& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+ToolBar::~ToolBar()
+{
+}
+
+ToolBar ToolBar::New()
+{
+  return Internal::ToolBar::New();
+}
+
+ToolBar ToolBar::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ToolBar, Internal::ToolBar>(handle);
+}
+
+void ToolBar::AddControl( Actor control, float relativeSize, Toolkit::Alignment::Type alignment, const Toolkit::Alignment::Padding& padding )
+{
+  GetImpl( *this ).AddControl( control, relativeSize, alignment, padding );
+}
+
+void ToolBar::RemoveControl( Actor control )
+{
+  GetImpl( *this ).RemoveControl( control );
+}
+
+ToolBar::ToolBar( Internal::ToolBar& implementation )
+: Control( implementation )
+{
+}
+
+ToolBar::ToolBar( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ToolBar>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/tool-bar/tool-bar.h b/dali-toolkit/devel-api/controls/tool-bar/tool-bar.h
new file mode 100644 (file)
index 0000000..a9ad2e0
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef DALI_TOOLKIT_TOOL_BAR_H
+#define DALI_TOOLKIT_TOOL_BAR_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/alignment/alignment.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+class ToolBar;
+}
+
+/**
+ * Provides a tool bar where other controls (Dali::Actor) could be placed.
+ * controls could be added into three different groups: on the left, center or right.
+ * AddControl() and RemoveControl() methods should be used to add and remove controls. The use of Actor's Dali::Actor::Add() method
+ * is not forbidden, it adds controls on the left group with a size of 10% of the total tool bar size.
+ * Dali::Actor::Remove() method does nothing.
+ */
+class DALI_TOOLKIT_API ToolBar : public Control
+{
+public:
+  static const Toolkit::Alignment::Padding DEFAULT_PADDING; ///< Default padding space between controls. By default all values are set to 0.
+
+public:
+  /**
+   * Create a ToolBar handle; this can be initialised with ToolBar::New()
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  ToolBar();
+
+  /**
+   * Copy constructor. Creates another handle that points to the same real object
+   * @param handle to copy from
+   */
+  ToolBar( const ToolBar& handle );
+
+  /**
+   * Assignment operator. Changes this handle to point to another real object
+   */
+  ToolBar& operator=( const ToolBar& handle );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ToolBar();
+
+  /**
+   * Create an initialized ToolBar.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static ToolBar New();
+
+  /**
+   * Downcast an Object handle to ToolBar. If handle points to a ToolBar the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return handle to a ToolBar or an uninitialized handle
+   */
+  static ToolBar DownCast( BaseHandle handle );
+
+  /**
+   * Adds an additional control to the tool bar.
+   * @pre The tool bar needs to be initialized.
+   * @pre The alignment needs to be horizontal.
+   * @param control An Actor with the additional control.
+   * @param relativeSize Control's size as a percentage of the tool bar width.
+   * @param alignment Where to insert controls. Possible values are Toolkit::Alignment::Left, Toolkit::Alignment::Center or Toolkit::Alignment::Right.
+   * @param padding Padding values used for the added control (left, right, top, bottom). By default, no padding is added.
+   */
+  void AddControl( Actor control, float relativeSize, Toolkit::Alignment::Type alignment, const Toolkit::Alignment::Padding& padding = DEFAULT_PADDING );
+
+  /**
+   * Removes a control from the tool bar.
+   * @pre control must have been added before to this tool bar.
+   * @param control The control to be removed.
+   */
+  void RemoveControl( Actor control );
+
+public: // Not intended for application developers
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL ToolBar( Internal::ToolBar& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL ToolBar( Dali::Internal::CustomActor* internal );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOL_BAR_H
diff --git a/dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h b/dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h
new file mode 100644 (file)
index 0000000..d473cec
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef DALI_TOOLKIT_TOOLTIP_PROPERTIES_H
+#define DALI_TOOLKIT_TOOLTIP_PROPERTIES_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Tooltip
+{
+
+/**
+ * @brief The properties used for a Tooltip.
+ */
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The content to display.
+   * @details Name "content", type Property::STRING, Property::MAP or Property::ARRAY.
+   *          If Property::STRING is used, then the string is shown as a text and the default font style for a Tooltip will be used.
+   *          This can be overridden by passing in a Property::MAP of TextVisual properties. For text styling purposes, a Property::MAP excluding the TEXT property can be sent.
+   *          If a different Visual is required, then a Property::MAP defining that visual can be set.
+   *          If more than one visual is required, then a Property::ARRAY can be used. The contents are added to the layout as per their order in the array. Text has to be styled in the visual passed in (default toolkit style will not be used).
+   * @note Mandatory.
+   * @note If set using Property::STRING, then when retrieved, a Property::MAP is returned.
+   *       If set using a Property::MAP or Property::ARRAY, then the appropriate type is returned.
+   * @see Toolkit::TextVisual
+   */
+  CONTENT = CORE_PROPERTY_MAX_INDEX + 1,
+
+  /**
+   * @brief The layout of the content.
+   * @details Name "layout", type Property::VECTOR2.
+   *          The number of rows and columns expected.
+   *          ( 1, 2 ) means 1 row, 2 columns so the content will have two items placed on one row.
+   *          ( 2, 2 ) means 2 rows, 2 columns so the content will have 4 items with two items placed on each row.
+   * @note Optional.
+   * @note If not provided, the default is to put all items in the same row.
+   */
+  LAYOUT,
+
+  /**
+   * @brief Time to wait in seconds before a tooltip is shown while the is movement is within the allowed threshold.
+   * @details Name "waitTime", type Property::FLOAT.
+   * @note Optional.
+   * @note If not provided, the default is 0.5 seconds.
+   */
+  WAIT_TIME,
+
+  /**
+   * @brief The background of the tooltip.
+   * @details Name "background", type Property::STRING or Property::MAP.
+   *          If Property::STRING, then the path to the image is required and it's assumed that there are no borders.
+   * @note Optional.
+   * @note If not provided, the default is taken from the stylesheet.
+   * @note When retrieved, a Property::MAP is returned.
+   * @see Tooltip::Background
+   */
+  BACKGROUND,
+
+  /**
+   * @brief The tail used by the tooltip.
+   * @details Name "tail", type Property::BOOLEAN or Property::MAP.
+   *          If Property::BOOLEAN and true, then the default visuals are used for the tail.
+   *          A Property::MAP can be used to override the visuals for the tail.
+   * @note Optional.
+   * @note The default is false, i.e. to not show a tail.
+   * @note When retrieved, a Property::MAP is returned.
+   * @note If the popup has to be moved because it goes out of bounds, then the tail is not shown regardless of whether it is set or not.
+   * @see Tooltip::Tail
+   */
+  TAIL,
+
+  /**
+   * @brief The position of the tooltip in relation to the control.
+   * @details Name "position", type Tooltip::Position::Type (Property::INTEGER) or Property::STRING.
+   * @note Optional.
+   * @note If not provided, the default is Tooltip::Position::BELOW.
+   * @note When retrieved, a Tooltip::Position::Type (Property::INTEGER) is returned.
+   */
+  POSITION,
+
+  /**
+   * @brief If Tooltip::Position::HOVER_POINT is used for the POSITION, then this is the offset the tooltip is displayed at from the hover point.
+   * @details Name "hoverPointOffset", type Property::VECTOR2.
+   * @note Optional.
+   * @note If not provided, the default is Vector2( 10.0f, 10.0f ).
+   */
+  HOVER_POINT_OFFSET,
+
+  /**
+   * @brief The movement threshold allowed before showing (or hiding a popup).
+   * @details Name "movementThreshold", type Property::INTEGER.
+   *          This value is used as the threshold to hide the popup as well if DISAPPEAR_ON_MOVEMENT is set to true.
+   * @note Optional.
+   * @note If not provided, the default is 5.
+   */
+  MOVEMENT_THRESHOLD,
+
+  /**
+   * @brief If true, the tooltip will disappear after hover movement beyond a certain distance.
+   * @details Name "disappearOnMovement", type Property::BOOLEAN.
+   * @note Optional.
+   * @note If not provided, the default is to disappear only when moving out of bounds of the control.
+   */
+  DISAPPEAR_ON_MOVEMENT,
+};
+
+} // namespace Property
+
+namespace Background
+{
+
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief The image to use as the background.
+   * @details Name "visual", type Property::STRING.
+   */
+  VISUAL,
+
+  /**
+   * @brief The size of the borders in the order: left, right, bottom, top.
+   * @details Name "border", type Property::RECTANGLE.
+   *          This is different from the nPatch border as the it will place the content within the bounds specified.
+   *          For example, there could be some round corners in the image used and we may not want the content going over the rounded corners.
+   * @note Optional.
+   * @note If not provided, then then it is assumed that the image does not have a border.
+   */
+  BORDER
+};
+
+} // namespace Property
+
+} // namespace Background
+
+/**
+ * @brief The tail used by the tooltip.
+ */
+namespace Tail
+{
+
+/**
+ * @brief The properties of the tail used by the tooltip.
+ */
+namespace Property
+{
+
+enum
+{
+  /**
+   * @brief Whether to show the tail or not.
+   * @details Name "visibility", type Property::BOOLEAN.
+   * @note Optional.
+   * @note If the popup has to be moved because it goes out of bounds, then the tail is not shown regardless of whether it is set or not.
+   */
+  VISIBILITY,
+
+  /**
+   * @brief The image used for the tail if it is above the tooltip.
+   * @details Name "aboveVisual", type Property::STRING.
+   */
+  ABOVE_VISUAL,
+
+  /**
+   * @brief The image used for the tail if it is below the tooltip.
+   * @details Name "belowVisual", type Property::STRING.
+   */
+  BELOW_VISUAL
+};
+
+} // namespace Property
+
+} // namespace Tail
+
+namespace Position
+{
+
+/**
+ * @brief The position of the tooltip in relation to the control.
+ */
+enum Type
+{
+  ABOVE, ///< The tooltip will appear above the control.
+  BELOW, ///< The tooltip will appear below the control.
+  HOVER_POINT ///< The tooltip will appear near the hover point.
+};
+
+} // namespace Position
+
+} // namespace Tooltip
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TOOLTIP_PROPERTIES_H
diff --git a/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp b/dali-toolkit/devel-api/controls/video-view/video-view-devel.cpp
new file mode 100755 (executable)
index 0000000..317d34d
--- /dev/null
@@ -0,0 +1,41 @@
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/devel-api/controls/video-view/video-view-devel.h>\r
+#include <dali-toolkit/internal/controls/video-view/video-view-impl.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Toolkit\r
+{\r
+\r
+namespace DevelVideoView\r
+{\r
+\r
+Any GetMediaPlayer( VideoView videoView )\r
+{\r
+  return Dali::Toolkit::GetImpl( videoView ).GetMediaPlayer();\r
+}\r
+\r
+\r
+} // namespace DevelVideoView\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
diff --git a/dali-toolkit/devel-api/controls/video-view/video-view-devel.h b/dali-toolkit/devel-api/controls/video-view/video-view-devel.h
new file mode 100755 (executable)
index 0000000..b121506
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef DALI_TOOLKIT_VIDEO_VIEW_DEVEL_H\r
+#define DALI_TOOLKIT_VIDEO_VIEW_DEVEL_H\r
+\r
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>\r
+#include <dali/public-api/object/any.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Toolkit\r
+{\r
+\r
+namespace DevelVideoView\r
+{\r
+\r
+\r
+/**\r
+ * @brief Returns the internal media player.\r
+ * @param[in] videoView The current VideoView\r
+ * @return The internal media player of current VideoView\r
+ */\r
+DALI_TOOLKIT_API Any GetMediaPlayer( VideoView videoView );\r
+\r
+\r
+} // namespace DevelVideoView\r
+\r
+} // namespace Toolkit\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_VIDEO_VIEW_DEVEL_H\r
diff --git a/dali-toolkit/devel-api/controls/web-view/web-view.cpp b/dali-toolkit/devel-api/controls/web-view/web-view.cpp
new file mode 100644 (file)
index 0000000..20ae948
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/devel-api/controls/web-view/web-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/web-view/web-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+WebView::WebView()
+{
+}
+
+WebView::WebView( const WebView& WebView )
+: Control( WebView )
+{
+}
+
+WebView& WebView::operator=( const WebView& view )
+{
+  if( &view != this )
+  {
+    Control::operator=( view );
+  }
+
+  return *this;
+}
+
+WebView::~WebView()
+{
+}
+
+WebView WebView::New()
+{
+  return Internal::WebView::New();
+}
+
+WebView WebView::New( const std::string& locale, const std::string& timezoneId )
+{
+  return Internal::WebView::New( locale, timezoneId );
+}
+
+WebView WebView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast< WebView, Internal::WebView >( handle );
+}
+
+void WebView::LoadUrl( const std::string& url )
+{
+  Dali::Toolkit::GetImpl( *this ).LoadUrl( url );
+}
+
+void WebView::LoadHTMLString( const std::string& htmlString )
+{
+  Dali::Toolkit::GetImpl( *this ).LoadHTMLString( htmlString );
+}
+
+void WebView::Reload()
+{
+  Dali::Toolkit::GetImpl( *this ).Reload();
+}
+
+void WebView::StopLoading()
+{
+  Dali::Toolkit::GetImpl( *this ).StopLoading();
+}
+
+void WebView::Suspend()
+{
+  Dali::Toolkit::GetImpl( *this ).Suspend();
+}
+
+void WebView::Resume()
+{
+  Dali::Toolkit::GetImpl( *this ).Resume();
+}
+
+bool WebView::CanGoForward()
+{
+  return Dali::Toolkit::GetImpl( *this ).CanGoForward();
+}
+
+void WebView::GoForward()
+{
+  Dali::Toolkit::GetImpl( *this ).GoForward();
+}
+
+bool WebView::CanGoBack()
+{
+  return Dali::Toolkit::GetImpl( *this ).CanGoBack();
+}
+
+void WebView::GoBack()
+{
+  Dali::Toolkit::GetImpl( *this ).GoBack();
+}
+
+void WebView::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+{
+  Dali::Toolkit::GetImpl( *this ).EvaluateJavaScript( script, resultHandler );
+}
+
+void WebView::EvaluateJavaScript( const std::string& script )
+{
+  Dali::Toolkit::GetImpl( *this ).EvaluateJavaScript( script, nullptr );
+}
+
+void WebView::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler )
+{
+  Dali::Toolkit::GetImpl( *this ).AddJavaScriptMessageHandler( exposedObjectName, handler );
+}
+
+void WebView::ClearHistory()
+{
+  Dali::Toolkit::GetImpl( *this ).ClearHistory();
+}
+
+void WebView::ClearCache()
+{
+  Dali::Toolkit::GetImpl( *this ).ClearCache();
+}
+
+void WebView::ClearCookies()
+{
+  Dali::Toolkit::GetImpl( *this ).ClearCookies();
+}
+
+WebView::WebViewPageLoadSignalType& WebView::PageLoadStartedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).PageLoadStartedSignal();
+}
+
+WebView::WebViewPageLoadSignalType& WebView::PageLoadFinishedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).PageLoadFinishedSignal();
+}
+
+WebView::WebViewPageLoadErrorSignalType& WebView::PageLoadErrorSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).PageLoadErrorSignal();
+}
+
+WebView::WebView( Internal::WebView& implementation )
+: Control( implementation )
+{
+}
+
+WebView::WebView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer< Internal::WebView >( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/controls/web-view/web-view.h b/dali-toolkit/devel-api/controls/web-view/web-view.h
new file mode 100644 (file)
index 0000000..ad39718
--- /dev/null
@@ -0,0 +1,493 @@
+#ifndef DALI_TOOLKIT_WEB_VIEW_H
+#define DALI_TOOLKIT_WEB_VIEW_H
+
+/*
+ * Copyright (c) 2018 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 <functional>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  class WebView;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_toolkit_controls_web_view
+ * @{
+ */
+
+/**
+ * @brief WebView is a control for displaying web content.
+ *
+ * This enables embedding web pages in the application.
+ *
+ * For working WebView, a web engine plugin for a platform should be provided.
+ *
+ */
+class DALI_TOOLKIT_API WebView : public Control
+{
+public:
+
+  /**
+   * @brief A structure used to contain the cache model enumeration.
+   */
+  struct CacheModel
+  {
+    /**
+     * @brief Enumeration for cache model options.
+     */
+    enum Type
+    {
+      /**
+       * @brief Use the smallest cache capacity.
+       */
+      DOCUMENT_VIEWER,
+
+      /**
+       * @brief Use the bigger cache capacity than DocumentBrowser.
+       */
+      DOCUMENT_BROWSER,
+
+      /**
+       * @brief Use the biggest cache capacity.
+       */
+      PRIMARY_WEB_BROWSER
+    };
+  };
+
+  /**
+   * @brief A structure used to contain the cookie acceptance policy enumeration.
+   */
+  struct CookieAcceptPolicy
+  {
+    /**
+     * @brief Enumeration for the cookies accept policies.
+     */
+    enum Type
+    {
+      /**
+       * @brief Accepts every cookie sent from any page.
+       */
+      ALWAYS,
+
+      /**
+       * @brief Rejects all the cookies.
+       */
+      NEVER,
+
+      /**
+       * @brief Accepts only cookies set by the main document that is loaded.
+       */
+      NO_THIRD_PARTY
+    };
+  };
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX = PROPERTY_START_INDEX + 1000,
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the WebView class.
+   */
+  struct Property
+  {
+    enum
+    {
+      /**
+       * @brief The url to load.
+       * @details name "url", type Property::STRING.
+       */
+      URL = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The cache model.
+       * @details Name "cacheModel", type WebView::CacheModel::Type (Property::INTEGER) or Property::STRING.
+       * @note Default is WebView::CacheModel::DOCUMENT_VIEWER.
+       * @see WebView::CacheModel::Type
+       */
+      CACHE_MODEL,
+
+      /**
+       * @brief The cookie acceptance policy.
+       * @details Name "cookieAcceptPolicy", type WebView::CookieAcceptPolicy::Type (Property::INTEGER) or Property::STRING.
+       * @note Default is WebView::CookieAcceptPolicy::NO_THIRD_PARTY.
+       * @see WebView::CookieAcceptPolicy::Type
+       */
+      COOKIE_ACCEPT_POLICY,
+
+      /**
+       * @brief The user agent string.
+       * @details Name "userAgent", type Property::STRING.
+       */
+      USER_AGENT,
+
+      /**
+       * @brief Whether JavaScript is enabled.
+       * @details Name "enableJavaScript", type Property::BOOLEAN.
+       * @note Default is true.
+       */
+      ENABLE_JAVASCRIPT,
+
+      /**
+       * @brief Whether images can be loaded automatically.
+       * @details Name "loadImagesAutomatically", type Property::BOOLEAN.
+       * @note Default is true.
+       */
+      LOAD_IMAGES_AUTOMATICALLY,
+
+      /**
+       * @brief The default text encoding name.
+       * @details Name "defaultTextEncodingName", type Property::STRING.
+       * @note If the value is not set, the web engine detects web page's text encoding.
+       */
+      DEFAULT_TEXT_ENCODING_NAME,
+
+      /**
+       * @brief The default font size in pixel.
+       * @details Name "defaultFontSize", type Property::INT.
+       * @note Default is 16.
+       */
+      DEFAULT_FONT_SIZE
+    };
+  };
+
+  /**
+   * @brief Enumeration for indicating error code of page loading.
+   */
+  enum class LoadErrorCode
+  {
+    /**
+     * @brief Unknown.
+     */
+    UNKNOWN = 0,
+
+    /**
+     * @brief User canceled.
+     */
+    CANCELED,
+
+    /**
+     * @brief Can't show the page for this MIME type.
+     */
+    CANT_SUPPORT_MIMETYPE,
+
+    /**
+     * @brief File IO error.
+     */
+    FAILED_FILE_IO,
+
+    /**
+     * @brief Cannot connect to the network.
+     */
+    CANT_CONNECT,
+
+    /**
+     * @brief Fail to look up host from the DNS.
+     */
+    CANT_LOOKUP_HOST,
+
+    /**
+     * @brief Fail to SSL/TLS handshake.
+     */
+    FAILED_TLS_HANDSHAKE,
+
+    /**
+     * @brief Received certificate is invalid.
+     */
+    INVALID_CERTIFICATE,
+
+    /**
+     * @brief Connection timeout.
+     */
+    REQUEST_TIMEOUT,
+
+    /**
+     * @brief Too many redirects.
+     */
+    TOO_MANY_REDIRECTS,
+
+    /**
+     * @brief Too many requests during this load.
+     */
+    TOO_MANY_REQUESTS,
+
+    /**
+     * @brief Malformed URL.
+     */
+    BAD_URL,
+
+    /**
+     * @brief Unsupported scheme.
+     */
+    UNSUPPORTED_SCHEME,
+
+    /**
+     * @brief User authentication failed on the server.
+     */
+    AUTHENTICATION,
+
+    /**
+     * @brief Web server has an internal server error.
+     */
+    INTERNAL_SERVER
+  };
+
+  /**
+   * @brief WebView signal type related with page loading.
+   */
+  typedef Signal< void ( WebView, const std::string& ) > WebViewPageLoadSignalType;
+
+  /**
+   * @brief WebView signal type related with page loading error.
+   */
+  typedef Signal< void ( WebView, const std::string&, LoadErrorCode ) > WebViewPageLoadErrorSignalType;
+
+public:
+
+  /**
+   * @brief Creates an initialized WebView.
+   * @return A handle to a newly allocated Dali WebView
+   *
+   * @note WebView will not display anything
+   */
+  static WebView New();
+
+  /**
+   * @brief Creates an initialized WebView.
+   *
+   * @param [in] locale The locale of Web
+   * @param [in] timezoneId The timezoneId of Web
+   */
+  static WebView New( const std::string& locale, const std::string& timezoneId );
+
+  /**
+   * @brief Creates an uninitialized WebView.
+   */
+  WebView();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handel types must not contain data or virtual methods.
+   */
+  ~WebView();
+
+  /*
+   * @brief Copy constructor.
+   *
+   * @param[in] WebView WebView to copy. The copied WebView will point at the same implementation
+   */
+  WebView( const WebView& WebView );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] WebView The WebView to assign from
+   * @return The updated WebView
+   */
+  WebView& operator=( const WebView& WebView );
+
+  /**
+   * @brief Downcasts a handle to WebView handle.
+   *
+   * If handle points to a WebView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to a WebView or an uninitialized handle
+   */
+  static WebView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Loads a web page based on a given URL.
+   *
+   * @param [in] url The URL of the resource to load
+   */
+  void LoadUrl( const std::string& url );
+
+  /**
+   * @brief Loads a given string as web contents.
+   *
+   * @param [in] htmlString The string to use as the contents of the web page
+   */
+  void LoadHTMLString( const std::string& htmlString );
+
+  /**
+   * @brief Reloads the Web.
+   */
+  void Reload();
+
+  /**
+   * @brief Stops loading web contents on the current page.
+   */
+  void StopLoading();
+
+  /**
+   * @brief Suspends the operation associated with the view.
+   */
+  void Suspend();
+
+  /**
+   * @brief Resumes the operation associated with the view object after calling Suspend().
+   */
+  void Resume();
+
+  /**
+   * @brief Returns whether forward is possible.
+   *
+   * @return True if forward is possible, false otherwise
+   */
+  bool CanGoForward();
+
+  /**
+   * @brief Goes forward in the navigation history.
+   */
+  void GoForward();
+
+  /**
+   * @brief Returns whether backward is possible.
+   *
+   * @return True if backward is possible, false otherwise
+   */
+  bool CanGoBack();
+
+  /**
+   * @brief Goes back in the navigation history.
+   */
+  void GoBack();
+
+  /**
+   * @brief Evaluates JavaScript code represented as a string.
+   *
+   * @param[in] script The JavaScript code
+   * @param[in] resultHandler The callback function to be called by the JavaScript runtime. This carries evaluation result.
+   */
+  void EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler );
+
+  /**
+   * @brief Evaluates JavaScript code represented as a string.
+   *
+   * @param[in] script The JavaScript code
+   */
+  void EvaluateJavaScript( const std::string& script );
+
+  /**
+   * @brief Inject a JavaScript object with a message handler into the WebView.
+   *
+   * @note The injected object will appear in the JavaScript context to be loaded next.
+   *
+   * Example:
+   *
+   * 1. Native
+   *
+   *     webview.AddJavaScriptMessageHandler( "myObject", []( const std::string& message ) {
+   *         printf( "Received a message from JS: %s", message.c_str() );
+   *     });
+   *
+   *     // Start WebView by loading URL
+   *     webview.LoadUrl( url );
+   *
+   * 2. JavaScript
+   *
+   *     myObject.postMessage( "Hello World!" ); // "Received a message from JS: Hello World!"
+   *
+   *
+   * @param[in] exposedObjectName The name of exposed object
+   * @param[in] handler The callback function
+   */
+  void AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler );
+
+  /**
+   * @brief Clears the history of Web.
+   */
+  void ClearHistory();
+
+  /**
+   * @brief Clears the cache of Web.
+   */
+  void ClearCache();
+
+  /**
+   * @brief Clears all the cookies of Web.
+   */
+  void ClearCookies();
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is started.
+   *
+   * @return A signal object to connect with
+   */
+  WebViewPageLoadSignalType& PageLoadStartedSignal();
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is finished.
+   *
+   * @return A signal object to connect with
+   */
+  WebViewPageLoadSignalType& PageLoadFinishedSignal();
+
+  /**
+   * @brief Connects to this signal to be notified when an error occurs in page loading.
+   *
+   * @return A signal object to connect with.
+   */
+  WebViewPageLoadErrorSignalType& PageLoadErrorSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in] implementation The WebView implementation
+   */
+  DALI_INTERNAL WebView( Internal::WebView& implementation );
+
+  /**
+   * @brief Allows the creation of this WebView from an Internal::CustomActor pointer.
+   *
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL WebView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_WEB_VIEW_H
diff --git a/dali-toolkit/devel-api/direction-enums.h b/dali-toolkit/devel-api/direction-enums.h
new file mode 100644 (file)
index 0000000..d03979b
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMS_H
+#define DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMS_H
+
+/*
+ * Copyright (c) 2019 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 Direction
+{
+  enum Type
+  {
+    LEFT_TO_RIGHT = 0,
+    RIGHT_TO_LEFT
+  };
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMS_H
diff --git a/dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.cpp b/dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.cpp
new file mode 100755 (executable)
index 0000000..bbbcf51
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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 <dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+DragAndDropDetector::DragAndDropDetector()
+{
+}
+
+DragAndDropDetector::~DragAndDropDetector()
+{
+}
+
+DragAndDropDetector DragAndDropDetector::New()
+{
+  return Internal::DragAndDropDetector::New();
+}
+
+void DragAndDropDetector::Attach(Control control)
+{
+  GetImplementation(*this).Attach(control);
+}
+
+void DragAndDropDetector::Detach(Control control)
+{
+  GetImplementation(*this).Detach(control);
+}
+
+void DragAndDropDetector::DetachAll()
+{
+  GetImplementation(*this).DetachAll();
+}
+
+uint32_t DragAndDropDetector::GetAttachedControlCount() const
+{
+  return GetImplementation(*this).GetAttachedControlCount();
+}
+
+Control DragAndDropDetector::GetAttachedControl(uint32_t index) const
+{
+  return GetImplementation(*this).GetAttachedControl(index);
+}
+
+const std::string& DragAndDropDetector::GetContent() const
+{
+  return GetImplementation(*this).GetContent();
+}
+
+const Vector2& DragAndDropDetector::GetCurrentScreenPosition() const
+{
+  return GetImplementation(*this).GetCurrentScreenPosition();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::StartedSignal()
+{
+  return GetImplementation(*this).StartedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::EnteredSignal()
+{
+  return GetImplementation(*this).EnteredSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::ExitedSignal()
+{
+  return GetImplementation(*this).ExitedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::MovedSignal()
+{
+  return GetImplementation(*this).MovedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::DroppedSignal()
+{
+  return GetImplementation(*this).DroppedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::EndedSignal()
+{
+  return GetImplementation(*this).EndedSignal();
+}
+
+DragAndDropDetector::DragAndDropDetector( Internal::DragAndDropDetector* detector )
+: BaseHandle( detector )
+{
+}
+
+} //namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h b/dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h
new file mode 100755 (executable)
index 0000000..15b14b2
--- /dev/null
@@ -0,0 +1,272 @@
+#ifndef DALI_DRAG_AND_DROP_DETECTOR_H
+#define DALI_DRAG_AND_DROP_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class DragAndDropDetector;
+}
+
+/**
+ * @brief The DragAndDropDetector%s provides signals when draggable objects are dragged into other object.
+ *
+ * It provides signals for when the draggable object start drag, draggable object enters other object, moves around in other object,
+ * leaves other object, dropped into other object and finally when the drag ended.
+ *
+ * The basic usage is shown below:
+ *
+ * @code
+ *
+ *  void Example()
+ *  {
+ *    DragAndDropDetector detector = DragAndDropDetector::New();
+ *
+ *    // Get notifications when the draggable item start drag
+ *    detector.StartedSignal().Connect( &OnStarted );
+ *
+ *    // Get notifications when the draggable item enters other item
+ *    detector.EnteredSignal().Connect( &OnEntered );
+ *
+ *    // Get notifications when the draggable item leaves other item
+ *    detector.ExitedSignal().Connect( &OnExited );
+ *
+ *    // Get notifications when the draggable item is moved within other item
+ *    detector.MovedSignal().Connect( &OnMoved );
+ *
+ *    // Get notifications when the draggable item is dropped
+ *    detector.DroppedSignal().Connect( &OnDropped );
+ *
+ *    // Get notifications when the draggable object drag ended
+ *    detector.EndedSignal().Connect( &OnEnded );
+ *  }
+ *
+ *  void OnStarted( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Position = " << detector.GetCurrentScreenPosition() << std::endl;
+ *  }
+ *
+ *  void OnEntered( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Change mode as required
+ *  }
+ *
+ *  void OnExited( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Change mode as required
+ *  }
+ *
+ *  void OnMoved( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Position = " << detector.GetCurrentScreenPosition() << std::endl;
+ *  }
+ *
+ *  void OnDropped( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Position = " << detector.GetCurrentScreenPosition() << ", Content = " << detector.GetContent() << std::endl;
+ *  }
+ *
+ *  void OnEnded( Control control, DragAndDropDetector detector )
+ *  {
+ *    // Change mode as required
+ *  }
+ *
+ * @endcode
+ */
+class DALI_TOOLKIT_API DragAndDropDetector : public BaseHandle
+{
+public:
+
+  // Typedefs
+
+  using DragAndDropSignal = Signal< void ( Control, DragAndDropDetector ) >; ///< Drag & Drop signal
+
+  /**
+   * @brief Create an initialized DragAndDropDetector.
+   *
+   * @return A handle to a newly allocated Dali DragAndDropDetector
+   */
+  static DragAndDropDetector New();
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized with DragAndDropDetector::New().
+   */
+  DragAndDropDetector();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~DragAndDropDetector();
+
+  /**
+   * @brief Returns the dropped content.
+   *
+   * @return A reference to the string representing the dropped content.
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @brief Attaches a Control to the detector.
+   *
+   * @note You can attach several controls to a DragAndDropDetector.
+   * DragAndDropDetector will keep a handle to the control and keep it alive as long as
+   * DragAndDropDetector is deleted or Detach is called.
+   */
+  void Attach(Control control);
+
+  /**
+   * @brief Detaches the attached control from the detector.
+   *
+   * @pre The specified control has been attached to the DragAndDropDetector.
+   */
+  void Detach(Control control);
+
+  /**
+   * @brief Detaches all attached control from the detector.
+   *
+   * @pre At least one control has been attached to the DragAndDropDetector.
+   */
+  void DetachAll();
+
+  /**
+   * @brief Returns the number of controls attached to the DragAndDropDetector.
+   *
+   * @pre The DragAndDropDetector has been initialized.
+   */
+  uint32_t GetAttachedControlCount() const;
+
+  /**
+   * @brief Returns a control by index. An empty handle if the index is not valid.
+   *
+   * @pre The DragAndDropDetector has been initialized.
+   */
+  Control GetAttachedControl(uint32_t index) const;
+
+  /**
+   * @brief Returns the current position of the dragged object.
+   *
+   * This is the dropped position when an object is dropped.
+   * @return The current screen position.
+   */
+  const Vector2& GetCurrentScreenPosition() const;
+
+  // Signals
+  /**
+   * @brief This is emitted when a dragged object start drag.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& StartedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object enters other object.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& EnteredSignal();
+
+  /**
+   * @brief This is emitted when a dragged object leaves other object.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& ExitedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object is moved within other object.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& MovedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object is dropped within other object.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& DroppedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object drag ended.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( Control control, DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& EndedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by DragAndDropDetector::Get().
+   *
+   * @param[in] detector A pointer to the drag and drop detector.
+   */
+  explicit DALI_INTERNAL DragAndDropDetector( Internal::DragAndDropDetector* detector );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_DRAG_AND_DROP_DETECTOR_H
diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list
new file mode 100755 (executable)
index 0000000..219fb28
--- /dev/null
@@ -0,0 +1,255 @@
+# Set the source directory
+SET( devel_api_src_dir ${ROOT_SRC_DIR}/dali-toolkit/devel-api )
+
+# Add local source files here
+SET( devel_api_src_files
+  ${devel_api_src_dir}/asset-manager/asset-manager.cpp
+  ${devel_api_src_dir}/builder/base64-encoding.cpp
+  ${devel_api_src_dir}/builder/builder.cpp
+  ${devel_api_src_dir}/builder/json-parser.cpp
+  ${devel_api_src_dir}/builder/tree-node.cpp
+  ${devel_api_src_dir}/controls/control-devel.cpp
+  ${devel_api_src_dir}/controls/control-wrapper.cpp
+  ${devel_api_src_dir}/controls/control-wrapper-impl.cpp
+  ${devel_api_src_dir}/controls/bloom-view/bloom-view.cpp
+  ${devel_api_src_dir}/controls/bubble-effect/bubble-emitter.cpp
+  ${devel_api_src_dir}/controls/buttons/toggle-button.cpp
+  ${devel_api_src_dir}/controls/effects-view/effects-view.cpp
+  ${devel_api_src_dir}/controls/magnifier/magnifier.cpp
+  ${devel_api_src_dir}/controls/navigation-view/navigation-view.cpp
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-landscape-view.cpp
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-portrait-view.cpp
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-view.cpp
+  ${devel_api_src_dir}/controls/popup/confirmation-popup.cpp
+  ${devel_api_src_dir}/controls/popup/popup.cpp
+  ${devel_api_src_dir}/controls/scene3d-view/scene3d-view.cpp
+  ${devel_api_src_dir}/controls/shadow-view/shadow-view.cpp
+  ${devel_api_src_dir}/controls/super-blur-view/super-blur-view.cpp
+  ${devel_api_src_dir}/controls/text-controls/text-editor-devel.cpp
+  ${devel_api_src_dir}/controls/text-controls/text-field-devel.cpp
+  ${devel_api_src_dir}/controls/text-controls/text-selection-popup.cpp
+  ${devel_api_src_dir}/controls/text-controls/text-selection-toolbar.cpp
+  ${devel_api_src_dir}/controls/tool-bar/tool-bar.cpp
+  ${devel_api_src_dir}/controls/video-view/video-view-devel.cpp
+  ${devel_api_src_dir}/controls/web-view/web-view.cpp
+  ${devel_api_src_dir}/focus-manager/keyinput-focus-manager.cpp
+  ${devel_api_src_dir}/focus-manager/keyboard-focus-manager-devel.cpp
+  ${devel_api_src_dir}/image-loader/async-image-loader-devel.cpp
+  ${devel_api_src_dir}/image-loader/atlas-upload-observer.cpp
+  ${devel_api_src_dir}/image-loader/image-atlas.cpp
+  ${devel_api_src_dir}/image-loader/texture-manager.cpp
+  ${devel_api_src_dir}/layouting/flex-node.cpp
+  ${devel_api_src_dir}/styling/style-manager-devel.cpp
+  ${devel_api_src_dir}/text/bitmap-font.cpp
+  ${devel_api_src_dir}/text/text-utils-devel.cpp
+  ${devel_api_src_dir}/transition-effects/cube-transition-cross-effect.cpp
+  ${devel_api_src_dir}/transition-effects/cube-transition-effect.cpp
+  ${devel_api_src_dir}/transition-effects/cube-transition-fold-effect.cpp
+  ${devel_api_src_dir}/transition-effects/cube-transition-wave-effect.cpp
+  ${devel_api_src_dir}/visual-factory/transition-data.cpp
+  ${devel_api_src_dir}/visual-factory/visual-factory.cpp
+  ${devel_api_src_dir}/visual-factory/visual-base.cpp
+  ${devel_api_src_dir}/controls/gaussian-blur-view/gaussian-blur-view.cpp
+  ${devel_api_src_dir}/drag-drop-detector/drag-and-drop-detector.cpp
+)
+
+# Add devel header files here
+SET( devel_api_header_files
+  ${devel_api_src_dir}/direction-enums.h
+  ${devel_api_src_dir}/toolkit-property-index-ranges.h
+)
+
+SET( devel_api_controls_header_files
+  ${devel_api_src_dir}/controls/control-depth-index-ranges.h
+  ${devel_api_src_dir}/controls/control-devel.h
+  ${devel_api_src_dir}/controls/control-wrapper.h
+  ${devel_api_src_dir}/controls/control-wrapper-impl.h
+)
+
+SET( devel_api_bloom_view_header_files
+  ${devel_api_src_dir}/controls/bloom-view/bloom-view.h
+)
+
+SET( devel_api_bubble_emitter_header_files
+  ${devel_api_src_dir}/controls/bubble-effect/bubble-emitter.h
+)
+
+SET( devel_api_buttons_header_files
+  ${devel_api_src_dir}/controls/buttons/button-devel.h
+  ${devel_api_src_dir}/controls/buttons/toggle-button.h
+)
+
+SET( devel_api_builder_header_files
+  ${devel_api_src_dir}/builder/base64-encoding.h
+  ${devel_api_src_dir}/builder/builder.h
+  ${devel_api_src_dir}/builder/json-parser.h
+  ${devel_api_src_dir}/builder/tree-node.h
+)
+
+SET( devel_api_effects_view_header_files
+  ${devel_api_src_dir}/controls/effects-view/effects-view.h
+)
+
+
+SET( devel_api_layouting_header_files
+  ${devel_api_src_dir}/layouting/flex-node.h
+)
+
+SET( devel_api_magnifier_header_files
+  ${devel_api_src_dir}/controls/magnifier/magnifier.h
+)
+
+SET( devel_api_navigation_view_header_files
+  ${devel_api_src_dir}/controls/navigation-view/navigation-view.h
+)
+
+SET( devel_api_page_turn_view_header_files
+  ${devel_api_src_dir}/controls/page-turn-view/page-factory.h
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-landscape-view.h
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-portrait-view.h
+  ${devel_api_src_dir}/controls/page-turn-view/page-turn-view.h
+)
+
+SET( devel_api_popup_header_files
+  ${devel_api_src_dir}/controls/popup/confirmation-popup.h
+  ${devel_api_src_dir}/controls/popup/popup.h
+)
+
+SET( devel_api_visual_factory_header_files
+  ${devel_api_src_dir}/visual-factory/transition-data.h
+  ${devel_api_src_dir}/visual-factory/visual-factory.h
+  ${devel_api_src_dir}/visual-factory/visual-base.h
+)
+
+SET( devel_api_visuals_header_files
+  ${devel_api_src_dir}/visuals/animated-gradient-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/animated-image-visual-actions-devel.h
+  ${devel_api_src_dir}/visuals/animated-vector-image-visual-actions-devel.h
+  ${devel_api_src_dir}/visuals/animated-vector-image-visual-signals-devel.h
+  ${devel_api_src_dir}/visuals/arc-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/color-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/image-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/image-visual-actions-devel.h
+  ${devel_api_src_dir}/visuals/text-visual-properties-devel.h
+  ${devel_api_src_dir}/visuals/visual-properties-devel.h
+)
+
+SET( devel_api_scene3d_view_header_files
+  ${devel_api_src_dir}/controls/scene3d-view/scene3d-view.h
+)
+
+SET( devel_api_shadow_view_header_files
+  ${devel_api_src_dir}/controls/shadow-view/shadow-view.h
+)
+
+SET( devel_api_focus_manager_header_files
+  ${devel_api_src_dir}/focus-manager/keyinput-focus-manager.h
+  ${devel_api_src_dir}/focus-manager/keyboard-focus-manager-devel.h
+)
+
+SET( devel_api_image_loader_header_files
+  ${devel_api_src_dir}/image-loader/async-image-loader-devel.h
+  ${devel_api_src_dir}/image-loader/atlas-upload-observer.h
+  ${devel_api_src_dir}/image-loader/image-atlas.h
+  ${devel_api_src_dir}/image-loader/texture-manager.h
+)
+
+SET( devel_api_shader_effects_header_files
+  ${devel_api_src_dir}/shader-effects/alpha-discard-effect.h
+  ${devel_api_src_dir}/shader-effects/dissolve-effect.h
+  ${devel_api_src_dir}/shader-effects/distance-field-effect.h
+  ${devel_api_src_dir}/shader-effects/image-region-effect.h
+  ${devel_api_src_dir}/shader-effects/motion-blur-effect.h
+  ${devel_api_src_dir}/shader-effects/motion-stretch-effect.h
+)
+
+SET( devel_api_styling_header_files
+  ${devel_api_src_dir}/styling/style-manager-devel.h
+)
+
+SET( devel_api_super_blur_view_header_files
+  ${devel_api_src_dir}/controls/super-blur-view/super-blur-view.h
+)
+
+SET( devel_api_text_controls_header_files
+  ${devel_api_src_dir}/controls/text-controls/text-editor-devel.h
+  ${devel_api_src_dir}/controls/text-controls/text-field-devel.h
+  ${devel_api_src_dir}/controls/text-controls/text-label-devel.h
+  ${devel_api_src_dir}/controls/text-controls/text-selection-popup.h
+  ${devel_api_src_dir}/controls/text-controls/text-selection-toolbar.h
+  ${devel_api_src_dir}/controls/text-controls/text-style-properties-devel.h
+)
+
+SET( devel_api_text_header_files
+  ${devel_api_src_dir}/text/text-enumerations-devel.h
+  ${devel_api_src_dir}/text/bitmap-font.h
+  ${devel_api_src_dir}/text/text-utils-devel.h
+)
+
+SET( devel_api_tool_bar_header_files
+  ${devel_api_src_dir}/controls/tool-bar/tool-bar.h
+)
+
+SET( devel_api_tooltip_header_files
+  ${devel_api_src_dir}/controls/tooltip/tooltip-properties.h
+)
+
+SET( devel_api_transition_effects_header_files
+  ${devel_api_src_dir}/transition-effects/cube-transition-effect.h
+  ${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
+)
+
+SET( devel_api_gaussian_blur_view_header_files
+  ${devel_api_src_dir}/controls/gaussian-blur-view/gaussian-blur-view.h
+)
+
+SET( devel_api_video_view_header_files
+  ${devel_api_src_dir}/controls/video-view/video-view-devel.h
+)
+
+SET( devel_api_web_view_header_files
+  ${devel_api_src_dir}/controls/web-view/web-view.h
+)
+
+SET( devel_api_drag_and_drop_detector_header_files
+  ${devel_api_src_dir}/drag-drop-detector/drag-and-drop-detector.h
+)
+
+SET( SOURCES ${SOURCES}
+  ${devel_api_src_files}
+)
+
+SET( DEVEL_API_HEADERS ${DEVEL_API_HEADERS}
+  ${devel_api_header_files}
+  ${devel_api_controls_header_files}
+  ${devel_api_bloom_view_header_files}
+  ${devel_api_bubble_emitter_header_files}
+  ${devel_api_buttons_header_files}
+  ${devel_api_builder_header_files}
+  ${devel_api_effects_view_header_files}
+  ${devel_api_layouting_header_files}
+  ${devel_api_magnifier_header_files}
+  ${devel_api_navigation_view_header_files}
+  ${devel_api_page_turn_view_header_files}
+  ${devel_api_popup_header_files}
+  ${devel_api_visual_factory_header_files}
+  ${devel_api_visuals_header_files}
+  ${devel_api_scene3d_view_header_files}
+  ${devel_api_shadow_view_header_files}
+  ${devel_api_focus_manager_header_files}
+  ${devel_api_image_loader_header_files}
+  ${devel_api_shader_effects_header_files}
+  ${devel_api_styling_header_files}
+  ${devel_api_super_blur_view_header_files}
+  ${devel_api_text_controls_header_files}
+  ${devel_api_text_header_files}
+  ${devel_api_tool_bar_header_files}
+  ${devel_api_tooltip_header_files}
+  ${devel_api_transition_effects_header_files}
+  ${devel_api_gaussian_blur_view_header_files}
+  ${devel_api_video_view_header_files}
+  ${devel_api_web_view_header_files}
+  ${devel_api_drag_and_drop_detector_header_files}
+)
diff --git a/dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.cpp b/dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.cpp
new file mode 100644 (file)
index 0000000..17645b9
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h>
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelKeyboardFocusManager
+{
+
+void SetCustomAlgorithm(KeyboardFocusManager keyboardFocusManager, CustomAlgorithmInterface& interface)
+{
+  GetImpl(keyboardFocusManager).SetCustomAlgorithm(interface);
+}
+
+void EnableFocusIndicator(KeyboardFocusManager keyboardFocusManager, bool enable)
+{
+  GetImpl(keyboardFocusManager).EnableFocusIndicator(enable);
+}
+
+bool IsFocusIndicatorEnabled(KeyboardFocusManager keyboardFocusManager)
+{
+  return GetImpl(keyboardFocusManager).IsFocusIndicatorEnabled();
+}
+
+} // namespace DevelKeyboardFocusManager
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h b/dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h
new file mode 100644 (file)
index 0000000..dd59fcd
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_DEVEL_H
+#define DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/public-api/controls/control.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelKeyboardFocusManager
+{
+/**
+ * @brief Interface used to provide custom keyboard focus algorithm for retrieving the next focusable actor.
+ *
+ * The application / toolkit can implement the interface and override the keyboard focus behaviour.
+ * Upon providing an implementation of this interface, the PreFocusChangeSignal is no longer emitted.
+ * If focus is changing within a layout container, then the layout container is queried first to provide
+ * the next focusable actor. If this does not provide a valid actor, then the Keyboard FocusManager will
+ * check focusable properties to determine next focusable actor. If focusable properties are not set,
+ * then the Keyboard FocusManager calls the GetNextFocusableActor() method of this interface.
+ */
+class CustomAlgorithmInterface
+{
+public:
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~CustomAlgorithmInterface() {};
+
+  /**
+   * @brief Called by the KeyboardFocusManager to get the next focusable actor.
+   *
+   * @param[in] current The current focused actor
+   * @param[in] proposed The proposed focused actor
+   * @param[in] direction The direction of focus movement
+   * @return A handle to the next focusable actor
+   */
+  virtual Actor GetNextFocusableActor(Actor current, Actor proposed, Control::KeyboardFocus::Direction direction) = 0;
+};
+
+/**
+ * @brief Provide the implementation of custom Focus algorithm interface
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ * @param[in] interface The user's implementation of CustomAlgorithmInterface
+ * @see DevelKeyboardFocusManager::CustomAlgorithmInterface
+ */
+DALI_TOOLKIT_API void SetCustomAlgorithm(KeyboardFocusManager keyboardFocusManager, CustomAlgorithmInterface& interface);
+
+/**
+ * @brief Decide using focus indicator or not
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ * @param[in] enable Whether using focus indicator or not
+ */
+DALI_TOOLKIT_API void EnableFocusIndicator(KeyboardFocusManager keyboardFocusManager, bool enable);
+
+/**
+ * @brief Check focus indicator is enabled or not
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ * @return True when focus indicator is enabled
+ */
+DALI_TOOLKIT_API bool IsFocusIndicatorEnabled(KeyboardFocusManager keyboardFocusManager);
+
+} // namespace DevelKeyboardFocusManager
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_DEVEL_H
diff --git a/dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.cpp b/dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.cpp
new file mode 100644 (file)
index 0000000..a951045
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 "keyinput-focus-manager.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+KeyInputFocusManager::KeyInputFocusManager()
+{
+}
+
+KeyInputFocusManager::~KeyInputFocusManager()
+{
+}
+
+KeyInputFocusManager KeyInputFocusManager::Get()
+{
+  KeyInputFocusManager manager;
+
+  // Check whether the focus manager is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton(typeid(KeyInputFocusManager));
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to focus manager
+      manager = KeyInputFocusManager(dynamic_cast<Internal::KeyInputFocusManager*>(handle.GetObjectPtr()));
+    }
+
+    if(!manager)
+    {
+      // If not, create the focus manager and register it as a singleton
+      manager = KeyInputFocusManager(new Internal::KeyInputFocusManager());
+      singletonService.Register(typeid(manager), manager);
+    }
+  }
+
+  return manager;
+}
+
+KeyInputFocusManager::KeyInputFocusManager(Internal::KeyInputFocusManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+void KeyInputFocusManager::SetFocus(Control control)
+{
+  GetImpl(*this).SetFocus(control);
+}
+
+Control KeyInputFocusManager::GetCurrentFocusControl() const
+{
+  return GetImpl(*this).GetCurrentFocusControl();
+}
+
+void KeyInputFocusManager::RemoveFocus(Control control)
+{
+  GetImpl(*this).RemoveFocus(control);
+}
+
+KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
+{
+  return GetImpl(*this).KeyInputFocusChangedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h b/dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h
new file mode 100644 (file)
index 0000000..e54f18f
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef DALI_TOOLKIT_KEYINPUT_FOCUS_MANAGER_H
+#define DALI_TOOLKIT_KEYINPUT_FOCUS_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class KeyInputFocusManager;
+}
+
+/**
+ * KeyInputFocusManager
+ * This class provides the functionality of registering for keyboard events for controls.
+ * The keyinput focus manager maintains a stack of controls, With the last added control receiving
+ * all the keyboard events first. And if the conrol doesn't consume the event it is passed to
+ * the next control in the stack. If none of the controls in the stack consume the key event then
+ * UnhandledKeyEventSignal() is emitted.
+ *
+ * Signals
+ * | %Signal Name         | Method                            |
+ * |----------------------|-----------------------------------|
+ * | keyInputFocusChanged | @ref KeyInputFocusChangedSignal() |
+ */
+class DALI_TOOLKIT_API KeyInputFocusManager : public BaseHandle
+{
+public:
+
+  // KeyInputFocusChanged
+  typedef Signal< void (Control, Control) > KeyInputFocusChangedSignalType;
+
+public:
+
+  /**
+   * Create a KeyInputFocusManager handle; this can be initialised with KeyInputFocusManager::Get()
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  KeyInputFocusManager();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~KeyInputFocusManager();
+
+  /**
+   * Get the singleton of KeyInputFocusManager object.
+   * @return A handle to the KeyInputFocusManager control.
+   */
+  static KeyInputFocusManager Get();
+
+  /**
+   * Sets keyboard focus for a control.
+   * Note: A control can be set to be in focus and still not receive all the key events if another control has over ridden it.
+   * As the key input focus mechanism works like a stack, the top most control receives all the key events, and passes on the
+   * unhandled events to the controls below in the stack. A control in the stack will regain key input focus when there are no more
+   * controls above it in the focus stack.
+   *
+   * @pre The Control is not in the focus stack. If it is allready present in the top of the stack it results in a no-op, If it is
+   * present in the stack but not on the top of the stack, then the control is moved to the top of the focus stack.
+   * @param[in] control The Control to receive keyboard input
+   */
+  void SetFocus(Control control);
+
+  /**
+   * Query for the control that is currently set to be on top of the fcous stack and receives all
+   * keyboard input events first.
+   * @return Pointer to the control set to receive keyboard inputs.
+   */
+  Control GetCurrentFocusControl() const;
+
+  /**
+   * Removes focus for the given control, The control will no longer receive events from keyboard.
+   * @param [in] control which should be removed from focus.
+   */
+  void RemoveFocus(Control control);
+
+public: // Signals
+
+  /**
+   * This signal is emitted when the key input focus control changes.
+   * Two control parameters are sent as part of this signal, the first being the signal that now has the focus, the second
+   * being the one that has lost focus.
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback(Control focusGainedControl, Control focusLostActor);
+   * @endcode
+   * @return The signal to connect to.
+   */
+  KeyInputFocusChangedSignalType& KeyInputFocusChangedSignal();
+
+private:
+
+  explicit DALI_INTERNAL KeyInputFocusManager(Internal::KeyInputFocusManager *impl);
+
+}; // class KeyInputFocusManager
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_KEYINPUT_FOCUS_MANAGER_H
diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.cpp
new file mode 100644 (file)
index 0000000..5fc985f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 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/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace DevelAsyncImageLoader
+{
+
+uint32_t Load( AsyncImageLoader asyncImageLoader,
+               const std::string& url,
+               ImageDimensions dimensions,
+               FittingMode::Type fittingMode,
+               SamplingMode::Type samplingMode,
+               bool orientationCorrection,
+               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
+{
+  return GetImplementation( asyncImageLoader ).Load( Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad);
+}
+
+uint32_t ApplyMask( AsyncImageLoader asyncImageLoader,
+                    Devel::PixelBuffer pixelBuffer,
+                    Devel::PixelBuffer maskPixelBuffer,
+                    float contentScale,
+                    bool cropToMask,
+                    DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
+{
+  return GetImplementation( asyncImageLoader ).ApplyMask( pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad );
+}
+
+PixelBufferLoadedSignalType& PixelBufferLoadedSignal( AsyncImageLoader asyncImageLoader )
+{
+  return GetImplementation( asyncImageLoader ).PixelBufferLoadedSignal();
+}
+
+} // Devel
+} // Toolkit
+} // Dali
diff --git a/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h b/dali-toolkit/devel-api/image-loader/async-image-loader-devel.h
new file mode 100644 (file)
index 0000000..99ca154
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_IMAGE_LOADER_ASYNC_IMAGE_LOADER_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_IMAGE_LOADER_ASYNC_IMAGE_LOADER_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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/signals/dali-signal.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace DevelAsyncImageLoader
+{
+
+typedef Signal< void ( uint32_t, Devel::PixelBuffer ) > PixelBufferLoadedSignalType;
+
+/**
+ * @brief Whether to multiply alpha into color channels on load
+ */
+enum class PreMultiplyOnLoad
+{
+  OFF = 0, ///< Don't modify the image
+  ON           ///< Multiply alpha into color channels on load
+};
+
+/**
+ * @brief Starts an image loading task.
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] asyncImageLoader The ayncImageLoader
+ * @param[in] url The URL of the image file to load
+ * @param[in] dimensions The width and height to fit the loaded image to
+ * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+ * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+ * @param[in] orientationCorrection Reorient the image to respect any orientation metadata in its header
+ * @param[in] preMultiplyOnLoad ON if the image color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+ * @return The loading task id
+ */
+DALI_TOOLKIT_API uint32_t Load( AsyncImageLoader asyncImageLoader,
+                                const std::string& url,
+                                ImageDimensions dimensions,
+                                FittingMode::Type fittingMode,
+                                SamplingMode::Type samplingMode,
+                                bool orientationCorrection,
+                                DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
+
+/**
+ * @brief Starts an mask applying task.
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] asyncImageLoader The ayncImageLoader
+ * @param[in] pixelBuffer Pointer to raw pixel data to be masked
+ * @param[in] maskPixelBuffer Pointer to raw masking data
+ * @param[in] contentScale The factor to scale the content
+ * @param[in] cropToMask Whether to crop the content to the mask size
+ * @param[in] preMultiplyOnLoad ON if the image color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+ * @return The masking task id
+ */
+DALI_TOOLKIT_API uint32_t ApplyMask( AsyncImageLoader asyncImageLoader,
+                                     Devel::PixelBuffer pixelBuffer,
+                                     Devel::PixelBuffer maskPixelBuffer,
+                                     float contentScale,
+                                     bool cropToMask,
+                                     DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
+
+/**
+ * Connect to this signal if you want to load a PixelBuffer instead of a PixelData.
+ * @note Connecting to this signal prevents the emission of the ImageLoadedSignal.
+ */
+DALI_TOOLKIT_API PixelBufferLoadedSignalType&  PixelBufferLoadedSignal( AsyncImageLoader asyncImageLoader );
+
+}
+} // Toolkit
+} // Dali
+
+#endif
diff --git a/dali-toolkit/devel-api/image-loader/atlas-upload-observer.cpp b/dali-toolkit/devel-api/image-loader/atlas-upload-observer.cpp
new file mode 100644 (file)
index 0000000..f362edc
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "atlas-upload-observer.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AtlasUploadObserver::AtlasUploadObserver()
+{}
+
+AtlasUploadObserver::~AtlasUploadObserver()
+{
+  // Notify the registerd ImageAtlas object about the destruction of observer.
+  const std::size_t size( mAtlasList.Count() );
+  for( std::size_t i = 0; i < size; ++i )
+  {
+    if( mAtlasList[i] )
+    {
+      mAtlasList[i]->ObserverDestroyed( this );
+    }
+  }
+  mAtlasList.Clear();
+}
+
+void AtlasUploadObserver::Register( Internal::ImageAtlas& imageAtlas )
+{
+  // Add to the list so that the ImageAtlas could get notified in the destructor.
+  // If the same atlas is exist in the list already, we would still save the duplicated copy.
+  mAtlasList.PushBack( &imageAtlas );
+}
+
+void AtlasUploadObserver::Unregister( Internal::ImageAtlas& imageAtlas )
+{
+  const std::size_t size( mAtlasList.Count() );
+  for( std::size_t i = 0; i < size; i++ )
+  {
+    if( mAtlasList[i] == &imageAtlas )
+    {
+      // Remove from list
+      mAtlasList.Erase( mAtlasList.Begin() + i );
+      // If there are duplicated copies of same pointer, only the first one is removed
+      return;
+    }
+  }
+}
+
+}
+
+}
diff --git a/dali-toolkit/devel-api/image-loader/atlas-upload-observer.h b/dali-toolkit/devel-api/image-loader/atlas-upload-observer.h
new file mode 100644 (file)
index 0000000..53d1c0e
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_H
+#define DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_H
+
+/*
+ * Copyright (c) 2018 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/public-api/dali-toolkit-common.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/signals/callback.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class ImageAtlas;
+}
+
+/**
+ * @brief Base class used to observe the upload status of the ImageAtlas when requesting an image atlasing.
+ *
+ * Derived class should implement the UploadCompleted method which would get executed once the texture is ready.
+ */
+class DALI_TOOLKIT_API AtlasUploadObserver
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  AtlasUploadObserver();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~AtlasUploadObserver();
+
+  /**
+   * The action to be taken once the upload is completed.
+   */
+  virtual void UploadCompleted() = 0;
+
+public: // not intended for developer, called by ImageAtlas internally to get notified when this observer dies
+
+  /**
+   * @brief Register an ImageAtlas which be notified when the observer is destructing.
+   * @param[in] imageAtlas The ImageAtlas object to get notification about the destruction of the observer.
+   */
+  void Register( Internal::ImageAtlas& imageAtlas );
+
+  /**
+   * @brief Unregister an ImageAtlas which be notified when the observer is destructing.
+   * @param[in] imageAtlas The ImageAtlas object to get notification about the destruction of the observer.
+   */
+  void Unregister( Internal::ImageAtlas& imageAtlas );
+
+private:
+
+  Vector<Internal::ImageAtlas*> mAtlasList; ///< The list of the registered ImageAtlas object
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_ATLAS_UPLOAD_OBSERVER_H */
diff --git a/dali-toolkit/devel-api/image-loader/image-atlas.cpp b/dali-toolkit/devel-api/image-loader/image-atlas.cpp
new file mode 100644 (file)
index 0000000..84903b3
--- /dev/null
@@ -0,0 +1,113 @@
+ /*
+ * 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 "image-atlas.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ImageAtlas::ImageAtlas()
+{
+}
+
+ImageAtlas::~ImageAtlas()
+{
+}
+
+Texture ImageAtlas::PackToAtlas( const std::vector<PixelData>& pixelData, Dali::Vector<Vector4>& textureRects  )
+{
+  return Internal::ImageAtlas::PackToAtlas( pixelData, textureRects );
+}
+
+ImageAtlas::ImageAtlas(Internal::ImageAtlas* internal)
+: BaseHandle( internal )
+{
+}
+
+ImageAtlas::ImageAtlas( const ImageAtlas& handle )
+: BaseHandle( handle )
+{
+}
+
+ImageAtlas& ImageAtlas::operator=( const ImageAtlas& handle )
+{
+  BaseHandle::operator=(handle);
+  return *this;
+}
+
+ImageAtlas ImageAtlas::New(SizeType width, SizeType height,
+                           Pixel::Format pixelFormat)
+{
+  IntrusivePtr<Internal::ImageAtlas> internal = Internal::ImageAtlas::New( width, height, pixelFormat);
+  return ImageAtlas( internal.Get() );
+}
+
+Texture ImageAtlas::GetAtlas()
+{
+  return GetImplementation( *this ).GetAtlas();
+}
+
+float ImageAtlas::GetOccupancyRate() const
+{
+  return GetImplementation( *this ).GetOccupancyRate();
+}
+
+
+void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
+{
+  GetImplementation( *this ).SetBrokenImage( brokenImageUrl );
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect,
+                         const std::string& url,
+                         ImageDimensions size,
+                         FittingMode::Type fittingMode,
+                         bool orientationCorrection )
+{
+  return Upload( textureRect, url, size, fittingMode, orientationCorrection, NULL );
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect,
+                         const std::string& url,
+                         ImageDimensions size,
+                         FittingMode::Type fittingMode,
+                         bool orientationCorrection,
+                         AtlasUploadObserver* atlasUploadObserver )
+{
+  return GetImplementation(*this).Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver );
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect, PixelData pixelData )
+{
+  return GetImplementation(*this).Upload( textureRect, pixelData );
+}
+
+void ImageAtlas::Remove(const Vector4& textureRect)
+{
+  GetImplementation(*this).Remove( textureRect );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/image-loader/image-atlas.h b/dali-toolkit/devel-api/image-loader/image-atlas.h
new file mode 100644 (file)
index 0000000..991c624
--- /dev/null
@@ -0,0 +1,202 @@
+#ifndef DALI_TOOLKIT_IMAGE_ATLAS_H
+#define DALI_TOOLKIT_IMAGE_ATLAS_H
+/*
+ * Copyright (c) 2018 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 <stdint.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ImageAtlas;
+}
+
+/**
+ * @brief An ImageAtlas is a large texture containing multiple smaller images.
+ *
+ * Only images with url provided or pixel data are supported for uploading.
+ * The images are loaded by a worker thread to avoid blocking the main event thread.
+ */
+class DALI_TOOLKIT_API ImageAtlas : public BaseHandle
+{
+public:
+
+  typedef uint32_t SizeType;
+
+public:
+
+  /**
+   * @brief Pack a group of  pixel data into atlas.
+   * @param[in] pixelData The group of the pixel data to be packed into the atlas.
+   * @param[out] textureRects The list of texture areas where each frame is located inside the atlas.
+   * @return The atlas texture.
+   */
+  static Texture PackToAtlas( const std::vector<PixelData>& pixelData, Dali::Vector<Vector4>& textureRects  );
+
+  /**
+   * @brief Create a new ImageAtlas.
+   *
+   * @param [in] width          The atlas width in pixels.
+   * @param [in] height         The atlas height in pixels.
+   * @param [in] pixelFormat    The pixel format (rgba 32 bit by default).
+   * @return A handle to a new ImageAtlas.
+   */
+  static ImageAtlas New( SizeType width, SizeType height,
+                         Pixel::Format pixelFormat = Pixel::RGBA8888 );
+
+  /**
+   * @brief Create an empty handle.
+   *
+   * Calling member functions of an empty handle is not allowed.
+   */
+  ImageAtlas();
+
+  /**
+   * @brief Destructor.
+   */
+  ~ImageAtlas();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  ImageAtlas( const ImageAtlas& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle
+   * @return A reference to this
+   */
+  ImageAtlas& operator=( const ImageAtlas& handle );
+
+  /**
+   * @brief Get the atlas image.
+   *
+   * This atlas texture is still valid after destroying the ImageAtlas object.
+   *
+   * @return The atlas texture
+   */
+  Texture GetAtlas();
+
+  /*
+   * @brief Query what percentage of space is been occupied in the atlas.
+   *
+   * @return The occupancy rate of the atlas.
+   */
+  float GetOccupancyRate() const;
+
+  /**
+   * @brief Set the broken image which is used to replace the image if loading fails.
+   *
+   * @param[in] brokenImageUrl The url of the broken image.
+   */
+  void SetBrokenImage( const std::string& brokenImageUrl );
+
+  /**
+   * @brief Upload a resource image to the atlas.
+   *
+   * @note To make the atlasing efficient, a valid size should be provided.
+   *       If size is not provided, then the image file will be opened to read the actual size for loading.
+   *       Do not set a size that is bigger than the actual image size, as the up-scaling is not available,
+   *       the content of the area not covered by actual image is undefined, it will not be cleared.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] url The URL of the resource image file to use.
+   * @param [in] size The width and height to fit the loaded image to.
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @return True if there is enough space to fit this image in,false otherwise.
+   */
+  bool Upload( Vector4& textureRect,
+               const std::string& url,
+               ImageDimensions size = ImageDimensions(),
+               FittingMode::Type fittingMode = FittingMode::DEFAULT,
+               bool orientationCorrection = true );
+
+  /**
+   * @brief Upload a resource image to the atlas.
+   *
+   * @note To make the atlasing efficient, a valid size should be provided.
+   *       If size is not provided, then the image file will be opened to read the actual size for loading.
+   *       Do not set a size that is bigger than the actual image size, as the up-scaling is not available,
+   *       the content of the area not covered by actual image is undefined, it will not be cleared.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] url The URL of the resource image file to use.
+   * @param [in] size The width and height to fit the loaded image to.
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param[in] atlasUploadObserver The observer to observe the upload state inside the ImageAtlas.
+   * @return True if there is enough space to fit this image in,false otherwise.
+   * @note The valid callback function here is required to have the signature of void( void ).
+   */
+  bool Upload( Vector4& textureRect,
+               const std::string& url,
+               ImageDimensions size,
+               FittingMode::Type fittingMode,
+               bool orientationCorrection,
+               AtlasUploadObserver* atlasUploadObserver );
+
+  /**
+   * @brief Upload a pixel buffer to atlas
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] pixelData The pixel data.
+   */
+  bool Upload( Vector4& textureRect, PixelData pixelData );
+
+  /**
+   * @brief Remove the image at the given rectangle.
+   *
+   * The rectangular area is marked unoccupied, so new image can be added to this area.
+   *
+   * @param [in] textureRect The texture area to be removed.
+   */
+  void Remove( const Vector4& textureRect );
+
+public: // Not intended for developer use
+
+  explicit DALI_INTERNAL ImageAtlas( Internal::ImageAtlas* impl );
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_ATLAS_H
diff --git a/dali-toolkit/devel-api/image-loader/texture-manager.cpp b/dali-toolkit/devel-api/image-loader/texture-manager.cpp
new file mode 100644 (file)
index 0000000..d46d2b4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/devel-api/image-loader/texture-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace TextureManager
+{
+
+std::string AddTexture( Texture& texture )
+{
+  TextureSet set = TextureSet::New();
+  set.SetTexture( 0u, texture );
+  return AddTexture( set );
+}
+
+std::string AddTexture( TextureSet& textureSet )
+{
+  auto visualFactory = Toolkit::VisualFactory::Get();
+  auto& textureMgr = GetImplementation( visualFactory ).GetTextureManager();
+  return textureMgr.AddExternalTexture( textureSet );
+}
+
+TextureSet RemoveTexture( const std::string& textureUrl )
+{
+  auto visualFactory = Toolkit::VisualFactory::Get();
+  auto& textureMgr = GetImplementation( visualFactory ).GetTextureManager();
+  return textureMgr.RemoveExternalTexture( textureUrl );
+}
+
+} // TextureManager
+
+} // Toolkit
+
+} // Dali
diff --git a/dali-toolkit/devel-api/image-loader/texture-manager.h b/dali-toolkit/devel-api/image-loader/texture-manager.h
new file mode 100755 (executable)
index 0000000..46d3ef9
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
+#define DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/rendering/texture-set.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * API to interface with the toolkit texture manager
+ * Allows developers to add Textures through TextureSets to toolkit so that visuals can use them to render
+ */
+namespace TextureManager
+{
+
+/**
+ * @brief Add a Texture to texture manager
+ * Toolkit keeps the Texture handle until RemoveTexture is called.
+ * @note this method does not check for duplicates,
+ *       if same Texture is added multiple times, a different URL is returned each time
+ * @param[in] texture the Texture to add
+ * @return the Url string representing this texture
+ */
+DALI_TOOLKIT_API std::string AddTexture( Texture& texture );
+
+/**
+ * @brief Add a TextureSet to texture manager
+ * Toolkit keeps the TextureSet handle until RemoveTexture is called.
+ * @note this method does not check for duplicates,
+ *       if same TextureSet is added multiple times, a different URL is returned each time
+ * @param[in] textureSet the TextureSet to add
+ * @return the Url string representing this texture
+ */
+DALI_TOOLKIT_API std::string AddTexture( TextureSet& textureSet );
+
+/**
+ * @brief Removes a TextureSet from toolkit
+ * @note TextureSet may still be used by visuals and kept alive by them
+ * @param[in] textureUrl to remove
+ * @return the handle to the TextureSet or empty handle in case TextureSet is not found
+ */
+DALI_TOOLKIT_API TextureSet RemoveTexture( const std::string& textureUrl );
+
+} // TextureManager
+
+} // Toolkit
+
+} // Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_TEXTURE_MANAGER_H
diff --git a/dali-toolkit/devel-api/layouting/flex-node.cpp b/dali-toolkit/devel-api/layouting/flex-node.cpp
new file mode 100644 (file)
index 0000000..f13549c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2019 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 "flex-node.h"
+
+//EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/weak-handle.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/third-party/yoga/Yoga.h>
+
+#if defined(DEBUG_ENABLED)
+static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_FLEX" );
+#endif
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Flex
+{
+
+namespace
+{
+// Common callback function that is registered when AddChild is called.
+// Calls MeasureNode which in turns calls the actual callback passed in AddChild not the common callback.
+YGSize MeasureChild(YGNodeRef child, float width, YGMeasureMode measureModeWidth, float height, YGMeasureMode measureModeHeight)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild\n" );
+  // Get the Node from the YGNodeRef
+  Toolkit::Flex::Node* childNode =  static_cast<Toolkit::Flex::Node*>(YGNodeGetContext(child));
+
+  YGSize childSize{ 1, 1 }; // Initialise variable.
+
+  DALI_ASSERT_DEBUG( childNode );
+
+  // Call measure function assigned to this Node
+  Toolkit::Flex::SizeTuple nodeSize = childNode->MeasureNode( width, measureModeWidth, height, measureModeHeight );
+  childSize.width = nodeSize.width;
+  childSize.height = nodeSize.height;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "MeasureChild, childNode valid %f,%f\n", childSize.width, childSize.height );
+
+  return childSize;
+}
+
+} // unamed namespace
+
+struct Node;
+
+using NodePtr = std::unique_ptr<Node>;
+
+using  FlexNodeVector = std::vector< NodePtr>;
+
+struct Node::Impl
+{
+  YGNodeRef mYogaNode;
+  MeasureCallback mMeasureCallback;
+  WeakHandle< Dali::Actor > mActor;
+  FlexNodeVector mChildNodes;
+};
+
+Node::Node() : mImpl( new Impl )
+{
+  mImpl->mYogaNode = YGNodeNew();
+  YGNodeSetContext( mImpl->mYogaNode, this );
+  mImpl->mMeasureCallback = NULL;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Node()  Context [%p] set to mYogaNode[%p]\n", this, mImpl->mYogaNode );
+
+  // Set default style
+  YGNodeStyleSetFlexDirection( mImpl->mYogaNode, YGFlexDirectionColumn );
+  YGNodeStyleSetFlexWrap( mImpl->mYogaNode, YGWrapNoWrap );
+  YGNodeStyleSetJustifyContent( mImpl->mYogaNode, YGJustifyFlexStart );
+  YGNodeStyleSetAlignContent( mImpl->mYogaNode, YGAlignFlexStart );
+  YGNodeStyleSetAlignItems( mImpl->mYogaNode, YGAlignFlexStart );
+}
+
+Node::~Node()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() >> \n");
+  if( mImpl->mYogaNode )
+  {
+    YGNodeFreeRecursive( mImpl->mYogaNode );
+    mImpl->mYogaNode = nullptr;
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destructor() <<\n");
+}
+
+void Node::AddChild( Actor child, Extents margin, MeasureCallback measureFunction, int index )
+{
+  if( child )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddChild[%s] to node[%p] at index:%d\n", child.GetName().c_str(), mImpl->mYogaNode, index );
+
+    NodePtr childNode( new Node() );
+
+    // Store measure function passed in so can call it when the MeasureChild function is called.
+    childNode->mImpl->mMeasureCallback = measureFunction;
+
+    childNode->mImpl->mActor = child;
+    Vector2 minumumSize = child.GetMinimumSize();
+    Vector2 maximumSize = child.GetMaximumSize();
+
+    YGNodeStyleSetMaxWidth( childNode->mImpl->mYogaNode, maximumSize.width );
+    YGNodeStyleSetMaxHeight( childNode->mImpl->mYogaNode, maximumSize.height );
+    YGNodeStyleSetMinWidth( childNode->mImpl->mYogaNode, minumumSize.width );
+    YGNodeStyleSetMinHeight( childNode->mImpl->mYogaNode, minumumSize.height );
+
+    YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeLeft, margin.start );
+    YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeTop, margin.top );
+    YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeRight, margin.end );
+    YGNodeStyleSetMargin( childNode->mImpl->mYogaNode, YGEdgeBottom, margin.bottom );
+
+    YGNodeSetMeasureFunc( childNode->mImpl->mYogaNode, &MeasureChild );
+
+    YGNodeInsertChild( mImpl->mYogaNode, childNode->mImpl->mYogaNode, index );
+
+    mImpl->mChildNodes.emplace_back( std::move(childNode) );
+  }
+}
+
+void Node::RemoveChild( Actor child )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild child:[%s] from internal nodeCount[%d] childCount[%d]\n", child.GetName().c_str(), YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size()  );
+
+  auto iterator = std::find_if( mImpl->mChildNodes.begin(),mImpl->mChildNodes.end(),
+                                [&child]( NodePtr& childNode ){ return childNode->mImpl->mActor.GetHandle() == child;});
+
+  if( iterator != mImpl->mChildNodes.end() )
+  {
+      YGNodeRemoveChild( mImpl->mYogaNode, (*iterator)->mImpl->mYogaNode );
+      mImpl->mChildNodes.erase(iterator);
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RemoveChild internal nodeCount[%d] childCount[%d]\n", YGNodeGetChildCount( mImpl->mYogaNode ), mImpl->mChildNodes.size()  );
+}
+
+SizeTuple Node::MeasureNode( float width, int widthMode, float height, int heightMode)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode\n" );
+
+  // Execute callback registered with AddChild
+  Toolkit::Flex::SizeTuple nodeSize{8,8}; // Default size set to 8,8 to aid bug detection.
+  if( mImpl->mMeasureCallback && mImpl->mActor.GetHandle() )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode MeasureCallback executing on %s\n", mImpl->mActor.GetHandle().GetName().c_str() );
+    nodeSize = mImpl->mMeasureCallback( mImpl->mActor.GetHandle(), width, widthMode, height, heightMode );
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MeasureNode nodeSize width:%f height:%f\n", nodeSize.width, nodeSize.height );
+  return nodeSize;
+}
+
+void Node::CalculateLayout(float availableWidth, float availableHeight, bool isRTL)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "CalculateLayout availableSize(%f,%f)\n", availableWidth, availableHeight );
+  YGNodeCalculateLayout( mImpl->mYogaNode, availableWidth, availableHeight, isRTL ? YGDirectionRTL : YGDirectionLTR );
+}
+
+Dali::Vector4 Node::GetNodeFrame( int index ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame[%d]\n", index );
+  YGNodeRef childNode = YGNodeGetChild( mImpl->mYogaNode, index );
+  Dali::Vector4 frame = Vector4::ZERO;
+  if(childNode)
+  {
+    frame.x = YGNodeLayoutGetLeft( childNode );
+    frame.y = YGNodeLayoutGetTop( childNode );
+    frame.z = frame.x + YGNodeLayoutGetWidth( childNode );
+    frame.w = frame.y + YGNodeLayoutGetHeight( childNode );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Node index[%d] child ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
+                   index, childNode, frame.x , frame.y, frame.z, frame.w);
+  }
+  else
+  {
+    frame.x = YGNodeLayoutGetLeft( mImpl->mYogaNode );
+    frame.y = YGNodeLayoutGetTop( mImpl->mYogaNode );
+    frame.z = frame.x + YGNodeLayoutGetWidth( mImpl->mYogaNode );
+    frame.w = frame.y + YGNodeLayoutGetHeight( mImpl->mYogaNode );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetNodeFrame Root index[%d] root ptr[%p] GetYogaNodeFrame left:%f top:%f right:%f bottom:%f\n",
+                   index, mImpl->mYogaNode, frame.x , frame.y, frame.z, frame.w);
+  }
+
+  return frame;
+}
+void Node::SetFlexDirection( Dali::Toolkit::Flex::FlexDirection flexDirection )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex direction[%d]\n", flexDirection );
+
+  YGNodeStyleSetFlexDirection( mImpl->mYogaNode, static_cast<YGFlexDirection>(flexDirection) );
+}
+
+Dali::Toolkit::Flex::FlexDirection Node::GetFlexDirection() const
+{
+  return static_cast<Dali::Toolkit::Flex::FlexDirection>(YGNodeStyleGetFlexDirection( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexJustification( Dali::Toolkit::Flex::Justification flexJustification )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex justification[%d]\n", flexJustification )
+
+  YGNodeStyleSetJustifyContent( mImpl->mYogaNode, static_cast<YGJustify>(flexJustification) );
+}
+
+Dali::Toolkit::Flex::Justification Node::GetFlexJustification() const
+{
+  return static_cast<Dali::Toolkit::Flex::Justification>(YGNodeStyleGetJustifyContent( mImpl->mYogaNode ));
+}
+
+Dali::Toolkit::Flex::WrapType Node::GetFlexWrap() const
+{
+  return static_cast<Dali::Toolkit::Flex::WrapType>(YGNodeStyleGetFlexWrap( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex alignment[%d]\n", flexAlignment )
+
+  YGNodeStyleSetAlignContent( mImpl->mYogaNode , static_cast<YGAlign>(flexAlignment) );
+}
+
+Dali::Toolkit::Flex::Alignment Node::GetFlexAlignment() const
+{
+  return static_cast<Dali::Toolkit::Flex::Alignment>(YGNodeStyleGetAlignContent( mImpl->mYogaNode ));
+}
+
+void Node::SetFlexItemsAlignment(Dali::Toolkit::Flex::Alignment flexAlignment )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex items alignment[%d] on mYogaNode[%p]\n", flexAlignment, mImpl->mYogaNode )
+
+  YGNodeStyleSetAlignItems( mImpl->mYogaNode, static_cast<YGAlign>(flexAlignment) );
+}
+
+Dali::Toolkit::Flex::Alignment Node::GetFlexItemsAlignment() const
+{
+  return static_cast<Dali::Toolkit::Flex::Alignment>( YGNodeStyleGetAlignItems( mImpl->mYogaNode ));
+}
+
+float Node::GetFlexWidth() const
+{
+  float flexWidth = YGNodeLayoutGetWidth( mImpl->mYogaNode );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] width[%f]\n", mImpl->mYogaNode, flexWidth)
+
+  return flexWidth;
+}
+
+float Node::GetFlexHeight() const
+{
+  float flexHeight = YGNodeLayoutGetHeight( mImpl->mYogaNode );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Get flex mYogaNode[%p] height[%f]\n", mImpl->mYogaNode, flexHeight)
+
+  return flexHeight;
+}
+
+void Node::SetMargin( Extents margin )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex margin\n")
+
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeLeft, margin.start );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeTop, margin.top );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeRight, margin.end );
+  YGNodeStyleSetMargin( mImpl->mYogaNode, YGEdgeBottom, margin.bottom );
+}
+
+void Node::SetPadding( Extents padding )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set padding\n")
+
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeLeft, padding.start );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeTop, padding.top );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeRight, padding.end );
+  YGNodeStyleSetPadding( mImpl->mYogaNode, YGEdgeBottom, padding.bottom );
+}
+
+void Node::SetFlexWrap( Dali::Toolkit::Flex::WrapType wrapType )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Set flex wrap[%d] on mYogaNode[%p]\n", wrapType, mImpl->mYogaNode )
+
+  YGNodeStyleSetFlexWrap( mImpl->mYogaNode, static_cast<YGWrap>(wrapType) );
+}
+
+} // Flex
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/layouting/flex-node.h b/dali-toolkit/devel-api/layouting/flex-node.h
new file mode 100644 (file)
index 0000000..1b76f76
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
+#define DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/actors/actor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Flex
+{
+
+class Node;
+
+/**
+ * @brief Enumeration for the direction of the main axis in the flex container. This determines
+ * the direction that flex items are laid out in the flex container.
+ */
+enum class FlexDirection
+{
+  COLUMN,                  ///< The flexible items are displayed vertically as a column
+  COLUMN_REVERSE,          ///< The flexible items are displayed vertically as a column, but in reverse order
+  ROW,                     ///< The flexible items are displayed horizontally as a row
+  ROW_REVERSE              ///< The flexible items are displayed horizontally as a row, but in reverse order
+};
+
+/**
+ * @brief Enumeration for the alignment of the flex items when the items do not use all available
+ * space on the main-axis.
+ */
+enum class Justification
+{
+  FLEX_START,              ///< Items are positioned at the beginning of the container
+  CENTER,                  ///< Items are positioned at the center of the container
+  FLEX_END,                ///< Items are positioned at the end of the container
+  SPACE_BETWEEN,           ///< Items are positioned with equal space between the items
+  SPACE_AROUND             ///< Items are positioned with equal space before, between, and after the items
+};
+
+/**
+ * @brief Enumeration for the wrap type of the flex container when there is not enough room for
+ * all the items on one flex line.
+ */
+enum class WrapType
+{
+  NO_WRAP,                 ///< Flex items laid out in single line (shrunk to fit the flex container along the main axis)
+  WRAP                     ///< Flex items laid out in multiple lines if needed
+};
+
+/**
+ * @brief Enumeration for the alignment of the flex items or lines when the items or lines do not
+ * use all the available space on the cross-axis.
+ */
+enum class Alignment
+{
+    AUTO,                  ///< Currently unsupported, placeholder for inheritance of parent alignment.
+
+    FLEX_START,            ///< At the beginning of the container
+    CENTER,                ///< At the center of the container
+    FLEX_END,              ///< At the end of the container
+    STRETCH                ///< Stretch to fit the container
+};
+
+
+/**
+ * Struct used for MeasureCallback
+ */
+struct SizeTuple
+{
+  SizeTuple( float x, float y ) : width( x ), height( y ){}
+
+  float width;
+  float height;
+};
+
+/**
+ * @brief Callback signature for child Actor measure callback.
+ * @note Actor, child Actor to measure
+ * @note float, available width for child
+ * @note int, width measure specifcation mode
+ * @note float, available height for child
+ * @note int, height measure specification mode
+ */
+using MeasureCallback = SizeTuple (*)( Dali::Actor, float , int , float , int );
+
+/**
+ * This class provides the API for calling into the Flex layout implementation.
+ */
+class DALI_TOOLKIT_API Node
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  Node();
+
+  /**
+   * @brief Destructor.
+   */
+  ~Node();
+
+  Node& operator=(Node&&) = default;
+  Node(Node&&) = default;
+  Node(const Node&) = delete;
+  Node& operator=(const Node&) = delete;
+
+  /**
+   * @brief Insert child into the FlexLayout at the given index.
+   * @param[in] child Actor to insert.
+   * @param[in] margin of child Actor.
+   * @param[in] measureFunction for the child.
+   * @param[in] index to insert at.
+   */
+  void AddChild( Actor child, Extents margin, MeasureCallback measureFunction, int index );
+
+  /**
+   * @brief Remove child from the FlexLayout at the given index.
+   * @param[in] child child to be removed.
+   */
+  void RemoveChild( Actor child );
+
+  /**
+   * @brief Return the dimensions of the node.
+   * @param[in] width width specification
+   * @param[in] widthMode width specification mode
+   * @param[in] height height specification
+   * @param[in] heightMode height specification mode
+   * @return Size tuple representing the width and height of the node
+   */
+  SizeTuple MeasureNode( float width, int widthMode, float height, int heightMode );
+
+  /**
+   * @brief Perform the layout measure calculations.
+   * @param[in] availableWidth Amount of space available for layout, width.
+   * @param[in] availableHeight Amount of space available for layout, height.
+   * @param[in] isRTL Is the direction of the layout right to left.
+   */
+  void CalculateLayout( float availableWidth, float availableHeight, bool isRTL );
+
+  /**
+   * @brief Get the calculated width of the given node.
+   * @return the width of the node
+   */
+  float GetFlexWidth() const;
+
+  /**
+   * @brief Get the calculated height of the given node.
+   * @return the height of the node
+   */
+  float GetFlexHeight() const;
+
+  /**
+   * @brief Get frame coordinates of the node at the given index.
+   * @param[in] index of the child
+   * @return Frame structure left x, top y, right z, bottom w
+   */
+  Vector4 GetNodeFrame(int index ) const;
+
+  /**
+   * @brief Set the flex direction in the layout.
+   * The direction of the main-axis which determines the direction that flex items are laid out.
+   * @param[in] flexDirection The flex direction.
+   */
+  void SetFlexDirection( FlexDirection flexDirection );
+
+  /**
+   * @brief Get the flex direction in the layout.
+   * @return The flex direction.
+   */
+  FlexDirection GetFlexDirection() const;
+
+  /**
+   * @brief Set the justification in the layout.
+   * @param[in] flexJustification The flex justification.
+   */
+  void SetFlexJustification( Justification flexJustification );
+
+  /**
+   * @brief Get the flex justification in the layout.
+   * @return The flex justification.
+   */
+  Justification GetFlexJustification() const;
+
+  /**
+   * @brief Set the wrap in the layout.
+   * @param[in] flexWrap The flex wrap.
+   */
+  void SetFlexWrap(WrapType flexWrap );
+
+  /**
+   * @brief Get the flex wrap in the layout.
+   * @return The flex wrap.
+   */
+  WrapType GetFlexWrap() const;
+
+  /**
+   * @brief Set the alignment of the layout content.
+   * @param[in] flexAlignment The alignment of the content.
+   */
+  void SetFlexAlignment( Alignment flexAlignment );
+
+  /**
+   * @brief Get the alignment of the layout content.
+   * @return The flex content alignment.
+   */
+  Alignment GetFlexAlignment() const;
+
+  /**
+   * @brief Set the alignment of the layout items.
+   * @param[in] flexAlignment The alignment of the items.
+   */
+  void SetFlexItemsAlignment( Alignment flexAlignment );
+
+  /**
+   * @brief Get the alignment of the layout items.
+   * @return The flex items alignment.
+   */
+  Alignment GetFlexItemsAlignment() const;
+
+  /**
+   * @brief Set the margin.
+   * @param[in] margin The margin value.
+   */
+  void SetMargin( Extents margin );
+
+  /**
+   * @brief Set the padding.
+   * @param[in] padding The padding value.
+   */
+  void SetPadding( Extents padding );
+
+private:
+  struct Impl;
+  std::unique_ptr< Impl > mImpl;
+
+}; // Node
+
+
+} // namespace Flex
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_LAYOUTING_FLEX_NODE_H
diff --git a/dali-toolkit/devel-api/shader-effects/alpha-discard-effect.h b/dali-toolkit/devel-api/shader-effects/alpha-discard-effect.h
new file mode 100644 (file)
index 0000000..ec2fe78
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_TOOLKIT_ALPHA_DISCARD_EFFECT_H
+#define DALI_TOOLKIT_ALPHA_DISCARD_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Creates a new Alpha discard effect
+ *
+ * Alpha discard effect is used to discard fragments when the alpha colour value is below a threshold.
+ * This is useful for stenciling.
+ *
+ * Usage example:
+ *
+ *   ImageView actor = ImageView::New( EXAMPLE_IMAGE_PATH );
+ *   Property::Map alphaDiscardEffect = CreateAlphaDiscardEffect();
+ *   actor.SetProperty( ImageView::Property::IMAGE, alphaDiscardEffect );
+ *
+ * @return A property map of the required shaders.
+ */
+inline Property::Map CreateAlphaDiscardEffect()
+{
+  const char* ALPHA_DISCARD_FRAGMENT_SHADER_SOURCE =
+      "varying mediump vec2 vTexCoord;                                \n"
+      "                                                               \n"
+      "uniform sampler2D sTexture;                                    \n"
+      "uniform lowp vec4 uColor;                                      \n"
+      "void main()                                                    \n"
+      "{                                                              \n"
+      "  mediump vec4 color = texture2D( sTexture, vTexCoord );       \n"
+      "  if(color.a <= 0.0001)                                        \n"
+      "  {                                                            \n"
+      "    discard;                                                   \n"
+      "  }                                                            \n"
+      "  gl_FragColor = color * uColor;                               \n"
+      "}                                                              \n";
+
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = ALPHA_DISCARD_FRAGMENT_SHADER_SOURCE;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ALPHA_DISCARD_EFFECT_H
diff --git a/dali-toolkit/devel-api/shader-effects/dissolve-effect.h b/dali-toolkit/devel-api/shader-effects/dissolve-effect.h
new file mode 100644 (file)
index 0000000..a4ae564
--- /dev/null
@@ -0,0 +1,236 @@
+#ifndef DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H
+#define DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H
+
+/*
+ * Copyright (c) 2019 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.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Set the dissolve central line.
+ *
+ * Use one point (position) and one direction ( displacement ) vector to define this line
+ * 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
+ */
+inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position, const Vector2& displacement, float initialProgress )
+{
+  // the line passes through 'position' and has the direction of 'displacement'
+  float coefA, coefB, coefC; //line equation: Ax+By+C=0;
+  coefA = displacement.y;
+  coefB = -displacement.x;
+  coefC = -displacement.y*position.x + displacement.x*position.y;
+
+  float inversedAABB = 1.f / (coefA*coefA+coefB*coefB);
+  float inversedSqrtAABB = sqrtf(inversedAABB);
+  float saddleA;
+
+  //saddle surface(Hyperbolic paraboloid)function, used to calculate the dissolve starting time
+  //z = y*y/a/a - x*x/b/b
+  //with our selection of parameters(a and b), this value for any texture coordinate is between -1.0 and 1.0
+
+  Vector3 saddleParam; // [0]: a*a, [1]: b*b, [2] b
+  Vector2 translation;
+  Vector2 rotation;
+  float toNext = -1.f;
+  if( displacement.x > 0.f || (EqualsZero(displacement.x) && displacement.y > 0.f) )
+  {
+    toNext = 1.f;
+  }
+
+  if( (displacement.y * displacement.x < 0.0f) )
+  {
+    //distance from (0,0) to the line
+    float distanceTopLeft =  fabsf(coefC) * inversedSqrtAABB;
+    //distance from (1, 1 ) to the line
+    float distanceBottomRight = fabsf(coefA+coefB+coefC) * inversedSqrtAABB;
+    saddleA = std::max( distanceTopLeft, distanceBottomRight );
+
+    //foot of a perpendicular: (1,0) to the line
+    float footX1 = ( coefB*coefB - coefA*coefC) * inversedAABB;
+    float footY1 = (-coefA*coefB - coefB*coefC) * inversedAABB;
+    //foot of a perpendicular: (0,1) to the line
+    float footX2 = (-coefA*coefB - coefA*coefC) * inversedAABB;
+    float footY2 = ( coefA*coefA - coefB*coefC) * inversedAABB;
+    saddleParam[1] = (footX1-footX2)*(footX1-footX2) + (footY1-footY2)*(footY1-footY2);
+    translation = Vector2(-footX2,-footY2);
+  }
+  else
+  {
+    //distance from(1,0) to the line
+    float distanceTopRight = fabsf(coefA+coefC) * inversedSqrtAABB;
+    //distance from(0,1) to the line
+    float distanceBottomLeft = fabsf(coefB+coefC) * inversedSqrtAABB;
+    saddleA = std::max( distanceTopRight, distanceBottomLeft );
+    //foot of a perpendicular: (0,0) to the line
+    float footX3 = (-coefA*coefC) * inversedAABB;
+    float footY3 = (-coefB*coefC) * inversedAABB;
+    //foot of a perpendicular: (1.0,1.0) to the line
+    float footX4 = ( coefB*coefB - coefA*coefB - coefA*coefC) * inversedAABB;
+    float footY4 = (-coefA*coefB + coefA*coefA- coefB*coefC) * inversedAABB;
+    saddleParam[1] = (footX3-footX4)*(footX3-footX4) + (footY3-footY4)*(footY3-footY4);
+    translation = Vector2(-footX3, -footY3);
+  }
+
+  saddleParam[2] = sqrtf(saddleParam[1]);
+  saddleParam[0] = saddleA*saddleA;
+  rotation = Vector2(-displacement.x, displacement.y);
+  rotation.Normalize();
+
+  actor.RegisterProperty( "uSaddleParam", saddleParam );
+  actor.RegisterProperty( "uTranslation", translation );
+  actor.RegisterProperty( "uRotation", rotation );
+  actor.RegisterProperty( "uToNext", toNext );
+  actor.RegisterProperty( "uPercentage", initialProgress, Dali::Property::ANIMATABLE );
+}
+/**
+ * @brief Create a new Dissolve effect
+ *
+ *  DissolveEffect is a custom shader effect to achieve Dissolve effects in image views.
+ *
+ *  Animatable/Constrainable uniforms:
+ *    "uPercentage" - This value is proportional to the distortion applied; a value of zero means no distortion.
+ *
+ *  @param[in] useHighPrecision True if using high precision in fragment shader for fully random noise, false otherwise
+ *  @return The newly created Property::Map with the dissolve effect
+ */
+
+inline Property::Map CreateDissolveEffect( bool useHighPrecision = true )
+{
+  const char* prefixHighPrecision( "precision highp float;\n");
+  const char* prefixMediumPrecision( "precision mediump float;\n" );
+
+  const char* vertexShader( DALI_COMPOSE_SHADER(
+    attribute mediump vec2 aPosition;\n
+    \n
+    uniform mediump mat4 uMvpMatrix;\n
+    uniform vec3 uSize;\n
+    uniform vec4 uTextureRect;
+    \n
+    uniform float uPercentage;\n
+    uniform vec3 uSaddleParam;\n
+    uniform vec2 uTranslation;\n
+    uniform vec2 uRotation; \n
+    uniform float uToNext;\n
+    \n
+    varying float vPercentage;\n
+    varying vec2 vTexCoord;\n
+
+    void main()\n
+    {\n
+      mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+      vertexPosition.xyz *= uSize;\n
+      vertexPosition = uMvpMatrix * vertexPosition;\n
+      gl_Position = vertexPosition;\n
+
+      vec2 texCoord = aPosition + vec2(0.5);
+      vTexCoord = texCoord;\n
+      //Calculate the distortion value given the dissolve central line
+      vec2 value = texCoord + uTranslation; \n
+      mat2 rotateMatrix = mat2( uRotation.s, uRotation.t, -uRotation.t, uRotation.s ); \n
+      value = rotateMatrix * value; \n
+      if(uToNext == 1.0)  \n
+        value.s = uSaddleParam[2] + value.s; \n
+      float delay = value.t*value.t / uSaddleParam[0] - value.s*value.s/uSaddleParam[1];\n
+      vPercentage = clamp( uPercentage*2.0 - 0.5*sin(delay*1.571) - 0.5, 0.0, 1.0 ); \n
+    })
+  );
+
+  const char* fragmentShader( DALI_COMPOSE_SHADER(
+    varying float vPercentage;\n
+    varying mediump vec2 vTexCoord;\n
+    \n
+    uniform sampler2D sTexture;\n
+    uniform lowp vec4 uColor;\n
+    uniform vec4 uTextureRect;
+    \n
+    float rand(vec2 co) \n
+    {\n
+      return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n
+    }\n
+    \n
+    void main()\n
+    {\n
+
+      //Calculate the randomness
+      float offsetS = rand( vTexCoord * vPercentage ) - vTexCoord.s; \n
+      float offsetT = rand( vec2(vTexCoord.t*vPercentage, vTexCoord.s * vPercentage) ) - vTexCoord.t; \n
+      vec2 lookupCoord = vTexCoord + vec2(offsetS, offsetT) * vPercentage; \n
+      gl_FragColor = texture2D( sTexture, lookupCoord ) * uColor; \n
+      gl_FragColor.a *= 1.0 - vPercentage; \n
+    } )
+  );
+
+  Property::Map map;
+
+  Property::Map customShader;
+
+  std::string vertexShaderString;
+  std::string fragmentShaderString;
+  if( useHighPrecision )
+  {
+    vertexShaderString.reserve(strlen( prefixHighPrecision ) + strlen( vertexShader ));
+    vertexShaderString.append( prefixHighPrecision );
+
+    fragmentShaderString.reserve(strlen( prefixHighPrecision ) + strlen( fragmentShader ));
+    fragmentShaderString.append( prefixHighPrecision );
+  }
+  else
+  {
+    vertexShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( vertexShader ));
+    vertexShaderString.append( prefixMediumPrecision );
+
+    fragmentShaderString.reserve(strlen( prefixMediumPrecision ) + strlen( fragmentShader ));
+    fragmentShaderString.append( prefixMediumPrecision );
+  }
+
+  vertexShaderString.append( vertexShader );
+  fragmentShaderString.append( fragmentShader );
+
+  customShader[ Visual::Shader::Property::VERTEX_SHADER ] = vertexShaderString;
+  customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentShaderString;
+
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_X ] = 20;
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_Y ] = 20;
+
+  customShader[ Visual::Shader::Property::HINTS ] = Shader::Hint::OUTPUT_IS_TRANSPARENT;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SHADER_EFFECT_DISSOLVE_H
diff --git a/dali-toolkit/devel-api/shader-effects/distance-field-effect.h b/dali-toolkit/devel-api/shader-effects/distance-field-effect.h
new file mode 100644 (file)
index 0000000..8c4b800
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef DALI_TOOLKIT_SHADER_EFFECT_DISTANCEFIELD_H
+#define DALI_TOOLKIT_SHADER_EFFECT_DISTANCEFIELD_H
+
+/*
+ * Copyright (c) 2019 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.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * Creates a new DistanceFieldEffect
+ *
+ * DistanceFieldEffect is a custom shader effect to achieve distance field on Image actors
+ *
+ * Animatable/Constrainable uniforms - These will need to be registered to the actor as a custom property to take into effect:
+ *
+ *  "uDoGlow"       - The glow state. If true, glow is enabled
+ *  "uGlowBoundary" - The glow boundary factor
+ *  "uGlowColor"    - The glow color multiplier
+
+ *  "uDoShadow"     - The shadow state. If true, shadows is enabled. Cannot be used with glow/and or outline
+ *  "uShadowColor"  - The shadow color multiplier
+ *  "uShadowOffset" - The shadow offset
+
+ *  "uDoOutline"    - The outline state. If true, outline is enabled
+ *  "uOutlineColor" - The outline color multiplier
+ *  "uOutlineParams"- Thickness of outline. The outline thickness is determined by two values.
+ *                    First value [0-1] Specifies the distance field value for the center of the outline.
+ *                    Second value [0-1] Specifies the softness/width/anti-aliasing of the outlines inner edge.
+ *
+ *  @return The newly created Property::Map with the distance field effect
+ */
+inline Dali::Property::Map CreateDistanceFieldEffect()
+{
+  const char* fragmentShaderPrefix( "#extension GL_OES_standard_derivatives : enable\n" );
+
+  const char* fragmentShader( DALI_COMPOSE_SHADER(
+      varying mediump vec2 vTexCoord;\n
+      \n
+      uniform mediump float uGlowBoundary;\n
+      uniform mediump vec2  uOutlineParams;\n
+      uniform lowp    vec4  uOutlineColor;\n
+      uniform lowp    vec4  uShadowColor;\n
+      uniform mediump vec2  uShadowOffset;\n
+      uniform lowp    vec4  uGlowColor;\n
+      uniform lowp    float uDoOutline;\n
+      uniform lowp    float uDoShadow;\n
+      uniform lowp    float uDoGlow;\n
+      \n
+      uniform sampler2D sTexture;\n
+      uniform lowp vec4 uColor;\n
+      \n
+      void main()\n
+      {\n
+        // sample distance field\n
+        mediump float smoothing = 0.5;\n
+
+        mediump float distance = texture2D(sTexture, vTexCoord).a;\n
+        mediump float smoothWidth = fwidth(distance);\n
+        mediump float alphaFactor = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, distance);\n
+        lowp    vec4  color;\n
+        if (uDoShadow == 0.0)\n
+        {\n
+          mediump float alpha = uColor.a * alphaFactor;\n
+          lowp    vec4  rgb = uColor;\n
+          \n
+          if (uDoOutline > 0.0)\n
+          {\n
+            mediump float outlineWidth = uOutlineParams[1] + smoothWidth;\n
+            mediump float outlineBlend = smoothstep(uOutlineParams[0] - outlineWidth, uOutlineParams[0] + outlineWidth, distance);\n
+            alpha = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, distance);\n
+            rgb = mix(uOutlineColor, uColor, outlineBlend);\n
+          }\n
+          \n
+          if (uDoGlow > 0.0)\n
+          {\n
+            rgb = mix(uGlowColor, rgb, alphaFactor);\n
+            alpha = smoothstep(uGlowBoundary, smoothing, distance);\n
+          }\n
+          \n
+          // set fragment color\n
+          color = vec4(rgb.rgb, alpha);\n
+        }\n
+        \n
+        else // (uDoShadow > 0.0)\n
+        {\n
+          mediump float shadowDistance = texture2D(sTexture, vTexCoord - uShadowOffset).a;\n
+          mediump float inText = alphaFactor;\n
+          mediump float inShadow = smoothstep(smoothing - smoothWidth, smoothing + smoothWidth, shadowDistance);\n
+          \n
+          // inside object, outside shadow\n
+          if (inText == 1.0)\n
+          {\n
+            color = uColor;\n
+          }\n
+          // inside object, outside shadow\n
+          else if ((inText != 0.0) && (inShadow == 0.0))\n
+          {\n
+            color = uColor;\n
+            color.a *= inText;\n
+          }\n
+          // outside object, completely inside shadow\n
+          else if ((inText == 0.0) && (inShadow == 1.0))\n
+          {\n
+            color = uShadowColor;\n
+          }\n
+          // inside object, completely inside shadow\n
+          else if ((inText != 0.0) && (inShadow == 1.0))\n
+          {\n
+            color = mix(uShadowColor, uColor, inText);\n
+            color.a = uShadowColor.a;\n
+          }\n
+          // inside object, inside shadow's border\n
+          else if ((inText != 0.0) && (inShadow != 0.0))\n
+          {\n
+            color = mix(uShadowColor, uColor, inText);\n
+            color.a *= max(inText, inShadow);\n
+          }\n
+          // inside shadow's border\n
+          else if (inShadow != 0.0)\n
+          {\n
+            color = uShadowColor;\n
+            color.a *= inShadow;\n
+          }\n
+          // outside shadow and object\n
+          else \n
+          {\n
+            color.a = 0.0;\n
+          }\n
+          \n
+        }\n
+        \n
+        gl_FragColor = color;\n
+        \n
+      } )
+  );
+
+  Property::Map map;
+
+  Property::Map customShader;
+
+  std::string fragmentShaderString;
+  fragmentShaderString.reserve( strlen( fragmentShaderPrefix ) + strlen( fragmentShader ) );
+  fragmentShaderString.append( fragmentShaderPrefix );
+  fragmentShaderString.append( fragmentShader );
+
+  customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentShaderString;
+  customShader[ Visual::Shader::Property::HINTS ] = Shader::Hint::OUTPUT_IS_TRANSPARENT;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SHADER_EFFECT_DISTANCEFIELD_H
diff --git a/dali-toolkit/devel-api/shader-effects/image-region-effect.h b/dali-toolkit/devel-api/shader-effects/image-region-effect.h
new file mode 100644 (file)
index 0000000..f031f15
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_TOOLKIT_IMAGE_REGION_EFFECT_H
+#define DALI_TOOLKIT_IMAGE_REGION_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Creates a new ImageRegionEffect
+ *
+ * ImageRegionEffect is a custom shader effect to show only a region of an Image actor.
+ *
+ * Animatable/Constrainable uniforms:
+ *  "uTopLeft"      - The top-left corner of the image region. The coordinates are in percentage,
+ *                    (0,0) being the top-left and (1,1) the bottom right of the original image
+ *  "uBottomRight"  - The bottom-right corner of the image region. The coordinates are in percentage,
+ *                    (0,0) being the top-left and (1,1) the bottom right of the original image
+ *
+ * @return A property map of the required shader
+ */
+inline Property::Map CreateImageRegionEffect()
+{
+  std::string vertexShader(
+      "attribute mediump vec2 aPosition;\n"
+      "\n"
+      "uniform mediump mat4 uMvpMatrix;\n"
+      "uniform vec3 uSize;\n"
+      "uniform vec4 uTextureRect;"
+      "\n"
+      "varying vec2 vTexCoord;\n"
+
+      "uniform mediump vec2 uTopLeft;\n"
+      "uniform mediump vec2 uBottomRight;\n"
+      "void main()\n"
+      "{\n"
+      "  mediump vec4 position = vec4(aPosition, 0.0, 1.0);\n"
+      "  position.xyz *= uSize;\n"
+      "  gl_Position = uMvpMatrix * position;\n"
+      // The line below is doing the same as the following commented lines:
+      //"  vec2 imageSize = uTextureRect.zw - uTextureRect.xy;\n"
+      //"  vec2 topLeft = uTextureRect.xy + uTopLeft * imageSize;\n"
+      //"  vec2 bottomRight = uTextureRect.xy + uBottomRight * imageSize;\n"
+      //"  vec2 texCoord = (aTexCoord - uTextureRect.xy) / imageSize;\n"
+      //"  vTexCoord = topLeft + texCoord * ( bottomRight - topLeft );\n"
+
+      "  vec2 texCoord = aPosition + vec2(0.5);\n"
+      "  vTexCoord = uTextureRect.xy + uTopLeft * ( uTextureRect.zw - uTextureRect.xy ) + ( texCoord - uTextureRect.xy ) * ( uBottomRight - uTopLeft );\n"
+      "}\n"
+  );
+
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ Visual::Shader::Property::VERTEX_SHADER ] = vertexShader;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_REGION_EFFECT_H
diff --git a/dali-toolkit/devel-api/shader-effects/motion-blur-effect.h b/dali-toolkit/devel-api/shader-effects/motion-blur-effect.h
new file mode 100644 (file)
index 0000000..1e16f21
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef DALI_TOOLKIT_SHADER_EFFECT_MOTION_BLUR_H
+#define DALI_TOOLKIT_SHADER_EFFECT_MOTION_BLUR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Set the properties for the motion blur
+ *
+ * @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 )
+{
+  actor.RegisterProperty( "uBlurTexCoordScale", 0.125f );
+  actor.RegisterProperty( "uGeometryStretchFactor", 0.05f );
+  actor.RegisterProperty( "uSpeedScalingFactor", 0.5f );
+  actor.RegisterProperty( "uObjectFadeStart", Vector2( 0.25f, 0.25f ) );
+  actor.RegisterProperty( "uObjectFadeEnd", Vector2( 0.5f, 0.5f ) );
+  actor.RegisterProperty( "uAlphaScale", 0.75f );
+  actor.RegisterProperty( "uNumSamples", static_cast<float>( numBlurSamples ) );
+  actor.RegisterProperty( "uRecipNumSamples", 1.0f / static_cast<float>( numBlurSamples ) );
+  actor.RegisterProperty( "uRecipNumSamplesMinusOne", 1.0f / static_cast<float>( numBlurSamples - 1.0f ) );
+  Property::Index uModelProperty = actor.RegisterProperty( "uModelLastFrame", Matrix::IDENTITY );
+
+  Constraint constraint = Constraint::New<Matrix>( actor, uModelProperty, EqualToConstraint() );
+  constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );
+  constraint.Apply();
+}
+
+/**
+ * @brief Create a new MotionBlurEffect
+ *
+ * Motion blur shader works on a per object basis. Objects will
+ * blur when they move, or if the camera moves.
+ *
+ * Animatable/Constrainable uniforms:
+ *  "uBlurTexCoordScale"      - This scales the offset for texture samples along the motion velocity vector.
+ *                              A smaller value means the samples will be spaced closer, larger value further
+ *                              apart. User should use this to get the blur to look contiguous, i.e. the blur
+ *                              texels should not be too widely spread, with gaps in between. Default 0.125.
+ *  "uGeometryStretchFactor"  - This scales the amount the geometry stretches backwards along the motion velocity
+ *                              vector. A smaller value means the geometry stretches less, larger it stretches more.
+ *                              User should use this to get the blur to 'bleed' into areas outside the physical
+ *                              bounds of the actor. We need this as the blur is only applied inside the bounds of
+ *                              the actor, but you would expect motion blur trails where the actor was previously
+ *                              but is there no longer. Default 0.05.
+ *  "uSpeedScalingFactor"     - This takes the magnitude of the motion velocity vector and scales it to produce a
+ *                              value which is used to fade the blur in / out with the speed that the actor is moving.
+ *                              As the blur fades in, more of the blur is visible and less of the original actor, and
+ *                              viceversa. This value is also used to control how much to fade the actor near the
+ *                              edges, based on the speed the actor is moving. When the actor is at rest this is not applied.
+ *                              Default 0.5.
+ *  "uObjectFadeStart"        - The displacement from the centre of the actor that the actor will start to fade towards its
+ *                              edges. This is used to prevent an unsightly hard edge between the blurred actor and the scene.
+ *                              Depends on the values of the vertices in the vertex stream. When the actor is at rest this is
+ *                              not applied. Default 0.25, which is half way towards the edge for an ImageVisual::QUAD.
+ *  "uObjectFadeEnd"          - The displacement from the centre of the actor that the actor will finish fading towards its
+ *                              edges. This is used to prevent an unsightly hard edge between the blurred actor and the scene.
+ *                              Depends on the values of the vertices in the vertex stream. When the actor is at rest this is
+ *                              not applied.Default 0.5, which is all the way towards the edge for an ImageVisual::QUAD.
+ *  "uAlphaScale"             - Global scaler applied to the alpha of the actor. Used to make the blurred actor a bit more subtle
+ *                              (helps to hide discontinuities due to limited number of texture samples) and reveal a bit of the
+ *                              background behind it as it moves. When the actor is at rest this is not applied. Default 0.75.
+ *  "uNumSamples"             - The number of texture samples to be taken. Increasing the number of samples provides better quality
+ *                              at the cost of performance.
+ *  "uModelLastFrame"         - The model to world space transformation matrix of the actor in the previous frame.
+ *
+ * @return The newly created Property::Map with the motion blur effect
+ */
+inline Property::Map CreateMotionBlurEffect()
+{
+  std::string vertexSource;
+  vertexSource =
+      "precision mediump float;\n"
+
+      "attribute vec2 aPosition;\n"
+
+      "uniform mat4 uMvpMatrix;\n"
+      "uniform mat4 uModelView;\n"
+      "uniform mat4 uViewMatrix;\n"
+      "uniform mat4 uProjection;\n"
+      "uniform vec3 uSize;\n"
+
+      "uniform mat4 uModelLastFrame;\n"
+      "float timeDelta = 0.0167;\n"
+
+      "uniform float uGeometryStretchFactor;\n"
+      "uniform float uSpeedScalingFactor;\n"
+
+      // outputs
+      "varying vec2 vModelSpaceCenterToPos;\n"
+      "varying vec2 vScreenSpaceVelocityVector;\n"
+      "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
+
+      "void main()\n"
+      "{\n"
+      // get view space position of vertex this frame and last frame
+      " vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
+      " vertexPosition.xyz *= uSize;\n"
+
+      " vec4 viewSpaceVertex = uModelView * vertexPosition;\n"
+      " vec4 viewSpaceVertexLastFrame = (uViewMatrix * uModelLastFrame) * vertexPosition;\n"
+      " float reciprocalTimeDelta = 1.0 / timeDelta;\n"
+
+      // work out vertex's last movement in view space
+      " vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;\n"
+
+      // get clip space position of vertex this frame and last frame
+      " vec4 clipSpaceVertex = uMvpMatrix * vertexPosition;\n"
+      " vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;\n"
+
+      // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
+      // by assuming the objects model space origin is at its center and taking the dot product of the vector from center to vertex with the motion direction
+      " float t = 0.0;\n"
+      " float posDeltaLength = length(viewSpacePosDelta);\n"
+      " if(posDeltaLength > 0.001)\n" // avoid div by 0 if object has barely moved
+      " {\n"
+      "   vec4 viewSpaceCenterToPos = uModelView * vec4(vertexPosition.xy, 0.0, 0.0);\n"
+      "   float centerToVertexDist = length(viewSpaceCenterToPos);\n"
+      "   if(centerToVertexDist > 0.001)\n" // avoid div by 0 if object has vertex at model space origin
+      "   {\n"
+      "     vec3 viewSpacePosDeltaNormalised = viewSpacePosDelta / posDeltaLength;\n"
+      "     vec3 viewSpaceCenterToPosNormalised = viewSpaceCenterToPos.xyz / centerToVertexDist;\n"
+      "     t = (dot(viewSpacePosDeltaNormalised, viewSpaceCenterToPosNormalised) * 0.5 ) + 0.5;\n" // scale and bias from [-1..1] to [0..1]
+      "   }\n"
+      " }\n"
+      // output vertex position lerped with its last position, based on how much it is trailing,
+      // this stretches the geom back along where it has just been, giving a warping effect
+      // Note: we must take account of time delta to convert position delta into a velocity, so changes are smooth (take into account frame time correctly)
+      " gl_Position = mix(clipSpaceVertexLastFrame, clipSpaceVertex, t * uGeometryStretchFactor * reciprocalTimeDelta);\n"
+
+      // work out vertex's last movement in normalised device coordinates [-1..1] space, i.e. perspective divide
+      " vec2 ndcVertex = clipSpaceVertex.xy / clipSpaceVertex.w;\n"
+      " vec2 ndcVertexLastFrame = clipSpaceVertexLastFrame.xy / clipSpaceVertexLastFrame.w;\n"
+      // scale and bias so that a value of 1.0 corresponds to screen size (NDC is [-1..1] = 2)
+      " vScreenSpaceVelocityVector = ((ndcVertex - ndcVertexLastFrame) * 0.5 * reciprocalTimeDelta);\n"
+      " vScreenSpaceVelocityVector.y = -vScreenSpaceVelocityVector.y;\n" // TODO negated due to y being inverted in our coordinate system?
+      // calculate a scaling factor proportional to velocity, which we can use to tweak how things look
+      " vSpeed = length(vScreenSpaceVelocityVector) * uSpeedScalingFactor;\n"
+      " vSpeed = clamp(vSpeed, 0.0, 1.0);\n"
+
+      // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
+      " vModelSpaceCenterToPos = viewSpaceVertex.xy;\n"
+
+      " vec2 texCoord = aPosition + vec2(0.5);"
+      " vTexCoord = texCoord;\n"
+      "}\n";
+
+
+  std::string fragmentSource;
+  fragmentSource =
+      "precision mediump float;\n"
+
+      "uniform sampler2D sTexture;\n"
+      "uniform vec4 uColor;\n"
+
+      "uniform vec2 uObjectFadeStart;\n"
+      "uniform vec2 uObjectFadeEnd;\n"
+      "uniform float uAlphaScale;\n"
+      "uniform float uBlurTexCoordScale;\n"
+      "uniform float uNumSamples;\n"
+      "uniform float uRecipNumSamples;\n"
+      "uniform float uRecipNumSamplesMinusOne;\n"
+      // inputs
+      "varying vec2 vModelSpaceCenterToPos;\n"
+      "varying vec2 vScreenSpaceVelocityVector;\n"
+      "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
+
+      "void main()\n"
+      "{\n"
+      // calculate an alpha value that will fade the object towards its extremities, we need this to avoid an unsightly hard edge between color values of
+      // the blurred object and the unblurred background. Use smoothstep also to hide any hard edges (discontinuities) in rate of change of this alpha gradient
+      " vec2 centerToPixel = abs(vModelSpaceCenterToPos);\n"
+      " vec2 fadeToEdges = smoothstep(0.0, 1.0, 1.0 - ((centerToPixel - uObjectFadeStart) / (uObjectFadeEnd - uObjectFadeStart)));\n"
+      " float fadeToEdgesScale = fadeToEdges.x * fadeToEdges.y * uAlphaScale;\n" // apply global scaler
+      " fadeToEdgesScale = mix(1.0, fadeToEdgesScale, vSpeed);\n" // fade proportional to speed, so opaque when at rest
+
+      // scale velocity vector by user requirements
+      " vec2 velocity = vScreenSpaceVelocityVector * uBlurTexCoordScale;\n"
+
+      // standard actor texel
+      " vec4 colActor = texture2D(sTexture, vTexCoord);\n"
+
+      // blurred actor - gather texture samples from the actor texture in the direction of motion
+      " vec4 col = colActor * uRecipNumSamples;\n"
+      " for(float i = 1.0; i < uNumSamples; i += 1.0)\n"
+      " {\n"
+      "   float t = i * uRecipNumSamplesMinusOne;\n"
+      "   col += texture2D(sTexture, vTexCoord + (velocity * t)) * uRecipNumSamples;\n"
+      " }\n"
+      " gl_FragColor = mix(colActor, col, vSpeed);\n" // lerp blurred and non-blurred actor based on speed of motion
+      " gl_FragColor.a = fadeToEdgesScale;//colActor.a * fadeToEdgesScale;\n" // fade blurred actor to its edges based on speed of motion
+      " gl_FragColor *= uColor;\n"
+      "}\n";
+
+
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ Visual::Shader::Property::VERTEX_SHADER ] = vertexSource;
+  customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentSource;
+
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_X ] = 10;
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_Y ] = 10;
+
+  customShader[ Visual::Shader::Property::HINTS ] = Shader::Hint::OUTPUT_IS_TRANSPARENT;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+}
+
+}
+
+#endif // DALI_TOOLKIT_SHADER_EFFECT_MOTION_BLUR_H
diff --git a/dali-toolkit/devel-api/shader-effects/motion-stretch-effect.h b/dali-toolkit/devel-api/shader-effects/motion-stretch-effect.h
new file mode 100644 (file)
index 0000000..3adfb3f
--- /dev/null
@@ -0,0 +1,212 @@
+#ifndef DALI_TOOLKIT_SHADER_EFFECT_MOTION_STRETCH_H
+#define DALI_TOOLKIT_SHADER_EFFECT_MOTION_STRETCH_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Set the properties for the motion stretch
+ */
+inline void SetMotionStretchProperties( Actor& actor )
+{
+  actor.RegisterProperty( "uGeometryStretchFactor", 0.5f );
+  actor.RegisterProperty( "uSpeedScalingFactor", 0.5f );
+  actor.RegisterProperty( "uObjectFadeStart", Vector2( 0.25f, 0.25f ) );
+  actor.RegisterProperty( "uObjectFadeEnd", Vector2( 0.5f, 0.5f ) );
+  actor.RegisterProperty( "uAlphaScale", 0.75f );
+  Property::Index uModelProperty = actor.RegisterProperty( "uModelLastFrame", Matrix::IDENTITY );
+
+  Constraint constraint = Constraint::New<Matrix>( actor, uModelProperty, EqualToConstraint() );
+  constraint.AddSource( Source( actor , Actor::Property::WORLD_MATRIX ) );
+  constraint.Apply();
+}
+
+/**
+ * @brief Creates a new MotionStretchEffect
+ *
+ * Motion stretch shader works on a per object basis. Objects will stretch in the direction of motion when they move, or if the camera moves.
+ *
+ * Animatable/Constrainable uniforms:
+ *  "uGeometryStretchFactor"  - This scales the amount the geometry stretches along the motion velocity vector.
+ *                              A smaller value means the geometry stretches less, larger it stretches more. Default 0.5.
+ *  "uSpeedScalingFactor"     - This value is used to control how much to fade the actor near the edges, based on the
+ *                              speed the actor is moving. When the actor is at rest this is not applied. Default 0.5.
+ *  "uObjectFadeStart"        - The displacement from the centre of the actor that the actor will start to fade towards
+ *                              its edges. This is used to prevent an unsightly hard edge between the stretched actor and
+ *                              the scene. Depends on the values of the vertices in the vertex stream. When the actor is at
+ *                              rest this is not applied. Default Vector2(0.25, 0.25), which is half way towards the edge for
+ *                              an ImageVisual::QUAD.
+ *  "uObjectFadeEnd"          - The displacement from the centre of the actor that the actor will finish fading towards its edges.
+ *                              This is used to prevent an unsightly hard edge between the stretched actor and the scene. Depends
+ *                              on the values of the vertices in the vertex stream. When the actor is at rest this is not applied.
+ *                              Default 0.5, which is all the way towards the edge for an ImageVisual::QUAD.
+ *  "uAlphaScale"             - Global scaler applied to the alpha of the actor. Used to make the stretched actor a bit more subtle
+ *                              and reveal a bit of the background behind it as it moves. When the actor is at rest this is not
+ *                              applied. Default 0.75.
+ *  "uModelLastFrame"         - The model to world space transformation matrix of the actor in the previous frame.
+ *
+ * @return The newly created Property::Map with the motion stretch effect
+ */
+inline Property::Map CreateMotionStretchEffect()
+{
+  std::string vertexSource;
+  vertexSource =
+      "precision mediump float;\n"
+
+      "attribute vec2 aPosition;\n"
+
+      "uniform mat4 uMvpMatrix;\n"
+      "uniform mat4 uModelView;\n"
+      "uniform mat4 uViewMatrix;\n"
+      "uniform mat4 uProjection;\n"
+      "uniform vec3 uSize;\n"
+
+      "uniform mat4  uModelLastFrame;\n"
+      "float timeDelta = 0.0167;\n"
+
+      "uniform float uGeometryStretchFactor;\n"
+      "uniform float uSpeedScalingFactor;\n"
+
+      // outputs
+      "varying vec2 vModelSpaceCenterToPos;\n"
+      "varying vec2 vScreenSpaceVelocityVector;\n"
+      "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
+
+      "void main()\n"
+      "{\n"
+      // get view space position of vertex this frame and last frame
+      " vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
+      " vertexPosition.xyz *= uSize;\n"
+
+      " vec4 viewSpaceVertex = uModelView * vertexPosition;\n"
+      " vec4 viewSpaceVertexLastFrame = uViewMatrix * uModelLastFrame * vertexPosition;\n"
+
+      // work out vertex's last movement in view space
+      " vec3 viewSpacePosDelta = viewSpaceVertex.xyz - viewSpaceVertexLastFrame.xyz;\n"
+      " float reciprocalTimeDelta = 1.0 / timeDelta;\n"
+
+      // get clip space position of vertex this frame and last frame
+      " vec4 clipSpaceVertex = uMvpMatrix * vertexPosition;\n"
+      " vec4 clipSpaceVertexLastFrame = uProjection * viewSpaceVertexLastFrame;\n"
+
+      // decide how much this vertex is 'trailing', i.e. at the back of the object relative to its direction of motion. We do this
+      // by assuming the objects model space origin is at its center and taking the dot product of the vector from center to vertex with the motion direction
+      " float t = 0.0;\n"
+      " float posDeltaLength = length(viewSpacePosDelta);\n"
+      " if(posDeltaLength > 0.001)\n" // avoid div by 0 if object has barely moved
+      " {\n"
+      "   vec4 viewSpaceCenterToPos = uModelView * vec4(aPosition, 0.0, 0.0);\n"
+      "   float centerToVertexDist = length(viewSpaceCenterToPos);\n"
+      "   if(centerToVertexDist > 0.001)\n" // avoid div by 0 if object has vertex at model space origin
+      "   {\n"
+      "     vec3 viewSpacePosDeltaNormalised = viewSpacePosDelta / posDeltaLength;\n"
+      "     vec3 viewSpaceCenterToPosNormalised = viewSpaceCenterToPos.xyz / centerToVertexDist;\n"
+      "     t = (dot(viewSpacePosDeltaNormalised, viewSpaceCenterToPosNormalised) * 0.5 ) + 0.5;\n" // scale and bias from [-1..1] to [0..1]
+      "   }\n"
+      " }\n"
+      // output vertex position lerped with its last position, based on how much it is trailing,
+      // this stretches the geom back along where it has just been, giving a warping effect
+      // We raise t to a power in order that non-trailing vertices are effected much more than trailing ones
+      // Note: we must take account of time delta to convert position delta into a velocity, so changes are smooth (take into account frame time correctly)
+      " gl_Position = mix(clipSpaceVertexLastFrame, clipSpaceVertex, t * t * t * uGeometryStretchFactor * reciprocalTimeDelta);\n"
+
+      // work out vertex's last movement in normalised device coordinates [-1..1] space, i.e. perspective divide
+      " vec2 ndcVertex = clipSpaceVertex.xy / clipSpaceVertex.w;\n"
+      " vec2 ndcVertexLastFrame = clipSpaceVertexLastFrame.xy / clipSpaceVertexLastFrame.w;\n"
+      // scale and bias so that a value of 1.0 corresponds to screen size (NDC is [-1..1] = 2)
+      " vScreenSpaceVelocityVector = ((ndcVertex - ndcVertexLastFrame) * 0.5 * reciprocalTimeDelta);\n"
+      " vScreenSpaceVelocityVector.y = -vScreenSpaceVelocityVector.y;\n" // TODO negated due to y being inverted in our coordinate system?
+      // calculate a scaling factor proportional to velocity, which we can use to tweak how things look
+      " vSpeed = length(vScreenSpaceVelocityVector) * uSpeedScalingFactor;\n"
+      " vSpeed = clamp(vSpeed, 0.0, 1.0);\n"
+
+      // provide fragment shader with vector from center of object to pixel (assumes the objects model space origin is at its center and verts have same z)
+      " vModelSpaceCenterToPos = viewSpaceVertex.xy;\n"
+
+      " vec2 texCoord = aPosition + vec2(0.5);"
+      " vTexCoord = texCoord;\n"
+      "}\n";
+
+  std::string fragmentSource;
+  fragmentSource =
+      "precision mediump float;\n"
+
+      "uniform sampler2D sTexture;\n"
+      "uniform vec4 uColor;\n"
+
+      "uniform vec2 uObjectFadeStart;\n"
+      "uniform vec2 uObjectFadeEnd;\n"
+      "uniform float uAlphaScale;\n"
+
+      // inputs
+      "varying vec2 vModelSpaceCenterToPos;\n"
+      "varying vec2 vScreenSpaceVelocityVector;\n"
+      "varying float vSpeed;\n"
+      "varying vec2 vTexCoord;\n"
+
+      "void main()\n"
+      "{\n"
+      // calculate an alpha value that will fade the object towards its extremities, we need this to avoid an unsightly hard edge between color values of
+      // the stretched object and the background. Use smoothstep also to hide any hard edges (discontinuities) in rate of change of this alpha gradient
+      " vec2 centerToPixel = abs( vModelSpaceCenterToPos );\n"
+      " vec2 fadeToEdges = smoothstep(0.0, 1.0, 1.0 - ((centerToPixel - uObjectFadeStart) / (uObjectFadeEnd - uObjectFadeStart)));\n"
+      " float fadeToEdgesScale = fadeToEdges.x * fadeToEdges.y * uAlphaScale;\n" // apply global scaler
+      " fadeToEdgesScale = mix(1.0, fadeToEdgesScale, vSpeed);\n" // fade proportional to speed, so opaque when at rest
+
+      // standard actor texel
+      " vec4 colActor = texture2D(sTexture, vTexCoord);\n"
+      " gl_FragColor = colActor;\n"
+      " gl_FragColor.a *= fadeToEdgesScale;\n" // fade actor to its edges based on speed of motion
+      " gl_FragColor *= uColor;\n"
+      "}";
+
+  Property::Map map;
+
+  Property::Map customShader;
+  customShader[ Visual::Shader::Property::VERTEX_SHADER ] = vertexSource;
+  customShader[ Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentSource;
+
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_X ] = 10;
+  customShader[ Visual::Shader::Property::SUBDIVIDE_GRID_Y ] = 10;
+
+  customShader[ Visual::Shader::Property::HINTS ] = Shader::Hint::OUTPUT_IS_TRANSPARENT;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+}
+
+}
+
+#endif // DALI_TOOLKIT_SHADER_EFFECT_MOTION_STRETCH_H
diff --git a/dali-toolkit/devel-api/styling/style-manager-devel.cpp b/dali-toolkit/devel-api/styling/style-manager-devel.cpp
new file mode 100644 (file)
index 0000000..7ac5a64
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelStyleManager
+{
+
+const Property::Map GetConfigurations( StyleManager styleManager )
+{
+  return GetImpl(styleManager).GetConfigurations();
+}
+
+} // namespace DevelStyleManager
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/styling/style-manager-devel.h b/dali-toolkit/devel-api/styling/style-manager-devel.h
new file mode 100644 (file)
index 0000000..ab00ee3
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef DALI_TOOLKIT_STYLE_MANAGER_DEVEL_H
+#define DALI_TOOLKIT_STYLE_MANAGER_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/styling/style-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelStyleManager
+{
+
+
+/**
+ * @brief Gets all currently defined configurations.
+ *
+ * @pre The Builder has been initialized.
+ * @param[in] styleManager The instance of StyleManager
+ * @return A property map to the currently defined configurations
+**/
+DALI_TOOLKIT_API const Property::Map GetConfigurations( StyleManager styleManager );
+
+} // namespace DevelStyleManager
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_STYLE_MANAGER_DEVEL_H
diff --git a/dali-toolkit/devel-api/text/bitmap-font.cpp b/dali-toolkit/devel-api/text/bitmap-font.cpp
new file mode 100755 (executable)
index 0000000..77bf3ff
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/devel-api/text/bitmap-font.h>
+
+// EXTERNAL INCLUDE
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <cstring>
+
+// INTERNAL INCLUDE
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelText
+{
+
+Glyph::Glyph()
+: url{},
+  utf8{},
+  ascender{ 0.f },
+  descender{ 0.f }
+{}
+
+Glyph::Glyph( const std::string& url, const std::string utf8Character, float ascender, float descender )
+: url{ url },
+  utf8{},
+  ascender{ ascender },
+  descender{ descender }
+{
+  DALI_ASSERT_DEBUG( utf8Character.size() <= 4u );
+
+  std::copy( utf8Character.begin(), utf8Character.end(), utf8 );
+}
+
+Glyph::~Glyph()
+{}
+
+BitmapFontDescription::BitmapFontDescription()
+: glyphs{},
+  name{},
+  underlinePosition{ 0.f },
+  underlineThickness{ 1.f },
+  isColorFont{ false }
+{}
+
+BitmapFontDescription::~BitmapFontDescription()
+{}
+
+void CreateBitmapFont( const BitmapFontDescription& description, TextAbstraction::BitmapFont& bitmapFont )
+{
+  bitmapFont.glyphs.reserve( description.glyphs.size() );
+  bitmapFont.name = description.name;
+  bitmapFont.underlinePosition = description.underlinePosition;
+  bitmapFont.underlineThickness = description.underlineThickness;
+  bitmapFont.isColorFont = description.isColorFont;
+
+  for( const auto& glyph : description.glyphs )
+  {
+    uint32_t c = 0u;
+    Text::Utf8ToUtf32( glyph.utf8, Text::GetUtf8Length( glyph.utf8[0u] ), &c );
+
+    TextAbstraction::BitmapGlyph bitmapGlyph( glyph.url, c, glyph.ascender, glyph.descender );
+
+    bitmapFont.glyphs.push_back( std::move( bitmapGlyph ) );
+  }
+}
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/text/bitmap-font.h b/dali-toolkit/devel-api/text/bitmap-font.h
new file mode 100755 (executable)
index 0000000..0d463df
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef DALI_TOOLKIT_FONT_BITMAP_DEVEL_H
+#define DALI_TOOLKIT_FONT_BITMAP_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <string>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+// Forward declarations
+struct BitmapFont;
+}
+
+namespace Toolkit
+{
+
+namespace DevelText
+{
+
+/**
+ * @brief Struct that stores the needed info to create a bitmap glyph.
+ */
+
+struct DALI_TOOLKIT_API Glyph
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults.
+   */
+  Glyph();
+
+  /**
+   * @brief Constructor.
+   *
+   * Initialize the members with the given values.
+   *
+   * @param[in] url The url of the bitmap for that glyph.
+   * @param[in] utf8 The utf8 codification of the glyph.
+   * @param[in] ascender The ascender of the glyph.
+   * @param[in] descender The descender of the glyph.
+   */
+  Glyph( const std::string& url, const std::string utf8, float ascender, float descender );
+
+  /**
+   * @brief Default destructor.
+   */
+  ~Glyph();
+
+  std::string url; ///< The url of the glyph.
+  uint8_t utf8[4]; ///< the glyph encoded in utf8
+  float ascender;  ///< The ascender. The distance from the base line to the top of the glyph.
+  float descender; ///< The descender. The distance from the base line to the bottom of the glyph.
+};
+
+/**
+ * @brief Describes a bitmap font.
+ */
+struct DALI_TOOLKIT_API BitmapFontDescription
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults.
+   */
+  BitmapFontDescription();
+
+  /**
+   * @brief Default destructor.
+   */
+  ~BitmapFontDescription();
+
+  std::vector<Glyph> glyphs; ///< Vector of glyphs.
+  std::string name;          ///< Name of the font.
+  float underlinePosition;   ///< The position of the underline from the base line.
+  float underlineThickness;  ///< The thickness of the underline.
+  bool isColorFont:1;        ///< Whether the glyphs of this font have their own colors.
+};
+
+/**
+ * @brief Creates a bitmap font with the given description.
+ *
+ * The @p bitmapFont output can be passed to the FontClient::GetFontId()
+ * method to load the font and get an Id.
+ *
+ * @param[in] description The description of the bitmap font.
+ * @param[out] bitmapFont A bitmap font.
+ *
+ * @note If the @e ascender and @e descender of the glyphs are zero, the @e descender value will be left as zero and all the bitmaps will be loaded to find out the @e ascender value.
+ */
+DALI_TOOLKIT_API void CreateBitmapFont( const BitmapFontDescription& description, TextAbstraction::BitmapFont& bitmapFont );
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UTILS_DEVEL_H
diff --git a/dali-toolkit/devel-api/text/text-enumerations-devel.h b/dali-toolkit/devel-api/text/text-enumerations-devel.h
new file mode 100644 (file)
index 0000000..4e9b278
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
+#define DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
+
+/*
+ * Copyright (c) 2017 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 DevelText
+{
+
+namespace TextDirection
+{
+
+enum Type
+{
+  LEFT_TO_RIGHT,
+  RIGHT_TO_LEFT
+};
+
+} // namespace TextDirection
+
+namespace VerticalLineAlignment
+{
+
+enum Type
+{
+  TOP,
+  MIDDLE,
+  BOTTOM
+};
+
+} // namespace VerticalLineAlignment
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_TEXT_ENUMERATIONS_DEVEL_H
diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp
new file mode 100755 (executable)
index 0000000..fc8afb9
--- /dev/null
@@ -0,0 +1,1323 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/devel-api/text/text-utils-devel.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/text-renderer.h>
+#include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-model.h>
+
+namespace Dali
+{
+
+using namespace TextAbstraction;
+
+namespace Toolkit
+{
+using namespace Text;
+
+namespace DevelText
+{
+
+namespace Layout
+{
+
+/**
+ * @brief The text's layout.
+ */
+enum Type
+{
+  SINGLELINE, ///< The text is laid out on a single line.
+  MULTILINE,  ///< The text is laid out in multiple lines.
+  CIRCULAR,   ///< The text is laid out on a single line following a circular path.
+};
+
+} // namespace Layout
+
+namespace CircularAlignment
+{
+
+/**
+ * @brief The enumerations for the circular alignment.
+ */
+enum Type
+{
+  BEGIN,  ///< The text is aligned to the @p begin angle of the arc (or to the @p begin+increment if it's a RTL text).
+  CENTER, ///< The text is centered within the arc.
+  END,    ///< The text is aligned to the @p begin+increment angle of the arc (or to the @p begin if it's a RTL text).
+};
+
+} // namespace CircularAlignment
+
+const float TO_POINT_26_DOT_6 = 64.f;
+const float TO_FLOAT = 1.f / 255.f;
+const float TO_UCHAR = 255.f;
+const bool RTL = true;
+const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians
+const float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
+const float RAD_225 = RAD_135    + Math::PI_2; ///< 225 degrees in radians;
+const float RAD_270 = 3.f * Math::PI_2;        ///< 270 degrees in radians;
+const float RAD_315 = RAD_225    + Math::PI_2; ///< 315 degrees in radians;
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, MULTILINE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, CIRCULAR )
+DALI_ENUM_TO_STRING_TABLE_END( LAYOUT_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( CIRCULAR_ALIGNMENT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, END )
+DALI_ENUM_TO_STRING_TABLE_END( CIRCULAR_ALIGNMENT_TYPE )
+
+bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout)
+{
+  return Scripting::GetEnumerationProperty(propertyValue, LAYOUT_TYPE_TABLE, LAYOUT_TYPE_TABLE_COUNT, layout);
+}
+
+bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, DevelText::CircularAlignment::Type& circularAlignment)
+{
+  return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment);
+}
+
+Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout )
+{
+  if( textParameters.text.empty() )
+  {
+    Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth,
+                                                                          textParameters.textHeight,
+                                                                          Dali::Pixel::RGBA8888 );
+
+    const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888);
+    unsigned char* buffer = pixelBuffer.GetBuffer();
+    memset(buffer, 0, bufferSize);
+
+    return pixelBuffer;
+  }
+
+  MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+  FontClient fontClient = FontClient::Get();
+  MetricsPtr metrics;
+  Text::Layout::Engine layoutEngine;             ///< The layout engine.
+  Text::ModelPtr textModel = Text::Model::New(); ///< Pointer to the text's model.
+  Vector<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
+  Vector<bool> isEmoji;                          ///< Whether the glyph is an emoji.
+
+  // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
+  metrics = Metrics::New( fontClient );
+  layoutEngine.SetMetrics( metrics );
+
+  TextAbstraction::TextRenderer::Parameters rendererParameters( textModel->mVisualModel->mGlyphs,
+                                                                textModel->mVisualModel->mGlyphPositions,
+                                                                textModel->mVisualModel->mColors,
+                                                                textModel->mVisualModel->mColorIndices,
+                                                                blendingMode,
+                                                                isEmoji );
+
+  rendererParameters.width = textParameters.textWidth;
+  rendererParameters.height = textParameters.textHeight;
+  rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888
+
+  Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
+  Vector<Character> mirroredUtf32Characters;                                                                        // The utf32Characters Characters but mirrored if there are RTL text.
+  Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
+  Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
+  Vector<FontDescriptionRun>& fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns;                 // Desired font descriptions.
+  Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
+  Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
+  //Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo;     // The bidirectional info per line.
+  Vector<CharacterDirection>& directions = textModel->mLogicalModel->mCharacterDirections;                          // Character's directions.
+  Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
+
+  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
+  Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
+  Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
+  Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                                                         // The laid out lines.
+
+  Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
+
+  // the default font's description.
+  FontDescription defaultFontDescription;
+  PointSize26Dot6 defaultPointSize = FontClient::DEFAULT_POINT_SIZE;
+
+  Length numberOfCharacters = 0u;                          // The number of characters (not glyphs!).
+  bool isTextMirrored = false;                             // Whether the text has been mirrored.
+
+  const uint8_t* utf8 = NULL;                              // pointer to the first character of the text (encoded in utf8)
+  Length textSize = 0u;                                    // The length of the utf8 string.
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Process the markup string if the mark-up processor is enabled.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  MarkupProcessData markupProcessData( colorRuns,
+                                       fontDescriptionRuns,
+                                       textModel->mLogicalModel->mEmbeddedItems );
+
+  if (textParameters.markupEnabled)
+  {
+    ProcessMarkupString(textParameters.text, markupProcessData);
+    textSize = markupProcessData.markupProcessedText.size();
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
+  }
+  else
+  {
+    textSize = textParameters.text.size();
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    utf8 = reinterpret_cast<const uint8_t*>(textParameters.text.c_str());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Convert from utf8 to utf32
+  ////////////////////////////////////////////////////////////////////////////////
+
+  utf32Characters.Resize(textSize);
+
+  // Transform a text array encoded in utf8 into an array encoded in utf32.
+  // It returns the actual number of characters.
+  numberOfCharacters = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
+  utf32Characters.Resize( numberOfCharacters );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the Line and Word Break Info.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  lineBreakInfo.Resize( numberOfCharacters, LINE_NO_BREAK );
+
+  SetLineBreakInfo( utf32Characters,
+                    0u,
+                    numberOfCharacters,
+                    lineBreakInfo );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the script runs.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  multilanguageSupport.SetScripts( utf32Characters,
+                                   0u,
+                                   numberOfCharacters,
+                                   scripts );
+
+  // Check if there are emojis.
+  // If there are an RGBA8888 pixel format is needed.
+  for( const auto& run : scripts )
+  {
+    if( run.script == TextAbstraction::Script::EMOJI )
+    {
+      rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
+      break;
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the font runs.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // Set the description font run with the given text parameters.
+  FontDescriptionRun fontDescriptionRun;
+  fontDescriptionRun.characterRun.characterIndex = 0u;
+  fontDescriptionRun.characterRun.numberOfCharacters = numberOfCharacters;
+
+  fontDescriptionRun.familyLength = 0u;
+  fontDescriptionRun.familyName = nullptr;
+  fontDescriptionRun.familyDefined = !textParameters.fontFamily.empty();
+  if( fontDescriptionRun.familyDefined )
+  {
+    // The allocated memory will be freed when the logical model is destroyed.
+    fontDescriptionRun.familyLength = textParameters.fontFamily.size();
+    fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+    memcpy( fontDescriptionRun.familyName, textParameters.fontFamily.c_str(), fontDescriptionRun.familyLength );
+  }
+
+  fontDescriptionRun.weightDefined = !textParameters.fontWeight.empty();
+  if( fontDescriptionRun.weightDefined )
+  {
+    fontDescriptionRun.weight = StringToWeight( textParameters.fontWeight.c_str() );
+  }
+
+  fontDescriptionRun.widthDefined = !textParameters.fontWidth.empty();
+  if( fontDescriptionRun.widthDefined )
+  {
+    fontDescriptionRun.width = StringToWidth( textParameters.fontWidth.c_str() );
+  }
+
+  fontDescriptionRun.slantDefined = !textParameters.fontSlant.empty();
+  if( fontDescriptionRun.slantDefined )
+  {
+    fontDescriptionRun.slant = StringToSlant( textParameters.fontSlant.c_str() );
+  }
+
+  fontDescriptionRun.sizeDefined = !EqualsZero( textParameters.fontSize );
+  if( fontDescriptionRun.sizeDefined )
+  {
+    fontDescriptionRun.size = static_cast<unsigned int>( textParameters.fontSize * TO_POINT_26_DOT_6 );
+  }
+
+  fontDescriptionRuns.PushBack( fontDescriptionRun );
+
+  // Validates the fonts. If there is a character with no assigned font it sets a default one.
+  // After this call, fonts are validated.
+  multilanguageSupport.ValidateFonts( utf32Characters,
+                                      scripts,
+                                      fontDescriptionRuns,
+                                      defaultFontDescription,
+                                      defaultPointSize,
+                                      0u,
+                                      numberOfCharacters,
+                                      validFonts );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the Bidirectional info.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  bidirectionalInfo.Reserve( 1u );
+
+  SetBidirectionalInfo( utf32Characters,
+                        scripts,
+                        lineBreakInfo,
+                        0u,
+                        numberOfCharacters,
+                        bidirectionalInfo );
+
+  const bool hasBidirectionalText = 0u != bidirectionalInfo.Count();
+  if( hasBidirectionalText )
+  {
+    // Only set the character directions if there is right to left characters.
+    GetCharactersDirection( bidirectionalInfo,
+                            numberOfCharacters,
+                            0u,
+                            numberOfCharacters,
+                            directions );
+
+    // This paragraph has right to left text. Some characters may need to be mirrored.
+    // TODO: consider if the mirrored string can be stored as well.
+
+    isTextMirrored = GetMirroredText( utf32Characters,
+                                      directions,
+                                      bidirectionalInfo,
+                                      0u,
+                                      numberOfCharacters,
+                                      mirroredUtf32Characters );
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyphs. Text shaping
+  ////////////////////////////////////////////////////////////////////////////////
+
+  const Vector<Character>& textToShape = isTextMirrored ? mirroredUtf32Characters : utf32Characters;
+
+  newParagraphGlyphs.Reserve( 1u );
+
+  // Shapes the text.
+  ShapeText( textToShape,
+             lineBreakInfo,
+             scripts,
+             validFonts,
+             0u,
+             0u,
+             numberOfCharacters,
+             rendererParameters.glyphs,
+             glyphsToCharacters,
+             charactersPerGlyph,
+             newParagraphGlyphs );
+
+  // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+  textModel->mVisualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
+  textModel->mVisualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
+
+  const Length numberOfGlyphs = rendererParameters.glyphs.Count();
+
+  // Once the text has been shaped and the glyphs created it's possible to replace the font id of those glyphs
+  // that represent an image or an item and create the embedded item layout info.
+  // Note: the position of the embedded item can't be set until the text is laid-out.
+  embeddedItemLayout.Reserve( textModel->mLogicalModel->mEmbeddedItems.Count() );
+  for( const auto& item : textModel->mLogicalModel->mEmbeddedItems )
+  {
+    // Get the glyph that matches with the character index.
+    const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
+    GlyphInfo& glyph = rendererParameters.glyphs[glyphIndex];
+
+    glyph.fontId = 0u;
+    Pixel::Format pixelFormat = Pixel::A8;
+    TextAbstraction::FontClient::EmbeddedItemDescription description = { std::string( item.url, item.urlLength ), item.width, item.height, item.colorBlendingMode };
+    glyph.index = fontClient.CreateEmbeddedItem( description, pixelFormat ); // Set here an index to an item.
+
+    if( ( Pixel::RGBA8888 == pixelFormat ) || ( Pixel::BGRA8888 == pixelFormat ) )
+    {
+      rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888;
+    }
+
+    // If the url is empty the item is going to be added after the text is rendered. It's needed to store the layout here.
+    if( description.url.empty() )
+    {
+      EmbeddedItemInfo embeddedInfo =
+      {
+        item.characterIndex,
+        glyphIndex,
+        Vector2::ZERO,
+        Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
+        Size( static_cast<float>( item.width ), static_cast<float>( item.height ) ),
+        Degree( 0.f ),
+        item.colorBlendingMode
+      };
+
+      embeddedItemLayout.PushBack( embeddedInfo );
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Retrieve the glyph's metrics.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the color runs in glyphs.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  SetColorSegmentationInfo( colorRuns,
+                            charactersToGlyph,
+                            glyphsPerCharacter,
+                            0u,
+                            0u,
+                            numberOfCharacters,
+                            textModel->mVisualModel->mColors,
+                            textModel->mVisualModel->mColorIndices );
+
+  // Insert the default color at the beginning of the vector.
+  textModel->mVisualModel->mColors.Insert( textModel->mVisualModel->mColors.Begin(),textParameters.textColor );
+
+  // Set how the embedded items are blended with text color.
+  blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE );
+
+  if( !textParameters.isTextColorSet )
+  {
+    // Traverse the color runs.
+    for( const auto& run : colorRuns )
+    {
+      const GlyphIndex firstGlyph = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
+      const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+      const GlyphIndex lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
+
+      for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
+      {
+        blendingMode[index] = ColorBlendingMode::MULTIPLY;
+      }
+    }
+  }
+
+  // Traverse the embedded items and update the blending mode vector.
+  for( const auto& item : textModel->mLogicalModel->mEmbeddedItems )
+  {
+    const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
+    blendingMode[glyphIndex] = item.colorBlendingMode;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Set the isEmoji Vector
+  ////////////////////////////////////////////////////////////////////////////////
+
+  isEmoji.Resize( numberOfGlyphs, false );
+
+  for( const auto& run : scripts )
+  {
+    if( run.script == TextAbstraction::Script::EMOJI )
+    {
+      const GlyphIndex firstGlyph = textModel->mVisualModel->mCharactersToGlyph[run.characterRun.characterIndex];
+      const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+      const GlyphIndex lastGlyphPlusOne = textModel->mVisualModel->mCharactersToGlyph[lastCharacter] + textModel->mVisualModel->mGlyphsPerCharacter[lastCharacter];
+
+      for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index )
+      {
+        isEmoji[index] = true;
+      }
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Layout the text.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // Sets the alignment
+  HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER;
+  HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
+  VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER;
+  Layout::Type layout = Layout::SINGLELINE;
+  CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN;
+
+  Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment );
+  GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment );
+  horizontalCircularAlignment = horizontalAlignment;
+
+  Property::Value verticalAlignmentStr( textParameters.verticalAlignment );
+  GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment );
+
+  Property::Value layoutStr( textParameters.layout );
+  GetLayoutEnumeration( layoutStr, layout );
+
+  Property::Value circularAlignmentStr( textParameters.circularAlignment );
+  GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment );
+
+  // Whether the layout is multi-line.
+  const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX;
+  layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line.
+
+
+  // Whether the layout is circular.
+  const bool isCircularTextLayout = (Layout::CIRCULAR == layout);
+  const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle );
+
+  // Calculates the max ascender or the max descender.
+  // Is used to calculate the radius of the base line of the text.
+  float maxAscenderDescender = 0.f;
+  if( isCircularTextLayout )
+  {
+    FontId currentFontId = 0u;
+    for( const auto& glyph : rendererParameters.glyphs )
+    {
+      if( currentFontId != glyph.fontId )
+      {
+        currentFontId = glyph.fontId;
+        FontMetrics metrics;
+        fontClient.GetFontMetrics(currentFontId, metrics);
+        maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender );
+      }
+    }
+  }
+  const unsigned int radius = textParameters.radius - static_cast<unsigned int>( maxAscenderDescender );
+
+  // Convert CircularAlignment to HorizontalAlignment.
+  if( isCircularTextLayout )
+  {
+    switch( circularAlignment )
+    {
+      case CircularAlignment::BEGIN:
+      {
+        horizontalCircularAlignment = Toolkit::HorizontalAlignment::BEGIN;
+        break;
+      }
+      case CircularAlignment::CENTER:
+      {
+        horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER;
+        break;
+      }
+      case CircularAlignment::END:
+      {
+        horizontalCircularAlignment = Toolkit::HorizontalAlignment::END;
+        break;
+      }
+    }
+  }
+
+  // Set the layout parameters.
+  Size textLayoutArea( static_cast<float>( textParameters.textWidth ),
+                     static_cast<float>( textParameters.textHeight ) );
+
+  if( isCircularTextLayout )
+  {
+    // In a circular layout, the length of the text area depends on the radius.
+    rendererParameters.radius = radius;
+    textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast<float>( rendererParameters.radius ) );
+  }
+
+  textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment;
+  textModel->mLineWrapMode = LineWrap::WORD;
+  textModel->mIgnoreSpacesAfterText = false;
+  textModel->mMatchSystemLanguageDirection = false;
+  Text::Layout::Parameters layoutParameters( textLayoutArea,
+                                             textModel );
+
+  // Resize the vector of positions to have the same size than the vector of glyphs.
+  rendererParameters.positions.Resize( numberOfGlyphs );
+
+  // Whether the last character is a new paragraph character.
+  layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] );
+
+  // The initial glyph and the number of glyphs to layout.
+  layoutParameters.startGlyphIndex = 0u;
+  layoutParameters.numberOfGlyphs = numberOfGlyphs;
+  layoutParameters.startLineIndex = 0u;
+  layoutParameters.estimatedNumberOfLines = 1u;
+  layoutParameters.interGlyphExtraAdvance = 0.f;
+
+  // Update the visual model.
+  Size newLayoutSize;
+  bool isAutoScrollEnabled = false;
+  layoutEngine.LayoutText( layoutParameters,
+                           newLayoutSize,
+                           textParameters.ellipsisEnabled,
+                           isAutoScrollEnabled );
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Align the text.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // Retrieve the line of text to know the direction and the width. @todo multi-line
+  const LineRun& line = lines[0u];
+
+  if( isCircularTextLayout )
+  {
+    // Set the circular alignment.
+    rendererParameters.circularLayout = isClockwise ? TextRenderer::Parameters::CLOCKWISE : TextRenderer::Parameters::COUNTER_CLOCKWISE;
+
+    // Update the text's height to be used by the ellipsis code.
+    textLayoutArea.height = newLayoutSize.height;
+
+    // Set the size of the text laid out on a straight horizontal line.
+    rendererParameters.circularWidth = static_cast<unsigned int>( newLayoutSize.width );
+    rendererParameters.circularHeight = static_cast<unsigned int>( newLayoutSize.height );
+
+    // Calculate the center of the circular text according the horizontal and vertical alingments and the radius.
+    switch( horizontalAlignment )
+    {
+      case HorizontalAlignment::BEGIN:
+      {
+        rendererParameters.centerX = static_cast<int>(textParameters.radius);
+        break;
+      }
+      case HorizontalAlignment::CENTER:
+      {
+        rendererParameters.centerX = static_cast<int>( textParameters.textWidth / 2u );
+        break;
+      }
+      case HorizontalAlignment::END:
+      {
+        rendererParameters.centerX = static_cast<int>( textParameters.textWidth ) - static_cast<int>(textParameters.radius);
+        break;
+      }
+    }
+
+    switch( verticalAlignment )
+    {
+      case VerticalAlignment::TOP:
+      {
+        rendererParameters.centerY = static_cast<int>(textParameters.radius);
+        break;
+      }
+      case VerticalAlignment::CENTER:
+      {
+        rendererParameters.centerY = static_cast<int>( textParameters.textHeight / 2u );
+        break;
+      }
+      case VerticalAlignment::BOTTOM:
+      {
+        rendererParameters.centerY = static_cast<int>( textParameters.textHeight ) - static_cast<int>(textParameters.radius);
+        break;
+      }
+    }
+
+    // Calculate the beginning angle according with the given horizontal alignment.
+    const bool isRTL = RTL == line.direction;
+
+    CircularAlignment::Type alignment = circularAlignment;
+    if( isRTL )
+    {
+      // Swap the alignment type if the line is right to left.
+      switch( alignment )
+      {
+        case CircularAlignment::BEGIN:
+        {
+          alignment = CircularAlignment::END;
+          break;
+        }
+        case CircularAlignment::CENTER:
+        {
+          // Nothing to do.
+          break;
+        }
+        case CircularAlignment::END:
+        {
+          alignment = CircularAlignment::BEGIN;
+          break;
+        }
+      }
+    }
+
+    float angleOffset = 0.f;
+
+    switch( alignment )
+    {
+      case CircularAlignment::BEGIN:
+      {
+        angleOffset = 0.f;
+        break;
+      }
+      case CircularAlignment::CENTER:
+      {
+        const bool isNeg = textParameters.incrementAngle < 0.f;
+        const float textWidth = static_cast<float>( rendererParameters.circularWidth );
+        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        break;
+      }
+      case CircularAlignment::END:
+      {
+        const bool isNeg = textParameters.incrementAngle < 0.f;
+        const float textWidth = static_cast<float>( rendererParameters.circularWidth );
+        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        break;
+      }
+    }
+
+    // Update the beginning angle with the calculated offset.
+    rendererParameters.beginAngle = Radian( Degree( textParameters.beginAngle ) ) + angleOffset;
+
+    // Set the vertical position of the glyphs.
+    for( auto& position : rendererParameters.positions )
+    {
+      position.y = 0.f;
+    }
+  }
+  else
+  {
+    // Calculate the vertical offset according with the given alignment.
+    float penY = 0.f;
+
+    switch( verticalAlignment )
+    {
+      case VerticalAlignment::TOP:
+      {
+        penY = line.ascender;
+        break;
+      }
+      case VerticalAlignment::CENTER:
+      {
+        penY = line.ascender + 0.5f * ( textLayoutArea.height - ( line.ascender - line.descender ) );
+        break;
+      }
+      case VerticalAlignment::BOTTOM:
+      {
+        penY = textLayoutArea.height;
+        break;
+      }
+    }
+
+    // Calculate the horizontal offset according with the given alignment.
+  float alignmentOffset = 0.f;
+    layoutEngine.Align( textLayoutArea,
+                      0u,
+                      numberOfCharacters,
+                      horizontalAlignment,
+                      lines,
+                      alignmentOffset,
+                      Dali::LayoutDirection::LEFT_TO_RIGHT,
+                      false );
+
+    // Update the position of the glyphs with the calculated offsets.
+    for( auto& position : rendererParameters.positions )
+  {
+    position.x += line.alignmentOffset;
+    position.y = penY;
+  }
+  }
+
+  // Cairo adds the bearing to the position of the glyph
+  // that has already been added by the DALi's layout engine,
+  // so it's needed to be removed here.
+  for( unsigned int index = 0u; index < rendererParameters.glyphs.Count(); ++index )
+  {
+    const GlyphInfo& glyph = rendererParameters.glyphs[index];
+    Vector2& position = rendererParameters.positions[index];
+
+    position.x -= glyph.xBearing;
+  }
+
+  // Set the position of the embedded items (if there is any).
+  EmbeddedItemInfo* embeddedItemLayoutBuffer = embeddedItemLayout.Begin();
+
+  for( Length index = 0u, endIndex = embeddedItemLayout.Count(); index < endIndex; ++index )
+  {
+    EmbeddedItemInfo& embeddedItem = *( embeddedItemLayoutBuffer + index );
+
+    embeddedItem.position = rendererParameters.positions[embeddedItem.glyphIndex];
+
+    if( isCircularTextLayout )
+    {
+      // Calculate the new position of the embedded item in the circular path.
+
+      // Center of the bitmap.
+      const float halfWidth = 0.5f * embeddedItem.size.width;
+      const float halfHeight = 0.5f * embeddedItem.size.height;
+      double centerX = static_cast<double>( embeddedItem.position.x + halfWidth );
+      double centerY = static_cast<double>(embeddedItem.position.y - halfHeight);
+
+      Dali::TextAbstraction::CircularTextParameters circularTextParameters;
+
+      circularTextParameters.radius = static_cast<double>( radius );
+      circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
+      circularTextParameters.beginAngle = static_cast<double>( -rendererParameters.beginAngle + Dali::Math::PI_2 );
+      circularTextParameters.centerX = 0.5f * static_cast<double>( textParameters.textWidth );
+      circularTextParameters.centerY = 0.5f * static_cast<double>( textParameters.textHeight );
+
+      // Calculate the rotation angle.
+      float radians = rendererParameters.beginAngle;
+      if( isClockwise )
+      {
+        radians += static_cast<float>( circularTextParameters.invRadius * centerX );
+        radians = -radians;
+      }
+      else
+      {
+        radians -= static_cast<float>( circularTextParameters.invRadius * centerX );
+        radians = -radians + Dali::Math::PI;
+      }
+      embeddedItem.angle = Degree( Radian( radians ) );
+
+      Dali::TextAbstraction::TransformToArc( circularTextParameters, centerX, centerY );
+
+      // Recalculate the size of the embedded item after the rotation to position it correctly.
+      float width = embeddedItem.size.width;
+      float height = embeddedItem.size.height;
+
+      // Transform the input angle into the range [0..2PI]
+      radians = fmod( radians, TWO_PI );
+      radians += ( radians < 0.f ) ? TWO_PI : 0.f;
+
+      // Does the same operations than rotate by shear.
+      if( ( radians > Math::PI_4 ) && ( radians <= RAD_135 ) )
+      {
+        std::swap( width, height );
+        radians -= Math::PI_2;
+      }
+      else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
+      {
+        radians -= Math::PI;
+      }
+      else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
+      {
+        std::swap( width, height );
+        radians -= RAD_270;
+      }
+
+      if( fabs( radians ) > Dali::Math::MACHINE_EPSILON_10 )
+      {
+        const float angleSinus = fabs( sin( radians ) );
+        const float angleCosinus = cos( radians );
+
+        // Calculate the rotated image dimensions.
+        embeddedItem.rotatedSize.height = width * angleSinus + height * angleCosinus;
+        embeddedItem.rotatedSize.width = height * angleSinus + width * angleCosinus + 1.f;
+      }
+
+      embeddedItem.position.x = floor( static_cast<float>( centerX ) - 0.5f * embeddedItem.rotatedSize.width );
+      embeddedItem.position.y = floor( static_cast<float>( centerY ) - 0.5f * embeddedItem.rotatedSize.height );
+    }
+    else
+    {
+      embeddedItem.position.y -= embeddedItem.size.height;
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Ellipsis the text.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  if( textParameters.ellipsisEnabled )
+  {
+    const LineRun& line = lines[0u]; // TODO: multi-line
+
+    if( line.ellipsis )
+    {
+      Length finalNumberOfGlyphs = 0u;
+
+      if( ( line.ascender - line.descender ) > textLayoutArea.height )
+      {
+        // The height of the line is bigger than the height of the text area.
+        // Show the ellipsis glyph even if it doesn't fit in the text area.
+        // If no text is rendered then issues are rised and it may be a while
+        // until is find out that the text area is too small.
+
+        // Get the first glyph which is going to be replaced and the ellipsis glyph.
+        GlyphInfo& glyphInfo = rendererParameters.glyphs[0u];
+        const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphInfo.fontId ) );
+
+        // Change the 'x' and 'y' position of the ellipsis glyph.
+        Vector2& position = rendererParameters.positions[0u];
+        position.x = ellipsisGlyph.xBearing;
+        position.y = textLayoutArea.height - ellipsisGlyph.yBearing;
+
+        // Replace the glyph by the ellipsis glyph.
+        glyphInfo = ellipsisGlyph;
+
+        // Set the final number of glyphs
+        finalNumberOfGlyphs = 1u;
+      }
+      else
+      {
+
+        // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
+        float firstPenX = 0.f; // Used if rtl text is elided.
+        bool firstPenSet = false;
+
+        // Add the ellipsis glyph.
+        bool inserted = false;
+        float removedGlypsWidth = 0.f;
+        Length numberOfRemovedGlyphs = 0u;
+        if (line.glyphRun.numberOfGlyphs > 0u)
+        {
+          GlyphIndex index = line.glyphRun.numberOfGlyphs - 1u;
+
+          GlyphInfo* glyphs = rendererParameters.glyphs.Begin();
+          Vector2* glyphPositions = rendererParameters.positions.Begin();
+
+          float penY = 0.f;
+
+          // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
+          while( !inserted )
+          {
+            const GlyphInfo& glyphToRemove = *( glyphs + index );
+
+            if( 0u != glyphToRemove.fontId )
+            {
+              // i.e. The font id of the glyph shaped from the '\n' character is zero.
+
+              // Need to reshape the glyph as the font may be different in size.
+              const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) );
+
+              if( !firstPenSet )
+              {
+                const Vector2& position = *( glyphPositions + index );
+
+                // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+                penY = position.y;
+
+                // Calculates the first penX which will be used if rtl text is elided.
+                firstPenX = position.x - glyphToRemove.xBearing;
+                if( firstPenX < -ellipsisGlyph.xBearing )
+                {
+                  // Avoids to exceed the bounding box when rtl text is elided.
+                  firstPenX = -ellipsisGlyph.xBearing;
+                }
+
+                removedGlypsWidth = -ellipsisGlyph.xBearing;
+
+                firstPenSet = true;
+              }
+
+              removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+
+              // Calculate the width of the ellipsis glyph and check if it fits.
+              const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+              if( ellipsisGlyphWidth < removedGlypsWidth )
+              {
+                GlyphInfo& glyphInfo = *( glyphs + index );
+                Vector2& position = *( glyphPositions + index );
+                position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
+
+                // Replace the glyph by the ellipsis glyph.
+                glyphInfo = ellipsisGlyph;
+
+                // Update the isEmoji vector
+                isEmoji[index] = false;
+
+                // Change the 'x' and 'y' position of the ellipsis glyph.
+
+                if( position.x > firstPenX )
+                {
+                  position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+                }
+
+                position.x += ellipsisGlyph.xBearing;
+                position.y = penY;
+
+                inserted = true;
+              }
+            }
+
+            if( !inserted )
+            {
+              if( index > 0u )
+              {
+                --index;
+              }
+              else
+              {
+                // No space for the ellipsis.
+                inserted = true;
+              }
+              ++numberOfRemovedGlyphs;
+            }
+
+            // Set the final number of glyphs
+            finalNumberOfGlyphs = line.glyphRun.numberOfGlyphs - numberOfRemovedGlyphs;
+          }
+        }
+
+        // Resize the number of glyphs/positions
+        rendererParameters.glyphs.Resize( finalNumberOfGlyphs );
+        rendererParameters.positions.Resize( finalNumberOfGlyphs );
+
+        // Remove from the embedded items those exceding the last laid out glyph.
+        embeddedItemLayout.Erase( std::remove_if( embeddedItemLayout.Begin(),
+                                                  embeddedItemLayout.End(),
+                                                  [finalNumberOfGlyphs]( const EmbeddedItemInfo& item )
+                                                  {
+                                                     return item.glyphIndex >= finalNumberOfGlyphs;
+                                                  } ),
+                                 embeddedItemLayout.End() );
+      }
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Render the text.
+  ////////////////////////////////////////////////////////////////////////////////
+
+  rendererParameters.width = textParameters.textWidth;
+  rendererParameters.height = textParameters.textHeight;
+
+  TextAbstraction::TextRenderer renderer = TextAbstraction::TextRenderer::Get();
+  return renderer.Render( rendererParameters );
+}
+
+Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters )
+{
+  // The size of the pixel data.
+  const int width = static_cast<int>(shadowParameters.input.GetWidth());
+  const int height = static_cast<int>(shadowParameters.input.GetHeight());
+
+  // The shadow's offset.
+  const int xOffset = static_cast<int>( shadowParameters.offset.x );
+  const int yOffset = static_cast<int>( shadowParameters.offset.y );
+
+  // The size in bytes of the pixel of the input's buffer.
+  const Pixel::Format inputFormat = shadowParameters.input.GetPixelFormat();
+  const unsigned int inputPixelSize = Pixel::GetBytesPerPixel( inputFormat );
+  const bool isA8 = Pixel::A8 == inputFormat;
+
+  // Creates the output pixel buffer.
+  Devel::PixelBuffer outputPixelBuffer = Devel::PixelBuffer::New(width, height, Pixel::RGBA8888);
+
+  // Clear the output buffer
+  unsigned char* outputPixelBufferPtr = outputPixelBuffer.GetBuffer();
+  memset(outputPixelBufferPtr, 0, width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888));
+
+  // Gets the buffer of the input pixel buffer.
+  const unsigned char* const inputPixelBuffer = shadowParameters.input.GetBuffer();
+
+  float textColor[4u];
+  if (isA8)
+  {
+    memcpy(textColor, shadowParameters.textColor.AsFloat(), 4u * sizeof(float));
+  }
+  const float* const shadowColor = shadowParameters.color.AsFloat();
+
+  // Traverse the input pixel buffer and write the text on the foreground and the shadow on the background.
+  for (int rowIndex = 0; rowIndex < height; ++rowIndex)
+  {
+    // Calculates the rowIndex to the input pixel buffer for the shadow and whether it's within the boundaries.
+    const int yOffsetIndex = rowIndex - yOffset;
+    const bool isValidRowIndex = ((yOffsetIndex >= 0) && (yOffsetIndex < height));
+
+    const int rows = rowIndex * width;
+    const int offsetRows = yOffsetIndex * width;
+    for (int columnIndex = 0; columnIndex < width; ++columnIndex)
+    {
+      // Index to the input buffer to retrieve the alpha value of the foreground text.
+      const unsigned int index = inputPixelSize * static_cast<unsigned int>(rows + columnIndex);
+
+      // Build the index to the input buffer to retrieve the alpha value of the background shadow.
+      unsigned int shadowIndex = 0u;
+      bool isValidShadowIndex = false;
+      if (isValidRowIndex)
+      {
+        const int xOffsetIndex = columnIndex - xOffset;
+        isValidShadowIndex = ((xOffsetIndex >= 0) && (xOffsetIndex < width));
+
+        if (isValidShadowIndex)
+        {
+          shadowIndex = inputPixelSize * static_cast<unsigned int>(offsetRows + xOffsetIndex);
+        }
+      }
+
+      // If the input buffer is an alpha mask, retrieve the values for the foreground text and the background shadow.
+      // If not retrieve the color.
+      float inputShadowOffsetAlphaValue = 1.f;
+      float inputAlphaValue = 1.f;
+      if (isA8)
+      {
+        // Retrieve the alpha value for the shadow.
+        inputShadowOffsetAlphaValue = isValidShadowIndex ? (static_cast<float>(*(inputPixelBuffer + shadowIndex)) / 255.f) : 0.f;
+
+        // Retrieve the alpha value for the text.
+        inputAlphaValue = static_cast<float>(*(inputPixelBuffer + index)) / 255.f;
+      }
+      else
+      {
+        // The input buffer is not an alpha mask. Retrieve the color.
+        textColor[0u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 0u) );
+        textColor[1u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 1u) );
+        textColor[2u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 2u) );
+        textColor[3u] = TO_FLOAT * static_cast<float>( *(inputPixelBuffer + index + 3u) );
+        inputAlphaValue = textColor[3u];
+        inputShadowOffsetAlphaValue = isValidShadowIndex ? TO_FLOAT * static_cast<float>( *(inputPixelBuffer + shadowIndex + 3u) ) : 0.f;
+      }
+
+      // Build the output color.
+      float outputColor[4u];
+
+      if( shadowParameters.blendShadow )
+      {
+        // Blend the shadow's color with the text's color on top
+        const float textAlpha = textColor[3u] * inputAlphaValue;
+        const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
+
+        // Blends the alpha.
+        outputColor[3u] = 1.f - ((1.f - textAlpha) * (1.f - shadowAlpha));
+        const bool isOutputAlphaZero = outputColor[3u] < Dali::Math::MACHINE_EPSILON_1000;
+        if( isOutputAlphaZero )
+        {
+          std::fill( outputColor, outputColor + 4u, 0.f );
+        }
+        else
+        {
+          // Blends the RGB components.
+          float shadowComponent = 0.f;
+          float textComponent = 0.f;
+
+          shadowComponent = shadowColor[0u] * inputShadowOffsetAlphaValue;
+          textComponent = textColor[0u] * inputAlphaValue;
+          outputColor[0u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+
+          shadowComponent = shadowColor[1u] * inputShadowOffsetAlphaValue;
+          textComponent = textColor[1u] * inputAlphaValue;
+          outputColor[1u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+
+          shadowComponent = shadowColor[2u] * inputShadowOffsetAlphaValue;
+          textComponent = textColor[2u] * inputAlphaValue;
+          outputColor[2u] =  (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]);
+        }
+      }
+      else
+      {
+        // No blending!!!
+        std::fill( outputColor, outputColor + 4u, 0.f );
+
+        const float textAlpha = textColor[3u];
+        const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue;
+
+        // Write shadow first.
+        if( shadowAlpha > Dali::Math::MACHINE_EPSILON_1000 )
+        {
+          outputColor[0u] = shadowColor[0u] * inputShadowOffsetAlphaValue;
+          outputColor[1u] = shadowColor[1u] * inputShadowOffsetAlphaValue;
+          outputColor[2u] = shadowColor[2u] * inputShadowOffsetAlphaValue;
+          outputColor[3u] = shadowAlpha;
+        }
+
+        // Write character on top.
+        if( textAlpha > Dali::Math::MACHINE_EPSILON_1000 )
+        {
+          outputColor[0u] = textColor[0u];
+          outputColor[1u] = textColor[1u];
+          outputColor[2u] = textColor[2u];
+          outputColor[3u] = textAlpha;
+        }
+      }
+
+      // Write the color into the output pixel buffer.
+      const unsigned int outputIndex = 4u * (rows + columnIndex);
+      *(outputPixelBufferPtr + outputIndex + 0u) = static_cast<unsigned char>( TO_UCHAR * outputColor[0u] );
+      *(outputPixelBufferPtr + outputIndex + 1u) = static_cast<unsigned char>( TO_UCHAR * outputColor[1u] );
+      *(outputPixelBufferPtr + outputIndex + 2u) = static_cast<unsigned char>( TO_UCHAR * outputColor[2u] );
+      *(outputPixelBufferPtr + outputIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * outputColor[3u] );
+    }
+  }
+
+  // Returns the pixel buffer.
+  return outputPixelBuffer;
+}
+
+Devel::PixelBuffer ConvertToRgba8888(Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha)
+{
+  if (Dali::Pixel::A8 != pixelBuffer.GetPixelFormat())
+  {
+    // Does nothing.
+    return pixelBuffer;
+  }
+
+  const unsigned int width = pixelBuffer.GetWidth();
+  const unsigned int height = pixelBuffer.GetHeight();
+  Devel::PixelBuffer newPixelBuffer = Devel::PixelBuffer::New( width, height, Dali::Pixel::RGBA8888 );
+
+  unsigned char* dstBuffer = newPixelBuffer.GetBuffer();
+  const unsigned char* const srcBuffer = pixelBuffer.GetBuffer();
+
+  const unsigned char r = static_cast<unsigned char>( TO_UCHAR * color.r );
+  const unsigned char g = static_cast<unsigned char>( TO_UCHAR * color.g );
+  const unsigned char b = static_cast<unsigned char>( TO_UCHAR * color.b );
+
+  unsigned char dstColor[4];
+  for( unsigned int j = 0u; j < height; ++j )
+  {
+    const unsigned int lineIndex = j * width;
+    for( unsigned int i=0u; i < width; ++i )
+    {
+      const unsigned int srcIndex = lineIndex + i;
+
+      const float srcAlpha = static_cast<float>( *( srcBuffer + srcIndex ) );
+
+      if( multiplyByAlpha )
+      {
+        dstColor[0u] = static_cast<unsigned char>( srcAlpha * color.r );
+        dstColor[1u] = static_cast<unsigned char>( srcAlpha * color.g );
+        dstColor[2u] = static_cast<unsigned char>( srcAlpha * color.b );
+        dstColor[3u] = static_cast<unsigned char>( srcAlpha * color.a );
+      }
+      else
+      {
+        dstColor[0u] = r;
+        dstColor[1u] = g;
+        dstColor[2u] = b;
+        dstColor[3u] = static_cast<unsigned char>( srcAlpha );
+      }
+
+      const unsigned int dstIndex = srcIndex * 4u;
+      memcpy( dstBuffer + dstIndex, dstColor, 4u );
+    }
+  }
+
+  return newPixelBuffer;
+}
+
+void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend)
+{
+  const Dali::Pixel::Format pixelFormat = dst.GetPixelFormat();
+  if( src.GetPixelFormat() != pixelFormat )
+  {
+    DALI_LOG_ERROR("PixelBuffer::SetBuffer. The pixel format of the new data must be the same of the current pixel buffer.");
+    return;
+  }
+
+  const unsigned int srcWidth = src.GetWidth();
+  const unsigned int srcHeight = src.GetHeight();
+  const unsigned int dstWidth = dst.GetWidth();
+  const unsigned int dstHeight = dst.GetHeight();
+
+  if( ( x > dstWidth ) ||
+      ( y > dstHeight ) ||
+      ( x + srcWidth > dstWidth ) ||
+      ( y + srcHeight > dstHeight ) )
+  {
+    DALI_LOG_ERROR("PixelBuffer::SetBuffer. The source pixel buffer is out of the boundaries of the destination pixel buffer.");
+    return;
+  }
+
+  const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(pixelFormat);
+  if( bytesPerPixel == 0u || bytesPerPixel == 12u || bytesPerPixel == 24u )
+  {
+    return;
+  }
+  const unsigned int alphaIndex = bytesPerPixel - 1u;
+
+  const unsigned char* const srcBuffer = src.GetBuffer();
+  unsigned char* dstBuffer = dst.GetBuffer();
+
+  if( !blend )
+  {
+    const unsigned int currentLineSize = dstWidth * bytesPerPixel;
+    const unsigned int newLineSize = srcWidth * bytesPerPixel;
+    unsigned char* currentBuffer = dstBuffer + (y * dstWidth + x) * bytesPerPixel;
+    for (unsigned int j = 0u; j < srcHeight; ++j)
+    {
+      memcpy(currentBuffer + j * currentLineSize, srcBuffer + j * newLineSize, newLineSize);
+    }
+  }
+  else
+  {
+    float outputColor[4u];
+
+    // Blend the src pixel buffer with the dst pixel buffer as background.
+    //
+    //  fgColor, fgAlpha, bgColor, bgAlpha
+    //
+    //  alpha = 1 - ( 1 - fgAlpha ) * ( 1 - bgAlpha )
+    //  color = ( fgColor * fgAlpha / alpha ) + ( bgColor * bgAlpha * ( 1 - fgAlpha ) / alpha )
+
+    // Jump till the 'x,y' position
+    const unsigned int dstWidthBytes = dstWidth * bytesPerPixel;
+    dstBuffer += ( y * dstWidthBytes + x * bytesPerPixel );
+
+    for (unsigned int j = 0u; j < srcHeight; ++j)
+    {
+      const unsigned int srcLineIndex = j * srcWidth;
+      for (unsigned int i = 0u; i < srcWidth; ++i)
+      {
+        const float srcAlpha = TO_FLOAT * static_cast<float>( *( srcBuffer + bytesPerPixel * ( srcLineIndex + i ) + alphaIndex ) );
+        const float dstAlpha = TO_FLOAT * static_cast<float>( *(dstBuffer + i*bytesPerPixel + alphaIndex) );
+
+        // Blends the alpha channel.
+        const float oneMinusSrcAlpha = 1.f - srcAlpha;
+        outputColor[alphaIndex] = 1.f - (oneMinusSrcAlpha * (1.f - dstAlpha));
+
+        // Blends the RGB channels.
+        const bool isOutputAlphaZero = outputColor[alphaIndex] < Dali::Math::MACHINE_EPSILON_1000;
+        if( isOutputAlphaZero )
+        {
+          std::fill( outputColor, outputColor + bytesPerPixel, 0.f );
+        }
+        else
+        {
+          const float srcAlphaOverOutputAlpha = srcAlpha / outputColor[alphaIndex];                                    // fgAlpha / alpha
+          const float dstAlphaOneMinusSrcAlphaOverOutputAlpha = dstAlpha * oneMinusSrcAlpha / outputColor[alphaIndex]; // bgAlpha * ( 1 - fgAlpha ) / alpha
+          for (unsigned int index = 0u; index < alphaIndex; ++index)
+          {
+            const float dstComponent = TO_FLOAT * static_cast<float>( *( dstBuffer + i * bytesPerPixel + index ) ) * dstAlpha;
+            const float srcComponent = TO_FLOAT * static_cast<float>(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + index) ) * srcAlpha;
+            outputColor[index] = ( srcComponent * srcAlphaOverOutputAlpha ) + ( dstComponent * dstAlphaOneMinusSrcAlphaOverOutputAlpha );
+          }
+        }
+
+        for (unsigned int index = 0u; index < bytesPerPixel; ++index)
+        {
+          *(dstBuffer + i * bytesPerPixel + index) = static_cast<unsigned char>( TO_UCHAR * outputColor[index] );
+        }
+      }
+
+      dstBuffer += dstWidthBytes;
+    }
+  }
+}
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/text/text-utils-devel.h b/dali-toolkit/devel-api/text/text-utils-devel.h
new file mode 100755 (executable)
index 0000000..83c6ea9
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef DALI_TOOLKIT_TEXT_UTILS_DEVEL_H
+#define DALI_TOOLKIT_TEXT_UTILS_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelText
+{
+
+/**
+ * @brief Struct with the text and style parameters to be rendered into a pixel buffer.
+ */
+struct DALI_TOOLKIT_API RendererParameters
+{
+  RendererParameters()
+  : text{},
+    horizontalAlignment{ "begin" },
+    verticalAlignment{ "top" },
+    fontFamily{},
+    fontWeight{},
+    fontWidth{},
+    fontSlant{},
+    layout{ "singleLine" },
+    circularAlignment{ "begin" },
+    textColor{ Color::WHITE },
+    fontSize{ 0.f },
+    textWidth{ 0u },
+    textHeight{ 0u },
+    radius{ 0u },
+    beginAngle{ 0.f },
+    incrementAngle{ 0.f },
+    ellipsisEnabled{ true },
+    markupEnabled{ false },
+    isTextColorSet{ false }
+  {}
+
+  std::string text;                ///< The text to be rendered encoded in utf8.
+
+  std::string horizontalAlignment; ///< The horizontal alignment: one of {"begin", "center", "end"}.
+  std::string verticalAlignment;   ///< The vertical alignment: one of {"top", "center", "bottom"}.
+
+  std::string fontFamily;          ///< The font's family.
+  std::string fontWeight;          ///< The font's weight: one of {"thin", "ultraLight", "extraLight", "light", "demiLight", "semiLight", "book", "normal", "regular", "medium", "demiBold", "semiBold", "bold", "ultraBold", "extraBold", "black", "heavy", "extraBlack"}.
+  std::string fontWidth;           ///< The font's width: one of {"ultraCondensed", "extraCondensed", "condensed", "semiCondensed", "normal", "semiExpanded", "expanded", "extraExpanded", "ultraExpanded"}.
+  std::string fontSlant;           ///< The font's slant. one of {"normal", "roman", "italic", "oblique"}
+  std::string layout;              ///< The type of layout: one of {"singleLine", "multiLine", "circular"}
+  std::string circularAlignment;   ///< The text alignment within the arc: one of {"begin", "center", "end"}. The @p horizontalAlignment and @p verticalAlignment can be used to align the text within the text area.
+
+  Vector4 textColor;               ///< The default text's color. Default is white.
+
+  float fontSize;           ///< The font's size (in points).
+
+  unsigned int textWidth;          ///< The width in pixels of the boundaries where the text is going to be laid-out.
+  unsigned int textHeight;         ///< The height in pixels of the boundaries where the text is going to be laid-out.
+
+  unsigned int radius;             ///< The radius in pixels of the circular text.
+  float beginAngle;                ///< The begin angle in degrees of the text area on the circle. The top of the circle is 0°, the right side 90°, the bottom 180° and the left 270°.
+  float incrementAngle;            ///< The increment angle in degrees of the text area on the circle. The @p incrementAngle defines a direction. If positive, the text will be laid out clockwise.
+
+  bool ellipsisEnabled:1;          ///< Whether the ellipsis layout option is enabled.
+  bool markupEnabled:1;            ///< Whether the mark-up processor is enabled.
+  bool isTextColorSet:1;           ///< Whether a default color has been set.
+};
+
+/**
+ * @brief Struct with info of the embedded items layout.
+ */
+struct DALI_TOOLKIT_API EmbeddedItemInfo
+{
+  TextAbstraction::CharacterIndex characterIndex;       ///< Index to the character within the string.
+  TextAbstraction::GlyphIndex glyphIndex;               ///< Index to the glyph
+  Vector2 position;                                     ///< The layout position within the buffer (top, left corner).
+  Size size;                                            ///< The size within the buffer of the embedded item.
+  Size rotatedSize;                                     ///< The rotated size within the buffer of the embedded item.
+  Degree angle;                                         ///< Rotation angle of the pixel buffer in degrees.
+  TextAbstraction::ColorBlendingMode colorBlendingMode; ///< Whether the color of the image is multiplied by the color of the text.
+};
+
+/**
+* @brief Struct with the parameters needed to build a shadow for the given pixel buffer.
+*/
+struct DALI_TOOLKIT_API ShadowParameters
+{
+  Devel::PixelBuffer input; ///< The input pixel buffer used to create the shadow.
+  Vector4 textColor;        ///< The color of the text.
+  Vector4 color;            ///< The color of the shadow.
+  Vector2 offset;           ///< The offset of the shadow.
+  bool blendShadow;         ///< Whether to blend the shadow.
+};
+
+/**
+ * @brief Renders text into a pixel buffer.
+ *
+ * @note: Can process a mark-up string.
+ * @note: It does the font selection, RTL reordering, shaping and layouting.
+ * @note: The width of the pixel buffer may be different to the given @e textWidth
+ *        due to some padding pixels added.
+ *
+ *  The text is laid-out for the given size @e (textWidth,textHeight).
+ *  If the @e multiLineEnabled option is enabled, the text will wrap in lines.
+ *  If the @e ellipsisEnabled option is enabled, the text will be ellided if
+ *  there is no more space for new lines.
+ *
+ *  It won't be rendered the parts of the text exceeding the boundaries of
+ *  the given width and height.
+ *
+ *  If the given @e textHeight is zero, a big enough pixel buffer will be created
+ *  to render the full text.
+ *
+ *  If the given @e textWidth is zero, the 'natural size' of the text will be
+ *  used to create the pixel buffer to render the full text.
+ *
+ *  If the radius is not zero, the text will be laid-out following a circular path.
+ *  In that case the text is laid-out in a single line.
+ *
+ * If the mark-up string contains embedded items, the @p embeddedItemLayout vector
+ * contains the layout info of each embedded item.
+ *
+ * @param[in] textParameters The text and style options.
+ * @param[out] embeddedItemLayout The layout info of the embedded items.
+ *
+ * @return A pixel buffer with the text rendered on it.
+ */
+DALI_TOOLKIT_API Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout );
+
+/**
+ * @brief Creates a shadow for the text given in the input pixel buffer.
+ *
+ * The function returns a RGBA8888 pixel buffer with the text and its shadow rendered on it.
+ *
+ * The pixel format of the @e input pixel buffer could be an A8 or an RGBA8888. If it's
+ * an A8 pixel buffer, it uses the given @e textColor to give color to the text. Otherwise
+ * it uses the color of the @e input pixel buffer.
+ *
+ * @param[in] shadowParameters The parameters needed to create the text's shadow.
+ *
+ * @return A pixel buffer with the text and the shadow rendered on it.
+ */
+DALI_TOOLKIT_API Devel::PixelBuffer CreateShadow(const ShadowParameters& shadowParameters);
+
+/**
+ * @brief Converts a @p pixelBuffer with pixel format A8 to RGBA8888 using the given @p color.
+ *
+ * @note Does nothing if the @p pixelBuffer is not A8.
+ *
+ * @param[in] pixelBuffer The pixel buffer with pixel format A8
+ * @param[in] color The color used to convert to RGBA8888
+ * @param[in] multiplyByAlpha Whether to multiply the @p color with the alpha value of the @p pixel @p buffer.
+ *
+ * @return The pixel buffer converted to RGBA8888.
+ */
+DALI_TOOLKIT_API Devel::PixelBuffer ConvertToRgba8888( Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha );
+
+/**
+* @brief Updates the @p dst pixel buffer with the data from @p src pixel buffer.
+*
+* @note Both pixel buffers must have the same pixel format. Does nothing if both pixel format are different.
+* @note The function does nothing if the @p src pixel buffer doesn't fit into the @p dst pixel buffer.
+*
+* The @p src pixel buffer could be blended with the @p dst pixel buffer if @p blend is set to @e true.
+*
+* @param[in] src The pixel buffer from where the data is read.
+* @param[in] dst The pixel buffer where the data is written..
+* @param[in] x The top left corner's X within the destination pixel buffer.
+* @param[in] y The top left corner's y within the destination pixel buffer.
+* @param[in] blend Whether to blend the source pixel buffer with the destination pixel buffer as background.
+*/
+DALI_TOOLKIT_API void UpdateBuffer( Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend);
+
+} // namespace DevelText
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UTILS_DEVEL_H
diff --git a/dali-toolkit/devel-api/toolkit-property-index-ranges.h b/dali-toolkit/devel-api/toolkit-property-index-ranges.h
new file mode 100644 (file)
index 0000000..1861a93
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_DEVEL_TOOLKIT_PROPERTY_INDEX_RANGES_H
+#define DALI_DEVEL_TOOLKIT_PROPERTY_INDEX_RANGES_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/object/property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @brief Enumeration for the start and end property ranges.
+ */
+enum DevelPropertyRanges
+{
+  LAYOUT_GROUP_CHILD_PROPERTY_START_INDEX = CHILD_PROPERTY_REGISTRATION_START_INDEX + 1000,     ///< Layout Group Property Start Index.
+  LAYOUT_GROUP_CHILD_PROPERTY_END_INDEX   = LAYOUT_GROUP_CHILD_PROPERTY_START_INDEX + 999,      ///< Layout Group Property End Index.
+  LINEAR_LAYOUT_CHILD_PROPERTY_START_INDEX = LAYOUT_GROUP_CHILD_PROPERTY_END_INDEX + 1,         ///< Linear Layout Property Start Index.
+  LINEAR_LAYOUT_CHILD_PROPERTY_END_INDEX   = LINEAR_LAYOUT_CHILD_PROPERTY_START_INDEX + 999,    ///< Linear Layout Property End Index.
+  GRID_LAYOUT_CHILD_PROPERTY_START_INDEX = LINEAR_LAYOUT_CHILD_PROPERTY_END_INDEX + 1,          ///< Grid Layout Property Start Index.
+  GRID_LAYOUT_CHILD_PROPERTY_END_INDEX   = GRID_LAYOUT_CHILD_PROPERTY_START_INDEX + 999,        ///< Grid Layout Property End Index.
+  FLEX_LAYOUT_CHILD_PROPERTY_START_INDEX = GRID_LAYOUT_CHILD_PROPERTY_END_INDEX + 1,            ///< Flex Layout Property Start Index.
+  FLEX_LAYOUT_CHILD_PROPERTY_END_INDEX   = FLEX_LAYOUT_CHILD_PROPERTY_START_INDEX + 999,        ///< Flex Layout Property End Index.
+  ABSOLUTE_LAYOUT_CHILD_PROPERTY_START_INDEX = FLEX_LAYOUT_CHILD_PROPERTY_END_INDEX +1,         ///< Absolute Layout Property Start Index.
+  ABSOLUTE_LAYOUT_CHILD_PROPERTY_END_INDEX = ABSOLUTE_LAYOUT_CHILD_PROPERTY_START_INDEX + 999,  ///< Absolute Layout Property End Index.
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_DEVEL_TOOLKIT_PROPERTY_INDEX_RANGES_H
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.cpp b/dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.cpp
new file mode 100644 (file)
index 0000000..a989b72
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 "cube-transition-cross-effect.h"
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+CubeTransitionCrossEffect::CubeTransitionCrossEffect( Internal::CubeTransitionCrossEffect& implementation )
+: CubeTransitionEffect( implementation )
+{
+}
+
+CubeTransitionCrossEffect::CubeTransitionCrossEffect( Dali::Internal::CustomActor* internal )
+: CubeTransitionEffect( internal )
+{
+  VerifyCustomActorPointer< Internal::CubeTransitionCrossEffect >( internal );
+}
+
+CubeTransitionCrossEffect CubeTransitionCrossEffect::New( unsigned int numRows, unsigned int numColumns )
+{
+  return Internal::CubeTransitionCrossEffect::New( numRows, numColumns );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h b/dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h
new file mode 100644 (file)
index 0000000..adbab92
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_TOOLKIT_CUBE_TRANSITION_CROSS_EFFECT_H
+#define DALI_TOOLKIT_CUBE_TRANSITION_CROSS_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  /**
+   * CubeTransitionCrossEffect implementation class
+   */
+  class CubeTransitionCrossEffect;
+
+} // namespace Internal
+
+/**
+ * SubClass of CubeTransitionEffect
+ * Rotate the neighboring cubes in perpendicular directions to transition from one image to another
+ */
+class DALI_TOOLKIT_API CubeTransitionCrossEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * Create an initialized CubeTransitionCrossEffect
+   * @param[in] numRows How many rows of cubes
+   * @param[in] numColumns How many columns of cubes
+   * @return The initialized CubeTransitionCrossEffect object
+   */
+  static CubeTransitionCrossEffect New( unsigned int numRows, unsigned int numColumns );
+
+
+public: // Not intended for developer use
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL CubeTransitionCrossEffect( Internal::CubeTransitionCrossEffect& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL CubeTransitionCrossEffect( Dali::Internal::CustomActor* internal );
+
+}; // class CubeTransitionCrossEffect
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CUBE_TRANSITION_CROSS_EFFECT_H
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-effect.cpp b/dali-toolkit/devel-api/transition-effects/cube-transition-effect.cpp
new file mode 100644 (file)
index 0000000..6cd9de4
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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 "cube-transition-effect.h"
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+CubeTransitionEffect::CubeTransitionEffect()
+{
+}
+
+CubeTransitionEffect::~CubeTransitionEffect()
+{
+}
+
+CubeTransitionEffect::CubeTransitionEffect( Internal::CubeTransitionEffect& implementation )
+: Control( implementation )
+{
+}
+
+CubeTransitionEffect::CubeTransitionEffect( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::CubeTransitionEffect>(internal);
+}
+
+CubeTransitionEffect CubeTransitionEffect::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<CubeTransitionEffect, Internal::CubeTransitionEffect>( handle );
+}
+
+void CubeTransitionEffect::SetTransitionDuration( float duration )
+{
+  GetImpl(*this).SetTransitionDuration( duration );
+}
+
+float CubeTransitionEffect::GetTransitionDuration() const
+{
+  return GetImpl(*this).GetTransitionDuration();
+}
+
+void CubeTransitionEffect::SetCubeDisplacement( float displacement )
+{
+  GetImpl(*this).SetCubeDisplacement( displacement );
+}
+
+float CubeTransitionEffect::GetCubeDisplacement() const
+{
+  return GetImpl(*this).GetCubeDisplacement();
+}
+
+bool CubeTransitionEffect::IsTransitioning()
+{
+  return GetImpl(*this).IsTransitioning();
+}
+
+void CubeTransitionEffect::SetCurrentTexture( Texture texture )
+{
+  GetImpl(*this).SetCurrentTexture( texture );
+}
+
+void CubeTransitionEffect::SetTargetTexture( Texture texture )
+{
+  GetImpl(*this).SetTargetTexture( texture );
+}
+
+void CubeTransitionEffect::StartTransition( bool toNextImage )
+{
+  GetImpl(*this).StartTransition( toNextImage );
+}
+
+void CubeTransitionEffect::StartTransition( Vector2 panPosition, Vector2 panDisplacement )
+{
+  GetImpl(*this).StartTransition( panPosition, panDisplacement );
+}
+
+void CubeTransitionEffect::PauseTransition()
+{
+  GetImpl(*this).PauseTransition();
+}
+
+void CubeTransitionEffect::ResumeTransition()
+{
+  GetImpl(*this).ResumeTransition();
+}
+
+void CubeTransitionEffect::StopTransition()
+{
+  GetImpl(*this).StopTransition();
+}
+
+CubeTransitionEffect::TransitionCompletedSignalType& CubeTransitionEffect::TransitionCompletedSignal()
+{
+  return GetImpl( *this ).TransitionCompletedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-effect.h b/dali-toolkit/devel-api/transition-effects/cube-transition-effect.h
new file mode 100755 (executable)
index 0000000..9f9efc0
--- /dev/null
@@ -0,0 +1,225 @@
+#ifndef DALI_TOOLKIT_CUBE_TRANSITION_EFFECT_H
+#define DALI_TOOLKIT_CUBE_TRANSITION_EFFECT_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/texture.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+/**
+ * CubeTransitionEffect implementation class
+ */
+class CubeTransitionEffect;
+
+} // namespace Internal
+
+/**
+ * CubeTransitionEffect is a base class of custom transition effect on Images
+ * The two images are partitioned into tiles and serves as two perpendicular faces of cubes
+ * By rotating these cubes to transit from one image to another
+ *
+ * Usage example:
+ *
+ * @code
+ *
+ * //create a new CubeTransitionEffect
+ * //use the New funtion of subclass ( CubeTransitionWaveEffect or CubeTransitionCrossEffect )
+ * CubeTransitionEffect cubeEffect = CubeTransitionWaveEffect::New(numRows, numColumns);
+ *
+ * //set the duration of transition animation
+ * cubeEffect.SetTransitionDuration( animationDuration );
+ *
+ * //set the displacement of bouncing movement during cube's rotation
+ * cubeEffect.SetCubeDisplacement( cubeDisplacement  );
+ *
+ * // Add to stage
+ * stage.Add( cubeEffect );
+ *
+ * // Set the current image,
+ * // only need to set at beginning or when the current image was transitioned to with no effect or other effect
+ * cubeEffect.SetCurrentImage( firstImage );
+ *
+ * // Set target image, paired with startTransition. These two steps would be repeated as needed
+ * cubeEffect.SetTargetimage( secondImage );
+ * // Activate the effect
+ * //   no param / param ture: default horizontally left panGesture
+ * //   or param false:  default horizontally right panGesture
+ * //   or params position & displacement: specified the panGesture
+ * cubeEffect.StartTransition( );
+ *
+ * @endcode
+ *
+ * Signals
+ * | %Signal Name        | Method                           |
+ * |---------------------|----------------------------------|
+ * | transitionCompleted | @ref TransitionCompletedSignal() |
+ */
+class DALI_TOOLKIT_API CubeTransitionEffect : public Control
+{
+public:
+
+  /**
+   * Create an uninitialized CubeTransitionEffect;
+   * this can be initialized by New function of its subclass
+   */
+  CubeTransitionEffect();
+
+  /**
+   * Destructor
+   */
+  ~CubeTransitionEffect();
+
+  /**
+   * @brief Downcast an Object handle to a CubeTransitionEffect handle.
+   *
+   * If handle points to a CubeTransitionEffect object the downcast produces
+   * a valid handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle A handle to an object
+   * @return A handle to a CubeTransitionEffect object or an uninitialized handle
+   */
+  static CubeTransitionEffect DownCast( BaseHandle handle );
+
+  /**
+   * Set the duration of transition animation
+   * @param[in] duration The duration of transition animation
+   */
+  void SetTransitionDuration( float duration );
+
+  /**
+   * Get the duration of transition animation
+   * @return duration The duration of transition animation
+   */
+  float GetTransitionDuration() const;
+
+  /**
+   * Set the displacement of bouncing animation during cube's rotation
+   * @param[in] displacement The displacement of bouncing animation
+   */
+  void SetCubeDisplacement( float displacement );
+
+  /**
+   * Get the displacement of bouncing animation during cube's rotation
+   * @return displacement The displacement of bouncing animation
+   */
+  float GetCubeDisplacement() const;
+
+  /**
+   * Return the transition status
+   * @return True if the transition is under processing; false if finished
+   */
+  bool IsTransitioning();
+
+  /**
+   * Set the current texture to transition from
+   * if using this same effect continually, only need to set once
+   * @param[in] texture The current texture
+   */
+  void SetCurrentTexture( Texture texture );
+
+  /**
+   * Set the target texture to transit to
+   * @param[in] texture The new Texture showing on stage
+   */
+  void SetTargetTexture( Texture texture );
+
+  /**
+   * Activate the transition animation with horizontally left/right panGesture
+   * @pre target image is set
+   * @param[in] toNextImage Horizontally left panGesture if true, horizontally right if false
+   */
+  void StartTransition( bool toNextImage = true );
+
+  /**
+   * Activate the transition animation with specified panGesture
+   * @pre target image is set
+   * @param[in] panPosition The press down position of panGesture
+   * @param[in] panDisplacement The displacement vector of panGesture
+   */
+  void StartTransition( Vector2 panPosition, Vector2 panDisplacement );
+
+  /**
+   * Pause the transition animation.
+   * It does nothing if the animation is not running.
+   */
+  void PauseTransition();
+
+  /**
+   * Re-Activate the transition animation after it is paused by calling PauseTransition().
+   * It does nothing in other cases.
+   */
+  void ResumeTransition();
+
+  /**
+   * Inactivate the transition animation if it is running.
+   * Also set the rotation and position of cubes, colors of tile to the same as the start state when the animation if finished completely
+   * It does nothing if the animation is not running.
+   */
+  void StopTransition();
+
+public: //Signal
+
+  //Transition animation completed signal
+  typedef Signal< void ( CubeTransitionEffect, Texture ) >  TransitionCompletedSignalType;
+
+  /**
+   * Signal emitted when the transition has completed animation
+   * A callback of the following type may be connected
+   * @code
+   *   void YourCallbackName( CubeTransitionEffect cubeEffect, Texture currentTexture );
+   * @endcode
+   * @return The Signal to connect to.
+   */
+  TransitionCompletedSignalType& TransitionCompletedSignal();
+
+public: // Not intended for developer use
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL CubeTransitionEffect( Internal::CubeTransitionEffect& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL CubeTransitionEffect( Dali::Internal::CustomActor* internal );
+
+}; //class CubeTransitionEffect
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CUBE_TRANSITION_EFFECT_H
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.cpp b/dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.cpp
new file mode 100644 (file)
index 0000000..7d47057
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 "cube-transition-fold-effect.h"
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+CubeTransitionFoldEffect::CubeTransitionFoldEffect( Internal::CubeTransitionFoldEffect& implementation )
+: CubeTransitionEffect( implementation )
+{
+}
+
+CubeTransitionFoldEffect::CubeTransitionFoldEffect( Dali::Internal::CustomActor* internal )
+: CubeTransitionEffect( internal )
+{
+  VerifyCustomActorPointer< Internal::CubeTransitionFoldEffect >( internal );
+}
+
+CubeTransitionFoldEffect CubeTransitionFoldEffect::New(unsigned int numRows, unsigned int numColumns )
+{
+  return Internal::CubeTransitionFoldEffect::New( numRows, numColumns );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h b/dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h
new file mode 100644 (file)
index 0000000..f3b093b
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_TOOLKIT_CUBE_TRANSITION_FOLD_EFFECT_H
+#define DALI_TOOLKIT_CUBE_TRANSITION_FOLD_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  /**
+   * CubeTransitionFoldEffectimplementation class
+   */
+  class CubeTransitionFoldEffect;
+
+} // namespace Internal
+
+/**
+ * SubClass of CubeTransitionEffect
+ * Rotate the neighboring cubes in opposite directions to transition from one image to another
+ */
+class DALI_TOOLKIT_API CubeTransitionFoldEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * Create an initialized CubeTransitionFoldEffect
+   * @param[in] numRows How many rows of cubes
+   * @param[in] numColumns How many columns of cubes
+   * @return The initialized CubeTransitionFoldEffect object
+   */
+  static CubeTransitionFoldEffect New( unsigned int numRows, unsigned int numColumns );
+
+
+public: // Not intended for developer use
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL CubeTransitionFoldEffect( Internal::CubeTransitionFoldEffect& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL CubeTransitionFoldEffect( Dali::Internal::CustomActor* internal );
+
+}; // class CubeTransitionFoldEffect
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CUBE_TRANSITION_FOLD_EFFECT_H
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.cpp b/dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.cpp
new file mode 100644 (file)
index 0000000..66315ad
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 "cube-transition-wave-effect.h"
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+CubeTransitionWaveEffect::CubeTransitionWaveEffect( Internal::CubeTransitionWaveEffect& implementation )
+: CubeTransitionEffect( implementation )
+{
+}
+
+CubeTransitionWaveEffect::CubeTransitionWaveEffect( Dali::Internal::CustomActor* internal )
+: CubeTransitionEffect( internal )
+{
+  VerifyCustomActorPointer< Internal::CubeTransitionWaveEffect >( internal );
+}
+
+CubeTransitionWaveEffect CubeTransitionWaveEffect::New(unsigned int numRows, unsigned int numColumns )
+{
+  return Internal::CubeTransitionWaveEffect::New( numRows, numColumns );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h b/dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h
new file mode 100644 (file)
index 0000000..493b7c6
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_TOOLKIT_CUBE_TRANSITION_WAVE_EFFECT_H
+#define DALI_TOOLKIT_CUBE_TRANSITION_WAVE_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  /**
+   * CubeTransitionWaveEffect implementation class
+   */
+  class CubeTransitionWaveEffect;
+
+} // namespace Internal
+
+/**
+ * SubClass of CubeTransitionEffect
+ * Rotate the cubes successively according to the finger movement to achieve wave-like transition effect
+ */
+class DALI_TOOLKIT_API CubeTransitionWaveEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * Create an initialized CubeTransitionWaveEffect
+   * @param[in] numRows How many rows of cubes
+   * @param[in] numColumns How many columns of cubes
+   * @return The initialized CubeTransitionWaveEffect object
+   */
+  static CubeTransitionWaveEffect New( unsigned int numRows, unsigned int numColumns );
+
+
+public: // Not intended for developer use
+
+  /**
+   * Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL CubeTransitionWaveEffect( Internal::CubeTransitionWaveEffect& implementation );
+
+  /**
+   * Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  DALI_INTERNAL CubeTransitionWaveEffect( Dali::Internal::CustomActor* internal );
+
+}; // class CubeTransitionWaveEffect
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CUBE_TRANSITION_WAVE_EFFECT_H
diff --git a/dali-toolkit/devel-api/visual-factory/transition-data.cpp b/dali-toolkit/devel-api/visual-factory/transition-data.cpp
new file mode 100644 (file)
index 0000000..86d6128
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/internal/visuals/transition-data-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+TransitionData::TransitionData()
+{
+}
+
+TransitionData::~TransitionData()
+{
+}
+
+TransitionData TransitionData::New( const Property::Array& transition )
+{
+  Internal::TransitionDataPtr transitionData = Internal::TransitionData::New( transition );
+  return TransitionData( transitionData.Get() );
+}
+
+TransitionData TransitionData::New( const Property::Map& transition )
+{
+  Internal::TransitionDataPtr transitionData = Internal::TransitionData::New( transition );
+  return TransitionData( transitionData.Get() );
+}
+
+TransitionData TransitionData::DownCast( BaseHandle handle )
+{
+  return TransitionData( dynamic_cast<Dali::Toolkit::Internal::TransitionData*>(handle.GetObjectPtr()));
+}
+
+TransitionData::TransitionData( const TransitionData& handle )
+: BaseHandle( handle )
+{
+}
+
+TransitionData& TransitionData::operator=( const TransitionData& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+size_t TransitionData::Count() const
+{
+  return GetImplementation( *this ).Count();
+}
+
+Property::Map TransitionData::GetAnimatorAt( size_t index )
+{
+  return GetImplementation( *this ).GetAnimatorAt( index );
+}
+
+TransitionData::TransitionData( Internal::TransitionData* pointer )
+: BaseHandle( pointer )
+{
+}
+
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/visual-factory/transition-data.h b/dali-toolkit/devel-api/visual-factory/transition-data.h
new file mode 100755 (executable)
index 0000000..9bba0f6
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef DALI_TOOLKIT_TRANSITION_DATA_H
+#define DALI_TOOLKIT_TRANSITION_DATA_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-handle.h>
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class TransitionData;
+}
+
+/**
+ * @brief This object translates data from a property array of maps
+ * into an array of animators.
+ *
+ * Each animator describes a named object and a named property of that object
+ * to be animated. Internally, these are translated into object instances and
+ * property indices to be animated.
+ * @see Dali::Toolkit::Internal::Control::CreateTransition()
+ *
+ * The animators can each be retrieved as a Property::Map by using Count() and
+ * GetAnimatorAt().
+ *
+ * In psuedo-JSON, the property array can be represented as follows:
+ *
+ * [
+ *   {
+ *     "target": "objectName",
+ *     "property": "propertyKey",
+ *     "initialValue": <value>,  # The property value can be one of several types
+ *     "targetValue":  <value>,
+ *     "animator": {
+ *       "alphaFunction":<easing-function>",
+ *       "timePeriod":{
+ *         "duration": 1.0,
+ *         "delay":    0.0
+ *       }
+ *     }
+ *   },
+ *   # more animators
+ * ]
+ *
+ */
+class DALI_TOOLKIT_API TransitionData : public BaseHandle
+{
+public:
+  /**
+   * Create an uninitialized handle
+   *
+   * @SINCE_1_2.12
+   */
+  TransitionData();
+
+  /**
+   * Destructor - non virtual
+   *
+   * @SINCE_1_2.12
+   */
+  ~TransitionData();
+
+  /**
+   * @brief Creates a TransitionData object
+   *
+   * @SINCE_1_2.12
+   * @param[in] transition The transition data to store (a single animator)
+   * @return A handle to an initialized data.
+   */
+  static TransitionData New( const Property::Map& transition );
+
+  /**
+   * @brief Creates a TransitionData object
+   *
+   * @SINCE_1_2.12
+   * @param[in] transition The transition data to store (an array of maps of animators)
+   * @return A handle to an initialized data.
+   */
+  static TransitionData New( const Property::Array& transition );
+
+  /**
+   * @brief Downcast to a TransitionData handle
+   *
+   * @SINCE_1_2.12
+   * If handle is not a TransitionData, the returned handle is left uninitialized.
+   * @param[in] handle Handle to an object
+   * @return TransitionData handle or an uninitialized handle.
+   */
+  static TransitionData DownCast( BaseHandle handle );
+
+  /**
+   * @brief Copy constructor
+   *
+   * @SINCE_1_2.12
+   * @param[in] handle Handle to an object
+   */
+  TransitionData( const TransitionData& handle );
+
+  /**
+   * @brief Assignment Operator
+   *
+   * @SINCE_1_2.12
+   * @param[in] handle Handle to an object
+   * @return A reference to this object.
+   */
+  TransitionData& operator=( const TransitionData& handle );
+
+  /**
+   * @brief returns the count of the individual property transitions
+   * stored within this handle.
+   *
+   * @SINCE_1_2.12
+   * @return The count of individual transitions
+   */
+  size_t Count() const;
+
+  /**
+   * @brief Return the animator at the given index as a property map.
+   * @param[in] index The index of the animator ( Must be less than Count() )
+   * @return A property map representing the animator
+   */
+  Property::Map GetAnimatorAt( size_t index );
+
+public: // Not intended for application developers
+
+  explicit DALI_INTERNAL TransitionData( Internal::TransitionData *impl );
+};
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TRANSITION_DATA_H
diff --git a/dali-toolkit/devel-api/visual-factory/visual-base.cpp b/dali-toolkit/devel-api/visual-factory/visual-base.cpp
new file mode 100644 (file)
index 0000000..7b20c60
--- /dev/null
@@ -0,0 +1,104 @@
+ /*
+ * Copyright (c) 2018 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 <dali-toolkit/devel-api/visual-factory/visual-base.h>
+
+// INTERAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Visual::Base::Base()
+{
+}
+
+Visual::Base::~Base()
+{
+}
+
+Visual::Base::Base( const Visual::Base& handle )
+: BaseHandle( handle )
+{
+}
+
+Visual::Base& Visual::Base::operator=( const Visual::Base& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+Visual::Base::Base(Internal::Visual::Base *impl)
+: BaseHandle( impl )
+{
+}
+
+void Visual::Base::SetName( const std::string& name )
+{
+  GetImplementation( *this ).SetName( name );
+}
+
+const std::string& Visual::Base::GetName() const
+{
+  return GetImplementation( *this ).GetName();
+}
+
+void Visual::Base::SetTransformAndSize( const Dali::Property::Map& transform, Size controlSize )
+{
+  GetImplementation( *this ).SetTransformAndSize( transform, controlSize );
+}
+
+float Visual::Base::GetHeightForWidth( float width )
+{
+  return GetImplementation( *this ).GetHeightForWidth( width );
+}
+
+float Visual::Base::GetWidthForHeight( float height )
+{
+  return GetImplementation( *this ).GetWidthForHeight( height );
+}
+
+void Visual::Base::GetNaturalSize(Vector2& naturalSize )
+{
+  GetImplementation( *this ).GetNaturalSize( naturalSize );
+}
+
+void Visual::Base::SetDepthIndex( int index )
+{
+  GetImplementation( *this ).SetDepthIndex( index );
+}
+
+int Visual::Base::GetDepthIndex() const
+{
+  return GetImplementation( *this ).GetDepthIndex();
+}
+
+void Visual::Base::CreatePropertyMap( Dali::Property::Map& map ) const
+{
+  GetImplementation( *this ).CreatePropertyMap( map );
+}
+
+
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/visual-factory/visual-base.h b/dali-toolkit/devel-api/visual-factory/visual-base.h
new file mode 100755 (executable)
index 0000000..94db5c4
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef DALI_TOOLKIT_VISUAL_BASE_H
+#define DALI_TOOLKIT_VISUAL_BASE_H
+/*
+ * Copyright (c) 2018 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 <dali/public-api/object/base-handle.h>
+#include <dali/public-api/actors/actor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Visual
+{
+class Base;
+}
+}
+
+namespace Visual
+{
+
+/**
+ * @brief A Visual provides a renderer for drawing a control component. A control may have multiple visuals.
+ *
+ * Visuals reuse geometry, shader etc. across controls. They ensure that the renderer and texture sets exist only when control is on-stage.
+ * Each visual also responds to actor size and color change, and provides clipping at the renderer level.
+ * Note: The visual responds to the the Actor::COLOR by blending it with the 'Multiply' operator.
+ *
+ * The following properties are optional, but can be supplied in the property map to Dali::Toolkit::VisualFactory::CreateVisual().
+ *
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | customShader            | MAP              |
+ * | transform               | MAP              |
+ *
+ * where \b customShader is a map with at least one of the following properties:
+ * | %Property Name          | Type                       | Required | Default | Description                             |
+ * |-------------------------|----------------------------|----------|---------|-----------------------------------------|
+ * | vertexShader            | STRING                     | No       | ""      | Vertex shader code                      |
+ * | fragmentShader          | STRING                     | No       | ""      | Fragment shader code                    |
+ * | subdivideGridX          | INTEGER                    | No       | 1       | How to subdivide the grid along X       |
+ * | subdivideGridY          | INTEGER                    | No       | 1       | How to subdivide the grid along Y       |
+ * | shaderHints             | INTEGER or ARRAY of STRING | No       | NONE    | Bitmask of hints @sa Dali::Shader::Hint |
+ *
+ * and \b transform is a map with the following properties:
+ * | %Property Name          | Type              | Required | Default                | Description                                         |
+ * |-------------------------|-------------------|----------|------------------------|-----------------------------------------------------|
+ * | offset                  | VECTOR2           | No       | (0,0)                  | Offset of visual from origin                        |
+ * | size                    | VECTOR2           | No       | (1,1)                  | size of visual                                      |
+ * | origin                  | INTEGER or STRING | No       | CENTER                 | origin of the visual @sa Dali::Toolkit::Align       |
+ * | anchorPoint             | INTEGER or STRING | No       | CENTER                 | anchor point of the visual @sa Dali::Toolkit::Align |
+ * | offsetPolicy            | VECTOR2           | No       | ( RELATIVE, RELATIVE ) | @sa Dali::Toolkit::Visual::Transform::Policy   |
+ * | sizePolicy              | VECTOR2           | No       | ( RELATIVE, RELATIVE ) | @sa Dali::Toolkit::Visual::Transform::Policy   |
+ *
+ * Relative means that the component describes a factor of the parent control size;
+ * size.x = 1 means full width; size.y = 0.5 means half height.
+ *
+ * Absolute means that the component describes world units (equivalent to pixels)
+ *
+ */
+class DALI_TOOLKIT_API Base : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an empty Visual Handle
+   */
+  Base();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Base();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle.
+   */
+  Base( const Base& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  Base& operator=( const Base& handle );
+
+  /**
+   * @brief Set the name of the visual
+   *
+   * Used by the styling system to animate properties
+   * @param[in] name The name to give the visual
+   */
+  void SetName( const std::string& name );
+
+  /**
+   * @brief Get the name of the visual
+   *
+   * Used by the styling system to animate properties
+   * @return The name of the visual
+   */
+  const std::string& GetName() const;
+
+  /**
+   * @brief Sets the transform and the control size
+   *
+   * @param[in] transform A property map describing the transform
+   * @param[in] controlSize The size of the parent control for visuals that need to scale internally.
+   */
+  void SetTransformAndSize( const Dali::Property::Map& transform, Size controlSize );
+
+  /**
+   * @brief Returns the height for a given width.
+   *
+   * @param[in] width Width to use.
+   *
+   * @return The height based on the width.
+   */
+  float GetHeightForWidth( float width );
+
+  /**
+   * @brief Returns the width for a given height.
+   *
+   * @param[in] height Height to use.
+   *
+   * @return The width based on the height.
+   */
+  float GetWidthForHeight( float height );
+
+  /**
+   * @brief Return the natural size of the visual.
+   *
+   * Deriving classes stipulate the natural size and by default a
+   * visual has a ZERO natural size.
+   *
+   * @note A visual may not actually have a natural size until it has
+   * been placed on stage and acquired all it's resources.
+   *
+   * @param[out] naturalSize The visual's natural size
+   */
+  void GetNaturalSize( Vector2& naturalSize );
+
+  /**
+   * @brief Set the depth index of this visual.
+   *
+   * Depth-index controls draw-order for overlapping visuals.
+   * Visuals with higher depth indices are rendered in front of other visual with smaller values
+   *
+   * @param[in] index The depth index of this visual.
+   */
+  void SetDepthIndex( int index );
+
+  /**
+   * @brief Get the depth index of this visual
+   *
+   * @return The depth index of this visual.
+   */
+  int GetDepthIndex() const;
+
+  /**
+   * @brief Create the property map representing this visual.
+   *
+   * @param[out] map The visual property map.
+   */
+  void CreatePropertyMap( Dali::Property::Map& map ) const;
+
+public: // Not intended for application developers
+
+  explicit DALI_INTERNAL Base(Internal::Visual::Base *impl);
+
+};
+
+} // namespace Visual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /*DALI_TOOLKIT_VISUAL_BASE_H*/
diff --git a/dali-toolkit/devel-api/visual-factory/visual-factory.cpp b/dali-toolkit/devel-api/visual-factory/visual-factory.cpp
new file mode 100644 (file)
index 0000000..b24adbb
--- /dev/null
@@ -0,0 +1,124 @@
+ /*
+ * 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 "visual-factory.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+  const char * const DALI_DEBUG_RENDERING("DALI_DEBUG_RENDERING");
+}
+
+VisualFactory VisualFactory::Get()
+{
+  VisualFactory factory;
+
+  // Check whether the VisualFactory is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if( singletonService )
+  {
+    BaseHandle handle = singletonService.GetSingleton( typeid(VisualFactory) );
+    if( handle )
+    {
+      //If so, downcast the handle of singleton to VisualFactory
+      factory = VisualFactory( dynamic_cast<Internal::VisualFactory*>(handle.GetObjectPtr()) );
+    }
+
+    if( !factory )// If not, create the VisualFactory and register it as a singleton
+    {
+      // Check whether debug rendering is required
+      if( EnvironmentVariable::GetEnvironmentVariable( DALI_DEBUG_RENDERING ) )
+      {
+        factory = VisualFactory( new Internal::VisualFactory(true) );
+      }
+      else
+      {
+        factory = VisualFactory( new Internal::VisualFactory(false) );
+      }
+      singletonService.Register( typeid(VisualFactory), factory );
+
+    }
+  }
+
+  return factory;
+}
+
+VisualFactory::VisualFactory()
+{
+}
+
+VisualFactory::~VisualFactory()
+{
+}
+
+VisualFactory::VisualFactory( const VisualFactory& handle )
+: BaseHandle( handle )
+{
+}
+
+VisualFactory& VisualFactory::operator=( const VisualFactory& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+VisualFactory::VisualFactory(Internal::VisualFactory *impl)
+: BaseHandle(impl)
+{
+}
+
+Visual::Base VisualFactory::CreateVisual( const Property::Map& propertyMap )
+{
+  return GetImplementation( *this ).CreateVisual( propertyMap );
+}
+
+Visual::Base VisualFactory::CreateVisual( const Image& image )
+{
+  return GetImplementation( *this ).CreateVisual( image );
+}
+
+Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size )
+{
+  return GetImplementation( *this ).CreateVisual( url, size );
+}
+
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  GetImplementation( *this ).SetPreMultiplyOnLoad( preMultiply );
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+  return GetImplementation( *this ).GetPreMultiplyOnLoad();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/devel-api/visual-factory/visual-factory.h b/dali-toolkit/devel-api/visual-factory/visual-factory.h
new file mode 100644 (file)
index 0000000..0a86754
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef DALI_TOOLKIT_VISUAL_FACTORY_H
+#define DALI_TOOLKIT_VISUAL_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-handle.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+
+namespace Dali
+{
+class Image;
+struct Vector4;
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class VisualFactory;
+}
+
+/**
+ * @brief VisualFactory is a singleton object that provides and shares visuals between controls
+ *
+ * By setting environment variable 'DALI_DEBUG_RENDERING', a debug visual is used which renders a quad wireframe.
+ *
+ * The visual type is required in the property map for requesting a visual.
+ *
+ * | %Property Name           | Type              |
+ * |--------------------------|-------------------|
+ * | visualType               | INTEGER or STRING |
+ * | shader                   | MAP               |
+ */
+class DALI_TOOLKIT_API VisualFactory : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create or retrieve VisualFactory singleton.
+   *
+   * @return A handle to the VisualFactory control.
+   */
+  static VisualFactory Get();
+
+  /**
+   * @brief Create a VisualFactory handle.
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  VisualFactory();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~VisualFactory();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle.
+   */
+  VisualFactory( const VisualFactory& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  VisualFactory& operator=( const VisualFactory& handle );
+
+  /**
+   * @brief Request the visual
+   *
+   * @param[in] propertyMap The map contains the properties required by the visual.
+   *            The content of the map determines the type of visual that will be returned.
+   * @return The handle to the created visual
+   */
+  Visual::Base CreateVisual( const Property::Map& propertyMap  );
+
+  /**
+   * @brief Request the visual to render the image.
+   *
+   * @param[in] image The image to be rendered.
+   * @return The pointer pointing to the visual
+   */
+  Visual::Base CreateVisual( const Image& image );
+
+  /**
+   * @brief Request the visual to render the given resource at the url.
+   *
+   * @param[in] url The URL to the resource to be rendered.
+   * @param[in] size The width and height to fit the loaded image to.
+   * @return The pointer pointing to the visual
+   */
+  Visual::Base CreateVisual( const std::string& url, ImageDimensions size );
+
+  /**
+   * @brief Enable or disable premultiplying alpha in images and image visuals.
+   *
+   * The default is to enable pre-multiplication on load.
+   *
+   * Applications that have assets with pre-multiplied alpha already applied should turn this option off.
+   *
+   * @param[in] preMultiply True if loaded images for image visuals should have alpha multiplied into the color
+   * channels.
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @brief Get the setting for automatically pre-multiplying image visual images on load.
+   *
+   * @return True if loaded images have pre-multiplied alpha applied on load, false otherwise.
+   */
+  bool GetPreMultiplyOnLoad() const;
+
+private:
+
+  explicit DALI_INTERNAL VisualFactory(Internal::VisualFactory *impl);
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VISUAL_FACTORY_H
diff --git a/dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h
new file mode 100755 (executable)
index 0000000..41b3f31
--- /dev/null
@@ -0,0 +1,347 @@
+#ifndef DALI_TOOLKIT_DEVEL_ANIMATED_GRADIENT_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_DEVEL_ANIMATED_GRADIENT_VISUAL_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ *
+ */
+
+/**
+ * @brief AnimatedGradientVisual is to render a smooth transition of colors to the control's quad with animation.
+ */
+namespace DevelAnimatedGradientVisual
+{
+
+/**
+ * @brief AnimatedGradientVisual Property
+ */
+namespace Property
+{
+
+/**
+ * @brief AnimatedGradientVisual Property
+ */
+enum
+{
+  /**
+   * @brief The form of gradient.
+   * @details Name "gradientType", type GradientType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is GradientType::LINEAR.
+   * @see GradientType::Type
+   */
+  GRADIENT_TYPE = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The coordinate system inside of control's quad.
+   * @details Name "unitType", type UnitType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is UnitType::OBJECT_BOUNDING_BOX.
+   * @see UnitType::Type
+   */
+  UNIT_TYPE,
+
+  /**
+   * @brief The policy of color when gradient coordinate is not between 0 and 1.
+   * @details Name "spreadType", type SpreadType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is SpreadType::REFLECT.
+   * @see SpreadType::Type
+   */
+  SPREAD_TYPE,
+
+  /**
+   * @brief The position of a gradient coordinate is 0. If GRADIENT_TYPE is RADIAL, than it will be center of circle.
+   * @details Name "startPosition", type Property::Vector2 or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property
+   * @note If not supplied, default is Vector2( -0.5f, 0.0f ).
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property
+   */
+  START_POSITION,
+
+  /**
+   * @brief The color of a gradient coordinate is 0.
+   * @details Name "startColor", type Property::Vector4 or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is Vector4( 143.0f, 170.0f, 220.0f, 255.0f ) / 255.0f.
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   */
+  START_COLOR,
+
+  /**
+   * @brief The position of a gradient coordinate is 1.
+   * @details Name "endPosition", type Property::Vector2 or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is Vector2( 0.5f, 0.0f ).
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   */
+  END_POSITION,
+
+  /**
+   * @brief The color of a gradient coordinate is 1.
+   * @details Name "endColor", type Property::Vector4 or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is Vector4( 255.0f, 163.0f, 163.0f, 255.0f ) / 255.0f.
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property
+   */
+  END_COLOR,
+
+  /**
+   * @brief The center of rotate START_POSITION and END_POSITION.
+   * @details Name "rotateCenter", type Property::Vector2 or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is Vector2( 0.0f, 0.0f ).
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property
+   */
+  ROTATE_CENTER,
+
+  /**
+   * @brief The amount of rotate START_POSITION and END_POSITION in radian.
+   * @details Name "rotateAmount", type Property::FLOAT or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is 0.0f.
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property
+   */
+  ROTATE_AMOUNT,
+
+  /**
+   * @brief The offset of gradient coordinate. The point will have a color where (gradient coordinate + offset).
+   * @details Name "offset", type Property::FLOAT or Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   * @note If not supplied, default is Animation from 0.0f to 2.0f, with duration 3.0f seconds.
+   * @note This can be animated when you use type as Property::Map which index is AnimatedGradientVisual::AnimationParameter::Property.
+   */
+  OFFSET
+};
+
+} // namespace Property
+
+/**
+ * @brief The type of gradient form. It decide the method of calculate gradient coordinate.
+ * - If GradientType::Type is LINEAR, gradient coordinate is dot product with the line which contain START_POSITION and END_POSITION.
+ * - If GradientType::Type is RADIAL, gradient coordinate is euclidean distance from START_POSITION.
+ */
+namespace GradientType
+{
+
+/**
+ * @brief The type of gradient form. It decide the method of calculate gradient coordinate.
+ * - If GradientType::Type is LINEAR, gradient coordinate is dot product with the line which contain START_POSITION and END_POSITION.
+ * - If GradientType::Type is RADIAL, gradient coordinate is euclidean distance from START_POSITION.
+ */
+enum Type
+{
+  LINEAR, ///< Draw gradient linear form.
+  RADIAL ///< Draw gradient radial form.
+};
+
+} // namespace GradientType
+
+/**
+ * @brief The type of coordinate system for certain attributes of the points in a gradients.
+ * This applies to the START_POSITION, END_POSITION, and ROTATE_CENTER.
+ */
+namespace UnitType
+{
+
+/**
+ * @brief The type of coordinate system for certain attributes of the points in a gradients.
+ * This applies to the START_POSITION, END_POSITION, and ROTATE_CENTER.
+ */
+enum Type
+{
+  OBJECT_BOUNDING_BOX, ///< Use positions coordinate in bottom-left(-0.5,-0.5) ~ top-right(0.5,0.5).
+  USER_SPACE, ///< Use positions coordinate in bottom-left(-ActorSize.xy * 0.5) ~ top-right(ActorSize.xy * 0.5).
+};
+
+} // namespace UnitType
+
+/**
+ * @brief The policies that define what happens if the gradient coordinate is not between 0 and 1.
+ */
+namespace SpreadType
+{
+
+/**
+ * @brief The policies that define what happens if the gradient coordinate is not between 0 and 1.
+ */
+enum Type
+{
+  REFLECT, ///<  Reflect the gradient pattern start-to-end, end-to-start, start-to-end etc.
+  REPEAT, ///< Repeat the gradient pattern start-to-end, start-to-end, start-to-end etc.
+  CLAMP, ///< Use the terminal colors of gradient.
+};
+
+} // namespace SpreadType
+
+/**
+ * @brief AnimatedGradientVisual::AnimationParameter is information of each properties animation.
+ * Value animate from start to target during duration seconds.
+ * Each start/target value type for AnimatedGradientVisual Property is :
+ * - START_POSITION, END_POSITION, ROTATE_CENTER is Property::Vector2
+ * - START_COLOR, END_COLOR is Property::Vector4
+ * - ROTATE_AMOUNT, OFFSET is Property::FLOAT
+ * You can set the animation information to AnimatedGradientVisual Property by using Property::MAP.
+ */
+namespace AnimationParameter
+{
+
+/**
+ * @brief AnimatedGradientVisual::AnimationParameter Property
+ */
+enum Property
+{
+
+  /**
+   * @brief The start value of this animation.
+   * @details Name "startValue", type depends on AnimatedGradientVisual Property.
+   * @note If not supplied, default is Property::Value( 0.0f ).
+   */
+  START = DevelAnimatedGradientVisual::Property::OFFSET + 1,
+
+  /**
+   * @brief The target value of this animation.
+   * @details Name "targetValue", type depends on AnimatedGradientVisual Property.
+   * @note If not supplied, default is Property::Value( 0.0f ).
+   */
+  TARGET,
+
+  /**
+   * @brief The direction of this animation.
+   * @details Name "directionType", type DirectionType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is DirectionType::FORWARD.
+   * @see DirectionType::Type
+   */
+  DIRECTION,
+
+  /**
+   * @brief The duration of this animation in seconds.
+   * @details Name "duration", type Property::FLOAT.
+   * @note If not supplied, default is 3.0f.
+   */
+  DURATION,
+
+  /**
+   * @brief The delay of this animation in seconds.
+   * If delay is positive, wait the animation 'delay' seconds.
+   * If delay is negative, skip the animation '-delay' seconds.
+   * @details Name "delay", type Property::FLOAT.
+   * @note If not supplied, default is 0.0f.
+   */
+  DELAY,
+
+  /**
+   * @brief The repeat count of this animation.
+   * If repeat is negative, animate unlimited loop.
+   * If repeat is zero, animation will no run.
+   * If repeat is positive, animate 'repeat' times.
+   * @details Name "repeat", type Property::INTEGER.
+   * @note If not supplied, default is 0.
+   */
+  REPEAT,
+
+  /**
+   * @brief The delay before each loop of this animation in seconds.
+   * @details Name "repeatDelay", type Property::FLOAT.
+   * @note If not supplied, default is 0.0f.
+   */
+  REPEAT_DELAY,
+
+  /**
+   * @brief The motion of this animation.
+   * @details Name "motionType", type MotionType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is MotionType::LOOP.
+   * @see MotionType::Type
+   */
+  MOTION_TYPE,
+
+  /**
+   * @brief The easing option of this animation.
+   * @details Name "easingType", type EasingType::Type (Property::INTEGER) or Property::STRING.
+   * @note If not supplied, default is EasingType::LINEAR.
+   * @see EasingType::Type
+   */
+  EASING_TYPE
+};
+
+/**
+ * @brief The type of animation direction
+ */
+namespace DirectionType
+{
+
+/**
+ * @brief The type of animation direction
+ */
+enum Type
+{
+  FORWARD, ///< Animate value from START to TARGET
+  BACKWARD, ///< Animate value frome TARGET to START
+};
+
+} // namespace DirectionType
+
+/**
+ * @brief The type of animation motion
+ */
+namespace MotionType
+{
+
+/**
+ * @brief The type of animation motion
+ */
+enum Type
+{
+  LOOP, ///< Animate loopingmode restart
+  MIRROR, ///< Animate loopingmode auto_reverse
+};
+
+} // namespace MotionType
+
+/**
+ * @brief The type of animation easing
+ */
+namespace EasingType
+{
+
+/**
+ * @brief The type of animation easing
+ */
+enum Type
+{
+  LINEAR, ///< Easing animation linear
+  IN, ///< Ease-in animation (slow start -> fast finish)
+  OUT, ///< Ease-out animation (fast start -> slow finish)
+  IN_OUT, ///< Ease-in and Ease-out animation (slow start -> slow finish)
+};
+
+} // namespace EasingType
+
+} // namespace AnimationParameter
+
+} // namespace DevelAnimatedGradientVisual
+
+/**
+ *
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif
diff --git a/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h b/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h
new file mode 100644 (file)
index 0000000..4218045
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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 DevelAnimatedImageVisual
+{
+
+/**
+ * @brief Actions that the animated image visual can perform.  These actions are called through the Visual::Base::DoAction API.
+ */
+namespace Action
+{
+/**
+ * @brief The available actions for this visual
+ */
+enum Type
+{
+  PLAY,        ///< Play the animated GIF. This is also Default playback mode.
+  PAUSE,       ///< Pause the animated GIF.
+  STOP,        ///< Stop the animated GIF.
+  JUMP_TO      ///< Jump to the specified frame. Property::INTEGER value should be passed.
+};
+
+} // namespace Action
+
+} // namespace DevelAnimatedImageVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h b/dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h
new file mode 100644 (file)
index 0000000..82d463c
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_ACTIONS_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_ACTIONS_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 DevelAnimatedVectorImageVisual
+{
+
+/**
+ * @brief Actions that the animated vector image visual can perform.  These actions are called through the Visual::Base::DoAction API.
+ */
+namespace Action
+{
+/**
+ * @brief The available actions for this visual
+ */
+enum Type
+{
+  PLAY,            ///< Play the animated vector image.
+  PAUSE,           ///< Pause the animated vector image.
+  STOP,            ///< Stop the animated vector image. This is also Default playback mode.
+  JUMP_TO,         ///< Jump to the specified frame. Property::INTEGER value should be passed.
+  UPDATE_PROPERTY  ///< Update the properties of the animated vector image.
+};
+
+} // namespace Action
+
+} // namespace DevelAnimatedVectorImageVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_ACTIONS_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h b/dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h
new file mode 100644 (file)
index 0000000..3ab14e1
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_SIGNALS_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_SIGNALS_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 DevelAnimatedVectorImageVisual
+{
+
+/**
+ * @brief Signal that the animated vector image visual can emit.
+ */
+namespace Signal
+{
+/**
+ * @brief The available signals for this visual
+ */
+enum Type
+{
+  ANIMATION_FINISHED      ///< Animation has finished.
+};
+
+} // namespace Signal
+
+} // namespace DevelAnimatedVectorImageVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_VECTOR_IMAGE_VISUAL_SIGNALS_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h
new file mode 100644 (file)
index 0000000..a10df8a
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef DALI_TOOLKIT_ARC_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_ARC_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelArcVisual
+{
+
+/**
+ * @brief ArcVisual Properties.
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the ArcVisual.
+ */
+enum
+{
+  /**
+   * @brief The thickness of the arc.
+   * @details Name "thickness", type Property::FLOAT.
+   * @note Mandatory.
+   */
+  THICKNESS = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The start angle where the arc begins in degrees.
+   * @details Name "startAngle", type Property::FLOAT.
+   * @note Optional. If not specified, the default is 0.
+   */
+  START_ANGLE,
+
+  /**
+   * @brief The sweep angle of the arc in degrees.
+   * @details Name "sweepAngle", type Property::FLOAT.
+   * The arc starts at a specified start angle and sweeps clockwise, drawing slices of pie.
+   * @note Optional. If not specified, the default is 360.
+   */
+  SWEEP_ANGLE,
+
+  /**
+   * @brief The cap of the arc.
+   * @details Name "cap", Type Cap::Type (Property::INTEGER)
+   * It specifies the shape of the endpoints.
+   * @note Optional. If not specified, the default is Cap::BUTT.
+   */
+  CAP,
+};
+
+} // namespace Property
+
+/**
+ * @brief Enumeration for the cap style.
+ */
+namespace Cap
+{
+
+enum Type
+{
+  BUTT,      ///< The arc does not extend beyond its two endpoints.
+  ROUND      ///< The arc will be extended by a half circle with the center at the end.
+};
+
+} // namespace Cap
+
+} // namespace DevelArcVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ARC_VISUAL_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/color-visual-properties-devel.h
new file mode 100644 (file)
index 0000000..654b290
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+
+namespace DevelColorVisual
+{
+
+/**
+ * @brief Additional ColorVisual Properties.
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of additional properties belonging to the ColorVisual.
+ */
+enum
+{
+  MIX_COLOR = Toolkit::ColorVisual::Property::MIX_COLOR,
+
+  /**
+   * @brief Whether to render if the MIX_COLOR is transparent.
+   * @details Name "renderIfTransparent", type Property::BOOLEAN.
+   * @note Optional.
+   * @note By default it's false, i.e. ColorVisual will not render if the MIX_COLOR is transparent.
+   */
+  RENDER_IF_TRANSPARENT = MIX_COLOR + 1,
+
+  /**
+   * @brief The blur radius of the visual.
+   * @details Name "blurRadius", type Property::FLOAT.
+   *          If the value is 0, the edge is sharp. Otherwise, the larger the value, the more the edge is blurred.
+   * @note Optional.
+   * @note The default is 0.
+   * @note The visual size increases by the blur radius.
+   */
+  BLUR_RADIUS = MIX_COLOR + 2,
+};
+
+} // namespace Property
+
+} // namespace ColorVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/image-visual-actions-devel.h b/dali-toolkit/devel-api/visuals/image-visual-actions-devel.h
new file mode 100644 (file)
index 0000000..78a1451
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_ACTIONS_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_ACTIONS_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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 DevelImageVisual
+{
+
+/**
+ * @brief Actions that the image visual can perform.  These actions are called through the Visual::Base::DoAction API.
+ */
+namespace Action
+{
+/**
+ * @brief The available actions for this visual
+ */
+enum Type
+{
+  RELOAD = 0  ///< Force reloading of the image, all visuals using this image will get the latest one.
+};
+
+} // namespace Actions
+
+} // namespace DevelImageVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_ACTIONS_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h
new file mode 100644 (file)
index 0000000..e6e5303
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelImageVisual
+{
+
+namespace Property
+{
+
+enum Type
+{
+  URL                 = Dali::Toolkit::ImageVisual::Property::URL,
+  FITTING_MODE        = Dali::Toolkit::ImageVisual::Property::FITTING_MODE,
+  SAMPLING_MODE       = Dali::Toolkit::ImageVisual::Property::SAMPLING_MODE,
+  DESIRED_WIDTH       = Dali::Toolkit::ImageVisual::Property::DESIRED_WIDTH,
+  DESIRED_HEIGHT      = Dali::Toolkit::ImageVisual::Property::DESIRED_HEIGHT,
+  SYNCHRONOUS_LOADING = Dali::Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING,
+  BORDER_ONLY         = Dali::Toolkit::ImageVisual::Property::BORDER_ONLY,
+  PIXEL_AREA          = Dali::Toolkit::ImageVisual::Property::PIXEL_AREA,
+  WRAP_MODE_U         = Dali::Toolkit::ImageVisual::Property::WRAP_MODE_U,
+  WRAP_MODE_V         = Dali::Toolkit::ImageVisual::Property::WRAP_MODE_V,
+  BORDER              = Dali::Toolkit::ImageVisual::Property::BORDER,
+  ATLASING            = Dali::Toolkit::ImageVisual::Property::ATLASING,
+  ALPHA_MASK_URL      = Dali::Toolkit::ImageVisual::Property::ALPHA_MASK_URL,
+  BATCH_SIZE          = Dali::Toolkit::ImageVisual::Property::BATCH_SIZE,
+  CACHE_SIZE          = Dali::Toolkit::ImageVisual::Property::CACHE_SIZE,
+  FRAME_DELAY         = Dali::Toolkit::ImageVisual::Property::FRAME_DELAY,
+  MASK_CONTENT_SCALE  = Dali::Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE,
+  CROP_TO_MASK        = Dali::Toolkit::ImageVisual::Property::CROP_TO_MASK,
+  LOAD_POLICY         = Dali::Toolkit::ImageVisual::Property::LOAD_POLICY,
+  RELEASE_POLICY      = Dali::Toolkit::ImageVisual::Property::RELEASE_POLICY,
+  ORIENTATION_CORRECTION = Dali::Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION,
+
+  /**
+   * @brief Overlays the auxiliary image on top of an NPatch image.
+   *
+   * The resulting visual image will be at least as large as the
+   * smallest possible n-patch or the auxiliary image, whichever is
+   * larger.
+   *
+   * @details Name "auxiliaryImage", Type Property::STRING, URL of the image.
+   * @note Default true
+   */
+  AUXILIARY_IMAGE = ORIENTATION_CORRECTION + 1,
+
+  /**
+   * @brief An alpha value for mixing between the masked main NPatch image and the auxiliary image
+   * @details Name "auxiliaryImageAlpha", Type Property::FLOAT, between 0 and 1
+   * @note Default 0
+   */
+  AUXILIARY_IMAGE_ALPHA = ORIENTATION_CORRECTION + 2,
+
+  /**
+   * @brief The number of times the AnimatedImageVisual or AnimatedVectorImageVisual will be looped.
+   * @details Name "loopCount", type Property::INTEGER.
+   * @note For Animated images only. Default -1. if < 0, loop unlimited. else, loop loopCount times.
+   */
+  LOOP_COUNT = ORIENTATION_CORRECTION + 3,
+
+  /**
+   * @brief The playing range the AnimatedVectorImageVisual will use.
+   *
+   * Animation will play between the values specified. The array can have two integer values.
+   * Or it can have one or two strings, which are markers. More will be ignored.
+   * Both values should be between 0 and the total frame number, otherwise they will be ignored.
+   * If the range provided is not in proper order ( minimum, maximum ), it will be reordered.
+   *
+   * A marker has its start frame and end frame.
+   * Animation will play between the start frame and the end frame of the marker if one marker is specified.
+   * Or animation will play between the start frame of the first marker and the end frame of the second marker if two markers are specified.
+   *
+   * @details Name "playRange", Type Property::ARRAY of Property::INTEGER or Property::ARRAY of Property::STRING.
+   * @note Default 0 and the total frame number.
+   */
+  PLAY_RANGE = ORIENTATION_CORRECTION + 4,
+
+  /**
+   * @brief The playing state the AnimatedVectorImageVisual will use.
+   * @details Name "playState", Type PlayState::Type (Property::INTEGER)
+   * @note This property is read-only.
+   */
+  PLAY_STATE = ORIENTATION_CORRECTION + 5,
+
+  /**
+   * @brief The current frame number the AnimatedVectorImageVisual will use.
+   * @details Name "currentFrameNumber", Type Property::INTEGER, between [0, the maximum frame number] or between the play range if specified
+   * @note This property is read-only.
+   */
+  CURRENT_FRAME_NUMBER = ORIENTATION_CORRECTION + 6,
+
+  /**
+   * @brief The total frame number the AnimatedVectorImageVisual will use.
+   * @details Name "totalFrameNumber", Type Property::INTEGER.
+   * @note This property is read-only.
+   */
+  TOTAL_FRAME_NUMBER = ORIENTATION_CORRECTION + 7,
+
+  /**
+   * @brief  The stop behavior the AnimatedImageVisual and AnimatedVectorImageVisual will use.
+   * @details Name "stopBehavior", Type StopBehavior::Type (Property::INTEGER)
+   * @note Default value is StopBehavior::CURRENT_FRAME.
+   */
+  STOP_BEHAVIOR = ORIENTATION_CORRECTION + 8,
+
+  /**
+   * @brief  The looping mode the AnimatedVectorImageVisual will use.
+   * @details Name "loopingMode", Type LoopingMode::Type (Property::INTEGER)
+   * @note Default value is LoopingMode::RESTART.
+   */
+  LOOPING_MODE = ORIENTATION_CORRECTION + 9,
+
+  /**
+   * @brief The content information the AnimatedVectorImageVisual will use.
+   * @details Name "contentInfo", Type Property::MAP.
+   * The map contains the layer name as a key and Property::Array as a value.
+   * And the array contains 2 integer values which are the frame numbers, the start frame number and the end frame number of the layer.
+   * @note This property is read-only.
+   */
+  CONTENT_INFO = ORIENTATION_CORRECTION + 10
+};
+
+} //namespace Property
+
+/**
+ * @brief Enumeration for what state the animation is in.
+ */
+namespace PlayState
+{
+
+enum Type
+{
+  STOPPED,   ///< Animation has stopped
+  PLAYING,   ///< The animation is playing
+  PAUSED     ///< The animation is paused
+};
+
+} // namespace PlayState
+
+/**
+ * @brief Enumeration for what to do when the animation is stopped.
+ */
+namespace StopBehavior
+{
+
+enum Type
+{
+  CURRENT_FRAME,  ///< When the animation is stopped, the current frame is shown.
+  FIRST_FRAME,    ///< When the animation is stopped, the first frame is shown.
+  LAST_FRAME      ///< When the animation is stopped, the last frame is shown.
+};
+
+} // namespace StopBehavoir
+
+/**
+ * @brief Enumeration for what looping mode is in.
+ */
+namespace LoopingMode
+{
+
+enum Type
+{
+  RESTART,      ///< When the animation arrives at the end in looping mode, the animation restarts from the beginning.
+  AUTO_REVERSE  ///< When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
+};
+
+} // namespace LoopingMode
+
+} // namespace DevelImageVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/text-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/text-visual-properties-devel.h
new file mode 100644 (file)
index 0000000..41f3c89
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_TEXT_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_TEXT_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelTextVisual
+{
+
+namespace Property
+{
+
+/**
+ * @brief All the visual types.
+ */
+enum
+{
+  TEXT                  = Dali::Toolkit::TextVisual::Property::TEXT,
+  FONT_FAMILY           = Dali::Toolkit::TextVisual::Property::FONT_FAMILY,
+  FONT_STYLE            = Dali::Toolkit::TextVisual::Property::FONT_STYLE,
+  POINT_SIZE            = Dali::Toolkit::TextVisual::Property::POINT_SIZE,
+  MULTI_LINE            = Dali::Toolkit::TextVisual::Property::MULTI_LINE,
+  HORIZONTAL_ALIGNMENT  = Dali::Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT,
+  VERTICAL_ALIGNMENT    = Dali::Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT,
+  TEXT_COLOR            = Dali::Toolkit::TextVisual::Property::TEXT_COLOR,
+  ENABLE_MARKUP         = Dali::Toolkit::TextVisual::Property::ENABLE_MARKUP,
+  SHADOW                = Dali::Toolkit::TextVisual::Property::SHADOW,
+  UNDERLINE             = Dali::Toolkit::TextVisual::Property::UNDERLINE,
+
+  /**
+   * @brief The default outline parameters.
+   * @details name "outline", type Property::MAP.
+   */
+  OUTLINE               = UNDERLINE + 1,
+
+  /**
+   * @copydoc Dali::Toolkit::DevelTextLabel::Property::BACKGROUND
+   */
+  BACKGROUND            = UNDERLINE + 2,
+};
+
+
+} // namespace Property
+
+} // namespace DevelTextVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_TEXT_VISUAL_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/devel-api/visuals/visual-properties-devel.h b/dali-toolkit/devel-api/visuals/visual-properties-devel.h
new file mode 100644 (file)
index 0000000..fd83765
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_PROPERTIES_DEVEL_H
+#define DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_PROPERTIES_DEVEL_H
+
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DevelVisual
+{
+
+/**
+ * @brief All the visual types.
+ */
+enum Type
+{
+  BORDER         = Dali::Toolkit::Visual::BORDER,
+  COLOR          = Dali::Toolkit::Visual::COLOR,
+  GRADIENT       = Dali::Toolkit::Visual::GRADIENT,
+  IMAGE          = Dali::Toolkit::Visual::IMAGE,
+  MESH           = Dali::Toolkit::Visual::MESH,
+  PRIMITIVE      = Dali::Toolkit::Visual::PRIMITIVE,
+  WIREFRAME      = Dali::Toolkit::Visual::WIREFRAME,
+  TEXT           = Dali::Toolkit::Visual::TEXT,
+  N_PATCH        = Dali::Toolkit::Visual::N_PATCH,
+  SVG            = Dali::Toolkit::Visual::SVG,
+  ANIMATED_IMAGE = Dali::Toolkit::Visual::ANIMATED_IMAGE,
+
+  ANIMATED_GRADIENT     = ANIMATED_IMAGE + 1,  ///< Renders an animated gradient.
+  ANIMATED_VECTOR_IMAGE = ANIMATED_IMAGE + 2,  ///< Renders an animated vector image.
+  ARC                   = ANIMATED_IMAGE + 3,  ///< Renders an arc.
+};
+
+/**
+ * @brief Visual Properties
+ */
+namespace Property
+{
+enum Type
+{
+  TYPE                = Dali::Toolkit::Visual::Property::TYPE,
+  SHADER              = Dali::Toolkit::Visual::Property::SHADER,
+  TRANSFORM           = Dali::Toolkit::Visual::Property::TRANSFORM,
+  PREMULTIPLIED_ALPHA = Dali::Toolkit::Visual::Property::PREMULTIPLIED_ALPHA,
+  MIX_COLOR           = Dali::Toolkit::Visual::Property::MIX_COLOR,
+  OPACITY             = Dali::Toolkit::Visual::Property::OPACITY,
+
+  /**
+   * @brief The fitting mode of the visual
+   * @details Name "fittingMode", type FittingMode (Property::INTEGER) or Property::STRING.
+   * @see DevelVisual::FittingMode
+   * @note The default is defined by the type of visual (if it's suitable to be stretched or not).
+   */
+  VISUAL_FITTING_MODE = OPACITY + 1,
+
+  /**
+   * @brief The radius for the rounded corners of the visual
+   * @details Name "cornerRadius", type Property::FLOAT.
+   * @note Optional.
+   */
+  CORNER_RADIUS = OPACITY + 2,
+};
+
+} // namespace Property
+
+
+/**
+ * @brief The values of this enum determine how the visual should be fit to the view
+ */
+enum FittingMode
+{
+  FIT_KEEP_ASPECT_RATIO,  ///< The visual should be scaled to fit, preserving aspect ratio
+  FILL,                   ///< The visual should be stretched to fill, not preserving aspect ratio
+};
+
+/**
+ * @brief Devel Visual Transform for the offset or size.
+ */
+namespace Transform
+{
+
+/**
+ * @brief Visual Transform Property.
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the type of Transform Property.
+ */
+enum Type
+{
+  SIZE_POLICY = Dali::Toolkit::Visual::Transform::Property::SIZE_POLICY,
+
+  /**
+   * @brief Extra size value that will be added to the computed visual size.
+   * @details Name "extraSize", type Vector2.
+   *
+   * @note It is an absolute value.
+   *       The property can be used when a user want to set a visual size as a combined value of `relative` and `absolute`.
+   *       For example, when a user want to set a visual size to (ControlSize * 2 + 10),
+   *       The transform map will be,
+   *       transformMap.Add( Transform::Property::SIZE, Vector2( 2.0f, 2.0f ) )
+   *                   .Add( Transform::Property::SIZE_POLICY, Vector2( Transform::Policy::Relative, Transform::Policy::Relative ) )
+   *                   .Add( Transform::Property::EXTRA_SIZE, Vector2( 10.0f, 10.0f ) );
+   */
+  EXTRA_SIZE = SIZE_POLICY + 1,
+};
+
+} // namespace Property
+
+} // namespace Transform
+
+} // namespace DevelVisual
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_VISUALS_VISUAL_PROPERTIES_DEVEL_H
diff --git a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp
new file mode 100644 (file)
index 0000000..7f69861
--- /dev/null
@@ -0,0 +1,1418 @@
+/*
+ * Copyright (c) 2019 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 "accessibility-manager-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/actors/layer.h>
+#include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/sound-player.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/devel-api/events/hit-test-algorithm.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+// Signals
+
+const char* const SIGNAL_FOCUS_CHANGED =           "focusChanged";
+const char* const SIGNAL_FOCUS_OVERSHOT =          "focusOvershot";
+const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focusedActorActivated";
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
+#endif
+
+const char* const ACTOR_FOCUSABLE("focusable");
+const char* const IS_FOCUS_GROUP("isFocusGroup");
+
+const char* FOCUS_BORDER_IMAGE_FILE_NAME = "B16-8_TTS_focus.9.png";
+
+const char* FOCUS_SOUND_FILE_NAME = "Focus.ogg";
+const char* FOCUS_CHAIN_END_SOUND_FILE_NAME = "End_of_List.ogg";
+
+/**
+ * The function to be used in the hit-test algorithm to check whether the actor is hittable.
+ */
+bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
+{
+  bool hittable = false;
+
+  switch (type)
+  {
+    case Dali::HitTestAlgorithm::CHECK_ACTOR:
+    {
+      // Check whether the actor is visible and not fully transparent.
+      if( actor.IsVisible()
+       && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
+      {
+        // Check whether the actor is focusable
+        Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
+        if(propertyActorFocusable != Property::INVALID_INDEX)
+        {
+          hittable = actor.GetProperty<bool>(propertyActorFocusable);
+        }
+      }
+      break;
+    }
+    case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+    {
+      if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
+      {
+        hittable = true;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return hittable;
+};
+
+}
+
+AccessibilityManager::AccessibilityManager()
+: mCurrentFocusActor(FocusIDPair(0, 0)),
+  mCurrentGesturedActor(),
+  mFocusIndicatorActor(),
+  mPreviousPosition( 0.0f, 0.0f ),
+  mRecursiveFocusMoveCounter(0),
+  mFocusSoundFilePath(),
+  mFocusChainEndSoundFilePath(),
+  mIsWrapped(false),
+  mIsFocusWithinGroup(false),
+  mIsEndcapFeedbackEnabled(false),
+  mIsEndcapFeedbackPlayed(false),
+  mIsAccessibilityTtsEnabled(false),
+  mTtsCreated(false),
+  mIsFocusIndicatorEnabled(false),
+  mContinuousPlayMode(false),
+  mIsFocusSoundFilePathSet(false),
+  mIsFocusChainEndSoundFilePathSet(false)
+{
+}
+
+AccessibilityManager::~AccessibilityManager()
+{
+}
+
+void AccessibilityManager::Initialise()
+{
+  AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+  adaptor.SetActionHandler(*this);
+  adaptor.SetGestureHandler(*this);
+
+  ChangeAccessibilityStatus();
+}
+
+AccessibilityManager::ActorAdditionalInfo AccessibilityManager::GetActorAdditionalInfo(const unsigned int actorID) const
+{
+  ActorAdditionalInfo data;
+  IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
+  if(iter != mIDAdditionalInfoContainer.end())
+  {
+    data = (*iter).second;
+  }
+
+  return data;
+}
+
+void AccessibilityManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
+{
+  ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
+  actorInfo.mFocusOrder = order;
+  mIDAdditionalInfoContainer.erase(actorID);
+  mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
+}
+
+void AccessibilityManager::SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text)
+{
+  if(actor)
+  {
+    unsigned int actorID = actor.GetId();
+
+    ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
+    info.mAccessibilityAttributes[type] = text;
+
+    mIDAdditionalInfoContainer.erase(actorID);
+    mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
+  }
+}
+
+std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const
+{
+  std::string text;
+
+  if(actor)
+  {
+    ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
+    text = data.mAccessibilityAttributes[type];
+  }
+
+  return text;
+}
+
+void AccessibilityManager::SetFocusOrder(Actor actor, const unsigned int order)
+{
+  // Do nothing if the focus order of the actor is not changed.
+  if(actor && GetFocusOrder(actor) != order)
+  {
+    // Firstly delete the actor from the focus chain if it's already there with a different focus order.
+    mFocusIDContainer.erase(GetFocusOrder(actor));
+
+    // Create/retrieve actor focusable property
+    Property::Index propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE );
+
+    if(order == 0)
+    {
+      // The actor is not focusable without a defined focus order.
+      actor.SetProperty(propertyActorFocusable, false);
+
+      // If the actor is currently being focused, it should clear the focus
+      if(actor == GetCurrentFocusActor())
+      {
+        ClearFocus();
+      }
+    }
+    else // Insert the actor to the focus chain
+    {
+      // Check whether there is another actor in the focus chain with the same focus order already.
+      FocusIDIter focusIDIter = mFocusIDContainer.find(order);
+      if(focusIDIter != mFocusIDContainer.end())
+      {
+        // We need to increase the focus order of that actor and all the actors followed it
+        // in the focus chain.
+        FocusIDIter lastIter = mFocusIDContainer.end();
+        --lastIter;//We want forward iterator to the last element here
+        mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
+
+        // Update the actor's focus order in its additional data
+        SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
+
+        for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
+        {
+          FocusIDIter previousIter = iter;
+          --previousIter;//We want forward iterator to the previous element here
+          unsigned int actorID = (*previousIter).second;
+          (*iter).second = actorID;
+
+          // Update the actor's focus order in its additional data
+          SynchronizeActorAdditionalInfo(actorID, (*iter).first);
+        }
+
+        mFocusIDContainer.erase(order);
+      }
+
+      // The actor is focusable
+      actor.SetProperty(propertyActorFocusable, true);
+
+      // Now we insert the actor into the focus chain with the specified focus order
+      mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
+    }
+
+    // Update the actor's focus order in its additional data
+    SynchronizeActorAdditionalInfo(actor.GetId(), order);
+  }
+}
+
+unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const
+{
+  unsigned int focusOrder = 0;
+
+  if(actor)
+  {
+    ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
+    focusOrder = data.mFocusOrder;
+  }
+
+  return focusOrder;
+}
+
+unsigned int AccessibilityManager::GenerateNewFocusOrder() const
+{
+  unsigned int order = 1;
+  FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
+
+  if(iter != mFocusIDContainer.rend())
+  {
+    order = (*iter).first + 1;
+  }
+
+  return order;
+}
+
+Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order)
+{
+  Actor actor = Actor();
+
+  FocusIDIter focusIDIter = mFocusIDContainer.find(order);
+  if(focusIDIter != mFocusIDContainer.end())
+  {
+    Actor rootActor = Stage::GetCurrent().GetRootLayer();
+    actor = rootActor.FindChildById(mFocusIDContainer[order]);
+  }
+
+  return actor;
+}
+
+bool AccessibilityManager::SetCurrentFocusActor(Actor actor)
+{
+  if(actor)
+  {
+    return DoSetCurrentFocusActor(actor.GetId());
+  }
+
+  return false;
+}
+
+bool AccessibilityManager::DoSetCurrentFocusActor(const unsigned int actorID)
+{
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+
+  // If the group mode is enabled, check which focus group the current focused actor belongs to
+  Actor focusGroup;
+  if(mIsFocusWithinGroup)
+  {
+    focusGroup = GetFocusGroup(GetCurrentFocusActor());
+  }
+
+  if(!focusGroup)
+  {
+    focusGroup = rootActor;
+  }
+
+  Actor actor = focusGroup.FindChildById(actorID);
+
+  // Check whether the actor is in the stage
+  if(actor)
+  {
+    // Check whether the actor is focusable
+    bool actorFocusable = false;
+    Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
+    if(propertyActorFocusable != Property::INVALID_INDEX)
+    {
+      actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
+    }
+
+    // Go through the actor's hierarchy to check whether the actor is visible
+    bool actorVisible = actor.IsVisible();
+    Actor parent = actor.GetParent();
+    while (actorVisible && parent && parent != rootActor)
+    {
+      actorVisible = parent.IsVisible();
+      parent = parent.GetParent();
+    }
+
+    // Check whether the actor is fully transparent
+    bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
+
+    // Set the focus only when the actor is focusable and visible and not fully transparent
+    if(actorVisible && actorFocusable && actorOpaque)
+    {
+      // Draw the focus indicator upon the focused actor
+      if( mIsFocusIndicatorEnabled )
+      {
+        actor.Add( GetFocusIndicatorActor() );
+      }
+
+      // Send notification for the change of focus actor
+      mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
+
+      // Save the current focused actor
+      mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
+
+      if(mIsAccessibilityTtsEnabled)
+      {
+        Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
+        if(soundPlayer)
+        {
+          if (!mIsFocusSoundFilePathSet)
+          {
+            const std::string soundDirPath = AssetManager::GetDaliSoundPath();
+            mFocusSoundFilePath = soundDirPath + FOCUS_SOUND_FILE_NAME;
+            mIsFocusSoundFilePathSet = true;
+          }
+          soundPlayer.PlaySound(mFocusSoundFilePath);
+        }
+
+        // Play the accessibility attributes with the TTS player.
+        Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
+
+        // Combine attribute texts to one text
+        std::string informationText;
+        for(int i = 0; i < Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
+        {
+          if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
+          {
+            if( i > 0 )
+            {
+              informationText += ", "; // for space time between each information
+            }
+            informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
+          }
+        }
+        player.Play(informationText);
+      }
+
+      return true;
+    }
+  }
+
+  DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
+  return false;
+}
+
+Actor AccessibilityManager::GetCurrentFocusActor()
+{
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+  return rootActor.FindChildById(mCurrentFocusActor.second);
+}
+
+Actor AccessibilityManager::GetCurrentFocusGroup()
+{
+  return GetFocusGroup(GetCurrentFocusActor());
+}
+
+unsigned int AccessibilityManager::GetCurrentFocusOrder()
+{
+  return mCurrentFocusActor.first;
+}
+
+bool AccessibilityManager::MoveFocusForward()
+{
+  bool ret = false;
+  mRecursiveFocusMoveCounter = 0;
+
+  FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
+  if(focusIDIter != mFocusIDContainer.end())
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
+    ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
+  }
+  else
+  {
+    // TODO: if there is not focused actor, move first actor
+    if(!mFocusIDContainer.empty())
+    {
+      //if there is not focused actor, move 1st actor
+      focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
+      DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
+      ret = DoSetCurrentFocusActor((*focusIDIter).second);
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
+
+  return ret;
+}
+
+bool AccessibilityManager::MoveFocusBackward()
+{
+  bool ret = false;
+  mRecursiveFocusMoveCounter = 0;
+
+  FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
+  if(focusIDIter != mFocusIDContainer.end())
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
+    ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
+  }
+  else
+  {
+    // TODO: if there is not focused actor, move last actor
+    if(!mFocusIDContainer.empty())
+    {
+      //if there is not focused actor, move last actor
+      focusIDIter = mFocusIDContainer.end();
+      --focusIDIter;//We want forward iterator to the last element here
+      DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
+      ret = DoSetCurrentFocusActor((*focusIDIter).second);
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
+
+  return ret;
+}
+
+void AccessibilityManager::DoActivate(Actor actor)
+{
+  if(actor)
+  {
+    Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+    if(control)
+    {
+      // Notify the control that it is activated
+      GetImplementation( control ).AccessibilityActivate();
+    }
+
+    // Send notification for the activation of focused actor
+    mFocusedActorActivatedSignal.Emit(actor);
+  }
+}
+
+void AccessibilityManager::ClearFocus()
+{
+  Actor actor = GetCurrentFocusActor();
+  if( actor && mFocusIndicatorActor )
+  {
+    actor.Remove( mFocusIndicatorActor );
+  }
+
+  mCurrentFocusActor = FocusIDPair(0, 0);
+
+  // Send notification for the change of focus actor
+  mFocusChangedSignal.Emit(actor, Actor());
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    // Stop the TTS playing if any
+    Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
+    player.Stop();
+  }
+}
+
+void AccessibilityManager::Reset()
+{
+  ClearFocus();
+  mFocusIDContainer.clear();
+  mIDAdditionalInfoContainer.clear();
+}
+
+void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup)
+{
+  if(actor)
+  {
+    // Create/Set focus group property.
+    actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
+  }
+}
+
+bool AccessibilityManager::IsFocusGroup(Actor actor) const
+{
+  // Check whether the actor is a focus group
+  bool isFocusGroup = false;
+
+  if(actor)
+  {
+    Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
+    if(propertyIsFocusGroup != Property::INVALID_INDEX)
+    {
+      isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
+    }
+  }
+
+  return isFocusGroup;
+}
+
+Actor AccessibilityManager::GetFocusGroup(Actor actor)
+{
+  // Go through the actor's hierarchy to check which focus group the actor belongs to
+  while (actor && !IsFocusGroup(actor))
+  {
+    actor = actor.GetParent();
+  }
+
+  return actor;
+}
+
+Vector2 AccessibilityManager::GetReadPosition() const
+{
+  AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+  return adaptor.GetReadPosition();
+}
+
+void AccessibilityManager::SetGroupMode(bool enabled)
+{
+  mIsFocusWithinGroup = enabled;
+}
+
+bool AccessibilityManager::GetGroupMode() const
+{
+  return mIsFocusWithinGroup;
+}
+
+void AccessibilityManager::SetWrapMode(bool wrapped)
+{
+  mIsWrapped = wrapped;
+}
+
+bool AccessibilityManager::GetWrapMode() const
+{
+  return mIsWrapped;
+}
+
+void AccessibilityManager::SetFocusIndicatorActor(Actor indicator)
+{
+  if( mFocusIndicatorActor != indicator )
+  {
+    Actor currentFocusActor = GetCurrentFocusActor();
+    if( currentFocusActor )
+    {
+      // The new focus indicator should be added to the current focused actor immediately
+      if( mFocusIndicatorActor )
+      {
+        currentFocusActor.Remove( mFocusIndicatorActor );
+      }
+
+      if( indicator )
+      {
+        currentFocusActor.Add( indicator );
+      }
+    }
+
+    mFocusIndicatorActor = indicator;
+  }
+}
+
+Actor AccessibilityManager::GetFocusIndicatorActor()
+{
+  if( ! mFocusIndicatorActor )
+  {
+    // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
+    const std::string imageDirPath = AssetManager::GetDaliImagePath();
+    const std::string focusBorderImagePath = imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME;
+
+    mFocusIndicatorActor = Toolkit::ImageView::New(focusBorderImagePath);
+    mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
+    mFocusIndicatorActor.SetZ( 1.0f );
+
+    // Apply size constraint to the focus indicator
+    mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  }
+
+  return mFocusIndicatorActor;
+}
+
+bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
+  DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
+
+  if( (forward && ++focusIDIter == mFocusIDContainer.end())
+    || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
+  {
+    if(mIsEndcapFeedbackEnabled)
+    {
+      if(mIsEndcapFeedbackPlayed == false)
+      {
+        // play sound & skip moving once
+        Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
+        if(soundPlayer)
+        {
+          if (!mIsFocusChainEndSoundFilePathSet)
+          {
+            const std::string soundDirPath = AssetManager::GetDaliSoundPath();
+            mFocusChainEndSoundFilePath = soundDirPath + FOCUS_CHAIN_END_SOUND_FILE_NAME;
+            mIsFocusChainEndSoundFilePathSet = true;
+          }
+          soundPlayer.PlaySound(mFocusChainEndSoundFilePath);
+        }
+
+        mIsEndcapFeedbackPlayed = true;
+        return true;
+      }
+      mIsEndcapFeedbackPlayed = false;
+    }
+
+    if(wrapped)
+    {
+      if(forward)
+      {
+        focusIDIter = mFocusIDContainer.begin();
+      }
+      else
+      {
+        focusIDIter = mFocusIDContainer.end();
+        --focusIDIter;//We want forward iterator to the last element here
+      }
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
+      // Send notification for handling overshooted situation
+      mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS);
+
+      return false; // Try to move the focus out of the scope
+    }
+  }
+
+  // Invalid focus.
+  if( focusIDIter == mFocusIDContainer.end() )
+  {
+    return false;
+  }
+
+  // Note: This function performs the focus change.
+  if( !DoSetCurrentFocusActor( (*focusIDIter).second ) )
+  {
+    mRecursiveFocusMoveCounter++;
+    if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
+    {
+      // We've attempted to focus all the actors in the whole focus chain and no actor
+      // can be focused successfully.
+      DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
+
+      return false;
+    }
+    else
+    {
+      return DoMoveFocus(focusIDIter, forward, wrapped);
+    }
+  }
+
+  return true;
+}
+
+void AccessibilityManager::SetFocusable(Actor actor, bool focusable)
+{
+  if(actor)
+  {
+    // Create/Set actor focusable property.
+    actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
+  }
+}
+
+bool AccessibilityManager::ChangeAccessibilityStatus()
+{
+  AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+  mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
+  Dali::Toolkit::AccessibilityManager handle( this );
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    // Show indicator when tts turned on if there is focused actor.
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      actor.Add( GetFocusIndicatorActor() );
+    }
+    mIsFocusIndicatorEnabled = true;
+
+    // Connect a signal to the TTS player to implement continuous reading mode.
+    Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
+    player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
+    mTtsCreated = true;
+  }
+  else
+  {
+    // Hide indicator when tts turned off
+    Actor actor = GetCurrentFocusActor();
+    if( actor && mFocusIndicatorActor )
+    {
+      actor.Remove( mFocusIndicatorActor );
+    }
+    mIsFocusIndicatorEnabled = false;
+
+    if( mTtsCreated )
+    {
+      // Disconnect the TTS state change signal.
+      Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
+      player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
+      mTtsCreated = true;
+    }
+  }
+
+  mStatusChangedSignal.Emit( handle );
+
+  return true;
+}
+
+bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionNextSignal.Empty() )
+  {
+    mActionNextSignal.Emit( handle );
+  }
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
+    return MoveFocusForward();
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionPreviousSignal.Empty() )
+  {
+    mActionPreviousSignal.Emit( handle );
+  }
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    mIsEndcapFeedbackEnabled = allowEndFeedback;
+    return MoveFocusBackward();
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionActivate()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionActivateSignal.Empty() )
+  {
+    mActionActivateSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  Actor actor = GetCurrentFocusActor();
+  if(actor)
+  {
+    DoActivate(actor);
+    ret = true;
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+
+  if( allowReadAgain )
+  {
+    if ( !mActionReadSignal.Empty() )
+    {
+      mActionReadSignal.Emit( handle );
+    }
+  }
+  else
+  {
+    if ( !mActionOverSignal.Empty() )
+    {
+      mActionOverSignal.Emit( handle );
+    }
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    // Find the focusable actor at the read position
+    AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+    Dali::HitTestAlgorithm::Results results;
+    Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
+
+    FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
+    if(focusIDIter != mFocusIDContainer.end())
+    {
+      if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
+      {
+        // Move the focus to the actor
+        ret = SetCurrentFocusActor(results.actor);
+        DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionReadNextSignal.Empty() )
+  {
+    mActionReadNextSignal.Emit( handle );
+  }
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    return MoveFocusForward();
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionReadPreviousSignal.Empty() )
+  {
+    mActionReadPreviousSignal.Emit( handle );
+  }
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    return MoveFocusBackward();
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionUp()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionUpSignal.Empty() )
+  {
+    mActionUpSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // Notify the control that it is activated
+        ret = GetImplementation( control ).OnAccessibilityValueChange(true);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionDown()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionDownSignal.Empty() )
+  {
+    mActionDownSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // Notify the control that it is activated
+        ret = GetImplementation( control ).OnAccessibilityValueChange(false);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::ClearAccessibilityFocus()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionClearFocusSignal.Empty() )
+  {
+    mActionClearFocusSignal.Emit( handle );
+  }
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    ClearFocus();
+    return true;
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touchEvent )
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionScrollSignal.Empty() )
+  {
+    mActionScrollSignal.Emit( handle, touchEvent );
+  }
+
+  return true;
+}
+
+bool AccessibilityManager::AccessibilityActionBack()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionBackSignal.Empty() )
+  {
+    mActionBackSignal.Emit( handle );
+  }
+
+  // TODO: Back to previous view
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+bool AccessibilityManager::AccessibilityActionScrollUp()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionScrollUpSignal.Empty() )
+  {
+    mActionScrollUpSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll up. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionScrollDown()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionScrollDownSignal.Empty() )
+  {
+    mActionScrollDownSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll down. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionPageLeft()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionPageLeftSignal.Empty() )
+  {
+    mActionPageLeftSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll left to the previous page. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionPageRight()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionPageRightSignal.Empty() )
+  {
+    mActionPageRightSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll right to the next page. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionPageUp()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionPageUpSignal.Empty() )
+  {
+    mActionPageUpSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll up to the previous page. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionPageDown()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionPageDownSignal.Empty() )
+  {
+    mActionPageDownSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // TODO: Notify the control to scroll down to the next page. Should control handle this?
+//        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionMoveToFirst()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionMoveToFirstSignal.Empty() )
+  {
+    mActionMoveToFirstSignal.Emit( handle );
+  }
+
+  // TODO: Move to the first item on screen
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+bool AccessibilityManager::AccessibilityActionMoveToLast()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionMoveToLastSignal.Empty() )
+  {
+    mActionMoveToLastSignal.Emit( handle );
+  }
+
+  // TODO: Move to the last item on screen
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+bool AccessibilityManager::AccessibilityActionReadFromTop()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionReadFromTopSignal.Empty() )
+  {
+    mActionReadFromTopSignal.Emit( handle );
+  }
+
+  // TODO: Move to the top item on screen and read from the item continuously
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+bool AccessibilityManager::AccessibilityActionReadFromNext()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+
+  if( !mActionReadFromNextSignal.Empty() )
+  {
+    mActionReadFromNextSignal.Emit( handle );
+  }
+
+  if( mIsAccessibilityTtsEnabled )
+  {
+    // Mark that we are in continuous play mode, so TTS signals can move focus.
+    mContinuousPlayMode = true;
+
+    // Attempt to move to the next item and read from the item continuously.
+    MoveFocusForward();
+  }
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
+{
+  if( mContinuousPlayMode )
+  {
+    // If we were playing and now we have stopped, attempt to play the next item.
+    if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
+    {
+      // Attempt to move the focus forward and play.
+      // If we can't cancel continuous play mode.
+      if( !MoveFocusForward() )
+      {
+        // We are done, exit continuous play mode.
+        mContinuousPlayMode = false;
+      }
+    }
+    else
+    {
+      // Unexpected play state change, exit continuous play mode.
+      mContinuousPlayMode = false;
+    }
+  }
+}
+
+bool AccessibilityManager::AccessibilityActionZoom()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionZoomSignal.Empty() )
+  {
+    mActionZoomSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if(actor)
+    {
+      Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+      if(control)
+      {
+        // Notify the control to zoom
+        ret = GetImplementation( control ).OnAccessibilityZoom();
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionReadPauseResume()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionReadPauseResumeSignal.Empty() )
+  {
+    mActionReadPauseResumeSignal.Emit( handle );
+  }
+
+  bool ret = false;
+
+  if(mIsAccessibilityTtsEnabled)
+  {
+    // Pause or resume the TTS player
+    Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
+    Dali::TtsPlayer::State state = player.GetState();
+    if(state == Dali::TtsPlayer::PLAYING)
+    {
+      player.Pause();
+      ret = true;
+    }
+    else if(state == Dali::TtsPlayer::PAUSED)
+    {
+      player.Resume();
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityManager::AccessibilityActionStartStop()
+{
+  Dali::Toolkit::AccessibilityManager handle( this );
+  if( !mActionStartStopSignal.Empty() )
+  {
+    mActionStartStopSignal.Emit( handle );
+  }
+
+  // TODO: Start/stop the current action
+
+  return mIsAccessibilityTtsEnabled;
+}
+
+bool AccessibilityManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
+{
+  bool handled = false;
+
+  // TODO: Need to convert the touchevent for the focused actor?
+
+  Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
+  if(control)
+  {
+    handled = GetImplementation( control ).OnAccessibilityTouch(touchEvent);
+  }
+
+  return handled;
+}
+
+bool AccessibilityManager::HandlePanGesture(const AccessibilityGestureEvent& panEvent)
+{
+  bool handled = false;
+
+  if( panEvent.state == AccessibilityGestureEvent::Started )
+  {
+    // Find the focusable actor at the event position
+    Dali::HitTestAlgorithm::Results results;
+    AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+
+    Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
+    mCurrentGesturedActor = results.actor;
+
+    if(!mCurrentGesturedActor)
+    {
+      DALI_LOG_ERROR("Gesture detected, but no hit actor\n");
+    }
+  }
+
+  // Gesture::Finished (Up) events are delivered with previous (Motion) event position
+  // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
+  if ( AccessibilityGestureEvent::Finished != panEvent.state )
+  {
+    // Store the previous position for next Gesture::Finished iteration.
+    mPreviousPosition = panEvent.previousPosition;
+  }
+
+  Actor rootActor = Stage::GetCurrent().GetRootLayer();
+
+  Dali::PanGesture pan( static_cast<Dali::Gesture::State>(panEvent.state) );
+
+  pan.time = panEvent.time;
+  pan.numberOfTouches = panEvent.numberOfTouches;
+  pan.screenPosition = panEvent.currentPosition;
+  pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
+  pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
+  pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
+
+  // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
+  while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
+  {
+    Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
+    if(control)
+    {
+      Vector2 localCurrent;
+      control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
+      pan.position = localCurrent;
+
+      Vector2 localPrevious;
+      control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
+
+      pan.displacement = localCurrent - localPrevious;
+      pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
+      pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
+
+      handled = GetImplementation( control ).OnAccessibilityPan(pan);
+    }
+
+    // If the gesture is not handled by the control, check its parent
+    if(!handled)
+    {
+      mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
+
+      if(!mCurrentGesturedActor)
+      {
+        DALI_LOG_ERROR("no more gestured actor\n");
+      }
+    }
+    else
+    {
+      // If handled, then update the pan gesture properties
+      PanGestureDetector::SetPanGestureProperties( pan );
+    }
+  }
+
+  return handled;
+}
+
+Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
+{
+  return mFocusChangedSignal;
+}
+
+Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
+{
+  return mFocusOvershotSignal;
+}
+
+Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
+{
+  return mFocusedActorActivatedSignal;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h
new file mode 100644 (file)
index 0000000..5c518fd
--- /dev/null
@@ -0,0 +1,772 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ACCESSIBILITY_MANAGER_H
+#define DALI_TOOLKIT_INTERNAL_ACCESSIBILITY_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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/common/map-wrapper.h>
+#include <dali/devel-api/adaptor-framework/accessibility-action-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
+#include <dali/public-api/adaptor-framework/tts-player.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AccessibilityManager;
+
+/**
+ * @copydoc Toolkit::AccessibilityManager
+ */
+class AccessibilityManager : public Dali::BaseObject, Dali::AccessibilityActionHandler, Dali::AccessibilityGestureHandler, public Dali::ConnectionTracker
+{
+public:
+
+  typedef Dali::Toolkit::AccessibilityManager::AccessibilityActionSignalType       AccessibilityActionSignalType;
+  typedef Dali::Toolkit::AccessibilityManager::AccessibilityActionScrollSignalType AccessibilityActionScrollSignalType;
+
+  struct ActorAdditionalInfo
+  {
+    ActorAdditionalInfo()
+    : mFocusOrder(0)
+    {
+    }
+
+    unsigned int mFocusOrder; ///< The focus order of the actor. It is undefined by default.
+
+    std::string mAccessibilityAttributes[Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM]; ///< The array of attribute texts
+  };
+
+  typedef std::pair<unsigned int, unsigned int>        FocusIDPair;
+  typedef std::map<unsigned int, unsigned int>         FocusIDContainer;
+  typedef FocusIDContainer::iterator                   FocusIDIter;
+  typedef FocusIDContainer::const_iterator             FocusIDConstIter;
+
+  typedef std::pair<unsigned int, ActorAdditionalInfo> IDAdditionalInfoPair;
+  typedef std::map<unsigned int, ActorAdditionalInfo>  IDAdditionalInfoContainer;
+  typedef IDAdditionalInfoContainer::iterator          IDAdditionalInfoIter;
+  typedef IDAdditionalInfoContainer::const_iterator    IDAdditionalInfoConstIter;
+
+  /**
+   * Construct a new AccessibilityManager.
+   */
+  AccessibilityManager();
+
+  /**
+   * Initialise the AccessibilityManager
+   */
+  void Initialise();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetAccessibilityAttribute
+   */
+  void SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetAccessibilityAttribute
+   */
+  std::string GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetFocusOrder
+   */
+  void SetFocusOrder(Actor actor, const unsigned int order);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetFocusOrder
+   */
+  unsigned int GetFocusOrder(Actor actor) const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GenerateNewFocusOrder
+   */
+  unsigned int GenerateNewFocusOrder() const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetActorByFocusOrder
+   */
+  Actor GetActorByFocusOrder(const unsigned int order);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetCurrentFocusActor
+   */
+  bool SetCurrentFocusActor(Actor actor);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetCurrentFocusActor
+   */
+  Actor GetCurrentFocusActor();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetCurrentFocusGroup
+   */
+  Actor GetCurrentFocusGroup();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetCurrentFocusOrder
+   */
+  unsigned int GetCurrentFocusOrder();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::MoveFocusForward
+   */
+  bool MoveFocusForward();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::MoveFocusBackward
+   */
+  bool MoveFocusBackward();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::ClearFocus
+   */
+  void ClearFocus();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::Reset
+   */
+  void Reset();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetFocusGroup
+   */
+  void SetFocusGroup(Actor actor, bool isFocusGroup);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::IsFocusGroup
+   */
+  bool IsFocusGroup(Actor actor) const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetGroupMode
+   */
+  void SetGroupMode(bool enabled);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetGroupMode
+   */
+  bool GetGroupMode() const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetWrapMode
+   */
+  void SetWrapMode(bool wrapped);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetWrapMode
+   */
+  bool GetWrapMode() const;
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::SetFocusIndicatorActor
+   */
+  void SetFocusIndicatorActor(Actor indicator);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetFocusIndicatorActor
+   */
+  Actor GetFocusIndicatorActor();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetFocusGroup
+   */
+  Actor GetFocusGroup(Actor actor);
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::GetReadPosition
+   */
+  Vector2 GetReadPosition() const;
+
+public:
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::FocusChangedSignal()
+   */
+  Toolkit::AccessibilityManager::FocusChangedSignalType& FocusChangedSignal();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::FocusOvershotSignal()
+   */
+  Toolkit::AccessibilityManager::FocusOvershotSignalType& FocusOvershotSignal();
+
+  /**
+   * @copydoc Toolkit::AccessibilityManager::FocusedActorActivatedSignal()
+   */
+  Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& FocusedActorActivatedSignal();
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::StatusChangedSignal
+   */
+  AccessibilityActionSignalType& StatusChangedSignal()
+  {
+    return mStatusChangedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::AccessibilityAdaptor::ActionNextSignal
+   */
+  AccessibilityActionSignalType& ActionNextSignal()
+  {
+    return mActionNextSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionPreviousSignal
+   */
+  AccessibilityActionSignalType& ActionPreviousSignal()
+  {
+    return mActionPreviousSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionActivateSignal
+   */
+  AccessibilityActionSignalType& ActionActivateSignal()
+  {
+    return mActionActivateSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionOverSignal
+   */
+  AccessibilityActionSignalType& ActionOverSignal()
+  {
+    return mActionOverSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadSignal
+   */
+  AccessibilityActionSignalType& ActionReadSignal()
+  {
+    return mActionReadSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadNextSignal
+   */
+  AccessibilityActionSignalType& ActionReadNextSignal()
+  {
+    return mActionReadNextSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadPreviousSignal
+   */
+  AccessibilityActionSignalType& ActionReadPreviousSignal()
+  {
+    return mActionReadPreviousSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionUpSignal
+   */
+  AccessibilityActionSignalType& ActionUpSignal()
+  {
+    return mActionUpSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionDownSignal
+   */
+  AccessibilityActionSignalType& ActionDownSignal()
+  {
+    return mActionDownSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionClearFocusSignal
+   */
+  AccessibilityActionSignalType& ActionClearFocusSignal()
+  {
+    return mActionClearFocusSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionBackSignal
+   */
+  AccessibilityActionSignalType& ActionBackSignal()
+  {
+    return mActionBackSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionScrollUpSignal
+   */
+  AccessibilityActionSignalType& ActionScrollUpSignal()
+  {
+    return mActionScrollUpSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionScrollDownSignal
+   */
+  AccessibilityActionSignalType& ActionScrollDownSignal()
+  {
+    return mActionScrollDownSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionPageLeftSignal
+   */
+  AccessibilityActionSignalType& ActionPageLeftSignal()
+  {
+    return mActionPageLeftSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionPageRightSignal
+   */
+  AccessibilityActionSignalType& ActionPageRightSignal()
+  {
+    return mActionPageRightSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionPageUpSignal
+   */
+  AccessibilityActionSignalType& ActionPageUpSignal()
+  {
+    return mActionPageUpSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionPageDownSignal
+   */
+  AccessibilityActionSignalType& ActionPageDownSignal()
+  {
+    return mActionPageDownSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionMoveToFirstSignal
+   */
+  AccessibilityActionSignalType& ActionMoveToFirstSignal()
+  {
+    return mActionMoveToFirstSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionMoveToLastSignal
+   */
+  AccessibilityActionSignalType& ActionMoveToLastSignal()
+  {
+    return mActionMoveToLastSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadFromTopSignal
+   */
+  AccessibilityActionSignalType& ActionReadFromTopSignal()
+  {
+    return mActionReadFromTopSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadFromNextSignal
+   */
+  AccessibilityActionSignalType& ActionReadFromNextSignal()
+  {
+    return mActionReadFromNextSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionZoomSignal
+   */
+  AccessibilityActionSignalType& ActionZoomSignal()
+  {
+    return mActionZoomSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadIndicatorInformationSignal
+   */
+  AccessibilityActionSignalType& ActionReadIndicatorInformationSignal()
+  {
+    return mActionReadIndicatorInformationSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionReadPauseResumeSignal
+   */
+  AccessibilityActionSignalType& ActionReadPauseResumeSignal()
+  {
+    return mActionReadPauseResumeSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionStartStopSignal
+   */
+  AccessibilityActionSignalType& ActionStartStopSignal()
+  {
+    return mActionStartStopSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::AccessibilityManager::ActionScrollSignal
+   */
+  AccessibilityActionScrollSignalType& ActionScrollSignal()
+  {
+    return mActionScrollSignal;
+  }
+
+protected:
+
+  /**
+   * Destructor
+   */
+  virtual ~AccessibilityManager();
+
+private:
+
+  /**
+   * Get the additional information (e.g. focus order and description) of the given actor.
+   * @param actorID The ID of the actor to be queried
+   * @return The additional information of the actor
+   */
+  ActorAdditionalInfo GetActorAdditionalInfo(const unsigned int actorID) const;
+
+  /**
+   * Synchronize the actor's additional information to reflect its latest focus order
+   * @param actorID The ID of the actor
+   * @param order The focus order of the actor
+   * @return The additional information of the actor
+   */
+  void SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order);
+
+  /**
+   * Move the focus to the specified actor and send notification for the focus change.
+   * @param actorID The ID of the actor to be queried
+   * @return Whether the focus is successful or not
+   */
+  bool DoSetCurrentFocusActor(const unsigned int actorID);
+
+  /**
+   * Move the focus to the next actor in the focus chain towards the specified direction.
+   * @param focusIDIter The iterator pointing to the current focused actor
+   * @param forward Whether the focus movement is forward or not. The focus movement will be backward if this is false.
+   * @param wrapped Whether the focus shoule be moved wrapped around or not
+   * @return Whether the focus is successful or not
+   */
+  bool DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped);
+
+  /**
+   * Activate the actor. If the actor is control, call OnAccessibilityActivated virtual function.
+   * This function will emit FocusedActorActivatedSignal.
+   * @param actor The actor to activate
+   */
+  void DoActivate(Actor actor);
+
+  /**
+   * Set whether the actor is focusable or not. A focusable property will be registered for
+   * the actor if not yet.
+   * @param actor The actor to be focused
+   * @param focusable Whether the actor is focusable or not
+   */
+  void SetFocusable(Actor actor, bool focusable);
+
+  /**
+   * Handle the accessibility pan gesture.
+   * @param[in]  panEvent  The pan event to be handled.
+   * @return whether the gesture is handled successfully or not.
+   */
+  virtual bool HandlePanGesture(const AccessibilityGestureEvent& panEvent);
+
+  /**
+   * Change the accessibility status when Accessibility feature(screen-reader) turned on or off.
+   * @return whether the status is changed or not.
+   */
+  virtual bool ChangeAccessibilityStatus();
+
+  /**
+   * Clear the accessibility focus from the current focused actor.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool ClearAccessibilityFocus();
+
+  /**
+   * Perform the accessibility action associated with a scroll event.
+   * @param touchEvent The touch point (and time) of the event.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool AccessibilityActionScroll( Dali::TouchEvent& touchEvent );
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick up).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPrevious(bool allowEndFeedback);
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick down).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionNext(bool allowEndFeedback);
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick left).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPrevious(bool allowEndFeedback);
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick right).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadNext(bool allowEndFeedback);
+
+  /**
+   * Perform the accessibility action to focus and read the actor (by one finger tap or move).
+   * @param allowReadAgain true if the action read again the same object (i.e. read action)
+   *                       false if the action just read when the focus object is changed (i.e. over action)
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionRead(bool allowReadAgain);
+
+  /**
+   * Perform the accessibility action to activate the current focused actor (by one finger double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionActivate();
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move up and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionUp();
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move down and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionDown();
+
+  /**
+   * Perform the accessibility action to navigate back (by two fingers circle draw).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionBack();
+
+  /**
+   * Perform the accessibility action to scroll up the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollUp();
+
+  /**
+   * Perform the accessibility action to scroll down the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollDown();
+
+  /**
+   * Perform the accessibility action to scroll left to the previous page (by two finger swipe left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageLeft();
+
+  /**
+   * Perform the accessibility action to scroll right to the next page (by two finger swipe right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageRight();
+
+  /**
+   * Perform the accessibility action to scroll up to the previous page (by one finger swipe left and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageUp();
+
+  /**
+   * Perform the accessibility action to scroll down to the next page (by one finger swipe right and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageDown();
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the screen
+   * (by one finger swipe up and down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToFirst();
+
+  /**
+   * Perform the accessibility action to move the focus to the last item on the screen
+   * (by one finger swipe down and up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToLast();
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the top
+   * and read from the top item continuously (by three fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromTop();
+
+  /**
+   * Perform the accessibility action to move the focus to and read from the next item
+   * continuously (by three fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromNext();
+
+  /**
+   * Perform the accessibility action to move the focus to do the zooming (by one finger triple tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionZoom();
+
+  /**
+   * Perform the accessibility action to pause/resume the current read out (by two fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPauseResume();
+
+  /**
+   * Perform the accessibility action to start/stop the current action (by two fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionStartStop();
+
+  /**
+   * Perform the accessibility action to mouse move (by one finger tap & hold and move).
+   * @param touchEvent touch event structure
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionTouch(const TouchEvent& touchEvent);
+
+  /**
+   * This function is connected to the TtsPlayer StateChangeSignal.
+   * It is called when the TTS players state changes.
+   * @param previousState The previous state of the TTS player (for comparison)
+   * @param currentState  The current state of the TTS player
+   */
+  void TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState );
+
+private:
+
+  // Undefined
+  AccessibilityManager(const AccessibilityManager&);
+
+  AccessibilityManager& operator=(const AccessibilityManager& rhs);
+
+private:
+
+  Toolkit::AccessibilityManager::FocusChangedSignalType mFocusChangedSignal; ///< The signal to notify the focus change
+  Toolkit::AccessibilityManager::FocusOvershotSignalType mFocusOvershotSignal; ///< The signal to notify the focus overshooted
+  Toolkit::AccessibilityManager::FocusedActorActivatedSignalType mFocusedActorActivatedSignal; ///< The signal to notify the activation of focused actor
+
+  // Action signals.
+  AccessibilityActionSignalType       mStatusChangedSignal;
+  AccessibilityActionSignalType       mActionNextSignal;
+  AccessibilityActionSignalType       mActionPreviousSignal;
+  AccessibilityActionSignalType       mActionActivateSignal;
+  AccessibilityActionSignalType       mActionOverSignal;
+  AccessibilityActionSignalType       mActionReadSignal;
+  AccessibilityActionSignalType       mActionReadNextSignal;
+  AccessibilityActionSignalType       mActionReadPreviousSignal;
+  AccessibilityActionSignalType       mActionUpSignal;
+  AccessibilityActionSignalType       mActionDownSignal;
+  AccessibilityActionSignalType       mActionClearFocusSignal;
+  AccessibilityActionSignalType       mActionBackSignal;
+  AccessibilityActionSignalType       mActionScrollUpSignal;
+  AccessibilityActionSignalType       mActionScrollDownSignal;
+  AccessibilityActionSignalType       mActionPageLeftSignal;
+  AccessibilityActionSignalType       mActionPageRightSignal;
+  AccessibilityActionSignalType       mActionPageUpSignal;
+  AccessibilityActionSignalType       mActionPageDownSignal;
+  AccessibilityActionSignalType       mActionMoveToFirstSignal;
+  AccessibilityActionSignalType       mActionMoveToLastSignal;
+  AccessibilityActionSignalType       mActionReadFromTopSignal;
+  AccessibilityActionSignalType       mActionReadFromNextSignal;
+  AccessibilityActionSignalType       mActionZoomSignal;
+  AccessibilityActionSignalType       mActionReadIndicatorInformationSignal;
+  AccessibilityActionSignalType       mActionReadPauseResumeSignal;
+  AccessibilityActionSignalType       mActionStartStopSignal;
+  AccessibilityActionScrollSignalType mActionScrollSignal;
+
+  FocusIDContainer mFocusIDContainer;       ///< The container to look up actor ID by focus order
+  IDAdditionalInfoContainer mIDAdditionalInfoContainer; ///< The container to look up additional information by actor ID
+  FocusIDPair mCurrentFocusActor;           ///< The focus order and actor ID of current focused actor
+  Actor mCurrentGesturedActor;              ///< The actor that will handle the gesture
+  Actor mFocusIndicatorActor;               ///< The focus indicator actor shared by all the focusable actors for highlight
+  Vector2 mPreviousPosition;                ///< The previous pan position; useful for calculating velocity for Gesture::Finished events
+  unsigned int mRecursiveFocusMoveCounter;  ///< The counter to count the number of recursive focus movement attempted before the focus movement is successful.
+  std::string mFocusSoundFilePath;          ///< The path of the focus sound file
+  std::string mFocusChainEndSoundFilePath;  ///< The path of the focus chain end sound file
+
+  bool mIsWrapped:1;                        ///< Whether the focus movement is wrapped around or not
+  bool mIsFocusWithinGroup:1;               ///< Whether the focus movement is limited to the current focus group or not
+  bool mIsEndcapFeedbackEnabled:1;          ///< Whether the endcap feedback need to be played when the focus leaves the end or vice versa
+  bool mIsEndcapFeedbackPlayed:1;           ///< Whether the endcap feedback was played or not
+  bool mIsAccessibilityTtsEnabled:1;        ///< Whether accessibility feature(screen-reader) turned on/off
+  bool mTtsCreated:1;                       ///< Whether the TTS Player has been accessed
+  bool mIsFocusIndicatorEnabled:1;          ///< Whether indicator should be shown / hidden. It could be enabled when TTS enabled or 'Tab' key operated.
+  bool mContinuousPlayMode:1;               ///< Keeps track of whether or not we are in continuous play mode
+  bool mIsFocusSoundFilePathSet:1;          ///< Whether the path of the focus sound file has been set
+  bool mIsFocusChainEndSoundFilePathSet:1;  ///< Whether the path of the focus chain end sound file has been set
+
+};
+
+} // namespace Internal
+
+inline Internal::AccessibilityManager& GetImpl(Dali::Toolkit::AccessibilityManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::AccessibilityManager&>(handle);
+}
+
+inline const Internal::AccessibilityManager& GetImpl(const Dali::Toolkit::AccessibilityManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::AccessibilityManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_ACCESSIBILITY_MANAGER_H
diff --git a/dali-toolkit/internal/builder/builder-animations.cpp b/dali-toolkit/internal/builder/builder-animations.cpp
new file mode 100644 (file)
index 0000000..dce9b61
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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 <dali/public-api/actors/layer.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <dali-toolkit/internal/builder/replacement.h>
+
+namespace // unnamed namespace
+{
+
+using namespace Dali;
+
+TimePeriod GetTimePeriod( const TreeNode& child, const Toolkit::Internal::Replacement& constant )
+{
+  OptionalFloat delay      = constant.IsFloat( IsChild(child, "delay" ) );
+  OptionalFloat duration   = constant.IsFloat( IsChild(child, "duration" ) );
+  DALI_ASSERT_ALWAYS( duration && "Time period must have at least a duration" );
+
+  if( delay )
+  {
+    return TimePeriod( *delay, *duration );
+  }
+  else
+  {
+    return TimePeriod( *duration );
+  }
+}
+
+Property::Value GetPropertyValue( const Property::Type& propType, const TreeNode& child )
+{
+  switch ( propType )
+  {
+    case Property::BOOLEAN:
+    {
+      return Property::Value( GetBoolean( child ) );
+    }
+
+    case Property::FLOAT:
+    {
+      return Property::Value( GetFloat( child ) );
+    }
+
+    case Property::VECTOR2:
+    {
+      return Property::Value( GetVector2( child ) );
+    }
+
+    case Property::VECTOR3:
+    {
+      return Property::Value( GetVector3( child ) );
+    }
+
+    case Property::VECTOR4:
+    {
+      return Property::Value( GetVector4( child ) );
+    }
+
+    case Property::ROTATION:
+    {
+      if( 4 == child.Size() )
+      {
+        Vector4 v(GetVector4(child));
+        // angle, axis as per spec
+        return Property::Value( Quaternion(Radian(Degree(v[3])),
+                                           Vector3(v[0],v[1],v[2])) );
+      }
+      else
+      {
+        // degrees as per spec
+        Vector3 rotation = GetVector3( child );
+        return Property::Value( Quaternion(Radian(Degree(rotation.x)),
+                                           Radian(Degree(rotation.y)),
+                                           Radian(Degree(rotation.z))) );
+      }
+    }
+
+    case Property::NONE: // fall
+    default:
+    {
+      DALI_ASSERT_ALWAYS( !"Property type incorrect" );
+    }
+  }
+}
+
+AlphaFunction GetAlphaFunction( const std::string& alphaFunction )
+{
+  typedef std::map< const std::string, Dali::AlphaFunction > AlphaFunctionLut;
+  static AlphaFunctionLut alphaFunctionLut;
+
+  if( 0 == alphaFunctionLut.size() )
+  {
+    // coding convention is uppercase enums
+    alphaFunctionLut["DEFAULT"]                    = AlphaFunction(AlphaFunction::DEFAULT);
+    alphaFunctionLut["LINEAR"]                     = AlphaFunction(AlphaFunction::LINEAR);
+    alphaFunctionLut["REVERSE"]                    = AlphaFunction(AlphaFunction::REVERSE);
+    alphaFunctionLut["EASE_IN_SQUARE"]             = AlphaFunction(AlphaFunction::EASE_IN_SQUARE);
+    alphaFunctionLut["EASE_OUT_SQUARE"]            = AlphaFunction(AlphaFunction::EASE_OUT_SQUARE);
+    alphaFunctionLut["EASE_IN"]                    = AlphaFunction(AlphaFunction::EASE_IN);
+    alphaFunctionLut["EASE_OUT"]                   = AlphaFunction(AlphaFunction::EASE_OUT);
+    alphaFunctionLut["EASE_IN_OUT"]                = AlphaFunction(AlphaFunction::EASE_IN_OUT);
+    alphaFunctionLut["EASE_IN_SINE"]               = AlphaFunction(AlphaFunction::EASE_IN_SINE);
+    alphaFunctionLut["EASE_OUT_SINE"]              = AlphaFunction(AlphaFunction::EASE_OUT_SINE);
+    alphaFunctionLut["EASE_IN_OUT_SINE"]           = AlphaFunction(AlphaFunction::EASE_IN_OUT_SINE);
+    alphaFunctionLut["BOUNCE"]                     = AlphaFunction(AlphaFunction::BOUNCE);
+    alphaFunctionLut["SIN"]                        = AlphaFunction(AlphaFunction::SIN);
+    alphaFunctionLut["EASE_OUT_BACK"]              = AlphaFunction(AlphaFunction::EASE_OUT_BACK);
+  }
+
+  const AlphaFunctionLut::const_iterator iter( alphaFunctionLut.find( alphaFunction ) );
+
+  if( iter != alphaFunctionLut.end() )
+  {
+    return iter->second;
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( iter != alphaFunctionLut.end() && "Unknown Alpha Constant" );
+    return Dali::AlphaFunction::DEFAULT;
+  }
+}
+
+} // unnamed namespace
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+Animation CreateAnimation( const TreeNode& child, const Replacement& constant, Dali::Actor searchRoot, Builder* const builder )
+{
+  float durationSum = 0.f;
+
+  Dali::Actor searchActor = searchRoot ? searchRoot : Dali::Stage::GetCurrent().GetRootLayer();
+
+  Animation animation( Animation::New( 0.f ) );
+
+  // duration needs to be set before AnimateTo calls for correct operation when AnimateTo has no "timePeriod".
+  OptionalFloat duration = constant.IsFloat( IsChild(child, "duration" ) );
+
+  if( duration )
+  {
+    animation.SetDuration( *duration );
+  }
+
+  if( OptionalBoolean looping = constant.IsBoolean(  IsChild(child, "loop" ) ) )
+  {
+    animation.SetLooping( *looping );
+  }
+
+  if( OptionalString endAction = constant.IsString(  IsChild(child, "endAction" ) ) )
+  {
+    if("BAKE" == *endAction)
+    {
+      animation.SetEndAction( Animation::Bake );
+    }
+    else if("DISCARD" == *endAction)
+    {
+      animation.SetEndAction( Animation::Discard );
+    }
+    else if("BAKE_FINAL" == *endAction)
+    {
+      animation.SetEndAction( Animation::BakeFinal );
+    }
+  }
+
+  if( OptionalString endAction = constant.IsString(  IsChild(child, "disconnectAction" ) ) )
+  {
+    if("BAKE" == *endAction)
+    {
+      animation.SetDisconnectAction( Animation::Bake );
+    }
+    else if("DISCARD" == *endAction)
+    {
+      animation.SetDisconnectAction( Animation::Discard );
+    }
+    else if("BAKE_FINAL" == *endAction)
+    {
+      animation.SetDisconnectAction( Animation::BakeFinal );
+    }
+  }
+
+  OptionalChild propertiesNode = IsChild(child, "properties" );
+  if(propertiesNode)
+  {
+    const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
+    for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
+    {
+      const TreeNode::KeyNodePair& pKeyChild = *iter;
+
+      OptionalString actorName( constant.IsString( IsChild(pKeyChild.second, "actor" ) ) );
+      OptionalString property(  constant.IsString( IsChild(pKeyChild.second, "property" ) ) );
+      DALI_ASSERT_ALWAYS( actorName && "Animation must specify actor name" );
+
+      Handle targetHandle = searchActor.FindChildByName( *actorName );
+      DALI_ASSERT_ALWAYS( targetHandle && "Actor must exist for property" );
+
+      Property::Value propValue;
+      Property::Index propIndex = Property::INVALID_INDEX;
+      if( property )
+      {
+        propIndex = targetHandle.GetPropertyIndex( *property );
+
+        // if the property is not found from the (actor) handle, try to downcast it to renderable actor
+        // to allow animating shader uniforms
+        if( propIndex == Property::INVALID_INDEX )
+        {
+            DALI_SCRIPT_WARNING( "Cannot find property on object\n" );
+            continue;
+        }
+      }
+
+      // these are the defaults
+      AlphaFunction alphaFunction( AlphaFunction::DEFAULT );
+      TimePeriod timePeriod( 0.f );
+
+      OptionalChild timeChild = IsChild( pKeyChild.second, "timePeriod" );
+
+      if( timeChild )
+      {
+        timePeriod = GetTimePeriod( *timeChild, constant );
+      }
+
+      durationSum = std::max( durationSum, timePeriod.delaySeconds + timePeriod.durationSeconds );
+
+      if( OptionalString alphaChild = constant.IsString( IsChild(pKeyChild.second, "alphaFunction" ) ) )
+      {
+        alphaFunction = GetAlphaFunction( *alphaChild );
+      }
+
+      if( OptionalChild keyFrameChild = IsChild(pKeyChild.second, "keyFrames") )
+      {
+        DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
+        Property prop = Property( targetHandle, propIndex );
+
+        KeyFrames keyframes = KeyFrames::New();
+
+        const TreeNode::ConstIterator endIter = (*keyFrameChild).CEnd();
+        for( TreeNode::ConstIterator iter = (*keyFrameChild).CBegin(); endIter != iter; ++iter )
+        {
+          const TreeNode::KeyNodePair& kfKeyChild = *iter;
+
+          OptionalFloat kfProgress = constant.IsFloat( IsChild(kfKeyChild.second, "progress" ) );
+          DALI_ASSERT_ALWAYS( kfProgress && "Key frame entry must have 'progress'" );
+
+          OptionalChild kfValue = IsChild( kfKeyChild.second, "value" );
+          DALI_ASSERT_ALWAYS( kfValue && "Key frame entry must have 'value'" );
+
+          try
+          {
+            propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *kfValue );
+          }
+          catch(...)
+          {
+            DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n",
+                              (*property).c_str(),
+                              PropertyTypes::GetName(prop.object.GetPropertyType(prop.propertyIndex)) );
+
+            throw;
+          }
+
+          AlphaFunction kfAlphaFunction( AlphaFunction::DEFAULT );
+          if( OptionalString alphaFuncStr = constant.IsString( IsChild(pKeyChild.second, "alphaFunction") ) )
+          {
+            kfAlphaFunction = GetAlphaFunction( *alphaFuncStr );
+          }
+
+          keyframes.Add( *kfProgress, propValue, kfAlphaFunction );
+        }
+
+        if( timeChild )
+        {
+          animation.AnimateBetween( prop, keyframes, alphaFunction, timePeriod );
+        }
+        else
+        {
+          animation.AnimateBetween( prop, keyframes, alphaFunction );
+        }
+      }
+      else if( OptionalString pathChild = IsString(pKeyChild.second, "path") )
+      {
+        //Get path
+        Path path = builder->GetPath(*pathChild);
+        if( path )
+        {
+          //Get forward vector if specified
+          Vector3 forward( 0.0f, 0.0f, 0.0f );
+          OptionalVector3 forwardProperty = constant.IsVector3( IsChild(pKeyChild.second, "forward" ) );
+          if( forwardProperty )
+          {
+            forward = *forwardProperty;
+          }
+
+          Actor actor = Actor::DownCast( targetHandle );
+          if( actor )
+          {
+            if( timeChild )
+            {
+              animation.Animate( actor, path, forward, alphaFunction, timePeriod );
+            }
+            else
+            {
+              animation.Animate( actor, path, forward, alphaFunction );
+            }
+
+          }
+        }
+        else
+        {
+          //Path not found
+          DALI_SCRIPT_WARNING( "Cannot find animation path '%s'\n", (*pathChild).c_str() );
+        }
+      }
+      else
+      {
+        DALI_ASSERT_ALWAYS( property  && "Animation must specify a property name" );
+
+        Property prop = Property( targetHandle, propIndex );
+        try
+        {
+          propValue = GetPropertyValue( prop.object.GetPropertyType(prop.propertyIndex), *IsChild(pKeyChild.second, "value") );
+        }
+        catch(...)
+        {
+          DALI_LOG_WARNING( "Property:'%s' type does not match value type '%s'\n", (*property).c_str(),
+                            PropertyTypes::GetName( prop.object.GetPropertyType(prop.propertyIndex) ) );
+
+          throw;
+        }
+
+        if( OptionalBoolean relative = constant.IsBoolean( IsChild(pKeyChild.second, "relative") ) )
+        {
+          if( timeChild )
+          {
+            animation.AnimateBy( prop, propValue, alphaFunction, timePeriod );
+          }
+          else
+          {
+            animation.AnimateBy( prop, propValue, alphaFunction );
+          }
+        }
+        else
+        {
+          if( timeChild )
+          {
+            animation.AnimateTo( prop, propValue, alphaFunction, timePeriod );
+          }
+          else
+          {
+            animation.AnimateTo( prop, propValue, alphaFunction );
+          }
+        }
+      }
+    }
+  }
+
+  if( !duration )
+  {
+    animation.SetDuration( durationSum );
+  }
+
+  return animation;
+}
+
+Animation CreateAnimation( const TreeNode& child, Builder* const builder )
+{
+  Replacement replacement;
+  return CreateAnimation( child, replacement, Stage::GetCurrent().GetRootLayer(), builder );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/internal/builder/builder-declarations.h b/dali-toolkit/internal/builder/builder-declarations.h
new file mode 100644 (file)
index 0000000..09a5fd1
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_TOOLKIT_BUILDER_DECLARATIONS_H
+#define DALI_TOOLKIT_BUILDER_DECLARATIONS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/extents.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector3.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/math/matrix.h>
+#include <dali/public-api/math/matrix3.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+#include <dali-toolkit/internal/builder/optional-value.h>
+
+typedef Dali::Toolkit::TreeNode TreeNode;
+typedef TreeNode::ConstIterator TreeConstIter;
+
+typedef OptionalValue<const TreeNode&> OptionalChild;
+typedef OptionalValue<std::string> OptionalString;
+typedef OptionalValue<float> OptionalFloat;
+typedef OptionalValue<int> OptionalInteger;
+typedef OptionalValue<unsigned int> OptionalUnsignedInt;
+typedef OptionalValue<bool> OptionalBoolean;
+typedef OptionalValue<Dali::Vector2> OptionalVector2;
+typedef OptionalValue<Dali::Vector3> OptionalVector3;
+typedef OptionalValue<Dali::Vector4> OptionalVector4;
+typedef OptionalValue<std::string> OptionalString;
+typedef OptionalValue<Dali::Matrix> OptionalMatrix;
+typedef OptionalValue<Dali::Matrix3> OptionalMatrix3;
+typedef OptionalValue<Dali::Rect<int> > OptionalRect;
+typedef OptionalValue<Dali::Extents> OptionalExtents;
+
+#endif // DALI_TOOLKIT_BUILDER_DECLARATIONS_H
diff --git a/dali-toolkit/internal/builder/builder-filesystem.h b/dali-toolkit/internal/builder/builder-filesystem.h
new file mode 100755 (executable)
index 0000000..2222d1b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_FILESYSTEM_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_FILESYSTEM_H
+
+/*
+ * Copyright (c) 2019 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 <fstream>
+#include <sstream>
+
+#include <stdio.h>
+
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+inline std::string GetFileContents(const std::string &fn)
+{
+  std::streampos bufferSize = 0;
+  Dali::Vector<char> fileBuffer;
+  if( !Dali::FileLoader::ReadFile( fn, bufferSize, fileBuffer, Dali::FileLoader::FileType::BINARY ) )
+  {
+      return std::string();
+  }
+
+  return std::string( &fileBuffer[0], bufferSize );
+}
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_FILESYSTEM_H
diff --git a/dali-toolkit/internal/builder/builder-get-is.inl.h b/dali-toolkit/internal/builder/builder-get-is.inl.h
new file mode 100644 (file)
index 0000000..01dab59
--- /dev/null
@@ -0,0 +1,444 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_GET_IS_INL
+#define DALI_TOOLKIT_INTERNAL_BUILDER_GET_IS_INL
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/builder-declarations.h>
+
+inline OptionalChild IsChild(const TreeNode* node, const std::string& childName)
+{
+  if( node )
+  {
+    const TreeNode* c = node->GetChild(childName);
+    if( NULL != c )
+    {
+      return OptionalChild( *c );
+    }
+    else
+    {
+      return OptionalChild();
+    }
+  }
+  else
+  {
+    return OptionalChild();
+  }
+}
+
+inline OptionalChild IsChildIgnoreCase(const TreeNode* node, const std::string& childName)
+{
+  if( node )
+  {
+    const TreeNode* c = node->GetChildIgnoreCase(childName);
+    if( NULL != c )
+    {
+      return OptionalChild( *c );
+    }
+    else
+    {
+      return OptionalChild();
+    }
+  }
+  else
+  {
+    return OptionalChild();
+  }
+}
+
+inline OptionalChild IsChild(const TreeNode& node, const std::string& childName)
+{
+  return IsChild(&node, childName);
+}
+
+inline OptionalChild IsChildIgnoreCase(const TreeNode& node, const std::string& childName)
+{
+  return IsChildIgnoreCase(&node, childName);
+}
+
+inline OptionalString IsString(const OptionalChild& node)
+{
+  if( node && (*node).GetType() == TreeNode::STRING )
+  {
+    return OptionalString((*node).GetString());
+  }
+  else
+  {
+    return OptionalString();
+  }
+}
+
+inline OptionalFloat IsFloat(const OptionalChild& node)
+{
+  OptionalFloat ret;
+
+  if( node )
+  {
+    if( (*node).GetType() == TreeNode::FLOAT )
+    {
+      ret = (*node).GetFloat();
+    }
+    else if( (*node).GetType() == TreeNode::INTEGER )
+    {
+      // JSON has number not float/int but JsonParser discriminates.
+      // Here we don't care so we allow coercion
+      ret = static_cast<float>( (*node).GetInteger() );
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalInteger IsInteger(const OptionalChild &node)
+{
+  OptionalInteger ret;
+
+  if( node )
+  {
+    if( (*node).GetType() == TreeNode::INTEGER )
+    {
+      ret = (*node).GetInteger();
+    }
+    else if( (*node).GetType() == TreeNode::FLOAT )
+    {
+      ret = static_cast<int>(  (*node).GetFloat() );
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalBoolean IsBoolean(const OptionalChild& node)
+{
+  if( node && (*node).GetType() == TreeNode::BOOLEAN )
+  {
+    return OptionalBoolean(1 == (*node).GetInteger());
+  }
+  else
+  {
+    return OptionalBoolean();
+  }
+}
+
+
+// copy N Numbers
+template <typename T>
+inline bool CopyNumbers(TreeNode::ConstIterator iter, int N, T& vector)
+{
+  for(int i = 0; i < N; ++i)
+  {
+    if( (*iter).second.GetType() == TreeNode::FLOAT)
+    {
+      vector[i] = (*iter).second.GetFloat();
+    }
+    else if( (*iter).second.GetType() == TreeNode::INTEGER )
+    {
+      vector[i] = static_cast<float>((*iter).second.GetInteger());
+    }
+    else
+    {
+      return false;
+    }
+    iter++;
+  }
+
+  return true;
+}
+
+inline OptionalVector4 IsVector4(const OptionalChild& node)
+{
+  OptionalVector4 ret;
+
+  if( node && (TreeNode::ARRAY == (*node).GetType()) && (*node).Size() >= 4 )
+  {
+    Dali::Vector4 v;
+    if( CopyNumbers((*node).CBegin(), 4, v) )
+    {
+      ret = OptionalVector4(v);
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalVector3 IsVector3(const OptionalChild& node)
+{
+  OptionalVector3 ret;
+
+  if( node && (TreeNode::ARRAY == (*node).GetType()) && (*node).Size() >= 3 )
+  {
+    Dali::Vector3 v;
+    if( CopyNumbers((*node).CBegin(), 3, v) )
+    {
+      ret = OptionalVector3(v);
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalVector2 IsVector2(const OptionalChild& node)
+{
+  OptionalVector2 ret;
+
+  if( node && (TreeNode::ARRAY == (*node).GetType()) && (*node).Size() >= 2 )
+  {
+    Dali::Vector2 v;
+    if( CopyNumbers((*node).CBegin(), 2, v) )
+    {
+      ret = OptionalVector2(v);
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalMatrix IsMatrix(const OptionalChild &node)
+{
+  OptionalMatrix ret;
+
+  if( node && (TreeNode::ARRAY == (*node).GetType()) && (*node).Size() >= 16 )
+  {
+    float v[16];
+    if( CopyNumbers((*node).CBegin(), 16, v) )
+    {
+      ret = OptionalMatrix(Dali::Matrix(v));
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalMatrix3 IsMatrix3(const OptionalChild& node)
+{
+  OptionalMatrix3 ret;
+
+  if( node && (TreeNode::ARRAY == (*node).GetType()) && (*node).Size() >= 9 )
+  {
+    float v[9];
+    if( CopyNumbers((*node).CBegin(), 9, v) )
+    {
+      ret = OptionalMatrix3(Dali::Matrix3(v[0], v[1], v[2],
+                                          v[3], v[4], v[5],
+                                          v[6], v[7], v[8] ));
+    }
+  }
+
+  return ret;
+}
+
+inline OptionalRect IsRect(const OptionalChild& node)
+{
+  OptionalRect ret;
+  if(node && (*node).Size())
+  {
+    if((*node).Size() >= 4)
+    {
+      TreeNode::ConstIterator iter((*node).CBegin());
+      int v[4];
+      if( CopyNumbers((*node).CBegin(), 4, v) )
+      {
+        ret = OptionalRect(Dali::Rect<int>(v[0], v[1], v[2], v[3]));
+      }
+    }
+  }
+  return ret;
+}
+
+inline OptionalExtents IsExtents(const OptionalChild& node)
+{
+  OptionalExtents extents;
+  if(node && (*node).Size())
+  {
+    if((*node).Size() >= 4)
+    {
+      TreeNode::ConstIterator iter((*node).CBegin());
+      int v[4];
+      if( CopyNumbers((*node).CBegin(), 4, v) )
+      {
+        extents = OptionalExtents(Dali::Extents(v[0], v[1], v[2], v[3]));
+      }
+    }
+  }
+  return extents;
+}
+
+//
+//
+//
+inline OptionalString IsString( const TreeNode& parent, const std::string& childName)
+{
+  return IsString( IsChild(&parent, childName) );
+}
+
+inline OptionalFloat IsFloat( const TreeNode& parent, const std::string& childName)
+{
+  return IsFloat( IsChild(&parent, childName) );
+}
+
+inline OptionalInteger IsInteger( const TreeNode& parent, const std::string& childName)
+{
+  return IsInteger( IsChild(&parent, childName) );
+}
+
+inline OptionalBoolean IsBoolean( const TreeNode& parent, const std::string& childName)
+{
+  return IsBoolean( IsChild(parent, childName) );
+}
+
+inline OptionalVector4 IsVector4(const TreeNode &parent, const std::string& childName)
+{
+  return IsVector4( IsChild(parent, childName) );
+}
+
+inline OptionalVector3 IsVector3(const TreeNode &parent, const std::string& childName)
+{
+  return IsVector3( IsChild(parent, childName) );
+}
+
+inline OptionalVector2 IsVector2(const TreeNode &parent, const std::string& childName)
+{
+  return IsVector2( IsChild(parent, childName) );
+}
+
+inline OptionalMatrix IsMatrix(const TreeNode &parent, const std::string& childName)
+{
+  return IsMatrix( IsChild(parent, childName) );
+}
+
+inline OptionalMatrix3 IsMatrix3(const TreeNode &parent, const std::string& childName)
+{
+  return IsMatrix3( IsChild(&parent, childName) );
+}
+
+inline OptionalRect IsRect(const TreeNode &parent, const std::string& childName)
+{
+  return IsRect( IsChild(&parent, childName) );
+}
+
+inline OptionalExtents IsExtents(const TreeNode &parent, const std::string& childName)
+{
+  return IsExtents( IsChild(&parent, childName) );
+}
+
+//
+//
+//
+inline OptionalString IsString( const TreeNode& node )
+{
+  return IsString( OptionalChild( node ) );
+}
+
+inline OptionalFloat IsFloat( const TreeNode& node )
+{
+  return IsFloat( OptionalChild( node ) );
+}
+
+inline OptionalInteger IsInteger( const TreeNode& node )
+{
+  return IsInteger( OptionalChild( node ) );
+}
+
+inline OptionalBoolean IsBoolean( const TreeNode& node )
+{
+  return IsBoolean( OptionalChild( node ) );
+}
+
+inline OptionalVector4 IsVector4(const TreeNode &node )
+{
+  return IsVector4( OptionalChild( node ) );
+}
+
+inline OptionalVector3 IsVector3(const TreeNode &node )
+{
+  return IsVector3( OptionalChild( node ) );
+}
+
+inline OptionalVector2 IsVector2(const TreeNode &node )
+{
+  return IsVector2( OptionalChild( node ) );
+}
+
+inline OptionalMatrix IsMatrix(const TreeNode &node )
+{
+  return IsMatrix( OptionalChild( node ) );
+}
+
+inline OptionalMatrix3 IsMatrix3(const TreeNode &node )
+{
+  return IsMatrix3( OptionalChild( node ) );
+}
+
+inline OptionalRect IsRect(const TreeNode &node )
+{
+  return IsRect( OptionalChild( node ) );
+}
+
+inline OptionalExtents IsExtents(const TreeNode &node )
+{
+  return IsExtents( OptionalChild( node ) );
+}
+
+//
+//
+//
+inline Dali::Vector4 GetVector4(const TreeNode &child)
+{
+  OptionalVector4 v( IsVector4( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+inline Dali::Vector3 GetVector3(const TreeNode &child)
+{
+  OptionalVector3 v( IsVector3( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+inline Dali::Vector2 GetVector2(const TreeNode &child)
+{
+  OptionalVector2 v( IsVector2( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+inline float GetFloat(const TreeNode &child)
+{
+  OptionalFloat v( IsFloat( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+inline bool GetBoolean(const TreeNode &child)
+{
+  OptionalBoolean v( IsBoolean( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+inline int GetInteger(const TreeNode &child)
+{
+  OptionalInteger v( IsInteger( OptionalChild( child ) ) );
+  DALI_ASSERT_ALWAYS(v);
+  return *v;
+}
+
+
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_GET_IS_INL
diff --git a/dali-toolkit/internal/builder/builder-impl-debug.cpp b/dali-toolkit/internal/builder/builder-impl-debug.cpp
new file mode 100644 (file)
index 0000000..2e89d71
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifdef DEBUG_ENABLED
+#include <dali-toolkit/internal/builder/builder-impl-debug.h>
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <iostream>
+#include <cstring>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+void LogTree( const Toolkit::JsonParser& parser )
+{
+  if( OptionalChild constants = IsChild(parser.GetRoot(), "constants") )
+  {
+    for(TreeNode::ConstIterator iter = (*constants).CBegin();
+        iter != (*constants).CEnd(); ++iter)
+    {
+      if( ( (*iter).first && strcmp( (*iter).first, "DUMP_TREE" ) == 0 ) ||
+          ( (*iter).second.GetType() == TreeNode::STRING && strcmp( (*iter).second.GetString(), "DUMP_TREE" ) == 0 ) )
+      {
+        std::ostringstream oss;
+        parser.Write(oss, 2);
+        std::cout << oss.str() << std::endl;
+      }
+    }
+  }
+}
+
+std::string PropertyValueToString( const Property::Value& value )
+{
+  std::ostringstream oss;
+  oss << value;
+
+  return oss.str();
+}
+
+} // Internal
+} // Toolkit
+} // Dali
+
+#endif // DEBUG_ENABLED
diff --git a/dali-toolkit/internal/builder/builder-impl-debug.h b/dali-toolkit/internal/builder/builder-impl-debug.h
new file mode 100644 (file)
index 0000000..8d30929
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_IMPL_DEBUG_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_IMPL_DEBUG_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.
+ */
+
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+
+#if defined( DEBUG_ENABLED )
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+#define DUMP_PARSE_TREE(parser)  LogTree(parser)
+#define DUMP_TEST_MAPPINGS(parser)                                      \
+  OptionalChild mappings = IsChild( parser.GetRoot(), KEYNAME_MAPPINGS ); \
+  if( mappings )                                                        \
+  {                                                                     \
+    std::ostringstream oss;                                             \
+    oss << "Mappings: {" << std::endl;                                  \
+    for( TreeNode::ConstIterator iter = (*mappings).CBegin(); iter != (*mappings).CEnd(); ++iter ) \
+    {                                                                   \
+      Property::Value value;                                            \
+      bool converted = GetPropertyMap(*mappings, (*iter).first, Property::NONE, value ); \
+      if( converted )                                                   \
+      {                                                                 \
+        oss << "  " << (*iter).first << ":" << value << std::endl;      \
+      }                                                                 \
+    }                                                                   \
+    oss << "}" << std::endl;                                            \
+    DALI_LOG_INFO( gFilterScript, Debug::Verbose, oss.str().c_str() );  \
+  }
+
+
+void LogTree( const Toolkit::JsonParser& mParser );
+
+std::string PropertyValueToString( const Property::Value& value );
+
+
+} // Internal
+} // Toolkit
+} // Dali
+
+#else
+
+#define DUMP_PARSE_TREE(parser)
+#define DUMP_TEST_MAPPINGS(parser)
+
+#endif // DEBUG_ENABLED
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_IMPL_DEBUG_H
diff --git a/dali-toolkit/internal/builder/builder-impl.cpp b/dali-toolkit/internal/builder/builder-impl.cpp
new file mode 100644 (file)
index 0000000..5165a09
--- /dev/null
@@ -0,0 +1,1644 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/builder/builder-impl.h>
+
+// EXTERNAL INCLUDES
+#include <sys/stat.h>
+#include <sstream>
+
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/type-info.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/signals/functor-delegate.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+
+#include <dali-toolkit/internal/builder/builder-declarations.h>
+#include <dali-toolkit/internal/builder/builder-filesystem.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <dali-toolkit/internal/builder/builder-impl-debug.h>
+#include <dali-toolkit/internal/builder/builder-set-property.h>
+#include <dali-toolkit/internal/builder/replacement.h>
+#include <dali-toolkit/internal/builder/tree-node-manipulator.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class Replacement;
+
+extern Animation CreateAnimation(const TreeNode& child, const Replacement& replacements, const Dali::Actor searchRoot, Builder* const builder );
+
+extern Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
+
+extern Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder);
+
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gFilterScript  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_SCRIPT");
+#endif
+
+namespace
+{
+
+#define TOKEN_STRING(x) #x
+
+const std::string KEYNAME_ACTORS           = "actors";
+const std::string KEYNAME_ENTRY_TRANSITION = "entryTransition";
+const std::string KEYNAME_EXIT_TRANSITION  = "exitTransition";
+const std::string KEYNAME_INCLUDES         = "includes";
+const std::string KEYNAME_INHERIT          = "inherit";
+const std::string KEYNAME_MAPPINGS         = "mappings";
+const std::string KEYNAME_NAME             = "name";
+const std::string KEYNAME_SIGNALS          = "signals";
+const std::string KEYNAME_STATES           = "states";
+const std::string KEYNAME_STYLES           = "styles";
+const std::string KEYNAME_TEMPLATES        = "templates";
+const std::string KEYNAME_TRANSITIONS      = "transitions";
+const std::string KEYNAME_TYPE             = "type";
+const std::string KEYNAME_VISUALS          = "visuals";
+
+const std::string PROPERTIES = "properties";
+const std::string ANIMATABLE_PROPERTIES = "animatableProperties";
+
+typedef std::vector<const TreeNode*> TreeNodeList;
+
+
+bool GetMappingKey( const std::string& str, std::string& key )
+{
+  bool result = false;
+  std::string test( str );
+  if( ! test.empty() )
+  {
+    if( test.at(0) == '<' )
+    {
+      if( test.at(test.length()-1) == '>' )
+      {
+        key = test.substr( 1, test.length()-2 );
+        result = true;
+      }
+    }
+  }
+  return result;
+}
+
+/*
+ * Recursively collects all styles in a node (An array of style names).
+ *
+ * stylesCollection The set of styles from the json file (a json object of named styles)
+ * style The style array to begin the collection from
+ * styleList The style list to add nodes to apply
+ */
+void CollectAllStyles( const TreeNode& stylesCollection, const TreeNode& style, TreeNodeList& styleList )
+{
+  // style is an array of style names
+  if( TreeNode::ARRAY == style.GetType() )
+  {
+    for(TreeNode::ConstIterator iter = style.CBegin(); iter != style.CEnd(); ++iter)
+    {
+      if( OptionalString styleName = IsString( (*iter).second ) )
+      {
+        if( OptionalChild node = IsChildIgnoreCase( stylesCollection, *styleName) )
+        {
+          styleList.push_back( &(*node) );
+
+          OptionalChild subStyle = IsChild( *node, KEYNAME_INHERIT );
+          if( ! subStyle )
+          {
+            subStyle = IsChild( *node, KEYNAME_STYLES );
+          }
+          if( subStyle )
+          {
+            CollectAllStyles( stylesCollection, *subStyle, styleList );
+          }
+        }
+      }
+    }
+  }
+}
+
+
+} // namespace anon
+
+
+Builder::Builder()
+: mSlotDelegate( this )
+{
+  mParser = Dali::Toolkit::JsonParser::New();
+
+  Property::Map defaultDirs;
+  defaultDirs[TOKEN_STRING(DALI_IMAGE_DIR)]       = AssetManager::GetDaliImagePath();
+  defaultDirs[TOKEN_STRING(DALI_SOUND_DIR)]       = AssetManager::GetDaliSoundPath();
+  defaultDirs[TOKEN_STRING(DALI_STYLE_DIR)]       = AssetManager::GetDaliStylePath();
+  defaultDirs[TOKEN_STRING(DALI_STYLE_IMAGE_DIR)] = AssetManager::GetDaliStyleImagePath();
+
+  AddConstants( defaultDirs );
+}
+
+void Builder::LoadFromString( std::string const& data, Dali::Toolkit::Builder::UIFormat format )
+{
+  // parser to get constants and includes only
+  Dali::Toolkit::JsonParser parser = Dali::Toolkit::JsonParser::New();
+
+  if( !parser.Parse( data ) )
+  {
+    DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
+                      parser.GetErrorLineNumber(),
+                      parser.GetErrorColumn(),
+                      parser.GetErrorDescription().c_str() );
+
+    DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
+  }
+  else
+  {
+    // load constant map (allows the user to override the constants in the json after loading)
+    LoadConstants( *parser.GetRoot(), mReplacementMap );
+    // load configuration map
+    LoadConfiguration( *parser.GetRoot(), mConfigurationMap );
+    // merge includes
+    if( OptionalChild includes = IsChild(*parser.GetRoot(), KEYNAME_INCLUDES) )
+    {
+      Replacement replacer( mReplacementMap );
+
+      for(TreeNode::ConstIterator iter = (*includes).CBegin(); iter != (*includes).CEnd(); ++iter)
+      {
+        OptionalString filename = replacer.IsString( (*iter).second );
+
+        if( filename )
+        {
+#if defined(DEBUG_ENABLED)
+          DALI_SCRIPT_VERBOSE("Loading Include '%s'\n", (*filename).c_str());
+#endif
+          LoadFromString( GetFileContents(*filename) );
+        }
+      }
+    }
+
+    if( mParser.Parse( data ) )
+    {
+      // Drop the styles and get them to be rebuilt against the new parse tree as required.
+      mStyles.Clear();
+    }
+    else
+    {
+      DALI_LOG_WARNING( "JSON Parse Error:%d:%d:'%s'\n",
+                        mParser.GetErrorLineNumber(),
+                        mParser.GetErrorColumn(),
+                        mParser.GetErrorDescription().c_str() );
+
+      DALI_ASSERT_ALWAYS(!"Cannot parse JSON");
+    }
+  }
+
+  DUMP_PARSE_TREE(mParser); // This macro only writes out if DEBUG is enabled and the "DUMP_TREE" constant is defined in the stylesheet.
+  DUMP_TEST_MAPPINGS(mParser);
+
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Cannot parse JSON");
+}
+
+void Builder::AddConstants( const Property::Map& map )
+{
+  mReplacementMap.Merge( map );
+}
+
+void Builder::AddConstant( const std::string& key, const Property::Value& value )
+{
+  mReplacementMap[key] = value;
+}
+
+const Property::Map& Builder::GetConfigurations() const
+{
+  return mConfigurationMap;
+}
+
+const Property::Map& Builder::GetConstants() const
+{
+  return mReplacementMap;
+}
+
+const Property::Value& Builder::GetConstant( const std::string& key ) const
+{
+  Property::Value* match = mReplacementMap.Find( key );
+  if( match )
+  {
+    return (*match);
+  }
+  else
+  {
+    static Property::Value invalid;
+    return invalid;
+  }
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor )
+{
+  Replacement replacement(map, mReplacementMap);
+  return CreateAnimation( animationName, replacement, sourceActor);
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const Property::Map& map )
+{
+  Replacement replacement(map, mReplacementMap);
+  return CreateAnimation( animationName, replacement, Stage::GetCurrent().GetRootLayer() );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, Dali::Actor sourceActor )
+{
+  Replacement replacement( mReplacementMap );
+
+  return CreateAnimation( animationName, replacement, sourceActor );
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName )
+{
+  Replacement replacement( mReplacementMap );
+
+  return CreateAnimation( animationName, replacement, Dali::Stage::GetCurrent().GetRootLayer() );
+}
+
+BaseHandle Builder::Create( const std::string& templateName )
+{
+  Replacement replacement( mReplacementMap );
+  return Create( templateName, replacement );
+}
+
+BaseHandle Builder::Create( const std::string& templateName, const Property::Map& map )
+{
+  Replacement replacement( map, mReplacementMap );
+  return Create( templateName, replacement );
+}
+
+BaseHandle Builder::CreateFromJson( const std::string& json )
+{
+  BaseHandle ret;
+
+  // merge in new template, hoping no one else has one named '@temp@'
+  std::string newTemplate =
+    std::string("{\"templates\":{\"@temp@\":") +                      \
+    json +                                                            \
+    std::string("}}");
+
+  if( mParser.Parse(newTemplate) )
+  {
+    Replacement replacement( mReplacementMap );
+    ret = Create( "@temp@", replacement );
+  }
+
+  return ret;
+}
+
+bool Builder::ApplyFromJson(  Handle& handle, const std::string& json )
+{
+  bool ret = false;
+
+  // merge new style, hoping no one else has one named '@temp@'
+  std::string newStyle =
+    std::string("{\"styles\":{\"@temp@\":") +                           \
+    json +                                                              \
+    std::string("}}");
+
+  if( mParser.Parse(newStyle) )
+  {
+    Replacement replacement( mReplacementMap );
+    ret = ApplyStyle( "@temp@", handle, replacement );
+  }
+
+  return ret;
+}
+
+bool Builder::ApplyStyle( const std::string& styleName, Handle& handle )
+{
+  Replacement replacer( mReplacementMap );
+  return ApplyStyle( styleName, handle, replacer );
+}
+
+bool Builder::LookupStyleName( const std::string& styleName )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES );
+  OptionalChild style  = IsChildIgnoreCase( *styles, styleName );
+
+  if( styles && style )
+  {
+    return true;
+  }
+  return false;
+}
+
+const StylePtr Builder::GetStyle( const std::string& styleName )
+{
+  const StylePtr* style = mStyles.FindConst( styleName );
+
+  if( style==NULL )
+  {
+    return StylePtr(NULL);
+  }
+  else
+  {
+    return *style;
+  }
+}
+
+void Builder::AddActors( Actor toActor )
+{
+  // 'stage' is the default/by convention section to add from
+  AddActors( "stage", toActor );
+}
+
+void Builder::AddActors( const std::string &sectionName, Actor toActor )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  Property::Map overrideMap;
+  Replacement replacements(overrideMap, mReplacementMap);
+
+  OptionalChild add = IsChild(*mParser.GetRoot(), sectionName);
+
+  if( add )
+  {
+    for( TreeNode::ConstIterator iter = (*add).CBegin(); iter != (*add).CEnd(); ++iter )
+    {
+      // empty actor adds directly to the stage
+      BaseHandle baseHandle = DoCreate( *mParser.GetRoot(), (*iter).second, Actor(), replacements );
+      Actor actor = Actor::DownCast(baseHandle);
+      if(actor)
+      {
+        toActor.Add( actor );
+      }
+    }
+
+    // if were adding the 'stage' section then also check for a render task called stage
+    // to add automatically
+    if( "stage" == sectionName )
+    {
+      if( OptionalChild renderTasks = IsChild(*mParser.GetRoot(), "renderTasks") )
+      {
+        if( OptionalChild tasks = IsChild(*renderTasks, "stage") )
+        {
+          CreateRenderTask( "stage" );
+        }
+      }
+    }
+  }
+}
+
+void Builder::CreateRenderTask( const std::string &name )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  Replacement constant(mReplacementMap);
+
+  const Stage& stage = Stage::GetCurrent();
+
+  OptionalChild tasks = IsChild(*mParser.GetRoot(), "renderTasks");
+
+  if(tasks)
+  {
+    //
+    // Create the tasks from the current task as generally we want
+    // to setup task zero and onwards. Although this does overwrite
+    // the properties of the current task.
+    //
+    if( OptionalChild renderTask = IsChild(*tasks, name ) )
+    {
+      RenderTaskList list = stage.GetRenderTaskList();
+      unsigned int start = list.GetTaskCount();
+
+      RenderTask task;
+      if(0 == start)
+      {
+        // zero should have already been created by the stage so really
+        // this case should never happen
+        task = list.CreateTask();
+        start++;
+      }
+
+      TreeNode::ConstIterator iter = (*renderTask).CBegin();
+      task = list.GetTask( start - 1 );
+
+      SetupTask( task, (*iter).second, constant  );
+
+      ++iter;
+
+      for(; iter != (*renderTask).CEnd(); ++iter )
+      {
+        task = list.CreateTask();
+        SetupTask( task, (*iter).second, constant );
+      }
+    }
+  }
+}
+
+Path Builder::GetPath( const std::string& name )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  Path ret;
+
+  PathLut::const_iterator iter( mPathLut.find( name ) );
+  if( iter != mPathLut.end() )
+  {
+    ret = iter->second;
+  }
+  else
+  {
+    if( OptionalChild paths = IsChild( *mParser.GetRoot(), "paths") )
+    {
+      if( OptionalChild path = IsChild( *paths, name ) )
+      {
+        //points property
+        if( OptionalChild pointsProperty = IsChild( *path, "points") )
+        {
+          Dali::Property::Value points(Property::ARRAY);
+          if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+          {
+            ret = Path::New();
+            ret.SetProperty( Path::Property::POINTS, points);
+
+            //controlPoints property
+            if( OptionalChild pointsProperty = IsChild( *path, "controlPoints") )
+            {
+              Dali::Property::Value points(Property::ARRAY);
+              if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+              {
+                ret.SetProperty( Path::Property::CONTROL_POINTS, points);
+              }
+            }
+            else
+            {
+              //Curvature
+              float curvature(0.25f);
+              if( OptionalFloat pointsProperty = IsFloat( *path, "curvature") )
+              {
+                curvature = *pointsProperty;
+              }
+              ret.GenerateControlPoints(curvature);
+            }
+
+            //Add the new path to the hash table for paths
+            mPathLut[ name ] = ret;
+          }
+        }
+        else
+        {
+          //Interpolation points not specified
+          DALI_SCRIPT_WARNING("Interpolation points not specified for path '%s'\n", name.c_str() );
+        }
+      }
+
+    }
+  }
+
+  return ret;
+}
+
+PathConstrainer Builder::GetPathConstrainer( const std::string& name )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  //Search the pathConstrainer in the LUT
+  size_t count( mPathConstrainerLut.size() );
+  for( size_t i(0); i!=count; ++i )
+  {
+    if( mPathConstrainerLut[i].name == name )
+    {
+      //PathConstrainer has already been created
+      return mPathConstrainerLut[i].pathConstrainer;
+    }
+  }
+
+  //Create a new PathConstrainer
+  PathConstrainer ret;
+  if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
+  {
+    if( OptionalChild pathConstrainer = IsChild( *constrainers, name ) )
+    {
+      OptionalString constrainerType(IsString(IsChild(*pathConstrainer, "type")));
+      if(!constrainerType)
+      {
+        DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() );
+      }
+      else if( *constrainerType == "PathConstrainer")
+      {
+        //points property
+        if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "points") )
+        {
+          Dali::Property::Value points(Property::ARRAY);
+          if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+          {
+            ret = PathConstrainer::New();
+            ret.SetProperty( PathConstrainer::Property::POINTS, points);
+
+            //controlPoints property
+            if( OptionalChild pointsProperty = IsChild( *pathConstrainer, "controlPoints") )
+            {
+              Dali::Property::Value points(Property::ARRAY);
+              if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+              {
+                ret.SetProperty( PathConstrainer::Property::CONTROL_POINTS, points);
+              }
+
+              //Forward vector
+              OptionalVector3 forward( IsVector3( IsChild(*pathConstrainer, "forward" ) ) );
+              if( forward )
+              {
+                ret.SetProperty( PathConstrainer::Property::FORWARD, *forward);
+              }
+
+              //Add the new constrainer to the vector of PathConstrainer
+              PathConstrainerEntry entry = {name,ret};
+              mPathConstrainerLut.push_back( entry );
+            }
+            else
+            {
+              //Control points not specified
+              DALI_SCRIPT_WARNING("Control points not specified for pathConstrainer '%s'\n", name.c_str() );
+            }
+          }
+        }
+        else
+        {
+          //Interpolation points not specified
+          DALI_SCRIPT_WARNING("Interpolation points not specified for pathConstrainer '%s'\n", name.c_str() );
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer '%s' is not a PathConstrainer\n", name.c_str() );
+      }
+    }
+  }
+
+  return ret;
+}
+
+
+bool Builder::IsPathConstrainer( const std::string& name )
+{
+  size_t count( mPathConstrainerLut.size() );
+  for( size_t i(0); i!=count; ++i )
+  {
+    if( mPathConstrainerLut[i].name == name )
+    {
+      return true;
+    }
+  }
+
+  if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
+  {
+    if( OptionalChild constrainer = IsChild( *constrainers, name ) )
+    {
+      OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
+      if(!constrainerType)
+      {
+        return false;
+      }
+      else
+      {
+         return *constrainerType == "PathConstrainer";
+      }
+    }
+  }
+  return false;
+}
+
+Dali::LinearConstrainer Builder::GetLinearConstrainer( const std::string& name )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  //Search the LinearConstrainer in the LUT
+  size_t count( mLinearConstrainerLut.size() );
+  for( size_t i(0); i!=count; ++i )
+  {
+    if( mLinearConstrainerLut[i].name == name )
+    {
+      //LinearConstrainer has already been created
+      return mLinearConstrainerLut[i].linearConstrainer;
+    }
+  }
+
+  //Create a new LinearConstrainer
+  LinearConstrainer ret;
+  if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
+  {
+    if( OptionalChild linearConstrainer = IsChild( *constrainers, name ) )
+    {
+      OptionalString constrainerType(IsString(IsChild(*linearConstrainer, "type")));
+      if(!constrainerType)
+      {
+        DALI_SCRIPT_WARNING("Constrainer type not specified for constrainer '%s'\n", name.c_str() );
+      }
+      else if( *constrainerType == "LinearConstrainer")
+      {
+        //points property
+        if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "value") )
+        {
+          Dali::Property::Value points(Property::ARRAY);
+          if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+          {
+            ret = Dali::LinearConstrainer::New();
+            ret.SetProperty( LinearConstrainer::Property::VALUE, points);
+
+            //controlPoints property
+            if( OptionalChild pointsProperty = IsChild( *linearConstrainer, "progress") )
+            {
+              Dali::Property::Value points(Property::ARRAY);
+              if( DeterminePropertyFromNode( *pointsProperty, Property::ARRAY, points ) )
+              {
+                ret.SetProperty( LinearConstrainer::Property::PROGRESS, points);
+              }
+            }
+            //Add the new constrainer to vector of LinearConstrainer
+            LinearConstrainerEntry entry = {name,ret};
+            mLinearConstrainerLut.push_back( entry );
+          }
+        }
+        else
+        {
+          //Interpolation points not specified
+          DALI_SCRIPT_WARNING("Values not specified for LinearConstrainer '%s'\n", name.c_str() );
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer '%s' is not a LinearConstrainer\n", name.c_str() );
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool Builder::IsLinearConstrainer( const std::string& name )
+{
+  // Search the LinearConstrainer in the LUT
+  size_t count( mLinearConstrainerLut.size() );
+  for( size_t i(0); i!=count; ++i )
+  {
+    if( mLinearConstrainerLut[i].name == name )
+    {
+      return true;
+    }
+  }
+
+  if( OptionalChild constrainers = IsChild( *mParser.GetRoot(), "constrainers") )
+  {
+    if( OptionalChild constrainer = IsChild( *constrainers, name ) )
+    {
+      OptionalString constrainerType(IsString(IsChild(*constrainer, "type")));
+      if(!constrainerType)
+      {
+        return false;
+      }
+      else
+      {
+         return *constrainerType == "LinearConstrainer";
+      }
+    }
+  }
+  return false;
+}
+
+Toolkit::Builder::BuilderSignalType& Builder::QuitSignal()
+{
+  return mQuitSignal;
+}
+
+void Builder::EmitQuitSignal()
+{
+  mQuitSignal.Emit();
+}
+
+Builder::~Builder()
+{
+}
+
+void Builder::LoadConfiguration( const TreeNode& root, Property::Map& intoMap )
+{
+  Replacement replacer(intoMap);
+
+  if( OptionalChild constants = IsChild(root, "config") )
+  {
+    for(TreeNode::ConstIterator iter = (*constants).CBegin();
+        iter != (*constants).CEnd(); ++iter)
+    {
+      Dali::Property::Value property;
+      if( (*iter).second.GetName() )
+      {
+        DeterminePropertyFromNode( (*iter).second, property, replacer );
+
+        // If config is string, find constant and replace it to original value.
+        if( (*iter).second.GetType() == TreeNode::STRING )
+        {
+          std::string stringConfigValue;
+          if( property.Get( stringConfigValue ) )
+          {
+            std::size_t pos = 0;
+
+            while( pos < stringConfigValue.size() )
+            {
+              // If we can't find "{","}" pair in stringConfigValue, will out loop.
+              std::size_t leftPos = stringConfigValue.find( "{", pos );
+              if( leftPos != std::string::npos )
+              {
+                std::size_t rightPos = stringConfigValue.find( "}", pos+1 );
+
+                if( rightPos != std::string::npos )
+                {
+                  // If we find "{","}" pair but can't find matched constant
+                  // try to find other "{","}" pair after current left position.
+                  pos = leftPos+1;
+
+                  for( uint32_t i = 0; i < mReplacementMap.Count() ; i++ )
+                  {
+                    Property::Key constant = mReplacementMap.GetKeyAt(i);
+
+                    // Compare string which is between "{" and "}" with constant string
+                    // If they are same, change string in stringConfigValue to mapped constant value.
+                    if ( 0 == stringConfigValue.compare( leftPos+1, rightPos-leftPos-1, constant.stringKey ) )
+                    {
+                      std::string replaceString;
+                      mReplacementMap.GetValue(i).Get( replaceString );
+
+                      stringConfigValue.replace( leftPos, rightPos-leftPos+1, replaceString );
+                      pos = leftPos + replaceString.size();
+                      break;
+                    }
+                  }
+                }
+                else
+                {
+                  // If we cannot find constant in const value, will out loop.
+                  pos = stringConfigValue.size();
+                }
+              }
+              else
+              {
+                // If we cannot find constant in const value, will out loop.
+                pos = stringConfigValue.size();
+              }
+            }
+            property = Property::Value( stringConfigValue );
+          }
+        }
+        intoMap[ (*iter).second.GetName() ] = property;
+      }
+    }
+  }
+}
+
+void Builder::LoadConstants( const TreeNode& root, Property::Map& intoMap )
+{
+  Replacement replacer(intoMap);
+
+  if( OptionalChild constants = IsChild(root, "constants") )
+  {
+    for(TreeNode::ConstIterator iter = (*constants).CBegin();
+        iter != (*constants).CEnd(); ++iter)
+    {
+      Dali::Property::Value property;
+      if( (*iter).second.GetName() )
+      {
+#if defined(DEBUG_ENABLED)
+        DALI_SCRIPT_VERBOSE("Constant set from json '%s'\n", (*iter).second.GetName());
+#endif
+        DeterminePropertyFromNode( (*iter).second, property, replacer );
+        intoMap[ (*iter).second.GetName() ] = property;
+      }
+    }
+  }
+
+#if defined(DEBUG_ENABLED)
+  Property::Value* iter = intoMap.Find( "CONFIG_SCRIPT_LOG_LEVEL" );
+  if( iter && iter->GetType() == Property::STRING )
+  {
+    std::string logLevel( iter->Get< std::string >() );
+    if( logLevel == "NoLogging" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::NoLogging );
+    }
+    else if( logLevel == "Concise" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::Concise );
+    }
+    else if( logLevel == "General" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::General );
+    }
+    else if( logLevel == "Verbose" )
+    {
+      gFilterScript->SetLogLevel( Integration::Log::Verbose );
+    }
+  }
+#endif
+}
+
+Animation Builder::CreateAnimation( const std::string& animationName, const Replacement& replacement, Dali::Actor sourceActor )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  Animation anim;
+
+  if( OptionalChild animations = IsChild(*mParser.GetRoot(), "animations") )
+  {
+    if( OptionalChild animation = IsChild(*animations, animationName) )
+    {
+      anim = Dali::Toolkit::Internal::CreateAnimation( *animation, replacement, sourceActor, this );
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed\n", animationName.c_str() );
+    }
+  }
+  else
+  {
+    DALI_SCRIPT_WARNING( "Request for Animation called '%s' failed (no animation section)\n", animationName.c_str() );
+  }
+
+  return anim;
+}
+
+BaseHandle Builder::Create( const std::string& templateName, const Replacement& constant )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  BaseHandle baseHandle;
+
+  OptionalChild templates = IsChild(*mParser.GetRoot(), KEYNAME_TEMPLATES);
+
+  if( !templates )
+  {
+    DALI_SCRIPT_WARNING("No template section found to CreateFromTemplate\n");
+  }
+  else
+  {
+    OptionalChild childTemplate = IsChild(*templates, templateName);
+    if(!childTemplate)
+    {
+      DALI_SCRIPT_WARNING("Template '%s' does not exist in template section\n", templateName.c_str());
+    }
+    else
+    {
+      OptionalString type = constant.IsString( IsChild(*childTemplate, KEYNAME_TYPE) );
+
+      if(!type)
+      {
+        DALI_SCRIPT_WARNING("Cannot create template '%s' as template section is missing 'type'\n", templateName.c_str());
+      }
+      else
+      {
+        baseHandle = DoCreate( *mParser.GetRoot(), *childTemplate, Actor(), constant );
+      }
+    }
+  }
+
+  return baseHandle;
+}
+
+/*
+ * Create a dali type from a node.
+ * If parent given and an actor type was created then add it to the parent and
+ * recursively add nodes children.
+ */
+BaseHandle Builder::DoCreate( const TreeNode& root, const TreeNode& node,
+                              Actor parent, const Replacement& replacements )
+{
+  BaseHandle baseHandle;
+  TypeInfo typeInfo;
+  const TreeNode* templateNode = NULL;
+
+  if( OptionalString typeName = IsString(node, KEYNAME_TYPE) )
+  {
+    typeInfo = TypeRegistry::Get().GetTypeInfo( *typeName );
+
+    if( !typeInfo )
+    {
+      // a template name is also allowed inplace of the type name
+      OptionalChild templates = IsChild( root, KEYNAME_TEMPLATES);
+
+      if( templates )
+      {
+        if( OptionalChild isTemplate = IsChild( *templates, *typeName ) )
+        {
+          templateNode = &(*isTemplate);
+
+          if( OptionalString templateTypeName = IsString(*templateNode, KEYNAME_TYPE) )
+          {
+            typeInfo = TypeRegistry::Get().GetTypeInfo( *templateTypeName );
+          }
+        }
+      }
+    }
+  }
+
+  if(!typeInfo)
+  {
+    DALI_SCRIPT_WARNING("Cannot create Dali type from node '%s'\n", node.GetName());
+  }
+  else
+  {
+    baseHandle       = typeInfo.CreateInstance();
+    Handle handle    = Handle::DownCast(baseHandle);
+    Actor actor      = Actor::DownCast(handle);
+
+    if(handle)
+    {
+
+      DALI_SCRIPT_VERBOSE("Create:%s\n", typeInfo.GetName().c_str());
+
+#if defined(DEBUG_ENABLED)
+      if(handle)
+      {
+        DALI_SCRIPT_VERBOSE("  Is Handle Object=%d\n", (long*)handle.GetObjectPtr());
+        DALI_SCRIPT_VERBOSE("  Is Handle Property Count=%d\n", handle.GetPropertyCount());
+      }
+
+      if(actor)
+      {
+        DALI_SCRIPT_VERBOSE("  Is Actor id=%d\n", actor.GetId());
+      }
+
+      Toolkit::Control control  = Toolkit::Control::DownCast(handle);
+      if(control)
+      {
+        DALI_SCRIPT_VERBOSE("  Is Control id=%d\n", actor.GetId());
+      }
+#endif // DEBUG_ENABLED
+
+      if( templateNode )
+      {
+        ApplyProperties( root, *templateNode, handle, replacements );
+
+        if( OptionalChild actors = IsChild( *templateNode, KEYNAME_ACTORS ) )
+        {
+          for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
+          {
+            DoCreate( root, (*iter).second, actor, replacements );
+          }
+        }
+      }
+
+      if( actor )
+      {
+        // add children of all the styles
+        if( OptionalChild actors = IsChild( node, KEYNAME_ACTORS ) )
+        {
+          for( TreeConstIter iter = (*actors).CBegin(); iter != (*actors).CEnd(); ++iter )
+          {
+            DoCreate( root, (*iter).second, actor, replacements );
+          }
+        }
+
+        // apply style on top as they need the children to exist
+        ApplyAllStyleProperties( root, node, actor, replacements );
+
+        // then add to parent
+        if( parent )
+        {
+          parent.Add( actor );
+        }
+      }
+      else
+      {
+        ApplyProperties( root, node, handle, replacements );
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Cannot create handle from type '%s'\n", typeInfo.GetName().c_str());
+    }
+  }
+
+  return baseHandle;
+}
+
+void Builder::SetupTask( RenderTask& task, const TreeNode& node, const Replacement& constant )
+{
+  const Stage& stage = Stage::GetCurrent();
+  Layer root  = stage.GetRootLayer();
+
+  if( OptionalString s = constant.IsString( IsChild(node, "sourceActor") ) )
+  {
+    Actor actor = root.FindChildByName(*s);
+    if(actor)
+    {
+      task.SetSourceActor( actor );
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Cannot find source actor on stage for render task called '%s'\n", (*s).c_str() );
+    }
+  }
+
+  if( OptionalString s = constant.IsString( IsChild(node, "cameraActor") ) )
+  {
+    CameraActor actor = CameraActor::DownCast( root.FindChildByName(*s) );
+    if(actor)
+    {
+      task.SetCameraActor( actor );
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Cannot find camera actor on stage for render task called '%s'\n", (*s).c_str() );
+    }
+  }
+
+  if( OptionalString s = constant.IsString( IsChild(node, "screenToFrameBufferFunction") ) )
+  {
+    if("DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION" == *s)
+    {
+      task.SetScreenToFrameBufferFunction( RenderTask::DEFAULT_SCREEN_TO_FRAMEBUFFER_FUNCTION );
+    }
+    else if("FULLSCREEN_FRAMEBUFFER_FUNCTION" == *s)
+    {
+      task.SetScreenToFrameBufferFunction( RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("todo");
+    }
+  }
+
+  // other setup is via the property system
+  SetProperties( node, task, constant );
+}
+
+bool Builder::ApplyStyle( const std::string& styleName, Handle& handle, const Replacement& replacement )
+{
+  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
+
+  OptionalChild styles = IsChild( *mParser.GetRoot(), KEYNAME_STYLES );
+
+  std::string styleNameLower(styleName);
+  OptionalChild style  = IsChildIgnoreCase( *styles, styleNameLower );
+
+  if( styles && style )
+  {
+    ApplyAllStyleProperties( *mParser.GetRoot(), *style, handle, replacement );
+    return true;
+  }
+  else
+  {
+    return false;
+  }
+}
+
+void Builder::ApplyAllStyleProperties( const TreeNode& root, const TreeNode& node,
+                                       Dali::Handle& handle, const Replacement& constant )
+{
+  const char* styleName = node.GetName();
+
+  StylePtr style = Style::New();
+
+  StylePtr* matchedStyle = NULL;
+  if( styleName )
+  {
+    matchedStyle = mStyles.Find( styleName );
+    if( ! matchedStyle )
+    {
+      OptionalChild styleNodes = IsChild(root, KEYNAME_STYLES);
+      OptionalChild inheritFromNode = IsChild(node, KEYNAME_INHERIT);
+      if( !inheritFromNode )
+      {
+        inheritFromNode = IsChild( node, KEYNAME_STYLES );
+      }
+
+      if( styleNodes )
+      {
+        if( inheritFromNode )
+        {
+          TreeNodeList additionalStyleNodes;
+
+          CollectAllStyles( *styleNodes, *inheritFromNode, additionalStyleNodes );
+
+#if defined(DEBUG_ENABLED)
+          for(TreeNode::ConstIterator iter = (*inheritFromNode).CBegin(); iter != (*inheritFromNode).CEnd(); ++iter)
+          {
+            if( OptionalString styleName = IsString( (*iter).second ) )
+            {
+              DALI_SCRIPT_VERBOSE("Style Applied '%s'\n", (*styleName).c_str());
+            }
+          }
+#endif
+
+          // a style may have other styles, which has other styles etc so we apply in reverse by convention.
+          for(TreeNodeList::reverse_iterator iter = additionalStyleNodes.rbegin(); iter != additionalStyleNodes.rend(); ++iter)
+          {
+            RecordStyle( style, *(*iter), handle, constant );
+            ApplySignals( root, *(*iter), handle );
+            ApplyStylesByActor( root, *(*iter), handle, constant );
+          }
+        }
+
+        RecordStyle( style, node, handle, constant );
+        mStyles.Add( styleName, style ); // shallow copy
+        matchedStyle = &style;
+      }
+    }
+  }
+
+  if( matchedStyle )
+  {
+    StylePtr style( *matchedStyle );
+    Dictionary<Property::Map> instancedProperties;
+    style->ApplyVisualsAndPropertiesRecursively( handle, instancedProperties );
+  }
+  else // If there were no styles, instead set properties
+  {
+    SetProperties( node, handle, constant );
+  }
+  ApplySignals( root, node, handle );
+  ApplyStylesByActor( root, node, handle, constant );
+}
+
+void Builder::RecordStyle( StylePtr           style,
+                           const TreeNode&    node,
+                           Dali::Handle&      handle,
+                           const Replacement& replacements )
+{
+  // With repeated calls, accumulate inherited states, visuals and properties
+  // but override any with same name
+
+  for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
+  {
+    const TreeNode::KeyNodePair& keyValue = *iter;
+    std::string key( keyValue.first );
+    if( key == KEYNAME_STATES )
+    {
+      const TreeNode& states = keyValue.second;
+      if( states.GetType() != TreeNode::OBJECT )
+      {
+        DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", key.c_str() );
+        continue;
+      }
+
+      for( TreeNode::ConstIterator iter = states.CBegin(); iter != states.CEnd(); ++iter )
+      {
+        const TreeNode& stateNode = (*iter).second;
+        const char* stateName = stateNode.GetName();
+        if( stateNode.GetType() != TreeNode::OBJECT )
+        {
+          DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON object\n", stateName );
+          continue;
+        }
+
+        StylePtr* stylePtr = style->subStates.Find( stateName );
+        if( stylePtr )
+        {
+          StylePtr style(*stylePtr);
+          RecordStyle( style, stateNode, handle, replacements );
+        }
+        else
+        {
+          StylePtr subState = Style::New();
+          RecordStyle( subState, stateNode, handle, replacements );
+          style->subStates.Add( stateName, subState );
+        }
+      }
+    }
+    else if( key == KEYNAME_VISUALS )
+    {
+      for( TreeNode::ConstIterator iter = keyValue.second.CBegin(); iter != keyValue.second.CEnd(); ++iter )
+      {
+        // Each key in this table should be a property name matching a visual.
+        const TreeNode::KeyNodePair& visual = *iter;
+        Dali::Property::Value property(Property::MAP);
+        if( DeterminePropertyFromNode( visual.second, Property::MAP, property, replacements ) )
+        {
+          Property::Map* mapPtr = style->visuals.Find( visual.first );
+          if( mapPtr )
+          {
+            // Override existing visuals
+            mapPtr->Clear();
+            mapPtr->Merge( *property.GetMap() );
+          }
+          else
+          {
+            Property::Map* map = property.GetMap();
+            if( map )
+            {
+              style->visuals.Add( visual.first, *map );
+            }
+          }
+        }
+      }
+    }
+    else if( key == KEYNAME_ENTRY_TRANSITION )
+    {
+      RecordTransitionData( keyValue, style->entryTransition, replacements );
+    }
+    else if( key == KEYNAME_EXIT_TRANSITION )
+    {
+      RecordTransitionData( keyValue, style->exitTransition, replacements );
+    }
+    else if( key == KEYNAME_TRANSITIONS )
+    {
+      RecordTransitions( keyValue, style->transitions, replacements );
+    }
+    else if( key == KEYNAME_TYPE ||
+             key == KEYNAME_ACTORS ||
+             key == KEYNAME_SIGNALS ||
+             key == KEYNAME_STYLES ||
+             key == KEYNAME_MAPPINGS ||
+             key == KEYNAME_INHERIT )
+    {
+      continue;
+    }
+    else // It's a property
+    {
+      Property::Index index;
+      Property::Value value;
+      if( MapToTargetProperty( handle, key, keyValue.second, replacements, index, value ) )
+      {
+        Property::Value* existingValuePtr = style->properties.Find( index );
+        if( existingValuePtr != NULL )
+        {
+          *existingValuePtr = value; // Overwrite existing property.
+        }
+        else
+        {
+          style->properties.Add( index, value );
+        }
+      }
+    }
+  }
+}
+
+void Builder::RecordTransitions(
+  const TreeNode::KeyNodePair& keyValue,
+  Property::Array& value,
+  const Replacement& replacements )
+{
+  //@todo add new transitions to style.transitions
+  //      override existing transitions. A transition matches on target & property name
+  const TreeNode& node = keyValue.second;
+  if( node.GetType() == TreeNode::ARRAY )
+  {
+    Dali::Property::Value property(Property::ARRAY);
+    if( DeterminePropertyFromNode( node, Property::ARRAY, property, replacements ) )
+    {
+      value = *property.GetArray();
+    }
+  }
+  else if( node.GetType() == TreeNode::OBJECT )
+  {
+    Dali::Property::Value property(Property::MAP);
+    if( DeterminePropertyFromNode( node, Property::MAP, property, replacements ) )
+    {
+      Property::Array propertyArray;
+      propertyArray.Add( property );
+      value = propertyArray;
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING( "RecordStyle() Node \"%s\" is not a JSON array or object\n", keyValue.first );
+  }
+}
+
+void Builder::RecordTransitionData(
+  const TreeNode::KeyNodePair& keyValue,
+  Toolkit::TransitionData& transitionData,
+  const Replacement& replacements )
+{
+  const TreeNode& node = keyValue.second;
+  if( node.GetType() == TreeNode::ARRAY )
+  {
+    Dali::Property::Value property(Property::ARRAY);
+    if( DeterminePropertyFromNode( keyValue.second, Property::ARRAY, property, replacements ) )
+    {
+      transitionData = Toolkit::TransitionData::New( *property.GetArray() );
+    }
+  }
+  else if( node.GetType() == TreeNode::OBJECT )
+  {
+    Dali::Property::Value property(Property::MAP);
+    if( DeterminePropertyFromNode( keyValue.second, Property::MAP, property, replacements ) )
+    {
+      transitionData = Toolkit::TransitionData::New( *property.GetMap() );
+    }
+  }
+}
+
+
+// Set properties from node on handle.
+void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
+                               Dali::Handle& handle, const Replacement& constant )
+{
+  SetProperties( node, handle, constant );
+  ApplySignals( root, node, handle );
+}
+
+void Builder::ApplySignals(const TreeNode& root, const TreeNode& node, Dali::Handle& handle )
+{
+  Actor actor = Actor::DownCast(handle);
+  if( actor )
+  {
+    // add signals
+    SetupSignalAction( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
+    SetupPropertyNotification( mSlotDelegate.GetConnectionTracker(), root, node, actor, this );
+  }
+}
+
+
+// Appling by style helper
+// use FindChildByName() to apply properties referenced in KEYNAME_ACTORS in the node
+void Builder::ApplyStylesByActor(  const TreeNode& root, const TreeNode& node,
+                                   Dali::Handle& handle, const Replacement& constant )
+{
+  if( Dali::Actor actor = Dali::Actor::DownCast( handle ) )
+  {
+    if( const TreeNode* actors = node.GetChild( KEYNAME_ACTORS ) )
+    {
+      // in a style the actor subtree properties referenced by actor name
+      for( TreeConstIter iter = actors->CBegin(); iter != actors->CEnd(); ++iter )
+      {
+        Dali::Actor foundActor;
+
+        if( (*iter).first )
+        {
+          foundActor = actor.FindChildByName( (*iter).first );
+        }
+
+        if( !foundActor )
+        {
+          DALI_SCRIPT_VERBOSE("Cannot find actor in style application '%s'\n", (*iter).first);
+        }
+        else
+        {
+          DALI_SCRIPT_VERBOSE("Styles applied to actor '%s'\n", (*iter).first);
+          ApplyProperties( root, (*iter).second, foundActor, constant );
+        }
+      }
+    }
+  }
+}
+
+/*
+ * Sets the handle properties found in the tree node
+ */
+void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replacement& constant )
+{
+  if( handle )
+  {
+    for( TreeNode::ConstIterator iter = node.CBegin(); iter != node.CEnd(); ++iter )
+    {
+      const TreeNode::KeyNodePair& keyChild = *iter;
+
+      std::string key( keyChild.first );
+
+      // ignore special fields;
+      if( key == KEYNAME_TYPE ||
+          key == KEYNAME_ACTORS ||
+          key == KEYNAME_SIGNALS ||
+          key == KEYNAME_STYLES ||
+          key == KEYNAME_MAPPINGS ||
+          key == KEYNAME_INHERIT ||
+          key == KEYNAME_STATES ||
+          key == KEYNAME_VISUALS ||
+          key == KEYNAME_ENTRY_TRANSITION ||
+          key == KEYNAME_EXIT_TRANSITION ||
+          key == KEYNAME_TRANSITIONS )
+      {
+        continue;
+      }
+
+      Property::Index index;
+      Property::Value value;
+
+      bool mapped = MapToTargetProperty( handle, key, keyChild.second, constant, index, value );
+      if( mapped )
+      {
+        DALI_SCRIPT_VERBOSE("SetProperty '%s' Index=:%d Value Type=%d Value '%s'\n", key.c_str(), index, value.GetType(), PropertyValueToString(value).c_str() );
+
+        handle.SetProperty( index, value );
+      }
+
+      // Add custom properties
+      SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
+      SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
+
+    } // for property nodes
+  }
+  else
+  {
+    DALI_SCRIPT_WARNING("Style applied to empty handle\n");
+  }
+}
+
+bool Builder::MapToTargetProperty(
+  Handle&            propertyObject,
+  const std::string& key,
+  const TreeNode&    node,
+  const Replacement& constant,
+  Property::Index&   index,
+  Property::Value&   value )
+{
+  bool mapped = false;
+
+  index = propertyObject.GetPropertyIndex( key );
+  if( Property::INVALID_INDEX != index )
+  {
+    Property::Type type = propertyObject.GetPropertyType(index);
+
+    // if node.value is a mapping, get the property value from the "mappings" table
+    if( node.GetType() == TreeNode::STRING )
+    {
+      std::string mappingKey;
+      if( GetMappingKey( node.GetString(), mappingKey) )
+      {
+        OptionalChild mappingRoot = IsChild( mParser.GetRoot(), KEYNAME_MAPPINGS );
+        mapped = GetPropertyMap( *mappingRoot, mappingKey.c_str(), type, value );
+      }
+    }
+    if( ! mapped )
+    {
+      mapped = DeterminePropertyFromNode( node, type, value, constant );
+      if( ! mapped )
+      {
+        // Just determine the property from the node and if it's valid, let the property object handle it
+        DeterminePropertyFromNode( node, value, constant );
+        mapped = ( value.GetType() != Property::NONE );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("Key '%s' not found.\n", key.c_str());
+  }
+  return mapped;
+}
+
+bool Builder::GetPropertyMap( const TreeNode& mappingRoot, const char* theKey, Property::Type propertyType, Property::Value& value )
+{
+  KeyStack keyStack;
+  return RecursePropertyMap( mappingRoot, keyStack, theKey, propertyType, value );
+}
+
+bool Builder::RecursePropertyMap( const TreeNode& mappingRoot, KeyStack& keyStack, const char* theKey, Property::Type propertyType, Property::Value& value )
+{
+  Replacement replacer( mReplacementMap );
+  bool result = false;
+
+  keyStack.push_back( theKey );
+
+  for( TreeNode::ConstIterator iter = mappingRoot.CBegin(); iter != mappingRoot.CEnd(); ++iter )
+  {
+    std::string aKey( (*iter).first );
+    if( aKey.compare( theKey ) == 0 )
+    {
+      if( propertyType == Property::NONE )
+      {
+        DeterminePropertyFromNode( (*iter).second, value, replacer );
+        result = true;
+      }
+      else
+      {
+        result = DeterminePropertyFromNode( (*iter).second, propertyType, value, replacer );
+      }
+
+      if( result )
+      {
+        ConvertChildValue(mappingRoot, keyStack, value);
+      }
+      break;
+    }
+  }
+  keyStack.pop_back();
+
+  return result;
+}
+
+bool Builder::ConvertChildValue( const TreeNode& mappingRoot, KeyStack& keyStack, Property::Value& child )
+{
+  bool result = false;
+
+  switch( child.GetType() )
+  {
+    case Property::STRING:
+    {
+      std::string value;
+      if( child.Get( value ) )
+      {
+        std::string key;
+        if( GetMappingKey( value, key ) )
+        {
+          // Check key for cycles:
+          result=true;
+          for( KeyStack::iterator iter = keyStack.begin() ; iter != keyStack.end(); ++iter )
+          {
+            if( key.compare(*iter) == 0 )
+            {
+              // key is already in stack; stop.
+              DALI_LOG_WARNING("Detected cycle in stylesheet mapping table:%s\n", key.c_str());
+              child = Property::Value("");
+              result=false;
+              break;
+            }
+          }
+
+          if( result )
+          {
+            // The following call will overwrite the child with the value
+            // from the mapping.
+            RecursePropertyMap( mappingRoot, keyStack, key.c_str(), Property::NONE, child );
+            result = true;
+          }
+        }
+      }
+      break;
+    }
+
+    case Property::MAP:
+    {
+      Property::Map* map = child.GetMap();
+      if( map )
+      {
+        for( Property::Map::SizeType i=0; i < map->Count(); ++i )
+        {
+          Property::Value& child = map->GetValue(i);
+          ConvertChildValue(mappingRoot, keyStack, child);
+        }
+      }
+      break;
+    }
+
+    case Property::ARRAY:
+    {
+      Property::Array* array = child.GetArray();
+      if( array )
+      {
+        for( Property::Array::SizeType i=0; i < array->Count(); ++i )
+        {
+          Property::Value& child = array->GetElementAt(i);
+          ConvertChildValue(mappingRoot, keyStack, child);
+        }
+      }
+      break;
+    }
+
+    default:
+      // Ignore other types.
+      break;
+  }
+
+  return result;
+}
+
+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 );
+    }
+  }
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/builder-impl.h b/dali-toolkit/internal/builder/builder-impl.h
new file mode 100755 (executable)
index 0000000..7830e68
--- /dev/null
@@ -0,0 +1,412 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_H
+
+/*
+ * Copyright (c) 2019 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 <list>
+#include <map>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/builder-declarations.h>
+#include <dali-toolkit/internal/builder/style.h>
+
+// Warning messages usually displayed
+#define DALI_SCRIPT_WARNING(format, ...) \
+  DALI_LOG_WARNING("Script:" format, ## __VA_ARGS__)
+
+// Info messages are usually debug build
+#define DALI_SCRIPT_INFO(format, ...) \
+  DALI_LOG_INFO(Dali::Toolkit::Internal::gFilterScript, Debug::General, "Script:" format, ## __VA_ARGS__)
+
+// Info Verbose need to be swiched on in gFilterScript filter constructor (by default set to General)
+#define DALI_SCRIPT_VERBOSE(format, ...) \
+  DALI_LOG_INFO(Dali::Toolkit::Internal::gFilterScript, Debug::Verbose, "Script:" format, ## __VA_ARGS__)
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+  class TreeNode;
+}
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFilterScript;
+#endif
+
+class Builder;
+class Replacement;
+
+/**
+ * @copydoc Toolkit::Builder
+ */
+class Builder : public Dali::BaseObject
+{
+public:
+
+  Builder();
+
+  /**
+   * @copydoc Toolkit::Builder::LoadFromString
+   */
+  void LoadFromString( const std::string &data,
+                       Dali::Toolkit::Builder::UIFormat rep = Dali::Toolkit::Builder::JSON );
+
+  /**
+   * @copydoc Toolkit::Builder::AddConstants
+   */
+  void AddConstants( const Property::Map& map );
+
+  /**
+   * @copydoc Toolkit::Builder::AddConstant
+   */
+  void AddConstant( const std::string& key, const Property::Value& value );
+
+  /**
+   * @copydoc Toolkit::Builder::GetConfigurations
+   */
+  const Property::Map& GetConfigurations() const;
+
+  /**
+   * @copydoc Toolkit::Builder::GetConstants
+   */
+  const Property::Map& GetConstants() const;
+
+  /**
+   * @copydoc Toolkit::Builder::GetConstant
+   */
+  const Property::Value& GetConstant( const std::string& key ) const;
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName );
+   */
+  Animation CreateAnimation( const std::string& animationName );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string& animationName, const Property::Map& map );
+   */
+  Animation CreateAnimation( const std::string& animationName, const Property::Map& map );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string&,Dali::Actor);
+   */
+  Animation CreateAnimation( const std::string& animationName, Dali::Actor sourceActor );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateAnimation( const std::string&,const Property::Map&, Dali::Actor);
+   */
+  Animation CreateAnimation( const std::string& animationName, const Property::Map& map, Dali::Actor sourceActor );
+
+  /**
+   * @copydoc Toolkit::Builder::Create( const std::string& templateName );
+   */
+  BaseHandle Create( const std::string& templateName );
+
+  /**
+   * @copydoc Toolkit::Builder::Create( const std::string& templateName, const Property::Map& map );
+   */
+  BaseHandle Create( const std::string& templateName, const Property::Map& map );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateFromJson( const std::string& json );
+   */
+  BaseHandle CreateFromJson( const std::string& json );
+
+  /**
+   * @copydoc Toolkit::Builder::ApplyFromJson( Handle& handle, const std::string& json );
+   */
+  bool ApplyFromJson(  Handle& handle, const std::string& json );
+
+  /**
+   * @copydoc Toolkit::Builder::ApplyStyle
+   */
+  bool ApplyStyle( const std::string& styleName, Handle& handle );
+
+  /**
+   * Lookup the stylename in builder. If it's found in the parse tree,
+   * then return true.
+   * @param[in] styleName The style name to search for
+   * @return true if the stylename exists
+   */
+  bool LookupStyleName( const std::string& styleName );
+
+  /**
+   * Lookup the stylename in the recorded Styles - if it exists,
+   * performs a shallow copy to the passed in style and returns true.
+   * Otherwise it returns false.
+
+   * @param[in] styleName The stylename to search for
+   * @return A const pointer to the style object
+   */
+  const StylePtr GetStyle( const std::string& styleName );
+
+  /**
+   * @copydoc Toolkit::Builder::AddActors
+   */
+  void AddActors( Actor toActor );
+
+  /**
+   * @copydoc Toolkit::Builder::AddActors
+   */
+  void AddActors( const std::string &sectionName, Actor toActor );
+
+  /**
+   * @copydoc Toolkit::Builder::CreateRenderTask
+   */
+  void CreateRenderTask( const std::string &name );
+
+  /**
+   * @copydoc Toolkit::Builder::GetPath
+   */
+  Path GetPath( const std::string &name );
+
+  /**
+   * @copydoc Toolkit::Builder::GetPathConstrainer
+   */
+  Dali::PathConstrainer GetPathConstrainer( const std::string& name );
+
+  /*
+   * Check if a given constrainer is of type PathConstrainer
+   * @param[in] name The name of the constrainer
+   * @return True if constainer is of type PathConstrainer, False otherwise
+   *
+   */
+  bool IsPathConstrainer( const std::string& name );
+
+  /**
+   * @copydoc Toolkit::Builder::GetLinearConstrainer
+   */
+  Dali::LinearConstrainer GetLinearConstrainer( const std::string& name );
+
+  /*
+   * Check if a given constrainer is of type LinearConstrainer
+   * @param[in] name The name of the constrainer
+   * @return True if constainer is of type LinearConstrainer, False otherwise
+   *
+   */
+  bool IsLinearConstrainer( const std::string& name );
+
+  /**
+   * @copydoc Toolkit::Builder::QuitSignal
+   */
+  Toolkit::Builder::BuilderSignalType& QuitSignal();
+
+  /**
+   * Emits the quit signal
+   */
+  void EmitQuitSignal();
+
+
+protected:
+
+  virtual ~Builder();
+
+private:
+  typedef std::vector<const char*> KeyStack;
+  typedef std::vector< TreeNode::KeyNodePair > MappingsLut;
+  typedef struct{ std::string name; Dali::LinearConstrainer linearConstrainer; } LinearConstrainerEntry;
+  typedef std::vector<LinearConstrainerEntry> LinearConstrainerLut;
+  typedef struct{ std::string name; Dali::PathConstrainer pathConstrainer; } PathConstrainerEntry;
+  typedef std::vector<PathConstrainerEntry> PathConstrainerLut;
+  typedef std::map<const std::string, Path> PathLut;
+
+private:
+  // Undefined
+  Builder(const Builder&);
+
+  // Undefined
+  Builder& operator=(const Builder& rhs);
+
+  void LoadConstants( const TreeNode& root, Property::Map& intoMap );
+
+  void LoadConfiguration( const TreeNode& root, Property::Map& intoMap );
+
+  Animation CreateAnimation( const std::string& animationName,
+                             const Replacement& replacement,
+                             Dali::Actor        sourceActor );
+
+  BaseHandle Create( const std::string& templateName,
+                     const Replacement& constant );
+
+  BaseHandle DoCreate( const TreeNode&    root,
+                       const TreeNode&    node,
+                       Actor              parent,
+                       const Replacement& replacements );
+
+  void SetupTask( RenderTask&              task,
+                  const Toolkit::TreeNode& node,
+                  const Replacement&       replacement );
+
+  bool ApplyStyle( const std::string& styleName,
+                   Handle&            handle,
+                   const Replacement& replacement);
+
+  void ApplyAllStyleProperties( const TreeNode&    root,
+                                const TreeNode&    node,
+                                Dali::Handle&      handle,
+                                const Replacement& constant );
+
+  void RecordStyles( const char*        styleName,
+                     const TreeNode&    node,
+                     Dali::Handle&      handle,
+                     const Replacement& replacements );
+
+  void RecordStyle( StylePtr           style,
+                    const TreeNode&    node,
+                    Dali::Handle&      handle,
+                    const Replacement& replacements );
+
+  void RecordTransitions( const TreeNode::KeyNodePair& keyValue,
+                          Property::Array& transitions,
+                          const Replacement& replacements );
+
+  void RecordTransitionData( const TreeNode::KeyNodePair& keyNode,
+                             Toolkit::TransitionData& transitionData,
+                             const Replacement& replacements );
+
+  void ApplyProperties( const TreeNode&    root,
+                        const TreeNode&    node,
+                        Dali::Handle&      handle,
+                        const Replacement& constant );
+
+  void ApplySignals( const TreeNode& root,
+                     const TreeNode& node,
+                     Dali::Handle& handle );
+
+  void ApplyStylesByActor( const TreeNode&    root,
+                           const TreeNode&    node,
+                           Dali::Handle&      handle,
+                           const Replacement& constant );
+
+  void SetProperties( const TreeNode&    node,
+                      Handle&            handle,
+                      const Replacement& constant );
+
+  bool MapToTargetProperty( Handle&            propertyObject,
+                            const std::string& key,
+                            const TreeNode&    node,
+                            const Replacement& constant,
+                            Property::Index&   index,
+                            Property::Value&   value );
+
+  /**
+   * Find the key in the mapping table, if it's present, then generate
+   * a property value for it (of the given type if available),
+   * recursing as necessary, and stopping if any cycles are detected.
+   *
+   * @param[in] mappingRoot The JSON node containing the mappings
+   * @param[in] theKey The key to search for
+   * @param[in] propertyType The property type if known, or NONE
+   * @param[in,out] value The string value to test and write back to.
+   */
+  bool GetPropertyMap( const TreeNode&  mappingRoot,
+                       const char*      theKey,
+                       Property::Type   propertyType,
+                       Property::Value& value );
+
+  void SetCustomProperties( const TreeNode&      node,
+                            Handle&              handle,
+                            const Replacement&   constant,
+                            const std::string&   childName,
+                            Property::AccessMode accessMode );
+
+  /**
+   * Find the key in the mapping table, if it's present, then generate
+   * a property value for it (of the given type if available),
+   * recursing as necessary, and stopping if any cycles are detected.
+   *
+   * @param[in] mappingRoot The JSON node containing the mappings
+   * @param[in] theKey The key to search for
+   * @param[in,out] keyStack the stack of visited keys
+   * @param[in] propertyType The property type if known, or NONE
+   * @param[in,out] value The string value to test and write back to.
+   */
+  bool RecursePropertyMap( const TreeNode&  mappingRoot,
+                           KeyStack&        keyStack,
+                           const char*      theKey,
+                           Property::Type   propertyType,
+                           Property::Value& value );
+
+
+  /**
+   * Tests if the value is a string delimited by <>. If it is, then it attempts to
+   * change the value to the mapping from a matching key in the mappings table.
+   * @param[in] mappingRoot The JSON node containing the mappings
+   * @param[in,out] keyStack the stack of visited keys
+   * @param[in,out] value The string value to test and write back to.
+   * @return true if the value was converted, false otherwise.
+   */
+  bool ConvertChildValue( const TreeNode& mappingRoot,
+                          KeyStack& keyStack,
+                          Property::Value& value );
+
+private:
+  Toolkit::JsonParser                 mParser;
+  PathLut                             mPathLut;
+  PathConstrainerLut                  mPathConstrainerLut;
+  LinearConstrainerLut                mLinearConstrainerLut;
+  SlotDelegate<Builder>               mSlotDelegate;
+  Property::Map                       mReplacementMap;
+  Property::Map                       mConfigurationMap;
+  MappingsLut                         mCompleteMappings;
+  Dictionary<StylePtr>                mStyles; // State based styles
+  Toolkit::Builder::BuilderSignalType mQuitSignal;
+};
+
+} // namespace Internal
+
+inline Internal::Builder& GetImpl(Dali::Toolkit::Builder& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::Builder&>(handle);
+}
+
+inline const Internal::Builder& GetImpl(const Dali::Toolkit::Builder& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::Builder&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_H
diff --git a/dali-toolkit/internal/builder/builder-set-property.cpp b/dali-toolkit/internal/builder/builder-set-property.cpp
new file mode 100644 (file)
index 0000000..367c527
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+#include <dali-toolkit/internal/builder/replacement.h>
+#include <dali-toolkit/internal/builder/builder-set-property.h>
+#include <dali-toolkit/internal/helpers/color-conversion.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * A property value type can be forced when its unknown by a disambiguation convention in the json
+ * ie  "myarray": [1,2,3,4] ; would be a vector but
+ *     "myarray": {"typeCast":"array", "value":[1,2,3,4]} would be an array
+ * @param child The node whose string to search for a disambiguated type
+ * @param value The value to set
+ * @param replacement The user overriding constant map
+ * @return True if child contained a disambiguated string that could be converted.
+ */
+bool Disambiguated(const TreeNode& child,
+                   Dali::Property::Value& value,
+                   const Replacement& replacement )
+{
+  OptionalString childType = IsString( IsChild(child, "typeCast") );
+  OptionalChild childValue = IsChild(child, "value");
+
+  if( childType && childValue && (2 == child.Size()) )
+  {
+    // this case allows disambiguation but normally the type is guessed
+    // 2 == child.count() is an extra check as the user could have a user dictionary/map with
+    // type-cast and value keys. If they do then a work around is to add a bogus key to not run this case.
+    if(*childType == "boolean")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::BOOLEAN, value, replacement);
+    }
+    else if(*childType == "float")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::FLOAT, value, replacement);
+    }
+    else if(*childType == "vector2")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::VECTOR2, value, replacement);
+    }
+    else if(*childType == "vector3")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::VECTOR3, value, replacement);
+    }
+    else if(*childType == "vector4")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::VECTOR4, value, replacement);
+    }
+    else if(*childType == "rotation")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::ROTATION, value, replacement);
+    }
+    else if(*childType == "rect")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::RECTANGLE, value, replacement);
+    }
+    else if(*childType == "string")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::STRING, value, replacement);
+    }
+    else if(*childType == "map")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::MAP, value, replacement);
+    }
+    else if(*childType == "array")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::ARRAY, value, replacement);
+    }
+    else if(*childType == "extents")
+    {
+      return DeterminePropertyFromNode( *childValue, Dali::Property::EXTENTS, value, replacement);
+    }
+  }
+
+  // else we failed to disambiguate
+  return false;
+}
+
+
+bool DeterminePropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value)
+{
+  Replacement noReplacement;
+  return DeterminePropertyFromNode( node, type, value, noReplacement );
+}
+
+bool DeterminePropertyFromNode( const TreeNode& node, Property::Type type, Property::Value& value,
+                                const Replacement& replacer )
+{
+  bool done = false;
+
+  switch(type)
+  {
+    case Property::BOOLEAN:
+    {
+      if( OptionalBoolean v = replacer.IsBoolean(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::FLOAT:
+    {
+      if( OptionalFloat v = replacer.IsFloat(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::INTEGER:
+    {
+      if( OptionalInteger v = replacer.IsInteger(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::VECTOR2:
+    {
+      if( OptionalVector2 v = replacer.IsVector2(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::VECTOR3:
+    {
+      if( OptionalVector3 v = replacer.IsVector3(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::VECTOR4:
+    {
+      if( OptionalVector4 v = replacer.IsVector4(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      else if( OptionalString s = replacer.IsString(node) )
+      {
+        Vector4 color;
+        done = ConvertStringToColor( *s, color );
+        value = color;
+      }
+      else if( TreeNode::OBJECT == node.GetType() )
+      {
+        // check for "r", "g" and "b" child color component nodes
+        OptionalInteger r = replacer.IsInteger( IsChild(node, "r") );
+        OptionalInteger g = replacer.IsInteger( IsChild(node, "g") );
+        OptionalInteger b = replacer.IsInteger( IsChild(node, "b") );
+        if( r && g && b )
+        {
+          float red( (*r) * (1.0f/255.0f) );
+          float green( (*g) * (1.0f/255.0f) );
+          float blue( (*b) * (1.0f/255.0f) );
+          // check for optional "a" (alpha) node, default to fully opaque if it is not found.
+          float alpha( 1.0f );
+          OptionalInteger a = replacer.IsInteger( IsChild(node, "a") );
+          if( a )
+          {
+            alpha = (*a) * (1.0f/255.0f);
+          }
+          value = Vector4( red, green, blue, alpha );
+          done = true;
+        }
+      }
+      break;
+    }
+    case Property::MATRIX3:
+    {
+      if( OptionalMatrix3 v = replacer.IsMatrix3(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::MATRIX:
+    {
+      if( OptionalMatrix v = replacer.IsMatrix(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::RECTANGLE:
+    {
+      if( OptionalRect v = replacer.IsRect(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::ROTATION:
+    {
+      if(4 == node.Size())
+      {
+        if( OptionalVector4 ov = replacer.IsVector4(node) )
+        {
+          const Vector4& v = *ov;
+          // angle, axis as per spec
+          value = Quaternion(Radian(Degree(v[3])),
+                             Vector3(v[0],v[1],v[2]));
+          done = true;
+        }
+      }
+      else
+      {
+        // degrees Euler as per spec
+        if( OptionalVector3 v = replacer.IsVector3(node) )
+        {
+          value = Quaternion(Radian(Degree((*v).x)),
+                             Radian(Degree((*v).y)),
+                             Radian(Degree((*v).z)));
+          done = true;
+        }
+      }
+      break;
+    }
+    case Property::STRING:
+    {
+      if( OptionalString v = replacer.IsString(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::ARRAY:
+    {
+      if( replacer.IsArray( node, value ) )
+      {
+        done = true;
+      }
+      else if(node.Size())
+      {
+        value = Property::Value(Property::ARRAY);
+        Property::Array* array = value.GetArray();
+
+        unsigned int i = 0;
+        TreeNode::ConstIterator iter(node.CBegin());
+
+        if( array )
+        {
+          for( ; i < node.Size(); ++i, ++iter)
+          {
+            Property::Value childValue;
+            DeterminePropertyFromNode( (*iter).second, childValue, replacer );
+            array->PushBack( childValue );
+          }
+
+          done = ( array->Count() == node.Size() );
+        }
+      }
+      break;
+    }
+    case Property::MAP:
+    {
+      if( replacer.IsMap( node, value ) )
+      {
+        done = true;
+      }
+      else if(node.Size())
+      {
+        value = Property::Value(Property::MAP);
+        Property::Map* map = value.GetMap();
+
+        unsigned int i = 0;
+        TreeNode::ConstIterator iter(node.CBegin());
+
+        if( map )
+        {
+          for( ; i < node.Size(); ++i, ++iter)
+          {
+            Property::Value childValue;
+            DeterminePropertyFromNode( (*iter).second, childValue, replacer );
+            map->Insert( (*iter).first, childValue );
+          }
+
+          done = ( map->Count() == node.Size() );
+        }
+      }
+      break;
+    }
+    case Property::EXTENTS:
+    {
+      if( OptionalExtents v = replacer.IsExtents(node) )
+      {
+        value = *v;
+        done = true;
+      }
+      break;
+    }
+    case Property::NONE:
+    {
+      break;
+    }
+  } // switch type
+
+  return done;
+}
+
+void DeterminePropertyFromNode( const TreeNode& node, Property::Value& value )
+
+{
+  Replacement replacer;
+  DeterminePropertyFromNode( node, value, replacer );
+}
+
+void DeterminePropertyFromNode( const TreeNode& node, Property::Value& value,
+                                const Replacement& replacer )
+{
+
+  TreeNode::NodeType nodeType = node.GetType();
+
+  // Some values are ambiguous as we have no Property::Type but can be disambiguated in the JSON.
+  // Currently Rotations and Rectangle must always be disambiguated when a type isn't available
+  if( !Disambiguated( node, value, replacer ) )
+  {
+    bool done = false;
+
+    // Here, nodes are handled with the following precedence order:
+    // 1) Nodes with children, that have type ARRAY: Checked for array types including vectors and matrices.
+    // 2) Nodes without children, that do not have type ARRAY OR OBJECT: Checked for primitive types (int / float /etc).
+    // 3) If no match so far; If type is OBJECT: attempt to create as a Property::Map.
+    // 4) If no match still; Create as array.
+
+    // First handle nodes with children.
+    if( node.Size() )
+    {
+      // Handle array types.
+      if( nodeType == TreeNode::ARRAY )
+      {
+        // our current heuristic for deciding an array is actually a vector and not say a map
+        // is to check if the values are all floats
+        bool allNumbers = true;
+        for( TreeConstIter iter = node.CBegin(); iter != node.CEnd(); ++iter )
+        {
+          OptionalFloat checkFloat = IsFloat( ( *iter ).second );
+          if( !checkFloat )
+          {
+            allNumbers = false;
+            break;
+          }
+        }
+
+        if( allNumbers )
+        {
+          // prefer finding vectors over presuming composite Property::Array...
+          if( OptionalMatrix v = IsMatrix( node ) )
+          {
+            value = *v;
+            done = true;
+          }
+          else if( OptionalMatrix3 v = IsMatrix3( node ) )
+          {
+            value = *v;
+            done = true;
+          }
+          else if( OptionalVector4 v = IsVector4( node ) )
+          {
+            value = *v;
+            done = true;
+          }
+          else if( OptionalVector3 v = IsVector3( node ) )
+          {
+            value = *v;
+            done = true;
+          }
+          else if( OptionalVector2 v = IsVector2( node ) )
+          {
+            value = *v;
+            done = true;
+          }
+          else if( 4 == node.Size() )
+          {
+            if( OptionalVector4 v = IsVector4( node ) )
+            {
+              value = *v;
+              done = true;
+            }
+          }
+        }
+      }
+    } // if node.size()
+    else if( ( nodeType != TreeNode::OBJECT ) && ( nodeType != TreeNode::ARRAY ) )
+    {
+      // no children so either one of bool, float, integer, string
+      OptionalBoolean aBool    = replacer.IsBoolean( node );
+      OptionalInteger anInt    = replacer.IsInteger( node );
+      OptionalFloat   aFloat   = replacer.IsFloat( node );
+      OptionalString  aString  = replacer.IsString( node );
+
+      if( aBool )
+      {
+        // a bool is also an int but here we presume int
+        if( anInt )
+        {
+          value = *anInt;
+        }
+        else
+        {
+          value = *aBool;
+        }
+      }
+      else
+      {
+        // Note: These are both floats and strings
+        // {"value":"123"}
+        // {"value":123}
+        // This means we can't have a string with purely numeric content without disambiguation.
+        if( aFloat )
+        {
+          value = *aFloat;
+        }
+        else if( anInt )
+        {
+          value = *anInt;
+        }
+        else
+        {
+          value = *aString;
+        }
+      } // if aBool
+
+      done = true;
+    } // if( node.size() )
+
+    // If we have not created a value so far, attempt to create a Map or Array.
+    if( !done )
+    {
+      // We are guaranteed to have at least one entry as this has been checked already.
+      TreeConstIter containerIterator = node.CBegin();
+      TreeConstIter containerEnd = node.CEnd();
+
+      // The TreeNode::OBJECT type implies a Property::Map.
+      if( nodeType == TreeNode::OBJECT )
+      {
+        // We have a key, treat container as a Map.
+        value = Property::Value( Property::MAP );
+        Property::Map* map = value.GetMap();
+
+        if( map )
+        {
+          // Iterate through container to add all entries.
+          for( ; containerIterator != containerEnd; ++containerIterator )
+          {
+            Property::Value childValue;
+            DeterminePropertyFromNode( ( *containerIterator ).second, childValue, replacer );
+            map->Insert( ( *containerIterator ).first, childValue );
+          }
+        }
+      }
+      else
+      {
+        // We don't have a key, treat container as an array.
+        // Note: We don't check if the node type is array here, as we want to cope with unknowns by creating an array also.
+        // This is the fall-back if no other types could be created.
+        value = Property::Value( Property::ARRAY );
+        Property::Array* array = value.GetArray();
+
+        if( array )
+        {
+          // Iterate through container to add all entries.
+          for( ; containerIterator != containerEnd; ++containerIterator )
+          {
+            Property::Value childValue;
+            DeterminePropertyFromNode( ( *containerIterator ).second, childValue, replacer );
+            array->PushBack( childValue );
+          }
+        }
+      }
+    } // if !done
+  } // if !Disambiguated()
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/builder-set-property.h b/dali-toolkit/internal/builder/builder-set-property.h
new file mode 100644 (file)
index 0000000..a9ae431
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_SET_PROPERTY_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_SET_PROPERTY_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
+{
+
+/**
+ * Set a property value from a tree node.
+ * This function determines the type of the property from the format of the string in the node.
+ * This is not always possible and if the type cannot be determined then then the type will default to Array.
+ * @param node  The node string to convert from
+ * @param value The property value to set
+ */
+void DeterminePropertyFromNode( const TreeNode&  node,
+                                Property::Value& value );
+
+/**
+ * Set a property value from a tree node as DeterminePropertyFromNode() above
+ * This function determines the type of the property from the format of the string in the node.
+ * This is not always possible and if the type cannot be determined then then the type will default to Array.
+ * @param node  The node string to convert from
+ * @param value The property value to set
+ * @param replacement The overriding replacement map (if any)
+ */
+void DeterminePropertyFromNode( const TreeNode&    node,
+                                Property::Value&   value,
+                                const Replacement& replacement );
+
+/**
+ * Set a property value as the given type from a tree node.
+ * @param node The node string to convert from
+ * @param type The property type to convert to.
+ * @param value The property value to set
+ * @return true if the string could be converted to the correct type.
+ */
+bool DeterminePropertyFromNode( const TreeNode&  node,
+                                Property::Type   type,
+                                Property::Value& value );
+
+/**
+ * Set a property value as the given type from a tree node as DeterminePropertyFromNode() above
+ * @param node The node string to convert from
+ * @param type The property type to convert to.
+ * @param value The property value to set
+ * @param replacement The overriding replacement map (if any)
+ * @return true if the string could be converted to the correct type.
+ */
+bool DeterminePropertyFromNode( const TreeNode&    node,
+                                Property::Type     type,
+                                Property::Value&   value,
+                                const Replacement& replacement );
+
+
+} // Internal namespace
+} // Toolkit namespace
+} // Dali namespace
+
+#endif //DALI_TOOLKIT_INTERNAL_BUILDER_SET_PROPERTY_H
diff --git a/dali-toolkit/internal/builder/builder-signals.cpp b/dali-toolkit/internal/builder/builder-signals.cpp
new file mode 100755 (executable)
index 0000000..9138e9b
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/type-info.h>
+#include <dali/public-api/object/property-notification.h>
+
+#include <dali/integration-api/debug.h>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+extern Animation CreateAnimation( const TreeNode& child, Dali::Toolkit::Internal::Builder* const builder  );
+extern void DeterminePropertyFromNode( const TreeNode& node, Property::Value& value );
+}
+}
+}
+
+namespace
+{
+using namespace Dali;
+
+//
+// Signal Actions
+//
+
+// Action on child actor. The child is found by name
+struct ChildActorAction
+{
+  std::string actorName;
+  std::string actionName;
+  std::string childName;
+  Property::Map parameters;
+
+  void operator()(void)
+  {
+    Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
+
+    if(actor)
+    {
+      Actor child_actor = actor.FindChildByName(childName);
+
+      if(child_actor)
+      {
+        child_actor.DoAction(actionName, parameters);
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Could not find child by name '%s'\n", childName.c_str());
+      }
+    }
+  };
+};
+
+// Action to set a property
+struct PropertySetAction
+{
+  std::string actorName;
+  std::string propertyName;
+  Property::Value value;
+
+  void operator()(void)
+  {
+    Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
+
+    if(actor)
+    {
+      Property::Index idx = actor.GetPropertyIndex(propertyName);
+
+      if( idx != Property::INVALID_INDEX )
+      {
+        if( actor.GetPropertyType(idx) != value.GetType() )
+        {
+          DALI_SCRIPT_WARNING("Set property action has different type for property '%s'\n", propertyName.c_str());
+        }
+        else
+        {
+          actor.SetProperty( idx, value );
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Set property action cannot find property '%s'\n", propertyName.c_str());
+      }
+    }
+  };
+};
+
+// Generic action on a handle (Animation & Actor)
+struct GenericAction
+{
+  std::string actorName;
+  std::string actionName;
+  Property::Map parameters;
+
+  void operator()(void)
+  {
+    Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName(actorName);
+    if(actor)
+    {
+      actor.DoAction(actionName, parameters);
+    }
+
+  };
+};
+
+struct QuitAction
+{
+  Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder> builder;
+
+  void operator()(void)
+  {
+    builder->EmitQuitSignal();
+  }
+};
+
+// Delay an animation play; ie wait as its not on stage yet
+struct DelayedAnimationPlay
+{
+  OptionalChild                                         animNode;
+  Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
+
+  void operator()(void)
+  {
+    Animation anim = Toolkit::Internal::CreateAnimation(*animNode, builder.Get() );
+    if(anim)
+    {
+      anim.Play();
+    }
+  };
+};
+
+// Delay a pathConstrainer apply
+struct DelayedConstrainerApply
+{
+  std::string     constrainerName;
+
+  std::vector<std::string> targetActorNames;
+  std::vector<std::string> sourceActorNames;
+  std::vector<std::string> targetPropertyNames;
+  std::vector<std::string> sourcePropertyNames;
+  std::vector<Vector2>  ranges;
+  std::vector<Vector2>  wrapRanges;
+
+  Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
+
+  /*
+   * Helper function to get the parameters to apply each constraint
+   * @param[in] i i-essim element
+   * @param[out] tagetActor Target actor for the constraint
+   * @param[out] tagetPropertyIndex Target property index for the constraint
+   * @param[out] sourceActor Source actor for the constraint
+   * @param[out] sourcePropertyIndex Source property index for the constraint
+   */
+  bool GetApplyParameters( size_t i,
+                           Actor& targetActor, Property::Index& targetPropertyIndex,
+                           Actor& sourceActor, Property::Index& sourcePropertyIndex)
+  {
+
+    targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+    targetPropertyIndex = Property::INVALID_INDEX;
+    if(targetActor)
+    {
+      targetPropertyIndex = targetActor.GetPropertyIndex(targetPropertyNames[i]);
+      if( targetPropertyIndex ==  Property::INVALID_INDEX )
+      {
+        DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", targetPropertyNames[i].c_str(), targetActorNames[i].c_str() );
+        return false;
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
+      return false;
+    }
+
+
+    sourceActor = Stage::GetCurrent().GetRootLayer().FindChildByName(sourceActorNames[i]);
+    sourcePropertyIndex = Property::INVALID_INDEX;
+    if(sourceActor)
+    {
+      sourcePropertyIndex = sourceActor.GetPropertyIndex(sourcePropertyNames[i]);
+      if( sourcePropertyIndex ==  Property::INVALID_INDEX )
+      {
+        DALI_SCRIPT_WARNING("Property '%s' not founded in actor '%s'\n", sourcePropertyNames[i].c_str(), sourceActorNames[i].c_str() );
+        return false;
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Actor '%s' not founded\n", targetActorNames[i].c_str() );
+      return false;
+    }
+    return true;
+  }
+
+  void operator()(void)
+  {
+    Actor sourceActor, targetActor;
+    Property::Index targetPropertyIndex(Property::INVALID_INDEX);
+    Property::Index sourcePropertyIndex(Property::INVALID_INDEX);
+    size_t actorCount( targetActorNames.size() );
+    if( builder.Get()->IsPathConstrainer( constrainerName ))
+    {
+      PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
+      if( constrainer )
+      {
+        for(size_t i(0); i<actorCount; ++i )
+        {
+
+          if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
+          {
+            constrainer.Apply( Property(targetActor,targetPropertyIndex),
+                               Property(sourceActor,sourcePropertyIndex),
+                               ranges[i],
+                               wrapRanges[i]);
+          }
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+      }
+    }
+    else if( builder.Get()->IsLinearConstrainer( constrainerName ) )
+    {
+      Dali::LinearConstrainer constrainer( builder.Get()->GetLinearConstrainer(constrainerName));
+      if( constrainer )
+      {
+        for(size_t i(0); i<actorCount; ++i )
+        {
+
+          if( GetApplyParameters( i, targetActor, targetPropertyIndex, sourceActor, sourcePropertyIndex ) )
+          {
+            constrainer.Apply( Property(targetActor,targetPropertyIndex),
+                               Property(sourceActor,sourcePropertyIndex),
+                               ranges[i],
+                               wrapRanges[i]);
+          }
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
+    }
+  }
+};
+
+// Delay a pathConstrainer remove
+struct DelayedConstrainerRemove
+{
+  std::string     constrainerName;
+  std::vector<std::string> targetActorNames;
+  Dali::IntrusivePtr<Dali::Toolkit::Internal::Builder>  builder;
+
+  void operator()(void)
+  {
+    size_t actorCount( targetActorNames.size() );
+    if( builder.Get()->IsPathConstrainer( constrainerName ))
+    {
+      PathConstrainer constrainer = builder.Get()->GetPathConstrainer(constrainerName);
+      if( constrainer )
+      {
+        for(size_t i(0); i<actorCount; ++i )
+        {
+          Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+          if(targetActor)
+          {
+            constrainer.Remove( targetActor );
+          }
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+      }
+    }
+    else if(builder.Get()->IsLinearConstrainer( constrainerName ))
+    {
+      LinearConstrainer constrainer = builder.Get()->GetLinearConstrainer(constrainerName);
+      if( constrainer )
+      {
+        for(size_t i(0); i<actorCount; ++i )
+        {
+          Actor targetActor = Stage::GetCurrent().GetRootLayer().FindChildByName(targetActorNames[i]);
+          if(targetActor)
+          {
+            constrainer.Remove( targetActor );
+          }
+        }
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Constrainer %s not found\n", constrainerName.c_str());
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Constrainer %s is not of a valid type\n", constrainerName.c_str());
+    }
+  }
+};
+
+/*
+ * Gets Property::Value from child
+ */
+Property::Value GetPropertyValue(const TreeNode &child)
+{
+  size_t nChildren = child.Size();
+
+  Property::Value ret;
+
+  if(0 == nChildren)
+  {
+    // cast away unused return for static analyzers
+    static_cast<void>( Dali::Toolkit::Internal::DeterminePropertyFromNode( child, ret ) );
+  }
+  else if(1 == nChildren)
+  {
+    // {"property": {"quaternion":[1,2,3,4]} }
+    // {"property": {"angle":22, "axis": [1,2,3]} }
+
+    OptionalChild quaternion  = IsChild(&child, "quaternion");
+    OptionalChild axis        = IsChild(&child, "axis");
+    OptionalChild angle       = IsChild(&child, "angle");
+
+    if(quaternion)
+    {
+      ret = Property::Value(Quaternion(GetVector4(*quaternion)));
+    }
+    else if(axis && angle)
+    {
+      ret = Property::Value(AngleAxis(Degree(GetFloat(*angle)), GetVector3(*axis)));
+    }
+  }
+  else if(2 == nChildren)
+  {
+    // {"property": [1,2]}
+    ret = Property::Value(GetVector2(child));
+  }
+  else if(3 == nChildren)
+  {
+    // {"property": [1,2,3]}
+    ret = Property::Value(GetVector3(child));
+  }
+  else if(4 == nChildren)
+  {
+    // {"property": [1,2,3,4]}
+    ret = Property::Value(GetVector4(child));
+  }
+
+  return ret;
+}
+
+
+/*
+ * Gets Parmeter list from child
+ * params is be cleared before insertion
+ */
+void GetParameters(const TreeNode& child, Property::Map& params)
+{
+  if( OptionalChild c = IsChild(child, "parameters") )
+  {
+    const TreeNode& node = *c;
+
+    params.Clear();
+
+    for(TreeNode::ConstIterator iter(node.CBegin()); iter != node.CEnd(); ++iter)
+    {
+      params[ (*iter).first ] = GetPropertyValue( (*iter).second );
+    }
+  }
+}
+
+// Shim for the property notifcation signal
+template <typename T>
+struct PropertyNotifcationSignalShim
+{
+  T mFunctor;
+
+  PropertyNotifcationSignalShim(T& functor) : mFunctor(functor) {}
+
+  void operator()(PropertyNotification& /* source */)
+  {
+    mFunctor();
+  }
+};
+
+// Specializations for the different signal connection calls between actor & PropertyNotification
+template <typename T>
+struct SignalConnector {};
+
+// Actor specialization
+template <>
+struct SignalConnector<Actor> {
+  Actor& mActor;
+  ConnectionTracker* mTracker;
+  const std::string& mName;
+
+  SignalConnector<Actor>(ConnectionTracker* tracker, Actor& actor, const std::string& name)
+  : mActor(actor), mTracker(tracker), mName(name) {}
+
+  template <typename T>
+  void Connect(T& functor)
+  {
+    mActor.ConnectSignal( mTracker, mName, functor);
+  }
+};
+
+// PropertyNotification specialization
+template <>
+struct SignalConnector<PropertyNotification>
+{
+  PropertyNotification& mNotification;
+  ConnectionTracker* mTracker;
+
+  SignalConnector<PropertyNotification>(ConnectionTracker* tracker, PropertyNotification &notification)
+  : mNotification(notification), mTracker(tracker) {}
+
+  template <typename T>
+  void Connect(T& functor)
+  {
+    mNotification.NotifySignal().Connect( mTracker, PropertyNotifcationSignalShim<T>(functor) );
+  }
+};
+
+/**
+ * Set an action functor on a signal
+ */
+template <typename T>
+void SetActionOnSignal(const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder, SignalConnector<T>& connector)
+{
+  OptionalString childActorName(IsString( IsChild(&child, "childActor")) );
+  OptionalString actorName(IsString( IsChild(&child, "actor")) );
+  OptionalString propertyName(IsString( IsChild(&child, "property")) );
+  OptionalChild  valueChild( IsChild(&child, "value") );
+
+  OptionalString actionName = IsString( IsChild(&child, "action") );
+  DALI_ASSERT_ALWAYS(actionName && "Signal must have an action");
+
+  if(childActorName)
+  {
+    ChildActorAction action;
+    action.actorName       = *actorName;
+    action.childName       = *childActorName;
+    action.actionName      = *actionName;
+    GetParameters(child, action.parameters);
+    connector.Connect( action );
+  }
+  else if(actorName)
+  {
+    if(propertyName && valueChild && ("set" == *actionName) )
+    {
+      PropertySetAction action;
+      action.actorName       = *actorName;
+      action.propertyName    = *propertyName;
+      // actor may not exist yet so we can't check the property type
+      Dali::Toolkit::Internal::DeterminePropertyFromNode( *valueChild, action.value );
+      connector.Connect( action );
+    }
+    else
+    {
+      GenericAction action;
+      action.actorName       = *actorName;
+      action.actionName      = *actionName;
+      GetParameters(child, action.parameters);
+      connector.Connect( action );
+    }
+  }
+  else if("quit" == *actionName)
+  {
+    QuitAction action;
+    action.builder = builder;
+    connector.Connect( action );
+  }
+  else if("play" == *actionName)
+  {
+    OptionalChild animations     = IsChild( root, "animations" );
+    OptionalString animationName = IsString( IsChild(child, "animation") );
+    if( animations && animationName )
+    {
+      if( OptionalChild animNode = IsChild(*animations, *animationName) )
+      {
+        DelayedAnimationPlay action;
+        action.animNode = animNode;
+        action.builder = builder;
+        // @todo; put constants into the map
+        connector.Connect( action );
+      }
+      else
+      {
+        DALI_SCRIPT_WARNING("Cannot find animation '%s'\n", (*animationName).c_str());
+      }
+    }
+    else
+    {
+      DALI_SCRIPT_WARNING("Cannot find animations section\n");
+    }
+  }
+  else if("applyConstraint" == *actionName )
+  {
+    OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
+    if( !constrainerName )
+    {
+      DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
+    }
+    else
+    {
+      DelayedConstrainerApply action;
+      action.constrainerName = *constrainerName;
+      action.builder = builder;
+      OptionalChild propertiesNode = IsChild(child, "properties");
+      if(propertiesNode)
+      {
+        const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
+        for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
+        {
+          const TreeNode::KeyNodePair& pKeyChild = *iter;
+          OptionalString sourceActorName(IsString(IsChild(pKeyChild.second, "source")));
+          if(!sourceActorName)
+          {
+            DALI_SCRIPT_WARNING("Need to specify source actor to apply the constraint\n");
+            continue;
+          }
+          OptionalString sourcePropertyName( IsString( IsChild(pKeyChild.second, "sourceProperty" ) ) );
+          if(!sourcePropertyName)
+          {
+            DALI_SCRIPT_WARNING("Need to specify source property to apply the constraint\n");
+            continue;
+          }
+
+          OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
+          if(!targetActorName)
+          {
+            DALI_SCRIPT_WARNING("Need to specify target actor to apply the constraint\n");
+            continue;
+          }
+
+          OptionalString targetPropertyName( IsString( IsChild(pKeyChild.second, "targetProperty" ) ) );
+          if(!targetPropertyName)
+          {
+            DALI_SCRIPT_WARNING("Need to specify target property name to apply the constraint\n");
+            continue;
+          }
+
+          OptionalVector2 range(IsVector2(IsChild(pKeyChild.second, "range")));
+          if(!range)
+          {
+            DALI_SCRIPT_WARNING("Constrainer range not specified\n");
+            continue;
+          }
+
+          Vector2 wrap(-std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
+          OptionalVector2 wrapRange(IsVector2(IsChild(pKeyChild.second, "wrap")));
+          if(wrapRange)
+          {
+            wrap = *wrapRange;
+          }
+
+          action.sourceActorNames.push_back(*sourceActorName);
+          action.sourcePropertyNames.push_back(*sourcePropertyName);
+          action.targetActorNames.push_back(*targetActorName);
+          action.targetPropertyNames.push_back(*targetPropertyName);
+          action.ranges.push_back(*range);
+          action.wrapRanges.push_back(wrap);
+        }
+        connector.Connect(action);
+      }
+    }
+  }
+  else if("removeConstraints" == *actionName )
+  {
+    OptionalString constrainerName = IsString( IsChild(child, "constrainer") );
+    if( !constrainerName )
+    {
+      DALI_SCRIPT_WARNING("Need to specify a constrainer\n");
+    }
+    else
+    {
+
+      DelayedConstrainerRemove action;
+      action.constrainerName = *constrainerName;
+      action.builder = builder;
+      OptionalChild propertiesNode = IsChild(child, "properties");
+      if(propertiesNode)
+      {
+        const TreeNode::ConstIterator endIter = (*propertiesNode).CEnd();
+        for( TreeNode::ConstIterator iter = (*propertiesNode).CBegin(); endIter != iter; ++iter )
+        {
+          const TreeNode::KeyNodePair& pKeyChild = *iter;
+          OptionalString targetActorName(IsString(IsChild(pKeyChild.second, "target")));
+          if(targetActorName)
+          {
+            action.targetActorNames.push_back(*targetActorName);
+          }
+          else
+          {
+            DALI_SCRIPT_WARNING("Need to specify target actor to remove the constraint\n");
+            continue;
+          }
+        }
+      }
+      connector.Connect(action);
+    }
+  }
+  else
+  {
+    // no named actor; presume self
+    GenericAction action;
+    action.actorName       = actor.GetName();
+    action.actionName      = *actionName;
+    GetParameters(child, action.parameters);
+    connector.Connect( action );
+  }
+}
+
+
+/**
+ * Get a notification condition argument0 as 'arg0' 'value' or 'min'
+ */
+float GetConditionArg0(const TreeNode &child)
+{
+  OptionalFloat f = IsFloat( IsChild(child, "arg0") );
+  // allowing some human preferable alternatives
+  if(!f)
+  {
+    f = IsFloat( IsChild(child, "value") );
+  }
+  if(!f)
+  {
+    f = IsFloat( IsChild(child, "min") );
+  }
+
+  DALI_ASSERT_ALWAYS(f && "Notification condition for arg0 not specified");
+
+  return *f;
+}
+
+/**
+ * Get a notification condition argument1 as 'arg1' or 'max'
+ */
+float GetConditionArg1(const TreeNode &child)
+{
+  OptionalFloat f = IsFloat( IsChild(child, "arg1") );
+  // allowing some human preferable alternatives
+  if(!f)
+  {
+    f = IsFloat( IsChild(child, "max") );
+  }
+
+  DALI_ASSERT_ALWAYS(f && "Notification condition for arg1 not specified");
+
+  return *f;
+}
+
+
+
+}; // anon namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+Actor SetupSignalAction(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
+Actor SetupPropertyNotification(const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder );
+
+/**
+ * Setup signals and actions on an actor
+ */
+Actor SetupSignalAction(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
+{
+  DALI_ASSERT_ALWAYS(actor);
+
+  if(OptionalChild signalsChild = IsChild(child, "signals"))
+  {
+    const TreeNode& signalsNode = *signalsChild;
+    const TreeConstIter endIter = signalsNode.CEnd();
+    for( TreeConstIter iter = signalsNode.CBegin(); endIter != iter; ++iter )
+    {
+      const TreeNode::KeyNodePair& key_child = *iter;
+
+      DALI_SCRIPT_INFO("  Creating Signal for: %s\n", actor.GetName().c_str());
+
+      OptionalString name( IsString( IsChild( key_child.second, "name")) );
+      DALI_ASSERT_ALWAYS(name && "Signal must have a name");
+
+      SignalConnector<Actor> connector(tracker, actor, *name);
+      SetActionOnSignal(root, key_child.second, actor, builder, connector);
+    }
+  }
+
+  return actor;
+}
+
+/**
+ * Setup Property notifications for an actor
+ */
+Actor SetupPropertyNotification(ConnectionTracker* tracker, const TreeNode &root, const TreeNode &child, Actor actor, Dali::Toolkit::Internal::Builder* const builder )
+{
+  DALI_ASSERT_ALWAYS(actor);
+
+  if(OptionalChild notificationsChild = IsChild(child,"notifications"))
+  {
+    const TreeNode& notificationsNode = *notificationsChild;
+    const TreeNode::ConstIterator endIter = notificationsNode.CEnd();
+    for( TreeNode::ConstIterator iter = notificationsNode.CBegin(); endIter != iter; ++iter )
+    {
+      const TreeNode::KeyNodePair& key_child = *iter;
+
+      OptionalString prop(IsString( IsChild(key_child.second, "property")) );
+      DALI_ASSERT_ALWAYS(prop && "Notification signal must specify a property");
+
+      Property::Index prop_index = actor.GetPropertyIndex(*prop);
+      DALI_ASSERT_ALWAYS(prop_index != Property::INVALID_INDEX && "Notification signal specifies an unknown property");
+
+      OptionalString cond(IsString( IsChild(key_child.second, "condition")));
+      DALI_ASSERT_ALWAYS(cond && "Notification signal must specify a condition");
+
+      if("False" == *cond)
+      {
+        PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
+                                                                           LessThanCondition(1.f) );
+        SignalConnector<PropertyNotification> connector(tracker, notification);
+        SetActionOnSignal(root, key_child.second, actor, builder, connector);
+      }
+      else if("LessThan" == *cond)
+      {
+        PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
+                                                                           LessThanCondition(GetConditionArg0(key_child.second)) );
+        SignalConnector<PropertyNotification> connector(tracker, notification);
+        SetActionOnSignal(root, key_child.second, actor, builder, connector);
+      }
+      else if("GreaterThan" == *cond)
+      {
+        PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
+                                                                           GreaterThanCondition(GetConditionArg0(key_child.second)) );
+        SignalConnector<PropertyNotification> connector(tracker, notification);
+        SetActionOnSignal(root, key_child.second, actor, builder, connector);
+      }
+      else if("Inside" == *cond)
+      {
+        PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
+                                                                           InsideCondition(GetConditionArg0(key_child.second),
+                                                                           GetConditionArg1(key_child.second)) );
+        SignalConnector<PropertyNotification> connector(tracker, notification);
+        SetActionOnSignal(root, key_child.second, actor, builder, connector);
+      }
+      else if("Outside" == *cond)
+      {
+        PropertyNotification notification = actor.AddPropertyNotification( actor.GetPropertyIndex(*prop),
+                                                                           OutsideCondition(GetConditionArg0(key_child.second),
+                                                                           GetConditionArg1(key_child.second)) );
+        SignalConnector<PropertyNotification> connector(tracker, notification);
+        SetActionOnSignal(root, key_child.second, actor, builder, connector);
+      }
+      else
+      {
+        DALI_ASSERT_ALWAYS(!"Unknown condition");
+      }
+    }
+  } // if notifications
+
+  return actor;
+
+} // AddPropertyNotification
+
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/dictionary.h b/dali-toolkit/internal/builder/dictionary.h
new file mode 100644 (file)
index 0000000..88095eb
--- /dev/null
@@ -0,0 +1,275 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
+
+/*
+ * Copyright (c) 2017 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/common/vector-wrapper.h>
+#include <algorithm>
+
+namespace Dali
+{
+extern bool CaseInsensitiveStringCompare( const std::string& a, const std::string& b );
+
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * The Dictionary template class enables a means of storing key-value
+ * pairs where the keys are strings and the value can be a complex
+ * type.
+ *
+ * It enables lookup of keys via case-insensitive match.
+ */
+
+
+typedef std::vector<std::string> DictionaryKeys;
+inline void Merge( DictionaryKeys& toDict, const DictionaryKeys& fromDict )
+{
+  for( DictionaryKeys::const_iterator fromIter = fromDict.begin(); fromIter != fromDict.end(); ++fromIter )
+  {
+    const std::string& fromKey = (*fromIter);
+    DictionaryKeys::iterator toIter = std::find( toDict.begin(), toDict.end(), fromKey );
+    if( toIter == toDict.end() )
+    {
+      toDict.push_back( fromKey );
+    }
+  }
+}
+
+
+template<typename EntryType>
+class Dictionary
+{
+private:
+  /**
+   * Element is a key-value pair
+   */
+  struct Element
+  {
+    std::string key;
+    EntryType entry;
+    Element( const std::string&name, EntryType entry )
+    : key( name ),
+      entry( entry )
+    {
+    }
+  };
+  typedef std::vector<Element> Elements;
+  Elements container;
+
+public:
+  /**
+   * Only allow const iteration over the dictionary
+   */
+  typedef typename Elements::const_iterator iterator;
+
+  /**
+   * Constructor
+   */
+  Dictionary<EntryType>()
+  {
+  }
+
+  /**
+   * Add a key value pair to the dictionary.
+   * If the entry does not already exist, add it to the dictionary
+   * using a shallow copy
+   */
+  bool Add( const std::string& name, const EntryType& entry )
+  {
+    for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter )
+    {
+      if( iter->key == name )
+      {
+        return false;
+      }
+    }
+    container.push_back( Element(name, entry) );
+    return true;
+  }
+
+  /**
+   * Add a key-value pair to the dictionary
+   * If the entry does not already exist, add it to the dictionary
+   * (shallow copy)
+   */
+  bool Add( const char* name, const EntryType& entry )
+  {
+    bool result=false;
+    if( name != NULL )
+    {
+      std::string theName(name);
+      result=Add(theName, entry);
+    }
+    return result;
+  }
+
+  /**
+   * Remove a key value pair from the dictionary.
+   */
+  void Remove( const std::string& name )
+  {
+    for( typename Elements::iterator iter = container.begin(); iter != container.end(); ++iter )
+    {
+      if( iter->key == name )
+      {
+        container.erase( iter );
+        break;
+      }
+    }
+  }
+
+  /**
+   * Remove a key value pair from the dictionary.
+   */
+  void Remove( const char* name )
+  {
+    if( name != NULL )
+    {
+      std::string theName(name);
+      Remove(theName);
+    }
+  }
+
+  void Merge( const Dictionary<EntryType>& dictionary )
+  {
+    for( typename Elements::const_iterator fromIter = dictionary.container.begin(); fromIter != dictionary.container.end(); ++fromIter )
+    {
+      bool found=false;
+      for( typename Elements::iterator toIter = container.begin(); toIter != container.end(); ++toIter )
+      {
+        if( fromIter->key == toIter->key )
+        {
+          found=true;
+          toIter->entry = fromIter->entry;
+        }
+      }
+      if( !found )
+      {
+        container.push_back( Element(fromIter->key, fromIter->entry) );
+      }
+    }
+  }
+
+  /**
+   * Find the element in the dictionary pointed at by key, and
+   * insensitive search, and return a const pointer to it, or NULL
+   */
+  const EntryType* FindConst( const std::string& key ) const
+  {
+    if( ! key.empty() )
+    {
+      for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+      {
+        if( Dali::CaseInsensitiveStringCompare(iter->key, key ))
+        {
+          const EntryType* result = &(iter->entry);
+          return result;
+        }
+      }
+    }
+    return NULL;
+  }
+
+  /**
+   * Find the element in the dictionary pointed at by key using a case
+   * insensitive search, and return a non-const pointer to it, or NULL
+   */
+  EntryType* Find( const std::string& key ) const
+  {
+    EntryType* result = NULL;
+    if( ! key.empty() )
+    {
+      for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+      {
+        if( Dali::CaseInsensitiveStringCompare(iter->key, key ))
+        {
+          // Const cast because of const_iterator. const_iterator because, STL.
+          result = const_cast<EntryType*>(&(iter->entry));
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Find the element in the dictionary pointed at by key using a case
+   * insensitive search, and return a const pointer to it, or NULL
+   */
+  const EntryType* FindConst( const char* key ) const
+  {
+    if( key != NULL )
+    {
+      std::string theKey(key);
+      return FindConst( theKey );
+    }
+    return NULL;
+  }
+
+  /**
+   * Find the element in the dictionary pointed at by key using a case
+   * insensitive search, and return a non-const pointer to it, or NULL
+   */
+  EntryType* Find( const char* key ) const
+  {
+    if( key != NULL )
+    {
+      std::string theKey(key);
+      return Find( theKey );
+    }
+    return NULL;
+  }
+  /**
+   * Return an iterator pointing at the first entry in the dictionary
+   */
+  typename Elements::const_iterator Begin() const
+  {
+    return container.begin();
+  }
+
+  /**
+   * Return an iterator pointing past the last entry in the dictionary
+   */
+  typename Elements::const_iterator End() const
+  {
+    return container.end();
+  }
+
+  void GetKeys( DictionaryKeys& keys ) const
+  {
+    keys.clear();
+    for( typename Elements::const_iterator iter = container.begin(); iter != container.end(); ++iter )
+    {
+      keys.push_back( (*iter).key );
+    }
+  }
+
+  void Clear()
+  {
+    container.clear();
+  }
+};
+
+
+
+}//Internal
+}//Toolkit
+}//Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_DICTIONARY_H
diff --git a/dali-toolkit/internal/builder/json-parser-impl.cpp b/dali-toolkit/internal/builder/json-parser-impl.cpp
new file mode 100644 (file)
index 0000000..fdec738
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/builder/json-parser-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/tree-node-manipulator.h>
+#include <dali-toolkit/internal/builder/json-parser-state.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const char ERROR_DESCRIPTION_NONE[] = "No Error";
+
+template <typename IteratorType,typename EndIteratorType>
+inline IteratorType Advance(IteratorType& iter, EndIteratorType& end, int n)
+{
+  for(int i =0; i < n; ++i)
+  {
+    ++iter;
+  }
+  return iter;
+}
+
+} // anon namespace
+
+
+JsonParser::JsonParser()
+  : mRoot(NULL),
+    mErrorDescription(ERROR_DESCRIPTION_NONE),
+    mErrorPosition(0),
+    mErrorLine(0),
+    mErrorColumn(0),
+    mNumberOfChars(0),
+    mNumberOfNodes(0)
+{
+}
+
+JsonParser::JsonParser(const TreeNode& tree)
+  : mRoot(NULL),
+    mErrorDescription(ERROR_DESCRIPTION_NONE),
+    mErrorPosition(0),
+    mErrorLine(0),
+    mErrorColumn(0),
+    mNumberOfChars(0),
+    mNumberOfNodes(0)
+{
+  mRoot = TreeNodeManipulator::Copy( tree, mNumberOfNodes, mNumberOfChars );
+
+  mSources.push_back( VectorChar( (sizeof(char) * mNumberOfChars) ) );
+
+  VectorChar& buffer = mSources.back();
+
+  VectorCharIter start = buffer.begin();
+
+  TreeNodeManipulator modify(mRoot);
+
+  modify.MoveStrings(start, buffer.end());
+}
+
+JsonParser::~JsonParser()
+{
+  if(mRoot)
+  {
+    TreeNodeManipulator modify(mRoot);
+    modify.RemoveChildren();
+    delete mRoot;
+    mRoot = NULL;
+  }
+}
+
+bool JsonParser::Parse(const std::string& source)
+{
+  mSources.push_back( VectorChar(source.begin(), source.end()) );
+
+  JsonParserState parserState(mRoot);
+
+  if( parserState.ParseJson(mSources.back()) )
+  {
+    mRoot = parserState.GetRoot();
+
+    mNumberOfChars += parserState.GetParsedStringSize();
+    mNumberOfNodes += parserState.GetCreatedNodeCount();
+
+    mErrorDescription   = ERROR_DESCRIPTION_NONE;
+    mErrorPosition      = 0;
+    mErrorLine          = 0;
+    mErrorColumn        = 0;
+  }
+  else
+  {
+    mRoot = NULL;
+
+    mErrorDescription   = parserState.GetErrorDescription();
+    if(NULL == mErrorDescription)
+    {
+      mErrorDescription = ERROR_DESCRIPTION_NONE;
+    }
+    mErrorPosition      = parserState.GetErrorPosition();
+    mErrorLine          = parserState.GetErrorLineNumber();
+    mErrorColumn        = parserState.GetErrorColumn();
+  }
+
+  return mRoot != NULL;
+}
+
+
+const TreeNode* JsonParser::GetRoot() const
+{
+  return mRoot;
+}
+
+bool JsonParser::ParseError() const
+{
+  return mErrorDescription != ERROR_DESCRIPTION_NONE;
+}
+
+int JsonParser::GetErrorPosition() const
+{
+  return mErrorPosition;
+}
+
+std::string JsonParser::GetErrorDescription() const
+{
+  return std::string(mErrorDescription);
+}
+
+int JsonParser::GetErrorLineNumber() const
+{
+  return mErrorLine;
+}
+
+int JsonParser::GetErrorColumn() const
+{
+  return mErrorColumn;
+}
+
+void JsonParser::Pack(void)
+{
+  mSources.push_back( VectorChar( (sizeof(char) * mNumberOfChars) ) );
+
+  VectorChar& buffer = mSources.back();
+
+  VectorCharIter start = buffer.begin();
+
+  TreeNodeManipulator modify(mRoot);
+
+  modify.MoveStrings(start, buffer.end());
+
+  mSources.erase( mSources.begin(), --mSources.end() );
+}
+
+void JsonParser::Write(std::ostream& output, int indent) const
+{
+  TreeNodeManipulator modify(mRoot);
+  modify.Write(output, indent);
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/json-parser-impl.h b/dali-toolkit/internal/builder/json-parser-impl.h
new file mode 100644 (file)
index 0000000..21992e9
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef DALI_JSON_PARSER_IMPL_H
+#define DALI_JSON_PARSER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <list>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/*
+ * Parses JSON
+ */
+class JsonParser : public BaseObject
+{
+public:
+  /*
+   * @copydoc Toolkit::JsonParser::JsonParser()
+   */
+  JsonParser();
+
+  /*
+   * @copydoc Toolkit::JsonParser::JsonParser(const TreeNode& tree)
+   */
+  explicit JsonParser(const TreeNode& tree);
+
+  /*
+   */
+  ~JsonParser();
+
+  /*
+   * @copydoc Toolkit::JsonParser::Parse()
+   */
+  bool Parse(const std::string& source);
+
+  /*
+   * @copydoc Toolkit::JsonParser::Pack()
+   */
+  void Pack(void);
+
+  /*
+   * @copydoc Toolkit::JsonParser::GetRoot()
+   */
+  const TreeNode* GetRoot() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::ParseError()
+   */
+  bool ParseError() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::GetErrorPosition()
+   */
+  int GetErrorPosition() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::GetErrorDescription()
+   */
+  std::string GetErrorDescription() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::GetErrorLineNumber()
+   */
+  int GetErrorLineNumber() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::GetErrorColumn()
+   */
+  int GetErrorColumn() const;
+
+  /*
+   * @copydoc Toolkit::JsonParser::Write()
+   */
+  void Write(std::ostream& output, int indent) const;
+
+private:
+  typedef std::vector<char> VectorChar;
+  typedef VectorChar::iterator VectorCharIter;
+
+  typedef std::list<VectorChar> SourceContainer;
+  typedef std::list<VectorChar>::iterator SourceContainerIter;
+
+  JsonParser(JsonParser &);
+  JsonParser& operator=(const JsonParser&);
+
+  SourceContainer mSources;         ///< List of strings from Parse() merge operations
+
+  TreeNode* mRoot;                  ///< Tree root
+
+  const char *mErrorDescription;    ///< Last parse error description
+  int mErrorPosition;               ///< Last parse error position
+  int mErrorLine;                   ///< Last parse error line
+  int mErrorColumn;                 ///< Last parse error column
+
+  int mNumberOfChars;               ///< The size of string data for all nodes
+  int mNumberOfNodes;               ///< Node count
+
+};
+
+} // namespace Internal
+
+
+inline const Internal::JsonParser& GetImplementation(const Toolkit::JsonParser& parser)
+{
+  DALI_ASSERT_ALWAYS( parser && "JsonParser handle is empty" );
+
+  const BaseObject& handle = parser.GetBaseObject();
+
+  return static_cast<const Internal::JsonParser&>(handle);
+}
+
+
+inline Internal::JsonParser& GetImplementation(Toolkit::JsonParser& parser)
+{
+  DALI_ASSERT_ALWAYS( parser && "JsonParser handle is empty" );
+
+  BaseObject& handle = parser.GetBaseObject();
+
+  return static_cast<Internal::JsonParser&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_JSON_PARSER_IMPL_H
diff --git a/dali-toolkit/internal/builder/json-parser-state.cpp b/dali-toolkit/internal/builder/json-parser-state.cpp
new file mode 100644 (file)
index 0000000..636bac1
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/builder/json-parser-state.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <algorithm>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// true if character represent a digit
+inline bool IsDigit(char c)
+{
+  return (c >= '0' && c <= '9');
+}
+
+// convert string to integer
+bool StringToInteger(const char *first, const char *last, int& out)
+{
+  int sign = 1;
+  if (first != last)
+  {
+    if (*first == '-')
+    {
+      sign = -1;
+      ++first;
+    }
+    else if (*first == '+')
+    {
+      ++first;
+    }
+  }
+
+  // json error for int starting with zero
+  if( 0 == (*first - '0') && (first+1 != last))
+  {
+    return false;
+  }
+
+  int result = 0;
+  for (; first != last && IsDigit(*first); ++first)
+  {
+    result = 10 * result + (*first - '0');
+  }
+  out = result * sign;
+
+  if(first != last)
+  {
+    return false;
+  }
+  else
+  {
+    return true;
+  }
+}
+
+// convert hexadecimal string to unsigned integer
+bool HexStringToUnsignedInteger(const char *first, const char *last, unsigned int& out)
+{
+  unsigned int result = 0;
+  for (; first != last; ++first)
+  {
+    int digit;
+    if (IsDigit(*first))
+    {
+      digit = *first - '0';
+    }
+    else if (*first >= 'a' && *first <= 'f')
+    {
+      digit = *first - 'a' + 10;
+    }
+    else if (*first >= 'A' && *first <= 'F')
+    {
+      digit = *first - 'A' + 10;
+    }
+    else
+    {
+      break;
+    }
+    result = 16 * result + digit;
+  }
+  out = result;
+
+  if(first != last)
+  {
+    return false;
+  }
+  else
+  {
+    return true;
+  }
+}
+
+// convert string to floating point
+bool StringToFloat(const char* first, const char* last, float& out)
+{
+  // sign
+  float sign = 1;
+  if (first != last)
+  {
+    if (*first == '-')
+    {
+      sign = -1;
+      ++first;
+    }
+    else if (*first == '+')
+    {
+      ++first;
+    }
+  }
+
+  // integer part
+  float result = 0;
+  for (; first != last && IsDigit(*first); ++first)
+  {
+    result = 10 * result + (*first - '0');
+  }
+
+  // fraction part
+  if (first != last && *first == '.')
+  {
+    ++first;
+
+    float inv_base = 0.1f;
+    for (; first != last && IsDigit(*first); ++first)
+    {
+      result += (*first - '0') * inv_base;
+      inv_base *= 0.1f;
+    }
+  }
+
+  // result w\o exponent
+  result *= sign;
+
+  // exponent
+  bool exponent_negative = false;
+  int exponent = 0;
+  if (first != last && (*first == 'e' || *first == 'E'))
+  {
+    ++first;
+
+    if (*first == '-')
+    {
+      exponent_negative = true;
+      ++first;
+    }
+    else if (*first == '+')
+    {
+      ++first;
+    }
+
+    if(first == last || !IsDigit(*first))
+    {
+      return false;
+    }
+
+    for (; first != last && IsDigit(*first); ++first)
+    {
+      exponent = 10 * exponent + (*first - '0');
+    }
+  }
+
+  if (exponent)
+  {
+    float power_of_ten = 10;
+    for (; exponent > 1; exponent--)
+    {
+      power_of_ten *= 10;
+    }
+
+    if (exponent_negative)
+    {
+      result /= power_of_ten;
+    }
+    else
+    {
+      result *= power_of_ten;
+    }
+  }
+
+  out = result;
+
+  if(first != last)
+  {
+    return false;
+  }
+  else
+  {
+    return true;
+  }
+}
+
+
+bool IsNumber(char c)
+{
+  bool ret = false;
+  switch( c )
+  {
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    {
+      ret = true;
+      break;
+    }
+    default:
+    {
+      ret = false;
+    }
+  }
+  return ret;
+}
+
+} // anon namespace
+
+
+JsonParserState::JsonParserState(TreeNode* _root)
+  : mRoot(_root), mCurrent(_root),
+    mErrorDescription(NULL), mErrorNewLine(0), mErrorColumn(0), mErrorPosition(0),
+    mNumberOfParsedChars(0), mNumberOfCreatedNodes(0), mFirstParse(false),
+    mState(STATE_START)
+{
+  if(_root == NULL)
+  {
+    mFirstParse = true;
+  }
+}
+
+TreeNode* JsonParserState::CreateNewNode(const char* name, TreeNode::NodeType type)
+{
+  TreeNode* node = NULL;
+
+  node = TreeNodeManipulator::NewTreeNode();
+  TreeNodeManipulator modifyNew(node);
+  modifyNew.SetType(type);
+  modifyNew.SetName(name);
+  if(mRoot == NULL)
+  {
+    mRoot    = node;
+    mCurrent = TreeNodeManipulator(mRoot);
+  }
+  else
+  {
+    mCurrent.AddChild(node);
+    mCurrent = modifyNew;
+  }
+
+  ++mNumberOfCreatedNodes;
+
+  return node;
+
+}
+
+TreeNode* JsonParserState::NewNode(const char* name, TreeNode::NodeType type)
+{
+  TreeNode* node = NULL;
+
+  if(mFirstParse)
+  {
+    node = CreateNewNode(name, type);
+  }
+  else
+  {
+    // a merging parse
+
+    if(name)
+    {
+      const TreeNode* found = mCurrent.GetChild(name);
+      if( NULL != found )
+      {
+        node = const_cast<TreeNode*>(found);
+      }
+    }
+    else
+    {
+      // if root node
+      if( mCurrent.GetParent() == NULL )
+      {
+        node = mRoot;
+      }
+    }
+
+    if(node)
+    {
+      // walk tree and deallocate children as were replacing this node
+      TreeNodeManipulator modify(node);
+
+      modify.SetName(name);
+
+      // Set the type of the existing node.
+      // Where the new type is different, then any children of this node will
+      // be deleted.
+      // When the type is an array of numbers, then this will also remove any children
+      // When the type is an object or other array, then the children will not be removed,
+      // but will instead follow these replace rules.
+      modify.SetType(type);
+
+      mCurrent = modify;
+    }
+    else
+    {
+      // if not found then create new
+      node = CreateNewNode(name, type);
+    }
+  }
+
+  return node;
+}
+
+TreeNode* JsonParserState::GetRoot()
+{
+  return mRoot;
+}
+
+bool JsonParserState::Error(const char* description)
+{
+  mErrorDescription = description;
+  return false;
+}
+
+bool JsonParserState::ParseWhiteSpace()
+{
+  bool c_comment   = false;
+  bool cpp_comment = false;
+
+  if( mIter == mEnd )
+  {
+    return true;
+  }
+
+  // skip white space
+  char nextChar = 0;
+  while(1)
+  {
+    char c = Char();
+
+    if(c == '\xA')
+    {
+      NewLine();
+    }
+
+    if( AtLeast(2) )
+    {
+      nextChar = mIter[1];
+    }
+    else
+    {
+      nextChar = 0;
+    }
+
+    if( cpp_comment )
+    {
+      if( '\n' == c )
+      {
+        cpp_comment = false;
+        Advance(1);
+        continue; // rather than carry on as comments may be back to back
+      }
+    }
+    else if( !c_comment && (c == '/' && nextChar == '/') )
+    {
+      cpp_comment = true;
+    }
+
+    if( c_comment )
+    {
+      if( c == '*' && nextChar == '/' )
+      {
+        c_comment = false;
+        Advance(2);
+        continue;
+      }
+    }
+    else if( !cpp_comment && (c == '/' && nextChar == '*') )
+    {
+      c_comment = true;
+    }
+
+    if( ! (c_comment || cpp_comment) )
+    {
+      if( ! (c == '\x20' || c == '\x9' || c == '\xD' || c == '\xA' ) )
+      {
+        break;
+      }
+    }
+
+    if( AdvanceEnded(1) )
+    {
+      break;
+    }
+
+  } // while(1)
+
+  return true;
+} // ParseWhiteSpace
+
+bool JsonParserState::ParseSymbol(const std::string& symbol)
+{
+  if( AtLeast( symbol.size() ) )
+  {
+    for(int i = 0; i < static_cast<int>( symbol.size() ); ++i)
+    {
+      if(*mIter != symbol[i])
+      {
+        return false;
+      }
+      Advance(1);
+    }
+    return true;
+  }
+  else
+  {
+    return false;
+  }
+}
+
+bool JsonParserState::ParseTrue()
+{
+  if( ParseSymbol("true") )
+  {
+    mCurrent.SetInteger(1);
+    mCurrent.SetType(TreeNode::BOOLEAN);
+    return true;
+  }
+  else
+  {
+    return Error("Unexpected character; expected symbol ie 'true'");
+  }
+}
+
+bool JsonParserState::ParseFalse()
+{
+  if( ParseSymbol("false") )
+  {
+    mCurrent.SetInteger(0);
+    mCurrent.SetType(TreeNode::BOOLEAN);
+    return true;
+  }
+  else
+  {
+    return Error("Unexpected character; expected symbol ie 'false'");
+  }
+}
+
+bool JsonParserState::ParseNULL()
+{
+  if( ParseSymbol("null") )
+  {
+    mCurrent.SetType(TreeNode::IS_NULL);
+    return true;
+  }
+  else
+  {
+    return Error("Unexpected character; expected symbol ie 'null'");
+  }
+}
+
+bool JsonParserState::ParseNumber()
+{
+  mCurrent.SetType( TreeNode::INTEGER );
+
+  VectorCharIter first = mIter;
+  char c = Char();
+
+  if( !(c == '-' || IsNumber(c) ) )
+  {
+    return Error("Number must start with '-' or 0-9");
+  }
+
+  while ( IsNumber(c) || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-' )
+  {
+    if (c == '.' || c == 'e' || c == 'E')
+    {
+      mCurrent.SetType( TreeNode::FLOAT );
+    }
+    Advance(1);
+    c = Char();
+  }
+
+  if( mCurrent.GetType() == TreeNode::INTEGER )
+  {
+    int i = 0;
+    if( StringToInteger(&(*first), &(*mIter), i ) )
+    {
+      mCurrent.SetInteger(i);
+    }
+    else
+    {
+      return Error("Bad integer number");
+    }
+  }
+
+  if(mCurrent.GetType() == TreeNode::FLOAT)
+  {
+    float f = 0.f;
+    if( StringToFloat(&(*first), &(*mIter), f) )
+    {
+      mCurrent.SetFloat(f);
+    }
+    else
+    {
+      return Error("Bad float number");
+    }
+  }
+
+  return (mCurrent.GetType() == TreeNode::INTEGER)  || (mCurrent.GetType() == TreeNode::FLOAT);
+}
+
+char* JsonParserState::EncodeString()
+{
+  int substitution = 0;
+  VectorCharIter first = mIter;
+  VectorCharIter last  = mIter;
+
+  while (*mIter)
+  {
+    if (static_cast<unsigned char>(*mIter) < '\x20')
+    {
+      static_cast<void>( Error("Control characters not allowed in strings") );
+      return NULL;
+    }
+    else if (*mIter == '\\' && AtLeast(2))
+    {
+      switch (*(mIter+1))
+      {
+        case '"':
+        {
+          *last = '"';
+          break;
+        }
+        case '\\':
+        {
+          *last = '\\';
+          break;
+        }
+        case '/':
+        {
+          *last = '/';
+          break;
+        }
+        case 'b':
+        {
+          *last = '\b';
+          break;
+        }
+        case 'f':
+        {
+          *last = '\f';
+          break;
+        }
+        case 'n':
+        {
+          *last = '\n';
+          break;
+        }
+        case 'r':
+        {
+          *last = '\r';
+          break;
+        }
+        case 't':
+        {
+          *last = '\t';
+          break;
+        }
+        case 'u':
+        {
+          unsigned int codepoint;
+          if( !AtLeast(6) )
+          {
+            static_cast<void>( Error("Bad unicode codepoint; not enough characters") );
+            return NULL;
+          }
+          if ( !HexStringToUnsignedInteger(&(*(mIter + 2)), &(*(mIter + 6)), codepoint) )
+          {
+            static_cast<void>( Error("Bad unicode codepoint") );
+            return NULL;
+          }
+
+          if (codepoint <= 0x7F)
+          {
+            *last = (char)codepoint;
+          }
+          else if (codepoint <= 0x7FF)
+          {
+            *last++ = (char)(0xC0 | (codepoint >> 6));
+            *last = (char)(0x80 | (codepoint & 0x3F));
+          }
+          else if (codepoint <= 0xFFFF)
+          {
+            *last++ = (char)(0xE0 | (codepoint >> 12));
+            *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
+            *last = (char)(0x80 | (codepoint & 0x3F));
+          }
+
+          Advance(4);
+          break;
+        } // case 'u' unicode
+
+        default:
+        {
+          static_cast<void>( Error("Unrecognized escape sequence") );
+          return NULL;
+        }
+      }
+
+      ++last;
+      Advance(2);
+    }
+    else if (*mIter == '{')
+    {
+      if((0 == substitution) && (*last != '\\'))
+      {
+        substitution = 1;
+      }
+      *last++ = *mIter;
+      Advance(1);
+    }
+    else if (*mIter == '}')
+    {
+      if(substitution)
+      {
+        substitution++;
+      }
+      *last++ = *mIter;
+      Advance(1);
+    }
+    else if (*mIter == '"')
+    {
+      *last = 0;
+      Advance(1);
+      break;
+    }
+    else
+    {
+      *last++ = *mIter;
+      Advance(1);
+    }
+
+  } // while(*mIter)
+
+  mNumberOfParsedChars += last - first;
+  mNumberOfParsedChars += 1 ; // null terminator
+
+  mCurrent.SetSubstitution( substitution > 1 );
+
+  // return true;
+  return &(*first);
+
+} // ParseString()
+
+bool JsonParserState::ParseJson(VectorChar& source)
+{
+  Reset();
+
+  if( 0 == source.size() )
+  {
+    return Error("Empty source buffer to parse");
+  }
+
+  mIter = source.begin();
+  mEnd  = source.end();
+
+  char* name = NULL;
+  char currentChar   = 0;
+  char lastCharacter = 0;
+
+  if( !ParseWhiteSpace() )
+  {
+    return false;
+  }
+
+  while(mIter != mEnd)
+  {
+    lastCharacter = currentChar;
+    currentChar = Char();
+
+    switch( mState )
+    {
+      case STATE_START:
+      {
+        if( '{' == currentChar )
+        {
+          NewNode(name, TreeNode::OBJECT);
+          mState = STATE_OBJECT;
+        }
+        else if( '[' == currentChar )
+        {
+          NewNode(name, TreeNode::ARRAY);
+          mState = STATE_VALUE;
+        }
+        else
+        {
+          return Error("Json must start with object {} or array []");
+        }
+
+        AdvanceSkipWhiteSpace(1);
+        break;
+      }
+      case STATE_OBJECT:
+      {
+        if( '}' == currentChar )
+        {
+          if(',' == lastCharacter)
+          {
+            return Error("Unexpected comma");
+          }
+
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          mState = STATE_VALUE;
+        }
+        else if ( '"' == currentChar )
+        {
+          mState = STATE_KEY;
+        }
+        else
+        {
+          return Error("Unexpected character");
+        }
+
+        AdvanceSkipWhiteSpace(1);
+        break;
+      }
+      case STATE_KEY:
+      {
+        name = EncodeString();
+        if( NULL == name )
+        {
+          return false;
+        }
+        if( !ParseWhiteSpace() )
+        {
+          return false;
+        }
+        if( ':' != Char())
+        {
+          return Error("Expected ':'");
+        }
+        if( !ParseWhiteSpace() )
+        {
+          return false;
+        }
+        mState = STATE_VALUE;
+
+        AdvanceSkipWhiteSpace(1);
+        break;
+      }
+      case STATE_VALUE:
+      {
+        if( '"' == currentChar )
+        {
+          Advance(1);
+          NewNode(name, TreeNode::STRING);
+          if( char* value = EncodeString() )
+          {
+            mCurrent.SetString(value);
+          }
+          else
+          {
+            return false;
+          }
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          AdvanceSkipWhiteSpace(0);
+        }
+        else if( IsNumber(currentChar) || currentChar == '-' )
+        {
+          NewNode(name, TreeNode::IS_NULL);
+          if( !ParseNumber() )
+          {
+            return false;
+          }
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          AdvanceSkipWhiteSpace(0);
+        }
+        else if( '{' == currentChar )
+        {
+          if( '}' == lastCharacter )
+          {
+            return Error("Expected a comma");
+          }
+          else
+          {
+            NewNode(name, TreeNode::OBJECT);
+            mState = STATE_OBJECT;
+            AdvanceSkipWhiteSpace(1);
+          }
+        }
+        else if( '}' == currentChar )
+        {
+          if(',' == lastCharacter)
+          {
+            return Error("Expected another value");
+          }
+
+          if(mCurrent.GetType() != TreeNode::OBJECT)
+          {
+            return Error("Mismatched array definition");
+          }
+
+          if(mCurrent.GetParent() == NULL)
+          {
+            mState = STATE_END;
+          }
+          else
+          {
+            if( !UpToParent() )
+            {
+              return false;
+            }
+          }
+          AdvanceSkipWhiteSpace(1);
+        }
+        else if( '[' == currentChar )
+        {
+          NewNode(name, TreeNode::ARRAY);
+          mState = STATE_VALUE;
+          AdvanceSkipWhiteSpace(1);
+        }
+        else if( ']' == currentChar )
+        {
+          if(',' == lastCharacter)
+          {
+            return Error("Expected a value");
+          }
+
+          if(mCurrent.GetType() != TreeNode::ARRAY)
+          {
+            return Error("Mismatched braces in object definition");
+          }
+
+          if(mCurrent.GetParent() == NULL)
+          {
+            mState = STATE_END;
+          }
+          else
+          {
+            if( !UpToParent() )
+            {
+              return false;
+            }
+          }
+          AdvanceSkipWhiteSpace(1);
+        }
+        else if( 't' == currentChar )
+        {
+          NewNode(name, TreeNode::BOOLEAN);
+          if( !ParseTrue() )
+          {
+            return false;
+          }
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          AdvanceSkipWhiteSpace(0);
+        }
+        else if( 'n' == currentChar )
+        {
+          NewNode(name, TreeNode::IS_NULL);
+          if( !ParseNULL() )
+          {
+            return false;
+          }
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          AdvanceSkipWhiteSpace(0);
+        }
+        else if( 'f' == currentChar)
+        {
+          NewNode(name, TreeNode::BOOLEAN);
+          if( !ParseFalse() )
+          {
+            return false;
+          }
+          if( !UpToParent() )
+          {
+            return false;
+          }
+          AdvanceSkipWhiteSpace(0);
+        }
+        else if( ',' == currentChar )
+        {
+          if( 0 == mCurrent.Size() )
+          {
+            return Error("Missing Value");
+          }
+
+          if(mCurrent.GetType() == TreeNode::OBJECT)
+          {
+            mState = STATE_OBJECT; // to get '"' in '"key":val'
+          }
+          else if(mCurrent.GetType() == TreeNode::ARRAY)
+          {
+            mState = STATE_VALUE; // array so just get next value
+          }
+          else
+          {
+            return Error("Unexpected character");
+          }
+          AdvanceSkipWhiteSpace(1);
+        }
+        else
+        {
+          return Error("Unexpected character");
+        }
+
+        name = NULL;
+
+        break;
+      } // case STATE_VALUE
+      case STATE_END:
+      {
+        return Error("Unexpected character. Json must have one object or array at its root");
+        break;
+      }
+    } // switch(mState)
+
+  } // while(1)
+
+  //
+  if( mState != STATE_END )
+  {
+    return Error("Unexpected termination character");
+  }
+
+  mIter = source.end();
+
+  return true;
+
+} // ParseJson
+
+
+void JsonParserState::Reset()
+{
+  mCurrent = TreeNodeManipulator(mRoot);
+
+  mErrorDescription   = NULL;
+  mErrorNewLine       = 0;
+  mErrorColumn        = 0;
+  mErrorPosition      = 0;
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/json-parser-state.h b/dali-toolkit/internal/builder/json-parser-state.h
new file mode 100644 (file)
index 0000000..210c11f
--- /dev/null
@@ -0,0 +1,315 @@
+#ifndef DALI_JSON_PARSE_STATE_H
+#define DALI_JSON_PARSE_STATE_H
+
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/dali-toolkit-common.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+
+#include <dali-toolkit/internal/builder/tree-node-manipulator.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/*
+ * A safer std::advance()
+ */
+template <typename IteratorType,typename EndIteratorType>
+inline int AdvanceIter(IteratorType& iter, EndIteratorType& end, int n)
+{
+  for(int i =0; i < n; ++i)
+  {
+    if(iter == end)
+    {
+      return n - i;
+    }
+    ++iter;
+  }
+  return n;
+}
+
+/*
+ * Maintains parser state machine
+ *
+ * If a NULL root node is passed in the constructor then a faster non merging parse is performed (the first pass).
+ * Otherwise the json tree is merged (and requires slower searching)
+ */
+class JsonParserState
+{
+public:
+  /*
+   * Constructor
+   * @param tree Tree to start with, pass NULL if no existing tree
+   */
+  explicit JsonParserState(TreeNode* tree);
+
+  /*
+   * Parse json source
+   * The source is modified in place
+   * @param source The vector buffer to parse
+   * @return true if parsed successfully
+   */
+  bool ParseJson(VectorChar& source);
+
+  /*
+   * Get the root node
+   * @return The root TreeNode
+   */
+  TreeNode* GetRoot();
+
+  /*
+   * Get the error description of the last parse
+   * @return The error description or NULL if no error
+   */
+  const char* GetErrorDescription() { return mErrorDescription; }
+
+  /*
+   * Get the error line number
+   * @return The line number of the error
+   */
+  int GetErrorLineNumber() { return mErrorNewLine; }
+
+  /*
+   * Get the error column
+   * @return The error column
+   */
+  int GetErrorColumn() { return mErrorColumn; }
+
+  /*
+   * Get the error position
+   * @return The error position
+   */
+  int GetErrorPosition() { return mErrorPosition; }
+
+  /*
+   * Get the size of the string data that has been parsed
+   * @return The size of string data
+   */
+  int GetParsedStringSize() { return mNumberOfParsedChars; };
+
+  /*
+   * Get the number of nodes created
+   * @return The number of nodes
+   */
+  int GetCreatedNodeCount() { return mNumberOfCreatedNodes; };
+
+private:
+  VectorCharIter mIter;                ///< Current position
+  VectorCharIter mStart;               ///< Start position
+  VectorCharIter mEnd;                 ///< End of buffer being parsed
+  TreeNode* mRoot;                     ///< Root node created
+  TreeNodeManipulator mCurrent;        ///< The Current modifiable node
+  const char* mErrorDescription;       ///< The error description if set
+  int mErrorNewLine;                   ///< The error line number
+  int mErrorColumn;                    ///< The error column
+  int mErrorPosition;                  ///< The error position
+  int mNumberOfParsedChars;            ///< The size of string data
+  int mNumberOfCreatedNodes;           ///< The number of nodes created
+  bool mFirstParse;                    ///< Flag if first parse
+
+  /*
+   * The current parse state
+   */
+  enum State
+  {
+    STATE_START,
+    STATE_OBJECT,
+    STATE_KEY,
+    STATE_VALUE,
+    STATE_END,
+  };
+
+  State mState;
+
+  // inhibited copy construct and assignment
+  JsonParserState(const JsonParserState&);
+  const JsonParserState& operator=(const JsonParserState&);
+
+  /*
+   * Parse over white space
+   * Increments the current position
+   * @return true if no parse errors
+   */
+  bool ParseWhiteSpace();
+
+  /*
+   * Parse over a number, setting the current node if found
+   * Increments the current position. Sets error data if parse error.
+   * @return true if found, false if parse error
+   */
+  bool ParseNumber();
+
+  /*
+   * Parse over a symbol
+   * Increments the current position. Sets error data if parse error.
+   * @return true if found, false if parse error
+   */
+  bool ParseSymbol(const std::string& symbol);
+
+  /*
+   * Parse over 'true' symbol, setting the current node if found
+   * Increments the current position. Sets error data if parse error.
+   * @return true if found, false if parse error
+   */
+  bool ParseTrue();
+
+  /*
+   * Parse over 'false' symbol, setting the current node if found
+   * Increments the current position. Sets error data if parse error.
+   * @return true if found, false if parse error
+   */
+  bool ParseFalse();
+
+  /*
+   * Parse over 'null' symbol, setting the current node if found
+   * Increments the current position. Sets error data if parse error.
+   * @return true if found, false if parse error
+   */
+  bool ParseNULL();
+
+  /*
+   * Parse over a string from the current position and insert escaped
+   * control characters in place in the string and a null terminator.
+   * This function works from and modifes the current buffer position.
+   * @return the start of the null terminated string
+   */
+  char* EncodeString();
+
+  /*
+   * Create a new node with name and type
+   */
+  TreeNode* CreateNewNode(const char* name, TreeNode::NodeType type);
+
+  /*
+   * Create a new node if first parse, else check if the node already
+   * exists and set it to a new type
+   */
+  TreeNode* NewNode(const char* name, TreeNode::NodeType type);
+
+  /*
+   * Set error meta data
+   * @returns always false.
+   */
+  bool Error(const char* description);
+
+  /*
+   * Reset state for another parse
+   */
+  void Reset();
+
+  /*
+   * Set current to its parent
+   * @return true if we had a parent, false and error otherwise
+   */
+  inline bool UpToParent()
+  {
+    if(NULL == mCurrent.GetParent())
+    {
+      return Error("Attempt to walk up above root");
+    }
+    mCurrent = TreeNodeManipulator( mCurrent.GetParent() );
+    return true;
+  }
+
+  /*
+   * Get the current character
+   */
+  inline char Char()
+  {
+    return *mIter;
+  }
+
+  /*
+   * @return True if there are at least n character left
+   */
+  inline bool AtLeast(int n)
+  {
+    // The standard suggests vector.end() can be decremented as
+    //   iter v.back() { *--v.end() }
+    // (ISO/IEC 14882:2003 C++ Standard 23.1.1/12 – Sequences)
+    return (mEnd - mIter) > n;
+  }
+
+  /*
+   * @return True if at the end of the data to parse
+   */
+  inline bool AtEnd()
+  {
+    return mEnd == mIter;
+  }
+
+  /*
+   * Advance current position by n characters or stop at mEnd
+   */
+  inline void Advance(int n)
+  {
+    int c = AdvanceIter(mIter, mEnd, n);
+    mErrorPosition += c;
+    mErrorColumn   += c;
+  }
+
+  /*
+   * Advance by n charaters and return true if we reached the end
+   */
+  inline bool AdvanceEnded(int n)
+  {
+    int c = AdvanceIter(mIter, mEnd, n);
+    mErrorPosition += c;
+    mErrorColumn   += c;
+    return mEnd == mIter;
+  }
+
+  /*
+   * Advance by at least n characters (stopping at mEnd) and skip any whitespace after n.
+   */
+  inline void AdvanceSkipWhiteSpace(int n)
+  {
+    int c = AdvanceIter(mIter, mEnd, n);
+    mErrorPosition += c;
+    mErrorColumn   += c;
+    static_cast<void>( ParseWhiteSpace() );
+  }
+
+  /*
+   * Increment new line counters
+   */
+  inline void NewLine()
+  {
+    ++mErrorNewLine;
+    mErrorColumn = 0;
+  }
+
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_JSON_PARSE_STATE_H
diff --git a/dali-toolkit/internal/builder/optional-value.h b/dali-toolkit/internal/builder/optional-value.h
new file mode 100644 (file)
index 0000000..666dd30
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_OPTIONAL_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_OPTIONAL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+template <typename T>
+struct OptionalTypes
+{
+  typedef T ValueType;
+  typedef const T& ReturnType;
+  static ReturnType Get(const ValueType& v) { return v; }
+  static ValueType Set(const ReturnType v) { return v; }
+  static bool Ok(const ValueType& v) { return true; }
+};
+
+template <typename T>
+struct OptionalTypes<T*>
+{
+  typedef T* ValueType;
+  typedef const T* ReturnType;
+  static ReturnType Get(const ValueType v) { return v; }
+  static ValueType Set(const ReturnType v) { return v; }
+  static bool Ok(const ReturnType v) { return NULL != v; }
+};
+
+template <typename T>
+struct OptionalTypes<T&>
+{
+  typedef T* ValueType;
+  typedef const T& ReturnType;
+  static ReturnType Get(const ValueType v) { return *v; }
+  static ValueType Set(const ReturnType v) { return &v; }
+  static bool Ok(const ReturnType v) { return true; }
+};
+
+template <typename T>
+class OptionalValue
+{
+public:
+  typedef void ( OptionalValue::*bool_type )() const;
+  typedef typename OptionalTypes<T>::ReturnType ReturnType;
+  typedef typename OptionalTypes<T>::ValueType ValueType;
+
+  OptionalValue(): mOk(false), mValue() {}
+  OptionalValue( T value ): mOk(OptionalTypes<T>::Ok(value)), mValue(OptionalTypes<T>::Set(value)) {}
+  OptionalValue( bool b, T value ): mOk(b), mValue(OptionalTypes<T>::Set(value)) {}
+
+  ReturnType operator *() const { return OptionalTypes<T>::Get(mValue); }
+
+  // safe bool idiom
+  operator bool_type() const {
+    return mOk == true ? &OptionalValue::this_type_does_not_support_comparisons : 0;
+  }
+
+private:
+  bool mOk;
+  ValueType mValue;
+  void this_type_does_not_support_comparisons() const {}
+};
+
+template <typename T, typename U>
+bool operator==( const OptionalValue<T>& lhs, const OptionalValue<U>& rhs )
+{
+  lhs.this_type_does_not_support_comparisons();
+  return false;
+}
+
+template <typename T, typename U>
+bool operator!=( const OptionalValue<T>& lhs, const OptionalValue<U>& rhs )
+{
+  lhs.this_type_does_not_support_comparisons();
+  return false;
+}
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_OPTIONAL_H
diff --git a/dali-toolkit/internal/builder/replacement.cpp b/dali-toolkit/internal/builder/replacement.cpp
new file mode 100644 (file)
index 0000000..a15ef21
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/replacement.h>
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace  // anon
+{
+
+Property::Value* FindReplacement( const std::string &str, const Property::Map& overrideMap, const Property::Map& defaultMap )
+{
+  Property::Value* ret  = overrideMap.Find( str );
+
+  if ( !ret )
+  {
+    ret = defaultMap.Find( str );
+
+    // @ todo
+    // try localized text ie dgettext. Look for colon  {DOMAIN:TEXT} {LC_MESSAGE:ID_XXXX}
+  }
+
+  return ret;
+}
+
+std::size_t FirstUnescapedChar(const std::string &initialValue, const std::size_t& startPos, const char c)
+{
+  std::size_t pos = initialValue.find( c, startPos );
+
+  if(pos > 0)
+  {
+    while( pos != std::string::npos )
+    {
+      if( '\\' == initialValue.at( pos-1 ) )
+      {
+        pos = initialValue.find( c, pos );
+      }
+      else
+      {
+        break;
+      }
+    }
+  }
+
+  return pos;
+}
+
+bool GetSubstitutionPosition( const std::string &initialValue, std::size_t &startPos, std::size_t &size )
+{
+  std::size_t pos = FirstUnescapedChar(initialValue, 0, '{');
+
+  if( std::string::npos == pos )
+  {
+    startPos = std::string::npos;
+    return false;
+  }
+  else
+  {
+    startPos = pos + 1;
+  }
+
+  pos = FirstUnescapedChar(initialValue, startPos, '}');
+
+  if( std::string::npos == pos )
+  {
+    size = std::string::npos;
+    return false;
+  }
+  else
+  {
+    size = pos - startPos;
+  }
+
+  return true;
+}
+
+bool ResolvePartialReplacement( const std::string &initialValue, Property::Value &out,
+                                const Property::Map& overrideMap, const Property::Map& defaultMap )
+{
+
+  if( initialValue.size() >= 2 )
+  {
+    // eg '{"constants": { "IMAGE_DIR": "/share/images" },
+    //      ...
+    //        "filename":"{IMAGE_DIR}/theme/header.png",
+    //
+    std::size_t startPos = 0;
+    std::size_t size     = std::string::npos;
+
+    if( !GetSubstitutionPosition( initialValue, startPos, size ) )
+    {
+      out = initialValue;
+      return true;
+    }
+    else
+    {
+      const std::string str( initialValue.substr( startPos, size ) );
+
+      Property::Value* value = FindReplacement( str, overrideMap, defaultMap );
+
+      if( !value )
+      {
+        DALI_SCRIPT_WARNING( "Cannot find replacement for '%s'\n", str.c_str() );
+      }
+      else
+      {
+        if( Property::STRING != value->GetType() )
+        {
+          DALI_SCRIPT_WARNING( "Cannot replace substring in non string property type='%s'. Initial value '%s'\n",
+                               PropertyTypes::GetName( out.GetType() ), initialValue.c_str() );
+        }
+        else
+        {
+          std::string newString = \
+            initialValue.substr(0, startPos - 1) +
+            value->Get< std::string >() +
+            initialValue.substr( startPos + size + 1 );
+
+          return ResolvePartialReplacement( newString, out, overrideMap,  defaultMap );
+        }
+      }
+    }
+  }
+
+  // if we get here we failed
+  return false;
+}
+
+} // namespace anon
+
+
+Replacement::Replacement( const Property::Map& overrideMap, const Property::Map& defaultMap )
+  : mOverrideMap( &overrideMap ), mDefaultMap( &defaultMap )
+{
+
+}
+
+namespace
+{
+Property::Map noMap;
+}
+
+Replacement::Replacement( const Property::Map& defaultMap )
+  : mOverrideMap( &noMap ), mDefaultMap( &defaultMap )
+{
+
+}
+
+Replacement::Replacement(  )
+  : mOverrideMap( &noMap ), mDefaultMap( &noMap )
+{
+
+}
+
+OptionalString Replacement::HasFullReplacement( const TreeNode & node ) const
+{
+  OptionalString ret;
+
+  if( node.HasSubstitution() && ((*mOverrideMap).Count() || (*mDefaultMap).Count()) )
+  {
+    OptionalString v = ::IsString( node );
+    if( v )
+    {
+      const std::string& initialValue = *v;
+      if( (initialValue[ 0 ] == '{') && (initialValue[ initialValue.size() -1 ] == '}') )
+      {
+        ret = initialValue.substr( 1, initialValue.size() - 2 );
+      }
+    }
+  }
+  return ret;
+}
+
+Property::Value Replacement::GetFullReplacement( const std::string& replacementString ) const
+{
+  Property::Value out;
+  DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
+  DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
+
+  Property::Value* value = FindReplacement( replacementString, *mOverrideMap, *mDefaultMap );
+
+  if( !value )
+  {
+    DALI_SCRIPT_WARNING("Cannot find replacement for '%s'\n", replacementString.c_str());
+  }
+  else
+  {
+    out = *value;
+#if defined(DEBUG_ENABLED)
+    DALI_SCRIPT_VERBOSE("  Full replacement for '%s' => to Type '%s'\n",
+                        replacementString.c_str(),
+                        PropertyTypes::GetName( out.GetType()) );
+#endif
+  }
+
+  return out;
+}
+
+OptionalBoolean Replacement::IsBoolean( const TreeNode & node ) const
+{
+  OptionalBoolean ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::BOOLEAN == value.GetType() )
+    {
+      ret = value.Get<bool>();
+    }
+  }
+  else
+  {
+    ret = ::IsBoolean( node );
+  }
+  return ret;
+}
+
+OptionalBoolean Replacement::IsBoolean( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsBoolean( *child );
+  }
+  else
+  {
+    return OptionalBoolean();
+  }
+}
+
+OptionalFloat Replacement::IsFloat( const TreeNode & node ) const
+{
+  OptionalFloat ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::FLOAT == value.GetType() )
+    {
+      ret = value.Get<float>();
+    }
+  }
+  else
+  {
+    ret = ::IsFloat( node );
+  }
+  return ret;
+}
+
+OptionalString Replacement::IsString( const TreeNode& node ) const
+{
+  OptionalString ret;
+
+  DALI_ASSERT_DEBUG( mOverrideMap && "missing map");
+  DALI_ASSERT_DEBUG( mDefaultMap && "missing map");
+
+  if( node.HasSubstitution() && ((*mOverrideMap).Count() || (*mDefaultMap).Count()) )
+  {
+    if( OptionalString v = ::IsString( node ) )
+    {
+      Property::Value value;
+      if( ResolvePartialReplacement( *v, value, *mOverrideMap, *mDefaultMap ) )
+      {
+        if( Property::STRING == value.GetType() )
+        {
+          ret = value.Get<std::string>();
+#if defined(DEBUG_ENABLED)
+          DALI_SCRIPT_VERBOSE("  Resolved substring replacement for '%s' => '%s'\n", (*v).c_str(), (*ret).c_str());
+#endif
+        }
+      }
+      else
+      {
+        ret = v; // sets the unexpanded. Expansion may occur later in processing with include files
+      }
+    }
+  }
+  else
+  {
+    ret = ::IsString( node );
+  }
+  return ret;
+}
+
+OptionalInteger Replacement::IsInteger( const TreeNode & node ) const
+{
+  OptionalInteger ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::INTEGER == value.GetType() )
+    {
+      ret = value.Get<int>();
+    }
+  }
+  else
+  {
+    ret = ::IsInteger( node );
+  }
+  return ret;
+}
+
+OptionalVector2 Replacement::IsVector2( const TreeNode & node ) const
+{
+  OptionalVector2 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR2 == value.GetType() )
+    {
+      ret = value.Get<Vector2>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector2( node );
+  }
+  return ret;
+}
+
+OptionalVector3 Replacement::IsVector3( const TreeNode & node ) const
+{
+  OptionalVector3 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR3 == value.GetType() )
+    {
+      ret = value.Get<Vector3>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector3( node );
+  }
+  return ret;
+}
+
+OptionalVector4 Replacement::IsVector4( const TreeNode & node ) const
+{
+  OptionalVector4 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::VECTOR4 == value.GetType() )
+    {
+      ret = value.Get<Vector4>();
+    }
+  }
+  else
+  {
+    ret = ::IsVector4( node );
+  }
+  return ret;
+}
+
+OptionalMatrix Replacement::IsMatrix( const TreeNode & node ) const
+{
+  OptionalMatrix ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::MATRIX == value.GetType() )
+    {
+      ret = value.Get<Matrix>();
+    }
+  }
+  else
+  {
+    ret = ::IsMatrix( node );
+  }
+  return ret;
+}
+
+OptionalMatrix3 Replacement::IsMatrix3( const TreeNode & node ) const
+{
+  OptionalMatrix3 ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::MATRIX3 == value.GetType() )
+    {
+      ret = value.Get<Matrix3>();
+    }
+  }
+  else
+  {
+    ret = ::IsMatrix3( node );
+  }
+  return ret;
+}
+
+OptionalRect Replacement::IsRect( const TreeNode & node ) const
+{
+  OptionalRect ret;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::RECTANGLE == value.GetType() )
+    {
+      ret = value.Get<Rect<int> >();
+    }
+  }
+  else
+  {
+    ret = ::IsRect( node );
+  }
+  return ret;
+}
+
+OptionalExtents Replacement::IsExtents( const TreeNode & node ) const
+{
+  OptionalExtents extents;
+  if( OptionalString replace = HasFullReplacement( node ) )
+  {
+    Property::Value value = GetFullReplacement( *replace );
+    if( Property::EXTENTS == value.GetType() )
+    {
+      extents = value.Get<Extents>();
+    }
+  }
+  else
+  {
+    extents = ::IsExtents( node );
+  }
+  return extents;
+}
+
+OptionalFloat Replacement::IsFloat( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsFloat( *child );
+  }
+  else
+  {
+    return OptionalFloat();
+  }
+}
+
+
+OptionalString Replacement::IsString( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsString( *child );
+  }
+  else
+  {
+    return OptionalString();
+  }
+}
+
+OptionalInteger Replacement::IsInteger( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsInteger( *child );
+  }
+  else
+  {
+    return OptionalInteger();
+  }
+}
+
+OptionalVector2 Replacement::IsVector2( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector2( *child );
+  }
+  else
+  {
+    return OptionalVector2();
+  }
+}
+
+OptionalVector3 Replacement::IsVector3( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector3( *child );
+  }
+  else
+  {
+    return OptionalVector3();
+  }
+}
+
+OptionalVector4 Replacement::IsVector4( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsVector4( *child );
+  }
+  else
+  {
+    return OptionalVector4();
+  }
+}
+
+OptionalMatrix Replacement::IsMatrix( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsMatrix( *child );
+  }
+  else
+  {
+    return OptionalMatrix();
+  }
+}
+
+OptionalMatrix3 Replacement::IsMatrix3( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsMatrix3( *child );
+  }
+  else
+  {
+    return OptionalMatrix3();
+  }
+}
+
+OptionalRect Replacement::IsRect( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsRect( *child );
+  }
+  else
+  {
+    return OptionalRect();
+  }
+}
+
+bool Replacement::IsMap( OptionalChild child, Property::Value& out ) const
+{
+  bool ret = false;
+
+  if( child )
+  {
+    if( OptionalString replace = HasFullReplacement( *child ) )
+    {
+      out = GetFullReplacement( *replace );
+      if( Property::MAP == out.GetType() )
+      {
+        ret = true;
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool Replacement::IsArray( OptionalChild child, Property::Value& out ) const
+{
+  bool ret = false;
+
+  if( child )
+  {
+    if( OptionalString replace = HasFullReplacement( *child ) )
+    {
+      out = GetFullReplacement( *replace );
+      if( Property::ARRAY == out.GetType() )
+      {
+        ret = true;
+      }
+    }
+  }
+
+  return ret;
+}
+
+OptionalExtents Replacement::IsExtents( OptionalChild child ) const
+{
+  if( child )
+  {
+    return IsExtents( *child );
+  }
+  else
+  {
+    return OptionalExtents();
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/replacement.h b/dali-toolkit/internal/builder/replacement.h
new file mode 100644 (file)
index 0000000..24260de
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_REPLACEMENT_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_REPLACEMENT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-value.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/builder-get-is.inl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+  class TreeNode;
+}
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/*
+ * Supports template replacement functionality
+ *
+ */
+class Replacement
+{
+public:
+
+  /*
+   * Constructor
+   */
+  Replacement();
+
+  /*
+   * Constructor with default and overriding map
+   *
+   * Make a deep copy of the tree.
+   * @param overrideMap The user overriding map
+   * @param defaultMap The default map to use
+   */
+  Replacement( const Property::Map& overrideMap, const Property::Map& defaultMap );
+
+  /*
+   * Constructor with default map
+   *
+   * Make a deep copy of the tree.
+   * @param overrideMap The user overriding map
+   */
+  Replacement( const Property::Map& defaultMap );
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalString IsString( const TreeNode& node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalBoolean IsBoolean( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalFloat IsFloat( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalInteger IsInteger( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector2 IsVector2( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector3 IsVector3( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalVector4 IsVector4( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalMatrix IsMatrix( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalMatrix3 IsMatrix3( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalRect IsRect( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param node The TreeNode to check
+   * @return Optional value
+   */
+  OptionalExtents IsExtents( const TreeNode & node ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalString IsString( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalFloat IsFloat( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalBoolean IsBoolean( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalInteger IsInteger( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector2 IsVector2( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector3 IsVector3( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalVector4 IsVector4( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalMatrix IsMatrix( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalMatrix3 IsMatrix3( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalRect IsRect( OptionalChild child ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  bool IsMap( OptionalChild child, Property::Value& out ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  bool IsArray( OptionalChild child, Property::Value& out ) const;
+
+  /* @brief Check node for a type
+   *
+   * @param child The optional child TreeNode
+   * @return Optional value
+   */
+  OptionalExtents IsExtents( OptionalChild child ) const;
+
+private:
+  // Overriding map (overrides the default map). The map is not owned.
+  const Property::Map* const mOverrideMap;
+
+  // Default map. The map is not owned.
+  const Property::Map* const mDefaultMap;
+
+  // compiler
+  // Replacement & operation=( Replacement& replacement );
+  // Replacement( const Replacement& copy );
+
+  // Returns the string if the node has a full replacement ie IMAGES if node is "{IMAGES}"
+  OptionalString HasFullReplacement( const TreeNode & node ) const;
+
+  // Returns the property value for a full replacement from the maps
+  Property::Value GetFullReplacement( const std::string& replacementString ) const;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUILDER_REPLACEMENT_H
diff --git a/dali-toolkit/internal/builder/style.cpp b/dali-toolkit/internal/builder/style.cpp
new file mode 100644 (file)
index 0000000..a5ced1b
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 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/handle.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/builder/style.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+extern const Dali::Scripting::StringEnum ControlStateTable[];
+extern const unsigned int ControlStateTableCount;
+
+StylePtr Style::New()
+{
+  StylePtr stylePtr( new Style() );
+  return stylePtr;
+}
+
+void Style::ApplyVisualsAndPropertiesRecursively(
+  Handle handle,
+  const Dictionary<Property::Map>& instancedProperties ) const
+{
+  ApplyVisuals( handle, instancedProperties );
+  ApplyProperties( handle );
+
+  Toolkit::Control control = Toolkit::Control::DownCast(handle);
+  if( control )
+  {
+    std::string stateName;
+    Property::Value value = control.GetProperty(DevelControl::Property::STATE);
+    Dali::Toolkit::DevelControl::State state = static_cast<Dali::Toolkit::DevelControl::State>(value.Get<int>());
+    stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( state, ControlStateTable, ControlStateTableCount );
+
+    if( ! stateName.empty() )
+    {
+      // Look up state in states table:
+      const StylePtr* stylePtr = subStates.FindConst( stateName );
+      if( stylePtr )
+      {
+        const StylePtr statePtr(*stylePtr);
+
+        // We have a state match.
+        statePtr->ApplyVisuals( handle, instancedProperties );
+        statePtr->ApplyProperties( handle );
+
+        // Apply substate visuals
+        Property::Value value = control.GetProperty(DevelControl::Property::SUB_STATE);
+        std::string subStateName;
+        if( value.Get( subStateName ) && ! subStateName.empty() )
+        {
+          const StylePtr* stylePtr = statePtr->subStates.FindConst( subStateName );
+          if( stylePtr )
+          {
+            const StylePtr subStatePtr(*stylePtr);
+            // We have a sub-state match.
+            subStatePtr->ApplyVisuals( handle, instancedProperties );
+            subStatePtr->ApplyProperties( handle );
+          }
+        }
+      }
+    }
+  }
+}
+
+void Style::ApplyVisuals(
+  Handle handle,
+  const Dictionary<Property::Map>& instancedProperties ) const
+{
+  ApplyVisuals( handle, visuals, instancedProperties );
+}
+
+void Style::ApplyVisuals(
+  Handle handle,
+  const Dictionary<Property::Map>& visualMaps,
+  const Dictionary<Property::Map>& instancedProperties )
+{
+  for( Dictionary<Property::Map>::iterator iter = visualMaps.Begin(); iter != visualMaps.End() ; ++iter )
+  {
+    const std::string& visualName = (*iter).key;
+    Property::Map map = (*iter).entry;
+    Property::Map* instancedMap = instancedProperties.Find( visualName );
+    ApplyVisual( handle, visualName, map, instancedMap );
+  }
+}
+
+void Style::ApplyVisual(
+  Handle handle,
+  const std::string& visualName,
+  const Property::Map& visualMap,
+  const Property::Map* instancedProperties )
+{
+  // Check if this visual name is a valid property of handle
+  Dali::Property::Index index = handle.GetPropertyIndex( visualName );
+  if( index != Property::INVALID_INDEX )
+  {
+    const Property::Map* applyMap = &visualMap;
+    Property::Map mergedMap;
+
+    // If there are instanced properties, and the visual types match,
+    // merge them into the visual map
+    if( instancedProperties )
+    {
+      Property::Value* instanceTypeValue = instancedProperties->Find( Toolkit::Visual::Property::TYPE);
+      Property::Value* newTypeValue = visualMap.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
+      if( instanceTypeValue && newTypeValue )
+      {
+        int instanceVisualType=-1;
+        int newVisualType=-1;
+        Scripting::GetEnumerationProperty( *instanceTypeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, instanceVisualType );
+        Scripting::GetEnumerationProperty( *newTypeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, newVisualType );
+
+        if( instanceVisualType == newVisualType )
+        {
+          // Same type - merge remaining instance data
+          mergedMap.Merge( visualMap );
+          mergedMap.Merge( *instancedProperties );
+          applyMap = &mergedMap;
+        }
+      }
+    }
+
+    // Apply the visual property map to the handle
+    const Property::Value value(const_cast<Property::Map&>(*applyMap));
+    handle.SetProperty( index, value );
+  }
+}
+
+void Style::ApplyProperties( Handle handle ) const
+{
+  for( Property::Map::SizeType i=0; i<properties.Count(); ++i )
+  {
+    KeyValuePair keyValue = properties.GetKeyValue( i );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      handle.SetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+  }
+}
+
+Style::Style()
+{
+}
+Style::~Style()
+{
+}
+
+
+} // Internal
+} // Toolkit
+} // Dali
diff --git a/dali-toolkit/internal/builder/style.h b/dali-toolkit/internal/builder/style.h
new file mode 100644 (file)
index 0000000..441f568
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
+#define DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
+
+/*
+ * Copyright (c) 2017 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/ref-object.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+#include <dali-toolkit/internal/builder/dictionary.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class Style;
+typedef IntrusivePtr<Style> StylePtr;
+
+/**
+ * This class encapsulates the style information for a given styled
+ * control.  It is generated only when a control instance looks up
+ * it's style information for the first time, and then stored by
+ * Builder.
+ *
+ * It contains the visual, property and transition definitions for the
+ * main control and for each state and sub-state within the control.
+ *
+ * It has methods to enable the base control to apply visuals and
+ * properties per state.
+ */
+class Style : public RefObject
+{
+public:
+  static StylePtr New();
+
+public:
+  /**
+   * Apply the visuals and properties for the current state/substate
+   * of the handle to the control pointed at by handle. Recurses
+   * through sub-states.
+   *
+   * @param[in] handle The handle to apply the visuals to
+   * @param[in] instancedProperties The maps from which to get instanced properties
+   */
+  void ApplyVisualsAndPropertiesRecursively( Handle handle,
+                                             const Dictionary<Property::Map>& instancedProperties ) const;
+
+  /**
+   * Apply the visuals of the style to the control pointed at by
+   * handle.
+   *
+   * @param[in] handle The handle to apply the visuals to
+   * @param[in] instancedProperties The maps from which to get instanced properties
+   */
+  void ApplyVisuals( Handle handle,
+                     const Dictionary<Property::Map>& instancedProperties ) const;
+
+  /**
+   * Apply the properties from the visualMaps and the instancedProperties
+   * to the control pointed at by handle.
+   *
+   * @param[in] handle The handle to apply the properties to
+   * @param[in] visualMaps The visual maps from which to get the styled properties
+   * @param[in] instancedProperties The maps from which to get instanced properties
+   */
+  static void ApplyVisuals( Handle handle,
+                            const Dictionary<Property::Map>& visualMaps,
+                            const Dictionary<Property::Map>& instancedProperties );
+
+  /**
+   * Apply the properties from the visualMap and optional instancedProperties
+   * to the control pointed at by handle.
+   */
+  static void ApplyVisual( Handle handle,
+                           const std::string& visualName,
+                           const Property::Map& visualMap,
+                           const Property::Map* instancedProperties );
+
+  /**
+   * Apply the properties of the style to the control pointed at by
+   * handle.
+   *
+   * @param[in] handle The handle to apply the properties to
+   */
+  void ApplyProperties( Handle handle ) const;
+
+protected:
+  /**
+   * @brief Default constructor.
+   */
+  Style();
+
+  /**
+   * @brief virtual destructor.
+   */
+  virtual ~Style();
+
+private:
+  // Not implemented
+  DALI_INTERNAL Style( const Style& rhs );
+
+  // Not implemented
+  DALI_INTERNAL Style& operator=(const Style& rhs);
+
+public:
+  // Everything must be shallow-copiable.
+  Dictionary<StylePtr> subStates; // Each named style maps to a state.
+  Dictionary<Property::Map> visuals;
+  Property::Map properties;
+  Property::Array transitions;
+  Toolkit::TransitionData entryTransition;
+  Toolkit::TransitionData exitTransition;
+};
+
+} // Internal
+} // Toolkit
+} // Dali
+
+
+#endif //DALI_TOOLKIT_INTERNAL_BUILDER_STYLE_H
diff --git a/dali-toolkit/internal/builder/tree-node-manipulator.cpp b/dali-toolkit/internal/builder/tree-node-manipulator.cpp
new file mode 100644 (file)
index 0000000..9567306
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * 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 <cstring>
+#include <sstream>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/builder/tree-node-manipulator.h>
+
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+void Indent(std::ostream& o, int level, int indentWidth)
+{
+  for (int i = 0; i < level*indentWidth; ++i)
+  {
+    o << " ";
+  }
+}
+
+std::string EscapeQuotes( const char* aString)
+{
+  std::string escapedString;
+  int length = strlen(aString);
+  escapedString.reserve(length);
+
+  const char* end = aString+length;
+  for( const char* iter = aString; iter != end ; ++iter)
+  {
+    if(*iter != '\"')
+    {
+      escapedString.push_back(*iter);
+    }
+    else
+    {
+      escapedString.append("\\\"");
+    }
+  }
+  return escapedString;
+}
+
+} // anonymous namespace
+
+TreeNodeManipulator::TreeNodeManipulator(TreeNode* node)
+  : mNode(node)
+{
+}
+
+TreeNode* TreeNodeManipulator::NewTreeNode()
+{
+  return new TreeNode();
+}
+
+void TreeNodeManipulator::ShallowCopy(const TreeNode* from, TreeNode* to)
+{
+  DALI_ASSERT_DEBUG(from);
+  DALI_ASSERT_DEBUG(to);
+
+  if( from )
+  {
+    to->mName         = from->mName;
+    to->mType         = from->mType;
+    to->mSubstituion  = from->mSubstituion;
+    switch(from->mType)
+    {
+      case TreeNode::INTEGER:
+      {
+        to->mIntValue = from->mIntValue;
+        break;
+      }
+      case TreeNode::FLOAT:
+      {
+        to->mFloatValue = from->mFloatValue;
+        break;
+      }
+      case TreeNode::STRING:
+      {
+        to->mStringValue = from->mStringValue;
+        break;
+      }
+      case TreeNode::BOOLEAN:
+      {
+        to->mIntValue = from->mIntValue;
+        break;
+      }
+      case TreeNode::IS_NULL:
+      case TreeNode::OBJECT:
+      case TreeNode::ARRAY:
+      {
+        break;
+      }
+    }
+  }
+
+}
+
+void TreeNodeManipulator::MoveNodeStrings(VectorCharIter& start, const VectorCharIter& sentinel)
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  if(mNode->mName)
+  {
+    mNode->mName = CopyString(mNode->mName, start, sentinel);
+  }
+
+  if(TreeNode::STRING == mNode->mType)
+  {
+    mNode->mStringValue = CopyString(mNode->mStringValue, start, sentinel);
+  }
+}
+
+void TreeNodeManipulator::MoveStrings(VectorCharIter& start, const VectorCharIter& sentinel)
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  TreeNodeManipulator modify(mNode);
+  modify.MoveNodeStrings(start, sentinel);
+  RecurseMoveChildStrings(start, sentinel);
+}
+
+void TreeNodeManipulator::RecurseMoveChildStrings(VectorCharIter& start, const VectorCharIter& sentinel)
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  TreeNode* child = mNode->mFirstChild;
+  while(child)
+  {
+    TreeNodeManipulator manipChild(child);
+    manipChild.MoveNodeStrings(start, sentinel);
+    child = child->mNextSibling;
+  }
+
+  child = mNode->mFirstChild;
+  while(child)
+  {
+    TreeNodeManipulator manipChild(child);
+    manipChild.RecurseMoveChildStrings(start, sentinel);
+    child = child->mNextSibling;
+  }
+}
+
+void TreeNodeManipulator::RemoveChildren()
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  CollectNodes collector;
+
+  DepthFirst( mNode, collector );
+
+  for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
+  {
+    if( *iter != mNode)
+    {
+      delete *iter;
+    }
+  }
+
+  mNode->mFirstChild = NULL;
+  mNode->mLastChild  = NULL;
+}
+
+TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
+{
+  TreeNode* root = NewTreeNode();
+
+  ShallowCopy(&tree, root);
+
+  if(tree.mName)
+  {
+    numberChars += std::strlen(tree.mName) + 1;
+  }
+
+  if(TreeNode::STRING == tree.mType)
+  {
+    numberChars += std::strlen(tree.mStringValue) + 1;
+  }
+
+  ++numberNodes;
+
+  CopyChildren(&tree, root, numberNodes, numberChars);
+
+  return root;
+}
+
+void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
+{
+  DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
+  DALI_ASSERT_DEBUG(to);
+
+  for( TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
+  {
+    const TreeNode* child = &((*iter).second);
+    if(child->mName)
+    {
+      numberChars += std::strlen(child->mName) + 1;
+    }
+
+    if(TreeNode::STRING == child->mType)
+    {
+      numberChars += std::strlen(child->mStringValue) + 1;
+    }
+
+    TreeNode* newNode = NewTreeNode();
+
+    ShallowCopy(child, newNode);
+
+    TreeNodeManipulator modify(to);
+
+    modify.AddChild(newNode);
+
+    ++numberNodes;
+
+    CopyChildren(child, newNode, numberNodes, numberChars);
+  }
+}
+
+TreeNode *TreeNodeManipulator::AddChild(TreeNode *rhs)
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  rhs->mParent = mNode;
+  if (mNode->mLastChild)
+  {
+    mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
+  }
+  else
+  {
+    mNode->mFirstChild = mNode->mLastChild = rhs;
+  }
+  return rhs;
+}
+
+TreeNode::NodeType TreeNodeManipulator::GetType() const
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  return mNode->GetType();
+}
+
+size_t TreeNodeManipulator::Size() const
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  return mNode->Size();
+}
+
+void TreeNodeManipulator::SetType( TreeNode::NodeType type)
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+
+  if( mNode->mType != type )
+  {
+    mNode->mType = type;
+
+    if( NULL != mNode->mFirstChild )
+    {
+      // value types have no children
+      bool removeChildren = ! (TreeNode::OBJECT == type || TreeNode::ARRAY == type);
+
+      // ie if swapping array for object
+      removeChildren = (removeChildren == true) ? true : type != mNode->mType;
+
+      // so remove any children
+      if( removeChildren && NULL != mNode->mFirstChild)
+      {
+        RemoveChildren();
+      }
+    }
+  }
+  else if( TreeNode::ARRAY == mNode->mType )
+  {
+    if( mNode->mFirstChild != NULL )
+    {
+      TreeNode::NodeType type = mNode->mFirstChild->GetType();
+
+      if( TreeNode::FLOAT == type || TreeNode::INTEGER == type )
+      {
+        // Arrays of numbers should be replaced, not appended to.
+        RemoveChildren();
+      }
+    }
+  }
+}
+
+void TreeNodeManipulator::SetName( const char* name )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  mNode->mName = name;
+}
+
+void TreeNodeManipulator::SetSubstitution( bool b )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  mNode->mSubstituion = b;
+}
+
+TreeNode* TreeNodeManipulator::GetParent() const
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  return NULL == mNode ? NULL : mNode->mParent;
+}
+
+const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  return NULL == mNode ? NULL : mNode->GetChild(name);
+}
+
+void TreeNodeManipulator::SetString( const char* string )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  SetType(TreeNode::STRING);
+  mNode->mStringValue = string;
+}
+
+void TreeNodeManipulator::SetInteger( int i )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  SetType(TreeNode::INTEGER);
+  mNode->mIntValue = i;
+}
+
+void TreeNodeManipulator::SetFloat( float f )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  SetType(TreeNode::FLOAT);
+  mNode->mFloatValue = f;
+}
+
+void TreeNodeManipulator::SetBoolean( bool b )
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  SetType(TreeNode::BOOLEAN);
+  mNode->mIntValue = b == true ? 1 : 0;
+}
+
+void TreeNodeManipulator::Write(std::ostream& output, int indent) const
+{
+  DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
+  DoWrite(mNode, output, 0, indent, false);
+}
+
+void TreeNodeManipulator::DoWrite(const TreeNode *value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
+{
+  DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
+
+  if(!groupChildren)
+  {
+    Indent(output, level, indentWidth);
+  }
+
+  if (value->GetName())
+  {
+    output << "\"" << value->GetName() << "\":";
+  }
+
+  switch(value->GetType())
+  {
+    case TreeNode::IS_NULL:
+    {
+      output << "null";
+      if(NULL != value->mNextSibling)
+      {
+        output << ", ";
+      }
+      if( !groupChildren )
+      {
+        output << std::endl;
+      }
+      break;
+    }
+    case TreeNode::OBJECT:
+    case TreeNode::ARRAY:
+    {
+      bool groupMyChildren = false;
+
+      if( TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
+          ( TreeNode::INTEGER == value->mFirstChild->GetType() ||
+            TreeNode::FLOAT   == value->mFirstChild->GetType() ) )
+      {
+        groupMyChildren = true;
+      }
+
+      if( value->GetType() == TreeNode::OBJECT)
+      {
+        output << std::endl;
+        Indent(output, level, indentWidth);
+        output << "{";
+      }
+      else
+      {
+        if( !groupMyChildren )
+        {
+          output << std::endl;
+          Indent(output, level, indentWidth);
+        }
+        output << "[";
+      }
+
+      if( groupMyChildren )
+      {
+        output << " ";
+      }
+      else
+      {
+        output << std::endl;
+      }
+
+      for (TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
+      {
+        DoWrite( &((*it).second), output, level+1, indentWidth, groupMyChildren );
+      }
+
+      if( !groupMyChildren )
+      {
+        Indent(output, level, indentWidth);
+      }
+
+      if( value->GetType() == TreeNode::OBJECT )
+      {
+        output << "}";
+      }
+      else
+      {
+        output << "]";
+      }
+
+      if( NULL != value->mNextSibling )
+      {
+        output << ",";
+      }
+
+      if( !groupChildren )
+      {
+        output << std::endl;
+      }
+
+      groupChildren = false;
+      break;
+    }
+    case TreeNode::STRING:
+    {
+      std::string escapedString = EscapeQuotes(value->GetString());
+      output << "\"" << escapedString << "\"";
+      if(NULL != value->mNextSibling)
+      {
+        output << ",";
+      }
+
+      if( groupChildren )
+      {
+        output << " ";
+      }
+      else
+      {
+        output << std::endl;
+      }
+      break;
+    }
+    case TreeNode::INTEGER:
+    {
+      output << value->GetInteger();
+      if(NULL != value->mNextSibling)
+      {
+        output << ",";
+      }
+
+      if( groupChildren )
+      {
+        output << " ";
+      }
+      else
+      {
+        output << std::endl;
+      }
+      break;
+    }
+    case TreeNode::FLOAT:
+    {
+      output.setf( std::ios::floatfield );
+      output << value->GetFloat();
+      output.unsetf( std::ios::floatfield );
+      if(NULL != value->mNextSibling)
+      {
+        output << ",";
+      }
+
+      if( groupChildren )
+      {
+        output << " ";
+      }
+      else
+      {
+        output << std::endl;
+      }
+      break;
+    }
+    case TreeNode::BOOLEAN:
+    {
+      if( value->GetInteger() )
+      {
+        output << "true";
+      }
+      else
+      {
+        output << "false";
+      }
+
+      if(NULL != value->mNextSibling)
+      {
+        output << ",";
+      }
+
+      if( groupChildren )
+      {
+        output << " ";
+      }
+      else
+      {
+        output << std::endl;
+      }
+
+      break;
+    }
+  } // switch
+} // DoWrite
+
+
+const TreeNode* FindIt(const std::string& childName, const TreeNode* node)
+{
+  DALI_ASSERT_DEBUG(node);
+
+  const TreeNode* found = NULL;
+
+  if( node )
+  {
+    if( NULL != (found = node->GetChild(childName)) )
+    {
+      return found;
+    }
+    else
+    {
+      for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
+      {
+        if( NULL != (found = FindIt(childName, &((*iter).second)) ) )
+        {
+          return found;
+        }
+      }
+    }
+  }
+  return found;
+}
+
+char *CopyString( const char *fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
+{
+  DALI_ASSERT_DEBUG(fromString);
+  DALI_ASSERT_DEBUG(iter != sentinel);
+
+  char *start= &(*iter);
+  const char *ptr = fromString;
+
+  if(ptr)
+  {
+    while(*ptr != 0)
+    {
+      DALI_ASSERT_DEBUG(iter != sentinel);
+      *iter++ = *ptr++;
+    }
+
+    *iter++ = 0;
+  }
+  return start;
+}
+
+
+} // namespace internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/builder/tree-node-manipulator.h b/dali-toolkit/internal/builder/tree-node-manipulator.h
new file mode 100644 (file)
index 0000000..267c69e
--- /dev/null
@@ -0,0 +1,263 @@
+#ifndef DALI_SCRIPT_TREE_NODE_MANIPULATOR_H
+#define DALI_SCRIPT_TREE_NODE_MANIPULATOR_H
+
+/*
+ * Copyright (c) 2019 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 <utility> // pair
+#include <iterator>
+#include <cstring>
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+typedef std::vector<char> VectorChar;
+typedef VectorChar::iterator VectorCharIter;
+
+/*
+ * TreeNodeManipulator performs modification operations on a TreeNode which are
+ * otherwise prohibited on the TreeNode public interface.
+ */
+class TreeNodeManipulator
+{
+public:
+  /*
+   * Constructor
+   * @param node The TreeNode to modify
+   */
+  explicit TreeNodeManipulator(TreeNode* node);
+
+  /*
+   * Create a new TreeNode instance
+   * @return new TreeNode
+   */
+  static TreeNode* NewTreeNode();
+
+  /*
+   * Shallow copy node data
+   * Shallow copy the data but doesnt parent or copy children
+   * @param from Node to copy from
+   * @param to Node to copy to
+   */
+  static void ShallowCopy(const TreeNode* from, TreeNode* to);
+
+  /*
+   * Moves all string data to a new buffer. There must be enough space for all string data.
+   * @param start The buffer start
+   * @param sentinel The end of the buffer
+   */
+  void MoveStrings(VectorCharIter& start, const VectorCharIter& sentinel);
+
+  /*
+   * Remove all children from the node
+   */
+  void RemoveChildren();
+
+  /*
+   * Make a deep copy of the tree.
+   * @param tree The tree to copy
+   * @param numberOfNodes The number of nodes that were copied
+   * @param numberOfChars The size of string data.
+   */
+  static TreeNode* Copy(const TreeNode& tree, int& numberOfNodes, int& numberOfChars);
+
+  /*
+   * Add child to the node
+   * @param child The child to add
+   * @return the added child
+   */
+  TreeNode *AddChild(TreeNode *child);
+
+  /*
+   * Change the type of the Node
+   * NB: If the type changes from a type with children to a value type without children then
+   *     the children are removed
+   * @param type The new type
+   */
+  void SetType( TreeNode::NodeType type);
+
+  /*
+   * Set the name of the node
+   * @param name The name to set
+   */
+  void SetName( const char* name );
+
+  /*
+   * Set the substituion flag
+   * The substitution flag indicates this nodes string value contains a reference to another node
+   * in the tree.
+   * @param on The state
+   */
+  void SetSubstitution( bool on );
+
+  /*
+   * Get the nodes type
+   * @return The nodes type
+   */
+  TreeNode::NodeType GetType() const;
+
+  /*
+   * Get the number of children of the node
+   * @return The number of children
+   */
+  size_t Size() const;
+
+  /*
+   * Set the node as a string value
+   * @param string The string value
+   */
+  void SetString( const char* string );
+
+  /*
+   * Set the node as an integer value
+   * @param i The integer
+   */
+  void SetInteger( int i );
+
+  /*
+   * Set the node as an float value
+   * @param f The float
+   */
+  void SetFloat( float f );
+
+  /*
+   * Set the node as an boolean value
+   * @param b The boolean
+   */
+  void SetBoolean( bool b );
+
+  /*
+   * Get the nodes parent
+   * @return The nodes parent
+   */
+  TreeNode* GetParent() const;
+
+  /*
+   * Get the nodes child by name
+   * @param name The childs name
+   * @return The nodes if found, else NULL
+   */
+  const TreeNode* GetChild(const std::string& name) const;
+
+  /*
+   * @copydoc Dali::Scripting::JsonParser::Write()
+   */
+  void Write(std::ostream& output, int indent) const;
+
+private:
+  TreeNode *mNode;
+
+  /*
+   * Move the nodes strings to the buffer
+   */
+  void MoveNodeStrings(VectorCharIter& start, const VectorCharIter& sentinel);
+
+  /*
+   * Recursively move child strings to the buffer
+   */
+  void RecurseMoveChildStrings(VectorCharIter& start, const VectorCharIter& sentinel);
+
+  /*
+   * Recursively copy children
+   */
+  static void CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars);
+
+  /*
+   * Do write to string stream
+   */
+  void DoWrite(const TreeNode *value, std::ostream& output, int level, int ident, bool groupChildren) const;
+
+};
+
+/*
+ * Collect nodes
+ */
+struct CollectNodes : public std::unary_function<TreeNode*, void>
+{
+  CollectNodes() {};
+
+  /*
+   * Call operator to add nodes to the list
+   */
+  result_type operator()(argument_type& n)
+  {
+    DALI_ASSERT_DEBUG(n && "Operation on NULL JSON node");
+    nodes.push_back(n);
+  }
+
+  typedef std::vector<const TreeNode*> VectorNodes;
+  typedef VectorNodes::iterator iterator;
+
+  VectorNodes nodes; ///< List of collected nodes
+};
+
+/*
+ * Depth first walk of nodes applying given operation (unary_function)
+ */
+template <typename Operation>
+void DepthFirst( TreeNode* node, Operation& operation)
+{
+  DALI_ASSERT_DEBUG(node && "Operation on NULL JSON node");
+
+  for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
+  {
+    // iterator access is const for external api but were modifying
+    DepthFirst( const_cast<TreeNode*>(&((*iter).second)), operation);
+  }
+
+  operation(node);
+
+}
+
+/*
+ * Recursive search on the tree for the child with the given name
+ * @param childName The name to find
+ * @param tree The tree to search
+ * @return the TreeNode if found, else NULL
+ */
+const TreeNode* FindIt(const std::string& childName, const TreeNode* tree);
+
+/*
+ * Copy string to a buffer
+ * Raises if there is not enough space in the buffer
+ * @param fromString The string
+ * @param iter The start of the buffer
+ * @param sentinel The buffer sentinel
+ * @return The start of the given buffer
+ */
+char *CopyString( const char *fromString, VectorCharIter& iter, const VectorCharIter& sentinel);
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_SCRIPT_TREE_NODE_MANIPULATOR_H
diff --git a/dali-toolkit/internal/controls/alignment/alignment-impl.cpp b/dali-toolkit/internal/controls/alignment/alignment-impl.cpp
new file mode 100644 (file)
index 0000000..6641d26
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "alignment-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-input.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+//Type Registration
+BaseHandle Create()
+{
+  return Toolkit::Alignment::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Alignment, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+/**
+ * @param padding The padding value
+ * @param horizontalAlignment The horizontal alignment.
+ * @param verticalAlignment The vertical alignment.
+ * @param currentSize of the object
+ * @param parentSize
+ */
+inline Vector3 GetPosition( const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment,
+                            const Vector2& currentSize, const Vector2& parentSize )
+{
+  Vector3 position( 0.f, 0.f, 0.f );
+
+  switch( horizontalAlignment )
+  {
+    case Dali::Toolkit::Alignment::HorizontalLeft:
+    {
+      position.x += padding.left;
+      break;
+    }
+    case Dali::Toolkit::Alignment::HorizontalRight:
+    {
+      position.x -= padding.right;
+      break;
+    }
+    case Dali::Toolkit::Alignment::HorizontalCenter: // FALLTHROUGH
+    default: // use center as default
+    {
+      if( currentSize.width + padding.left + padding.right >= parentSize.width )
+      {
+        position.x += 0.5f * ( padding.left - padding.right );
+      }
+      break;
+    }
+  }
+
+  switch( verticalAlignment )
+  {
+    case Dali::Toolkit::Alignment::VerticalTop:
+    {
+      position.y += padding.top;
+      break;
+    }
+    case Dali::Toolkit::Alignment::VerticalBottom:
+    {
+      position.y -= padding.bottom;
+      break;
+    }
+    case Dali::Toolkit::Alignment::VerticalCenter: // FALLTHROUGH
+    default: // use center as default
+    {
+      if( currentSize.height + padding.top + padding.bottom >= parentSize.height )
+      {
+        position.y += 0.5f * ( padding.top - padding.bottom );
+      }
+      break;
+    }
+  }
+
+  return position;
+}
+
+} // namespace
+
+Toolkit::Alignment Alignment::New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< Alignment > internalAlignment = new Alignment( horizontal, vertical );
+
+  // Pass ownership to Toolkit::Alignment
+  Toolkit::Alignment alignment( *internalAlignment );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalAlignment->Initialize();
+
+  return alignment;
+}
+
+void Alignment::SetAlignmentType( Toolkit::Alignment::Type type )
+{
+  // Horizontal Alignment
+  if( type & Toolkit::Alignment::HorizontalRight )
+  {
+    mHorizontal = Toolkit::Alignment::HorizontalRight;
+  }
+  if( type & Toolkit::Alignment::HorizontalLeft )
+  {
+    mHorizontal = Toolkit::Alignment::HorizontalLeft;
+  }
+  if( type & Toolkit::Alignment::HorizontalCenter )
+  {
+    mHorizontal = Toolkit::Alignment::HorizontalCenter;
+  }
+
+  // Vertical Alignment
+  if( type & Toolkit::Alignment::VerticalBottom )
+  {
+    mVertical = Toolkit::Alignment::VerticalBottom;
+  }
+  if( type & Toolkit::Alignment::VerticalTop )
+  {
+    mVertical = Toolkit::Alignment::VerticalTop;
+  }
+  if( type & Toolkit::Alignment::VerticalCenter )
+  {
+    mVertical = Toolkit::Alignment::VerticalCenter;
+  }
+
+  RelayoutRequest();
+}
+
+Toolkit::Alignment::Type Alignment::GetAlignmentType() const
+{
+  return Toolkit::Alignment::Type( mHorizontal | mVertical );
+}
+
+void Alignment::SetScaling( Toolkit::Alignment::Scaling scaling )
+{
+  mScaling = scaling;
+
+  RelayoutRequest();
+}
+
+Toolkit::Alignment::Scaling Alignment::GetScaling() const
+{
+  return mScaling;
+}
+
+void Alignment::SetPadding( const Toolkit::Alignment::Padding& padding )
+{
+  DALI_ASSERT_ALWAYS( ( padding.left >= 0.f ) && ( padding.top >= 0.f ) && ( padding.right >= 0.f ) && ( padding.bottom >= 0.f ) );
+
+  mPadding = padding;
+
+  RelayoutRequest();
+}
+
+const Toolkit::Alignment::Padding& Alignment::GetPadding() const
+{
+  return mPadding;
+}
+
+void Alignment::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  // lay out the actors
+  Vector3 anchorPointAndParentOrigin  = Vector3::ZERO;
+  anchorPointAndParentOrigin.z = 0.5f;
+  // anchorPoint.x is initialized to 0.0, which is HorizontalLeft
+  if( Toolkit::Alignment::HorizontalCenter == mHorizontal )
+  {
+    anchorPointAndParentOrigin.x = 0.5f;
+  }
+  else if( Toolkit::Alignment::HorizontalRight == mHorizontal )
+  {
+    anchorPointAndParentOrigin.x = 1.0f;
+  }
+  // anchorPoint.y is initialized to 0.0, which is VerticalTop
+  if( Toolkit::Alignment::VerticalCenter == mVertical )
+  {
+    anchorPointAndParentOrigin.y = 0.5f;
+  }
+  else if( Toolkit::Alignment::VerticalBottom == mVertical )
+  {
+    anchorPointAndParentOrigin.y = 1.0f;
+  }
+
+  for( unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i )
+  {
+    Actor child = Self().GetChildAt(i);
+
+    child.SetAnchorPoint( anchorPointAndParentOrigin );
+    child.SetParentOrigin( anchorPointAndParentOrigin );
+
+    Vector2 currentChildSize( child.GetTargetSize().GetVectorXY() );
+    if( currentChildSize == Vector2::ZERO )
+    {
+      currentChildSize = child.GetNaturalSize();
+    }
+
+    bool renegotiate = true;
+    Vector2 newChildSize;
+    newChildSize.width  = size.width - ( mPadding.left + mPadding.right );
+    newChildSize.height = size.height- (  mPadding.top + mPadding.bottom );
+
+    // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
+    if( ( newChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( newChildSize.height > Math::MACHINE_EPSILON_1000 ) &&
+        ( currentChildSize.width > Math::MACHINE_EPSILON_1000 ) && ( currentChildSize.height > Math::MACHINE_EPSILON_1000 ) )
+    {
+      // no point trying to squeeze actors into too small size
+      switch( mScaling )
+      {
+        case Toolkit::Alignment::ScaleNone:
+        {
+          // Nothing to do
+          renegotiate = false;
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFill:
+        {
+          // Nothing to do, newChildSize is already full size minus padding
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFitKeepAspect:
+        {
+          newChildSize = currentChildSize * std::min( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ScaleToFillKeepAspect:
+        {
+          newChildSize = currentChildSize * std::max( ( newChildSize.width / currentChildSize.width ), ( newChildSize.height / currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ShrinkToFit:
+        {
+          newChildSize = Vector2( std::min( newChildSize.width, currentChildSize.width ), std::min( newChildSize.height, currentChildSize.height ) );
+          break;
+        }
+        case Toolkit::Alignment::ShrinkToFitKeepAspect:
+        {
+          // check source size vs target size to see if we need to shrink
+          float widthScale = ( newChildSize.width < currentChildSize.width ) ? (newChildSize.width / currentChildSize.width) : 1.f;
+          float heightScale = ( newChildSize.height < currentChildSize.height ) ? (newChildSize.height / currentChildSize.height) : 1.0f;
+          // use smaller of the scales
+          float scale = std::min( widthScale, heightScale );
+          // check if we need to scale
+          if( scale < 1.0f )
+          {
+            // scale natural size to fit inside
+            newChildSize *= scale;
+          }
+          break;
+        }
+      }
+    }
+
+    child.SetPosition( GetPosition( mPadding, mHorizontal, mVertical , newChildSize, currentChildSize ) );
+
+    if( renegotiate )
+    {
+      container.Add( child, newChildSize );
+    }
+  }
+}
+
+Alignment::Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mHorizontal( horizontal ),
+  mVertical( vertical ),
+  mScaling( Toolkit::Alignment::ScaleNone ),
+  mPadding( 0.f, 0.f, 0.f, 0.f )
+{
+}
+
+Alignment::~Alignment()
+{
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/alignment/alignment-impl.h b/dali-toolkit/internal/controls/alignment/alignment-impl.h
new file mode 100644 (file)
index 0000000..83f5301
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ALIGNMENT_H
+#define DALI_TOOLKIT_INTERNAL_ALIGNMENT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/alignment/alignment.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class Alignment;
+
+namespace Internal
+{
+
+/**
+ * Alignment is a control to position and resize actors inside other container actors.
+ * @see Dali::Toolkit::Alignment for more details.
+ */
+class Alignment : public Control
+{
+public:
+
+  /**
+   * Create an initialized Alignment.
+   * @param type Type of alignment.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static Toolkit::Alignment New( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical );
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::SetAlignmentType()
+   */
+  void SetAlignmentType( Toolkit::Alignment::Type type );
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::GetAlignmentType()
+   */
+  Toolkit::Alignment::Type GetAlignmentType() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::SetScaling()
+   */
+  void SetScaling( Toolkit::Alignment::Scaling scaling );
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::GetScaling()
+   */
+  Toolkit::Alignment::Scaling GetScaling() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::SetPadding()
+   */
+  void SetPadding( const Toolkit::Alignment::Padding& padding );
+
+  /**
+   * @copydoc Dali::Toolkit::Alignment::GetPadding()
+   */
+  const Toolkit::Alignment::Padding& GetPadding() const;
+
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+private:
+
+  /**
+   * Constructor.
+   * It initializes Alignment members.
+   */
+  Alignment( Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Alignment();
+
+private:
+
+  // Undefined
+  Alignment(const Alignment&);
+  Alignment& operator=(const Alignment&);
+
+private:
+  Toolkit::Alignment::Type    mHorizontal; ///< Type of alignment.
+  Toolkit::Alignment::Type    mVertical;   ///< Type of alignment.
+  Toolkit::Alignment::Scaling mScaling;    ///< Stores the geometry scaling.
+  Toolkit::Alignment::Padding mPadding;    ///< Stores the padding values.
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Alignment& GetImpl( Toolkit::Alignment& alignment )
+{
+  DALI_ASSERT_ALWAYS( alignment );
+
+  Dali::RefObject& handle = alignment.GetImplementation();
+
+  return static_cast<Toolkit::Internal::Alignment&>( handle );
+}
+
+inline const Toolkit::Internal::Alignment& GetImpl( const Toolkit::Alignment& alignment )
+{
+  DALI_ASSERT_ALWAYS( alignment );
+
+  const Dali::RefObject& handle = alignment.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::Alignment&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_ALIGNMENT_H
diff --git a/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp b/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp
new file mode 100644 (file)
index 0000000..14f179b
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2017 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 "bloom-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+#include <dali-toolkit/devel-api/controls/bloom-view/bloom-view.h>
+#include <dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+using namespace Dali;
+
+BaseHandle Create()
+{
+  return Toolkit::BloomView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::BloomView, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+// default parameters
+const float BLOOM_THRESHOLD_DEFAULT = 0.25f;
+const float BLOOM_BLUR_STRENGTH_DEFAULT = 1.0f;
+const float BLOOM_INTENSITY_DEFAULT = 1.0f;
+const float IMAGE_INTENSITY_DEFAULT = 1.0f;
+const float BLOOM_SATURATION_DEFAULT = 1.0f;
+const float IMAGE_SATURATION_DEFAULT = 1.0f;
+
+// gaussian blur
+const unsigned int BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
+const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
+const Pixel::Format BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
+const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_FADE_IN = 1.0f;                                       // default, fully blurred
+const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
+const float BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
+
+const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
+
+const char* const BLOOM_BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
+const char* const BLOOM_THRESHOLD_PROPERTY_NAME = "uBloomThreshold";
+const char* const RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME = "uRecipOneMinusBloomThreshold";
+const char* const BLOOM_INTENSITY_PROPERTY_NAME = "uBloomIntensity";
+const char* const BLOOM_SATURATION_PROPERTY_NAME = "uBloomSaturation";
+const char* const IMAGE_INTENSITY_PROPERTY_NAME = "uImageIntensity";
+const char* const IMAGE_SATURATION_PROPERTY_NAME = "uImageSaturation";
+
+///////////////////////////////////////////////////////
+//
+// Bloom shaders
+//
+
+const char* const BLOOM_EXTRACT_FRAGMENT_SOURCE =
+  "varying mediump vec2 vTexCoord;\n"
+  "uniform sampler2D sTexture;\n"
+  "uniform lowp vec4 uColor;\n"
+  "uniform mediump float uBloomThreshold;\n"
+  "uniform mediump float uRecipOneMinusBloomThreshold;\n"
+  "void main()\n"
+  "{\n"
+  "  mediump vec4 col;\n"
+  "  col = texture2D(sTexture, vTexCoord);\n"
+  "  col = (col - uBloomThreshold) * uRecipOneMinusBloomThreshold;\n" // remove intensities lower than the thresold and remap intensities above the threshold to [0..1]
+  "  gl_FragColor = clamp(col, 0.0, 1.0);\n"
+  "}\n";
+
+const char* const COMPOSITE_FRAGMENT_SOURCE =
+  "precision mediump float;\n"
+  "varying mediump vec2 vTexCoord;\n"
+  "uniform sampler2D sTexture;\n"
+  "uniform sampler2D sEffect;\n"
+  "uniform lowp vec4 uColor;\n"
+  "uniform float uBloomIntensity;\n"
+  "uniform float uImageIntensity;\n"
+  "uniform float uBloomSaturation;\n"
+  "uniform float uImageSaturation;\n"
+
+  "vec4 ChangeSaturation(vec4 col, float sat)\n"
+  "{\n"
+  "  float grey = dot(col.rgb, vec3(0.3, 0.6, 0.1));\n"
+  "  return mix(vec4(grey, grey, grey, 1.0), col, sat);\n"
+  "}\n"
+
+  "void main()\n"
+  "{\n"
+  "  mediump vec4 image;\n"
+  "  mediump vec4 bloom;\n"
+  "  image = texture2D(sTexture, vTexCoord);\n"
+  "  bloom = texture2D(sEffect, vTexCoord);\n"
+  "  image = ChangeSaturation(image, uImageSaturation) * uImageIntensity;\n"
+  "  bloom = ChangeSaturation(bloom, uBloomSaturation) * uBloomIntensity;\n"
+  "  image *= 1.0 - clamp(bloom, 0.0, 1.0);\n" // darken base where bloom is strong, to prevent excessive burn-out of result
+  "  gl_FragColor = image + bloom;\n"
+  "}\n";
+
+} // namespace
+
+
+
+BloomView::BloomView()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mBlurNumSamples(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
+  mBlurBellCurveWidth(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH),
+  mPixelFormat(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
+  mDownsampleWidthScale(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
+  mDownsampleHeightScale(BLOOM_GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
+  mDownsampledWidth( 0.0f ),
+  mDownsampledHeight( 0.0f ),
+  mTargetSize(Vector2::ZERO),
+  mLastSize(Vector2::ZERO),
+  mChildrenRoot(Actor::New()),
+  mInternalRoot(Actor::New() ),
+  mBloomThresholdPropertyIndex(Property::INVALID_INDEX),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mBloomIntensityPropertyIndex(Property::INVALID_INDEX),
+  mBloomSaturationPropertyIndex(Property::INVALID_INDEX),
+  mImageIntensityPropertyIndex(Property::INVALID_INDEX),
+  mImageSaturationPropertyIndex(Property::INVALID_INDEX),
+  mActivated( false )
+{
+}
+
+BloomView::BloomView( const unsigned int blurNumSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                    const float downsampleWidthScale, const float downsampleHeightScale)
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mBlurNumSamples(blurNumSamples),
+  mBlurBellCurveWidth(blurBellCurveWidth),
+  mPixelFormat(renderTargetPixelFormat),
+  mDownsampleWidthScale(downsampleWidthScale),
+  mDownsampleHeightScale(downsampleHeightScale),
+  mDownsampledWidth( 0.0f ),
+  mDownsampledHeight( 0.0f ),
+  mTargetSize(Vector2::ZERO),
+  mLastSize(Vector2::ZERO),
+  mChildrenRoot(Actor::New()),
+  mInternalRoot(Actor::New()),
+  mBloomThresholdPropertyIndex(Property::INVALID_INDEX),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mBloomIntensityPropertyIndex(Property::INVALID_INDEX),
+  mBloomSaturationPropertyIndex(Property::INVALID_INDEX),
+  mImageIntensityPropertyIndex(Property::INVALID_INDEX),
+  mImageSaturationPropertyIndex(Property::INVALID_INDEX),
+  mActivated( false )
+{
+}
+
+BloomView::~BloomView()
+{
+}
+
+Toolkit::BloomView BloomView::New()
+{
+  BloomView* impl = new BloomView();
+
+  Dali::Toolkit::BloomView handle = Dali::Toolkit::BloomView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+Toolkit::BloomView BloomView::New(const unsigned int blurNumSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                                const float downsampleWidthScale, const float downsampleHeightScale)
+{
+  BloomView* impl = new BloomView( blurNumSamples, blurBellCurveWidth, renderTargetPixelFormat, downsampleWidthScale, downsampleHeightScale);
+
+  Dali::Toolkit::BloomView handle = Dali::Toolkit::BloomView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+///////////////////////////////////////////////////////////
+//
+// Private methods
+//
+
+void BloomView::OnInitialize()
+{
+  // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
+  mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
+  mInternalRoot.SetParentOrigin( ParentOrigin::CENTER );
+
+  //////////////////////////////////////////////////////
+  // Create actors
+
+  // Create an image view for rendering from the scene texture to the bloom texture
+  mBloomExtractActor = Actor::New();
+  mBloomExtractActor.SetParentOrigin( ParentOrigin::CENTER );
+
+  // Create an image view for compositing the result (scene and bloom textures) to output
+  mCompositeActor = Actor::New();
+  mCompositeActor.SetParentOrigin( ParentOrigin::CENTER );
+
+  // Create an image view for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
+  mTargetActor = Actor::New();
+  mTargetActor.SetParentOrigin( ParentOrigin::CENTER );
+
+  // Create the Gaussian Blur object + render tasks
+  // Note that we use mBloomExtractTarget as the source image and also re-use this as the gaussian blur final render target. This saves the gaussian blur code from creating it
+  // render targets etc internally, so we make better use of resources
+  // Note, this also internally creates the render tasks used by the Gaussian blur, this must occur after the bloom extraction and before the compositing
+  mGaussianBlurView = Dali::Toolkit::GaussianBlurView::New(mBlurNumSamples, mBlurBellCurveWidth, mPixelFormat, mDownsampleWidthScale, mDownsampleHeightScale, true);
+  mGaussianBlurView.SetParentOrigin( ParentOrigin::CENTER );
+
+
+  //////////////////////////////////////////////////////
+  // Create cameras for the renders corresponding to the (potentially downsampled) render targets' size
+  mRenderDownsampledCamera = CameraActor::New();
+  mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
+  mRenderDownsampledCamera.SetInvertYAxis( true );
+
+  mRenderFullSizeCamera = CameraActor::New();
+  mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
+  mRenderFullSizeCamera.SetInvertYAxis( true );
+
+
+  ////////////////////////////////
+  // Connect to actor tree
+  Self().Add( mChildrenRoot );
+  Self().Add( mInternalRoot );
+  mInternalRoot.Add( mBloomExtractActor );
+  mInternalRoot.Add( mGaussianBlurView );
+  mInternalRoot.Add( mCompositeActor );
+  mInternalRoot.Add( mTargetActor );
+  mInternalRoot.Add( mRenderDownsampledCamera );
+  mInternalRoot.Add( mRenderFullSizeCamera );
+
+  // bind properties for / set shader constants to defaults
+  SetupProperties();
+}
+
+void BloomView::OnSizeSet(const Vector3& targetSize)
+{
+  mTargetSize = Vector2(targetSize);
+  mChildrenRoot.SetSize(targetSize);
+  mCompositeActor.SetSize(targetSize);
+  mTargetActor.SetSize(targetSize);
+
+  // Children render camera must move when GaussianBlurView object is
+  // resized. This is since we cannot change render target size - so we need
+  // to remap the child actors' rendering accordingly so they still exactly
+  // fill the render target. Note that this means the effective resolution of
+  // the child render changes as the GaussianBlurView object changes size,
+  // this is the trade off for not being able to modify render target size
+  // Change camera z position based on GaussianBlurView actor height
+  float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
+  mRenderFullSizeCamera.SetZ( mTargetSize.height * cameraPosConstraintScale);
+
+  // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
+  if(mActivated)
+  {
+    Deactivate();
+    Activate();
+  }
+
+  Control::OnSizeSet( targetSize );
+}
+
+void BloomView::OnChildAdd( Actor& child )
+{
+  if( child != mChildrenRoot && child != mInternalRoot)
+  {
+    mChildrenRoot.Add( child );
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void BloomView::OnChildRemove( Actor& child )
+{
+  mChildrenRoot.Remove( child );
+
+  Control::OnChildRemove( child );
+}
+
+void BloomView::AllocateResources()
+{
+  // size of render targets etc is based on the size of this actor, ignoring z
+  if(mTargetSize != mLastSize || !mActivated)
+  {
+    mLastSize = mTargetSize;
+
+    // get size of downsampled render targets
+    mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
+    mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
+
+
+    //////////////////////////////////////////////////////
+    // Create cameras
+
+    // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
+    mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+    mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
+    mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
+    mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+
+    mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
+
+    // Create and place a camera for the children render, corresponding to its render target size
+    mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+    mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
+    mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
+    mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+
+    float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
+    mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
+
+    //////////////////////////////////////////////////////
+    // Pass size change onto GaussianBlurView, so it matches
+    mGaussianBlurView.SetSize(mTargetSize);
+    GetImpl(mGaussianBlurView).AllocateResources();
+
+    mGaussianBlurView.SetVisible( true );
+
+    //////////////////////////////////////////////////////
+    // Create render targets
+
+    // create off screen buffer of new size to render our child actors to
+    mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+    Texture textureForChildren = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+    mRenderTargetForRenderingChildren.AttachColorTexture( textureForChildren );
+
+    mBloomExtractTarget = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
+    Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight) );
+    mBloomExtractTarget.AttachColorTexture( texture );
+
+    FrameBuffer blurExtractTarget = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
+    texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight) );
+    blurExtractTarget.AttachColorTexture( texture );
+
+    mOutputRenderTarget = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+    Texture outputTexture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+    mOutputRenderTarget.AttachColorTexture( outputTexture );
+
+    //////////////////////////////////////////////////////
+    // Point actors and render tasks at new render targets
+
+    Renderer bloomRenderer = CreateRenderer( BASIC_VERTEX_SOURCE, BLOOM_EXTRACT_FRAGMENT_SOURCE );
+    SetRendererTexture( bloomRenderer, mRenderTargetForRenderingChildren );
+    mBloomExtractActor.AddRenderer( bloomRenderer );
+    mBloomExtractActor.SetSize( mDownsampledWidth, mDownsampledHeight ); // size needs to match render target
+
+    // set GaussianBlurView to blur our extracted bloom
+    mGaussianBlurView.SetUserImageAndOutputRenderTarget( mBloomExtractTarget.GetColorTexture(), blurExtractTarget );
+
+    // use the completed blur in the first buffer and composite with the original child actors render
+    Renderer compositeRenderer = CreateRenderer( BASIC_VERTEX_SOURCE, COMPOSITE_FRAGMENT_SOURCE );
+    SetRendererTexture( compositeRenderer, mRenderTargetForRenderingChildren );
+    TextureSet textureSet = compositeRenderer.GetTextures();
+    textureSet.SetTexture( 0u, mRenderTargetForRenderingChildren.GetColorTexture() );
+    textureSet.SetTexture( 1u, blurExtractTarget.GetColorTexture() );
+    mCompositeActor.AddRenderer( compositeRenderer );
+
+    // set up target actor for rendering result, i.e. the blurred image
+    Renderer targetRenderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
+    SetRendererTexture( targetRenderer, mOutputRenderTarget );
+    mTargetActor.AddRenderer( targetRenderer );
+  }
+}
+
+void BloomView::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // create render task to render our child actors to offscreen buffer
+  mRenderChildrenTask = taskList.CreateTask();
+  mRenderChildrenTask.SetSourceActor( mChildrenRoot );
+  mRenderChildrenTask.SetExclusive(true);
+  mRenderChildrenTask.SetInputEnabled( false );
+  mRenderChildrenTask.SetClearEnabled( true );
+  mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera); // use camera that covers render target exactly
+  mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
+
+  // Extract the bright part of the image and render to a new buffer. Downsampling also occurs at this stage to save pixel fill, if it is set up.
+  mBloomExtractTask = taskList.CreateTask();
+  mBloomExtractTask.SetSourceActor( mBloomExtractActor );
+  mBloomExtractTask.SetExclusive(true);
+  mBloomExtractTask.SetInputEnabled( false );
+  mBloomExtractTask.SetClearEnabled( true );
+  mBloomExtractTask.SetCameraActor(mRenderDownsampledCamera);
+  mBloomExtractTask.SetFrameBuffer( mBloomExtractTarget );
+
+  // GaussianBlurView tasks must be created here, so they are executed in the correct order with respect to BloomView tasks
+  GetImpl(mGaussianBlurView).CreateRenderTasks();
+
+  // Use an image view displaying the children render and composite it with the blurred bloom buffer, targeting the output
+  mCompositeTask = taskList.CreateTask();
+  mCompositeTask.SetSourceActor( mCompositeActor );
+  mCompositeTask.SetExclusive(true);
+  mCompositeTask.SetInputEnabled( false );
+  mCompositeTask.SetClearEnabled( true );
+  mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
+  mCompositeTask.SetFrameBuffer( mOutputRenderTarget );
+}
+
+void BloomView::RemoveRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  taskList.RemoveTask(mRenderChildrenTask);
+  taskList.RemoveTask(mBloomExtractTask);
+
+  GetImpl(mGaussianBlurView).RemoveRenderTasks();
+
+  taskList.RemoveTask(mCompositeTask);
+}
+
+void BloomView::Activate()
+{
+  // make sure resources are allocated and start the render tasks processing
+  AllocateResources();
+  CreateRenderTasks();
+  mActivated = true;
+}
+
+void BloomView::Deactivate()
+{
+  // stop render tasks processing
+  // Note: render target resources are automatically freed since we set the Image::Unused flag
+  RemoveRenderTasks();
+
+  mRenderTargetForRenderingChildren.Reset();
+  mBloomExtractTarget.Reset();
+  mOutputRenderTarget.Reset();
+
+  // Reset children
+  mBloomExtractActor.RemoveRenderer( 0u );
+  mTargetActor.RemoveRenderer( 0u );
+  mCompositeActor.RemoveRenderer( 0u );
+
+  mGaussianBlurView.SetVisible( false );
+
+  mActivated = false;
+}
+
+/**
+ * RecipOneMinusConstraint
+ *
+ * f(current, property) = property
+ */
+struct RecipOneMinusConstraint
+{
+  RecipOneMinusConstraint(){}
+
+  void operator()( float& current, const PropertyInputContainer& inputs )
+  {
+    current = 1.0f / ( 1.0f - inputs[0]->GetFloat() );
+  }
+};
+
+// create properties and constraints to tie internal shader etc settings to BloomView object. User can therefore animate / set them via BloomView object without knowing about
+// internal implementation classes
+void BloomView::SetupProperties()
+{
+  CustomActor self = Self();
+
+
+  ///////////////////////////////////////////
+  // bloom threshold
+
+  // set defaults, makes sure properties are registered with shader
+  mBloomExtractActor.RegisterProperty( BLOOM_THRESHOLD_PROPERTY_NAME, BLOOM_THRESHOLD_DEFAULT );
+  mBloomExtractActor.RegisterProperty( RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME, 1.0f / (1.0f - BLOOM_THRESHOLD_DEFAULT) );
+
+  // Register a property that the user can control to change the bloom threshold
+  mBloomThresholdPropertyIndex = self.RegisterProperty(BLOOM_THRESHOLD_PROPERTY_NAME, BLOOM_THRESHOLD_DEFAULT);
+  Property::Index shaderBloomThresholdPropertyIndex = mBloomExtractActor.GetPropertyIndex(BLOOM_THRESHOLD_PROPERTY_NAME);
+  Constraint bloomThresholdConstraint = Constraint::New<float>( mBloomExtractActor, shaderBloomThresholdPropertyIndex, EqualToConstraint());
+  bloomThresholdConstraint.AddSource( Source(self, mBloomThresholdPropertyIndex) );
+  bloomThresholdConstraint.Apply();
+
+  // precalc 1.0 / (1.0 - threshold) on CPU to save shader insns, using constraint to tie to the normal threshold property
+  Property::Index shaderRecipOneMinusBloomThresholdPropertyIndex = mBloomExtractActor.GetPropertyIndex(RECIP_ONE_MINUS_BLOOM_THRESHOLD_PROPERTY_NAME);
+  Constraint thresholdConstraint = Constraint::New<float>( mBloomExtractActor, shaderRecipOneMinusBloomThresholdPropertyIndex, RecipOneMinusConstraint());
+  thresholdConstraint.AddSource( LocalSource(shaderBloomThresholdPropertyIndex) );
+  thresholdConstraint.Apply();
+
+
+  ////////////////////////////////////////////
+  // bloom strength
+
+  // Register a property that the user can control to fade the blur in / out via internal GaussianBlurView object
+  mBlurStrengthPropertyIndex = self.RegisterProperty(BLOOM_BLUR_STRENGTH_PROPERTY_NAME, BLOOM_BLUR_STRENGTH_DEFAULT);
+  Constraint blurStrengthConstraint = Constraint::New<float>( mGaussianBlurView, mGaussianBlurView.GetBlurStrengthPropertyIndex(), EqualToConstraint());
+  blurStrengthConstraint.AddSource( Source(self, mBlurStrengthPropertyIndex) );
+  blurStrengthConstraint.Apply();
+
+
+  ////////////////////////////////////////////
+  // bloom intensity
+
+  // Register a property that the user can control to fade the bloom intensity via internally hidden shader
+  mBloomIntensityPropertyIndex = self.RegisterProperty(BLOOM_INTENSITY_PROPERTY_NAME, BLOOM_INTENSITY_DEFAULT);
+  mCompositeActor.RegisterProperty( BLOOM_INTENSITY_PROPERTY_NAME, BLOOM_INTENSITY_DEFAULT );
+  Property::Index shaderBloomIntensityPropertyIndex = mCompositeActor.GetPropertyIndex(BLOOM_INTENSITY_PROPERTY_NAME);
+  Constraint bloomIntensityConstraint = Constraint::New<float>( mCompositeActor, shaderBloomIntensityPropertyIndex, EqualToConstraint());
+  bloomIntensityConstraint.AddSource( Source(self, mBloomIntensityPropertyIndex) );
+  bloomIntensityConstraint.Apply();
+
+
+  ////////////////////////////////////////////
+  // bloom saturation
+
+  // Register a property that the user can control to fade the bloom saturation via internally hidden shader
+  mBloomSaturationPropertyIndex = self.RegisterProperty(BLOOM_SATURATION_PROPERTY_NAME, BLOOM_SATURATION_DEFAULT);
+  mCompositeActor.RegisterProperty( BLOOM_SATURATION_PROPERTY_NAME, BLOOM_SATURATION_DEFAULT );
+  Property::Index shaderBloomSaturationPropertyIndex = mCompositeActor.GetPropertyIndex(BLOOM_SATURATION_PROPERTY_NAME);
+  Constraint bloomSaturationConstraint = Constraint::New<float>( mCompositeActor, shaderBloomSaturationPropertyIndex, EqualToConstraint());
+  bloomSaturationConstraint.AddSource( Source(self, mBloomSaturationPropertyIndex) );
+  bloomSaturationConstraint.Apply();
+
+
+  ////////////////////////////////////////////
+  // image intensity
+
+  // Register a property that the user can control to fade the image intensity via internally hidden shader
+  mImageIntensityPropertyIndex = self.RegisterProperty(IMAGE_INTENSITY_PROPERTY_NAME, IMAGE_INTENSITY_DEFAULT);
+  mCompositeActor.RegisterProperty( IMAGE_INTENSITY_PROPERTY_NAME, IMAGE_INTENSITY_DEFAULT );
+  Property::Index shaderImageIntensityPropertyIndex = mCompositeActor.GetPropertyIndex(IMAGE_INTENSITY_PROPERTY_NAME);
+  Constraint imageIntensityConstraint = Constraint::New<float>( mCompositeActor, shaderImageIntensityPropertyIndex, EqualToConstraint());
+  imageIntensityConstraint.AddSource( Source(self, mImageIntensityPropertyIndex) );
+  imageIntensityConstraint.Apply();
+
+
+  ////////////////////////////////////////////
+  // image saturation
+
+  // Register a property that the user can control to fade the image saturation via internally hidden shader
+  mImageSaturationPropertyIndex = self.RegisterProperty(IMAGE_SATURATION_PROPERTY_NAME, IMAGE_SATURATION_DEFAULT);
+  mCompositeActor.RegisterProperty( IMAGE_SATURATION_PROPERTY_NAME, IMAGE_SATURATION_DEFAULT );
+  Property::Index shaderImageSaturationPropertyIndex = mCompositeActor.GetPropertyIndex(IMAGE_SATURATION_PROPERTY_NAME);
+  Constraint imageSaturationConstraint = Constraint::New<float>( mCompositeActor, shaderImageSaturationPropertyIndex, EqualToConstraint());
+  imageSaturationConstraint.AddSource( Source(self, mImageSaturationPropertyIndex) );
+  imageSaturationConstraint.Apply();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.h b/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.h
new file mode 100644 (file)
index 0000000..0377146
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BLOOM_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_BLOOM_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <sstream>
+#include <cmath>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/bloom-view/bloom-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class BloomView;
+
+namespace Internal
+{
+
+/**
+ * BloomEffect implementation class
+ */
+class BloomView : public Control
+{
+public:
+  /**
+   * @copydoc Dali::Toolkit::BloomView::BloomView
+   */
+  BloomView();
+
+  /**
+   * @copydoc Dali::Toolkit::BloomView::BloomView
+   */
+  BloomView(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                   const float downsampleWidthScale, const float downsampleHeightScale);
+
+  /**
+   * @copydoc Dali::Toolkit::BloomView::~BloomView
+   */
+  virtual ~BloomView();
+
+  /**
+   * @copydoc Dali::Toolkit::BloomView::New
+   */
+  static Dali::Toolkit::BloomView New();
+  static Dali::Toolkit::BloomView New( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                              const float downsampleWidthScale, const float downsampleHeightScale);
+  void Activate();
+  void Deactivate();
+
+  Property::Index GetBloomThresholdPropertyIndex() const {return mBloomThresholdPropertyIndex;}
+  Property::Index GetBlurStrengthPropertyIndex() const {return mBlurStrengthPropertyIndex;}
+  Property::Index GetBloomIntensityPropertyIndex() const {return mBloomIntensityPropertyIndex;}
+  Property::Index GetBloomSaturationPropertyIndex() const {return mBloomSaturationPropertyIndex;}
+  Property::Index GetImageIntensityPropertyIndex() const {return mImageIntensityPropertyIndex;}
+  Property::Index GetImageSaturationPropertyIndex() const {return mImageSaturationPropertyIndex;}
+
+private:
+
+  virtual void OnInitialize();
+  virtual void OnSizeSet(const Vector3& targetSize);
+
+  /**
+   * @copydoc Control::OnChildAdd()
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnChildRemove()
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  void AllocateResources();
+  void CreateRenderTasks();
+  void RemoveRenderTasks();
+
+  void SetupProperties();
+
+
+  /////////////////////////////////////////////////////////////
+  unsigned int mBlurNumSamples;   // number of blur samples in each of horiz/vert directions
+  float mBlurBellCurveWidth;      // constant used when calculating the gaussian weights
+  Pixel::Format mPixelFormat;     // pixel format used by render targets
+
+  /////////////////////////////////////////////////////////////
+  // downsampling is used for the separated blur passes to get increased blur with the same number of samples and also to make rendering quicker
+  float mDownsampleWidthScale;
+  float mDownsampleHeightScale;
+  float mDownsampledWidth;
+  float mDownsampledHeight;
+
+
+  /////////////////////////////////////////////////////////////
+  // for checking if we need to reallocate render targets
+  Vector2 mTargetSize;
+  Vector2 mLastSize;
+
+  /////////////////////////////////////////////////////////////
+  // for creating a subtree for all user added child actors, so that we can have them exclusive to the mRenderChildrenTask and our other actors exclusive to our other tasks
+  Actor mChildrenRoot;
+  // for creating a subtree for the internal actors
+  Actor mInternalRoot;
+
+  /////////////////////////////////////////////////////////////
+  // for mapping offscreen renders to render target sizes
+  CameraActor mRenderFullSizeCamera;
+  CameraActor mRenderDownsampledCamera;
+
+  /////////////////////////////////////////////////////////////
+  // for rendering all user added children to offscreen target
+  FrameBuffer mRenderTargetForRenderingChildren;
+  RenderTask mRenderChildrenTask;
+
+  /////////////////////////////////////////////////////////////
+  // for extracting bright parts of image to an offscreen target
+  FrameBuffer mBloomExtractTarget; // for rendering bright parts of image into separate texture, also used as target for gaussian blur
+  RenderTask mBloomExtractTask;
+  Actor mBloomExtractActor;
+
+  /////////////////////////////////////////////////////////////
+  // for blurring extracted bloom
+  Dali::Toolkit::GaussianBlurView mGaussianBlurView;
+
+  /////////////////////////////////////////////////////////////
+  // for compositing bloom and children renders to offscreen target
+  RenderTask mCompositeTask;
+
+  Actor mCompositeActor;
+
+  /////////////////////////////////////////////////////////////
+  // for holding blurred result
+  FrameBuffer mOutputRenderTarget;
+  Actor mTargetActor;
+
+  /////////////////////////////////////////////////////////////
+  // Properties for setting by user, e.g. by animations
+  Property::Index mBloomThresholdPropertyIndex;
+  Property::Index mBlurStrengthPropertyIndex;
+  Property::Index mBloomIntensityPropertyIndex;
+  Property::Index mBloomSaturationPropertyIndex;
+  Property::Index mImageIntensityPropertyIndex;
+  Property::Index mImageSaturationPropertyIndex;
+
+  bool mActivated:1;
+
+private:
+
+  // Undefined copy constructor.
+  BloomView( const BloomView& );
+
+  // Undefined assignment operator.
+  BloomView& operator=( const BloomView& );
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::BloomView& GetImpl( Toolkit::BloomView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::BloomView&>(handle);
+}
+
+inline const Toolkit::Internal::BloomView& GetImpl( const Toolkit::BloomView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::BloomView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BLOOM_VIEW_H
diff --git a/dali-toolkit/internal/controls/bubble-effect/bubble-effect.h b/dali-toolkit/internal/controls/bubble-effect/bubble-effect.h
new file mode 100644 (file)
index 0000000..65b485f
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUBBLE_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_BUBBLE_EFFECT_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/rendering/shader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Create the shader to be used by the renderer
+ * @param[in] numberOfBubble How many groups of uniforms are used to control the bubble movement.
+ * @return A handle to the newly created shader.
+ */
+inline Shader CreateBubbleShader( unsigned int numBubble )
+{
+  const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump float   aIndex;\n
+  attribute mediump vec2    aPosition;\n
+  attribute highp   vec2    aTexCoord;\n
+  varying   mediump vec2    vTexCoord;\n
+  uniform   mediump mat4    uMvpMatrix;\n
+  // the gravity applied to the y direction
+  uniform mediump float uGravity;\n
+  // xy: the emit position of the bubble; zw: the destination of the bubble.
+  // The bubble is moving from (xy) to (zw plus the y drop influenced by gravity).
+  uniform vec4 uStartEndPosition[NUMBER_OF_BUBBLE];\n
+  // The undergoing percentage of the bubble movement. 0.0: start from emit position, 1.0: reach the destination
+  uniform float uPercentage[NUMBER_OF_BUBBLE];\n
+  uniform vec2 uInvertedMovementArea;\n
+  // The bubble number is restricted by the available uniform num.
+  // To increase the displayed bubble, every uStartEndPosition and uPercentage uniform is applied to a small bunch of bubbles (9 here)
+  // The offset defines the random offset between bubbles within the bunch.
+  uniform vec2 uOffset[9];\n
+  // This uniform is used to change the bubble size during running time
+  uniform float uDynamicScale;\n
+  varying float vPercentage;\n
+  varying vec2  vEffectTexCoord;\n
+  void main()\n
+  {\n
+    vec4 position = vec4( aPosition, 0.0, 1.0 );\n
+    // The Z coordinate is used to record the bubble index within current mesh actor
+    int index = int(aIndex); \n
+    //for some i between 0 ~ NUMBER_OF_BUBBLE-1: i,i+NUMBER_OF_BUBBLE, i+NUMBER_OF_BUBBLE*2, ... (up to i+NUMBER_OF_BUBBLE*8) belongs to the same bunch.
+    int groupIdx = index / NUMBER_OF_BUBBLE;\n
+    // The bubbles within the same bunch applies the same uniforms uStartEndPosition[idx] & uPercentage[idx]
+    int idx = index - groupIdx*NUMBER_OF_BUBBLE;\n
+    float percentage = uPercentage[idx];
+    // early out if uPercentage is (zero || one) setting position to zero (zero sized triangles)
+    if( percentage <= 0.0 || percentage >= 1.0 )\n
+    {\n
+      gl_Position = vec4(0.0);\n
+      return;\n
+    }\n
+    vec4 startAndEnd = uStartEndPosition[idx];\n
+    // The final position is added up different offset for bubbles
+    startAndEnd.zw += uOffset[groupIdx];\n
+    \n
+    // increase the bubble size from 0% to 100% during the first 1/5 of movement & apply the dynamic scale
+    // the new xy value containes both the new scale and new bubble position
+    position.xy *= uDynamicScale*min(percentage*5.0, 1.0);\n
+    position.xy += mix(startAndEnd.xy, startAndEnd.zw, percentage);\n
+    // The gravity is g*t*t on the y direction
+    position.y += uGravity * pow(percentage, 2.0);\n
+    gl_Position = uMvpMatrix * position;\n
+    \n
+    // Add multiple bubble shapes in the effect
+    vTexCoord = aTexCoord;\n
+    vPercentage = percentage;\n
+    // Use the emit position color for the bubble
+    vEffectTexCoord = startAndEnd.xy * uInvertedMovementArea + vec2(0.5);\n
+  }\n
+  );
+
+  const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2  vTexCoord;\n
+  uniform lowp    vec4  uColor;\n
+  uniform sampler2D     sBackground;\n
+  uniform sampler2D     sBubbleShape;\n
+  varying mediump float vPercentage;\n
+  varying mediump vec2  vEffectTexCoord;\n
+  \n
+  void main()\n
+  {\n
+    // Get the emit pisition color, and Mix with the actor color
+    mediump vec4 fragColor = texture2D(sBackground, vEffectTexCoord)*uColor;\n
+    // Apply the shape defined by the texture contained sBubbleShape
+    // And make the opacity being 0.7, and animate from 0.7 to 0 during the last 1/3 of movement
+    fragColor.a  *= texture2D(sBubbleShape, vTexCoord).a * ( 2.1 - max( vPercentage*2.1, 1.4 ) );\n
+    gl_FragColor = fragColor;\n
+  }\n
+  );
+
+  std::ostringstream vertexShaderStringStream;
+  vertexShaderStringStream << "#define NUMBER_OF_BUBBLE "<< numBubble << "\n"
+                           << VERTEX_SHADER;
+  Shader shader = Shader::New( vertexShaderStringStream.str(), FRAGMENT_SHADER );
+
+  return shader;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+#endif // DALI_TOOLKIT_INTERNAL_BUBBLE_EFFECT_H
diff --git a/dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.cpp b/dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.cpp
new file mode 100644 (file)
index 0000000..d4c46ea
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "bubble-emitter-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/bubble-effect/bubble-effect.h>
+#include <dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h>
+
+namespace
+{
+struct Vertex
+{
+  Vertex()
+  : index( 0.0f ), position(), textureCoord()
+  {
+  }
+
+  Vertex( float index, const Dali::Vector2& position, const Dali::Vector2& textureCoord )
+  : index( index ), position( position ), textureCoord( textureCoord )
+  {
+  }
+
+  float index;
+  Dali::Vector2 position;
+  Dali::Vector2 textureCoord;
+};
+
+/**
+ * Return a random value between the given interval.
+ * @param[in] f0 The low bound
+ * @param[in] f1 The up bound
+ * @param[in] seed The seed to genergate random number
+ * @return A random value between the given interval
+ */
+float RandomRange(float f0, float f1, unsigned int& seed)
+{
+  return f0 + (rand_r( &seed ) & 0xfff) * (f1-f0) * (1.0f/4095.0f);
+}
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  attribute mediump vec2 aTexCoord;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * vec4(aPosition*uSize.xy,0.0,1.0);
+    vTexCoord = aTexCoord;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+    precision highp float;\n
+    uniform vec3 uHSVDelta;\n
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    float rand(vec2 co) \n
+    {\n
+      return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n}
+    \n
+    vec3 rgb2hsv(vec3 c)\n
+    {\n
+      vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n
+      vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n
+      vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n
+      \n
+      float d = q.x - min(q.w, q.y);\n
+      float e = 1.0e-10;\n
+      return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n
+    }\n
+    vec3 hsv2rgb(vec3 c)\n
+    {\n
+      vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n
+      vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n
+      return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n
+    }\n
+    void main() {\n
+      vec4 color = texture2D(sTexture, vTexCoord); \n
+      vec3 hsvColor = rgb2hsv( color.rgb );\n
+      // modify the hsv Value
+      hsvColor += uHSVDelta * rand(vTexCoord); \n
+      // if the new vale exceeds one, then decrease it
+      hsvColor -= max(hsvColor*2.0 - vec3(2.0), 0.0);\n
+      // if the new vale drops below zero, then increase it
+      hsvColor -= min(hsvColor*2.0, 0.0);\n
+      color = vec4( hsv2rgb( hsvColor ), 1.0 ); \n
+      gl_FragColor = color; \n
+    }\n
+  );
+
+Dali::Geometry CreateTexturedQuad()
+{
+  struct Vertex
+  {
+    Dali::Vector2 position;
+    Dali::Vector2 texCoord;
+  };
+
+  static const Vertex data[] = {{ Dali::Vector2( -0.5f, -0.5f ), Dali::Vector2( 0.0f, 0.0f ) },
+                                { Dali::Vector2(  0.5f, -0.5f ), Dali::Vector2( 1.0f, 0.0f ) },
+                                { Dali::Vector2( -0.5f,  0.5f ), Dali::Vector2( 0.0f, 1.0f ) },
+                                { Dali::Vector2(  0.5f,  0.5f ), Dali::Vector2( 1.0f, 1.0f ) }};
+
+  //Create a vertex buffer for vertex positions and texture coordinates
+  Dali::PropertyBuffer vertexBuffer = Dali::PropertyBuffer::New( Dali::Property::Map()
+                                              .Add( "aPosition", Dali::Property::VECTOR2 )
+                                              .Add( "aTexCoord", Dali::Property::VECTOR2 ) );
+  vertexBuffer.SetData( data, 4u );
+
+  //Create the geometry
+  Dali::Geometry geometry = Dali::Geometry::New();
+  geometry.AddVertexBuffer( vertexBuffer );
+  geometry.SetType(Dali::Geometry::TRIANGLE_STRIP );
+
+  return geometry;
+}
+
+}
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+BubbleEmitter::BubbleEmitter( const Vector2& movementArea,
+                              Texture shapeTexture,
+                              unsigned int maximumNumberOfBubble,
+                              const Vector2& bubbleSizeRange )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mShapeTexture( shapeTexture ),
+  mMovementArea( movementArea ),
+  mBubbleSizeRange( bubbleSizeRange ),
+  mDensity( 5 ),
+  mTotalNumOfBubble( maximumNumberOfBubble ),
+  mCurrentBubble( 0 ),
+  mRandomSeed( 0 ),
+  mRenderTaskRunning(false)
+{
+  // Calculate how many shaders are required
+  if( mTotalNumOfBubble>100 )
+  {
+    mNumBubblePerRenderer = 100;
+    mNumRenderer = mTotalNumOfBubble / 100;
+    if( mNumRenderer*mNumBubblePerRenderer < mTotalNumOfBubble )
+    {
+      mNumRenderer++;
+      mNumBubblePerRenderer =  mTotalNumOfBubble / mNumRenderer+1;
+      mTotalNumOfBubble = mNumRenderer * mNumBubblePerRenderer;
+    }
+  }
+  else
+  {
+    mNumBubblePerRenderer = mTotalNumOfBubble;
+    mNumRenderer = 1;
+  }
+
+  mRandomSeed = time( NULL );
+}
+
+BubbleEmitter::~BubbleEmitter()
+{
+}
+
+Toolkit::BubbleEmitter BubbleEmitter::New( const Vector2& winSize,
+                                           Texture shapeTexture,
+                                           unsigned int maximumNumberOfBubble,
+                                           const Vector2& bubbleSizeRange )
+{
+  // Create the implementation
+   IntrusivePtr<BubbleEmitter> internalBubbleEmitter ( new BubbleEmitter( winSize, shapeTexture,
+                                                            maximumNumberOfBubble,bubbleSizeRange ) );
+
+  // Pass ownership to Toolkit::BubbleEmitter handle
+  Toolkit::BubbleEmitter bubbleEmitter( *internalBubbleEmitter );
+
+  //Second phase of implementeation : Initialization
+  internalBubbleEmitter->OnInitialize();
+
+  return bubbleEmitter;
+}
+
+void BubbleEmitter::OnInitialize()
+{
+  // Create the root actor, all the meshActor should be its children
+  mBubbleRoot = Actor::New();
+  mBubbleRoot.SetSize(mMovementArea);
+
+  // Prepare the frame buffer to store the color adjusted background texture
+  Vector2 imageSize = Vector2( mMovementArea.width/4.f, mMovementArea.height/4.f );
+  mFrameBuffer = FrameBuffer::New( imageSize.x, imageSize.y, 0 );
+  mEffectTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, imageSize.x, imageSize.y );
+  mFrameBuffer.AttachColorTexture( mEffectTexture );
+
+  // Generate the geometry, which is used by all bubbleActors
+  mMeshGeometry =  CreateGeometry( mNumBubblePerRenderer*mDensity );
+
+  Shader bubbleShader = CreateBubbleShader( mNumBubblePerRenderer );
+
+  mTextureSet = TextureSet::New();
+  mTextureSet.SetTexture( 0u, mEffectTexture );
+  mTextureSet.SetTexture( 1u, mShapeTexture );
+
+  // Create the renderers to render the bubbles
+  mBubbleRenderers.resize( mNumRenderer );
+  for(unsigned int i=0; i < mNumRenderer; i++ )
+  {
+    mBubbleRenderers[i].Initialize( mNumBubblePerRenderer, mMovementArea, mMeshGeometry, mTextureSet, bubbleShader );
+    mBubbleRoot.AddRenderer( mBubbleRenderers[i].GetRenderer() );
+  }
+
+  // Create a cameraActor for the off screen render task.
+  mCameraActor = CameraActor::New(mMovementArea);
+  mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
+
+  Stage stage = Stage::GetCurrent();
+
+  stage.Add(mCameraActor);
+  stage.ContextRegainedSignal().Connect(this, &BubbleEmitter::OnContextRegained);
+}
+
+Actor BubbleEmitter::GetRootActor()
+{
+  return mBubbleRoot;
+}
+
+void BubbleEmitter::SetBackground( Texture bgTexture, const Vector3& hsvDelta )
+{
+  mBackgroundTexture = bgTexture;
+  mHSVDelta = hsvDelta;
+
+  //Create RenderTask source actor
+  Actor sourceActor = Actor::New();
+  sourceActor.SetSize( mMovementArea );
+  sourceActor.SetParentOrigin(ParentOrigin::CENTER);
+  sourceActor.RegisterProperty( "uHSVDelta", hsvDelta );
+  Stage::GetCurrent().Add( sourceActor );
+
+  //Create renderer
+  Dali::Geometry geometry = CreateTexturedQuad();
+  Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+  Renderer renderer = Renderer::New( geometry, shader );
+  TextureSet textureSet = TextureSet::New();
+  textureSet.SetTexture(0u, bgTexture );
+  renderer.SetTextures( textureSet );
+  sourceActor.AddRenderer( renderer );
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  RenderTask task = taskList.CreateTask();
+  task.SetRefreshRate( RenderTask::REFRESH_ONCE );
+  task.SetSourceActor( sourceActor );
+  task.SetExclusive(true);
+  task.SetCameraActor(mCameraActor);
+  task.GetCameraActor().SetInvertYAxis(true);
+  task.SetFrameBuffer( mFrameBuffer );
+  task.FinishedSignal().Connect(this, &BubbleEmitter::OnRenderFinished);
+  mRenderTaskRunning = true;
+}
+
+void BubbleEmitter::SetBubbleShape( Texture shapeTexture )
+{
+  mTextureSet.SetTexture( 1, shapeTexture );
+}
+
+void BubbleEmitter::SetBubbleScale( float scale )
+{
+  for(unsigned int i=0; i < mNumRenderer; i++ )
+  {
+    mBubbleRenderers[i].SetDynamicScale( scale );
+  }
+}
+
+void BubbleEmitter::SetBubbleDensity( unsigned int density )
+{
+  DALI_ASSERT_ALWAYS( density>0 && density<=9 && " Only densities between 1 to 9 are valid " );
+
+  if( density == mDensity )
+  {
+    return;
+  }
+  else
+  {
+    mDensity = density;
+    mMeshGeometry =  CreateGeometry( mNumBubblePerRenderer*mDensity );
+    for(unsigned int i=0; i < mNumRenderer; i++ )
+    {
+      mBubbleRenderers[i].SetGeometry( mMeshGeometry );
+    }
+  }
+}
+
+// clear the resources created for the off screen rendering
+void BubbleEmitter::OnRenderFinished(RenderTask& source)
+{
+  mRenderTaskRunning = false;
+  Actor sourceActor = source.GetSourceActor();
+  Stage stage = Stage::GetCurrent();
+  stage.Remove(sourceActor);
+  stage.GetRenderTaskList().RemoveTask(source);
+}
+
+void BubbleEmitter::OnContextRegained()
+{
+  // Context was lost, so the framebuffer has been destroyed. Re-create render task
+  // and trigger re-draw if not already running
+  if( ! mRenderTaskRunning )
+  {
+    SetBackground( mBackgroundTexture, mHSVDelta );
+  }
+}
+
+void BubbleEmitter::EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
+{
+  unsigned int curUniform = mCurrentBubble  % mNumBubblePerRenderer;
+  unsigned int groupIdx = mCurrentBubble / mNumBubblePerRenderer;
+  SetBubbleParameter( mBubbleRenderers[groupIdx], curUniform, emitPosition - Vector2(mMovementArea.x*0.5f,mMovementArea.y*0.5f), direction, displacement);
+  animation.AnimateTo( mBubbleRenderers[groupIdx].GetPercentageProperty(curUniform),
+                       1.f, AlphaFunction::LINEAR );
+
+  mCurrentBubble = (mCurrentBubble + 1) % mTotalNumOfBubble;
+}
+
+void BubbleEmitter::Restore()
+{
+  for(unsigned int i=0; i < mNumRenderer; i++ )
+  {
+    mBubbleRenderers[i].ResetProperties();
+  }
+}
+
+Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
+{
+  unsigned int numVertex = numOfPatch*4u;
+  Vector<Vertex> vertexData;
+  vertexData.Reserve( numVertex );
+
+  unsigned int numIndex = numOfPatch*6u;
+  Vector<unsigned short> indexData;
+  indexData.Reserve( numIndex );
+
+  for(unsigned int i = 0; i < numOfPatch; i++)
+  {
+    float halfSize = RandomRange(mBubbleSizeRange.x, mBubbleSizeRange.y, mRandomSeed) * 0.5f;
+
+    float index = static_cast<float>( i );
+    vertexData.PushBack( Vertex( index, Vector2(-halfSize,-halfSize),Vector2(0.f,0.f) ) );
+    vertexData.PushBack( Vertex( index, Vector2(-halfSize, halfSize), Vector2(0.f,1.f) ) );
+    vertexData.PushBack( Vertex( index, Vector2( halfSize, halfSize),  Vector2(1.f,1.f) ) );
+    vertexData.PushBack( Vertex( index, Vector2( halfSize,-halfSize), Vector2(1.f,0.f) ) );
+
+    unsigned short idx = index * 4;
+    indexData.PushBack( idx );
+    indexData.PushBack( idx+1 );
+    indexData.PushBack( idx+2 );
+    indexData.PushBack( idx );
+    indexData.PushBack( idx+2 );
+    indexData.PushBack( idx+3 );
+  }
+
+  Property::Map vertexFormat;
+  vertexFormat["aIndex"] = Property::FLOAT;
+  vertexFormat["aPosition"] = Property::VECTOR2;
+  vertexFormat["aTexCoord"] = Property::VECTOR2;
+  PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
+  vertices.SetData( &vertexData[0], numVertex );
+
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertices );
+  geometry.SetIndexBuffer( &indexData[0], numIndex );
+
+  return geometry;
+}
+
+void BubbleEmitter::SetBubbleParameter( BubbleRenderer& bubbleRenderer, unsigned int curUniform,
+                                        const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement )
+{
+  Vector2 dir(direction);
+
+  int halfRange = displacement.x / 2;
+  // for the y coordinate, always negative, so bubbles always go upwards
+  Vector2 randomVec( rand_r( &mRandomSeed ) % static_cast<int>(displacement.x) - halfRange, -rand_r( &mRandomSeed ) % static_cast<int>(displacement.y) );
+  dir.Normalize();
+  randomVec.x -= dir.x*halfRange;
+  randomVec.y *= 1.0f - fabsf(dir.x)*0.33f;
+
+  if(randomVec.y > 0.0f)
+  {
+    randomVec.y *= 0.33f;
+  }
+  Vector4 startAndEndPos( emitPosition.x, emitPosition.y, emitPosition.x+randomVec.x, emitPosition.y+randomVec.y );
+  bubbleRenderer.SetStartAndEndPosition( curUniform, startAndEndPos );
+
+  bubbleRenderer.SetPercentage( curUniform, 0.f);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.h b/dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.h
new file mode 100644 (file)
index 0000000..e6879ae
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUBBLE_EMITTER_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_BUBBLE_EMITTER_IMPL_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/property-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/sampler.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/bubble-effect/bubble-emitter.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class BubbleRenderer;
+
+/**
+ * BubbleEmitter implementation class.
+ */
+class BubbleEmitter : public Control
+{
+public:
+
+  /**
+   * Destructor
+   */
+  ~BubbleEmitter();
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::New
+   */
+  static Toolkit::BubbleEmitter New( const Vector2& winSize,
+                                     Texture shapeTexture,
+                                     unsigned int maximumNumberOfBubble,
+                                     const Vector2& bubbleSizeRange );
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::GetRootActor
+   */
+  Actor GetRootActor();
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::SetBackground
+   */
+  void SetBackground( Texture bgTexture, const Vector3& hsvDelta );
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::SetShape
+   */
+  void SetBubbleShape( Texture shapeTexture );
+
+  /**
+   * @copydoc Toolkit::BubbleEmiter::SetBubbleScale
+   */
+  void SetBubbleScale( float scale );
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::SetBubbleDensity
+   */
+  void SetBubbleDensity( unsigned int density );
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::EmitBubble
+   */
+  void EmitBubble( Animation& animation, const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement );
+
+  /**
+   * @copydoc Toolkit::BubbleEmitter::Restore
+   */
+  void Restore();
+
+private:
+
+  /**
+   * Construct a new BubbleEmitter object.
+   * @param[in] movementArea The size of the bubble moving area
+   * @param[in] shapeTexture The alpha channnel of this texture defines the bubble shape.
+   * @param[in] maximumNumberOfBubble The maximum number of bubble needed.
+   * @param[in] bubbleSizeRange The size range of the bubbles; x component is the minimal size, and y component is the maximum size.
+   */
+  BubbleEmitter( const Vector2& movementArea,
+                 Texture shapeTexture,
+                 unsigned int maximumNumberOfBubble,
+                 const Vector2& bubbleSizeRange );
+
+  /**
+   * This method is called after the CubeTransitionEffect has been initialized.
+   * The meshActors and BubbleEffects are created here.
+   */
+  void OnInitialize();
+
+  /**
+   * Create the geometry of a mesh.
+   * @param[in] numOfPatch The triangle number in the mesh is 2*numOfPatch; two triangles for each bubble.
+   * @return The mesh geometry.
+   */
+  Geometry CreateGeometry( unsigned int numOfPatch );
+
+  /**
+   * Callback function of the finished signal of off-screen render task.
+   * @param[in] source The render task used to create the color adjusted background texture.
+   */
+  void OnRenderFinished(RenderTask& source);
+
+  /**
+   * Callback function from Stage to tell us if the context has been regained.
+   */
+  void OnContextRegained();
+
+  /**
+   * Set the uniform values to the shader effect to emit a bubble
+   * @param[in] bubbleRenderer The BubbleRenderer
+   * @param[in] curUniform The index of the uniform array in the shader
+   * @param[in] emitPosition The start position of the bubble movement.
+   * @param[in] direction The direction used to constrain the bubble to move in an adjacent direction around it.
+   * @param[in] displacement The displacement used to bound the moving distance of the bubble.
+   */
+  void SetBubbleParameter( BubbleRenderer& bubbleRenderer, unsigned int curUniform,
+                           const Vector2& emitPosition, const Vector2& direction, const Vector2& displacement );
+
+private:
+
+  Actor                       mBubbleRoot;          ///<The bubble root actor. Need to add it to stage to get the bubbles rendered.
+  Texture                     mShapeTexture;        ///< The alpha channnel of this texture defines the bubble shape.
+  Texture                     mBackgroundTexture;   ///< The original background texture
+  Texture                     mEffectTexture;       ///< Texture which stores the adjusted color of the background image.The bubbles pick color from this image.
+  FrameBuffer                 mFrameBuffer;         ///< FrameBuffer used for offscreen rendering
+  CameraActor                 mCameraActor;         ///< The render task views the scene from the perspective of this actor.
+
+  Geometry                    mMeshGeometry;         ///< The mesh geometry which contains the vertices and indices data
+  TextureSet                  mTextureSet;           ///< The texture set which controls the bubble display
+  std::vector<BubbleRenderer> mBubbleRenderers;      ///< The BubbleRenderer vector, its size is mNumShader.
+
+  Vector2                     mMovementArea;        ///< The size of the bubble moving area, usually the same size as the background.
+  Vector2                     mBubbleSizeRange;     ///< The size range of the bubbles; x component is the low bound, and y component is the up bound.
+  Vector3                     mHSVDelta;            ///< The HSV difference used to adjust the background image color.
+
+  unsigned int                mNumBubblePerRenderer;   ///< How many bubbles for each BubbleRenderer.
+  unsigned int                mNumRenderer;            ///< How many BubbleRenderers are used.
+  unsigned int                mDensity;             ///< How many bubbles will emit at each time, they are controlled by same uniforms in the shader.
+  unsigned int                mTotalNumOfBubble;    ///< mNumBubblePerShader*mNumShader.
+  unsigned int                mCurrentBubble;       ///< Keep track of the index for the newly emitted bubble
+  unsigned int                mRandomSeed;          ///< Seed to generate random number.
+
+  bool                        mRenderTaskRunning;   ///< If the background render task is currently running
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Internal::BubbleEmitter& GetImpl(Dali::Toolkit::BubbleEmitter& obj)
+{
+  DALI_ASSERT_ALWAYS(obj && "BubbleEmitter handle is empty");
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::BubbleEmitter&>(handle);
+}
+
+inline const Internal::BubbleEmitter& GetImpl(const Dali::Toolkit::BubbleEmitter& obj)
+{
+  DALI_ASSERT_ALWAYS(obj && "BubbleEmitter handle is empty");
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::BubbleEmitter&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUBBLE_EMITTER_IMPL_H
diff --git a/dali-toolkit/internal/controls/bubble-effect/bubble-renderer.cpp b/dali-toolkit/internal/controls/bubble-effect/bubble-renderer.cpp
new file mode 100644 (file)
index 0000000..88b1a85
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "bubble-renderer.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+#include <sstream>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+BubbleRenderer::BubbleRenderer()
+: mRenderer(),
+  mIndicesOffset(),
+  mIndiceStartEndPos(),
+  mIndicesPercentage(),
+  mIndexGravity( Property::INVALID_INDEX ),
+  mIndexDynamicScale( Property::INVALID_INDEX ),
+  mIndexInvertedMovementArea( Property::INVALID_INDEX )
+{
+}
+
+void BubbleRenderer::Initialize( unsigned int numberOfBubble, const Vector2& movementArea, Geometry geometry, TextureSet textureSet, Shader shader  )
+{
+  if( mRenderer )
+  {
+    // This function is supposed to be called once
+    return;
+  }
+
+  mRenderer = Renderer::New( geometry, shader );
+  mRenderer.SetTextures( textureSet );
+
+  // register uniforms
+  mIndexGravity = mRenderer.RegisterProperty( "uGravity", 50.f );
+  mIndexDynamicScale = mRenderer.RegisterProperty( "uDynamicScale", 1.f );
+
+  mIndexInvertedMovementArea = mRenderer.RegisterProperty( "uInvertedMovementArea", Vector2(1.f,1.f) / movementArea );
+
+  mIndicesOffset.resize(9);
+  int offset = movementArea.Length() / 10.f;
+
+  unsigned int seed = time( NULL );
+
+  mIndicesOffset[0] = mRenderer.RegisterProperty( "uOffset[0]", Vector2( 0.f,0.f ) );
+  mIndicesOffset[1] = mRenderer.RegisterProperty( "uOffset[1]", Vector2( rand_r( &seed ) % offset,  rand_r( &seed ) % offset ) );
+  mIndicesOffset[2] = mRenderer.RegisterProperty( "uOffset[2]", Vector2( rand_r( &seed ) % offset, -rand_r( &seed ) % offset ) );
+  mIndicesOffset[3] = mRenderer.RegisterProperty( "uOffset[3]", Vector2(-rand_r( &seed ) % offset,  rand_r( &seed ) % offset ) );
+  mIndicesOffset[4] = mRenderer.RegisterProperty( "uOffset[4]", Vector2(-rand_r( &seed ) % offset, -rand_r( &seed ) % offset ) );
+  mIndicesOffset[5] = mRenderer.RegisterProperty( "uOffset[5]", Vector2( rand_r( &seed ) % offset, 0.f ) );
+  mIndicesOffset[6] = mRenderer.RegisterProperty( "uOffset[6]", Vector2(-rand_r( &seed ) % offset, 0.f ) );
+  mIndicesOffset[7] = mRenderer.RegisterProperty( "uOffset[7]", Vector2( 0.f,  rand_r( &seed ) % offset ) );
+  mIndicesOffset[8] = mRenderer.RegisterProperty( "uOffset[8]", Vector2( 0.f, -rand_r( &seed ) % offset ) );
+
+  Vector4 zeroVector;
+  mIndiceStartEndPos.resize( numberOfBubble );
+  mIndicesPercentage.resize( numberOfBubble );
+  for( unsigned int i=0; i<numberOfBubble; i++ )
+  {
+    std::ostringstream ossProperty;
+    ossProperty<< "uStartEndPosition["<< i << "]";
+    mIndiceStartEndPos[i] = mRenderer.RegisterProperty( ossProperty.str(), zeroVector );
+
+    ossProperty.str("");
+    ossProperty<< "uPercentage["<< i << "]";
+    mIndicesPercentage[i] = mRenderer.RegisterProperty( ossProperty.str(), 0.f );
+  }
+}
+
+Renderer& BubbleRenderer::GetRenderer()
+{
+  return mRenderer;
+}
+
+void BubbleRenderer::SetGeometry( Geometry geometry )
+{
+  mRenderer.SetGeometry( geometry );
+}
+
+void BubbleRenderer::SetStartAndEndPosition( unsigned int index, const Vector4& startAndEndPosition )
+{
+  mRenderer.SetProperty( mIndiceStartEndPos[index], startAndEndPosition );
+}
+
+void BubbleRenderer::SetPercentage( unsigned int index, float percentage )
+{
+  mRenderer.SetProperty( mIndicesPercentage[index], percentage );
+}
+
+void BubbleRenderer::SetGravity( float gravity )
+{
+  mRenderer.SetProperty( mIndexGravity, gravity );
+}
+
+void BubbleRenderer::SetDynamicScale( float scale )
+{
+  mRenderer.SetProperty( mIndexDynamicScale, scale );
+}
+
+Property BubbleRenderer::GetPercentageProperty( unsigned int index )
+{
+  return Property( mRenderer, mIndicesPercentage[index] );
+}
+
+void BubbleRenderer::ResetProperties()
+{
+  Vector4 zeroVector;
+  for( unsigned int i=0; i<mIndicesPercentage.size(); i++ )
+  {
+    SetPercentage( i, 0.f);
+    SetStartAndEndPosition( i, zeroVector );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h b/dali-toolkit/internal/controls/bubble-effect/bubble-renderer.h
new file mode 100644 (file)
index 0000000..a1ae6a6
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUBBLE_RENDERER_H
+#define DALI_TOOLKIT_INTERNAL_BUBBLE_RENDERER_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/rendering/renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * BubbleRenderer renders a group of bubbles.Each bubble can be moved separately.
+ * Its custom shader achieves similar effect of particle system by applying on a specially created mesh
+ * Each bubble is rendered on a patch with two triangles; and each mesh can contain multiple such patches, thus a group.
+ */
+class BubbleRenderer
+{
+public:
+
+  /**
+   * Constructor   *
+   * @return A newly allocated object.
+   */
+  BubbleRenderer();
+
+  /**
+   * @brief Destructor
+   */
+  ~BubbleRenderer(){}
+
+  /**
+   * Prepare for the rendering: create the renderer, and register properties
+   * @param[in] numberOfBubble How many groups of uniforms are used to control the bubble movement.
+   * Note: Limited by the maximum available uniforms, this parameter cannot be bigger than 100.
+   * Ideally use one group of uniform to control one bubble.
+   * If the num of patches in the MeshActor is more than groups of uniforms,
+   * the uniform values will be shared by multiple bubbles. Allow up to 9 times.
+   * @param[in] movementArea The size of the bubble moving area, usually the same size as the background.
+   * @param[in] geometry The geometry to be used by the renderer
+   * @param[in] textureSet The texture set to be used by the renderer
+   * @param[in] shader The shader set to be used by the renderer
+   */
+  void Initialize( unsigned int numberOfBubble, const Vector2& movementArea, Geometry geometry, TextureSet textureSet, Shader shader  );
+
+  /**
+   * Return the mesh actor which is used to display the bubbles
+   */
+  Renderer& GetRenderer();
+
+  /**
+   * Sets the geometry to be used by the renderer
+   * @param[in] geometry The geometry to be used by the renderer
+   */
+  void SetGeometry( Geometry geometry );
+
+  /**
+   * Set the start and end positions of the index-th bubble's movement.
+   * @param[in] index Indicate which bubble these properties are applied on.
+   * @param[in] startAndEndPosition The start and the end position of movement.
+   */
+  void SetStartAndEndPosition( unsigned int index, const Vector4& startAndEndPosition );
+
+  /**
+   * Set the movement completed percentage of the index-th bubble.
+   * The bubble will appear at start position when percentage equals to zero,
+   * and disappear near end position (affected by gravity) when percentage equals to one.
+   * This percentage property is used to animate the bubble movement.
+   * @param[in] index Indicate which bubble this property is applied on.
+   * @param[in] percentage Set the percentage property value ( between zero and one ).
+   */
+  void SetPercentage( unsigned int index, float percentage );
+
+  /**
+   * Set the gravity applied to the y direction, which makes the bubbles no longer moving on a straight line.
+   * @param[in] gravity The gravity on the y direction.
+   */
+  void SetGravity( float gravity );
+
+  /**
+   * Set the scale factor applied to the bubbles
+   * @param[in] scale The scale factor applied on all bubbles.
+   */
+  void SetDynamicScale( float scale );
+
+  /**
+   * Get the idx-th percentage property.
+   * @param[in] idx The percentage property index.
+   * @return the idx-th percentage property.
+   */
+  Property GetPercentageProperty( unsigned int idx );
+
+  /**
+   * Reset the uniform values to default.
+   */
+  void ResetProperties();
+
+private:
+
+  Renderer     mRenderer;
+
+  //properties mapped as uniforms
+  std::vector<Property::Index> mIndicesOffset;             ///< Indices of the properties mapping to uniform array 'uOffset'
+  std::vector<Property::Index> mIndiceStartEndPos;         ///< Indices of the properties mapping to uniform array 'uStartAndEndPos'
+  std::vector<Property::Index> mIndicesPercentage;         ///< Indices of the properties mapping to uniform array 'uPercentage'
+  Property::Index              mIndexGravity;              ///< Index of the property mapping to uniform 'uGravity'
+  Property::Index              mIndexDynamicScale;         ///< Index of the property mapping to uniform 'uDynamicScale'
+  Property::Index              mIndexInvertedMovementArea; ///< Index of the property mapping to uniform 'uInvertedMovementArea'
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUBBLE_RENDERER_H
diff --git a/dali-toolkit/internal/controls/bubble-effect/color-adjuster.h b/dali-toolkit/internal/controls/bubble-effect/color-adjuster.h
new file mode 100644 (file)
index 0000000..bbf81a9
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef DALI_TOOLKIT_INTERNAL_COLOR_ADJUSTER_H
+#define DALI_TOOLKIT_INTERNAL_COLOR_ADJUSTER_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/math/vector3.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+#define DALI_COMPOSE_SHADER(STR) #STR
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+inline void SetColorAdjusterProperties( Actor& actor, const Vector3& hsvDelta, bool ignoreAlpha = false )
+{
+  actor.RegisterProperty( "uHSVDelta", hsvDelta );
+  actor.RegisterProperty( "uIgnoreAlpha", ignoreAlpha ? 1.f : 0.f );
+}
+
+/**
+* Creates a new ColorAdjuster effect.
+* ColorAdjuster is a custom shader effect to adjust the image color in HSV space.
+* @param[in] hsvDelta The color difference to apply to the HSV channel.
+* @param[in] ignoreAlpha If true, the result color will be opaque even though source has alpha value
+* @return A handle to a newly allocated Dali resource.
+*/
+inline Property::Map CreateColorAdjuster()
+{
+  std::string fragmentShader = DALI_COMPOSE_SHADER(
+    precision highp float;\n
+    uniform vec3 uHSVDelta;\n
+    uniform float uIgnoreAlpha;\n
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    float rand(vec2 co) \n
+    {\n
+      return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); \n}
+    \n
+    vec3 rgb2hsv(vec3 c)\n
+    {\n
+      vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n
+      vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n
+      vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n
+      \n
+      float d = q.x - min(q.w, q.y);\n
+      float e = 1.0e-10;\n
+      return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n
+    }\n
+    vec3 hsv2rgb(vec3 c)\n
+    {\n
+      vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n
+      vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n
+      return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n
+    }\n
+    void main() {\n
+      vec4 color = texture2D(sTexture, vTexCoord); \n
+      vec3 hsvColor = rgb2hsv( color.rgb );\n
+      // modify the hsv Value
+      hsvColor += uHSVDelta * rand(vTexCoord); \n
+      // if the new vale exceeds one, then decrease it
+      hsvColor -= max(hsvColor*2.0 - vec3(2.0), 0.0);\n
+      // if the new vale drops below zero, then increase it
+      hsvColor -= min(hsvColor*2.0, 0.0);\n
+      color.rgb = hsv2rgb( hsvColor ); \n
+      // uIgnoreAlpha decide the result alpha will be 1.0 or source's alpha
+      color.a += uIgnoreAlpha;\n
+      gl_FragColor = color; \n
+    }\n
+  );
+
+  Property::Map customShader;
+  customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentShader;
+
+  Property::Map map;
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+
+  return map;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_COLOR_ADJUSTER_H
diff --git a/dali-toolkit/internal/controls/buttons/button-impl.cpp b/dali-toolkit/internal/controls/buttons/button-impl.cpp
new file mode 100644 (file)
index 0000000..1af6848
--- /dev/null
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (c) 2019 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 "button-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/internal/visuals/text/text-visual.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+#if defined(DEBUG_ENABLED)
+    Debug::Filter* gLogButtonFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_BUTTON_CONTROL");
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  // empty handle as we cannot create button (but type registered for clicked signal)
+  return BaseHandle();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Button, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabled",                           BOOLEAN, DISABLED                              )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "autoRepeating",                      BOOLEAN, AUTO_REPEATING                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "initialAutoRepeatingDelay",          FLOAT,   INITIAL_AUTO_REPEATING_DELAY          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "nextAutoRepeatingDelay",             FLOAT,   NEXT_AUTO_REPEATING_DELAY             )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "togglable",                          BOOLEAN, TOGGLABLE                             )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selected",                           BOOLEAN, SELECTED                              )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedVisual",                   MAP,     UNSELECTED_VISUAL                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedVisual",                     MAP,     SELECTED_VISUAL                       )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedVisual",             MAP,     DISABLED_SELECTED_VISUAL              )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedVisual",           MAP,     DISABLED_UNSELECTED_VISUAL            )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "unselectedBackgroundVisual",         MAP,     UNSELECTED_BACKGROUND_VISUAL          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "label",                              MAP,     LABEL                                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "selectedBackgroundVisual",           MAP,     SELECTED_BACKGROUND_VISUAL            )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledUnselectedBackgroundVisual", MAP,     DISABLED_UNSELECTED_BACKGROUND_VISUAL )
+DALI_PROPERTY_REGISTRATION( Toolkit, Button, "disabledSelectedBackgroundVisual",   MAP,     DISABLED_SELECTED_BACKGROUND_VISUAL   )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelRelativeAlignment",             STRING,  LABEL_RELATIVE_ALIGNMENT              )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "labelPadding",                       VECTOR4, LABEL_PADDING                         )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, Button, "visualPadding",                      VECTOR4, VISUAL_PADDING                        )
+
+// Signals:
+DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "pressed",                               SIGNAL_PRESSED               )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "released",                              SIGNAL_RELEASED              )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "clicked",                               SIGNAL_CLICKED               )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Button, "stateChanged",                          SIGNAL_STATE_CHANGED         )
+
+// Actions:
+DALI_ACTION_REGISTRATION(   Toolkit, Button, "buttonClick",                           ACTION_BUTTON_CLICK          )
+
+DALI_TYPE_REGISTRATION_END()
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( ALIGNMENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, END )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, TOP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Internal::Button, BOTTOM )
+DALI_ENUM_TO_STRING_TABLE_END( ALIGNMENT )
+
+const Scripting::StringEnum ALIGNMENT_STRING_TABLE[] =
+{
+  { "BEGIN",  Button::BEGIN   },
+  { "END",    Button::END     },
+  { "TOP",    Button::TOP     },
+  { "BOTTOM", Button::BOTTOM  },
+};
+
+const unsigned int ALIGNMENT_STRING_TABLE_COUNT = sizeof( ALIGNMENT_STRING_TABLE ) / sizeof( ALIGNMENT_STRING_TABLE[0] );
+
+const Property::Index VISUAL_INDEX_FOR_STATE[][Button::STATE_COUNT] =
+{
+  { Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::UNSELECTED_VISUAL },
+  { Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::SELECTED_VISUAL  },
+  { Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL },
+  { Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL, Toolkit::Button::Property::DISABLED_SELECTED_VISUAL }
+};
+
+/**
+ * Checks if given map contains a text string
+ */
+bool MapContainsTextString( Property::Map& map )
+{
+  bool result = false;
+  Property::Value* value = map.Find( Toolkit::TextVisual::Property::TEXT );
+  if ( value )
+  {
+    std::string textString;
+    value->Get( textString );
+    if ( !textString.empty() )
+    {
+      result = true;
+    }
+  }
+  return result;
+}
+
+} // unnamed namespace
+
+Button::Button()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mAutoRepeatingTimer(),
+  mTextLabelAlignment( END ),
+  mAutoRepeating( false ),
+  mTogglableButton( false ),
+  mTextStringSetFlag( false ),
+  mInitialAutoRepeatingDelay( 0.0f ),
+  mNextAutoRepeatingDelay( 0.0f ),
+  mAnimationTime( 0.0f ),
+  mButtonPressedState( UNPRESSED ),
+  mButtonState( UNSELECTED_STATE ),
+  mPreviousButtonState( mButtonState ),
+  mClickActionPerforming( false )
+{
+}
+
+Button::~Button()
+{
+}
+
+void Button::SetAutoRepeating( bool autoRepeating )
+{
+  mAutoRepeating = autoRepeating;
+
+  // An autorepeating button can't be a toggle button.
+  if( autoRepeating )
+  {
+    if( IsSelected() )
+    {
+      SetSelected( false ); // UnSelect before switching off Toggle feature.
+    }
+    mTogglableButton = false;
+  }
+}
+
+void Button::SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay )
+{
+  DALI_ASSERT_DEBUG( initialAutoRepeatingDelay > 0.f );
+  mInitialAutoRepeatingDelay = initialAutoRepeatingDelay;
+}
+
+void Button::SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay )
+{
+  DALI_ASSERT_DEBUG( nextAutoRepeatingDelay > 0.f );
+  mNextAutoRepeatingDelay = nextAutoRepeatingDelay;
+}
+
+void Button::SetTogglableButton( bool togglable )
+{
+  mTogglableButton = togglable;
+
+  // A toggle button can't be an autorepeating button.
+  if( togglable )
+  {
+    mAutoRepeating = false;
+  }
+}
+
+void Button::SetSelected( bool selected )
+{
+  if( mTogglableButton )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetSelected (%s)\n", (selected?"true":"false") );
+
+    if ( selected && ( mButtonState != SELECTED_STATE ) )
+    {
+      ChangeState( SELECTED_STATE );
+    }
+    else if ( !selected && ( mButtonState != UNSELECTED_STATE ) )
+    {
+      ChangeState( UNSELECTED_STATE );
+    }
+  }
+}
+
+void Button::SetDisabled( bool disabled )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetDisabled(%s) state(%d)\n", (disabled)?"disabled":"active", mButtonState );
+
+  if ( disabled )
+  {
+    if ( mButtonState == SELECTED_STATE )
+    {
+      ChangeState( DISABLED_SELECTED_STATE );
+    }
+    else if ( mButtonState == UNSELECTED_STATE )
+    {
+      ChangeState( DISABLED_UNSELECTED_STATE );
+    }
+  }
+  else
+  {
+    if ( mButtonState == DISABLED_SELECTED_STATE )
+    {
+      ChangeState( SELECTED_STATE );
+    }
+    else if ( mButtonState == DISABLED_UNSELECTED_STATE )
+    {
+      ChangeState( UNSELECTED_STATE );
+    }
+  }
+}
+
+bool Button::IsDisabled() const
+{
+  return ( mButtonState == DISABLED_SELECTED_STATE || mButtonState == DISABLED_UNSELECTED_STATE ) ;
+}
+
+bool Button::ValidateState( State requestedState )
+{
+  /*  Below tables shows allowed state transitions
+   *  Match rows in first column to following columns, if true then transition allowed.
+   *  eg UNSELECTED_STATE to DISABLED_UNSELECTED_STATE is true so state transition allowed.
+   *
+                                                             to| UNSELECTED_STATE | SELECTED_STATE | DISABLED_UNSELECTED_STATE | DISABLED_SELECTED_STATE |*/
+                                 /* from*/
+  bool transitionTable[4][4] = { /* UNSELECTED_STATE*/         {      false,            true,               true,                   false         },
+                                 /* SELECTED_STATE*/           {      true,             false,              false,                  true          },
+                                 /* DISABLED_UNSELECTED_STATE*/{      true,             true,               false,                  false         },
+                                 /* DISABLED_SELECTED_STATE*/  {      false,            true,               false,                  false         }
+                               };
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ValidateState ReuestedState:%d, CurrentState:%d, result:%s\n",
+                 requestedState, mButtonState, (transitionTable[mButtonState][requestedState])?"change-accepted":"change-denied");
+
+  return transitionTable[mButtonState][requestedState];
+}
+
+void Button::ChangeState( State requestedState )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d)\n", requestedState );
+
+  // Validate State before changing
+  if ( !ValidateState( requestedState ))
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::ChangeState ReuestedState(%d) not validated\n", requestedState );
+    return;
+  }
+
+  // If not on stage the button could have still been set to selected so update state
+  mPreviousButtonState = mButtonState; // Store previous state for visual removal (used when animations ended)
+  mButtonState = requestedState; // Update current state
+
+  if ( Self().OnStage() )
+  {
+    OnStateChange( mButtonState ); // Notify derived buttons
+    SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
+    SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
+    // If animation supported then visual removal should be performed after any transition animation has completed.
+    // If Required Visual is not loaded before current visual is removed then a flickering will be evident.
+    // Derived button can override OnButtonVisualRemoval
+    OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
+    OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
+    RelayoutRequest();
+  }
+
+  Toolkit::Button handle( GetOwner() );
+  // Emit signal.
+  mStateChangedSignal.Emit( handle );
+}
+
+bool Button::IsSelected() const
+{
+  bool selected = ( mButtonState == SELECTED_STATE ) || ( mButtonState == DISABLED_SELECTED_STATE );
+  return mTogglableButton && selected;
+}
+
+void Button::MergeWithExistingLabelProperties( const Property::Map& inMap, Property::Map& outMap )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties with %d properties\n", inMap.Count() );
+
+  /**
+   * Properties for the Label visual could be from a style sheet but after being set the "TEXT" property could be set.
+   * Hence would need to create the Text Visual with the complete merged set of properties.
+   *
+   * 1) Find Label Visual
+   * 2) Retrieve current properties ( settings )
+   * 3) Merge with new properties ( settings )
+   * 4) Return new merged map
+   */
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
+  if ( visual )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties Visual already exists, retrieving existing map\n");
+    visual.CreatePropertyMap( outMap );
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties retrieved %d properties\n", outMap.Count() );
+  }
+
+  outMap.Merge( inMap );
+
+  // Store if a text string has been supplied.
+
+  mTextStringSetFlag = MapContainsTextString( outMap );
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "MergeLabelProperties now has %d properties\n", outMap.Count() );
+}
+
+void Button::SetLabelAlignment( Button::Align labelAlignment)
+{
+  mTextLabelAlignment = labelAlignment;
+  RelayoutRequest();
+}
+
+Button::Align Button::GetLabelAlignment()
+{
+  return mTextLabelAlignment;
+}
+
+/**
+ * Create Visual for given index from a property map or url.
+ * 1) Check if value passed in is a url and create visual
+ * 2) Create visual from map if step (1) is false
+ * 3) Register visual with control with false for enable flag. Button will later enable visual when needed ( Button::SelectRequiredVisual )
+ * 4) Unregister visual if empty map was provided. This is the method to remove a visual
+ */
+void Button::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent index(%d)\n", index );
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base buttonVisual;
+
+  std::string imageUrl;
+  if( value.Get( imageUrl ) )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using image URL(%d)\n", index );
+    if ( !imageUrl.empty() )
+    {
+      DALI_ASSERT_DEBUG( index != Toolkit::Button::Property::LABEL && "Creating a Image Visual instead of Text Visual " );
+      buttonVisual = visualFactory.CreateVisual(  imageUrl, ImageDimensions()  );
+    }
+  }
+  else
+  {
+    // if its not a string then get a Property::Map from the property if possible.
+    Property::Map *map = value.GetMap();
+    if( map && !map->Empty()  ) // Empty map results in current visual removal.
+    {
+      DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent Using Map(%d)\n", index );
+      buttonVisual = visualFactory.CreateVisual( *map );
+    }
+  }
+
+  if ( buttonVisual )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "CreateVisualsForComponent RegisterVisual index(%d) enabled(%s)\n",
+                   index, DevelControl::IsVisualEnabled( *this, index )?"true":"false" );
+    // enable the visual if needed for current state
+    const bool enabled = ( ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] )||
+                           ( index == VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] )||
+                           ( index == Toolkit::Button::Property::LABEL ) );
+    DevelControl::RegisterVisual( *this, index, buttonVisual, enabled, visualDepth );
+  }
+  else
+  {
+    DevelControl::UnregisterVisual( *this, index );
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "CreateVisualsForComponent Visual not created or empty map (clearing visual).(%d)\n", index);
+  }
+  RelayoutRequest();
+}
+
+bool Button::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual visual(%d)\n", visualIndex);
+  bool success = false;
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
+  if ( visual )
+  {
+    visual.CreatePropertyMap( retreivedMap );
+    success = true;
+  }
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetPropertyMapForVisual %s\n", success?"Success":"Failure");
+  return success;
+}
+
+bool Button::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  Dali::BaseHandle handle( object );
+
+  Toolkit::Button button = Toolkit::Button::DownCast( handle );
+
+  DALI_ASSERT_DEBUG( button );
+
+  if( 0 == strcmp( actionName.c_str(), ACTION_BUTTON_CLICK ) )
+  {
+    ret = GetImplementation( button ).DoClickAction( attributes );
+  }
+
+  return ret;
+}
+
+bool Button::DoClickAction( const Property::Map& attributes )
+{
+  // Prevents the button signals from doing a recursive loop by sending an action
+  // and re-emitting the signals.
+  if( !mClickActionPerforming )
+  {
+    mClickActionPerforming = true;
+    ButtonDown();
+    if ( !mTogglableButton )
+    {
+      mButtonPressedState = DEPRESSED;
+    }
+    ButtonUp();
+    mClickActionPerforming = false;
+
+    return true;
+  }
+
+  return false;
+}
+
+void Button::ButtonDown()
+{
+  if( mTogglableButton )
+  {
+    if ( mButtonState != SELECTED_STATE )
+    {
+      SetSelected( true );
+      mButtonPressedState = TOGGLE_DEPRESSED;
+    }
+    else
+    {
+      mButtonPressedState = DEPRESSED;
+    }
+  }
+  else
+  {
+    Pressed();
+    mButtonPressedState = DEPRESSED;
+    if( mAutoRepeating )
+    {
+       SetUpTimer( mInitialAutoRepeatingDelay );
+    }
+  }
+
+  // The pressed signal should be emitted regardless of toggle mode.
+  Toolkit::Button handle( GetOwner() );
+  mPressedSignal.Emit( handle );
+}
+
+void Button::ButtonUp()
+{
+  bool emitSignalsForPressAndReleaseAction = false;
+
+  if( DEPRESSED == mButtonPressedState )
+  {
+    if( mTogglableButton ) // Button up will change state
+    {
+      emitSignalsForPressAndReleaseAction = OnToggleReleased(); // Derived toggle buttons can override this to provide custom behaviour
+    }
+    else
+    {
+      Released(); // Button up will result in unselected state
+      if( mAutoRepeating )
+      {
+        mAutoRepeatingTimer.Reset();
+      }
+      emitSignalsForPressAndReleaseAction = true;
+    }
+  }
+  else if ( TOGGLE_DEPRESSED == mButtonPressedState )
+  {
+    emitSignalsForPressAndReleaseAction = true; // toggle released after being pressed, a click
+  }
+
+  if ( emitSignalsForPressAndReleaseAction )
+  {
+    // The clicked and released signals should be emitted regardless of toggle mode.
+    Toolkit::Button handle( GetOwner() );
+    mReleasedSignal.Emit( handle );
+    mClickedSignal.Emit( handle );
+  }
+}
+
+bool Button::OnToggleReleased()
+{
+  SetSelected( !IsSelected() );
+  mButtonPressedState = UNPRESSED;
+  return true;
+}
+
+
+void Button::OnTouchPointLeave()
+{
+  if( DEPRESSED == mButtonPressedState )
+  {
+    if( !mTogglableButton )
+    {
+      Released();
+
+      if( mAutoRepeating )
+      {
+        mAutoRepeatingTimer.Reset();
+      }
+    }
+
+    mButtonPressedState = UNPRESSED;
+
+    // The released signal should be emitted regardless of toggle mode.
+    Toolkit::Button handle( GetOwner() );
+    mReleasedSignal.Emit( handle );
+  }
+}
+
+void Button::OnTouchPointInterrupted()
+{
+  OnTouchPointLeave();
+}
+
+Toolkit::Button::ButtonSignalType& Button::PressedSignal()
+{
+  return mPressedSignal;
+}
+
+Toolkit::Button::ButtonSignalType& Button::ReleasedSignal()
+{
+  return mReleasedSignal;
+}
+
+Toolkit::Button::ButtonSignalType& Button::ClickedSignal()
+{
+  return mClickedSignal;
+}
+
+Toolkit::Button::ButtonSignalType& Button::StateChangedSignal()
+{
+  return mStateChangedSignal;
+}
+
+bool Button::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::Button button = Toolkit::Button::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_PRESSED ) )
+  {
+    button.PressedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_RELEASED ) )
+  {
+    button.ReleasedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_CLICKED ) )
+  {
+    button.ClickedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_STATE_CHANGED ) )
+  {
+    button.StateChangedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void Button::OnInitialize()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnInitialize\n" );
+
+  Actor self = Self();
+
+  mTapDetector = TapGestureDetector::New();
+  mTapDetector.Attach( self );
+  mTapDetector.DetectedSignal().Connect(this, &Button::OnTap);
+
+  self.SetKeyboardFocusable( true );
+
+  self.TouchSignal().Connect( this, &Button::OnTouch );
+}
+
+bool Button::OnAccessibilityActivated()
+{
+  return OnKeyboardEnter();
+}
+
+bool Button::OnTouch( Actor actor, const TouchData& touch )
+{
+
+  // Only events are processed when the button is not disabled
+  auto result( false );
+
+  if( !IsDisabled() )
+  {
+    if ( 1 == touch.GetPointCount() )
+    {
+      switch( touch.GetState( 0 ) )
+      {
+        case PointState::DOWN:
+        {
+          ButtonDown();
+          break;
+        }
+        case PointState::UP:
+        {
+          ButtonUp();
+          break;
+        }
+        case PointState::INTERRUPTED:
+        {
+          OnTouchPointInterrupted();
+          break;
+        }
+        case PointState::LEAVE:
+        {
+          OnTouchPointLeave();
+          break;
+        }
+        case PointState::MOTION:
+        case PointState::STATIONARY: // FALLTHROUGH
+        {
+          // Nothing to do
+          break;
+        }
+      }
+    }
+    else if( 1 < touch.GetPointCount() )
+    {
+      OnTouchPointLeave(); // Notification for derived classes.
+
+      // Sets the button state to the default
+      mButtonPressedState = UNPRESSED;
+    }
+    result = true;
+  }
+  return result;
+}
+
+bool Button::OnKeyboardEnter()
+{
+  // When the enter key is pressed, or button is activated, the click action is performed.
+  Property::Map attributes;
+  bool ret = DoClickAction( attributes );
+
+  return ret;
+}
+
+void Button::OnStageDisconnection()
+{
+  if( DEPRESSED == mButtonPressedState )
+  {
+    if( !mTogglableButton )
+    {
+      Released();
+
+      if( mAutoRepeating )
+      {
+        mAutoRepeatingTimer.Reset();
+      }
+    }
+  }
+
+  mButtonPressedState = UNPRESSED;
+
+  Control::OnStageDisconnection(); // Visuals will be set off stage
+}
+
+void Button::OnStageConnection( int depth )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnStageConnection ptr(%p) \n", this );
+  OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ BACKGROUND ] );
+  OnButtonVisualRemoval( VISUAL_INDEX_FOR_STATE[ mPreviousButtonState ][ FOREGROUND ] );
+  SelectRequiredVisual( Toolkit::Button::Property::LABEL );
+  SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ BACKGROUND ] );
+  SelectRequiredVisual( VISUAL_INDEX_FOR_STATE[ mButtonState ][ FOREGROUND ] );
+  Control::OnStageConnection( depth ); // Enabled visuals will be put on stage
+  RelayoutRequest();
+}
+
+Vector3 Button::GetNaturalSize()
+{
+  Vector3 size = Vector3::ZERO;
+
+  bool horizontalAlignment = mTextLabelAlignment == BEGIN || mTextLabelAlignment == END; // label and visual side by side
+
+  // Get natural size of foreground ( largest of the possible visuals )
+  Size largestProvidedVisual;
+  Size labelSize = Size::ZERO;
+
+  bool foreGroundVisualUsed = false;
+
+  for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
+  {
+    Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][FOREGROUND] );
+    Size visualSize;
+    if ( visual )
+    {
+      visual.GetNaturalSize( visualSize );
+      largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
+      largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
+      foreGroundVisualUsed = true;
+    }
+  }
+
+  if ( !foreGroundVisualUsed ) // If foreground visual not supplied then use the background visual to calculate Natural size
+  {
+    for ( int state = Button::UNSELECTED_STATE; state < Button::STATE_COUNT; state++ )
+    {
+      Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[state][BACKGROUND] );
+      Size visualSize;
+      if ( visual )
+      {
+        visual.GetNaturalSize( visualSize );
+        largestProvidedVisual.width = std::max(largestProvidedVisual.width, visualSize.width );
+        largestProvidedVisual.height = std::max(largestProvidedVisual.height, visualSize.height );
+      }
+    }
+  }
+
+  // Get horizontal padding total
+  if ( largestProvidedVisual.width > 0 )  // if visual exists
+  {
+    size.width += largestProvidedVisual.width + mForegroundPadding.left + mForegroundPadding.right;
+  }
+  // Get vertical padding total
+  if ( largestProvidedVisual.height > 0 )
+  {
+    size.height += largestProvidedVisual.height + mForegroundPadding.top + mForegroundPadding.bottom;
+  }
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize visual Size(%f,%f)\n",
+                 largestProvidedVisual.width, largestProvidedVisual.height );
+
+  // Get natural size of label if text has been set
+  if ( mTextStringSetFlag )
+  {
+    Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL );
+
+    if ( visual )
+    {
+      visual.GetNaturalSize( labelSize );
+
+      DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize labelSize(%f,%f) padding(%f,%f)\n",
+                     labelSize.width, labelSize.height, mLabelPadding.left + mLabelPadding.right, mLabelPadding.top + mLabelPadding.bottom);
+
+      labelSize.width += mLabelPadding.left + mLabelPadding.right;
+      labelSize.height += mLabelPadding.top + mLabelPadding.bottom;
+
+      // Add label size to height or width depending on alignment position
+      if ( horizontalAlignment )
+      {
+        size.width += labelSize.width;
+        size.height = std::max(size.height, labelSize.height );
+      }
+      else
+      {
+        size.height += labelSize.height;
+        size.width = std::max(size.width, labelSize.width );
+      }
+    }
+  }
+
+  if( size.width < 1 && size.height < 1 )
+  {
+    // if no image or label then use Control's natural size
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "GetNaturalSize Using control natural size\n");
+    size = Control::GetNaturalSize();
+  }
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "Button GetNaturalSize (%f,%f)\n", size.width, size.height );
+
+  return size;
+}
+
+void Button::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnSetResizePolicy\n");
+  RelayoutRequest();
+}
+
+/**
+ * Visuals are sized and positioned in this function.
+ * Whilst the control has it's size negotiated it has to size it's visuals explicitly here.
+ */
+
+void Button::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout targetSize(%f,%f) ptr(%p) state[%d]\n", size.width, size.height, this, mButtonState );
+
+  Toolkit::Visual::Base currentVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][FOREGROUND] );
+  Toolkit::Visual::Base currentBackGroundVisual = DevelControl::GetVisual( *this, VISUAL_INDEX_FOR_STATE[mButtonState][BACKGROUND] );
+
+  // Sizes and padding set to zero, if not present then values will no effect calculations.
+  Vector2 visualPosition = Vector2::ZERO;
+  Vector2 labelPosition = Vector2::ZERO;
+  Size visualSize = Size::ZERO;
+  Padding foregroundVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
+  Padding labelVisualPadding = Padding(0.0f, 0.0f, 0.0f, 0.0f );
+
+  if ( mTextStringSetFlag )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Label padding setting padding:%f,%f,%f,%f\n", mLabelPadding.y, mLabelPadding.x, mLabelPadding.width,mLabelPadding.height );
+    labelVisualPadding = mLabelPadding;
+  }
+
+  if ( currentVisual )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Foreground Visual setting padding:%f,%f,%f,%f\n", mForegroundPadding.y, mForegroundPadding.x, mForegroundPadding.width,mForegroundPadding.height );
+    currentVisual.GetNaturalSize( visualSize );
+    foregroundVisualPadding = mForegroundPadding;
+  }
+
+  Toolkit::Align::Type visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
+
+  Vector2 visualAndPaddingSize = Vector2( ( foregroundVisualPadding.x + visualSize.width + foregroundVisualPadding.y ),
+                                          ( foregroundVisualPadding.width + visualSize.height + foregroundVisualPadding.height ));
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout visualAndPaddingSize(%f,%f)\n", visualAndPaddingSize.width, visualAndPaddingSize.height);
+
+  // Text Visual should take all space available after foreground visual size and all padding is considered.
+  // Remaining Space priority, Foreground padding, foreground visual, Text padding then Text visual.
+  Size remainingSpaceForText = Size::ZERO;
+
+  switch ( mTextLabelAlignment )
+  {
+    case BEGIN :
+    {
+      visualAnchorPoint = Toolkit::Align::TOP_END;
+      visualPosition.x = foregroundVisualPadding.right;
+      visualPosition.y = foregroundVisualPadding.top;
+
+      labelPosition.x = labelVisualPadding.x;
+      labelPosition.y = labelVisualPadding.top;
+
+      remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
+      remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
+      break;
+    }
+    case END :
+    {
+      visualAnchorPoint = Toolkit::Align::TOP_BEGIN;
+      visualPosition.x = foregroundVisualPadding.left;
+      visualPosition.y = foregroundVisualPadding.top;
+
+      labelPosition.x = visualAndPaddingSize.width + labelVisualPadding.x;
+      labelPosition.y = labelVisualPadding.top;
+
+      remainingSpaceForText.width = size.width - visualAndPaddingSize.width - labelVisualPadding.x - labelVisualPadding.y;
+      remainingSpaceForText.height = size.height - labelVisualPadding.top - labelVisualPadding.bottom;
+      break;
+    }
+    case TOP :
+    {
+      visualAnchorPoint = Toolkit::Align::BOTTOM_END;
+      visualPosition.x = foregroundVisualPadding.left;
+      visualPosition.y = foregroundVisualPadding.bottom;
+
+      labelPosition.x = labelVisualPadding.left;
+      labelPosition.y = labelVisualPadding.top;
+
+      remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
+      remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
+
+      break;
+    }
+    case BOTTOM :
+    {
+      visualAnchorPoint = Toolkit::Align::TOP_END;
+      visualPosition.x = foregroundVisualPadding.left;
+      visualPosition.y = foregroundVisualPadding.top;
+
+      labelPosition.x = labelVisualPadding.left;
+      labelPosition.y = visualAndPaddingSize.height + labelVisualPadding.top;
+
+      remainingSpaceForText.width = size.width - labelVisualPadding.x - labelVisualPadding.y;
+      remainingSpaceForText.height = size.height - visualAndPaddingSize.height - labelVisualPadding.top - labelVisualPadding.bottom;
+
+      break;
+    }
+  }
+
+  if ( currentBackGroundVisual )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual background size to(%f,%f)\n", size.width, size.height);
+
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, size )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+
+    currentBackGroundVisual.SetTransformAndSize( visualTransform, size );
+  }
+
+  if ( currentVisual )
+  {
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height);
+
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                   .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
+
+    currentVisual.SetTransformAndSize( visualTransform, size );
+  }
+
+  if ( mTextStringSetFlag )
+  {
+    Toolkit::Visual::Base textVisual = DevelControl::GetVisual( *this, Toolkit::Button::Property::LABEL ); // No need to search for Label visual if no text set.
+
+    if ( textVisual )
+    {
+      if ( !currentVisual )
+      {
+        DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout Only Text\n");
+        labelPosition.x = labelVisualPadding.left;
+        labelPosition.y = labelVisualPadding.height;
+      }
+
+      Vector2 preSize = Vector2( static_cast< int >( remainingSpaceForText.x ), static_cast< int >( remainingSpaceForText.y ));
+
+      DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size(%f,%f) text Position(%f,%f) \n", remainingSpaceForText.width, remainingSpaceForText.height, labelPosition.x, labelPosition.y);
+
+      DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout text Size -- (%f,%f) text Position(%f,%f) \n", preSize.width, preSize.height, labelPosition.x, labelPosition.y);
+
+
+      Property::Map textVisualTransform;
+      textVisualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, preSize )
+                         .Add( Toolkit::Visual::Transform::Property::OFFSET, labelPosition )
+                         .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                         .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                         .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                         .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, visualAnchorPoint );
+
+      textVisual.SetTransformAndSize( textVisualTransform, size );
+    }
+  }
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout selected (%s) \n", IsSelected()?"yes":"no" );
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "OnRelayout << \n");
+}
+
+void Button::OnTap(Actor actor, const TapGesture& tap)
+{
+  // Prevents Parent getting a tap event
+}
+
+void Button::SetUpTimer( float delay )
+{
+  mAutoRepeatingTimer = Dali::Timer::New( static_cast<unsigned int>( 1000.f * delay ) );
+  mAutoRepeatingTimer.TickSignal().Connect( this, &Button::AutoRepeatingSlot );
+  mAutoRepeatingTimer.Start();
+}
+
+bool Button::AutoRepeatingSlot()
+{
+  bool consumed = false;
+  if( !IsDisabled() )
+  {
+    // Restart the autorepeat timer.
+    SetUpTimer( mNextAutoRepeatingDelay );
+
+    Pressed();
+
+    Toolkit::Button handle( GetOwner() );
+
+    //Emit signal.
+    consumed = mReleasedSignal.Emit( handle );
+    consumed = mClickedSignal.Emit( handle );
+    consumed |= mPressedSignal.Emit( handle );
+ }
+
+  return consumed;
+}
+
+void Button::Pressed()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Pressed\n" );
+
+  if( mButtonState == UNSELECTED_STATE )
+  {
+    ChangeState( SELECTED_STATE );
+    OnPressed();  // Notifies the derived class the button has been pressed.
+  }
+}
+
+void Button::Released()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::Released\n" );
+
+  if( mButtonState == SELECTED_STATE && !mTogglableButton )
+  {
+    ChangeState( UNSELECTED_STATE );
+    OnReleased(); //    // Notifies the derived class the button has been released.
+  }
+  mButtonPressedState = UNPRESSED;
+}
+
+void Button::SelectRequiredVisual( Property::Index visualIndex )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SelectRequiredVisual index(%d) state(%d)\n", visualIndex, mButtonState );
+  // only enable visuals that exist
+  if( DevelControl::GetVisual( *this, visualIndex ) )
+  {
+    DevelControl::EnableVisual( *this, visualIndex, true );
+  }
+}
+
+void Button::RemoveVisual( Property::Index visualIndex )
+{
+  // Use OnButtonVisualRemoval if want button developer to have the option to override removal.
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::RemoveVisual index(%d) state(%d)\n", visualIndex, mButtonState );
+
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
+
+  if( visual )
+  {
+    DevelControl::EnableVisual( *this, visualIndex, false );
+  }
+}
+
+void Button::OnButtonVisualRemoval( Property::Index visualIndex )
+{
+  // Derived Buttons can over ride this to prevent default removal.
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::OnButtonVisualRemoval index(%d)\n", visualIndex );
+  RemoveVisual( visualIndex );
+}
+
+void Button::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty index[%d]\n", index );
+
+  if ( button )
+  {
+    switch ( index )
+    {
+      case Toolkit::Button::Property::DISABLED:
+      {
+        GetImplementation( button ).SetDisabled( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::AUTO_REPEATING:
+      {
+        GetImplementation( button ).SetAutoRepeating( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
+      {
+        GetImplementation( button ).SetInitialAutoRepeatingDelay( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
+      {
+        GetImplementation( button ).SetNextAutoRepeatingDelay( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::TOGGLABLE:
+      {
+        GetImplementation( button ).SetTogglableButton( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::SELECTED:
+      {
+        GetImplementation( button ).SetSelected( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Button::Property::UNSELECTED_VISUAL:
+      case Toolkit::Button::Property::SELECTED_VISUAL:
+      case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
+      case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
+      {
+        GetImplementation( button ).CreateVisualsForComponent( index, value, DepthIndex::CONTENT );
+        break;
+      }
+
+      case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
+      {
+        GetImplementation( button ).CreateVisualsForComponent( index , value, DepthIndex::BACKGROUND);
+        break;
+      }
+
+      case Toolkit::Button::Property::LABEL:
+      {
+        Property::Map outTextVisualProperties;
+        std::string textString;
+
+        if ( value.Get( textString ) )
+        {
+          DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetProperty Setting TextVisual with string[%s]\n", textString.c_str() );
+
+          Property::Map setPropertyMap;
+          setPropertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT )
+                        .Add( Toolkit::TextVisual::Property::TEXT, textString );
+
+          GetImplementation( button ).MergeWithExistingLabelProperties( setPropertyMap, outTextVisualProperties );
+        }
+        else
+        {
+          // Get a Property::Map from the property if possible.
+          Property::Map* setPropertyMap = value.GetMap();
+          if( setPropertyMap )
+          {
+            TextVisual::ConvertStringKeysToIndexKeys( *setPropertyMap );
+            GetImplementation( button ).MergeWithExistingLabelProperties( *setPropertyMap, outTextVisualProperties );
+          }
+        }
+
+        if( !outTextVisualProperties.Empty() )
+        {
+          GetImplementation( button ).CreateVisualsForComponent( index, outTextVisualProperties, DepthIndex::CONTENT );
+        }
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
+      {
+        Button::Align labelAlignment(END);
+        Scripting::GetEnumeration< Button::Align> ( value.Get< std::string >().c_str(),
+                                                    ALIGNMENT_TABLE, ALIGNMENT_TABLE_COUNT,
+                                                    labelAlignment );
+
+        GetImplementation( button ).SetLabelAlignment( labelAlignment );
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::LABEL_PADDING:
+      {
+        Vector4 padding ( value.Get< Vector4 >() );
+        GetImplementation( button ).SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::VISUAL_PADDING:
+      {
+        Vector4 padding ( value.Get< Vector4 >() );
+        GetImplementation( button ).SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Button::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::Button button = Toolkit::Button::DownCast( Dali::BaseHandle( object ) );
+
+  if ( button )
+  {
+    switch ( propertyIndex )
+    {
+      case Toolkit::Button::Property::DISABLED:
+      {
+        value = GetImplementation( button ).IsDisabled();
+        break;
+      }
+
+      case Toolkit::Button::Property::AUTO_REPEATING:
+      {
+        value = GetImplementation( button ).mAutoRepeating;
+        break;
+      }
+
+      case Toolkit::Button::Property::INITIAL_AUTO_REPEATING_DELAY:
+      {
+        value = GetImplementation( button ).mInitialAutoRepeatingDelay;
+        break;
+      }
+
+      case Toolkit::Button::Property::NEXT_AUTO_REPEATING_DELAY:
+      {
+        value = GetImplementation( button ).mNextAutoRepeatingDelay;
+        break;
+      }
+
+      case Toolkit::Button::Property::TOGGLABLE:
+      {
+        value = GetImplementation( button ).mTogglableButton;
+        break;
+      }
+
+      case Toolkit::Button::Property::SELECTED:
+      {
+        value = GetImplementation( button ).IsSelected();
+        break;
+      }
+
+      case Toolkit::Button::Property::UNSELECTED_VISUAL:
+      case Toolkit::Button::Property::SELECTED_VISUAL:
+      case Toolkit::Button::Property::DISABLED_SELECTED_VISUAL:
+      case Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL:
+      case Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::DISABLED_SELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::DISABLED_UNSELECTED_BACKGROUND_VISUAL:
+      case Toolkit::Button::Property::LABEL:
+      {
+        Property::Map visualProperty;
+        if ( GetImplementation( button ).GetPropertyMapForVisual( propertyIndex, visualProperty ) )
+        {
+          value = visualProperty;
+        }
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::LABEL_RELATIVE_ALIGNMENT:
+      {
+        const char* alignment = Scripting::GetEnumerationName< Button::Align >( GetImplementation( button ).GetLabelAlignment(),
+                                                                                ALIGNMENT_STRING_TABLE,
+                                                                                ALIGNMENT_STRING_TABLE_COUNT );
+        if( alignment )
+        {
+          value = std::string( alignment );
+        }
+
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::LABEL_PADDING:
+      {
+        Padding padding = GetImplementation( button ).GetLabelPadding();
+        value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
+        break;
+      }
+
+      case Toolkit::DevelButton::Property::VISUAL_PADDING:
+      {
+        Padding padding = GetImplementation( button ).GetForegroundPadding();
+        value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
+      }
+    }
+  }
+
+  return value;
+}
+
+void Button::SetLabelPadding( const Padding& padding)
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetLabelPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
+  mLabelPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
+  RelayoutRequest();
+}
+
+Padding Button::GetLabelPadding()
+{
+  return mLabelPadding;
+}
+
+void Button::SetForegroundPadding( const Padding& padding)
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "Button::SetForegroundPadding padding(%f,%f,%f,%f)\n", padding.left, padding.right, padding.bottom, padding.top );
+  mForegroundPadding = Padding( padding.left, padding.right, padding.bottom, padding.top );
+  RelayoutRequest();
+}
+
+Padding Button::GetForegroundPadding()
+{
+  return mForegroundPadding;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/buttons/button-impl.h b/dali-toolkit/internal/controls/buttons/button-impl.h
new file mode 100644 (file)
index 0000000..0915d3e
--- /dev/null
@@ -0,0 +1,571 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BUTTON_H
+#define DALI_TOOLKIT_INTERNAL_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/animation/animation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class Button;
+
+namespace Internal
+{
+
+/**
+ * @copydoc Toolkit::Button
+ *
+ * Button is the base class implementation for all buttons.
+ *
+ * @note
+ *
+ * All Foreground/Icon visuals expected to be the same size.
+ * Background visuals will take the size of the control.
+ * Padding and struts take size precedence over visuals when available space is limited.
+ * Icon/Foreground visuals take size precedence over Labels when available space is limited.
+ */
+class Button : public Control
+{
+
+public:
+
+  /**
+   * Enum describing the position the text label can be in relation to the control (and foreground/icon)
+   */
+  enum Align
+  {
+    BEGIN,  // At the start of the control before the foreground/icon
+    END,    // At the end of the control after the foreground/icon
+    TOP,    // At the top of the control above the foreground/icon
+    BOTTOM  // At the bottom of the control below the foreground/icon
+  };
+
+public:
+
+  /**
+   * @brief Sets the button as \e disabled.
+   * @param[in] disabled Disabled property
+   */
+  void SetDisabled( bool disabled );
+
+  /**
+   * @brief Returns if the button is disabled.
+   * @return \e true if the button is \e disabled
+   */
+  bool IsDisabled() const;
+
+  /**
+   * @brief Sets the \e autorepeating property.
+   * @param[in] autoRepeating \e autorepeating property
+   */
+  void SetAutoRepeating( bool autoRepeating );
+
+  /**
+   * @brief Sets the initial autorepeating delay.
+   * @param[in] initialAutoRepeatingDelay in seconds
+   */
+  void SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay );
+
+  /**
+   * @brief Sets the next autorepeating delay.
+   * @param[in] nextAutoRepeatingDelay in seconds
+   */
+  void SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay );
+
+  /**
+   * @brief Sets the \e togglable property.
+   * @param[in] togglable Togglable property
+   */
+  void SetTogglableButton( bool togglable );
+
+  /**
+   * @brief Sets the button as selected or unselected.
+   * @param[in] selected Selected property
+   */
+  void SetSelected( bool selected );
+
+  /**
+   * @brief Returns if the selected property is set and the button is togglable.
+   * @return \e true if the button is \e selected
+   */
+  bool IsSelected() const;
+
+  /**
+   * @brief Produces a Property::Map of Text properties to create a Text Visual, merging existing properties with supplied map
+   * If the label does not exist yet, it is created.
+   * The derived buttons are notified if any properties are changed.
+   * @param[in] properties A Property::Map of key-value pairs of properties to set.
+   * @param[out] properties A Property::Map of text visual properties to set after merging inMap with existing maps
+   */
+  void MergeWithExistingLabelProperties( const Property::Map& inMap, Property::Map& outMap );
+
+  /**
+   * Performs actions as requested using the action name.
+   * @param[in] object The object on which to perform the action.
+   * @param[in] actionName The action to perform.
+   * @param[in] attributes The attributes with which to perfrom this action.
+   * @return true if action has been accepted by this control
+   */
+  static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes );
+
+public:
+
+  /**
+   * Button's state
+   */
+  enum State
+  {
+    UNSELECTED_STATE,              ///< The button is unselected.
+    SELECTED_STATE,                ///< The button is selected.
+    DISABLED_UNSELECTED_STATE,     ///< The button is disabled and unselected.
+    DISABLED_SELECTED_STATE,       ///< The button is disabled and selected.
+    STATE_COUNT,                   ///< Number of States
+  };
+
+  /**
+   * Enum to distinguish the different style-able components of the button
+   */
+  enum Visuals
+  {
+    UNSELECTED_FOREGROUND = 0,
+    SELECTED_FOREGROUND,
+    DISABLED_SELECTED_FOREGROUND,
+    DISABLED_UNSELECTED_FOREGROUND,
+    UNSELECTED_BACKGROUND,
+    SELECTED_BACKGROUND,
+    DISABLED_UNSELECTED_BACKGROUND,
+    DISABLED_SELECTED_BACKGROUND,
+    VISUALS_COUNT
+  };
+
+  /**
+   * Enum to list types of visual a state can have.
+   */
+  enum VisualState
+  {
+    BACKGROUND = 0,
+    FOREGROUND,
+    VISUAL_STATE_COUNT
+  };
+
+protected:
+
+  /**
+   * Button press state which is not the same as the actual button's state.
+   * For example An UNSELECTED button can be DEPRESSED, but until released, the actual button state doesn't change to SELECTED
+   */
+  enum PressState
+  {
+    DEPRESSED,                           ///< The button is up.
+    UNPRESSED,                           ///< The button is down.
+    TOGGLE_DEPRESSED,                    ///< The button has been pressed down and will stay depressed when released.
+  };
+
+  /**
+   * Construct a new Button.
+   */
+  Button();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Button();
+  /**
+   * @return A reference to the label actor.
+   */
+  Actor& GetLabelActor();
+
+  /**
+   * @return A reference to the unselected button image.
+   */
+  Actor GetUnselectedImage();
+
+  /**
+   * @return A reference to the selected image.
+   */
+  Actor GetSelectedImage();
+
+private:
+
+  /**
+   * Perform the click action to click the button.
+   * @param[in] attributes The attributes to perfrom this action.
+   * @return true if this control can perform action.
+   */
+  bool DoClickAction( const Property::Map& attributes );
+
+  /**
+   * This method is called when the button is a Toggle button and released
+   * Could be reimplemented in subclasses to provide specific behaviour.
+   * @return bool returns true if state changed.
+   */
+  virtual bool OnToggleReleased();
+
+  /**
+   * This method is called when touch leaves the boundary of the button or several touch points are received.
+   * Could be reimplemented in subclasses to provide specific behaviour.
+   */
+  virtual void OnTouchPointLeave();
+
+  /**
+   * This method is called when the touch is interrupted.
+   * Could be reimplemented in subclasses to provide specific behaviour.
+   */
+  virtual void OnTouchPointInterrupted();
+
+  /**
+   * This method is called when the \e selected property is changed.
+   */
+  virtual void OnStateChange( State newState ){}
+
+  /**
+   * This method is called when the \e disabled property is changed.
+   */
+  virtual void OnDisabled() {}
+
+  /**
+   * This method is called when the button is pressed.
+   */
+  virtual void OnPressed() {}
+
+  /**
+   * This method is called when the button is released.
+   */
+  virtual void OnReleased() {}
+
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::PushButton::PressedSignal()
+   */
+  Toolkit::Button::ButtonSignalType& PressedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::PushButton::ReleasedSignal()
+   */
+  Toolkit::Button::ButtonSignalType& ReleasedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Button::ClickedSignal()
+   */
+  Toolkit::Button::ButtonSignalType& ClickedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Button::StateChangedSignal()
+   */
+  Toolkit::Button::ButtonSignalType& StateChangedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+protected: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   * @note If overridden by deriving button classes, then an up-call to Button::OnInitialize MUST be made at the start.
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::OnAccessibilityActivated()
+   */
+  virtual bool OnAccessibilityActivated();
+
+  /**
+   * @copydoc Toolkit::Control::OnKeyboardEnter()
+   */
+  virtual bool OnKeyboardEnter();
+
+  /**
+   * @copydoc Toolkit::Control::OnStageDisconnection()
+   * @note If overridden by deriving button classes, then an up-call to Button::OnStageDisconnection MUST be made at the end.
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc Toolkit::Control::OnStageConnnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Toolkit::Control::GetNaturalSize
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Toolkit::Control::OnSetResizePolicy
+   */
+  virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension );
+
+  /**
+   * @copydoc Toolkit::Control::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+private:
+
+  /**
+   * @brief Handler for touch data
+   * @param[in]  actor  The touched actor.
+   * @param[in]  touch  The touch info.
+   * @return true, if consumed, false otherwise.
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Handler for tap events.
+   * We do not actually do anything when we receive a tap as the button handles tap event through
+   * the touch event system itself as it requires more than just tap handling (e.g. leave events).
+   * This stops any of our parents receiving a tap gesture when it occurs within our area.
+   * @param[in]  actor  The tapped actor.
+   * @param[in]  tap    The tap gesture.
+   */
+  void OnTap(Actor actor, const TapGesture& tap);
+
+  /**
+   * Sets up the autorepeating timer.
+   * @param[in] delay The delay time in seconds.
+   */
+  void SetUpTimer( float delay );
+
+  /**
+   * Button has been pressed
+   */
+  void Pressed();
+
+  /**
+   * This method is called the button is down.
+   */
+  void ButtonDown();
+
+  /**
+   * This method is called when the button is up.
+   */
+  void ButtonUp();
+
+  /**
+   * Slot called when Dali::Timer::SignalTick signal. Resets the autorepeating timer.
+   */
+  bool AutoRepeatingSlot();
+
+  /**
+   *  Check the requested state is an allowed transition.
+   *  Some states can not be transitioned to from certain states.
+   *  @param[in] requestedState check if can transition to this state
+   *  @return bool true if state change valid
+   */
+  bool ValidateState( State requestedState );
+
+  /**
+   * Changes the button state when an action occurs on it
+   * @param[in] requestedState the state to change to
+   */
+  void ChangeState( State requestedState );
+
+  /**
+   * This method is called when the button is released.
+   */
+  void Released();
+
+protected:
+
+  /**
+   * Set Text Label Padding
+   * @param[in] padding BEGIN END BOTTOM TOP
+   */
+  void SetLabelPadding( const Padding& padding );
+
+  /**
+   * Get Text Label padding
+   * @return Padding
+   */
+  Padding GetLabelPadding();
+
+  /**
+   * Set Foreground/icon Padding
+   * @param[in] padding BEGIN END BOTTOM TOP
+   */
+  void SetForegroundPadding( const Padding& padding);
+
+  /**
+   * Get Foreground padding
+   * @ return Padding
+   */
+  Padding GetForegroundPadding();
+
+  /**
+   * @brief Setup the button components for example foregrounds and background
+   * @param[in] index the index of the visual to set
+   * @param[in] value the value to set on the component
+   * @param[in] visualDepth the depth of the visual if overlapping another
+   */
+  void CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth );
+
+  /**
+   * @brief Get the Property map for the given Visual
+   * @param[in] visualIndex visual index of the required visual
+   * @param[out] retreivedMap the property map used to construct the required visual
+   * @return bool success flag, true if visual found
+   */
+  bool GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const;
+  /**
+   * Returns the animation to be used for transition, creating the animation if needed.
+   * @return The initialised transition animation.
+   */
+  Dali::Animation GetTransitionAnimation();
+
+  /**
+   * @brief Set the position of the label relative to foreground/icon, if both present
+   * @param[in] labelAlignment given alignment setting
+   */
+  void SetLabelAlignment( Align labelAlignment);
+
+  /**
+   * @brief Get set alignment of label in relation to foreground/icon
+   * @return Set alignment value
+   */
+  Align GetLabelAlignment();
+
+  /**
+   * Removes the visual from the button (un-staged)
+   * If the derived button does not want the visual removed then use this virtual function to
+   * define the required behaviour.
+   * Can decide to only remove specified visuals via index
+   */
+  virtual void OnButtonVisualRemoval( Property::Index visualIndex );
+
+
+private:
+
+  /**
+   * Removes the visual from the button and prepares it to be transitioned out
+   * @param[in] visualIndex the visual to remove
+   */
+  void RemoveVisual( Property::Index visualIndex );
+
+  /**
+   * Adds the required visual to the button.
+   * @param[in] visualIndex The Property index of the visual required
+   */
+  void SelectRequiredVisual( Property::Index visualIndex );
+
+  // Undefined
+  Button( const Button& );
+
+  // Undefined
+  Button& operator = ( const Button& );
+
+private:
+
+  // Signals
+  Toolkit::Button::ButtonSignalType mPressedSignal;           ///< Signal emitted when the button is pressed.
+  Toolkit::Button::ButtonSignalType mReleasedSignal;          ///< Signal emitted when the button is released.
+  Toolkit::Button::ButtonSignalType mClickedSignal;           ///< Signal emitted when the button is clicked.
+  Toolkit::Button::ButtonSignalType mStateChangedSignal;      ///< Signal emitted when the button's state is changed.
+
+  Timer            mAutoRepeatingTimer;
+
+  Actor            mLabel;                      ///< Stores the button text label.
+  Padding          mLabelPadding;               ///< The padding around the label (if present).
+  Padding          mForegroundPadding;          ///< The padding around the foreground/icon visual (if present).
+
+  Align            mTextLabelAlignment;           ///< Position of text label in relation to foreground/icon when both are present.
+
+  TapGestureDetector mTapDetector;
+
+  bool             mAutoRepeating;              ///< Stores the autorepeating property.
+  bool             mTogglableButton;            ///< Stores the togglable property as a flag.
+  bool             mTextStringSetFlag;          ///< Stores if text has been set. Required in relayout but don't want to calculate there.
+
+  float            mInitialAutoRepeatingDelay;  ///< Stores the initial autorepeating delay in seconds.
+  float            mNextAutoRepeatingDelay;     ///< Stores the next autorepeating delay in seconds.
+
+  float            mAnimationTime;
+
+  PressState       mButtonPressedState;         ///< In relation to the button being pressed/released
+  State            mButtonState;
+  State            mPreviousButtonState;        ///< During a transition between two states, this stores the previous state so Visuals can be removed.
+
+  // Actions
+  bool             mClickActionPerforming;      ///< Used to manage signal emissions during action
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Button& GetImplementation( Toolkit::Button& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<Toolkit::Internal::Button&>( handle );
+}
+
+inline const Toolkit::Internal::Button& GetImplementation( const Toolkit::Button& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  const Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::Button&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BUTTON_H
diff --git a/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp b/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp
new file mode 100644 (file)
index 0000000..9554ccb
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "check-box-button-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/images/resource-image.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/shader-effects/image-region-effect.h>
+#include <dali-toolkit/devel-api/shader-effects/image-region-effect.h>
+
+#if defined(DEBUG_ENABLED)
+  extern Debug::Filter* gLogButtonFilter;
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::CheckBoxButton::New();
+}
+
+TypeRegistration mType( typeid(Toolkit::CheckBoxButton), typeid(Toolkit::Button), Create );
+
+
+
+}
+
+Dali::Toolkit::CheckBoxButton CheckBoxButton::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< CheckBoxButton > internalCheckBoxButton = new CheckBoxButton();
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::CheckBoxButton checkBoxButton( *internalCheckBoxButton );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalCheckBoxButton->Initialize();
+
+  return checkBoxButton;
+}
+
+CheckBoxButton::CheckBoxButton()
+: Button()
+{
+  SetTogglableButton( true );
+}
+
+CheckBoxButton::~CheckBoxButton()
+{
+}
+
+void CheckBoxButton::OnInitialize()
+{
+  Button::OnInitialize();
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/buttons/check-box-button-impl.h b/dali-toolkit/internal/controls/buttons/check-box-button-impl.h
new file mode 100644 (file)
index 0000000..aa99068
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CHECK_BOX_BUTTON_H
+#define DALI_TOOLKIT_INTERNAL_CHECK_BOX_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/check-box-button.h>
+
+#include "button-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * CheckBoxButton implementation class.
+ *
+ * \sa Dali::Toolkit::CheckBoxButton
+ */
+class CheckBoxButton : public Button
+{
+public:
+
+  /**
+   * Create a new CheckBoxButton.
+   * @return A smart-pointer to the newly allocated CheckBoxButton.
+   */
+  static Dali::Toolkit::CheckBoxButton New();
+
+private:
+
+  /**
+   * Construct a new CheckBoxButton.
+   */
+  CheckBoxButton();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~CheckBoxButton();
+
+private: // From Button
+
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnInitialize
+   */
+  virtual void OnInitialize();
+
+private:
+
+  // Undefined
+  CheckBoxButton( const CheckBoxButton& );
+
+  // Undefined
+  CheckBoxButton& operator=( const CheckBoxButton& );
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::CheckBoxButton& GetImplementation( Toolkit::CheckBoxButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<Toolkit::Internal::CheckBoxButton&>( handle );
+}
+
+inline const Toolkit::Internal::CheckBoxButton& GetImplementation( const Toolkit::CheckBoxButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  const Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::CheckBoxButton&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CHECK_BOX_BUTTON_H
diff --git a/dali-toolkit/internal/controls/buttons/push-button-impl.cpp b/dali-toolkit/internal/controls/buttons/push-button-impl.cpp
new file mode 100644 (file)
index 0000000..f263489
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2019 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 "push-button-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+#if defined(DEBUG_ENABLED)
+  extern Debug::Filter* gLogButtonFilter;
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::PushButton::New();
+}
+
+// Properties
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::PushButton, Toolkit::Button, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "unselectedIcon",  STRING, UNSELECTED_ICON )
+DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "selectedIcon",  STRING, SELECTED_ICON )
+DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "iconAlignment",  STRING, ICON_ALIGNMENT )
+DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "labelPadding",  STRING, LABEL_PADDING )
+DALI_PROPERTY_REGISTRATION( Toolkit, PushButton, "iconPadding",  STRING, ICON_PADDING )
+
+DALI_TYPE_REGISTRATION_END()
+
+/*
+ * Table to define Text-to-enum conversions for IconAlignment.
+ */
+const Dali::Scripting::StringEnum IconAlignmentTable[] = {
+  { "LEFT",   Toolkit::Internal::PushButton::LEFT },
+  { "RIGHT",  Toolkit::Internal::PushButton::RIGHT },
+  { "TOP",    Toolkit::Internal::PushButton::TOP },
+  { "BOTTOM", Toolkit::Internal::PushButton::BOTTOM },
+}; const unsigned int IconAlignmentTableCount = sizeof( IconAlignmentTable ) / sizeof( IconAlignmentTable[0] );
+
+} // unnamed namespace
+
+namespace
+{
+
+} // unnamed namespace
+
+Dali::Toolkit::PushButton PushButton::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< PushButton > internalPushButton = new PushButton();
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::PushButton pushButton( *internalPushButton );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalPushButton->Initialize();
+
+  return pushButton;
+}
+
+PushButton::PushButton()
+: Button(),
+  mIconAlignment( RIGHT )
+{
+}
+
+PushButton::~PushButton()
+{
+}
+
+void PushButton::OnInitialize()
+{
+  Button::OnInitialize();
+
+  // Push button requires the Leave event.
+  Actor self = Self();
+  self.SetLeaveRequired( true );
+}
+
+void PushButton::SetIconAlignment( const PushButton::IconAlignment iconAlignment )
+{
+  mIconAlignment = iconAlignment;
+  Button::Align labelAlignment;
+  switch ( iconAlignment )
+  {
+  case RIGHT:
+  {
+    labelAlignment = Button::BEGIN;
+    break;
+  }
+  case TOP:
+  {
+    labelAlignment = Button::BOTTOM;
+    break;
+  }
+  case BOTTOM:
+  {
+    labelAlignment = Button::TOP;
+    break;
+  }
+  case LEFT:
+  default:
+    labelAlignment = Button::END;
+    break;
+  }
+
+  Button::SetLabelAlignment( labelAlignment );
+}
+
+const PushButton::IconAlignment PushButton::GetIconAlignment() const
+{
+  return mIconAlignment;
+}
+
+void PushButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
+
+  if ( pushButton )
+  {
+    PushButton& pushButtonImpl( GetImplementation( pushButton ) );
+
+    // Properties remain here for Tizen 3.0 legacy requirements. Are now in Button base class
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::PushButton::Property::UNSELECTED_ICON:
+      {
+        pushButtonImpl.CreateVisualsForComponent( Toolkit::Button::Property::UNSELECTED_VISUAL, value, DepthIndex::CONTENT );
+        break;
+      }
+      case Toolkit::PushButton::Property::SELECTED_ICON:
+      {
+        pushButtonImpl.CreateVisualsForComponent( Toolkit::Button::Property::SELECTED_VISUAL, value, DepthIndex::CONTENT );
+        break;
+      }
+      case Toolkit::PushButton::Property::ICON_ALIGNMENT:
+      {
+        IconAlignment iconAlignment;
+        if( Scripting::GetEnumeration< IconAlignment >( value.Get< std::string >().c_str(), IconAlignmentTable, IconAlignmentTableCount, iconAlignment ) )
+        {
+          pushButtonImpl.SetIconAlignment( iconAlignment );
+        }
+        break;
+      }
+      case Toolkit::PushButton::Property::LABEL_PADDING:
+      {
+        Vector4 padding ( value.Get< Vector4 >() );
+        pushButtonImpl.Button::SetLabelPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
+        break;
+      }
+      case Toolkit::PushButton::Property::ICON_PADDING:
+      {
+        Vector4 padding ( value.Get< Vector4 >() );
+        pushButtonImpl.Button::SetForegroundPadding( Padding( padding.x, padding.y, padding.z, padding.w ) );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value PushButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::PushButton pushButton = Toolkit::PushButton::DownCast( Dali::BaseHandle( object ) );
+
+  if ( pushButton )
+  {
+    PushButton& pushButtonImpl( GetImplementation( pushButton ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::PushButton::Property::UNSELECTED_ICON:
+      {
+        //value = pushButtonImpl.GetIcon( UNSELECTED_DECORATION );
+        break;
+      }
+      case Toolkit::PushButton::Property::SELECTED_ICON:
+      {
+        //value = pushButtonImpl.GetIcon( UNSELECTED_DECORATION );
+        break;
+      }
+      case Toolkit::PushButton::Property::ICON_ALIGNMENT:
+      {
+        value = Scripting::GetLinearEnumerationName< IconAlignment >( pushButtonImpl.GetIconAlignment(), IconAlignmentTable, IconAlignmentTableCount );
+        break;
+      }
+      case Toolkit::PushButton::Property::LABEL_PADDING:
+      {
+        Padding padding = pushButtonImpl.Button::GetLabelPadding();
+        value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
+        break;
+      }
+      case Toolkit::PushButton::Property::ICON_PADDING:
+      {
+        Padding padding = pushButtonImpl.Button::GetForegroundPadding();
+        value = Vector4( padding.x, padding.y, padding.top, padding.bottom);
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/buttons/push-button-impl.h b/dali-toolkit/internal/controls/buttons/push-button-impl.h
new file mode 100644 (file)
index 0000000..8e11d79
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PUSH_BUTTON_H
+#define DALI_TOOLKIT_INTERNAL_PUSH_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/push-button.h>
+#include "button-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * PushButton implementation class.
+ *
+ * \sa Dali::Toolkit::PushButton
+ */
+class PushButton : public Button
+{
+public:
+
+  /**
+   * Create a new PushButton.
+   * @return A smart-pointer to the newly allocated PushButton.
+   */
+  static Dali::Toolkit::PushButton New();
+
+protected:
+
+  /**
+   * Construct a new PushButton.
+   */
+  PushButton();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PushButton();
+
+public:
+
+  // Properties
+
+  /**
+   * Enum for the alignment modes of the icon.
+   */
+  enum IconAlignment
+  {
+    LEFT,
+    RIGHT,
+    TOP,
+    BOTTOM,
+    DEFAULT = RIGHT
+  };
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+private: // From Button
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnInitialize
+   */
+  virtual void OnInitialize();
+
+private:
+
+  /**
+   * @brief Sets the alignment mode to use to align the icon to the label.
+   *
+   * @param[in] iconAlignment The alignment mode to use
+   */
+  void SetIconAlignment( const PushButton::IconAlignment iconAlignment );
+
+  /**
+   * @brief Gets the alignment mode used to align the icon to the label.
+   *
+   * @return The alignment mode in use
+   */
+  const PushButton::IconAlignment GetIconAlignment() const;
+
+private:
+
+  // Undefined
+  PushButton( const PushButton& );
+
+  // Undefined
+  PushButton& operator=( const PushButton& );
+
+private:
+
+  IconAlignment  mIconAlignment;                 ///< The alignment of the icon against the label.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::PushButton& GetImplementation( Toolkit::PushButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<Toolkit::Internal::PushButton&>( handle );
+}
+
+inline const Toolkit::Internal::PushButton& GetImplementation( const Toolkit::PushButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  const Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::PushButton&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_PUSH_BUTTON_H
diff --git a/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp b/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp
new file mode 100644 (file)
index 0000000..bbd151a
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ */
+
+
+// CLASS HEADER
+#include "radio-button-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/images/resource-image.h>
+
+#if defined(DEBUG_ENABLED)
+  extern Debug::Filter* gLogButtonFilter;
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::RadioButton::New();
+}
+
+TypeRegistration typeRegistration( typeid( Toolkit::RadioButton ), typeid( Toolkit::Button ), Create);
+
+}
+
+Dali::Toolkit::RadioButton RadioButton::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< RadioButton > internalRadioButton = new RadioButton();
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::RadioButton radioButton(*internalRadioButton);
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalRadioButton->Initialize();
+
+  return radioButton;
+}
+
+RadioButton::RadioButton()
+{
+  SetTogglableButton(true);
+}
+
+RadioButton::~RadioButton()
+{
+}
+
+void RadioButton::OnInitialize()
+{
+  Button::OnInitialize();
+}
+
+bool RadioButton::OnToggleReleased()
+{
+  // Radio button overrides toggle release (button up) as doesn't allow un-selection to be performed on it directly.
+  return false;
+}
+
+void RadioButton::OnStateChange( State newState )
+{
+  // Radio button can be part of a group, if a button in the group is selected then all others should be unselected
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "RadioButton::OnStateChange state(%d)\n", newState );
+
+  if ( SELECTED_STATE ==  newState )
+  {
+    Actor parent = Self().GetParent();
+    if( parent )
+    {
+      for( unsigned int i = 0; i < parent.GetChildCount(); ++i )
+      {
+        Dali::Toolkit::RadioButton radioButtonChild = Dali::Toolkit::RadioButton::DownCast( parent.GetChildAt( i ) );
+        if( radioButtonChild && radioButtonChild != Self() )
+        {
+          radioButtonChild.SetProperty( Toolkit::Button::Property::SELECTED, false );
+        }
+      }
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/buttons/radio-button-impl.h b/dali-toolkit/internal/controls/buttons/radio-button-impl.h
new file mode 100644 (file)
index 0000000..944162b
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_TOOLKIT_INTERNAL_RADIO_BUTTON_H
+#define DALI_TOOLKIT_INTERNAL_RADIO_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/radio-button.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include "button-impl.h"
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * RadioButton implementation class.
+ *
+ * \sa Dali::Toolkit::RadioButton
+ */
+class RadioButton: public Button
+{
+public:
+
+  /**
+   * Create a new RadioButton.
+   *
+   * @return A smart-pointer to the newly allocated RadioButton.
+   */
+  static Dali::Toolkit::RadioButton New();
+
+private:
+
+  /**
+   * Construct a new RadioButton.
+   */
+  RadioButton();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~RadioButton();
+
+private: // From Button
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnStateChange
+   */
+  virtual void OnStateChange( State newState );
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnToggleReleased
+   */
+  virtual bool OnToggleReleased();
+
+private:
+
+  // Undefined
+  RadioButton( const RadioButton& origin );
+
+  // Undefined
+  RadioButton& operator=( const RadioButton& origin );
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::RadioButton& GetImplementation(Toolkit::RadioButton& button)
+{
+  DALI_ASSERT_ALWAYS(button);
+
+  Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<Toolkit::Internal::RadioButton&> (handle);
+}
+
+inline const Toolkit::Internal::RadioButton& GetImplementation(const Toolkit::RadioButton& button)
+{
+  DALI_ASSERT_ALWAYS(button);
+
+  const Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::RadioButton&> (handle);
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_RADIO_BUTTON_H
diff --git a/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp b/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp
new file mode 100755 (executable)
index 0000000..6aaf423
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2019 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 "toggle-button-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+#if defined(DEBUG_ENABLED)
+  extern Debug::Filter* gLogButtonFilter;
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::ToggleButton::New();
+}
+
+// Properties
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToggleButton, Toolkit::Button, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "stateVisuals",       ARRAY,     STATE_VISUALS        )
+DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "tooltips",           ARRAY,     TOOLTIPS             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ToggleButton, "currentStateIndex",  INTEGER,   CURRENT_STATE_INDEX  )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // unnamed namespace
+
+Dali::Toolkit::ToggleButton ToggleButton::New()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::New\n" );
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< ToggleButton > internalToggleButton = new ToggleButton();
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::ToggleButton toggleButton( *internalToggleButton );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalToggleButton->Initialize();
+
+  return toggleButton;
+}
+
+ToggleButton::ToggleButton()
+: Button(),
+  mToggleStates(),
+  mToggleVisuals(),
+  mToggleSelectedVisuals(),
+  mToggleDisabledVisuals(),
+  mToggleDisabledSelectedVisuals(),
+  mToggleTooltips(),
+  mCurrentToggleIndex(0)
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Constructor\n" );
+  SetTogglableButton( false );
+}
+
+ToggleButton::~ToggleButton()
+{
+}
+
+void ToggleButton::OnInitialize()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnInitialize\n" );
+  Button::OnInitialize();
+
+  // Toggle button requires the Leave event.
+  Actor self = Self();
+  self.SetLeaveRequired( true );
+}
+
+void ToggleButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::SetProperty index[%d]\n", propertyIndex );
+
+  if ( toggleButton )
+  {
+    ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ToggleButton::Property::STATE_VISUALS:
+      {
+        Property::Array stateArray;
+        if( value.Get( stateArray ) )
+        {
+          toggleButtonImpl.SetToggleStates( stateArray );
+        }
+
+        break;
+      }
+      case Toolkit::ToggleButton::Property::TOOLTIPS:
+      {
+        Property::Array* tipArray = value.GetArray();
+        if( tipArray )
+        {
+          std::vector<std::string> tips;
+          size_t tipsCount = tipArray->Count();
+          tips.resize( tipsCount );
+          for( size_t i = 0; i != tipsCount; ++i )
+          {
+            tipArray->GetElementAt( i ).Get( tips[i] );
+          }
+          toggleButtonImpl.SetToggleTooltips(tips);
+        }
+        break;
+      }
+      default :
+      {
+        break;
+      }
+    } // end of switch
+  }
+}
+
+Property::Value ToggleButton::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::ToggleButton toggleButton = Toolkit::ToggleButton::DownCast( Dali::BaseHandle( object ) );
+
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::GetProperty index[%d]\n", propertyIndex );
+
+  if ( toggleButton )
+  {
+    ToggleButton& toggleButtonImpl( GetImplementation( toggleButton ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ToggleButton::Property::STATE_VISUALS:
+      {
+        Property::Array array = toggleButtonImpl.GetToggleStates();
+        value = Property::Value( array );
+        break;
+      }
+      case Toolkit::ToggleButton::Property::TOOLTIPS:
+      {
+        Property::Value value1( Property::ARRAY );
+        Property::Array* tipArray = value1.GetArray();
+
+        if( tipArray )
+        {
+          std::vector<std::string> tips = toggleButtonImpl.GetToggleTooltips();
+          size_t tipsCount( tips.size() );
+          for( size_t i( 0 ); i != tipsCount; ++i )
+          {
+            tipArray->PushBack( tips[i] );
+          }
+        }
+        value = value1;
+        break;
+      }
+      case Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX:
+      {
+        value = static_cast<int>(toggleButtonImpl.mCurrentToggleIndex);
+        break;
+      }
+    } // end of switch
+  }
+
+  return value;
+}
+
+void ToggleButton::CreateVisualsForAllStates( const Property::Array& states, std::vector<Toolkit::Visual::Base>& visuals )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::CreateVisualsForAllStates\n" );
+
+  visuals.clear();
+
+  for ( unsigned int i = 0; i < states.Count(); i++ )
+  {
+    Property::Value value(  states[i] );
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+    Toolkit::Visual::Base stateVisual;
+
+    if ( value.GetType() == Property::MAP )
+    {
+      Property::Map *map = value.GetMap();
+      if( map && !map->Empty() ) // Empty map results in current visual removal.
+      {
+        DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using Map\n" );
+        stateVisual = visualFactory.CreateVisual( *map );
+      }
+    }
+    else if ( value.GetType() ==  Property::STRING )
+    {
+      std::string imageUrl = value.Get<std::string>();
+      DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals Using image URL\n" );
+      if ( !imageUrl.empty() )
+      {
+        stateVisual = visualFactory.CreateVisual( imageUrl, ImageDimensions() );
+      }
+    }
+
+    if ( stateVisual )
+    {
+      stateVisual.SetDepthIndex( DepthIndex::CONTENT );
+      visuals.push_back( stateVisual );
+    }
+  } // end of for
+  DALI_LOG_INFO( gLogButtonFilter, Debug::Verbose, "ToggleButton::CreateVisuals mToggleVisuals:%d\n", mToggleVisuals.size() );
+}
+
+void ToggleButton::SetToggleStates( const Property::Array& states )
+{ //this should really be generalized to be either string or maps so that any visual can be created.
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleStates\n" );
+  if ( !states.Empty() )
+  {
+    mToggleStates.Clear();
+    mToggleStates = states;
+    /* New toggle button index from 0. */
+    mCurrentToggleIndex = 0;
+
+    // Create all visuals, save to mToggleVisuals.
+    CreateVisualsForAllStates( states, mToggleVisuals );
+    CreateVisualsForAllStates( states, mToggleSelectedVisuals );
+    CreateVisualsForAllStates( states, mToggleDisabledVisuals );
+    CreateVisualsForAllStates( states, mToggleDisabledSelectedVisuals );
+
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::Began to register visual.\n" );
+
+    PrepareVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
+    PrepareVisual( Toolkit::Button::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
+    PrepareVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
+    PrepareVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
+
+    RelayoutRequest();
+  }
+}
+
+Property::Array ToggleButton::GetToggleStates() const
+{
+  return mToggleStates;
+}
+
+void ToggleButton::SetToggleTooltips( std::vector<std::string>& tips )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::SetToggleTooltips\n" );
+  if ( !tips.empty() )
+  {
+    mToggleTooltips.clear();
+    mToggleTooltips.swap( tips );
+  }
+
+  if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
+  {
+    Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
+  }
+
+  RelayoutRequest();
+}
+
+const std::vector<std::string>& ToggleButton::GetToggleTooltips() const
+{
+  return mToggleTooltips;
+}
+
+void ToggleButton::PrepareVisual(Property::Index index, Toolkit::Visual::Base& visual)
+{
+  bool enabled = false; // Disabled by default
+
+  // Unregister the visual with the given index if registered previously
+  if( DevelControl::GetVisual( *this, index ) )
+  {
+    // Check whether it was enabled to ensure we do the same with the new visual we're registering
+    enabled = DevelControl::IsVisualEnabled( *this, index );
+    DevelControl::UnregisterVisual( *this, index );
+  }
+
+  DevelControl::RegisterVisual( *this, index, visual, enabled );
+}
+
+void ToggleButton::RelayoutVisual( Property::Index index, const Vector2& size )
+{
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, index );
+  if ( visual )
+  {
+    Size visualSize = Size::ZERO;
+    Vector2 visualPosition = Vector2::ZERO;
+
+    visual.GetNaturalSize( visualSize );
+
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual size to(%f,%f)\n", visualSize.width, visualSize.height );
+    DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout Setting visual position to(%f,%f)\n", visualPosition.x, visualPosition.y );
+
+    Property::Map visualTransform;
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, visualSize )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET, visualPosition )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::CENTER )
+                   .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::CENTER );
+
+    visual.SetTransformAndSize( visualTransform, size );
+  }
+}
+
+void ToggleButton::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnRelayout targetSize(%f,%f) ptr(%p)\n", size.width, size.height, this );
+
+  RelayoutVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, size );
+  RelayoutVisual( Toolkit::Button::Property::SELECTED_VISUAL, size );
+  RelayoutVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, size );
+  RelayoutVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, size );
+}
+
+void ToggleButton::OnPressed()
+{
+  DALI_LOG_INFO( gLogButtonFilter, Debug::General, "ToggleButton::OnPressed\n" );
+  // State index will add 1 only when button is pressed.
+  mCurrentToggleIndex = ( mCurrentToggleIndex + 1 ) % mToggleVisuals.size();
+
+  // Both create SelectedVisual and UnselectedVisual
+  PrepareVisual( Toolkit::Button::Property::UNSELECTED_VISUAL, mToggleVisuals[mCurrentToggleIndex] );
+  PrepareVisual( Toolkit::Button::Property::SELECTED_VISUAL, mToggleSelectedVisuals[mCurrentToggleIndex] );
+  PrepareVisual( Toolkit::Button::Property::DISABLED_UNSELECTED_VISUAL, mToggleDisabledVisuals[mCurrentToggleIndex] );
+  PrepareVisual( Toolkit::Button::Property::DISABLED_SELECTED_VISUAL, mToggleDisabledSelectedVisuals[mCurrentToggleIndex] );
+
+  //Need to check mCurrentToggleIndex, it must less than the size of mToggleTooltips.
+  if ( !mToggleTooltips.empty() && ( mCurrentToggleIndex < mToggleTooltips.size() ) )
+  {
+    Self().SetProperty( Toolkit::DevelControl::Property::TOOLTIP, mToggleTooltips[mCurrentToggleIndex] );
+  }
+
+  RelayoutRequest();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/buttons/toggle-button-impl.h b/dali-toolkit/internal/controls/buttons/toggle-button-impl.h
new file mode 100644 (file)
index 0000000..2c4f753
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TOGGLE_BUTTON_H
+#define DALI_TOOLKIT_INTERNAL_TOGGLE_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/property-value.h>
+#include <dali/public-api/object/property-array.h>
+
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/buttons/toggle-button.h>
+#include "button-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * ToggleButton implementation class.
+ *
+ * \sa Dali::Toolkit::ToggleButton
+ */
+class ToggleButton : public Button
+{
+public:
+
+  /**
+   * Create a new ToggleButton.
+   * @return A smart-pointer to the newly allocated ToggleButton.
+   */
+  static Dali::Toolkit::ToggleButton New();
+
+protected:
+
+  /**
+   * Construct a new ToggleButton.
+   */
+  ToggleButton();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ToggleButton();
+
+public:
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+private:
+
+  /**
+   * Called to create all toggle visuals and save them to mToggleVisuals.
+   * @param[in] states The array store toggle states.
+   * @param[out] visuals The created state visual vector.
+   */
+  void CreateVisualsForAllStates( const Property::Array& states, std::vector<Toolkit::Visual::Base>& visuals );
+
+  /**
+   * Called to set toggle states when TOGGLE_STATES is set in SetProperty function.
+   * @param[in] states The array store toggle states.
+   */
+  void SetToggleStates( const Property::Array& states );
+
+  /**
+   * Called to retrieve toggle states.
+   * @return The toggle states array.
+   */
+  Property::Array GetToggleStates() const;
+
+  /**
+   * Called to set toggle tooltips when TOGGLE_TIPS is set in SetProperty function.
+   * @param[in] tips The array store toggle tips.
+   */
+  void SetToggleTooltips( std::vector<std::string>& tips );
+
+  /**
+   * Called to retrieve toggle tips.
+   * @return The toggle tips array.
+   */
+  const std::vector<std::string>& GetToggleTooltips() const;
+
+  /**
+   * Called to prepare visual for next state.
+   * @param[in] index The property index to set.
+   * @param[in] visual The visual to set.
+   */
+  void PrepareVisual(Property::Index index, Toolkit::Visual::Base& visual);
+
+  /**
+   * Called to relayout visual.
+   * @param[in] index The index of visual to relayout.
+   * @param[in] size The size of control.
+   */
+  void RelayoutVisual( Property::Index index, const Vector2& size );
+
+private: // From Button
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Internal::Button::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * This method is called when the button is pressed.
+   */
+  virtual void OnPressed();
+
+private:
+
+  // Undefined
+  ToggleButton( const ToggleButton& );
+
+  // Undefined
+  ToggleButton& operator=( const ToggleButton& );
+
+private:
+
+  Property::Array mToggleStates;                              ///< Toggle states, string or map.
+  std::vector<Toolkit::Visual::Base> mToggleVisuals;          ///< Save all unselected visuals.
+  std::vector<Toolkit::Visual::Base> mToggleSelectedVisuals;  ///< Save all selected visuals.
+  std::vector<Toolkit::Visual::Base> mToggleDisabledVisuals;  ///< Save all disabled unselected visuals.
+  std::vector<Toolkit::Visual::Base> mToggleDisabledSelectedVisuals;  ///< Save all disabled selected visuals.
+  std::vector<std::string> mToggleTooltips;               ///< Toggle tooltips.
+  unsigned int             mCurrentToggleIndex;       ///< The index of state.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ToggleButton& GetImplementation( Toolkit::ToggleButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ToggleButton&>( handle );
+}
+
+inline const Toolkit::Internal::ToggleButton& GetImplementation( const Toolkit::ToggleButton& button )
+{
+  DALI_ASSERT_ALWAYS( button );
+
+  const Dali::RefObject& handle = button.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ToggleButton&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TOGGLE_BUTTON_H
diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp
new file mode 100755 (executable)
index 0000000..eb6285a
--- /dev/null
@@ -0,0 +1,1457 @@
+/*
+ * Copyright (c) 2019 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 "control-data-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <cstring>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/control-wrapper-impl.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+extern const Dali::Scripting::StringEnum ControlStateTable[];
+extern const unsigned int ControlStateTableCount;
+
+
+// Not static or anonymous - shared with other translation units
+const Scripting::StringEnum ControlStateTable[] = {
+  { "NORMAL",   Toolkit::DevelControl::NORMAL   },
+  { "FOCUSED",  Toolkit::DevelControl::FOCUSED  },
+  { "DISABLED", Toolkit::DevelControl::DISABLED },
+};
+const unsigned int ControlStateTableCount = sizeof( ControlStateTable ) / sizeof( ControlStateTable[0] );
+
+
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+
+template<typename T>
+void Remove( Dictionary<T>& keyValues, const std::string& name )
+{
+  keyValues.Remove(name);
+}
+
+void Remove( DictionaryKeys& keys, const std::string& name )
+{
+  DictionaryKeys::iterator iter = std::find( keys.begin(), keys.end(), name );
+  if( iter != keys.end())
+  {
+    keys.erase(iter);
+  }
+}
+
+Toolkit::Visual::Type GetVisualTypeFromMap( const Property::Map& map )
+{
+  Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE  );
+  Toolkit::Visual::Type type = Toolkit::Visual::IMAGE;
+  if( typeValue )
+  {
+    Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, type );
+  }
+  return type;
+}
+
+/**
+ *  Finds visual in given array, returning true if found along with the iterator for that visual as a out parameter
+ */
+bool FindVisual( Property::Index targetIndex, const RegisteredVisualContainer& visuals, RegisteredVisualContainer::Iterator& iter )
+{
+  for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
+  {
+    if ( (*iter)->index ==  targetIndex )
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+void FindChangableVisuals( Dictionary<Property::Map>& stateVisualsToAdd,
+                           Dictionary<Property::Map>& stateVisualsToChange,
+                           DictionaryKeys& stateVisualsToRemove)
+{
+  DictionaryKeys copyOfStateVisualsToRemove = stateVisualsToRemove;
+
+  for( DictionaryKeys::iterator iter = copyOfStateVisualsToRemove.begin();
+       iter != copyOfStateVisualsToRemove.end(); ++iter )
+  {
+    const std::string& visualName = (*iter);
+    Property::Map* toMap = stateVisualsToAdd.Find( visualName );
+    if( toMap )
+    {
+      stateVisualsToChange.Add( visualName, *toMap );
+      stateVisualsToAdd.Remove( visualName );
+      Remove( stateVisualsToRemove, visualName );
+    }
+  }
+}
+
+Toolkit::Visual::Base GetVisualByName(
+  const RegisteredVisualContainer& visuals,
+  const std::string& visualName )
+{
+  Toolkit::Visual::Base visualHandle;
+
+  RegisteredVisualContainer::Iterator iter;
+  for ( iter = visuals.Begin(); iter != visuals.End(); iter++ )
+  {
+    Toolkit::Visual::Base visual = (*iter)->visual;
+    if( visual && visual.GetName() == visualName )
+    {
+      visualHandle = visual;
+      break;
+    }
+  }
+  return visualHandle;
+}
+
+/**
+ * Move visual from source to destination container
+ */
+void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisualContainer& source, RegisteredVisualContainer& destination )
+{
+   Toolkit::Visual::Base visual = (*sourceIter)->visual;
+   if( visual )
+   {
+     RegisteredVisual* rv = source.Release( sourceIter );
+     destination.PushBack( rv );
+   }
+}
+
+/**
+ * Performs actions as requested using the action name.
+ * @param[in] object The object on which to perform the action.
+ * @param[in] actionName The action to perform.
+ * @param[in] attributes The attributes with which to perfrom this action.
+ * @return true if action has been accepted by this control
+ */
+const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated";
+static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) )
+  {
+    Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+    if( control )
+    {
+      // if cast succeeds there is an implementation so no need to check
+      ret = Internal::GetImplementation( control ).OnAccessibilityActivated();
+    }
+  }
+
+  return ret;
+}
+
+/**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+const char* SIGNAL_KEY_EVENT = "keyEvent";
+const char* SIGNAL_KEY_INPUT_FOCUS_GAINED = "keyInputFocusGained";
+const char* SIGNAL_KEY_INPUT_FOCUS_LOST = "keyInputFocusLost";
+const char* SIGNAL_TAPPED = "tapped";
+const char* SIGNAL_PANNED = "panned";
+const char* SIGNAL_PINCHED = "pinched";
+const char* SIGNAL_LONG_PRESSED = "longPressed";
+static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( false );
+  Toolkit::Control control = Toolkit::Control::DownCast( handle );
+  if ( control )
+  {
+    Internal::Control& controlImpl( Internal::GetImplementation( control ) );
+    connected = true;
+
+    if ( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_EVENT ) )
+    {
+      controlImpl.KeyEventSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_GAINED ) )
+    {
+      controlImpl.KeyInputFocusGainedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_LOST ) )
+    {
+      controlImpl.KeyInputFocusLostSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_TAPPED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Tap );
+      controlImpl.GetTapGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PANNED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Pan );
+      controlImpl.GetPanGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_PINCHED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::Pinch );
+      controlImpl.GetPinchGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+    else if( 0 == strcmp( signalName.c_str(), SIGNAL_LONG_PRESSED ) )
+    {
+      controlImpl.EnableGestureDetection( Gesture::LongPress );
+      controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor );
+    }
+  }
+  return connected;
+}
+
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Internal::Control::New();
+}
+// Setup signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Control, CustomActor, Create );
+
+// Note: Properties are registered separately below.
+
+SignalConnectorType registerSignal1( typeRegistration, SIGNAL_KEY_EVENT, &DoConnectSignal );
+SignalConnectorType registerSignal2( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_GAINED, &DoConnectSignal );
+SignalConnectorType registerSignal3( typeRegistration, SIGNAL_KEY_INPUT_FOCUS_LOST, &DoConnectSignal );
+SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnectSignal );
+SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal );
+SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal );
+SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal );
+
+TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction );
+
+DALI_TYPE_REGISTRATION_END()
+
+/**
+ * @brief Iterate through given container and setOffStage any visual found
+ *
+ * @param[in] container Container of visuals
+ * @param[in] parent Parent actor to remove visuals from
+ */
+void SetVisualsOffStage( const RegisteredVisualContainer& container, Actor parent )
+{
+  for( auto iter = container.Begin(), end = container.End() ; iter!= end; iter++)
+  {
+    if( (*iter)->visual )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::SetOffStage Setting visual(%d) off stage\n", (*iter)->index );
+      Toolkit::GetImplementation((*iter)->visual).SetOffStage( parent );
+    }
+  }
+}
+
+} // unnamed namespace
+
+
+// Properties registered without macro to use specific member variables.
+const PropertyRegistration Control::Impl::PROPERTY_1( typeRegistration, "styleName",              Toolkit::Control::Property::STYLE_NAME,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_2( typeRegistration, "reservedProperty01",     Toolkit::Control::Property::RESERVED_PROPERTY_01,         Property::VECTOR4, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_3( typeRegistration, "reservedProperty02",     Toolkit::Control::Property::RESERVED_PROPERTY_02,         Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_4( typeRegistration, "keyInputFocus",          Toolkit::Control::Property::KEY_INPUT_FOCUS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_5( typeRegistration, "background",             Toolkit::Control::Property::BACKGROUND,                   Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_6( typeRegistration, "margin",                 Toolkit::Control::Property::MARGIN,                       Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_7( typeRegistration, "padding",                Toolkit::Control::Property::PADDING,                      Property::EXTENTS, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_8( typeRegistration, "tooltip",                Toolkit::DevelControl::Property::TOOLTIP,                 Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_9( typeRegistration, "state",                  Toolkit::DevelControl::Property::STATE,                   Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_10( typeRegistration, "subState",               Toolkit::DevelControl::Property::SUB_STATE,               Property::STRING,  &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_11( typeRegistration, "leftFocusableActorId",   Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "rightFocusableActorId", Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID,Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_13( typeRegistration, "upFocusableActorId",    Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID,   Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_14( typeRegistration, "downFocusableActorId",  Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+const PropertyRegistration Control::Impl::PROPERTY_15( typeRegistration, "shadow",                Toolkit::DevelControl::Property::SHADOW,                  Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty );
+
+
+Control::Impl::Impl( Control& controlImpl )
+: mControlImpl( controlImpl ),
+  mState( Toolkit::DevelControl::NORMAL ),
+  mSubStateName(""),
+  mLeftFocusableActorId( -1 ),
+  mRightFocusableActorId( -1 ),
+  mUpFocusableActorId( -1 ),
+  mDownFocusableActorId( -1 ),
+  mStyleName(""),
+  mBackgroundColor(Color::TRANSPARENT),
+  mStartingPinchScale( NULL ),
+  mMargin( 0, 0, 0, 0 ),
+  mPadding( 0, 0, 0, 0 ),
+  mKeyEventSignal(),
+  mKeyInputFocusGainedSignal(),
+  mKeyInputFocusLostSignal(),
+  mResourceReadySignal(),
+  mVisualEventSignal(),
+  mPinchGestureDetector(),
+  mPanGestureDetector(),
+  mTapGestureDetector(),
+  mLongPressGestureDetector(),
+  mTooltip( NULL ),
+  mInputMethodContext(),
+  mFlags( Control::ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mIsKeyboardNavigationSupported( false ),
+  mIsKeyboardFocusGroup( false )
+{
+}
+
+Control::Impl::~Impl()
+{
+  // All gesture detectors will be destroyed so no need to disconnect.
+  delete mStartingPinchScale;
+}
+
+Control::Impl& Control::Impl::Get( Internal::Control& internalControl )
+{
+  return *internalControl.mImpl;
+}
+
+const Control::Impl& Control::Impl::Get( const Internal::Control& internalControl )
+{
+  return *internalControl.mImpl;
+}
+
+// Gesture Detection Methods
+void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
+{
+  mControlImpl.OnPinch(pinch);
+}
+
+void Control::Impl::PanDetected(Actor actor, const PanGesture& pan)
+{
+  mControlImpl.OnPan(pan);
+}
+
+void Control::Impl::TapDetected(Actor actor, const TapGesture& tap)
+{
+  mControlImpl.OnTap(tap);
+}
+
+void Control::Impl::LongPressDetected(Actor actor, const LongPressGesture& longPress)
+{
+  mControlImpl.OnLongPress(longPress);
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual )
+{
+  RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::NOT_SET );
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex )
+{
+  RegisterVisual( index, visual, VisualState::ENABLED, DepthIndexValue::SET, depthIndex );
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled )
+{
+  RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::NOT_SET );
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex )
+{
+  RegisterVisual( index, visual, ( enabled ? VisualState::ENABLED : VisualState::DISABLED ), DepthIndexValue::SET, depthIndex );
+}
+
+void Control::Impl::RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "RegisterVisual:%d \n", index );
+
+  bool visualReplaced ( false );
+  Actor self = mControlImpl.Self();
+
+  // Set the depth index, if not set by caller this will be either the current visual depth, max depth of all visuals
+  // or zero.
+  int requiredDepthIndex = visual.GetDepthIndex();
+
+  if( depthIndexValueSet == DepthIndexValue::SET )
+  {
+    requiredDepthIndex = depthIndex;
+  }
+
+  // Visual replacement, existing visual should only be removed from stage when replacement ready.
+  if( !mVisuals.Empty() )
+  {
+    RegisteredVisualContainer::Iterator registeredVisualsiter;
+    // Check if visual (index) is already registered, this is the current visual.
+    if( FindVisual( index, mVisuals, registeredVisualsiter ) )
+    {
+      Toolkit::Visual::Base& currentRegisteredVisual = (*registeredVisualsiter)->visual;
+      if( currentRegisteredVisual )
+      {
+        // Store current visual depth index as may need to set the replacement visual to same depth
+        const int currentDepthIndex = (*registeredVisualsiter)->visual.GetDepthIndex();
+
+        // No longer required to know if the replaced visual's resources are ready
+        StopObservingVisual( currentRegisteredVisual );
+
+        // If control staged and visual enabled then visuals will be swapped once ready
+        if(  self.OnStage() && enabled )
+        {
+          // Check if visual is currently in the process of being replaced ( is in removal container )
+          RegisteredVisualContainer::Iterator visualQueuedForRemoval;
+          if ( FindVisual( index, mRemoveVisuals, visualQueuedForRemoval ) )
+          {
+            // Visual with same index is already in removal container so current visual pending
+            // Only the the last requested visual will be displayed so remove current visual which is staged but not ready.
+            Toolkit::GetImplementation( currentRegisteredVisual ).SetOffStage( self );
+            mVisuals.Erase( registeredVisualsiter );
+          }
+          else
+          {
+            // current visual not already in removal container so add now.
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "RegisterVisual Move current registered visual to removal Queue: %d \n", index );
+            MoveVisual( registeredVisualsiter, mVisuals, mRemoveVisuals );
+          }
+        }
+        else
+        {
+          // Control not staged or visual disabled so can just erase from registered visuals and new visual will be added later.
+          mVisuals.Erase( registeredVisualsiter );
+        }
+
+        // If we've not set the depth-index value and the new visual does not have a depth index applied to it, then use the previously set depth-index for this index
+        if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
+            ( visual.GetDepthIndex() == 0 ) )
+        {
+          requiredDepthIndex = currentDepthIndex;
+        }
+      }
+
+      visualReplaced = true;
+    }
+  }
+
+  // If not set, set the name of the visual to the same name as the control's property.
+  // ( If the control has been type registered )
+  if( visual.GetName().empty() )
+  {
+    // returns empty string if index is not found as long as index is not -1
+    std::string visualName = self.GetPropertyName( index );
+    if( !visualName.empty() )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Concise, "Setting visual name for property %d to %s\n",
+                     index, visualName.c_str() );
+      visual.SetName( visualName );
+    }
+  }
+
+  if( !visualReplaced ) // New registration entry
+  {
+    // If we've not set the depth-index value, we have more than one visual and the visual does not have a depth index, then set it to be the highest
+    if( ( depthIndexValueSet == DepthIndexValue::NOT_SET ) &&
+        ( mVisuals.Size() > 0 ) &&
+        ( visual.GetDepthIndex() == 0 ) )
+    {
+      int maxDepthIndex = std::numeric_limits< int >::min();
+
+      RegisteredVisualContainer::ConstIterator iter;
+      const RegisteredVisualContainer::ConstIterator endIter = mVisuals.End();
+      for ( iter = mVisuals.Begin(); iter != endIter; iter++ )
+      {
+        const int visualDepthIndex = (*iter)->visual.GetDepthIndex();
+        if ( visualDepthIndex > maxDepthIndex )
+        {
+          maxDepthIndex = visualDepthIndex;
+        }
+      }
+      ++maxDepthIndex; // Add one to the current maximum depth index so that our added visual appears on top
+      requiredDepthIndex = std::max( 0, maxDepthIndex ); // Start at zero if maxDepth index belongs to a background
+    }
+  }
+
+  if( visual )
+  {
+    // Set determined depth index
+    visual.SetDepthIndex( requiredDepthIndex );
+
+    // Monitor when the visual resources are ready
+    StartObservingVisual( visual );
+
+    DALI_LOG_INFO( gLogFilter, Debug::Concise, "New Visual registration index[%d] depth[%d]\n", index, requiredDepthIndex );
+    RegisteredVisual* newRegisteredVisual  = new RegisteredVisual( index, visual,
+                                             ( enabled == VisualState::ENABLED ? true : false ),
+                                             ( visualReplaced && enabled ) ) ;
+    mVisuals.PushBack( newRegisteredVisual );
+
+    Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+    // Put on stage if enabled and the control is already on the stage
+    if( ( enabled == VisualState::ENABLED ) && self.OnStage() )
+    {
+      visualImpl.SetOnStage( self );
+    }
+    else if( visualImpl.IsResourceReady() ) // When not being staged, check if visual already 'ResourceReady' before it was Registered. ( Resource may have been loaded already )
+    {
+      ResourceReady( visualImpl );
+    }
+
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::RegisterVisual() Registered %s(%d), enabled:%s\n",  visual.GetName().c_str(), index, enabled?"true":"false" );
+}
+
+void Control::Impl::UnregisterVisual( Property::Index index )
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    // stop observing visual
+    StopObservingVisual( (*iter)->visual );
+
+    Actor self( mControlImpl.Self() );
+    Toolkit::GetImplementation((*iter)->visual).SetOffStage( self );
+    (*iter)->visual.Reset();
+    mVisuals.Erase( iter );
+  }
+
+  if( FindVisual( index, mRemoveVisuals, iter ) )
+  {
+    Actor self( mControlImpl.Self() );
+    Toolkit::GetImplementation( (*iter)->visual ).SetOffStage( self );
+    (*iter)->pending = false;
+    (*iter)->visual.Reset();
+    mRemoveVisuals.Erase( iter );
+  }
+}
+
+Toolkit::Visual::Base Control::Impl::GetVisual( Property::Index index ) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    return (*iter)->visual;
+  }
+
+  return Toolkit::Visual::Base();
+}
+
+void Control::Impl::EnableVisual( Property::Index index, bool enable )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Control::EnableVisual(%d, %s)\n", index, enable?"T":"F");
+
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    if (  (*iter)->enabled == enable )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Visual %s(%d) already %s\n", (*iter)->visual.GetName().c_str(), index, enable?"enabled":"disabled");
+      return;
+    }
+
+    (*iter)->enabled = enable;
+    Actor parentActor = mControlImpl.Self();
+    if ( mControlImpl.Self().OnStage() ) // If control not on Stage then Visual will be added when StageConnection is called.
+    {
+      if ( enable )
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) on stage \n", (*iter)->visual.GetName().c_str(), index );
+        Toolkit::GetImplementation((*iter)->visual).SetOnStage( parentActor );
+      }
+      else
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::EnableVisual Setting %s(%d) off stage \n", (*iter)->visual.GetName().c_str(), index );
+        Toolkit::GetImplementation((*iter)->visual).SetOffStage( parentActor );  // No need to call if control not staged.
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING( "Control::EnableVisual(%d, %s) FAILED - NO SUCH VISUAL\n", index, enable?"T":"F" );
+  }
+}
+
+bool Control::Impl::IsVisualEnabled( Property::Index index ) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    return (*iter)->enabled;
+  }
+  return false;
+}
+
+void Control::Impl::StopObservingVisual( Toolkit::Visual::Base& visual )
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+  // Stop observing the visual
+  visualImpl.RemoveEventObserver( *this );
+}
+
+void Control::Impl::StartObservingVisual( Toolkit::Visual::Base& visual)
+{
+  Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+  // start observing the visual for events
+  visualImpl.AddEventObserver( *this );
+}
+
+// Called by a Visual when it's resource is ready
+void Control::Impl::ResourceReady( Visual::Base& object)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::Impl::ResourceReady() replacements pending[%d]\n", mRemoveVisuals.Count() );
+
+  Actor self = mControlImpl.Self();
+
+  // A resource is ready, find resource in the registered visuals container and get its index
+  for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
+  {
+    Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
+
+    if( &object == &registeredVisualImpl )
+    {
+      RegisteredVisualContainer::Iterator visualToRemoveIter;
+      // Find visual with the same index in the removal container
+      // Set if off stage as it's replacement is now ready.
+      // Remove if from removal list as now removed from stage.
+      // Set Pending flag on the ready visual to false as now ready.
+      if( FindVisual( (*registeredIter)->index, mRemoveVisuals, visualToRemoveIter ) )
+      {
+        (*registeredIter)->pending = false;
+        Toolkit::GetImplementation( (*visualToRemoveIter)->visual ).SetOffStage( self );
+        mRemoveVisuals.Erase( visualToRemoveIter );
+      }
+      break;
+    }
+  }
+
+  // A visual is ready so control may need relayouting if staged
+  if ( self.OnStage() )
+  {
+    mControlImpl.RelayoutRequest();
+  }
+
+  // Emit signal if all enabled visuals registered by the control are ready.
+  if( IsResourceReady() )
+  {
+    Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
+    mResourceReadySignal.Emit( handle );
+  }
+}
+
+void Control::Impl::NotifyVisualEvent( Visual::Base& object, Property::Index signalId )
+{
+  for( auto registeredIter = mVisuals.Begin(),  end = mVisuals.End(); registeredIter != end; ++registeredIter )
+  {
+    Internal::Visual::Base& registeredVisualImpl = Toolkit::GetImplementation( (*registeredIter)->visual );
+    if( &object == &registeredVisualImpl )
+    {
+      Dali::Toolkit::Control handle( mControlImpl.GetOwner() );
+      mVisualEventSignal.Emit( handle, (*registeredIter)->index, signalId );
+      break;
+    }
+  }
+}
+
+bool Control::Impl::IsResourceReady() const
+{
+  // Iterate through and check all the enabled visuals are ready
+  for( auto visualIter = mVisuals.Begin();
+         visualIter != mVisuals.End(); ++visualIter )
+  {
+    const Toolkit::Visual::Base visual = (*visualIter)->visual;
+    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+
+    // one of the enabled visuals is not ready
+    if( !visualImpl.IsResourceReady() && (*visualIter)->enabled )
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+Toolkit::Visual::ResourceStatus Control::Impl::GetVisualResourceStatus( Property::Index index ) const
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( index, mVisuals, iter ) )
+  {
+    const Toolkit::Visual::Base visual = (*iter)->visual;
+    const Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+    return visualImpl.GetResourceStatus( );
+  }
+
+  return Toolkit::Visual::ResourceStatus::PREPARING;
+}
+
+
+
+void Control::Impl::AddTransitions( Dali::Animation& animation,
+                                    const Toolkit::TransitionData& handle,
+                                    bool createAnimation )
+{
+  // Setup a Transition from TransitionData.
+  const Internal::TransitionData& transitionData = Toolkit::GetImplementation( handle );
+  TransitionData::Iterator end = transitionData.End();
+  for( TransitionData::Iterator iter = transitionData.Begin() ;
+       iter != end; ++iter )
+  {
+    TransitionData::Animator* animator = (*iter);
+
+    Toolkit::Visual::Base visual = GetVisualByName( mVisuals, animator->objectName );
+
+    if( visual )
+    {
+#if defined(DEBUG_ENABLED)
+      Dali::TypeInfo typeInfo;
+      ControlWrapper* controlWrapperImpl = dynamic_cast<ControlWrapper*>(&mControlImpl);
+      if( controlWrapperImpl )
+      {
+        typeInfo = controlWrapperImpl->GetTypeInfo();
+      }
+
+      DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Found %s visual for %s\n",
+                     visual.GetName().c_str(), typeInfo?typeInfo.GetName().c_str():"Unknown" );
+#endif
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.AnimateProperty( animation, *animator );
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Concise, "CreateTransition: Could not find visual. Trying actors");
+      // Otherwise, try any actor children of control (Including the control)
+      Actor child = mControlImpl.Self().FindChildByName( animator->objectName );
+      if( child )
+      {
+        Property::Index propertyIndex = DevelHandle::GetPropertyIndex( child, animator->propertyKey );
+        if( propertyIndex != Property::INVALID_INDEX )
+        {
+          if( animator->animate == false )
+          {
+            if( animator->targetValue.GetType() != Property::NONE )
+            {
+              child.SetProperty( propertyIndex, animator->targetValue );
+            }
+          }
+          else // animate the property
+          {
+            if( animator->initialValue.GetType() != Property::NONE )
+            {
+              child.SetProperty( propertyIndex, animator->initialValue );
+            }
+
+            if( createAnimation && !animation )
+            {
+              animation = Dali::Animation::New( 0.1f );
+            }
+
+            animation.AnimateTo( Property( child, propertyIndex ),
+                                 animator->targetValue,
+                                 animator->alphaFunction,
+                                 TimePeriod( animator->timePeriodDelay,
+                                             animator->timePeriodDuration ) );
+          }
+        }
+      }
+    }
+  }
+}
+
+Dali::Animation Control::Impl::CreateTransition( const Toolkit::TransitionData& transitionData )
+{
+  Dali::Animation transition;
+
+  if( transitionData.Count() > 0 )
+  {
+    AddTransitions( transition, transitionData, true );
+  }
+  return transition;
+}
+
+
+
+void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes )
+{
+  RegisteredVisualContainer::Iterator iter;
+  if ( FindVisual( visualIndex, mVisuals, iter ) )
+  {
+    Toolkit::GetImplementation((*iter)->visual).DoAction( actionId, attributes );
+  }
+}
+
+void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+
+  if ( control )
+  {
+    Control& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case Toolkit::Control::Property::STYLE_NAME:
+      {
+        controlImpl.SetStyleName( value.Get< std::string >() );
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::STATE:
+      {
+        bool withTransitions=true;
+        const Property::Value* valuePtr=&value;
+        Property::Map* map = value.GetMap();
+        if(map)
+        {
+          Property::Value* value2 = map->Find("withTransitions");
+          if( value2 )
+          {
+            withTransitions = value2->Get<bool>();
+          }
+
+          valuePtr = map->Find("state");
+        }
+
+        if( valuePtr )
+        {
+          Toolkit::DevelControl::State state( controlImpl.mImpl->mState );
+          if( Scripting::GetEnumerationProperty< Toolkit::DevelControl::State >( *valuePtr, ControlStateTable, ControlStateTableCount, state ) )
+          {
+            controlImpl.mImpl->SetState( state, withTransitions );
+          }
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::SUB_STATE:
+      {
+        std::string subState;
+        if( value.Get( subState ) )
+        {
+          controlImpl.mImpl->SetSubState( subState );
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mLeftFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mRightFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mUpFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if( value.Get( focusId ) )
+        {
+          controlImpl.mImpl->mDownFocusableActorId = focusId;
+        }
+      }
+      break;
+
+      case Toolkit::Control::Property::KEY_INPUT_FOCUS:
+      {
+        if ( value.Get< bool >() )
+        {
+          controlImpl.SetKeyInputFocus();
+        }
+        else
+        {
+          controlImpl.ClearKeyInputFocus();
+        }
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND:
+      {
+        std::string url;
+        Vector4 color;
+        const Property::Map* map = value.GetMap();
+        if( map && !map->Empty() )
+        {
+          controlImpl.SetBackground( *map );
+        }
+        else if( value.Get( url ) )
+        {
+          // don't know the size to load
+          Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( url, ImageDimensions() );
+          if( visual )
+          {
+            controlImpl.mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
+          }
+        }
+        else if( value.Get( color ) )
+        {
+          controlImpl.SetBackgroundColor(color);
+        }
+        else
+        {
+          // The background is an empty property map, so we should clear the background
+          controlImpl.ClearBackground();
+        }
+        break;
+      }
+
+      case Toolkit::Control::Property::MARGIN:
+      {
+        Extents margin;
+        if( value.Get( margin ) )
+        {
+          controlImpl.mImpl->SetMargin( margin );
+        }
+        break;
+      }
+
+      case Toolkit::Control::Property::PADDING:
+      {
+        Extents padding;
+        if( value.Get( padding ) )
+        {
+          controlImpl.mImpl->SetPadding( padding );
+        }
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::TOOLTIP:
+      {
+        TooltipPtr& tooltipPtr = controlImpl.mImpl->mTooltip;
+        if( ! tooltipPtr )
+        {
+          tooltipPtr = Tooltip::New( control );
+        }
+        tooltipPtr->SetProperties( value );
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::SHADOW:
+      {
+        const Property::Map* map = value.GetMap();
+        if( map && !map->Empty() )
+        {
+          controlImpl.mImpl->SetShadow( *map );
+        }
+        else
+        {
+          // The shadow is an empty property map, so we should clear the shadow
+          controlImpl.mImpl->ClearShadow();
+        }
+        break;
+      }
+
+    }
+  }
+}
+
+Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) );
+
+  if ( control )
+  {
+    Control& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case Toolkit::Control::Property::STYLE_NAME:
+      {
+        value = controlImpl.GetStyleName();
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::STATE:
+      {
+        value = controlImpl.mImpl->mState;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::SUB_STATE:
+      {
+        value = controlImpl.mImpl->mSubStateName;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mLeftFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mRightFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mUpFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mDownFocusableActorId;
+        break;
+      }
+
+      case Toolkit::Control::Property::KEY_INPUT_FOCUS:
+      {
+        value = controlImpl.HasKeyInputFocus();
+        break;
+      }
+
+      case Toolkit::Control::Property::BACKGROUND:
+      {
+        Property::Map map;
+        Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+
+        value = map;
+        break;
+      }
+
+      case Toolkit::Control::Property::MARGIN:
+      {
+        value = controlImpl.mImpl->GetMargin();
+        break;
+      }
+
+      case Toolkit::Control::Property::PADDING:
+      {
+        value = controlImpl.mImpl->GetPadding();
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::TOOLTIP:
+      {
+        Property::Map map;
+        if( controlImpl.mImpl->mTooltip )
+        {
+          controlImpl.mImpl->mTooltip->CreatePropertyMap( map );
+        }
+        value = map;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::SHADOW:
+      {
+        Property::Map map;
+        Toolkit::Visual::Base visual = controlImpl.mImpl->GetVisual( Toolkit::DevelControl::Property::SHADOW );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+
+        value = map;
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+
+void  Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties )
+{
+  for(RegisteredVisualContainer::Iterator iter = visuals.Begin(); iter!= visuals.End(); iter++)
+  {
+    if( (*iter)->visual )
+    {
+      Property::Map instanceMap;
+      Toolkit::GetImplementation((*iter)->visual).CreateInstancePropertyMap(instanceMap);
+      instancedProperties.Add( (*iter)->visual.GetName(), instanceMap );
+    }
+  }
+}
+
+
+void Control::Impl::RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName )
+{
+  Actor self( mControlImpl.Self() );
+
+  for ( RegisteredVisualContainer::Iterator visualIter = visuals.Begin();
+        visualIter != visuals.End(); ++visualIter )
+  {
+    Toolkit::Visual::Base visual = (*visualIter)->visual;
+    if( visual && visual.GetName() == visualName )
+    {
+      Toolkit::GetImplementation(visual).SetOffStage( self );
+      (*visualIter)->visual.Reset();
+      visuals.Erase( visualIter );
+      break;
+    }
+  }
+}
+
+void Control::Impl::RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals )
+{
+  Actor self( mControlImpl.Self() );
+  for( DictionaryKeys::iterator iter = removeVisuals.begin(); iter != removeVisuals.end(); ++iter )
+  {
+    const std::string visualName = *iter;
+    RemoveVisual( visuals, visualName );
+  }
+}
+
+void Control::Impl::RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange,
+                             Dictionary<Property::Map>& instancedProperties )
+{
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  for( Dictionary<Property::Map>::iterator iter = stateVisualsToChange.Begin();
+       iter != stateVisualsToChange.End(); ++iter )
+  {
+    const std::string& visualName = (*iter).key;
+    const Property::Map& toMap = (*iter).entry;
+
+    // is it a candidate for re-creation?
+    bool recreate = false;
+
+    Toolkit::Visual::Base visual = GetVisualByName( mVisuals, visualName );
+    if( visual )
+    {
+      Property::Map fromMap;
+      visual.CreatePropertyMap( fromMap );
+
+      Toolkit::Visual::Type fromType = GetVisualTypeFromMap( fromMap );
+      Toolkit::Visual::Type toType = GetVisualTypeFromMap( toMap );
+
+      if( fromType != toType )
+      {
+        recreate = true;
+      }
+      else
+      {
+        if( fromType == Toolkit::Visual::IMAGE || fromType == Toolkit::Visual::N_PATCH
+            || fromType == Toolkit::Visual::SVG || fromType == Toolkit::Visual::ANIMATED_IMAGE )
+        {
+          Property::Value* fromUrl = fromMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+          Property::Value* toUrl = toMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+
+          if( fromUrl && toUrl )
+          {
+            std::string fromUrlString;
+            std::string toUrlString;
+            fromUrl->Get(fromUrlString);
+            toUrl->Get(toUrlString);
+
+            if( fromUrlString != toUrlString )
+            {
+              recreate = true;
+            }
+          }
+        }
+      }
+
+      const Property::Map* instancedMap = instancedProperties.FindConst( visualName );
+      if( recreate || instancedMap )
+      {
+        RemoveVisual( mVisuals, visualName );
+        Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+      }
+      else
+      {
+        // @todo check to see if we can apply toMap without recreating the visual
+        // e.g. by setting only animatable properties
+        // For now, recreate all visuals, but merge in instance data.
+        RemoveVisual( mVisuals, visualName );
+        Style::ApplyVisual( handle, visualName, toMap, instancedMap );
+      }
+    }
+  }
+}
+
+void Control::Impl::ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState )
+{
+  // Collect all old visual names
+  DictionaryKeys stateVisualsToRemove;
+  if( oldState )
+  {
+    oldState->visuals.GetKeys( stateVisualsToRemove );
+    if( ! subState.empty() )
+    {
+      const StylePtr* oldSubState = oldState->subStates.FindConst(subState);
+      if( oldSubState )
+      {
+        DictionaryKeys subStateVisualsToRemove;
+        (*oldSubState)->visuals.GetKeys( subStateVisualsToRemove );
+        Merge( stateVisualsToRemove, subStateVisualsToRemove );
+      }
+    }
+  }
+
+  // Collect all new visual properties
+  Dictionary<Property::Map> stateVisualsToAdd;
+  if( newState )
+  {
+    stateVisualsToAdd = newState->visuals;
+    if( ! subState.empty() )
+    {
+      const StylePtr* newSubState = newState->subStates.FindConst(subState);
+      if( newSubState )
+      {
+        stateVisualsToAdd.Merge( (*newSubState)->visuals );
+      }
+    }
+  }
+
+  // If a name is in both add/remove, move it to change list.
+  Dictionary<Property::Map> stateVisualsToChange;
+  FindChangableVisuals( stateVisualsToAdd, stateVisualsToChange, stateVisualsToRemove);
+
+  // Copy instanced properties (e.g. text label) of current visuals
+  Dictionary<Property::Map> instancedProperties;
+  CopyInstancedProperties( mVisuals, instancedProperties );
+
+  // For each visual in remove list, remove from mVisuals
+  RemoveVisuals( mVisuals, stateVisualsToRemove );
+
+  // For each visual in add list, create and add to mVisuals
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  Style::ApplyVisuals( handle, stateVisualsToAdd, instancedProperties );
+
+  // For each visual in change list, if it requires a new visual,
+  // remove old visual, create and add to mVisuals
+  RecreateChangedVisuals( stateVisualsToChange, instancedProperties );
+}
+
+void Control::Impl::SetState( DevelControl::State newState, bool withTransitions )
+{
+  DevelControl::State oldState = mState;
+  Dali::CustomActor handle( mControlImpl.GetOwner() );
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "Control::Impl::SetState: %s\n",
+                (mState == DevelControl::NORMAL ? "NORMAL" :(
+                  mState == DevelControl::FOCUSED ?"FOCUSED" : (
+                    mState == DevelControl::DISABLED?"DISABLED":"NONE" ))));
+
+  if( mState != newState )
+  {
+    // If mState was Disabled, and new state is Focused, should probably
+    // store that fact, e.g. in another property that FocusManager can access.
+    mState = newState;
+
+    // Trigger state change and transitions
+    // Apply new style, if stylemanager is available
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+
+      if( stylePtr )
+      {
+        std::string oldStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( oldState, ControlStateTable, ControlStateTableCount );
+        std::string newStateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( newState, ControlStateTable, ControlStateTableCount );
+
+        const StylePtr* newStateStyle = stylePtr->subStates.Find( newStateName );
+        const StylePtr* oldStateStyle = stylePtr->subStates.Find( oldStateName );
+        if( oldStateStyle && newStateStyle )
+        {
+          // Only change if both state styles exist
+          ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, mSubStateName );
+        }
+      }
+    }
+  }
+}
+
+void Control::Impl::SetSubState( const std::string& subStateName, bool withTransitions )
+{
+  if( mSubStateName != subStateName )
+  {
+    // Get existing sub-state visuals, and unregister them
+    Dali::CustomActor handle( mControlImpl.GetOwner() );
+
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      const StylePtr stylePtr = GetImpl( styleManager ).GetRecordedStyle( Toolkit::Control( mControlImpl.GetOwner() ) );
+      if( stylePtr )
+      {
+        // Stringify state
+        std::string stateName = Scripting::GetEnumerationName< Toolkit::DevelControl::State >( mState, ControlStateTable, ControlStateTableCount );
+
+        const StylePtr* state = stylePtr->subStates.Find( stateName );
+        if( state )
+        {
+          StylePtr stateStyle(*state);
+
+          const StylePtr* newStateStyle = stateStyle->subStates.Find( subStateName );
+          const StylePtr* oldStateStyle = stateStyle->subStates.Find( mSubStateName );
+          if( oldStateStyle && newStateStyle )
+          {
+            std::string empty;
+            ReplaceStateVisualsAndProperties( *oldStateStyle, *newStateStyle, empty );
+          }
+        }
+      }
+    }
+
+    mSubStateName = subStateName;
+  }
+}
+
+void Control::Impl::OnStageDisconnection()
+{
+  Actor self = mControlImpl.Self();
+
+  // Any visuals set for replacement but not yet ready should still be registered.
+  // Reason: If a request was made to register a new visual but the control removed from stage before visual was ready
+  // then when this control appears back on stage it should use that new visual.
+
+  // Iterate through all registered visuals and set off stage
+  SetVisualsOffStage( mVisuals, self );
+
+  // Visuals pending replacement can now be taken out of the removal list and set off stage
+  // Iterate through all replacement visuals and add to a move queue then set off stage
+  for( auto removalIter = mRemoveVisuals.Begin(), end = mRemoveVisuals.End(); removalIter != end; removalIter++ )
+  {
+    Toolkit::GetImplementation((*removalIter)->visual).SetOffStage( self );
+  }
+
+  for( auto replacedIter = mVisuals.Begin(), end = mVisuals.End(); replacedIter != end; replacedIter++ )
+  {
+    (*replacedIter)->pending = false;
+  }
+
+  mRemoveVisuals.Clear();
+}
+
+void Control::Impl::SetMargin( Extents margin )
+{
+  mControlImpl.mImpl->mMargin = margin;
+
+  // Trigger a size negotiation request that may be needed when setting a margin.
+  mControlImpl.RelayoutRequest();
+}
+
+Extents Control::Impl::GetMargin() const
+{
+  return mControlImpl.mImpl->mMargin;
+}
+
+void Control::Impl::SetPadding( Extents padding )
+{
+  mControlImpl.mImpl->mPadding = padding;
+
+  // Trigger a size negotiation request that may be needed when setting a padding.
+  mControlImpl.RelayoutRequest();
+}
+
+Extents Control::Impl::GetPadding() const
+{
+  return mControlImpl.mImpl->mPadding;
+}
+
+void Control::Impl::SetInputMethodContext( InputMethodContext& inputMethodContext )
+{
+  mInputMethodContext = inputMethodContext;
+}
+
+bool Control::Impl::FilterKeyEvent( const KeyEvent& event )
+{
+  bool consumed ( false );
+
+  if ( mInputMethodContext )
+  {
+    consumed = mInputMethodContext.FilterEventKey( event );
+  }
+  return consumed;
+}
+
+DevelControl::VisualEventSignalType& Control::Impl::VisualEventSignal()
+{
+  return mVisualEventSignal;
+}
+
+void Control::Impl::SetShadow( const Property::Map& map )
+{
+  Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
+  visual.SetName("shadow");
+
+  if( visual )
+  {
+    mControlImpl.mImpl->RegisterVisual( Toolkit::DevelControl::Property::SHADOW, visual, DepthIndex::BACKGROUND_EFFECT );
+
+    mControlImpl.RelayoutRequest();
+  }
+}
+
+void Control::Impl::ClearShadow()
+{
+   mControlImpl.mImpl->UnregisterVisual( Toolkit::DevelControl::Property::SHADOW );
+
+   // Trigger a size negotiation request that may be needed when unregistering a visual.
+   mControlImpl.RelayoutRequest();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/control/control-data-impl.h b/dali-toolkit/internal/controls/control/control-data-impl.h
new file mode 100755 (executable)
index 0000000..210f6e2
--- /dev/null
@@ -0,0 +1,455 @@
+#ifndef DALI_TOOLKIT_CONTROL_DATA_IMPL_H
+#define DALI_TOOLKIT_CONTROL_DATA_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/type-registry.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-event-observer.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/internal/controls/tooltip/tooltip.h>
+#include <dali-toolkit/internal/builder/style.h>
+#include <dali-toolkit/internal/builder/dictionary.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+ /**
+  * Struct used to store Visual within the control, index is a unique key for each visual.
+  */
+struct RegisteredVisual
+{
+  Property::Index index;
+  Toolkit::Visual::Base visual;
+  bool enabled : 1;
+  bool pending : 1;
+
+  RegisteredVisual( Property::Index aIndex, Toolkit::Visual::Base &aVisual, bool aEnabled, bool aPendingReplacement )
+  : index(aIndex), visual(aVisual), enabled(aEnabled), pending( aPendingReplacement )
+  {
+  }
+};
+
+typedef Dali::OwnerContainer< RegisteredVisual* > RegisteredVisualContainer;
+
+
+/**
+ * @brief Holds the Implementation for the internal control class
+ */
+class Control::Impl : public ConnectionTracker, public Visual::EventObserver
+{
+
+public:
+
+  /**
+   * @brief Retrieves the implementation of the internal control class.
+   * @param[in] internalControl A ref to the control whose internal implementation is required
+   * @return The internal implementation
+   */
+  static Control::Impl& Get( Internal::Control& internalControl );
+
+  /**
+   * @copydoc Get( Internal::Control& )
+   */
+  static const Control::Impl& Get( const Internal::Control& internalControl );
+
+  /**
+   * @brief Constructor.
+   * @param[in] controlImpl The control which owns this implementation
+   */
+  Impl( Control& controlImpl );
+
+  /**
+   * @brief Destructor.
+   */
+  ~Impl();
+
+  /**
+   * @brief Called when a pinch is detected.
+   * @param[in] actor The actor the pinch occurred on
+   * @param[in] pinch The pinch gesture details
+   */
+  void PinchDetected(Actor actor, const PinchGesture& pinch);
+
+  /**
+   * @brief Called when a pan is detected.
+   * @param[in] actor The actor the pan occurred on
+   * @param[in] pinch The pan gesture details
+   */
+  void PanDetected(Actor actor, const PanGesture& pan);
+
+  /**
+   * @brief Called when a tap is detected.
+   * @param[in] actor The actor the tap occurred on
+   * @param[in] pinch The tap gesture details
+   */
+  void TapDetected(Actor actor, const TapGesture& tap);
+
+  /**
+   * @brief Called when a long-press is detected.
+   * @param[in] actor The actor the long-press occurred on
+   * @param[in] pinch The long-press gesture details
+   */
+  void LongPressDetected(Actor actor, const LongPressGesture& longPress);
+
+  /**
+   * @brief Called when a resource is ready.
+   * @param[in] object The visual whose resources are ready
+   * @note Overriding method in Visual::EventObserver.
+   */
+  virtual void ResourceReady( Visual::Base& object ) override;
+
+  /**
+   * @brief Called when an event occurs.
+   * @param[in] object The visual whose events occur
+   * @param[in] signalId The signal to emit. See Visual to find supported signals
+   * @note Overriding method in Visual::EventObserver.
+   */
+  virtual void NotifyVisualEvent( Visual::Base& object, Property::Index signalId ) override;
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, int depthIndex );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::RegisterVisual()
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, bool enabled, int depthIndex );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::UnregisterVisual()
+   */
+  void UnregisterVisual( Property::Index index );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::GetVisual()
+   */
+  Toolkit::Visual::Base GetVisual( Property::Index index ) const;
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::EnableVisual()
+   */
+  void EnableVisual( Property::Index index, bool enable );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::IsVisualEnabled()
+   */
+  bool IsVisualEnabled( Property::Index index ) const;
+
+  /**
+   * @brief Stops observing the given visual.
+   * @param[in] visual The visual to stop observing
+   */
+  void StopObservingVisual( Toolkit::Visual::Base& visual );
+
+  /**
+   * @brief Starts observing the given visual.
+   * @param[in] visual The visual to start observing
+   */
+  void StartObservingVisual( Toolkit::Visual::Base& visual);
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::GetVisualResourceStatus()
+   */
+  Toolkit::Visual::ResourceStatus GetVisualResourceStatus( Property::Index index ) const;
+
+  /**
+   * @param[in,out] animation Handle to existing animation, or an empty handle that
+   * can be set to a New animation if createAnimation is true
+   * @param[in] transitionData The transition data describing the animation
+   * @param[in] createAnimation True if the animation should be created
+   */
+  void AddTransitions( Dali::Animation& animation,
+                       const Toolkit::TransitionData& transitionData,
+                       bool createAnimation = false );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::CreateTransition()
+   */
+  Dali::Animation CreateTransition( const Toolkit::TransitionData& transitionData );
+
+  /**
+   * @copydoc Dali::Toolkit::DevelControl::DoAction()
+   */
+  void DoAction( Dali::Property::Index visualIndex, Dali::Property::Index actionId, const Dali::Property::Value attributes );
+
+  /**
+   * @brief Function used to set control properties.
+   * @param[in] object The object whose property to set
+   * @param[in] index The index of the property to set
+   * @param[in] value The value of the property to set
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Function used to retrieve the value of control properties.
+   * @param[in] object The object whose property to get
+   * @param[in] index The index of the property to get
+   * @return The value of the property
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @brief Sets the state of the control.
+   * @param[in] newState The state to set
+   * @param[in] withTransitions Whether to show a transition when changing to the new state
+   */
+  void SetState( DevelControl::State newState, bool withTransitions=true );
+
+  /**
+   * @brief Sets the sub-state of the control.
+   * @param[in] newState The sub-state to set
+   * @param[in] withTransitions Whether to show a transition when changing to the new sub-state
+   */
+  void SetSubState( const std::string& subStateName, bool withTransitions=true );
+
+  /**
+   * @brief Replaces visuals and properties from the old state to the new state.
+   * @param[in] oldState The old state
+   * @param[in] newState The new state
+   * @param[in] subState The current sub state
+   */
+  void ReplaceStateVisualsAndProperties( const StylePtr oldState, const StylePtr newState, const std::string& subState );
+
+  /**
+   * @brief Removes a visual from the control's container.
+   * @param[in] visuals The container of visuals
+   * @param[in] visualName The name of the visual to remove
+   */
+  void RemoveVisual( RegisteredVisualContainer& visuals, const std::string& visualName );
+
+  /**
+   * @brief Removes several visuals from the control's container.
+   * @param[in] visuals The container of visuals
+   * @param[in] removeVisuals The visuals to remove
+   */
+  void RemoveVisuals( RegisteredVisualContainer& visuals, DictionaryKeys& removeVisuals );
+
+  /**
+   * @brief Copies the visual properties that are specific to the control instance into the instancedProperties container.
+   * @param[in] visuals The control's visual container
+   * @param[out] instancedProperties The instanced properties are added to this container
+   */
+  void CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary<Property::Map>& instancedProperties );
+
+  /**
+   * @brief On state change, ensures visuals are moved or created appropriately.
+   *
+   * Go through the list of visuals that are common to both states.
+   * If they are different types, or are both image types with different
+   * URLs, then the existing visual needs moving and the new visual needs creating
+   *
+   * @param[in] stateVisualsToChange The visuals to change
+   * @param[in] instancedProperties The instanced properties @see CopyInstancedProperties
+   */
+  void RecreateChangedVisuals( Dictionary<Property::Map>& stateVisualsToChange, Dictionary<Property::Map>& instancedProperties );
+
+  /**
+   * @brief Whether the resource is ready
+   * @return True if the resource is read.
+   */
+  bool IsResourceReady() const;
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   */
+  void OnStageDisconnection();
+
+  /**
+   * @brief Sets the margin.
+   * @param[in] margin Margin is a collections of extent ( start, end, top, bottom )
+   */
+  void SetMargin( Extents margin );
+
+  /**
+   * @brief Returns the value of margin
+   * @return The value of margin
+   */
+  Extents GetMargin() const;
+
+  /**
+   * @brief Sets the padding.
+   * @param[in] padding Padding is a collections of extent ( start, end, top, bottom ).
+   */
+  void SetPadding( Extents padding );
+
+  /**
+   * @brief Returns the value of padding
+   * @return The value of padding
+   */
+  Extents GetPadding() const;
+
+  /**
+   * @brief Set the input method context.
+   * @param[in] inputMethodContext The input method context.
+   */
+  void SetInputMethodContext( InputMethodContext& inputMethodContext );
+
+  /**
+   * @brief Filter an key event.
+   * @param[in] event The key to be filtered.
+   * @return True if the key handled, otherwise false.
+   */
+  bool FilterKeyEvent( const KeyEvent& event );
+
+  /**
+   * @copydoc DevelControl::VisualEventSignal()
+   */
+  DevelControl::VisualEventSignalType& VisualEventSignal();
+
+  /**
+   * @brief Sets the shadow with a property map.
+   * @param[in] map The shadow property map
+   */
+  void SetShadow(const Property::Map& map);
+
+  /**
+   * @brief Clear the shadow.
+   */
+  void ClearShadow();
+
+private:
+
+  /**
+   * Used as an alternative to boolean so that it is obvious whether a visual is enabled/disabled.
+   */
+  struct VisualState
+  {
+    enum Type
+    {
+      DISABLED = 0, ///< Visual disabled.
+      ENABLED = 1   ///< Visual enabled.
+    };
+  };
+
+  /**
+   * Used as an alternative to boolean so that it is obvious whether a visual's depth value has been set or not by the caller.
+   */
+  struct DepthIndexValue
+  {
+    enum Type
+    {
+      NOT_SET = 0, ///< Visual depth value not set by caller.
+      SET = 1      ///< Visual depth value set by caller.
+    };
+  };
+
+  /**
+   * @brief Adds the visual to the list of registered visuals.
+   * @param[in] index The Property index of the visual, used to reference visual
+   * @param[in,out] visual The visual to register, which can be altered in this function
+   * @param[in] enabled false if derived class wants to control when visual is set on stage
+   * @param[in] depthIndexValueSet Set to true if the depthIndex has actually been set manually
+   * @param[in] depthIndex The visual's depth-index is set to this
+   *
+   * @note Registering a visual with an index that already has a registered visual will replace it. The replacement will
+   *       occur once the replacement visual is ready (loaded).
+   */
+  void RegisterVisual( Property::Index index, Toolkit::Visual::Base& visual, VisualState::Type enabled, DepthIndexValue::Type depthIndexValueSet, int depthIndex = 0 );
+
+public:
+
+  Control& mControlImpl;
+  DevelControl::State mState;
+  std::string mSubStateName;
+
+  int mLeftFocusableActorId;       ///< Actor ID of Left focusable control.
+  int mRightFocusableActorId;      ///< Actor ID of Right focusable control.
+  int mUpFocusableActorId;         ///< Actor ID of Up focusable control.
+  int mDownFocusableActorId;       ///< Actor ID of Down focusable control.
+
+  RegisteredVisualContainer mVisuals;     ///< Stores visuals needed by the control, non trivial type so std::vector used.
+  std::string mStyleName;
+  Vector4 mBackgroundColor;               ///< The color of the background visual
+  Vector3* mStartingPinchScale;           ///< The scale when a pinch gesture starts, TODO: consider removing this
+  Extents mMargin;                        ///< The margin values
+  Extents mPadding;                       ///< The padding values
+  Toolkit::Control::KeyEventSignalType mKeyEventSignal;
+  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusGainedSignal;
+  Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusLostSignal;
+  Toolkit::Control::ResourceReadySignalType mResourceReadySignal;
+  DevelControl::VisualEventSignalType mVisualEventSignal;
+
+  // Gesture Detection
+  PinchGestureDetector mPinchGestureDetector;
+  PanGestureDetector mPanGestureDetector;
+  TapGestureDetector mTapGestureDetector;
+  LongPressGestureDetector mLongPressGestureDetector;
+
+  // Tooltip
+  TooltipPtr mTooltip;
+
+  InputMethodContext mInputMethodContext;
+
+  ControlBehaviour mFlags : CONTROL_BEHAVIOUR_FLAG_COUNT;    ///< Flags passed in from constructor.
+  bool mIsKeyboardNavigationSupported :1;  ///< Stores whether keyboard navigation is supported by the control.
+  bool mIsKeyboardFocusGroup :1;           ///< Stores whether the control is a focus group.
+
+  RegisteredVisualContainer mRemoveVisuals;         ///< List of visuals that are being replaced by another visual once ready
+
+
+  // Properties - these need to be members of Internal::Control::Impl as they access private methods/data of Internal::Control and Internal::Control::Impl.
+  static const PropertyRegistration PROPERTY_1;
+  static const PropertyRegistration PROPERTY_2;
+  static const PropertyRegistration PROPERTY_3;
+  static const PropertyRegistration PROPERTY_4;
+  static const PropertyRegistration PROPERTY_5;
+  static const PropertyRegistration PROPERTY_6;
+  static const PropertyRegistration PROPERTY_7;
+  static const PropertyRegistration PROPERTY_8;
+  static const PropertyRegistration PROPERTY_9;
+  static const PropertyRegistration PROPERTY_10;
+  static const PropertyRegistration PROPERTY_11;
+  static const PropertyRegistration PROPERTY_12;
+  static const PropertyRegistration PROPERTY_13;
+  static const PropertyRegistration PROPERTY_14;
+  static const PropertyRegistration PROPERTY_15;
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_DATA_IMPL_H
diff --git a/dali-toolkit/internal/controls/control/control-debug.cpp b/dali-toolkit/internal/controls/control/control-debug.cpp
new file mode 100644 (file)
index 0000000..a359dee
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2018 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/integration-api/debug.h>
+#include <dali/public-api/object/property.h>
+#include <dali/public-api/object/property-index-ranges.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+#include <dali-toolkit/internal/controls/control/control-debug.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <iostream>
+#include <algorithm>
+#include <functional>
+
+#if defined(DEBUG_ENABLED)
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class JsonWriter
+{
+public:
+  JsonWriter( Property::Value& value )
+  : mValue(value)
+  {
+  }
+
+  std::string ToString()
+  {
+    std::ostringstream stream;
+    ToStream( stream );
+    return stream.str();
+  }
+
+  void ToStream( std::ostream& stream )
+  {
+    switch( mValue.GetType() )
+    {
+      case Dali::Property::BOOLEAN:
+      {
+        auto value = mValue.Get<bool>();
+        stream << ((value)?"true":"false");
+        break;
+      }
+      case Dali::Property::FLOAT:
+      {
+        stream << mValue.Get<float>();
+        break;
+      }
+      case Dali::Property::INTEGER:
+      {
+        stream << mValue.Get<int>();
+        break;
+      }
+      case Dali::Property::VECTOR2:
+      {
+        auto vector = mValue.Get<Vector2>();
+        stream << "[" << vector.x << ", " << vector.y << "]";
+        break;
+      }
+      case Dali::Property::VECTOR3:
+      {
+        auto vector = mValue.Get<Vector3>();
+        stream << "[" << vector.x << ", " << vector.y << ", " << vector.z << "]";
+        break;
+      }
+      case Dali::Property::VECTOR4:
+      {
+        auto vector = mValue.Get<Vector4>();
+        stream << "[" << vector.x << ", " << vector.y << ", " << vector.z << ", " << vector.w << "]";
+        break;
+      }
+      case Dali::Property::MATRIX3:
+      {
+        auto matrix = mValue.Get<Matrix3>();
+        stream << "[";
+        for( int i=0; i<9; ++i )
+        {
+          if( i>0)
+            stream << ",";
+          stream << matrix.AsFloat()[i];
+        }
+        stream << "]";
+        break;
+      }
+      case Dali::Property::MATRIX:
+      {
+        auto matrix = mValue.Get<Matrix>();
+        stream << "[";
+        for( int i=0; i<16; ++i )
+        {
+          if( i>0)
+            stream << ",";
+          stream << matrix.AsFloat()[i];
+        }
+        stream << "]";
+        break;
+      }
+      case Dali::Property::RECTANGLE:
+      {
+        auto vector = mValue.Get<Rect<int> >();
+        stream << "[" << vector.x << ", " << vector.y << ", " << vector.width << ", " << vector.height << "]";
+        break;
+      }
+      case Dali::Property::ROTATION:
+      {
+        auto angleAxis = mValue.Get<AngleAxis>();
+        stream << "[ [ " << angleAxis.axis.x << ", " << angleAxis.axis.y << ", " << angleAxis.axis.z << "], "
+               << angleAxis.angle.radian << "]";
+        break;
+      }
+      case Dali::Property::STRING:
+      {
+        stream << '"' << mValue.Get<std::string>() << '"';
+        break;
+      }
+      case Dali::Property::ARRAY:
+      {
+        auto array = mValue.GetArray();
+        stream << "[ ";
+        if( array )
+        {
+          for( Property::Array::SizeType i=0; i<array->Size(); ++i)
+          {
+            if( i>0)
+              stream << ", ";
+            auto outValue = JsonWriter( array->GetElementAt(i) );
+            stream << outValue.ToString();
+          }
+        }
+        stream << "]";
+        break;
+      }
+      case Dali::Property::MAP:
+      {
+        auto map = mValue.GetMap();
+        stream << "{ ";
+        if( map )
+        {
+          for( Property::Map::SizeType i=0; i<map->Count(); ++i)
+          {
+            if( i>0)
+              stream << ", ";
+            auto key = map->GetKeyAt( i );
+            auto outValue = JsonWriter( map->GetValue(i) );
+            stream << '\"' << key << "\":";
+            stream << outValue.ToString();
+          }
+        }
+        stream << "}";
+        break;
+      }
+      case Dali::Property::EXTENTS:
+      {
+        stream << mValue.Get<Extents>();
+        break;
+      }
+      case Dali::Property::NONE:
+      {
+        stream << "undefined type";
+        break;
+      }
+    }
+  }
+
+  Property::Value& mValue;
+};
+
+static std::ostream& operator<<( std::ostream& o, JsonWriter& value )
+{
+  value.ToStream(o);
+  return o;
+}
+
+
+std::ostream& operator<<( std::ostream& o, const RegisteredVisual& registeredVisual )
+{
+  o << "{\n" << "\"index\":" << registeredVisual.index << ",\n";
+  o << "\"enabled\":" << (registeredVisual.enabled?"true":"false") << ",\n";
+  o << "\"pending\":" << (registeredVisual.pending?"true":"false") << ",\n";
+
+  Property::Map map;
+  registeredVisual.visual.CreatePropertyMap( map );
+  o << "\"visual\": {\n\"name\":\"" << registeredVisual.visual.GetName() << "\",\n";
+  o << map << "}\n" << "\n}\n";
+  return o;
+}
+
+std::ostream& operator<<( std::ostream& o, const RegisteredVisualContainer& visualContainer )
+{
+  o<<"[\n";
+
+  bool first=true;
+  for( auto&& elem : visualContainer )
+  {
+    if(!first)
+    {
+      o << ",";
+    }
+    first = false;
+
+    o<<*elem<<"\n";
+  }
+  o<<"]\n";
+  return o;
+}
+
+std::ostream& DumpProperty( std::ostream& o, Property::Index index, Handle handle )
+{
+  auto propertyValue = handle.GetProperty( index );
+  auto jsonPropertyValue = JsonWriter(propertyValue);
+
+  o << "{\n";
+  o << "\"index\":" << index << ",\n";
+  o << "\"name\":\"" << handle.GetPropertyName( index ) << "\",\n";
+  o << "\"value\":" << jsonPropertyValue << "\n";
+  o << "}";
+  return o;
+}
+
+
+std::ostream& DumpPropertiesWithPredicate( std::ostream& o, Dali::Handle handle,
+                                           Property::IndexContainer& indices, std::function<bool(int)> predicate)
+{
+  bool first = true;
+  for( auto index : indices )
+  {
+    if( predicate( index ) )
+    {
+      if( !first )
+      {
+        o << ",";
+      }
+      o << std::endl;
+      first = false;
+      DumpProperty( o, index, handle );
+    }
+  }
+  return o;
+}
+
+std::ostream& DumpProperties( std::ostream& o, Handle handle )
+{
+  Property::IndexContainer indices;
+  handle.GetPropertyIndices( indices );
+
+  auto childPropertiesP = [](int index) -> bool
+    {
+      return CHILD_PROPERTY_REGISTRATION_START_INDEX <= index && index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX;
+    };
+  auto propertiesP = [](int index) -> bool
+    {
+      return !(CHILD_PROPERTY_REGISTRATION_START_INDEX <= index && index <= CHILD_PROPERTY_REGISTRATION_MAX_INDEX);
+    };
+
+  o << "\"childProperties\":[\n" ;
+  DumpPropertiesWithPredicate( o, handle, indices, childPropertiesP );
+  o << std::endl << "]," << std::endl;
+
+  o << "\"Properties\":[\n" ;
+  DumpPropertiesWithPredicate( o, handle, indices, propertiesP );
+  o << std::endl << "]" << std::endl;
+
+  return o;
+}
+
+std::string DumpControl( const Internal::Control& control )
+{
+  auto& controlData = Internal::Control::Impl::Get( control );
+
+  std::ostringstream oss;
+  oss << "{\n  ";
+  const std::string& name = control.Self().GetName();
+  if( ! name.empty() )
+  {
+    oss << "\"name\":\"" << name << "\",\n";
+  }
+  oss << "\"id\":\"" << control.Self().GetId() << "\",\n";
+  oss << "\"registeredVisuals\":\n" << controlData.mVisuals << ",\n";
+  oss << "\"removeVisuals\":\n" << controlData.mRemoveVisuals << ",\n";
+  oss << "\"rendererCount\":" << control.Self().GetRendererCount() << ",\n";
+  oss << "\"properties\":\n{\n";
+  DumpProperties( oss, control.Self() ) << "}\n";
+  oss << "}\n";
+  return oss.str();
+}
+
+std::string DumpActor( Actor actor )
+{
+  std::ostringstream oss;
+  oss << "{\n  ";
+  const std::string& name = actor.GetName();
+  if( ! name.empty() )
+  {
+    oss << "\"name\":\"" << name << "\",\n";
+  }
+  oss << "\"id\":\"" << actor.GetId() << "\",\n";
+  oss << "\"rendererCount\":" << actor.GetRendererCount() << ",\n";
+  oss << "\"properties\":\n{\n";
+  Toolkit::Internal::DumpProperties( oss, actor ) << "}\n";
+  oss << "}\n";
+  return oss.str();
+}
+
+void DumpControlHierarchy( std::ostream& o, Actor actor )
+{
+  auto control = Toolkit::Control::DownCast( actor );
+  o << "{\n";
+  if( control )
+  {
+    o << "\"Control\":" << DumpControl( Toolkit::Internal::GetImplementation( control ) );
+  }
+  else
+  {
+    o << "\"Actor\":" << DumpActor( actor );
+  }
+  o << ",\n\"children\":[\n";
+  bool first=true;
+  for( auto count=actor.GetChildCount(), i=0u; i<count; ++i )
+  {
+    if( !first )
+    {
+      o << ",";
+    }
+    first = false;
+    o << "\n";
+    DumpControlHierarchy( o, actor.GetChildAt( i ) );
+  }
+  o << "]}\n";
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
diff --git a/dali-toolkit/internal/controls/control/control-debug.h b/dali-toolkit/internal/controls/control/control-debug.h
new file mode 100644 (file)
index 0000000..c889ff4
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CONTROL_DEBUG_H
+#define DALI_TOOLKIT_INTERNAL_CONTROL_DEBUG_H
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#if defined(DEBUG_ENABLED)
+
+#include <dali/public-api/object/handle.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <iostream>
+#include <string>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Convert properties of handle into JSON output, separated into 'normal' and 'child' properties.
+ * @param[in] ouputStream the output stream to write to
+ * @param[in] handle The handle of the object from which to retrieve properties
+ * @return The output stream
+ */
+std::ostream& DumpProperties( std::ostream& outputStream, Handle handle );
+
+/**
+ * Dumps control internals, visuals and properties to a string in JSON format
+ */
+std::string DumpControl( const Internal::Control& control );
+
+/**
+ * Dumps actor internals and properties to a string in JSON format
+ */
+std::string DumpActor( Actor actor );
+
+/**
+ * Dumps actor hierarchy from a given root, but expands Control output to encompass Control internals.
+ * Formats the output in JSON.
+ * @param[in] ouputStream the output stream to write to
+ * @param[in] root The root actor
+ */
+void DumpControlHierarchy( std::ostream& outputStream, Actor rootActor );
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif
+
+#endif //DALI_TOOLKIT_INTERNAL_CONTROL_DEBUG_H
diff --git a/dali-toolkit/internal/controls/control/control-renderers.cpp b/dali-toolkit/internal/controls/control/control-renderers.cpp
new file mode 100644 (file)
index 0000000..052d822
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+#define DALI_COMPOSE_SHADER(STR) #STR
+
+const char * const BASIC_VERTEX_SOURCE = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition * uSize.xy, 0.0, 1.0);\n
+    vTexCoord = aPosition + vec2(0.5);
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+const char * const BASIC_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform vec4 uColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D(sTexture, vTexCoord);\n
+    gl_FragColor *= uColor;
+  }\n
+);
+
+Geometry CreateGridGeometry( Uint16Pair gridSize )
+{
+  uint16_t gridWidth = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector< Vector2 > vertices;
+  vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
+
+  for( int y = 0; y < gridHeight + 1; ++y )
+  {
+    for( int x = 0; x < gridWidth + 1; ++x )
+    {
+      vertices.PushBack( Vector2( (float)x/gridWidth - 0.5f, (float)y/gridHeight  - 0.5f) );
+    }
+  }
+
+  // Create indices
+  Vector< unsigned short > indices;
+  indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
+
+  for( unsigned int row = 0u; row < gridHeight; ++row )
+  {
+    unsigned int rowStartIndex = row*(gridWidth+1u);
+    unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
+
+    if( row != 0u ) // degenerate index on non-first row
+    {
+      indices.PushBack( rowStartIndex );
+    }
+
+    for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
+    {
+      indices.PushBack( rowStartIndex + column);
+      indices.PushBack( nextRowStartIndex + column);
+    }
+
+    if( row != gridHeight-1u ) // degenerate index on non-last row
+    {
+      indices.PushBack( nextRowStartIndex + gridWidth );
+    }
+  }
+
+  Property::Map vertexFormat;
+  vertexFormat[ "aPosition" ] = Property::VECTOR2;
+  PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
+  if( vertices.Size() > 0 )
+  {
+    vertexPropertyBuffer.SetData( &vertices[ 0 ], vertices.Size() );
+  }
+
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexPropertyBuffer );
+  if( indices.Size() > 0 )
+  {
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+  }
+
+  geometry.SetType( Geometry::TRIANGLE_STRIP );
+
+  return geometry;
+}
+
+Dali::Renderer CreateRenderer( const char* vertexSrc, const char* fragmentSrc )
+{
+  Dali::Shader shader = Dali::Shader::New( vertexSrc, fragmentSrc );
+
+  Dali::Geometry texturedQuadGeometry = Dali::Geometry::New();
+
+  struct VertexPosition { Dali::Vector2 position; };
+  struct VertexTexture { Dali::Vector2 texture; };
+
+  VertexPosition positionArray[] =
+  {
+    { Dali::Vector2( -0.5f, -0.5f ) },
+    { Dali::Vector2(  0.5f, -0.5f ) },
+    { Dali::Vector2( -0.5f,  0.5f ) },
+    { Dali::Vector2(  0.5f,  0.5f ) }
+  };
+  uint32_t numberOfVertices = sizeof(positionArray)/sizeof(VertexPosition);
+
+  Dali::Property::Map positionVertexFormat;
+  positionVertexFormat["aPosition"] = Dali::Property::VECTOR2;
+  Dali::PropertyBuffer positionVertices = Dali::PropertyBuffer::New( positionVertexFormat );
+  positionVertices.SetData( positionArray, numberOfVertices );
+  texturedQuadGeometry.AddVertexBuffer( positionVertices );
+
+  const uint16_t indices[] = { 0, 3, 1, 0, 2, 3 };
+  texturedQuadGeometry.SetIndexBuffer ( &indices[0], sizeof( indices )/ sizeof( indices[0] ) );
+
+  Dali::Renderer renderer = Dali::Renderer::New( texturedQuadGeometry, shader );
+
+  Dali::TextureSet textureSet = Dali::TextureSet::New();
+  renderer.SetTextures( textureSet );
+
+  return renderer;
+}
+
+Dali::Renderer CreateRenderer( const char* vertexSrc, const char* fragmentSrc, Dali::Shader::Hint::Value hints, Uint16Pair gridSize )
+{
+  Dali::Shader shader = Dali::Shader::New( vertexSrc, fragmentSrc, hints );
+
+  Dali::Geometry gridGeometry = CreateGridGeometry( gridSize );
+
+  Dali::Renderer renderer = Dali::Renderer::New( gridGeometry, shader );
+
+  Dali::TextureSet textureSet = Dali::TextureSet::New();
+  renderer.SetTextures( textureSet );
+
+  return renderer;
+}
+
+void SetRendererTexture( Dali::Renderer renderer, Dali::Texture texture )
+{
+  if( renderer )
+  {
+    Dali::TextureSet textureSet = renderer.GetTextures();
+    textureSet.SetTexture( 0u, texture );
+  }
+}
+
+void SetRendererTexture( Dali::Renderer renderer, Dali::FrameBuffer frameBuffer )
+{
+  if( frameBuffer )
+  {
+    Dali::Texture texture = frameBuffer.GetColorTexture();
+    SetRendererTexture( renderer, texture );
+  }
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/control/control-renderers.h b/dali-toolkit/internal/controls/control/control-renderers.h
new file mode 100644 (file)
index 0000000..320528c
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CONTROL_RENDERERS_H
+#define DALI_TOOLKIT_INTERNAL_CONTROL_RENDERERS_H
+
+/*
+ * Copyright (c) 2019 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/dali.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+extern const char* const BASIC_VERTEX_SOURCE;
+
+extern const char* const BASIC_FRAGMENT_SOURCE;
+
+/**
+ * Helper method for rendering an image with custom shader.
+ * @param[in] vertextSrc The custom vertex shader.
+ * @param[in] fragmentSrc The custom fragment shader.
+ * @return A newly created renderer.
+ */
+Dali::Renderer CreateRenderer( const char* vertexSrc, const char* fragmentSrc );
+
+/**
+ * Helper method for rendering an image with custom shader.
+ * @param[in] vertextSrc The custom vertex shader.
+ * @param[in] fragmentSrc The custom fragment shader.
+ * @param[in] gridSize The number of grid sub-divisions required.
+ * @return A newly created renderer.
+ */
+Dali::Renderer CreateRenderer( const char* vertexSrc, const char* fragmentSrc, Dali::Shader::Hint::Value hints, Dali::Uint16Pair gridSize );
+
+/**
+ * Helper method for setting the first texture passed to a renderer.
+ * @param[in] renderer The renderer using the texture.
+ * @param[in] texture The texture to set.
+ */
+void SetRendererTexture( Dali::Renderer renderer, Dali::Texture texture );
+
+/**
+ * Helper method for setting the first texture passed to a renderer.
+ * @param[in] renderer The renderer using the texture.
+ * @param[in] framebuffer A frame buffer color texture attached.
+ */
+void SetRendererTexture( Dali::Renderer renderer, Dali::FrameBuffer frameBuffer );
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CONTROL_RENDERERS_H
diff --git a/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp b/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp
new file mode 100644 (file)
index 0000000..0c34673
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2017 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 "effects-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
+#include <dali-toolkit/internal/filters/emboss-filter.h>
+#include <dali-toolkit/internal/filters/spread-filter.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+Dali::BaseHandle Create()
+{
+  return EffectsView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::EffectsView, Toolkit::Control, Create )
+DALI_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectSize", INTEGER, EFFECT_SIZE )
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, EffectsView, "effectOffset", VECTOR3, EFFECT_OFFSET )
+DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, EffectsView, "effectColor", Color::WHITE, EFFECT_COLOR )
+DALI_TYPE_REGISTRATION_END()
+
+const Pixel::Format EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT = Pixel::RGBA8888;
+const float         ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
+const Vector4       EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR( 0.0f, 0.0f, 0.0f, 0.0 );
+const bool          EFFECTS_VIEW_REFRESH_ON_DEMAND(false);
+
+#define DALI_COMPOSE_SHADER(STR) #STR
+
+const char* EFFECTS_VIEW_VERTEX_SOURCE = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec3 effectOffset;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    vertexPosition.xyz += effectOffset;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = aPosition + vec2(0.5);\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* EFFECTS_VIEW_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 effectColor;\n
+  \n
+  void main()\n
+  {\n
+     gl_FragColor = effectColor;\n
+     gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n
+  }\n
+);
+
+const float BLUR_KERNEL0[] = { 12.0f/16.0f,
+                               2.0f/16.0f, 2.0f/16.0f };
+
+const float BLUR_KERNEL1[] = { 8.0f/16.0f,
+                               4.0f/16.0f, 4.0f/16.0f };
+
+const float BLUR_KERNEL2[] = { 6.0f/16.0f,
+                               2.5f/16.0f, 2.5f/16.0f,
+                               1.5f/16.0f, 1.5f/16.0f,
+                               1.0f/16.0f, 1.0f/16.0f };
+
+const float BLUR_KERNEL3[] = { 4.0f/16.0f,
+                               3.0f/16.0f, 2.0f/16.0f,
+                               2.0f/16.0f, 2.0f/16.0f,
+                               1.0f/16.0f, 1.0f/16.0f };
+
+const float BLUR_KERNEL4[] = { 3.0f/16.0f,
+                               2.5f/16.0f,  2.5f/16.0f,
+                               1.75f/16.0f, 1.75f/16.0f,
+                               1.25f/16.0f, 1.25f/16.0f,
+                               1.0f/16.0f,  1.0f/16.0f };
+
+} // namespace
+
+Toolkit::EffectsView EffectsView::New()
+{
+  EffectsView* effectsView = new EffectsView;
+
+  Toolkit::EffectsView handle = Toolkit::EffectsView( *effectsView );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  effectsView->Initialize();
+
+  return handle;
+}
+
+EffectsView::EffectsView()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mChildrenRoot(Actor::New()),
+  mBackgroundColor( EFFECTS_VIEW_DEFAULT_BACKGROUND_COLOR ),
+  mTargetSize( Vector2::ZERO ),
+  mLastSize( Vector2::ZERO ),
+  mEffectSize(0),
+  mEffectType( Toolkit::EffectsView::INVALID_TYPE ),
+  mPixelFormat( EFFECTS_VIEW_DEFAULT_PIXEL_FORMAT ),
+  mEnabled( false ),
+  mRefreshOnDemand( EFFECTS_VIEW_REFRESH_ON_DEMAND )
+{
+}
+
+EffectsView::~EffectsView()
+{
+  RemoveFilters();
+}
+
+void EffectsView::SetType( Toolkit::EffectsView::EffectType type )
+{
+  if( mEffectType != type )
+  {
+    RemoveFilters();
+
+    Actor self = Self();
+
+    switch( type )
+    {
+      case Toolkit::EffectsView::DROP_SHADOW:
+      {
+        mFilters.PushBack( new SpreadFilter );
+        mFilters.PushBack( new BlurTwoPassFilter );
+        break;
+      }
+      case Toolkit::EffectsView::EMBOSS:
+      {
+        mFilters.PushBack( new SpreadFilter );
+        mFilters.PushBack( new EmbossFilter );
+        mFilters.PushBack( new BlurTwoPassFilter );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+
+    mEffectType = type;
+  }
+}
+
+Toolkit::EffectsView::EffectType EffectsView::GetType() const
+{
+  return mEffectType;
+}
+
+void EffectsView::Enable()
+{
+  // make sure resources are allocated and start the render tasks processing
+  AllocateResources();
+  CreateRenderTasks();
+  mEnabled = true;
+}
+
+void EffectsView::Disable()
+{
+  // stop render tasks processing
+  RemoveRenderTasks();
+  mLastSize = Vector2::ZERO; // Ensure resources are reallocated on subsequent enable
+  mEnabled = false;
+}
+
+void EffectsView::Refresh()
+{
+  RefreshRenderTasks();
+}
+
+void EffectsView::SetRefreshOnDemand( bool onDemand )
+{
+  mRefreshOnDemand = onDemand;
+
+  RefreshRenderTasks();
+}
+
+void EffectsView::SetPixelFormat( Pixel::Format pixelFormat )
+{
+  mPixelFormat = pixelFormat;
+}
+
+void EffectsView::SetBackgroundColor( const Vector4& color )
+{
+  mBackgroundColor = color;
+}
+
+Vector4 EffectsView::GetBackgroundColor() const
+{
+  return mBackgroundColor;
+}
+
+void EffectsView::SetEffectSize( int effectSize )
+{
+  mEffectSize = effectSize;
+
+  if( mEnabled )
+  {
+    const size_t numFilters( mFilters.Size() );
+    for( size_t i = 0; i < numFilters; ++i )
+    {
+      mFilters[i]->Disable();
+    }
+
+    SetupFilters();
+
+    for( size_t i = 0; i < numFilters; ++i )
+    {
+      mFilters[i]->Enable();
+    }
+  }
+}
+
+int EffectsView::GetEffectSize()
+{
+  return mEffectSize;
+}
+
+// From Control
+void EffectsView::OnInitialize()
+{
+  CustomActor self = Self();
+  mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
+  self.Add( mChildrenRoot );
+}
+
+void EffectsView::OnSizeSet(const Vector3& targetSize)
+{
+  mTargetSize = Vector2(targetSize);
+
+  // if we are already on stage, need to update render target sizes now to reflect the new size of this actor
+  if(mEnabled)
+  {
+    if( mLastSize != Vector2::ZERO )
+    {
+      Disable();
+    }
+    Enable();
+  }
+
+  mChildrenRoot.SetSize( targetSize );
+
+  Control::OnSizeSet( targetSize );
+}
+
+void EffectsView::OnStageConnection( int depth )
+{
+  Actor self( Self() );
+
+  // Create renderers
+  mRendererPostFilter = CreateRenderer( EFFECTS_VIEW_VERTEX_SOURCE, EFFECTS_VIEW_FRAGMENT_SOURCE );
+  mRendererPostFilter.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
+  self.AddRenderer( mRendererPostFilter );
+
+  mRendererForChildren = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
+  mRendererForChildren.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + 1 );
+  self.AddRenderer( mRendererForChildren );
+
+  Enable();
+
+  Control::OnStageConnection( depth );
+}
+
+void EffectsView::OnStageDisconnection()
+{
+  Actor self( Self() );
+
+  Disable();
+
+  const size_t numFilters( mFilters.Size() );
+  for( size_t i = 0; i < numFilters; ++i )
+  {
+    mFilters[i]->Disable();
+  }
+
+  // Remove renderers
+  self.RemoveRenderer( mRendererForChildren );
+  mRendererForChildren.Reset();
+
+  self.RemoveRenderer( mRendererPostFilter );
+  mRendererPostFilter.Reset();
+
+  Control::OnStageDisconnection();
+}
+
+void EffectsView::OnChildAdd( Actor& child )
+{
+  if( child != mChildrenRoot && child != mCameraForChildren )
+  {
+    mChildrenRoot.Add( child );
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void EffectsView::OnChildRemove( Actor& child )
+{
+  mChildrenRoot.Remove( child );
+
+  Control::OnChildRemove( child );
+}
+
+void EffectsView::SetupFilters()
+{
+  switch( mEffectType )
+  {
+    case Toolkit::EffectsView::DROP_SHADOW:
+    {
+      SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
+      spreadFilter->SetInputTexture( mFrameBufferForChildren.GetColorTexture() );
+      spreadFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
+      spreadFilter->SetRootActor( mChildrenRoot );
+      spreadFilter->SetBackgroundColor( mBackgroundColor );
+      spreadFilter->SetPixelFormat( mPixelFormat );
+      spreadFilter->SetSize( mTargetSize );
+      spreadFilter->SetSpread( mEffectSize );
+
+      BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[1] );
+      blurFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
+      blurFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
+      blurFilter->SetRootActor( mChildrenRoot );
+      blurFilter->SetBackgroundColor( mBackgroundColor );
+      blurFilter->SetPixelFormat( mPixelFormat );
+      blurFilter->SetSize( mTargetSize );
+
+      const float* kernel(NULL);
+      size_t kernelSize(0);
+      switch( mEffectSize )
+      {
+        case 4:  {  kernel = BLUR_KERNEL4; kernelSize = sizeof(BLUR_KERNEL4)/sizeof(BLUR_KERNEL4[0]); break; }
+        case 3:  {  kernel = BLUR_KERNEL3; kernelSize = sizeof(BLUR_KERNEL3)/sizeof(BLUR_KERNEL3[0]); break; }
+        case 2:  {  kernel = BLUR_KERNEL2; kernelSize = sizeof(BLUR_KERNEL2)/sizeof(BLUR_KERNEL2[0]); break; }
+        case 1:  {  kernel = BLUR_KERNEL1; kernelSize = sizeof(BLUR_KERNEL1)/sizeof(BLUR_KERNEL1[0]); break; }
+        case 0:
+        default: {  kernel = BLUR_KERNEL0; kernelSize = sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]); break; }
+      }
+      blurFilter->CreateKernel( kernel, kernelSize );
+      break;
+    }
+    case Toolkit::EffectsView::EMBOSS:
+    {
+      SpreadFilter* spreadFilter = static_cast< SpreadFilter* >( mFilters[0] );
+      spreadFilter->SetInputTexture( mFrameBufferForChildren.GetColorTexture() );
+      spreadFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
+      spreadFilter->SetRootActor( mChildrenRoot );
+      spreadFilter->SetBackgroundColor( mBackgroundColor );
+      spreadFilter->SetPixelFormat( Pixel::RGBA8888 );
+      spreadFilter->SetSize( mTargetSize );
+      spreadFilter->SetSpread( mEffectSize );
+
+      EmbossFilter* embossFilter = static_cast< EmbossFilter* >( mFilters[1] );
+      embossFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
+      embossFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
+      embossFilter->SetRootActor( mChildrenRoot );
+      embossFilter->SetBackgroundColor( mBackgroundColor );
+      embossFilter->SetPixelFormat( Pixel::RGBA8888 );
+      embossFilter->SetSize( mTargetSize );
+
+      BlurTwoPassFilter* blurFilter = static_cast< BlurTwoPassFilter* >( mFilters[2] );
+      blurFilter->SetInputTexture( mFrameBufferPostFilter.GetColorTexture() );
+      blurFilter->SetOutputFrameBuffer( mFrameBufferPostFilter );
+      blurFilter->SetRootActor( mChildrenRoot );
+      blurFilter->SetBackgroundColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0 ) );
+      blurFilter->SetPixelFormat( Pixel::RGBA8888 );
+      blurFilter->SetSize( mTargetSize );
+      blurFilter->CreateKernel( BLUR_KERNEL0, sizeof(BLUR_KERNEL0)/sizeof(BLUR_KERNEL0[0]) );
+
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+void EffectsView::AllocateResources()
+{
+  if(mTargetSize != mLastSize)
+  {
+    mLastSize = mTargetSize;
+    SetupCameras();
+
+    Actor self( Self() );
+
+    mFrameBufferForChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+    Texture textureForChildren = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+    mFrameBufferForChildren.AttachColorTexture( textureForChildren );
+
+    SetRendererTexture( mRendererForChildren, textureForChildren );
+
+    mFrameBufferPostFilter = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+    Texture texturePostFilter = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+    mFrameBufferPostFilter.AttachColorTexture( texturePostFilter );
+
+    SetRendererTexture( mRendererPostFilter, texturePostFilter );
+
+    SetupFilters();
+  }
+}
+
+void EffectsView::SetupCameras()
+{
+  if( !mCameraForChildren )
+  {
+    // Create a camera for the children render, corresponding to its render target size
+    mCameraForChildren = CameraActor::New(mTargetSize);
+    mCameraForChildren.SetParentOrigin(ParentOrigin::CENTER);
+    mCameraForChildren.SetInvertYAxis( true );
+    Self().Add( mCameraForChildren );
+  }
+  else
+  {
+    // place the camera for the children render, corresponding to its render target size
+    const float cameraPosScale( 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f) );
+    mCameraForChildren.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+    mCameraForChildren.SetNearClippingPlane(1.0f);
+    mCameraForChildren.SetAspectRatio(mTargetSize.width / mTargetSize.height);
+    mCameraForChildren.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+    mCameraForChildren.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosScale);
+    mCameraForChildren.SetZ( mTargetSize.height * cameraPosScale );
+  }
+}
+
+void EffectsView::CreateRenderTasks()
+{
+  if( mTargetSize == Vector2::ZERO )
+  {
+    return;
+  }
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // create render task to render our child actors to offscreen buffer
+  mRenderTaskForChildren = taskList.CreateTask();
+  mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForChildren.SetSourceActor( mChildrenRoot );
+  mRenderTaskForChildren.SetExclusive(true);
+  mRenderTaskForChildren.SetInputEnabled( false );
+  mRenderTaskForChildren.SetClearColor( mBackgroundColor );
+  mRenderTaskForChildren.SetClearEnabled( true );
+  mRenderTaskForChildren.SetFrameBuffer( mFrameBufferForChildren );
+  mRenderTaskForChildren.SetCameraActor(mCameraForChildren); // use camera that covers render target exactly
+
+  // Enable image filters
+  const size_t numFilters( mFilters.Size() );
+  for( size_t i = 0; i < numFilters; ++i )
+  {
+    mFilters[i]->Enable();
+  }
+}
+
+void EffectsView::RemoveRenderTasks()
+{
+  if( mTargetSize == Vector2::ZERO )
+  {
+    return;
+  }
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  taskList.RemoveTask(mRenderTaskForChildren);
+
+  const size_t numFilters( mFilters.Size() );
+  for( size_t i = 0; i < numFilters; ++i )
+  {
+    mFilters[i]->Disable();
+  }
+}
+
+void EffectsView::RefreshRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  if( mRenderTaskForChildren )
+  {
+    mRenderTaskForChildren.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+
+  const size_t numFilters( mFilters.Size() );
+  for( size_t i = 0; i < numFilters; ++i )
+  {
+    mFilters[i]->Refresh();
+  }
+}
+
+void EffectsView::RemoveFilters()
+{
+  const size_t numFilters( mFilters.Size() );
+  for( size_t i = 0; i < numFilters; ++i )
+  {
+    delete mFilters[i];
+  }
+  mFilters.Release();
+}
+
+void EffectsView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::EffectsView effectsView = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
+
+  if ( effectsView )
+  {
+    switch ( index )
+    {
+      case Toolkit::EffectsView::Property::EFFECT_SIZE:
+      {
+        int effectSize;
+        if( value.Get( effectSize ) )
+        {
+          GetImpl( effectsView ).SetEffectSize( effectSize );
+        }
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+Property::Value EffectsView::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::EffectsView imageview = Toolkit::EffectsView::DownCast( Dali::BaseHandle( object ) );
+
+  if ( imageview )
+  {
+    EffectsView& impl = GetImpl( imageview );
+    switch ( propertyIndex )
+    {
+      case Toolkit::EffectsView::Property::EFFECT_SIZE:
+      {
+         value = impl.GetEffectSize();
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/effects-view/effects-view-impl.h b/dali-toolkit/internal/controls/effects-view/effects-view-impl.h
new file mode 100644 (file)
index 0000000..0703f63
--- /dev/null
@@ -0,0 +1,269 @@
+#ifndef DALI_TOOLKIT_INTERNAL_EFFECTS_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_EFFECTS_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/effects-view/effects-view.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class GaussianBlurView;
+class ImageFilter;
+
+/**
+ * EffectsView implementation class
+ * @copydoc Dali::Toolkit::EffectsView
+ */
+class EffectsView : public Control
+{
+public:
+  /// @copydoc Dali::Toolkit::EffectsView New()
+  static Toolkit::EffectsView New();
+
+  /**
+   * Construct a new EffectsView.
+   * @copydoc Toolkit::EffectsView New()
+   */
+  EffectsView();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~EffectsView();
+
+public:
+
+  /// @copydoc Dali::Toolkit::EffectsView::SetType
+  void SetType( Toolkit::EffectsView::EffectType type );
+
+  /// @copydoc Dali::Toolkit::EffectsView::GetType
+  Toolkit::EffectsView::EffectType GetType() const;
+
+  /// @copydoc Dali::Toolkit::EffectsView::Refresh
+  void Refresh();
+
+  /// @copydoc Dali::Toolkit::EffectsView::SetRefreshOnDemand
+  void SetRefreshOnDemand( bool onDemand );
+
+  /// @copydoc Dali::Toolkit::EffectsView::SetPixelFormat
+  void SetPixelFormat( Pixel::Format pixelFormat );
+
+  /// @copydoc Dali::Toolkit::EffectsView::SetBackgroundColor(const Vector4&)
+  void SetBackgroundColor( const Vector4& color );
+
+  /// @copydoc Dali::Toolkit::GaussianBlurView::GetBackgroundColor
+  Vector4 GetBackgroundColor() const;
+
+  /**
+   * Set the effect size which decides the size of filter kernel.
+   * @param[in] effectSize The effect size.
+   */
+  void SetEffectSize( int effectSize );
+
+  /**
+   * Get the effect size.
+   * @return The effect size.
+   */
+  int GetEffectSize();
+
+  // Properties
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Internal::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet( const Vector3& targetSize )
+   */
+  virtual void OnSizeSet( const Vector3& targetSize );
+
+  /**
+   * @copydoc Toolkit::Internal::Control::OnStageConnection
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Toolkit::Internal::Control::OnStageDisconnection
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc Toolkit::Internal::Control::OnChildAdd
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Toolkit::Internal::Control::OnChildRemove
+   */
+  virtual void OnChildRemove( Actor& child );
+
+private:
+
+  /**
+   * Enable the effect when the control is set on stage
+   */
+  void Enable();
+
+  /**
+   * Disable the effect when the control is set off stage
+   */
+  void Disable();
+
+  /**
+   * Setup image filters
+   */
+  void SetupFilters();
+
+  /**
+   * Allocate resources
+   */
+  void AllocateResources();
+
+  /**
+   * Setup cameras
+   */
+  void SetupCameras();
+
+  /**
+   * Create render tasks for internal jobs
+   */
+  void CreateRenderTasks();
+
+  /**
+   * Remove render tasks
+   */
+  void RemoveRenderTasks();
+
+  /**
+   * Refresh render tasks
+   */
+  void RefreshRenderTasks();
+
+  /**
+   * Remove ImageFilters
+   */
+  void RemoveFilters();
+
+private:
+
+  // Undefined
+  EffectsView( const EffectsView& );
+
+  // Undefined
+  EffectsView& operator = ( const EffectsView& );
+
+private: // attributes/properties
+
+  /////////////////////////////////////////////////////////////
+  // for rendering all user added children to offscreen target
+  FrameBuffer           mFrameBufferForChildren;
+  Renderer              mRendererForChildren;
+  RenderTask            mRenderTaskForChildren;
+  CameraActor           mCameraForChildren;
+  Actor                 mChildrenRoot; // for creating a subtree for all user added child actors
+
+  /////////////////////////////////////////////////////////////
+  // background fill color
+  Vector4 mBackgroundColor;
+
+  /////////////////////////////////////////////////////////////
+  // for checking if we need to reallocate render targets
+  Vector2 mTargetSize;
+  Vector2 mLastSize;
+  /////////////////////////////////////////////////////////////
+  // post blur image
+  FrameBuffer           mFrameBufferPostFilter;
+  Renderer              mRendererPostFilter;
+
+  Vector<ImageFilter*> mFilters;
+
+  /////////////////////////////////////////////////////////////
+  // downsampling is used for the separated blur passes to get increased blur with the same number of samples and also to make rendering quicker
+  int mEffectSize;
+
+  /////////////////////////////////////////////////////////////
+  Toolkit::EffectsView::EffectType mEffectType;
+  Pixel::Format mPixelFormat;     ///< pixel format used by render targets
+
+  bool mEnabled:1;
+  bool mRefreshOnDemand:1;
+}; // class EffectsView
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::EffectsView& GetImpl( Toolkit::EffectsView& effectsView )
+{
+  DALI_ASSERT_ALWAYS( effectsView );
+
+  Dali::RefObject& handle = effectsView.GetImplementation();
+
+  return static_cast<Toolkit::Internal::EffectsView&>( handle );
+}
+
+inline const Toolkit::Internal::EffectsView& GetImpl( const Toolkit::EffectsView& effectsView )
+{
+  DALI_ASSERT_ALWAYS( effectsView );
+
+  const Dali::RefObject& handle = effectsView.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::EffectsView&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_EFFECTS_VIEW_H
diff --git a/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp b/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp
new file mode 100755 (executable)
index 0000000..1488f5e
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/controls/flex-container/flex-container-impl.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/integration-api/debug.h>
+
+using namespace Dali;
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+// debugging support, very useful when new features are added or bugs are hunted down
+// currently not called from code so compiler will optimize these away, kept here for future debugging
+
+#define FLEX_CONTAINER_TAG "DALI Toolkit::FlexContainer "
+#define FC_LOG(fmt, args,...) Debug::LogMessage(Debug::DebugInfo, FLEX_CONTAINER_TAG fmt, ## args)
+// #define FLEX_CONTAINER_DEBUG 1
+
+#if defined(FLEX_CONTAINER_DEBUG)
+void PrintNodes( Toolkit::Internal::FlexContainer::FlexItemNodeContainer itemNodes )
+{
+  // Print the style property and layout of all the children
+  for( unsigned int i = 0; i < itemNodes.size(); ++i )
+  {
+    FC_LOG( "Item %d style: \n", i );
+    YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsStyle | YGPrintOptionsChildren ) );
+    FC_LOG( "\n" );
+    FC_LOG( "Item %d layout: \n", i );
+    YGNodePrint( itemNodes[i].node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsChildren ) );
+    FC_LOG( "\n" );
+  }
+}
+
+#endif // defined(FLEX_CONTAINER_DEBUG)
+#endif // defined(DEBUG_ENABLED)
+
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::FlexContainer::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::FlexContainer, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "contentDirection",  INTEGER,  CONTENT_DIRECTION )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexDirection",     INTEGER,  FLEX_DIRECTION    )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "flexWrap",          INTEGER,  FLEX_WRAP         )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "justifyContent",    INTEGER,  JUSTIFY_CONTENT   )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignItems",        INTEGER,  ALIGN_ITEMS       )
+DALI_PROPERTY_REGISTRATION( Toolkit, FlexContainer,        "alignContent",      INTEGER,  ALIGN_CONTENT     )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flex",              FLOAT,    FLEX              )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "alignSelf",         INTEGER,  ALIGN_SELF        )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, FlexContainer,  "flexMargin",        VECTOR4,  FLEX_MARGIN       )
+
+DALI_TYPE_REGISTRATION_END()
+
+const Scripting::StringEnum ALIGN_SELF_STRING_TABLE[] =
+{
+  { "auto",        Toolkit::FlexContainer::ALIGN_AUTO        },
+  { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
+  { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
+  { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
+  { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
+};
+const unsigned int ALIGN_SELF_STRING_TABLE_COUNT = sizeof( ALIGN_SELF_STRING_TABLE ) / sizeof( ALIGN_SELF_STRING_TABLE[0] );
+
+const Scripting::StringEnum CONTENT_DIRECTION_STRING_TABLE[] =
+{
+  { "inherit",     Toolkit::FlexContainer::INHERIT           },
+  { "LTR",         Toolkit::FlexContainer::LTR               },
+  { "RTL",         Toolkit::FlexContainer::RTL               }
+};
+const unsigned int CONTENT_DIRECTION_STRING_TABLE_COUNT = sizeof( CONTENT_DIRECTION_STRING_TABLE ) / sizeof( CONTENT_DIRECTION_STRING_TABLE[0] );
+
+const Scripting::StringEnum FLEX_DIRECTION_STRING_TABLE[] =
+{
+  { "column",          Toolkit::FlexContainer::COLUMN          },
+  { "columnReverse",   Toolkit::FlexContainer::COLUMN_REVERSE  },
+  { "row",             Toolkit::FlexContainer::ROW             },
+  { "rowReverse",      Toolkit::FlexContainer::ROW_REVERSE     }
+};
+const unsigned int FLEX_DIRECTION_STRING_TABLE_COUNT = sizeof( FLEX_DIRECTION_STRING_TABLE ) / sizeof( FLEX_DIRECTION_STRING_TABLE[0] );
+
+const Scripting::StringEnum FLEX_WRAP_STRING_TABLE[] =
+{
+  { "noWrap",          Toolkit::FlexContainer::NO_WRAP         },
+  { "wrap",            Toolkit::FlexContainer::WRAP            }
+};
+const unsigned int FLEX_WRAP_STRING_TABLE_COUNT = sizeof( FLEX_WRAP_STRING_TABLE ) / sizeof( FLEX_WRAP_STRING_TABLE[0] );
+
+const Scripting::StringEnum JUSTIFY_CONTENT_STRING_TABLE[] =
+{
+  { "flexStart",       Toolkit::FlexContainer::JUSTIFY_FLEX_START     },
+  { "center",          Toolkit::FlexContainer::JUSTIFY_CENTER         },
+  { "flexEnd",         Toolkit::FlexContainer::JUSTIFY_FLEX_END       },
+  { "spaceBetween",    Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN  },
+  { "spaceAround",     Toolkit::FlexContainer::JUSTIFY_SPACE_AROUND   }
+};
+const unsigned int JUSTIFY_CONTENT_STRING_TABLE_COUNT = sizeof( JUSTIFY_CONTENT_STRING_TABLE ) / sizeof( JUSTIFY_CONTENT_STRING_TABLE[0] );
+
+const Scripting::StringEnum ALIGN_ITEMS_STRING_TABLE[] =
+{
+  { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
+  { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
+  { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
+  { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
+};
+const unsigned int ALIGN_ITEMS_STRING_TABLE_COUNT = sizeof( ALIGN_ITEMS_STRING_TABLE ) / sizeof( ALIGN_ITEMS_STRING_TABLE[0] );
+
+const Scripting::StringEnum ALIGN_CONTENT_STRING_TABLE[] =
+{
+  { "flexStart",   Toolkit::FlexContainer::ALIGN_FLEX_START  },
+  { "center",      Toolkit::FlexContainer::ALIGN_CENTER      },
+  { "flexEnd",     Toolkit::FlexContainer::ALIGN_FLEX_END    },
+  { "stretch",     Toolkit::FlexContainer::ALIGN_STRETCH     }
+};
+const unsigned int ALIGN_CONTENT_STRING_TABLE_COUNT = sizeof( ALIGN_CONTENT_STRING_TABLE ) / sizeof( ALIGN_CONTENT_STRING_TABLE[0] );
+
+} // Unnamed namespace
+
+Toolkit::FlexContainer FlexContainer::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< FlexContainer > impl = new FlexContainer();
+
+  // Pass ownership to CustomActor handle
+  Toolkit::FlexContainer handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+FlexContainer::~FlexContainer()
+{
+  YGNodeFree( mRootNode.node );
+
+  for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+  {
+    YGNodeFree( mChildrenNodes[i].node );
+  }
+
+  mChildrenNodes.clear();
+}
+
+void FlexContainer::SetContentDirection( Toolkit::FlexContainer::ContentDirection contentDirection)
+{
+  if( mContentDirection != contentDirection )
+  {
+    Dali::CustomActor ownerActor(GetOwner());
+
+    if( Toolkit::FlexContainer::INHERIT != contentDirection )
+    {
+      mContentDirection = contentDirection;
+
+      ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, false );
+
+      if( Toolkit::FlexContainer::LTR == contentDirection )
+      {
+        ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::LEFT_TO_RIGHT);
+      }
+      else
+      {
+        ownerActor.SetProperty(Dali::Actor::Property::LAYOUT_DIRECTION, Dali::LayoutDirection::RIGHT_TO_LEFT);
+      }
+    }
+    else
+    {
+      ownerActor.SetProperty( Dali::Actor::Property::INHERIT_LAYOUT_DIRECTION, true );
+
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetParent().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+      {
+        mContentDirection = Toolkit::FlexContainer::RTL;
+      }
+      else
+      {
+        mContentDirection = Toolkit::FlexContainer::LTR;
+      }
+    }
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::ContentDirection FlexContainer::GetContentDirection()
+{
+  return mContentDirection;
+}
+
+void FlexContainer::SetFlexDirection( Toolkit::FlexContainer::FlexDirection flexDirection )
+{
+  if( mFlexDirection != flexDirection )
+  {
+    mFlexDirection = flexDirection;
+    YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( flexDirection ) );
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::FlexDirection FlexContainer::GetFlexDirection()
+{
+  return mFlexDirection;
+}
+
+void FlexContainer::SetFlexWrap( Toolkit::FlexContainer::WrapType flexWrap )
+{
+  if( mFlexWrap != flexWrap )
+  {
+    mFlexWrap = flexWrap;
+    YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( flexWrap ) );
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::WrapType FlexContainer::GetFlexWrap()
+{
+  return mFlexWrap;
+}
+
+void FlexContainer::SetJustifyContent( Toolkit::FlexContainer::Justification justifyContent )
+{
+  if( mJustifyContent != justifyContent )
+  {
+    mJustifyContent = justifyContent;
+    YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( justifyContent ) );
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::Justification FlexContainer::GetJustifyContent()
+{
+  return mJustifyContent;
+}
+
+void FlexContainer::SetAlignItems( Toolkit::FlexContainer::Alignment alignItems )
+{
+  if( mAlignItems != alignItems )
+  {
+    mAlignItems = alignItems;
+    YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( alignItems ) );
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::Alignment FlexContainer::GetAlignItems()
+{
+  return mAlignItems;
+}
+
+void FlexContainer::SetAlignContent( Toolkit::FlexContainer::Alignment alignContent )
+{
+  if( mAlignContent != alignContent )
+  {
+    mAlignContent = alignContent;
+    YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( alignContent ) );
+
+    RelayoutRequest();
+  }
+}
+
+Toolkit::FlexContainer::Alignment FlexContainer::GetAlignContent()
+{
+  return mAlignContent;
+}
+
+void FlexContainer::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
+
+  if( flexContainer )
+  {
+    FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
+    switch( index )
+    {
+      case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
+      {
+        Toolkit::FlexContainer::ContentDirection contentDirection( Toolkit::FlexContainer::INHERIT );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetContentDirection( static_cast<Toolkit::FlexContainer::ContentDirection>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::ContentDirection >( value.Get< std::string >().c_str(),
+                                                                                   CONTENT_DIRECTION_STRING_TABLE,
+                                                                                   CONTENT_DIRECTION_STRING_TABLE_COUNT,
+                                                                                   contentDirection ) )
+        {
+          flexContainerImpl.SetContentDirection(contentDirection);
+        }
+        break;
+      }
+      case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
+      {
+        Toolkit::FlexContainer::FlexDirection flexDirection( Toolkit::FlexContainer::COLUMN );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetFlexDirection( static_cast<Toolkit::FlexContainer::FlexDirection>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::FlexDirection >( value.Get< std::string >().c_str(),
+                                                                                FLEX_DIRECTION_STRING_TABLE,
+                                                                                FLEX_DIRECTION_STRING_TABLE_COUNT,
+                                                                                flexDirection ) )
+        {
+          flexContainerImpl.SetFlexDirection(flexDirection);
+        }
+        break;
+      }
+      case Toolkit::FlexContainer::Property::FLEX_WRAP:
+      {
+        Toolkit::FlexContainer::WrapType flexWrap( Toolkit::FlexContainer::NO_WRAP );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetFlexWrap( static_cast<Toolkit::FlexContainer::WrapType>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::WrapType >( value.Get< std::string >().c_str(),
+                                                                           FLEX_WRAP_STRING_TABLE,
+                                                                           FLEX_WRAP_STRING_TABLE_COUNT,
+                                                                           flexWrap ) )
+        {
+          flexContainerImpl.SetFlexWrap(flexWrap);
+        }
+        break;
+      }
+      case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
+      {
+        Toolkit::FlexContainer::Justification justifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetJustifyContent( static_cast<Toolkit::FlexContainer::Justification>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Justification >( value.Get< std::string >().c_str(),
+                                                                                JUSTIFY_CONTENT_STRING_TABLE,
+                                                                                JUSTIFY_CONTENT_STRING_TABLE_COUNT,
+                                                                                justifyContent ) )
+        {
+          flexContainerImpl.SetJustifyContent(justifyContent);
+        }
+        break;
+      }
+      case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
+      {
+        Toolkit::FlexContainer::Alignment alignItems( Toolkit::FlexContainer::ALIGN_STRETCH );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetAlignItems( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
+                                                                            ALIGN_ITEMS_STRING_TABLE,
+                                                                            ALIGN_ITEMS_STRING_TABLE_COUNT,
+                                                                            alignItems ) )
+        {
+          flexContainerImpl.SetAlignItems(alignItems);
+        }
+        break;
+      }
+      case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
+      {
+        Toolkit::FlexContainer::Alignment alignContent( Toolkit::FlexContainer::ALIGN_FLEX_START );
+
+        if( value.GetType() == Property::INTEGER )
+        {
+          flexContainerImpl.SetAlignContent( static_cast<Toolkit::FlexContainer::Alignment>( value.Get< int >() ) );
+        }
+        else if( Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.Get< std::string >().c_str(),
+                                                                            ALIGN_CONTENT_STRING_TABLE,
+                                                                            ALIGN_CONTENT_STRING_TABLE_COUNT,
+                                                                            alignContent ) )
+        {
+          flexContainerImpl.SetAlignContent(alignContent);
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value FlexContainer::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast( Dali::BaseHandle( object ) );
+
+  if( flexContainer )
+  {
+    FlexContainer& flexContainerImpl( GetImpl( flexContainer ) );
+    switch( index )
+    {
+      case Toolkit::FlexContainer::Property::CONTENT_DIRECTION:
+      {
+        value = flexContainerImpl.GetContentDirection();
+        break;
+      }
+      case Toolkit::FlexContainer::Property::FLEX_DIRECTION:
+      {
+        value = flexContainerImpl.GetFlexDirection();
+        break;
+      }
+      case Toolkit::FlexContainer::Property::FLEX_WRAP:
+      {
+        value = flexContainerImpl.GetFlexWrap();
+        break;
+      }
+      case Toolkit::FlexContainer::Property::JUSTIFY_CONTENT:
+      {
+        value = flexContainerImpl.GetJustifyContent();
+        break;
+      }
+      case Toolkit::FlexContainer::Property::ALIGN_ITEMS:
+      {
+        value = flexContainerImpl.GetAlignItems();
+        break;
+      }
+      case Toolkit::FlexContainer::Property::ALIGN_CONTENT:
+      {
+        value = flexContainerImpl.GetAlignContent();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void FlexContainer::OnChildAdd( Actor& child )
+{
+  // Create a new node for the child.
+  FlexItemNode childNode;
+  childNode.actor = child;
+  childNode.node = YGNodeNew();
+
+  mChildrenNodes.push_back( childNode );
+  YGNodeInsertChild( mRootNode.node, childNode.node, mChildrenNodes.size() - 1 );
+
+  Control::OnChildAdd( child );
+}
+
+void FlexContainer::OnChildRemove( Actor& child )
+{
+  for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+  {
+    if( mChildrenNodes[i].actor.GetHandle() == child )
+    {
+      YGNodeRemoveChild( mRootNode.node, mChildrenNodes[i].node );
+      YGNodeFree( mChildrenNodes[i].node );
+
+      mChildrenNodes.erase( mChildrenNodes.begin() + i );
+
+      // Relayout the container only if instances were found
+      RelayoutRequest();
+      break;
+    }
+  }
+
+  Control::OnChildRemove( child );
+}
+
+void FlexContainer::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+  {
+    Actor child = mChildrenNodes[i].actor.GetHandle();
+    if( child )
+    {
+      // Anchor actor to top left of the container
+      if( child.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+      {
+        child.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      }
+      child.SetParentOrigin( ParentOrigin::TOP_LEFT );
+
+      float negotiatedWidth = child.GetRelayoutSize(Dimension::WIDTH);
+      float negotiatedHeight = child.GetRelayoutSize(Dimension::HEIGHT);
+
+      if( negotiatedWidth > 0 )
+      {
+        YGNodeStyleSetWidth( mChildrenNodes[i].node, negotiatedWidth );
+      }
+      if( negotiatedHeight > 0 )
+      {
+        YGNodeStyleSetHeight( mChildrenNodes[i].node, negotiatedHeight );
+      }
+    }
+  }
+
+  // Relayout the container
+  RelayoutChildren();
+#if defined(FLEX_CONTAINER_DEBUG)
+  PrintNodes( mChildrenNodes );
+#endif
+
+  for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+  {
+    Actor child = mChildrenNodes[i].actor.GetHandle();
+    if( child )
+    {
+      if( child.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
+      {
+        // Only Set to USE_ASSIGNED_SIZE if the child actor is flexible.
+
+        if( child.GetResizePolicy( Dimension::WIDTH ) != ResizePolicy::USE_ASSIGNED_SIZE )
+        {
+          child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
+        }
+        if( child.GetResizePolicy( Dimension::HEIGHT ) != ResizePolicy::USE_ASSIGNED_SIZE )
+        {
+          child.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
+        }
+      }
+      container.Add( child, Vector2(YGNodeLayoutGetWidth(mChildrenNodes[i].node), YGNodeLayoutGetHeight(mChildrenNodes[i].node) ) );
+    }
+  }
+}
+
+bool FlexContainer::RelayoutDependentOnChildren( Dimension::Type dimension )
+{
+  return true;
+}
+
+void FlexContainer::OnSizeSet( const Vector3& size )
+{
+  if( mRootNode.node )
+  {
+    Actor self = Self();
+    YGNodeStyleSetWidth( mRootNode.node, size.x );
+    YGNodeStyleSetHeight( mRootNode.node, size.y );
+
+    RelayoutRequest();
+  }
+
+  Control::OnSizeSet( size );
+}
+
+void FlexContainer::OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
+{
+  Toolkit::FlexContainer flexContainer = Toolkit::FlexContainer::DownCast(actor);
+  Toolkit::FlexContainer::ContentDirection direction;
+
+  if( type == Dali::LayoutDirection::RIGHT_TO_LEFT )
+  {
+    direction = Toolkit::FlexContainer::RTL;
+  }
+  else
+  {
+    direction = Toolkit::FlexContainer::LTR;
+  }
+
+  Toolkit::Internal::FlexContainer &flexContainerImpl = GetImpl( flexContainer );
+
+  if( flexContainerImpl.mContentDirection != direction )
+  {
+    Dali::CustomActor ownerActor(flexContainerImpl.GetOwner());
+    flexContainerImpl.mContentDirection = direction;
+
+    flexContainerImpl.RelayoutRequest();
+  }
+}
+
+void FlexContainer::ComputeLayout()
+{
+  if( mRootNode.node )
+  {
+    for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+    {
+      YGNodeRef childNode = mChildrenNodes[i].node;
+      Actor childActor = mChildrenNodes[i].actor.GetHandle();
+
+      // Intialize the style of the child.
+      YGNodeStyleSetMinWidth( childNode, childActor.GetMinimumSize().x );
+      YGNodeStyleSetMinHeight( childNode, childActor.GetMinimumSize().y );
+      YGNodeStyleSetMaxWidth( childNode, childActor.GetMaximumSize().x );
+      YGNodeStyleSetMaxHeight( childNode, childActor.GetMaximumSize().y );
+
+      // Check child properties on the child for how to layout it.
+      // These properties should be dynamically registered to the child which
+      // would be added to FlexContainer.
+
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX ) != Property::NONE )
+      {
+        YGNodeStyleSetFlex( childNode, childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX ).Get<float>() );
+      }
+
+      Toolkit::FlexContainer::Alignment alignSelf( Toolkit::FlexContainer::ALIGN_AUTO );
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF ) != Property::NONE )
+      {
+        Property::Value alignSelfPropertyValue = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::ALIGN_SELF );
+        if( alignSelfPropertyValue.GetType() == Property::INTEGER )
+        {
+          alignSelf = static_cast<Toolkit::FlexContainer::Alignment>( alignSelfPropertyValue.Get< int >() );
+        }
+        else if( alignSelfPropertyValue.GetType() == Property::STRING )
+        {
+          std::string value = alignSelfPropertyValue.Get<std::string>();
+          Scripting::GetEnumeration< Toolkit::FlexContainer::Alignment >( value.c_str(),
+                                                                          ALIGN_SELF_STRING_TABLE,
+                                                                          ALIGN_SELF_STRING_TABLE_COUNT,
+                                                                          alignSelf );
+        }
+        YGNodeStyleSetAlignSelf( childNode, static_cast<YGAlign>(alignSelf) );
+      }
+
+      if( childActor.GetPropertyType( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ) != Property::NONE )
+      {
+        Vector4 flexMargin = childActor.GetProperty( Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN ).Get<Vector4>();
+        YGNodeStyleSetMargin( childNode, YGEdgeLeft, flexMargin.x );
+        YGNodeStyleSetMargin( childNode, YGEdgeTop, flexMargin.y );
+        YGNodeStyleSetMargin( childNode, YGEdgeRight, flexMargin.z );
+        YGNodeStyleSetMargin( childNode, YGEdgeBottom, flexMargin.w );
+      }
+    }
+
+    // Calculate the layout
+    YGDirection nodeLayoutDirection = YGDirectionInherit;
+    switch( mContentDirection )
+    {
+    case Dali::Toolkit::FlexContainer::LTR:
+    {
+      nodeLayoutDirection = YGDirectionLTR;
+      break;
+    }
+
+    case Dali::Toolkit::FlexContainer::RTL:
+    {
+      nodeLayoutDirection = YGDirectionRTL;
+      break;
+    }
+
+    case Dali::Toolkit::FlexContainer::INHERIT:
+    {
+      nodeLayoutDirection = YGDirectionInherit;
+      break;
+    }
+    }
+
+#if defined(FLEX_CONTAINER_DEBUG)
+    YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
+#endif
+    YGNodeCalculateLayout( mRootNode.node, Self().GetMaximumSize().x, Self().GetMaximumSize().y, nodeLayoutDirection );
+#if defined(FLEX_CONTAINER_DEBUG)
+    YGNodePrint( mRootNode.node, (YGPrintOptions)( YGPrintOptionsLayout | YGPrintOptionsStyle | YGPrintOptionsChildren ) );
+#endif
+  }
+}
+
+void FlexContainer::RelayoutChildren()
+{
+  ComputeLayout();
+
+  // Set size and position of children according to the layout calculation
+  for( unsigned int i = 0; i < mChildrenNodes.size(); i++ )
+  {
+    Dali::Actor child = mChildrenNodes[i].actor.GetHandle();
+    if( child )
+    {
+      child.SetX( YGNodeLayoutGetLeft( mChildrenNodes[i].node ) );
+      child.SetY( YGNodeLayoutGetTop( mChildrenNodes[i].node ) );
+    }
+  }
+}
+
+Actor FlexContainer::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  Actor nextFocusableActor;
+
+  // First check whether there is any items in the container
+  if( mChildrenNodes.size() > 0 )
+  {
+    if ( !currentFocusedActor || currentFocusedActor == Self() )
+    {
+      // Nothing is currently focused, so the first child in the container should be focused.
+      nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
+    }
+    else
+    {
+      // Check whether the current focused actor is within flex container
+      int currentFocusedActorIndex = -1;
+      for( unsigned int index = 0; index < mChildrenNodes.size(); index++ )
+      {
+        if( currentFocusedActor == mChildrenNodes[index].actor.GetHandle() )
+        {
+          currentFocusedActorIndex = index;
+          break;
+        }
+      }
+
+      if( currentFocusedActorIndex > -1 )
+      {
+        int previousCheckedActorIndex = -1;
+        int nextFocusedActorIndex = currentFocusedActorIndex;
+        switch ( direction )
+        {
+          case Toolkit::Control::KeyboardFocus::LEFT:
+          case Toolkit::Control::KeyboardFocus::UP:
+          {
+            // Search the next focusable actor in the backward direction
+            do
+            {
+              nextFocusedActorIndex--;
+              if( nextFocusedActorIndex < 0 )
+              {
+                nextFocusedActorIndex = loopEnabled ? mChildrenNodes.size() - 1 : 0;
+              }
+              if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
+              {
+                previousCheckedActorIndex = nextFocusedActorIndex;
+              }
+              else
+              {
+                break;
+              }
+            } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
+            break;
+          }
+          case Toolkit::Control::KeyboardFocus::RIGHT:
+          case Toolkit::Control::KeyboardFocus::DOWN:
+          {
+            // Search the next focusable actor in the forward direction
+            do
+            {
+              nextFocusedActorIndex++;
+              if( nextFocusedActorIndex > static_cast<int>(mChildrenNodes.size() - 1) )
+              {
+                nextFocusedActorIndex = loopEnabled ? 0 : mChildrenNodes.size() - 1;
+              }
+              if( nextFocusedActorIndex != previousCheckedActorIndex && nextFocusedActorIndex != currentFocusedActorIndex )
+              {
+                previousCheckedActorIndex = nextFocusedActorIndex;
+              }
+              else
+              {
+                break;
+              }
+            } while ( !mChildrenNodes[nextFocusedActorIndex].actor.GetHandle().IsKeyboardFocusable() );
+            break;
+          }
+          default:
+          {
+            break;
+          }
+        }
+
+        if( nextFocusedActorIndex != currentFocusedActorIndex )
+        {
+          nextFocusableActor = mChildrenNodes[nextFocusedActorIndex].actor.GetHandle();
+        }
+        else
+        {
+          // No focusble child in the container
+          nextFocusableActor = Actor();
+        }
+      }
+      else
+      {
+        // The current focused actor is not within flex container, so the first child in the container should be focused.
+        nextFocusableActor = mChildrenNodes[0].actor.GetHandle();
+      }
+    }
+  }
+
+  return nextFocusableActor;
+}
+
+FlexContainer::FlexContainer()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mContentDirection( Toolkit::FlexContainer::INHERIT ),
+  mFlexDirection( Toolkit::FlexContainer::COLUMN ),
+  mFlexWrap( Toolkit::FlexContainer::NO_WRAP ),
+  mJustifyContent( Toolkit::FlexContainer::JUSTIFY_FLEX_START ),
+  mAlignItems( Toolkit::FlexContainer::ALIGN_STRETCH ),
+  mAlignContent( Toolkit::FlexContainer::ALIGN_FLEX_START )
+{
+  SetKeyboardNavigationSupport( true );
+}
+
+void FlexContainer::OnInitialize()
+{
+  // Initialize the node for the flex container itself
+  Dali::Actor self = Self();
+  self.LayoutDirectionChangedSignal().Connect( this, &FlexContainer::OnLayoutDirectionChanged );
+
+  mRootNode.actor = self;
+  mRootNode.node = YGNodeNew();
+  YGNodeSetContext( mRootNode.node, &mChildrenNodes );
+
+  // Set default style
+  YGNodeStyleSetFlexDirection( mRootNode.node, static_cast<YGFlexDirection>( mFlexDirection ) );
+  YGNodeStyleSetFlexWrap( mRootNode.node, static_cast<YGWrap>( mFlexWrap ) );
+  YGNodeStyleSetJustifyContent( mRootNode.node, static_cast<YGJustify>( mJustifyContent ) );
+  YGNodeStyleSetAlignItems( mRootNode.node, static_cast<YGAlign>( mAlignItems ) );
+  YGNodeStyleSetAlignContent( mRootNode.node, static_cast<YGAlign>( mAlignContent ) );
+
+  // Make self as keyboard focusable and focus group
+  self.SetKeyboardFocusable( true );
+  SetAsKeyboardFocusGroup( true );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/flex-container/flex-container-impl.h b/dali-toolkit/internal/controls/flex-container/flex-container-impl.h
new file mode 100755 (executable)
index 0000000..a4cb269
--- /dev/null
@@ -0,0 +1,274 @@
+#ifndef DALI_TOOLKIT_INTERNAL_FLEX_CONTAINER_H
+#define DALI_TOOLKIT_INTERNAL_FLEX_CONTAINER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/flex-container/flex-container.h>
+#include <dali-toolkit/third-party/yoga/Yoga.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * FlexContainer is a custom control for laying out actors in a Flexbox layout
+ * @see Dali::Toolkit:FlexContainer for more details
+ */
+class FlexContainer : public Control
+{
+public:
+
+  /**
+   * The structure to store the style properties and layout information of flex item
+   */
+  struct FlexItemNode
+  {
+    WeakHandle< Dali::Actor > actor;      ///< Actor handle of the flex item
+    YGNodeRef node;                     ///< The style properties and layout information
+  };
+
+  typedef std::vector< FlexItemNode > FlexItemNodeContainer;
+
+public:
+
+  /**
+   * Construct a new FlexContainer.
+   */
+  FlexContainer();
+
+  /**
+   * Create a new FlexContainer.
+   * @return A smart-pointer to the newly allocated FlexContainer.
+   */
+  static Toolkit::FlexContainer New();
+
+  /**
+   * @brief Set the primary direction in which content is ordered.
+   * @param[in] contentDirection The direction of the content.
+   */
+  void SetContentDirection(Toolkit::FlexContainer::ContentDirection contentDirection);
+
+  /**
+   * @brief Get the direction of the content.
+   * @return The direction of the content.
+   */
+  Toolkit::FlexContainer::ContentDirection GetContentDirection();
+
+  /**
+   * @brief Set the direction flex items are laid out.
+   * @param[in] flexDirection The direction flex items are laid out.
+   */
+  void SetFlexDirection(Toolkit::FlexContainer::FlexDirection flexDirection);
+
+  /**
+   * @brief Get the direction flex items are laid out.
+   * @return The direction flex items are laid out.
+   */
+  Toolkit::FlexContainer::FlexDirection GetFlexDirection();
+
+  /**
+   * @brief Set whether the flex items should wrap or not, if there
+   * is no enough room for them on one flex line.
+   * @param[in] flexWrap The wrap type.
+   */
+  void SetFlexWrap(Toolkit::FlexContainer::WrapType flexWrap);
+
+  /**
+   * @brief Get whether the flex items should wrap or not, if there
+   * is no enough room for them on one flex line.
+   * @return The wrap type.
+   */
+  Toolkit::FlexContainer::WrapType GetFlexWrap();
+
+  /**
+   * @brief Set the horizontal alignment of the flex items when the items
+   * do not use all available space on the main-axis.
+   * @param[in] justifyContent The horizontal alignment of flex items.
+   */
+  void SetJustifyContent(Toolkit::FlexContainer::Justification justifyContent);
+
+  /**
+   * @brief Get the horizontal alignment of the flex items when the items
+   * do not use all available space on the main-axis.
+   * @return The horizontal alignment of flex items.
+   */
+  Toolkit::FlexContainer::Justification GetJustifyContent();
+
+  /**
+   * @brief Set the vertical alignment of the flex items when the items
+   * do not use all available space on the cross-axis.
+   * @param[in] alignItems The vertical alignment of flex items.
+   */
+  void SetAlignItems(Toolkit::FlexContainer::Alignment alignItems);
+
+  /**
+   * @brief Get the vertical alignment of the flex items when the items
+   * do not use all available space on the cross-axis.
+   * @return The vertical alignment of flex items.
+   */
+  Toolkit::FlexContainer::Alignment GetAlignItems();
+
+  /**
+   * @brief Set the vertical alignment of the flex lines when the lines
+   * do not use all available space on the cross-axis.
+   * @param[in] alignItems The vertical alignment of flex lines.
+   */
+  void SetAlignContent(Toolkit::FlexContainer::Alignment alignContent);
+
+  /**
+   * @brief Get the vertical alignment of the flex lines when the lines
+   * do not use all available space on the cross-axis.
+   * @return The vertical alignment of flex lines.
+   */
+  Toolkit::FlexContainer::Alignment GetAlignContent();
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Control::OnChildAdd(Actor& child)
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnChildRemove(Actor& child)
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  /**
+   * @copydoc Control::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc Control::RelayoutDependentOnChildren()
+   */
+  virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS );
+
+  /**
+   * @copydoc Control::GetNextKeyboardFocusableActor
+   */
+  virtual Actor GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled );
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet( const Vector3& size )
+   */
+  virtual void OnSizeSet( const Vector3& size );
+
+  /**
+  * @copydoc OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type )
+  * @param[in] actor The actor whose layoutDirection is changed.
+  * @param[in] type  The layoutDirection.
+  */
+  void OnLayoutDirectionChanged( Dali::Actor actor, Dali::LayoutDirection::Type type );
+
+private: // Implementation
+
+  /**
+   * Calculate the layout properties of all the children
+   */
+  void ComputeLayout();
+
+  /**
+   * Calculate the layout of the children and relayout them with their new size and position
+   */
+  void RelayoutChildren();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~FlexContainer();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  FlexContainer(const FlexContainer&);
+  FlexContainer& operator=(const FlexContainer& rhs);
+
+private: // Data
+
+  FlexItemNode mRootNode;                    ///< Style properties and layout information of flex container
+  FlexItemNodeContainer mChildrenNodes;      ///< Style properties and layout information of flex items in the container
+
+  Toolkit::FlexContainer::ContentDirection mContentDirection;        ///< The content direction of the container
+  Toolkit::FlexContainer::FlexDirection mFlexDirection;              ///< The flex direction of the container
+  Toolkit::FlexContainer::WrapType mFlexWrap;                        ///< The wrap type of the container
+  Toolkit::FlexContainer::Justification mJustifyContent;             ///< The alignment of flex items in the container on the main-axis
+  Toolkit::FlexContainer::Alignment mAlignItems;                     ///< The alignment of flex items in the container on the cross-axis
+  Toolkit::FlexContainer::Alignment mAlignContent;                   ///< The alignment of flex lines in the container on the cross-axis
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::FlexContainer& GetImpl( Toolkit::FlexContainer& flexContainer )
+{
+  DALI_ASSERT_ALWAYS(flexContainer);
+
+  Dali::RefObject& handle = flexContainer.GetImplementation();
+
+  return static_cast<Toolkit::Internal::FlexContainer&>(handle);
+}
+
+inline const Toolkit::Internal::FlexContainer& GetImpl( const Toolkit::FlexContainer& flexContainer )
+{
+  DALI_ASSERT_ALWAYS(flexContainer);
+
+  const Dali::RefObject& handle = flexContainer.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::FlexContainer&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_FLEX_CONTAINER_H
diff --git a/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp b/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp
new file mode 100644 (file)
index 0000000..233a79c
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 2017 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 "gaussian-blur-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/property-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+// TODO:
+// pixel format / size - set from JSON
+// aspect ratio property needs to be able to be constrained also for cameras, not possible currently. Therefore changing aspect ratio of GaussianBlurView won't currently work
+// default near clip value
+// Manager object - re-use render targets if there are multiple GaussianBlurViews created
+
+
+/////////////////////////////////////////////////////////
+// IMPLEMENTATION NOTES
+
+// As the GaussianBlurView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
+// OnSetSize() does not get called when GaussianBlurView object size is modified using a Constraint.
+// OnSizeAnimation() only gets called once per AnimateTo/By() and if an Animation has N such calls then only the final one will end up being used. Therefore we can't use
+// OnSizeAnimation() to alter render target sizes.
+// To get around the above problems, we use fixed sized render targets, from the last SetSize() call (which calls OnSetSize()), then we adjust the internal cameras / actors
+// to take account of the changed GaussianBlurView object size, projecting to the unchanged render target sizes. This is done relative to the fixed render target / actor sizes
+// by using constraints relative to the GaussianBlurView actor size.
+
+
+// 2 modes:
+// 1st mode, this control has a tree of actors (use Add() to add children) that are rendered and blurred.
+// mRenderChildrenTask renders children to FB mRenderTargetForRenderingChildren
+// mHorizBlurTask renders mHorizBlurActor Actor showing FB mRenderTargetForRenderingChildren into FB mRenderTarget2
+// mVertBlurTask renders mVertBlurActor Actor showing FB mRenderTarget2 into FB mRenderTarget1
+// mCompositeTask renders mCompositingActor Actor showing FB mRenderTarget1 into FB mRenderTargetForRenderingChildren
+//
+// 2nd mode, an image is blurred and rendered to a supplied target framebuffer
+// mHorizBlurTask renders mHorizBlurActor Actor showing mUserInputImage into FB mRenderTarget2
+// mVertBlurTask renders mVertBlurActor Actor showing mRenderTarget2 into FB mUserOutputRenderTarget
+//
+// Only this 2nd mode handles ActivateOnce
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+using namespace Dali;
+
+BaseHandle Create()
+{
+  return Toolkit::GaussianBlurView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::GaussianBlurView, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+const unsigned int GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES = 5;
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH = 1.5f;
+const Pixel::Format GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH = 1.0f;                                       // default, fully blurred
+const char* const GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME = "GaussianBlurStrengthPropertyName";
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
+const float GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
+
+const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
+
+const char* const GAUSSIAN_BLUR_FRAGMENT_SOURCE = DALI_COMPOSE_SHADER(
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    uniform lowp vec4 uColor;\n
+    uniform mediump vec2 uSampleOffsets[NUM_SAMPLES];\n
+    uniform mediump float uSampleWeights[NUM_SAMPLES];\n
+
+    void main()\n
+    {\n
+       mediump vec4 col = texture2D(sTexture, vTexCoord + uSampleOffsets[0]) * uSampleWeights[0];\n
+       for (int i=1; i<NUM_SAMPLES; ++i)\n
+       {\n
+         col += texture2D(sTexture, vTexCoord + uSampleOffsets[i]) * uSampleWeights[i];\n
+       }\n
+       gl_FragColor = col;\n
+    }\n
+);
+
+} // namespace
+
+
+GaussianBlurView::GaussianBlurView()
+: Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mNumSamples(GAUSSIAN_BLUR_VIEW_DEFAULT_NUM_SAMPLES),
+  mBlurBellCurveWidth( 0.001f ),
+  mPixelFormat(GAUSSIAN_BLUR_VIEW_DEFAULT_RENDER_TARGET_PIXEL_FORMAT),
+  mDownsampleWidthScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_WIDTH_SCALE),
+  mDownsampleHeightScale(GAUSSIAN_BLUR_VIEW_DEFAULT_DOWNSAMPLE_HEIGHT_SCALE),
+  mDownsampledWidth( 0.0f ),
+  mDownsampledHeight( 0.0f ),
+  mBlurUserImage( false ),
+  mRenderOnce( false ),
+  mBackgroundColor( Color::BLACK ),
+  mTargetSize(Vector2::ZERO),
+  mLastSize(Vector2::ZERO),
+  mChildrenRoot(Actor::New()),
+  mInternalRoot(Actor::New()),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mActivated( false )
+{
+  SetBlurBellCurveWidth(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_BELL_CURVE_WIDTH);
+}
+
+GaussianBlurView::GaussianBlurView( const unsigned int numSamples,
+                                    const float blurBellCurveWidth,
+                                    const Pixel::Format renderTargetPixelFormat,
+                                    const float downsampleWidthScale,
+                                    const float downsampleHeightScale,
+                                    bool blurUserImage)
+: Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mNumSamples(numSamples),
+  mBlurBellCurveWidth( 0.001f ),
+  mPixelFormat(renderTargetPixelFormat),
+  mDownsampleWidthScale(downsampleWidthScale),
+  mDownsampleHeightScale(downsampleHeightScale),
+  mDownsampledWidth( 0.0f ),
+  mDownsampledHeight( 0.0f ),
+  mBlurUserImage( blurUserImage ),
+  mRenderOnce( false ),
+  mBackgroundColor( Color::BLACK ),
+  mTargetSize(Vector2::ZERO),
+  mLastSize(Vector2::ZERO),
+  mChildrenRoot(Actor::New()),
+  mInternalRoot(Actor::New()),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mActivated( false )
+{
+  SetBlurBellCurveWidth(blurBellCurveWidth);
+}
+
+GaussianBlurView::~GaussianBlurView()
+{
+}
+
+
+Toolkit::GaussianBlurView GaussianBlurView::New()
+{
+  GaussianBlurView* impl = new GaussianBlurView();
+
+  Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+Toolkit::GaussianBlurView GaussianBlurView::New(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                                const float downsampleWidthScale, const float downsampleHeightScale,
+                                                bool blurUserImage)
+{
+  GaussianBlurView* impl = new GaussianBlurView( numSamples, blurBellCurveWidth, renderTargetPixelFormat,
+                                                 downsampleWidthScale, downsampleHeightScale,
+                                                 blurUserImage);
+
+  Dali::Toolkit::GaussianBlurView handle = Dali::Toolkit::GaussianBlurView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+/////////////////////////////////////////////////////////////
+// for creating a subtree for all user added child actors, so that we can have them exclusive to the mRenderChildrenTask and our other actors exclusive to our other tasks
+// DEPRECATED: overloading Actor::Add()/Remove() not nice since breaks polymorphism. Need another method to pass ownership of added child actors to our internal actor root.
+void GaussianBlurView::Add(Actor child)
+{
+  mChildrenRoot.Add(child);
+}
+
+void GaussianBlurView::Remove(Actor child)
+{
+  mChildrenRoot.Remove(child);
+}
+
+void GaussianBlurView::SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget)
+{
+  // can only do this if the GaussianBlurView object was created with this parameter set
+  DALI_ASSERT_ALWAYS(mBlurUserImage);
+
+  mUserInputImage = inputImage;
+
+  SetRendererTexture( mHorizBlurActor.GetRendererAt(0), inputImage );
+
+  mUserOutputRenderTarget = outputRenderTarget;
+}
+
+FrameBuffer GaussianBlurView::GetBlurredRenderTarget() const
+{
+  if(!mUserOutputRenderTarget)
+  {
+    return mRenderTargetForRenderingChildren;
+  }
+
+  return mUserOutputRenderTarget;
+}
+
+void GaussianBlurView::SetBackgroundColor( const Vector4& color )
+{
+  mBackgroundColor = color;
+}
+
+Vector4 GaussianBlurView::GetBackgroundColor() const
+{
+  return mBackgroundColor;
+}
+
+///////////////////////////////////////////////////////////
+//
+// Private methods
+//
+
+void GaussianBlurView::OnInitialize()
+{
+  // root actor to parent all user added actors, needed to allow us to set that subtree as exclusive for our child render task
+  mChildrenRoot.SetParentOrigin(ParentOrigin::CENTER);
+  mInternalRoot.SetParentOrigin(ParentOrigin::CENTER);
+
+  //////////////////////////////////////////////////////
+  // Create shaders
+
+  std::ostringstream fragmentStringStream;
+  fragmentStringStream << "#define NUM_SAMPLES " << mNumSamples << "\n";
+  fragmentStringStream << GAUSSIAN_BLUR_FRAGMENT_SOURCE;
+  std::string fragmentSource(fragmentStringStream.str());
+
+  //////////////////////////////////////////////////////
+  // Create actors
+
+  // Create an actor for performing a horizontal blur on the texture
+  mHorizBlurActor = Actor::New();
+  mHorizBlurActor.SetParentOrigin(ParentOrigin::CENTER);
+  Renderer renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
+  mHorizBlurActor.AddRenderer( renderer );
+
+  // Create an actor for performing a vertical blur on the texture
+  mVertBlurActor = Actor::New();
+  mVertBlurActor.SetParentOrigin(ParentOrigin::CENTER);
+  renderer = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
+  mVertBlurActor.AddRenderer( renderer );
+
+  // Register a property that the user can control to fade the blur in / out via the GaussianBlurView object
+  Actor self = Self();
+  mBlurStrengthPropertyIndex = self.RegisterProperty(GAUSSIAN_BLUR_VIEW_STRENGTH_PROPERTY_NAME, GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH);
+
+  // Create an image view for compositing the blur and the original child actors render
+  if(!mBlurUserImage)
+  {
+    mCompositingActor = Actor::New();
+    mCompositingActor.SetParentOrigin(ParentOrigin::CENTER);
+    mCompositingActor.SetOpacity(GAUSSIAN_BLUR_VIEW_DEFAULT_BLUR_STRENGTH); // ensure alpha is enabled for this object and set default value
+    renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
+    mCompositingActor.AddRenderer( renderer );
+
+    Constraint blurStrengthConstraint = Constraint::New<float>( mCompositingActor, Actor::Property::COLOR_ALPHA, EqualToConstraint());
+    blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
+    blurStrengthConstraint.Apply();
+
+    // Create an image view for holding final result, i.e. the blurred image. This will get rendered to screen later, via default / user render task
+    mTargetActor = Actor::New();
+    mTargetActor.SetParentOrigin(ParentOrigin::CENTER);
+    renderer = CreateRenderer( BASIC_VERTEX_SOURCE, BASIC_FRAGMENT_SOURCE );
+    mTargetActor.AddRenderer( renderer );
+
+    //////////////////////////////////////////////////////
+    // Create cameras for the renders corresponding to the view size
+    mRenderFullSizeCamera = CameraActor::New();
+    mRenderFullSizeCamera.SetInvertYAxis( true );
+    mRenderFullSizeCamera.SetParentOrigin(ParentOrigin::CENTER);
+
+    //////////////////////////////////////////////////////
+    // Connect to actor tree
+    mInternalRoot.Add( mCompositingActor );
+    mInternalRoot.Add( mTargetActor );
+    mInternalRoot.Add( mRenderFullSizeCamera );
+  }
+
+  //////////////////////////////////////////////////////
+  // Create camera for the renders corresponding to the (potentially downsampled) render targets' size
+  mRenderDownsampledCamera = CameraActor::New();
+  mRenderDownsampledCamera.SetInvertYAxis( true );
+  mRenderDownsampledCamera.SetParentOrigin(ParentOrigin::CENTER);
+
+  //////////////////////////////////////////////////////
+  // Connect to actor tree
+  Self().Add( mChildrenRoot );
+  mInternalRoot.Add( mHorizBlurActor );
+  mInternalRoot.Add( mVertBlurActor );
+  mInternalRoot.Add( mRenderDownsampledCamera );
+}
+
+
+void GaussianBlurView::OnSizeSet(const Vector3& targetSize)
+{
+  mTargetSize = Vector2(targetSize);
+
+  mChildrenRoot.SetSize(targetSize);
+
+  if( !mBlurUserImage )
+  {
+    mCompositingActor.SetSize(targetSize);
+    mTargetActor.SetSize(targetSize);
+
+    // Children render camera must move when GaussianBlurView object is resized. This is since we cannot change render target size - so we need to remap the child actors' rendering
+    // accordingly so they still exactly fill the render target. Note that this means the effective resolution of the child render changes as the GaussianBlurView object changes
+    // size, this is the trade off for not being able to modify render target size
+    // Change camera z position based on GaussianBlurView actor height
+    float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
+    mRenderFullSizeCamera.SetZ(mTargetSize.height * cameraPosConstraintScale);
+  }
+
+
+  // if we have already activated the blur, need to update render target sizes now to reflect the new size of this actor
+  if(mActivated)
+  {
+    Deactivate();
+    Activate();
+  }
+
+  Control::OnSizeSet( targetSize );
+}
+
+void GaussianBlurView::OnChildAdd( Actor& child )
+{
+  if( child != mChildrenRoot && child != mInternalRoot)
+  {
+    mChildrenRoot.Add( child );
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void GaussianBlurView::OnChildRemove( Actor& child )
+{
+  mChildrenRoot.Remove( child );
+
+  Control::OnChildRemove( child );
+}
+
+void GaussianBlurView::AllocateResources()
+{
+  // size of render targets etc is based on the size of this actor, ignoring z
+  if(mTargetSize != mLastSize)
+  {
+    mLastSize = mTargetSize;
+
+    // get size of downsampled render targets
+    mDownsampledWidth = mTargetSize.width * mDownsampleWidthScale;
+    mDownsampledHeight = mTargetSize.height * mDownsampleHeightScale;
+
+    // Create and place a camera for the renders corresponding to the (potentially downsampled) render targets' size
+    mRenderDownsampledCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+    // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
+    mRenderDownsampledCamera.SetNearClippingPlane(1.0f);
+    mRenderDownsampledCamera.SetAspectRatio(mDownsampledWidth / mDownsampledHeight);
+    mRenderDownsampledCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+
+    mRenderDownsampledCamera.SetPosition(0.0f, 0.0f, ((mDownsampledHeight * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
+
+    // setup for normal operation
+    if(!mBlurUserImage)
+    {
+      // Create and place a camera for the children render, corresponding to its render target size
+      mRenderFullSizeCamera.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+      // TODO: how do we pick a reasonable value for near clip? Needs to relate to normal camera the user renders with, but we don't have a handle on it
+      mRenderFullSizeCamera.SetNearClippingPlane(1.0f);
+      mRenderFullSizeCamera.SetAspectRatio(mTargetSize.width / mTargetSize.height);
+      mRenderFullSizeCamera.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+
+      float cameraPosConstraintScale = 0.5f / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f);
+      mRenderFullSizeCamera.SetPosition(0.0f, 0.0f, mTargetSize.height * cameraPosConstraintScale);
+
+      // create offscreen buffer of new size to render our child actors to
+      mRenderTargetForRenderingChildren = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+      Texture texture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+      mRenderTargetForRenderingChildren.AttachColorTexture( texture );
+
+      // Set actor for performing a horizontal blur
+      SetRendererTexture( mHorizBlurActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
+
+      // Create offscreen buffer for vert blur pass
+      mRenderTarget1 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
+      texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
+      mRenderTarget1.AttachColorTexture( texture );
+
+      // use the completed blur in the first buffer and composite with the original child actors render
+      SetRendererTexture( mCompositingActor.GetRendererAt(0), mRenderTarget1 );
+
+      // set up target actor for rendering result, i.e. the blurred image
+      SetRendererTexture( mTargetActor.GetRendererAt(0), mRenderTargetForRenderingChildren );
+    }
+
+    // Create offscreen buffer for horiz blur pass
+    mRenderTarget2 = FrameBuffer::New( mDownsampledWidth, mDownsampledHeight, FrameBuffer::Attachment::NONE );
+    Texture texture = Texture::New(TextureType::TEXTURE_2D, mPixelFormat, unsigned(mDownsampledWidth), unsigned(mDownsampledHeight));
+    mRenderTarget2.AttachColorTexture( texture );
+
+    // size needs to match render target
+    mHorizBlurActor.SetSize(mDownsampledWidth, mDownsampledHeight);
+
+    // size needs to match render target
+    mVertBlurActor.SetSize(mDownsampledWidth, mDownsampledHeight);
+    SetRendererTexture( mVertBlurActor.GetRendererAt(0), mRenderTarget2 );
+
+    // set gaussian blur up for new sized render targets
+    SetShaderConstants();
+  }
+}
+
+void GaussianBlurView::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  if(!mBlurUserImage)
+  {
+    // create render task to render our child actors to offscreen buffer
+    mRenderChildrenTask = taskList.CreateTask();
+    mRenderChildrenTask.SetSourceActor( mChildrenRoot );
+    mRenderChildrenTask.SetExclusive(true);
+    mRenderChildrenTask.SetInputEnabled( false );
+    mRenderChildrenTask.SetClearEnabled( true );
+    mRenderChildrenTask.SetClearColor( mBackgroundColor );
+
+    mRenderChildrenTask.SetCameraActor(mRenderFullSizeCamera);
+    mRenderChildrenTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
+  }
+
+  // perform a horizontal blur targeting the second buffer
+  mHorizBlurTask = taskList.CreateTask();
+  mHorizBlurTask.SetSourceActor( mHorizBlurActor );
+  mHorizBlurTask.SetExclusive(true);
+  mHorizBlurTask.SetInputEnabled( false );
+  mHorizBlurTask.SetClearEnabled( true );
+  mHorizBlurTask.SetClearColor( mBackgroundColor );
+  mHorizBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  mHorizBlurTask.SetFrameBuffer( mRenderTarget2 );
+  if( mRenderOnce && mBlurUserImage )
+  {
+    mHorizBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+  }
+
+  // use the second buffer and perform a horizontal blur targeting the first buffer
+  mVertBlurTask = taskList.CreateTask();
+  mVertBlurTask.SetSourceActor( mVertBlurActor );
+  mVertBlurTask.SetExclusive(true);
+  mVertBlurTask.SetInputEnabled( false );
+  mVertBlurTask.SetClearEnabled( true );
+  mVertBlurTask.SetClearColor( mBackgroundColor );
+  mVertBlurTask.SetCameraActor(mRenderDownsampledCamera);
+  if(mUserOutputRenderTarget)
+  {
+    mVertBlurTask.SetFrameBuffer( mUserOutputRenderTarget );
+  }
+  else
+  {
+    mVertBlurTask.SetFrameBuffer( mRenderTarget1 );
+  }
+  if( mRenderOnce && mBlurUserImage )
+  {
+    mVertBlurTask.SetRefreshRate(RenderTask::REFRESH_ONCE);
+    mVertBlurTask.FinishedSignal().Connect( this, &GaussianBlurView::OnRenderTaskFinished );
+  }
+
+  // use the completed blur in the first buffer and composite with the original child actors render
+  if(!mBlurUserImage)
+  {
+    mCompositeTask = taskList.CreateTask();
+    mCompositeTask.SetSourceActor( mCompositingActor );
+    mCompositeTask.SetExclusive(true);
+    mCompositeTask.SetInputEnabled( false );
+
+    mCompositeTask.SetCameraActor(mRenderFullSizeCamera);
+    mCompositeTask.SetFrameBuffer( mRenderTargetForRenderingChildren );
+  }
+}
+
+void GaussianBlurView::RemoveRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  taskList.RemoveTask(mRenderChildrenTask);
+  taskList.RemoveTask(mHorizBlurTask);
+  taskList.RemoveTask(mVertBlurTask);
+  taskList.RemoveTask(mCompositeTask);
+}
+
+void GaussianBlurView::Activate()
+{
+  // make sure resources are allocated and start the render tasks processing
+  Self().Add( mInternalRoot );
+  AllocateResources();
+  CreateRenderTasks();
+  mActivated = true;
+}
+
+void GaussianBlurView::ActivateOnce()
+{
+  DALI_ASSERT_ALWAYS(mBlurUserImage); // Only works with blurring image mode.
+  mRenderOnce = true;
+  Activate();
+}
+
+void GaussianBlurView::Deactivate()
+{
+  // stop render tasks processing
+  // Note: render target resources are automatically freed since we set the Image::Unused flag
+  mInternalRoot.Unparent();
+  RemoveRenderTasks();
+  mRenderTargetForRenderingChildren.Reset();
+  mRenderTarget1.Reset();
+  mRenderTarget2.Reset();
+  mRenderOnce = false;
+  mActivated = false;
+}
+
+void GaussianBlurView::SetBlurBellCurveWidth(float blurBellCurveWidth)
+{
+  // a value of zero leads to undefined Gaussian weights, do not allow user to do this
+  mBlurBellCurveWidth = std::max( blurBellCurveWidth, 0.001f );
+}
+
+float GaussianBlurView::CalcGaussianWeight(float x)
+{
+  return (1.0f / sqrt(2.0f * Math::PI * mBlurBellCurveWidth)) * exp(-(x * x) / (2.0f * mBlurBellCurveWidth * mBlurBellCurveWidth));
+}
+
+void GaussianBlurView::SetShaderConstants()
+{
+  Vector2 *uvOffsets;
+  float ofs;
+  float *weights;
+  float w, totalWeights;
+  unsigned int i;
+
+  uvOffsets = new Vector2[mNumSamples + 1];
+  weights = new float[mNumSamples + 1];
+
+  totalWeights = weights[0] = CalcGaussianWeight(0);
+  uvOffsets[0].x = 0.0f;
+  uvOffsets[0].y = 0.0f;
+
+  for(i=0; i<mNumSamples >> 1; i++)
+  {
+    w = CalcGaussianWeight((float)(i + 1));
+    weights[(i << 1) + 1] = w;
+    weights[(i << 1) + 2] = w;
+    totalWeights += w * 2.0f;
+
+    // offset texture lookup to between texels, that way the bilinear filter in the texture hardware will average two samples with one lookup
+    ofs = ((float)(i << 1)) + 1.5f;
+
+    // get offsets from units of pixels into uv coordinates in [0..1]
+    float ofsX = ofs / mDownsampledWidth;
+    float ofsY = ofs / mDownsampledHeight;
+    uvOffsets[(i << 1) + 1].x = ofsX;
+    uvOffsets[(i << 1) + 1].y = ofsY;
+
+    uvOffsets[(i << 1) + 2].x = -ofsX;
+    uvOffsets[(i << 1) + 2].y = -ofsY;
+  }
+
+  for(i=0; i<mNumSamples; i++)
+  {
+    weights[i] /= totalWeights;
+  }
+
+  // set shader constants
+  Vector2 xAxis(1.0f, 0.0f);
+  Vector2 yAxis(0.0f, 1.0f);
+  for (i = 0; i < mNumSamples; ++i )
+  {
+    mHorizBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * xAxis );
+    mHorizBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
+
+    mVertBlurActor.RegisterProperty( GetSampleOffsetsPropertyName( i ), uvOffsets[ i ] * yAxis );
+    mVertBlurActor.RegisterProperty( GetSampleWeightsPropertyName( i ), weights[ i ] );
+  }
+
+  delete[] uvOffsets;
+  delete[] weights;
+}
+
+std::string GaussianBlurView::GetSampleOffsetsPropertyName( unsigned int index ) const
+{
+  DALI_ASSERT_ALWAYS( index < mNumSamples );
+
+  std::ostringstream oss;
+  oss << "uSampleOffsets[" << index << "]";
+  return oss.str();
+}
+
+std::string GaussianBlurView::GetSampleWeightsPropertyName( unsigned int index ) const
+{
+  DALI_ASSERT_ALWAYS( index < mNumSamples );
+
+  std::ostringstream oss;
+  oss << "uSampleWeights[" << index << "]";
+  return oss.str();
+}
+
+Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& GaussianBlurView::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+void GaussianBlurView::OnRenderTaskFinished(Dali::RenderTask& renderTask)
+{
+  Toolkit::GaussianBlurView handle( GetOwner() );
+  mFinishedSignal.Emit( handle );
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h b/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.h
new file mode 100644 (file)
index 0000000..7ecf96b
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GAUSSIAN_BLUR_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_GAUSSIAN_BLUR_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <sstream>
+#include <cmath>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class GaussianBlurView;
+
+namespace Internal
+{
+
+/**
+ * GaussianBlurView implementation class
+ */
+class GaussianBlurView : public Control
+{
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::GaussianBlurView::GaussianBlurView
+   */
+  GaussianBlurView();
+
+  /**
+   * @copydoc Dali::Toolkit::GaussianBlurView::GaussianBlurView
+   */
+  GaussianBlurView(const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                   const float downsampleWidthScale, const float downsampleHeightScale,
+                   bool blurUserImage);
+
+  /**
+   * @copydoc Dali::Toolkit::GaussianBlurView::~GaussianBlurView
+   */
+  virtual ~GaussianBlurView();
+
+  /**
+   * @copydoc Dali::Toolkit::GaussianBlurView::New
+   */
+  static Dali::Toolkit::GaussianBlurView New();
+  static Dali::Toolkit::GaussianBlurView New( const unsigned int numSamples, const float blurBellCurveWidth, const Pixel::Format renderTargetPixelFormat,
+                                              const float downsampleWidthScale, const float downsampleHeightScale,
+                                              bool blurUserImage);
+
+  void Add(Actor child);
+  void Remove(Actor child);
+
+  void Activate();
+  void ActivateOnce();
+  void Deactivate();
+
+  void SetUserImageAndOutputRenderTarget(Texture inputImage, FrameBuffer outputRenderTarget);
+
+  Property::Index GetBlurStrengthPropertyIndex() const {return mBlurStrengthPropertyIndex;}
+  FrameBuffer GetBlurredRenderTarget() const;
+
+  /// @copydoc Dali::Toolkit::GaussianBlurView::SetBackgroundColor(const Vector4&)
+  void SetBackgroundColor( const Vector4& color );
+
+  /// @copydoc Dali::Toolkit::GaussianBlurView::GetBackgroundColor
+  Vector4 GetBackgroundColor() const;
+
+  void AllocateResources();
+  void CreateRenderTasks();
+  void RemoveRenderTasks();
+  Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal& FinishedSignal();
+
+private:
+
+  virtual void OnInitialize();
+  virtual void OnSizeSet(const Vector3& targetSize);
+
+  /**
+   * @copydoc Control::OnChildAdd()
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnChildRemove()
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  void SetBlurBellCurveWidth(float blurBellCurveWidth);
+  float CalcGaussianWeight(float x);
+  void SetShaderConstants();
+  std::string GetSampleOffsetsPropertyName( unsigned int index ) const;
+  std::string GetSampleWeightsPropertyName( unsigned int index ) const;
+
+  void OnRenderTaskFinished(Dali::RenderTask& renderTask);
+
+  /////////////////////////////////////////////////////////////
+  unsigned int mNumSamples;       // number of blur samples in each of horiz/vert directions
+  float mBlurBellCurveWidth;      // constant used when calculating the gaussian weights
+  Pixel::Format mPixelFormat;     // pixel format used by render targets
+
+  /////////////////////////////////////////////////////////////
+  // downsampling is used for the separated blur passes to get increased blur with the same number of samples and also to make rendering quicker
+  float mDownsampleWidthScale;
+  float mDownsampleHeightScale;
+  float mDownsampledWidth;
+  float mDownsampledHeight;
+
+  /////////////////////////////////////////////////////////////
+  // if this is set to true, we blur a user supplied image rather than rendering and blurring children
+  bool mBlurUserImage:1;
+
+  /////////////////////////////////////////////////////////////
+  // if this is set to true, set the render tasks to refresh once
+  bool mRenderOnce:1;
+
+  /////////////////////////////////////////////////////////////
+  // background fill color
+  Vector4 mBackgroundColor;
+
+  /////////////////////////////////////////////////////////////
+  // for checking if we need to reallocate render targets
+  Vector2 mTargetSize;
+  Vector2 mLastSize;
+
+  /////////////////////////////////////////////////////////////
+  // for creating a subtree for all user added child actors, so that we can have them exclusive to the mRenderChildrenTask and our other actors exclusive to our other tasks
+  Actor mChildrenRoot;
+  // for creating a subtree for the internal actors
+  Actor mInternalRoot;
+
+  /////////////////////////////////////////////////////////////
+  // for mapping offscreen renders to render target sizes
+  CameraActor mRenderFullSizeCamera;
+  CameraActor mRenderDownsampledCamera;
+
+  /////////////////////////////////////////////////////////////
+  // for rendering all user added children to offscreen target
+  FrameBuffer mRenderTargetForRenderingChildren;
+  RenderTask mRenderChildrenTask;
+
+  /////////////////////////////////////////////////////////////
+  // for rendering separated blur passes to offscreen targets
+  FrameBuffer mRenderTarget1;
+  FrameBuffer mRenderTarget2;
+
+  Actor mHorizBlurActor;
+  Actor mVertBlurActor;
+
+  RenderTask mHorizBlurTask;
+  RenderTask mVertBlurTask;
+
+  /////////////////////////////////////////////////////////////
+  // for compositing blur and children renders to offscreen target
+  Actor mCompositingActor;
+  RenderTask mCompositeTask;
+
+  /////////////////////////////////////////////////////////////
+  // for holding blurred result
+  Actor mTargetActor;
+
+  /////////////////////////////////////////////////////////////
+  // for animating fade in / out of blur, hiding internal implementation but allowing user to set via GaussianBlurView interface
+  Property::Index mBlurStrengthPropertyIndex;
+
+  /////////////////////////////////////////////////////////////
+  // User can specify image to blur and output target, so we can use GaussianBlurView for arbitrary blur processes
+  Texture mUserInputImage;
+  FrameBuffer mUserOutputRenderTarget;
+
+  Dali::Toolkit::GaussianBlurView::GaussianBlurViewSignal mFinishedSignal; ///< Signal emitted when blur has completed.
+
+  bool mActivated:1;
+private:
+
+  // Undefined copy constructor.
+  GaussianBlurView( const GaussianBlurView& );
+
+  // Undefined assignment operator.
+  GaussianBlurView& operator=( const GaussianBlurView& );
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::GaussianBlurView& GetImpl( Toolkit::GaussianBlurView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::GaussianBlurView&>(handle);
+}
+
+inline const Toolkit::Internal::GaussianBlurView& GetImpl( const Toolkit::GaussianBlurView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::GaussianBlurView&>(handle);
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GAUSSIAN_BLUR_EFFECT_H
diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp
new file mode 100755 (executable)
index 0000000..035d1d8
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2019 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 "image-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::ImageView::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ImageView, Toolkit::Control, Create );
+DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "reservedProperty01", STRING, RESERVED_PROPERTY_01 )
+DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "image", MAP, IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, ImageView, "preMultipliedAlpha", BOOLEAN, PRE_MULTIPLIED_ALPHA )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, ImageView, "pixelArea", Vector4(0.f, 0.f, 1.f, 1.f), PIXEL_AREA )
+DALI_TYPE_REGISTRATION_END()
+
+} // anonymous namespace
+
+using namespace Dali;
+
+ImageView::ImageView()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mImageSize(),
+  mImageVisualPaddingSetByTransform( false )
+{
+}
+
+ImageView::~ImageView()
+{
+}
+
+Toolkit::ImageView ImageView::New()
+{
+  ImageView* impl = new ImageView();
+
+  Toolkit::ImageView handle = Toolkit::ImageView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+/////////////////////////////////////////////////////////////
+
+void ImageView::OnInitialize()
+{
+  // ImageView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to ImageView
+  Dali::Toolkit::Control handle( GetOwner() );
+  handle.ResourceReadySignal().Connect( this, &ImageView::OnResourceReady );
+}
+
+void ImageView::SetImage( Image image )
+{
+  // Don't bother comparing if we had a visual previously, just drop old visual and create new one
+  mImage = image;
+  mUrl.clear();
+  mPropertyMap.Clear();
+
+  Toolkit::Visual::Base visual =  Toolkit::VisualFactory::Get().CreateVisual( image );
+  if( visual )
+  {
+    if( !mVisual )
+    {
+      mVisual = visual;
+    }
+
+    if( !mShaderMap.Empty() )
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.SetCustomShader( mShaderMap );
+    }
+
+    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
+  }
+  else
+  {
+    // Unregister the existing visual
+    DevelControl::UnregisterVisual( *this, Toolkit::ImageView::Property::IMAGE );
+
+    // Trigger a size negotiation request that may be needed when unregistering a visual.
+    RelayoutRequest();
+  }
+
+  // Signal that a Relayout may be needed
+}
+
+void ImageView::SetImage( const Property::Map& map )
+{
+  // Comparing a property map is too expensive so just creating a new visual
+  mPropertyMap = map;
+  mUrl.clear();
+  mImage.Reset();
+
+  Toolkit::Visual::Base visual =  Toolkit::VisualFactory::Get().CreateVisual( mPropertyMap );
+  if( visual )
+  {
+    // Don't set mVisual until it is ready and shown. Getters will still use current visual.
+    if( !mVisual )
+    {
+      mVisual = visual;
+    }
+
+    if( !mShaderMap.Empty() )
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.SetCustomShader( mShaderMap );
+    }
+
+    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual  );
+  }
+  else
+  {
+    // Unregister the exsiting visual
+    DevelControl::UnregisterVisual( *this, Toolkit::ImageView::Property::IMAGE );
+
+    // Trigger a size negotiation request that may be needed when unregistering a visual.
+    RelayoutRequest();
+  }
+
+  // Signal that a Relayout may be needed
+}
+
+void ImageView::SetImage( const std::string& url, ImageDimensions size )
+{
+  // Don't bother comparing if we had a visual previously, just drop old visual and create new one
+  mUrl = url;
+  mImageSize = size;
+  mImage.Reset();
+  mPropertyMap.Clear();
+
+  // Don't set mVisual until it is ready and shown. Getters will still use current visual.
+  Toolkit::Visual::Base visual =  Toolkit::VisualFactory::Get().CreateVisual( url, size );
+  if( visual )
+  {
+    if( !mVisual )
+    {
+      mVisual = visual;
+    }
+
+    if( !mShaderMap.Empty() )
+    {
+      Internal::Visual::Base& visualImpl = Toolkit::GetImplementation( visual );
+      visualImpl.SetCustomShader( mShaderMap );
+    }
+
+    DevelControl::RegisterVisual( *this, Toolkit::ImageView::Property::IMAGE, visual );
+  }
+  else
+  {
+    // Unregister the exsiting visual
+    DevelControl::UnregisterVisual( *this, Toolkit::ImageView::Property::IMAGE );
+
+    // Trigger a size negotiation request that may be needed when unregistering a visual.
+    RelayoutRequest();
+  }
+
+  // Signal that a Relayout may be needed
+}
+
+Image ImageView::GetImage() const
+{
+  return mImage;
+}
+
+void ImageView::EnablePreMultipliedAlpha( bool preMultipled )
+{
+  if( mVisual )
+  {
+    Toolkit::GetImplementation( mVisual ).EnablePreMultipliedAlpha( preMultipled );
+  }
+}
+
+bool ImageView::IsPreMultipliedAlphaEnabled() const
+{
+  if( mVisual )
+  {
+    return Toolkit::GetImplementation( mVisual ).IsPreMultipliedAlphaEnabled();
+  }
+  return false;
+}
+
+void ImageView::SetDepthIndex( int depthIndex )
+{
+  if( mVisual )
+  {
+    mVisual.SetDepthIndex( depthIndex );
+  }
+}
+
+Vector3 ImageView::GetNaturalSize()
+{
+  if( mVisual )
+  {
+    Vector2 rendererNaturalSize;
+    mVisual.GetNaturalSize( rendererNaturalSize );
+
+    Extents padding;
+    padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+    rendererNaturalSize.width += ( padding.start + padding.end );
+    rendererNaturalSize.height += ( padding.top + padding.bottom );
+    return Vector3( rendererNaturalSize );
+  }
+
+  // if no visual then use Control's natural size
+  return Control::GetNaturalSize();
+}
+
+float ImageView::GetHeightForWidth( float width )
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  if( mVisual )
+  {
+    return mVisual.GetHeightForWidth( width ) + padding.top + padding.bottom;
+  }
+  else
+  {
+    return Control::GetHeightForWidth( width ) + padding.top + padding.bottom;
+  }
+}
+
+float ImageView::GetWidthForHeight( float height )
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  if( mVisual )
+  {
+    return mVisual.GetWidthForHeight( height ) + padding.start + padding.end;
+  }
+  else
+  {
+    return Control::GetWidthForHeight( height ) + padding.start + padding.end;
+  }
+}
+
+void ImageView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  Control::OnRelayout( size, container );
+
+  if( mVisual )
+  {
+    Property::Map transformMap = Property::Map();
+
+    Extents padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+    const Visual::FittingMode fittingMode = Toolkit::GetImplementation(mVisual).GetFittingMode();
+
+    bool zeroPadding = ( padding == Extents() );
+    if( ( !zeroPadding ) || // If padding is not zero
+        ( fittingMode == Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ) )
+    {
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(
+            Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+      {
+        std::swap( padding.start, padding.end );
+      }
+
+      auto finalOffset = Vector2( padding.start, padding.top );
+      mImageVisualPaddingSetByTransform = true;
+
+      // remove padding from the size to know how much is left for the visual
+      auto finalSize = size - Vector2( padding.start + padding.end, padding.top + padding.bottom );
+
+      // Should provide a transform that handles aspect ratio according to image size
+      if( fittingMode == Visual::FittingMode::FIT_KEEP_ASPECT_RATIO )
+      {
+        auto availableVisualSize = finalSize;
+
+        Vector2 naturalSize;
+        mVisual.GetNaturalSize( naturalSize );
+
+        // scale to fit the padded area
+        finalSize = naturalSize * std::min( ( naturalSize.width  ? ( availableVisualSize.width  / naturalSize.width  ) : 0 ),
+                                            ( naturalSize.height ? ( availableVisualSize.height / naturalSize.height ) : 0 ) );
+
+        // calculate final offset within the padded area
+        finalOffset += ( availableVisualSize - finalSize ) * .5f;
+      }
+
+      // populate the transform map
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, finalOffset )
+                  .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                      Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                  .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                  .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE, finalSize )
+                  .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY,
+                      Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+    }
+    else if ( mImageVisualPaddingSetByTransform && zeroPadding )  // Reset offset to zero only if padding applied previously
+    {
+      mImageVisualPaddingSetByTransform = false;
+      // Reset the transform map
+      transformMap.Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2::ZERO )
+                  .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY,
+                        Vector2( Toolkit::Visual::Transform::Policy::RELATIVE, Toolkit::Visual::Transform::Policy::RELATIVE ) );
+    }
+
+
+    mVisual.SetTransformAndSize( transformMap, size );
+
+    // mVisual is not updated util the resource is ready in the case of visual replacement.
+    // So apply the transform and size to the new visual.
+    Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+    if( visual && visual != mVisual )
+    {
+      visual.SetTransformAndSize( transformMap, size );
+    }
+  }
+}
+
+void ImageView::OnResourceReady( Toolkit::Control control )
+{
+  // Visual ready so update visual attached to this ImageView, following call to RelayoutRequest will use this visual.
+  mVisual = DevelControl::GetVisual( *this, Toolkit::ImageView::Property::IMAGE );
+  // Signal that a Relayout may be needed
+}
+
+///////////////////////////////////////////////////////////
+//
+// Properties
+//
+
+void ImageView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
+
+  if ( imageView )
+  {
+    ImageView& impl = GetImpl( imageView );
+    switch ( index )
+    {
+      case Toolkit::ImageView::Property::IMAGE:
+      {
+        std::string imageUrl;
+        Property::Map* map;
+        if( value.Get( imageUrl ) )
+        {
+          impl.SetImage( imageUrl, ImageDimensions() );
+        }
+        // if its not a string then get a Property::Map from the property if possible.
+        else
+        {
+          map = value.GetMap();
+          if( map )
+          {
+            Property::Value* shaderValue = map->Find( Toolkit::Visual::Property::SHADER, CUSTOM_SHADER );
+            // set image only if property map contains image information other than custom shader
+            if( map->Count() > 1u ||  !shaderValue )
+            {
+              impl.SetImage( *map );
+            }
+            // the property map contains only the custom shader
+            else if( ( map->Count() == 1u )&&( shaderValue ) )
+            {
+              Property::Map* shaderMap = shaderValue->GetMap();
+              if( shaderMap )
+              {
+                impl.mShaderMap = *shaderMap;
+
+                if( !impl.mUrl.empty() )
+                {
+                  impl.SetImage( impl.mUrl, impl.mImageSize );
+                }
+                else if( impl.mImage )
+                {
+                  impl.SetImage( impl.mImage );
+                }
+                else if( !impl.mPropertyMap.Empty() )
+                {
+                  impl.SetImage( impl.mPropertyMap );
+                }
+              }
+            }
+          }
+        }
+        break;
+      }
+
+      case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
+      {
+        bool isPre;
+        if( value.Get( isPre ) )
+        {
+          impl.EnablePreMultipliedAlpha( isPre );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value ImageView::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::ImageView imageview = Toolkit::ImageView::DownCast( Dali::BaseHandle( object ) );
+
+  if ( imageview )
+  {
+    ImageView& impl = GetImpl( imageview );
+    switch ( propertyIndex )
+    {
+      case Toolkit::ImageView::Property::IMAGE:
+      {
+        if ( !impl.mUrl.empty() )
+        {
+          value = impl.mUrl;
+        }
+        else if( impl.mImage )
+        {
+          Property::Map map;
+          Scripting::CreatePropertyMap( impl.mImage, map );
+          value = map;
+        }
+        else
+        {
+          Property::Map map;
+          Toolkit::Visual::Base visual = DevelControl::GetVisual( impl, Toolkit::ImageView::Property::IMAGE );
+          if( visual )
+          {
+            visual.CreatePropertyMap( map );
+          }
+          value = map;
+        }
+        break;
+      }
+
+      case Toolkit::ImageView::Property::PRE_MULTIPLIED_ALPHA:
+      {
+        value = impl.IsPreMultipliedAlphaEnabled();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.h b/dali-toolkit/internal/controls/image-view/image-view-impl.h
new file mode 100644 (file)
index 0000000..fe1bac1
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef DALI_TOOLKIT_INTERNAL_IMAGE_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_IMAGE_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class ImageView;
+
+namespace Internal
+{
+class ImageView : public Control
+{
+protected:
+
+  /**
+   * Construct a new ImageView.
+   */
+  ImageView();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ImageView();
+
+public:
+  /**
+   * Create a new ImageView.
+   * @return A smart-pointer to the newly allocated ImageView.
+   */
+  static Toolkit::ImageView New();
+
+  /**
+   * @copydoc Dali::Toolkit::SetImage
+   */
+  void SetImage( Image image );
+
+  /**
+   * @brief Sets this ImageView from an Dali::Property::Map
+   *
+   * If the handle is empty, ImageView will display nothing
+   * @param[in] map The Dali::Property::Map to use for to display.
+   */
+  void SetImage( const Dali::Property::Map& map );
+
+  /**
+   * @copydoc Dali::Toolkit::SetImage
+   */
+  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.
+   */
+  void EnablePreMultipliedAlpha( bool preMultipled );
+
+  /**
+   * @brief Query whether alpha is pre-multiplied.
+   *
+   * @return True if alpha is pre-multiplied, false otherwise.
+   */
+  bool IsPreMultipliedAlphaEnabled() const;
+
+  // Properties
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+  /**
+   * @brief Set the depth index of this image renderer
+   *
+   * Renderer with higher depth indices are rendered in front of other visuals with smaller values
+   *
+   * @param[in] depthIndex The depth index of this renderer
+   */
+  void SetDepthIndex( int depthIndex );
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize
+   */
+  void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::GetNaturalSize
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Toolkit::Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Toolkit::Control::GetWidthForHeight()
+   */
+  virtual float GetWidthForHeight( float height );
+
+  /**
+   * @copydoc Toolkit::Control::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+private:
+
+  /**
+   * @brief Callback for ResourceReadySignal
+   * param[in] control signal prototype
+   */
+  void OnResourceReady( Toolkit::Control control );
+
+private:
+  // Undefined
+  ImageView( const ImageView& );
+  ImageView& operator=( const ImageView& );
+
+private:
+  Toolkit::Visual::Base  mVisual;
+
+  std::string      mUrl;          ///< the url for the image if the image came from a URL, empty otherwise
+  Image            mImage;        ///< the Image if the image came from a Image, null otherwise
+  Property::Map    mPropertyMap;  ///< the Property::Map if the image came from a Property::Map, empty otherwise
+  Property::Map    mShaderMap;    ///< the Property::Map if the custom shader is set, empty otherwise
+  ImageDimensions  mImageSize;    ///< the image size
+
+  bool mImageVisualPaddingSetByTransform :1; //< Flag to indicate Padding was set using a transform.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::ImageView& GetImpl( Toolkit::ImageView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::ImageView&>(handle);
+}
+
+inline const Toolkit::Internal::ImageView& GetImpl( const Toolkit::ImageView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::ImageView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_IMAGE_VIEW_H
diff --git a/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp b/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp
new file mode 100644 (file)
index 0000000..f4ad54f
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/magnifier/magnifier-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/border-visual-properties.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+
+Dali::BaseHandle Create()
+{
+  return Toolkit::Magnifier::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Magnifier, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Magnifier, "frameVisibility",      BOOLEAN, FRAME_VISIBILITY     )
+DALI_PROPERTY_REGISTRATION( Toolkit, Magnifier, "magnificationFactor",  FLOAT,   MAGNIFICATION_FACTOR )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Magnifier, "sourcePosition",  VECTOR3, SOURCE_POSITION )
+
+DALI_TYPE_REGISTRATION_END()
+
+const float IMAGE_BORDER_INDENT = 5.0f;            ///< Indent of border in pixels.
+
+struct CameraActorPositionConstraint
+{
+  CameraActorPositionConstraint(const Vector2& stageSize, float defaultCameraDistance = 0.0f)
+  : mStageSize(stageSize),
+    mDefaultCameraDistance(defaultCameraDistance)
+  {
+  }
+
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    const Vector3& sourcePosition = inputs[0]->GetVector3();
+
+    current.x = sourcePosition.x + mStageSize.x * 0.5f;
+    current.y = sourcePosition.y + mStageSize.y * 0.5f;
+    current.z = sourcePosition.z + mDefaultCameraDistance;
+  }
+
+  Vector2 mStageSize;
+  float mDefaultCameraDistance;
+
+};
+
+struct RenderTaskViewportPositionConstraint
+{
+  RenderTaskViewportPositionConstraint(const Vector2& stageSize)
+  : mStageSize(stageSize)
+  {
+  }
+
+  void operator()( Vector2& current, const PropertyInputContainer& inputs )
+  {
+    current = inputs[0]->GetVector3(); // World position?
+
+    // should be updated when:
+    // Magnifier's world position/size/scale/parentorigin/anchorpoint changes.
+    // or Magnifier camera's world position changes.
+    Vector3 size = inputs[1]->GetVector3() * inputs[2]->GetVector3(); /* magnifier-size * magnifier-scale */
+
+    // Reposition, and resize viewport to reflect the world bounds of this Magnifier actor.
+    current.x += ( mStageSize.width - size.width ) * 0.5f;
+    current.y += ( mStageSize.height - size.height ) * 0.5f;
+  }
+
+  Vector2 mStageSize;
+};
+
+struct RenderTaskViewportSizeConstraint
+{
+  RenderTaskViewportSizeConstraint()
+  {
+  }
+
+  void operator()( Vector2& current, const PropertyInputContainer& inputs )
+  {
+    current = inputs[0]->GetVector3() * inputs[1]->GetVector3(); /* magnifier-size * magnifier-scale */
+  }
+};
+
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Magnifier
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Dali::Toolkit::Magnifier Magnifier::New()
+{
+  // Create the implementation
+  MagnifierPtr magnifier(new Magnifier());
+
+  // Pass ownership to CustomActor via derived handle
+  Dali::Toolkit::Magnifier handle(*magnifier);
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  magnifier->Initialize();
+
+  return handle;
+}
+
+Magnifier::Magnifier()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mDefaultCameraDistance(1000.f),
+  mActorSize(Vector3::ZERO),
+  mMagnificationFactor(1.0f)
+{
+}
+
+void Magnifier::SetSourceActor(Actor actor)
+{
+  mTask.SetSourceActor( actor );
+}
+
+void Magnifier::Initialize()
+{
+  Actor self = Self();
+  Vector2 stageSize(Stage::GetCurrent().GetSize());
+
+  // NOTE:
+  // sourceActor is a dummy delegate actor that takes the source property position,
+  // and generates a WORLD_POSITION, which is 1 frame behind the source property.
+  // This way the constraints for determining the camera position (source) and those
+  // for determining viewport position use the same 1 frame old values.
+  // A simple i) CameraPos = f(B), ii) B = f(A) set of constraints wont suffice as
+  // although CameraPos will use B, which is A's previous value. The constraint will
+  // not realise that B is still dirty as far as constraint (i) is concerned.
+  // Perhaps this is a bug in the way the constraint system factors into what is dirty
+  // and what is not.
+  mSourceActor = Actor::New();
+  Stage().GetCurrent().Add(mSourceActor);
+  mSourceActor.SetParentOrigin(ParentOrigin::CENTER);
+  Constraint constraint = Constraint::New<Vector3>( mSourceActor, Actor::Property::POSITION, EqualToConstraint() );
+  constraint.AddSource( Source( self, Toolkit::Magnifier::Property::SOURCE_POSITION ) );
+  constraint.Apply();
+
+  // create the render task this will render content on top of everything
+  // based on camera source position.
+  InitializeRenderTask();
+
+  // set up some constraints to:
+  // i) reposition (dest) frame actor based on magnifier actor's world position (this is 1 frame delayed)
+  // ii) reposition and resize (dest) the render task's viewport based on magnifier actor's world position (1 frame delayed) & size.
+  // iii) reposition (source) camera actor based on magnifier source actor's world position (this is 1 frame delayed)
+
+  // Apply constraint to camera's position
+  // Position our camera at the same distance from its target as the default camera is.
+  // The camera position doesn't affect how we render, just what we render (due to near and far clip planes)
+  // NOTE: We can't interrogate the default camera's position as it is not known initially (takes 1 frame
+  // for value to update).
+  // But we can determine the initial position using the same formula:
+  // distance = stage.height * 0.5 / tan(FOV * 0.5)
+
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+  RenderTask renderTask = taskList.GetTask(0u);
+  float fov = renderTask.GetCameraActor().GetFieldOfView();
+  mDefaultCameraDistance = (stageSize.height * 0.5f) / tanf(fov * 0.5f);
+
+  // Use a 1 frame delayed source position to determine the camera actor's position.
+  // This is necessary as the viewport is determined by the Magnifier's Actor's World position (which is computed
+  // at the end of the update cycle i.e. after constraints have been applied.)
+  //Property::Index propertySourcePositionDelayed = mCameraActor.RegisterProperty("delayedSourcePosition",   Vector3::ZERO);
+
+  constraint = Constraint::New<Vector3>( mCameraActor, Actor::Property::POSITION, CameraActorPositionConstraint(stageSize, mDefaultCameraDistance) );
+  constraint.AddSource( Source( mSourceActor, Actor::Property::WORLD_POSITION ) );
+  constraint.Apply();
+
+  // Apply constraint to render-task viewport position
+  constraint = Constraint::New<Vector2>( mTask, RenderTask::Property::VIEWPORT_POSITION, RenderTaskViewportPositionConstraint(stageSize) );
+  constraint.AddSource( Source( self, Actor::Property::WORLD_POSITION ) );
+  constraint.AddSource( Source( self, Actor::Property::SIZE ) );
+  constraint.AddSource( Source( self, Actor::Property::WORLD_SCALE ) );
+  constraint.Apply();
+
+  // Apply constraint to render-task viewport position
+  constraint = Constraint::New<Vector2>( mTask, RenderTask::Property::VIEWPORT_SIZE, RenderTaskViewportSizeConstraint() );
+  constraint.AddSource( Source( self, Actor::Property::SIZE ) );
+  constraint.AddSource( Source( self, Actor::Property::WORLD_SCALE ) );
+  constraint.Apply();
+}
+
+Magnifier::~Magnifier()
+{
+
+}
+
+void Magnifier::InitializeRenderTask()
+{
+  Stage stage = Stage::GetCurrent();
+
+  RenderTaskList taskList = stage.GetRenderTaskList();
+
+  mTask = taskList.CreateTask();
+  mTask.SetInputEnabled(false);
+  mTask.SetClearColor(Vector4(0.5f, 0.5f, 0.5f, 1.0f));
+  mTask.SetClearEnabled(true);
+
+  mCameraActor = CameraActor::New();
+  mCameraActor.SetType(Camera::FREE_LOOK);
+
+  stage.Add(mCameraActor);
+  mTask.SetCameraActor( mCameraActor );
+
+  SetFrameVisibility(true);
+}
+
+bool Magnifier::GetFrameVisibility() const
+{
+  return mFrame;
+}
+
+void Magnifier::SetFrameVisibility(bool visible)
+{
+  if(visible && !mFrame)
+  {
+    Actor self(Self());
+
+    mFrame = Actor::New( );
+    mFrame.SetInheritPosition(false);
+    mFrame.SetInheritScale(true);
+    mFrame.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
+    Vector3 sizeOffset(IMAGE_BORDER_INDENT*2.f - 2.f, IMAGE_BORDER_INDENT*2.f - 2.f, 0.0f);
+    mFrame.SetSizeModeFactor( sizeOffset );
+
+    Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+
+    Property::Map map;
+    map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::BORDER;
+    map[ Toolkit::BorderVisual::Property::COLOR ] = Color::WHITE;
+    map[ Toolkit::BorderVisual::Property::SIZE   ] = IMAGE_BORDER_INDENT;
+    Toolkit::Visual::Base borderVisual = visualFactory.CreateVisual( map );
+    Toolkit::GetImplementation(borderVisual).SetOnStage( mFrame );
+
+    Constraint constraint = Constraint::New<Vector3>( mFrame, Actor::Property::POSITION, EqualToConstraint() );
+    constraint.AddSource( ParentSource( Actor::Property::WORLD_POSITION ) );
+    constraint.Apply();
+
+    self.Add(mFrame);
+  }
+  else if(!visible && mFrame)
+  {
+    UnparentAndReset(mFrame);
+  }
+}
+
+void Magnifier::OnSizeSet(const Vector3& targetSize)
+{
+  // TODO: Once Camera/CameraActor properties function as proper animatable properties
+  // this code can disappear.
+  // whenever the size of the magnifier changes, the field of view needs to change
+  // to compensate for the new size of the viewport. this cannot be done within
+  // a constraint yet as Camera/CameraActor properties are not animatable/constrainable.
+  mActorSize = targetSize;
+  Update();
+
+  Control::OnSizeSet( targetSize );
+}
+
+float Magnifier::GetMagnificationFactor() const
+{
+  return mMagnificationFactor;
+}
+
+void Magnifier::SetMagnificationFactor(float value)
+{
+  mMagnificationFactor = value;
+  Update();
+}
+
+void Magnifier::Update()
+{
+  // TODO: Make Camera settings (fieldofview/aspectratio) as animatable constraints.
+
+  // should be updated when:
+  // Magnifier's world size/scale changes.
+  Actor self(Self());
+  Vector3 worldSize = mActorSize * self.GetCurrentWorldScale();
+
+  // Adjust field of view to scale content
+
+  // size.height / 2
+  // |------/
+  // |d    /
+  // |i   /
+  // |s  /
+  // |t /
+  // |./
+  // |/ <--- fov/2 radians.
+  //
+  const float fov = atanf( 0.5f * worldSize.height / mDefaultCameraDistance / mMagnificationFactor) * 2.0f;
+  mCameraActor.SetFieldOfView( fov );
+
+  // Adjust aspect ratio to compensate for rectangular viewports.
+  mCameraActor.SetAspectRatio( worldSize.width / worldSize.height );
+}
+
+void Magnifier::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Magnifier magnifier = Toolkit::Magnifier::DownCast( Dali::BaseHandle( object ) );
+
+  if( magnifier )
+  {
+    Magnifier& magnifierImpl( GetImpl( magnifier ) );
+    switch( index )
+    {
+      case Toolkit::Magnifier::Property::FRAME_VISIBILITY:
+      {
+        magnifierImpl.SetFrameVisibility( value.Get< bool >() );
+        break;
+      }
+      case Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR:
+      {
+        magnifierImpl.SetMagnificationFactor( value.Get< float >() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Magnifier::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Magnifier magnifier = Toolkit::Magnifier::DownCast( Dali::BaseHandle( object ) );
+
+  if( magnifier )
+  {
+    Magnifier& magnifierImpl( GetImpl( magnifier ) );
+    switch( index )
+    {
+      case Toolkit::Magnifier::Property::FRAME_VISIBILITY:
+      {
+        value = magnifierImpl.GetFrameVisibility();
+        break;
+      }
+      case Toolkit::Magnifier::Property::MAGNIFICATION_FACTOR:
+      {
+        value = magnifierImpl.GetMagnificationFactor();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/magnifier/magnifier-impl.h b/dali-toolkit/internal/controls/magnifier/magnifier-impl.h
new file mode 100644 (file)
index 0000000..c707523
--- /dev/null
@@ -0,0 +1,187 @@
+#ifndef DALI_TOOLKIT_INTERNAL_MAGNIFIER_H
+#define DALI_TOOLKIT_INTERNAL_MAGNIFIER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/render-tasks/render-task.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/magnifier/magnifier.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Magnifier;
+
+typedef IntrusivePtr<Magnifier>    MagnifierPtr;
+
+/**
+ * @copydoc Toolkit::Magnifier
+ */
+class Magnifier : public Control
+{
+public:
+
+  /**
+   * Create a new Magnifier.
+   * @return A public handle to the newly allocated Magnifier.
+   */
+  static Dali::Toolkit::Magnifier New();
+
+public:
+
+  /**
+   * @copydoc Toolkit::ImageView::SetSourceActor
+   */
+  void SetSourceActor(Actor actor);
+
+  /**
+   * Returns whether the frame is visible or not.
+   * @return true if frame is visible, false if not.
+   */
+  bool GetFrameVisibility() const;
+
+  /**
+   * Sets whether the frame part of the magnifier should be visible or not.
+   * @param[in] visible true to display frame, false to hide frame.
+   */
+  void SetFrameVisibility(bool visible);
+
+  /**
+   * Get the magnification factor of the magnifier
+   * The larger the value the larger the contents magnified.
+   * A value of 1.0f indications 1x magnification.
+   * @return Magnification factor is returned
+   */
+  float GetMagnificationFactor() const;
+
+  /**
+   * Set the magnification factor of the magnifier
+   * The larger the value the larger the contents magnified.
+   * A value of 1.0f indications 1x magnification.
+   * @param[in] value Magnification factor.
+   */
+  void SetMagnificationFactor(float value);
+
+  /**
+   * Update magnification
+   */
+  void Update();
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+protected:
+
+  /**
+   * Construct a new Magnifier.
+   */
+  Magnifier();
+
+  /**
+   * 2nd-phase initialization.
+   */
+  void Initialize();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Magnifier();
+
+private:
+
+  /**
+   * Initializes the render task required to render contents.
+   */
+  void InitializeRenderTask();
+
+private:
+
+  virtual void OnSizeSet(const Vector3& targetSize);
+
+private:
+
+  // Undefined
+  Magnifier(const Magnifier&);
+
+  // Undefined
+  Magnifier& operator=(const Magnifier& rhs);
+
+private:
+
+  RenderTask mTask;                             ///< Render Task to render the source actor contents.
+  CameraActor mCameraActor;                     ///< CameraActor attached to RenderTask
+  Actor mFrame;                                 ///< The Magnifier Frame
+  Actor mSourceActor;                           ///< Source Delegate Actor represents the source position to read.
+  float mDefaultCameraDistance;                 ///< Default RenderTask's camera distance from target.
+  Vector3 mActorSize;                           ///< The Actor size
+  float mMagnificationFactor;                   ///< Magnification factor 1.0f is default. same as content.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Magnifier& GetImpl(Toolkit::Magnifier& pub)
+{
+  DALI_ASSERT_ALWAYS(pub);
+
+  Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast<Toolkit::Internal::Magnifier&>(handle);
+}
+
+inline const Toolkit::Internal::Magnifier& GetImpl(const Toolkit::Magnifier& pub)
+{
+  DALI_ASSERT_ALWAYS(pub);
+
+  const Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::Magnifier&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_MAGNIFIER_H
diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp
new file mode 100644 (file)
index 0000000..3830f62
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 2017 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 "model3d-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraint-source.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Texture indices are constants.
+enum TextureIndex
+{
+  DIFFUSE_TEXTURE_INDEX,
+  NORMAL_TEXTURE_INDEX,
+  GLOSS_TEXTURE_INDEX
+};
+
+/**
+ * @brief Loads a texture from a file.
+ * @param[in] imageUrl The URL of the file
+ * @return A texture if loading succeeds, an empty handle otherwise
+ */
+Texture LoadTexture( const char* imageUrl )
+{
+  Texture texture;
+  Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
+  if( pixelBuffer )
+  {
+    texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+    PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+    texture.Upload( pixelData );
+    texture.GenerateMipmaps();
+  }
+
+  return texture;
+}
+
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::Model3dView::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Model3dView, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "geometryUrl",  STRING, GEOMETRY_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "materialUrl",  STRING, MATERIAL_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "imagesUrl",  STRING, IMAGES_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "illuminationType",  INTEGER, ILLUMINATION_TYPE)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture0Url",  STRING, TEXTURE0_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture1Url",  STRING, TEXTURE1_URL)
+DALI_PROPERTY_REGISTRATION( Toolkit, Model3dView, "texture2Url",  STRING, TEXTURE2_URL)
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Model3dView, "lightPosition",  VECTOR3, LIGHT_POSITION)
+
+DALI_TYPE_REGISTRATION_END()
+
+
+#define MAKE_SHADER(A)#A
+
+//  Diffuse illumination shader
+
+const char* SIMPLE_VERTEX_SHADER = MAKE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec2 aTexCoord;\n
+  attribute highp vec3 aNormal;\n
+  varying mediump vec3 vIllumination;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;\n
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 uLightPosition;\n
+
+  void main()\n
+  {\n
+    vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+    vec3 normal = uNormalMatrix * aNormal;\n
+    vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+
+    float lightDiffuse = max( dot( vecToLight, normal ), 0.0 );\n
+    vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
+
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* SIMPLE_FRAGMENT_SHADER = MAKE_SHADER(
+  precision mediump float;\n
+  varying mediump vec3 vIllumination;\n
+  uniform lowp vec4 uColor;\n
+
+  void main()\n
+  {\n
+    gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a);\n
+  }\n
+);
+
+//  Diffuse and specular illumination shader with albedo texture
+
+const char* VERTEX_SHADER = MAKE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec2 aTexCoord;\n
+  attribute highp vec3 aNormal;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vIllumination;\n
+  varying mediump float vSpecular;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 uLightPosition;\n
+
+  void main()
+  {\n
+    vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+    vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
+    vec3 normal = normalize(uNormalMatrix * aNormal);\n
+
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+    vec3 viewDir = normalize(-vertPos.xyz);
+
+    vec3 halfVector = normalize(viewDir + vecToLight);
+
+    float lightDiffuse = dot( vecToLight, normal );\n
+    lightDiffuse = max(0.0,lightDiffuse);\n
+    vIllumination = vec3(lightDiffuse * 0.5 + 0.5);\n
+
+    vec3 reflectDir = reflect(-vecToLight, normal);
+    vSpecular = pow( max(dot(reflectDir, viewDir), 0.0), 4.0 );
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = MAKE_SHADER(
+  precision mediump float;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vIllumination;\n
+  varying mediump float vSpecular;\n
+  uniform sampler2D sDiffuse;\n
+  uniform lowp vec4 uColor;\n
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb + vSpecular * 0.3, texture.a * uColor.a);\n
+  }\n
+);
+
+//  Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader
+
+const char* NRMMAP_VERTEX_SHADER = MAKE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec2 aTexCoord;\n
+  attribute highp vec3 aNormal;\n
+  attribute highp vec3 aTangent;\n
+  attribute highp vec3 aBiNormal;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vLightDirection;\n
+  varying mediump vec3 vHalfVector;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 uLightPosition;\n
+
+  void main()
+  {\n
+    vec4 vertexPosition = vec4(aPosition*min(uSize.x, uSize.y), 1.0);\n
+    vertexPosition = uObjectMatrix * vertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    vec4 vertPos = uModelView * vec4(aPosition.xyz, 1.0);\n
+    vec4 lightPos = uModelView * vec4(uLightPosition, 1.0);\n
+
+    vec3 tangent = normalize(uNormalMatrix * aTangent);
+    vec3 binormal = normalize(uNormalMatrix * aBiNormal);
+    vec3 normal = normalize(uNormalMatrix * aNormal);
+
+    vec3 vecToLight = normalize( lightPos.xyz - vertPos.xyz );\n
+    vLightDirection.x = dot(vecToLight, tangent);
+    vLightDirection.y = dot(vecToLight, binormal);
+    vLightDirection.z = dot(vecToLight, normal);
+
+    vec3 viewDir = normalize(-vertPos.xyz);
+    vec3 halfVector = normalize(viewDir + vecToLight);
+    vHalfVector.x = dot(halfVector, tangent);
+    vHalfVector.y = dot(halfVector, binormal);
+    vHalfVector.z = dot(halfVector, normal);
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* NRMMAP_FRAGMENT_SHADER = MAKE_SHADER(
+  precision mediump float;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vLightDirection;\n
+  varying mediump vec3 vHalfVector;\n
+  uniform sampler2D sDiffuse;\n
+  uniform sampler2D sNormal;\n
+  uniform sampler2D sGloss;\n
+  uniform lowp vec4 uColor;\n
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
+    vec4 glossMap = texture2D( sGloss, vTexCoord );\n
+
+    float lightDiffuse = max( 0.0, dot( normal, normalize(vLightDirection) ) );\n
+    lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
+
+    float shininess = pow (max (dot (normalize( vHalfVector ), normal), 0.0), 16.0)  ;
+
+    gl_FragColor = vec4( texture.rgb * uColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a);\n
+  }\n
+);
+
+
+} // anonymous namespace
+
+using namespace Dali;
+
+Model3dView::Model3dView()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
+{
+  mIlluminationType = Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP;
+
+  mCameraFOV = Math::PI_OVER_180 * 45.f;
+
+  mControlSize = Vector2(100.,100.);
+}
+
+Model3dView::~Model3dView()
+{
+}
+
+Toolkit::Model3dView Model3dView::New()
+{
+  Model3dView* impl = new Model3dView();
+
+  Dali::Toolkit::Model3dView handle = Dali::Toolkit::Model3dView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void Model3dView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
+
+  if( model3dView )
+  {
+    Model3dView& impl( GetImpl( model3dView ) );
+    switch( index )
+    {
+      case Toolkit::Model3dView::Property::GEOMETRY_URL:
+      {
+        if( value.Get(impl.mObjUrl) )
+        {
+          impl.LoadGeometry();
+          impl.CreateGeometry();
+        }
+        break;
+      }
+      case Toolkit::Model3dView::Property::MATERIAL_URL:
+      {
+        if( value.Get(impl.mTextureSetUrl) )
+        {
+          impl.LoadMaterial();
+          impl.CreateMaterial();
+          impl.LoadTextures();
+        }
+        break;
+      }
+      case Toolkit::Model3dView::Property::IMAGES_URL:
+      {
+        if( value.Get(impl.mImagesUrl) )
+        {
+          impl.LoadTextures();
+        }
+        break;
+      }
+      case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
+      {
+        int illuminationType;
+        if( value.Get(illuminationType) )
+        {
+          impl.mIlluminationType = Toolkit::Model3dView::IlluminationType(illuminationType);
+          impl.CreateGeometry();
+          impl.CreateMaterial();
+          impl.LoadTextures();
+        }
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE0_URL:
+      {
+        value.Get(impl.mTexture0Url);
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE1_URL:
+      {
+        value.Get(impl.mTexture1Url);
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE2_URL:
+      {
+        value.Get(impl.mTexture2Url);
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Model3dView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Model3dView model3dView = Toolkit::Model3dView::DownCast( Dali::BaseHandle( object ) );
+
+  if( model3dView )
+  {
+    Model3dView& impl( GetImpl( model3dView ) );
+    switch( index )
+    {
+      case Toolkit::Model3dView::Property::GEOMETRY_URL:
+      {
+        value = impl.mObjUrl;
+        break;
+      }
+      case Toolkit::Model3dView::Property::MATERIAL_URL:
+      {
+        value = impl.mTextureSetUrl;
+        break;
+      }
+      case Toolkit::Model3dView::Property::IMAGES_URL:
+      {
+        value = impl.mImagesUrl;
+        break;
+      }
+      case Toolkit::Model3dView::Property::ILLUMINATION_TYPE:
+      {
+        value = int(impl.mIlluminationType);
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE0_URL:
+      {
+        value = impl.mTexture0Url;
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE1_URL:
+      {
+        value = impl.mTexture1Url;
+        break;
+      }
+      case Toolkit::Model3dView::Property::TEXTURE2_URL:
+      {
+        value = impl.mTexture2Url;
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+/////////////////////////////////////////////////////////////
+
+
+void Model3dView::OnStageConnection( int depth )
+{
+  CustomActor self = Self();
+  self.AddRenderer( mRenderer );
+
+  if( mObjLoader.IsSceneLoaded() )
+  {
+    mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
+
+    CreateMaterial();
+    LoadTextures();
+
+    mRenderer.SetGeometry( mMesh );
+
+    //create constraint for lightPosition Property with uLightPosition in the shader
+    Vector3 lightPosition( 0, 0, 0 );
+    Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
+    Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
+    constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
+    constraint.Apply();
+  }
+
+  Control::OnStageConnection( depth );
+}
+
+///////////////////////////////////////////////////////////
+//
+// Private methods
+//
+
+void Model3dView::OnInitialize()
+{
+  //Create empty versions of the geometry and material so we always have a Renderer
+  Geometry mesh = Geometry::New();
+  Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  mRenderer = Renderer::New( mesh, shader );
+
+}
+
+void Model3dView::LoadGeometry()
+{
+  //Load file in adaptor
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if (FileLoader::ReadFile(mObjUrl,fileSize,fileContent,FileLoader::TEXT))
+  {
+    mObjLoader.ClearArrays();
+    mObjLoader.LoadObject(fileContent.Begin(), fileSize);
+
+    //Get size information from the obj loaded
+    mSceneCenter = mObjLoader.GetCenter();
+    mSceneSize = mObjLoader.GetSize();
+  }
+  else
+  {
+    //Error
+  }
+}
+
+void Model3dView::LoadMaterial()
+{
+  //Load file in adaptor
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if( FileLoader::ReadFile(mTextureSetUrl, fileSize, fileContent, FileLoader::TEXT) )
+  {
+    mObjLoader.LoadMaterial(fileContent.Begin(), fileSize, mTexture0Url, mTexture1Url, mTexture2Url);
+  }
+  else
+  {
+    //Error
+  }
+}
+
+void Model3dView::Load()
+{
+  LoadGeometry();
+  LoadMaterial();
+}
+
+void Model3dView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  UpdateView();
+}
+
+void Model3dView::UpdateView()
+{
+  if( mObjLoader.IsSceneLoaded() )
+  {
+    //The object will always be centred
+
+    Matrix scaleMatrix;
+    scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
+
+    mShader.RegisterProperty( "uObjectMatrix", scaleMatrix );
+  }
+}
+
+void Model3dView::CreateGeometry()
+{
+  if( mObjLoader.IsSceneLoaded() )
+  {
+    mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
+
+    if( mRenderer )
+    {
+      mRenderer.SetGeometry( mMesh );
+      mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+      mRenderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
+    }
+  }
+}
+
+void Model3dView::UpdateShaderUniforms()
+{
+  if( mShader )
+  {
+    //Update shader related info, uniforms, etc. for the new shader
+    UpdateView();
+
+    Vector3 lightPosition( 0, 0, 0 );
+    Dali::Property::Index lightProperty = mShader.RegisterProperty( "uLightPosition", lightPosition );
+
+    CustomActor self = Self();
+
+    //create constraint for lightPosition Property with uLightPosition in the shader
+    if( lightProperty )
+    {
+      Constraint constraint = Constraint::New<Vector3>( mShader, lightProperty, EqualToConstraint() );
+      constraint.AddSource( Source( self, Toolkit::Model3dView::Property::LIGHT_POSITION ) );
+      constraint.Apply();
+    }
+  }
+}
+
+void Model3dView::CreateMaterial()
+{
+  if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
+  {
+    if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) )
+    {
+      mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER );
+    }
+    else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
+             mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+    {
+      mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    }
+    else
+    {
+      mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+    }
+  }
+  else
+  {
+    mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  }
+
+  mTextureSet = TextureSet::New();
+
+  if( mRenderer )
+  {
+    mRenderer.SetTextures( mTextureSet );
+    mRenderer.SetShader( mShader );
+    mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
+  }
+
+  UpdateShaderUniforms();
+}
+
+void Model3dView::LoadTextures()
+{
+  if( !mTextureSet )
+  {
+    return;
+  }
+
+  Sampler sampler = Sampler::New();
+  sampler.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR );
+
+  // Setup diffuse texture.
+  if( !mTexture0Url.empty() && ( mIlluminationType != Toolkit::Model3dView::DIFFUSE ) )
+  {
+    std::string imageUrl = mImagesUrl + mTexture0Url;
+
+    //Load textures
+    Texture diffuseTexture = LoadTexture( imageUrl.c_str() );
+    if( diffuseTexture )
+    {
+      mTextureSet.SetTexture( DIFFUSE_TEXTURE_INDEX, diffuseTexture );
+      mTextureSet.SetSampler( DIFFUSE_TEXTURE_INDEX, sampler );
+    }
+  }
+
+  if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  {
+    // Setup normal map texture.
+    if( !mTexture1Url.empty() )
+    {
+      std::string imageUrl = mImagesUrl + mTexture1Url;
+
+      //Load textures
+      Texture normalTexture = LoadTexture( imageUrl.c_str() );
+      if( normalTexture )
+      {
+        mTextureSet.SetTexture( NORMAL_TEXTURE_INDEX, normalTexture );
+        mTextureSet.SetSampler( NORMAL_TEXTURE_INDEX, sampler );
+      }
+    }
+    if( !mTexture2Url.empty() )
+    {
+      // Setup gloss map texture.
+      std::string imageUrl = mImagesUrl + mTexture2Url;
+
+      //Load textures
+      Texture glossTexture = LoadTexture( imageUrl.c_str() );
+      if( glossTexture )
+      {
+        mTextureSet.SetTexture( GLOSS_TEXTURE_INDEX, glossTexture );
+        mTextureSet.SetSampler( GLOSS_TEXTURE_INDEX, sampler );
+      }
+    }
+  }
+}
+
+int Model3dView::GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType )
+{
+  int objectProperties = 0;
+
+  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ||
+      illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  {
+    objectProperties |= ObjLoader::TEXTURE_COORDINATES;
+  }
+
+  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  {
+    objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
+  }
+
+  return objectProperties;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h
new file mode 100644 (file)
index 0000000..51388f3
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef DALI_TOOLKIT_INTERNAL_MODEL3D_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_MODEL3D_VIEW_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class Model3dView;
+
+namespace Internal
+{
+/**
+ * @brief Impl class for Model3dView.
+ *
+ * All the geometry loaded with the control is automatically centered and scaled to fit
+ * the size of all the other controls. So the max is (0.5,0.5) and the min is (-0.5,-0.5)
+*/
+class Model3dView : public Control
+{
+public:
+
+  /**
+   * @brief Create a new Model3dView.
+   *
+   * @return A public handle to the newly allocated Model3dView.
+   */
+  static Toolkit::Model3dView New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   *
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @copydoc Control::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @brief Called to load both geometry (.obj) and material (.mtl) files
+   *
+   */
+  void Load();
+
+protected:
+
+  /**
+   * @brief Construct a new Model3dView.
+   */
+  Model3dView();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Model3dView();
+
+private:
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+private:
+
+  /**
+   * @brief Load geometry (.obj) from file
+   */
+  void LoadGeometry();
+
+  /**
+   * @brief Load material (.mtl) from file
+   */
+  void LoadMaterial();
+
+  /**
+   * @brief Create Geometry class from the loaded geometry
+   */
+  void CreateGeometry();
+
+  /**
+   * @brief Create Material and Shader classes from the loaded material
+   */
+  void CreateMaterial();
+
+  /**
+   * @brief Load samplers and add them to Material
+   */
+  void LoadTextures();
+
+  /**
+   * @brief Set matrix to shader to orientate geometry
+   */
+  void UpdateView();
+
+  /**
+   * @brief Update shader uniforms
+   */
+  void UpdateShaderUniforms();
+
+
+  /*
+   * @brief Given a specific shader type, find out which properties are necessary for it.
+   *
+   * @param[in] illuminationType The type of shader we intend to use.
+   * @return A bitmask of the properties we require to be loaded to use the given shader.
+   */
+  int GetShaderProperties( Toolkit::Model3dView::IlluminationType illuminationType );
+
+
+  ObjLoader mObjLoader;
+
+  //Properties
+  std::string mObjUrl;
+  std::string mTextureSetUrl;
+  std::string mImagesUrl;
+  std::string mTexture0Url;
+  std::string mTexture1Url;
+  std::string mTexture2Url;
+  Vector3 mLightPosition;
+  float mCameraFOV;
+  Toolkit::Model3dView::IlluminationType mIlluminationType;
+
+  //Size
+  Vector2 mControlSize;
+  Vector3 mSceneCenter;
+  Vector3 mSceneSize;
+
+  //Render members
+  Shader mShader;
+  TextureSet mTextureSet;
+  Geometry mMesh;
+  Renderer mRenderer;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::Model3dView& GetImpl( Toolkit::Model3dView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::Model3dView&>(handle);
+}
+
+inline const Toolkit::Internal::Model3dView& GetImpl( const Toolkit::Model3dView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::Model3dView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_MODEL_VIEW_H
diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp b/dali-toolkit/internal/controls/model3d-view/obj-loader.cpp
new file mode 100644 (file)
index 0000000..fca57b4
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2017 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 "obj-loader.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <string>
+#include <sstream>
+#include <string.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+  const int MAX_POINT_INDICES = 4;
+}
+using namespace Dali;
+
+ObjLoader::ObjLoader()
+{
+  mSceneLoaded = false;
+  mMaterialLoaded = false;
+  mHasTexturePoints = false;
+  mHasDiffuseMap = false;
+  mHasNormalMap = false;
+  mHasSpecularMap = false;
+  mSceneAABB.Init();
+}
+
+ObjLoader::~ObjLoader()
+{
+  ClearArrays();
+}
+
+bool ObjLoader::IsSceneLoaded()
+{
+  return mSceneLoaded;
+}
+
+bool ObjLoader::IsMaterialLoaded()
+{
+  return mMaterialLoaded;
+}
+
+void ObjLoader::CalculateHardFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
+                                          Dali::Vector<Vector3>& normals )
+{
+  int numFaceVertices = 3 * triangles.Size();  //Vertex per face, as each point has different normals for each face.
+  int normalIndex = 0;  //Tracks progress through the array of normals.
+
+  normals.Clear();
+  normals.Resize( numFaceVertices );
+
+  //For each triangle, calculate the normal by crossing two vectors on the triangle's plane.
+  for( unsigned long i = 0; i < triangles.Size(); i++ )
+  {
+    //Triangle vertices.
+    const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+    const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+    const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
+
+    //Triangle edges.
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
+
+    //Using edges as vectors on the plane, cross to get the normal.
+    Vector3 normalVector = edge1.Cross(edge2);
+    normalVector.Normalize();
+
+    //Assign normals to points.
+    for( unsigned long j = 0; j < 3; j++, normalIndex++ )
+    {
+      triangles[i].normalIndex[j] = normalIndex;
+      normals[normalIndex] = normalVector;
+    }
+  }
+}
+
+void ObjLoader::CalculateSoftFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
+                                          Dali::Vector<Vector3>& normals )
+{
+  int normalIndex = 0;  //Tracks progress through the array of normals.
+
+  normals.Clear();
+  normals.Resize( vertices.Size() );  //One (averaged) normal per point.
+
+  //For each triangle, calculate the normal by crossing two vectors on the triangle's plane
+  //We then add the triangle's normal to the cumulative normals at each point of it
+  for( unsigned long i = 0; i < triangles.Size(); i++ )
+  {
+    //Triangle vertices.
+    const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+    const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+    const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
+
+    //Triangle edges.
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
+
+    //Using edges as vectors on the plane, cross to get the normal.
+    Vector3 normalVector = edge1.Cross(edge2);
+
+    //Add this triangle's normal to the cumulative normal of each constituent point and set the index of the normal accordingly.
+    for( unsigned long j = 0; j < 3; j++, normalIndex++ )
+    {
+      triangles[i].normalIndex[j] = triangles[i].pointIndex[j]; //Normal index matches up to vertex index, as one normal per vertex.
+      normals[triangles[i].normalIndex[j]] += normalVector;
+    }
+  }
+
+  //Normalise the normals.
+  for( unsigned long i = 0; i < normals.Size(); i++ )
+  {
+    normals[i].Normalize();
+  }
+}
+
+//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
+void ObjLoader::CalculateTangentFrame()
+{
+  //Reset tangent and bitangent vectors to hold new values.
+  mTangents.Clear();
+  mBiTangents.Clear();
+  mTangents.Resize( mPoints.Size() );
+  mBiTangents.Resize( mPoints.Size() );
+
+  //For each triangle, calculate the tangent vector and then add it to the total tangent vector of each point.
+  for ( unsigned long a = 0; a < mTriangles.Size(); a++ )
+  {
+    Vector3 tangentVector;
+
+    const Vector3& v0 = mPoints[mTriangles[a].pointIndex[0]];
+    const Vector3& v1 = mPoints[mTriangles[a].pointIndex[1]];
+    const Vector3& v2 = mPoints[mTriangles[a].pointIndex[2]];
+
+    Vector3 edge1 = v1 - v0;
+    Vector3 edge2 = v2 - v0;
+
+    const Vector2& w0 = mTextures[mTriangles[a].textureIndex[0]];
+    const Vector2& w1 = mTextures[mTriangles[a].textureIndex[1]];
+    const Vector2& w2 = mTextures[mTriangles[a].textureIndex[2]];
+
+    float deltaU1 = w1.x - w0.x;
+    float deltaV1 = w1.y - w0.y;
+    float deltaU2 = w2.x - w0.x;
+    float deltaV2 = w2.y - w0.y;
+
+    float f = 1.0f / (deltaU1 * deltaV2 - deltaU2 * deltaV1);
+
+    tangentVector.x = f * ( deltaV2 * edge1.x - deltaV1 * edge2.x );
+    tangentVector.y = f * ( deltaV2 * edge1.y - deltaV1 * edge2.y );
+    tangentVector.z = f * ( deltaV2 * edge1.z - deltaV1 * edge2.z );
+
+    mTangents[mTriangles[a].pointIndex[0]] += tangentVector;
+    mTangents[mTriangles[a].pointIndex[1]] += tangentVector;
+    mTangents[mTriangles[a].pointIndex[2]] += tangentVector;
+  }
+
+  //Orthogonalize tangents and set binormals.
+  for ( unsigned long a = 0; a < mTangents.Size(); a++ )
+  {
+    const Vector3& n = mNormals[a];
+    const Vector3& t = mTangents[a];
+
+    // Gram-Schmidt orthogonalize
+    mTangents[a] = t - n * n.Dot(t);
+    mTangents[a].Normalize();
+
+    mBiTangents[a] = mNormals[a].Cross( mTangents[a] );
+  }
+}
+
+void ObjLoader::CenterAndScale( bool center, Dali::Vector<Vector3>& points )
+{
+  BoundingVolume newAABB;
+
+  Vector3 sceneSize = GetSize();
+
+  float biggestDimension = sceneSize.x;
+  if( sceneSize.y > biggestDimension )
+  {
+    biggestDimension = sceneSize.y;
+  }
+  if( sceneSize.z > biggestDimension )
+  {
+    biggestDimension = sceneSize.z;
+  }
+
+  newAABB.Init();
+  for( unsigned int ui = 0; ui < points.Size(); ++ui )
+  {
+    points[ui] = points[ui] - GetCenter();
+    points[ui] = points[ui] / biggestDimension;
+    newAABB.ConsiderNewPointInVolume(points[ui]);
+  }
+
+  mSceneAABB = newAABB;
+}
+
+void ObjLoader::CreateGeometryArray( Dali::Vector<Vertex> & vertices,
+                                     Dali::Vector<Vector2> & textures,
+                                     Dali::Vector<VertexExt> & verticesExt,
+                                     Dali::Vector<unsigned short> & indices,
+                                     bool useSoftNormals )
+{
+  //We must calculate the tangents and bitangents if they weren't supplied, or if they don't match up.
+  bool mustCalculateTangents = mTangents.Size() == 0 || mBiTangents.Size() == 0 ||
+                               mTangents.Size() != mBiTangents.Size() || mTangents.Size() != mNormals.Size() ||
+                               mBiTangents.Size() != mNormals.Size();
+
+  //However, we don't need to do this if the object doesn't use textures to begin with.
+  mustCalculateTangents &= mHasTexturePoints;
+
+  //We also have to recalculate the normals if we need to calculate tangents,
+  // as we need just one normal, tangent and bitangent per vertex, rather than the supplied per-face vertices.
+  //Alternatively, we need to calculate the normals if there weren't any to begin with.
+  if( mNormals.Size() == 0 || mustCalculateTangents )
+  {
+    if( useSoftNormals || mustCalculateTangents )
+    {
+      CalculateSoftFaceNormals( mPoints, mTriangles, mNormals );
+    }
+    else
+    {
+      CalculateHardFaceNormals( mPoints, mTriangles, mNormals );
+    }
+  }
+
+  //TODO: Use a better function to calculate tangents
+  if( mHasTexturePoints && mustCalculateTangents )
+  {
+    CalculateTangentFrame();
+  }
+
+  bool mapsCorrespond; //True if the sizes of the arrays necessary for the object agree.
+
+  if ( mHasTexturePoints )
+  {
+    mapsCorrespond = ( mPoints.Size() == mTextures.Size() ) && ( mTextures.Size() == mNormals.Size() );
+  }
+  else
+  {
+    mapsCorrespond = ( mPoints.Size() == mNormals.Size() );
+  }
+
+  //Check the number of points textures and normals
+  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[ui] = vertex;
+
+      if ( mHasTexturePoints )
+      {
+        textures[ui] = Vector2();
+        verticesExt[ui] = VertexExt();
+      }
+    }
+
+    int indiceIndex = 0;
+
+    //We copy the indices
+    for ( unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
+    {
+      for ( int j = 0 ; j < 3 ; ++j )
+      {
+        indices[indiceIndex] = mTriangles[ui].pointIndex[j];
+        indiceIndex++;
+
+        vertices[mTriangles[ui].pointIndex[j]].normal = mNormals[mTriangles[ui].normalIndex[j]];
+
+        if ( mHasTexturePoints )
+        {
+          textures[mTriangles[ui].pointIndex[j]] = mTextures[mTriangles[ui].textureIndex[j]];
+          verticesExt[mTriangles[ui].pointIndex[j]].tangent = mTangents[mTriangles[ui].normalIndex[j]];
+          verticesExt[mTriangles[ui].pointIndex[j]].bitangent = mBiTangents[mTriangles[ui].normalIndex[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 ( int j = 0 ; j < 3 ; ++j )
+      {
+        Vertex vertex;
+        vertex.position = mPoints[mTriangles[ui].pointIndex[j]];
+        vertex.normal = mNormals[mTriangles[ui].normalIndex[j]];
+        vertices[index] = vertex;
+
+        if ( mHasTexturePoints )
+        {
+          textures[index] = mTextures[mTriangles[ui].textureIndex[j]];
+          VertexExt vertexExt;
+          vertexExt.tangent = mTangents[mTriangles[ui].normalIndex[j]];
+          vertexExt.bitangent = mBiTangents[mTriangles[ui].normalIndex[j]];
+          verticesExt[index] = vertexExt;
+        }
+
+        index++;
+      }
+    }
+  }
+}
+
+bool ObjLoader::LoadObject( char* objBuffer, std::streampos fileSize )
+{
+  Vector3 point;
+  Vector2 texture;
+  std::string vet[MAX_POINT_INDICES], name;
+  int ptIdx[MAX_POINT_INDICES];
+  int nrmIdx[MAX_POINT_INDICES];
+  int texIdx[MAX_POINT_INDICES];
+  TriIndex triangle,triangle2;
+  int pntAcum = 0, texAcum = 0, nrmAcum = 0;
+  bool iniObj = false;
+  bool hasTexture = false;
+  int face = 0;
+
+  //Init AABB for the file
+  mSceneAABB.Init();
+
+  std::string strMatActual;
+
+  std::string input( objBuffer, fileSize );
+  std::istringstream ss(input);
+  ss.imbue( std::locale( "C" ) );
+
+
+  std::string line;
+  std::getline( ss, line );
+
+  while ( std::getline( ss, line ) )
+  {
+    std::istringstream isline( line, std::istringstream::in );
+    std::string tag;
+
+    isline >> tag;
+
+    if ( tag == "v" )
+    {
+      //Two different objects in the same file
+      isline >> point.x;
+      isline >> point.y;
+      isline >> point.z;
+      mPoints.PushBack( point );
+
+      mSceneAABB.ConsiderNewPointInVolume( point );
+    }
+    else if ( tag == "vn" )
+    {
+      isline >> point.x;
+      isline >> point.y;
+      isline >> point.z;
+
+      mNormals.PushBack( point );
+    }
+    else if ( tag == "#_#tangent" )
+    {
+      isline >> point.x;
+      isline >> point.y;
+      isline >> point.z;
+
+      mTangents.PushBack( point );
+    }
+    else if ( tag == "#_#binormal" )
+    {
+      isline >> point.x;
+      isline >> point.y;
+      isline >> point.z;
+
+      mBiTangents.PushBack( point );
+    }
+    else if ( tag == "vt" )
+    {
+      isline >> texture.x;
+      isline >> texture.y;
+
+      texture.y = 1.0-texture.y;
+      mTextures.PushBack( texture );
+    }
+    else if ( tag == "#_#vt1" )
+    {
+      isline >> texture.x;
+      isline >> texture.y;
+
+      texture.y = 1.0-texture.y;
+      mTextures2.PushBack( texture );
+    }
+    else if ( tag == "s" )
+    {
+    }
+    else if ( tag == "f" )
+    {
+      if ( !iniObj )
+      {
+        //name assign
+
+        iniObj = true;
+      }
+
+      int numIndices = 0;
+      while( ( numIndices < MAX_POINT_INDICES ) && ( isline >> vet[numIndices] ) )
+      {
+        numIndices++;
+      }
+
+      //Hold slashes that separate attributes of the same point.
+      char separator;
+      char separator2;
+
+      const char * subString; //A pointer to the position in the string as we move through it.
+
+      subString = strstr( vet[0].c_str(),"/" ); //Search for the first '/'
+
+      if( subString )
+      {
+        if( subString[1] == '/' ) // Of the form A//C, so has points and normals but no texture coordinates.
+        {
+          for( int i = 0 ; i < numIndices; i++)
+          {
+            std::istringstream isindex( vet[i] );
+            isindex >> ptIdx[i] >> separator >> separator2 >> nrmIdx[i];
+            texIdx[i] = 0;
+          }
+        }
+        else if( strstr( subString, "/" ) ) // Of the form A/B/C, so has points, textures and normals.
+        {
+          for( int i = 0 ; i < numIndices; i++ )
+          {
+            std::istringstream isindex( vet[i] );
+            isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i];
+          }
+
+          hasTexture = true;
+        }
+        else // Of the form A/B, so has points and textures but no normals.
+        {
+          for( int i = 0 ; i < numIndices; i++ )
+          {
+            std::istringstream isindex( vet[i] );
+            isindex >> ptIdx[i] >> separator >> texIdx[i];
+            nrmIdx[i] = 0;
+          }
+
+          hasTexture = true;
+        }
+      }
+      else // Simply of the form A, as in, point indices only.
+      {
+        for( int i = 0 ; i < numIndices; i++ )
+        {
+          std::istringstream isindex( vet[i] );
+          isindex >> ptIdx[i];
+          texIdx[i] = 0;
+          nrmIdx[i] = 0;
+        }
+      }
+
+      //If it is a triangle
+      if( numIndices == 3 )
+      {
+        for( int i = 0 ; i < 3; i++ )
+        {
+          triangle.pointIndex[i] = ptIdx[i] - 1 - pntAcum;
+          triangle.normalIndex[i] = nrmIdx[i] - 1 - nrmAcum;
+          triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
+        }
+        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++ )
+        {
+          triangle.pointIndex[i] = ptIdx[i] - 1 - pntAcum;
+          triangle.normalIndex[i] = nrmIdx[i] - 1 - nrmAcum;
+          triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
+        }
+        mTriangles.PushBack( triangle );
+        face++;
+
+        for( int i = 0 ; i < 3; i++ )
+        {
+          int idx = ( i + 2 ) % numIndices;
+          triangle2.pointIndex[i] = ptIdx[idx] - 1 - pntAcum;
+          triangle2.normalIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
+          triangle2.textureIndex[i] = texIdx[idx] - 1 - texAcum;
+        }
+        mTriangles.PushBack( triangle2 );
+        face++;
+      }
+    }
+    else if ( tag == "usemtl" )
+    {
+      isline >> strMatActual;
+    }
+    else if ( tag == "mtllib" )
+    {
+      isline >> strMatActual;
+    }
+    else if ( tag == "g" )
+    {
+      isline >> name;
+    }
+  }
+
+  if ( iniObj )
+  {
+    CenterAndScale( true, mPoints );
+    mSceneLoaded = true;
+    mHasTexturePoints = hasTexture;
+    return true;
+  }
+
+  return false;
+}
+
+void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl,
+                              std::string& normalTextureUrl, std::string& glossTextureUrl )
+{
+  float fR,fG,fB;
+
+  std::string info;
+
+  std::string input( objBuffer, fileSize );
+  std::istringstream ss(input);
+  ss.imbue(std::locale("C"));
+
+  std::string line;
+  std::getline( ss, line );
+
+  while ( std::getline( ss, line ) )
+  {
+    std::istringstream isline( line, std::istringstream::in );
+    std::string tag;
+
+    isline >> tag;
+
+    if ( tag == "newmtl" )  //name of the material
+    {
+      isline >> info;
+    }
+    else if ( tag == "Ka" ) //ambient color
+    {
+      isline >> fR >> fG >> fB;
+    }
+    else if ( tag == "Kd" ) //diffuse color
+    {
+      isline >> fR >> fG >> fB;
+    }
+    else if ( tag == "Ks" ) //specular color
+    {
+      isline >> fR >> fG >> fB;
+    }
+    else if ( tag == "Tf" ) //color
+    {
+    }
+    else if ( tag == "Ni" )
+    {
+    }
+    else if ( tag == "map_Kd" )
+    {
+      isline >> info;
+      diffuseTextureUrl = info;
+      mHasDiffuseMap = true;
+    }
+    else if ( tag == "bump" )
+    {
+      isline >> info;
+      normalTextureUrl = info;
+      mHasNormalMap = true;
+    }
+    else if ( tag == "map_Ks" )
+    {
+      isline >> info;
+      glossTextureUrl = info;
+      mHasSpecularMap = true;
+    }
+  }
+
+  mMaterialLoaded = true;
+}
+
+Geometry ObjLoader::CreateGeometry( int objectProperties, bool useSoftNormals )
+{
+  Geometry surface = Geometry::New();
+
+  Dali::Vector<Vertex> vertices;
+  Dali::Vector<Vector2> textures;
+  Dali::Vector<VertexExt> verticesExt;
+  Dali::Vector<unsigned short> indices;
+
+  CreateGeometryArray( vertices, textures, verticesExt, indices, useSoftNormals );
+
+  //All vertices need at least Position and Normal
+  Property::Map vertexFormat;
+  vertexFormat["aPosition"] = Property::VECTOR3;
+  vertexFormat["aNormal"] = Property::VECTOR3;
+  PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat );
+  surfaceVertices.SetData( &vertices[0], vertices.Size() );
+  surface.AddVertexBuffer( surfaceVertices );
+
+  //Some need texture coordinates
+  if( ( objectProperties & TEXTURE_COORDINATES ) && mHasTexturePoints && mHasDiffuseMap )
+  {
+    Property::Map textureFormat;
+    textureFormat["aTexCoord"] = Property::VECTOR2;
+    PropertyBuffer extraVertices = PropertyBuffer::New( textureFormat );
+    extraVertices.SetData( &textures[0], textures.Size() );
+
+    surface.AddVertexBuffer( extraVertices );
+  }
+
+  //Some need tangent and bitangent
+  if( ( objectProperties & TANGENTS ) && ( objectProperties & BINORMALS ) && mHasTexturePoints )
+  {
+    Property::Map vertexExtFormat;
+    vertexExtFormat["aTangent"] = Property::VECTOR3;
+    vertexExtFormat["aBiNormal"] = Property::VECTOR3;
+    PropertyBuffer extraVertices = PropertyBuffer::New( vertexExtFormat );
+    extraVertices.SetData( &verticesExt[0], verticesExt.Size() );
+
+    surface.AddVertexBuffer( extraVertices );
+  }
+
+  //If indices are required, we set them.
+  if ( indices.Size() )
+  {
+    surface.SetIndexBuffer ( &indices[0], indices.Size() );
+  }
+
+  return surface;
+}
+
+Vector3 ObjLoader::GetCenter()
+{
+  Vector3 center = GetSize() * 0.5 + mSceneAABB.pointMin;
+  return center;
+}
+
+Vector3 ObjLoader::GetSize()
+{
+  Vector3 size = mSceneAABB.pointMax - mSceneAABB.pointMin;
+  return size;
+}
+
+void ObjLoader::ClearArrays()
+{
+  mPoints.Clear();
+  mTextures.Clear();
+  mNormals.Clear();
+  mTangents.Clear();
+  mBiTangents.Clear();
+
+  mTriangles.Clear();
+
+  mSceneLoaded = false;
+}
+
+bool ObjLoader::IsTexturePresent()
+{
+  return mHasTexturePoints;
+}
+
+bool ObjLoader::IsDiffuseMapPresent()
+{
+  return mHasDiffuseMap;
+}
+
+bool ObjLoader::IsNormalMapPresent()
+{
+  return mHasNormalMap;
+}
+
+bool ObjLoader::IsSpecularMapPresent()
+{
+  return mHasSpecularMap;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/model3d-view/obj-loader.h b/dali-toolkit/internal/controls/model3d-view/obj-loader.h
new file mode 100644 (file)
index 0000000..78de233
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H
+#define DALI_TOOLKIT_INTERNAL_OBJ_LOADER_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/renderer.h>
+#include <limits>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class ObjLoader;
+
+namespace Internal
+{
+class ObjLoader
+{
+public:
+
+  struct TriIndex
+  {
+    int pointIndex[3];
+    int normalIndex[3];
+    int textureIndex[3];
+  };
+
+  struct Vertex
+  {
+    Vertex()
+    {}
+
+    Vertex( const Vector3& position, const Vector3& normal, const Vector2& textureCoord )
+    : position( position ), normal( normal )
+    {}
+
+    Vector3 position;
+    Vector3 normal;
+  };
+
+  struct VertexExt
+  {
+    VertexExt()
+    {}
+
+    VertexExt( const Vector3& tangent, const Vector3& binormal )
+    : tangent( tangent), bitangent( binormal )
+    {}
+
+    Vector3 tangent;
+    Vector3 bitangent;
+  };
+
+  struct BoundingVolume
+  {
+    void Init()
+    {
+      pointMin = Vector3( std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() );
+      pointMax = Vector3( std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min() );
+    }
+
+    void ConsiderNewPointInVolume( const Vector3& position )
+    {
+      pointMin.x = std::min( position.x, pointMin.x );
+      pointMin.y = std::min( position.y, pointMin.y );
+      pointMin.z = std::min( position.z, pointMin.z );
+
+      pointMax.x = std::max( position.x, pointMax.x );
+      pointMax.y = std::max( position.y, pointMax.y );
+      pointMax.z = std::max( position.z, pointMax.z );
+    }
+
+    Vector3 pointMin;
+    Vector3 pointMax;
+  };
+
+  //Defines bit masks to declare which properties are needed by anyone requesting a geometry.
+  enum ObjectProperties
+  {
+    TEXTURE_COORDINATES = 1 << 0,
+    TANGENTS = 1 << 1,
+    BINORMALS = 1 << 2
+  };
+
+  ObjLoader();
+  virtual ~ObjLoader();
+
+  bool      IsSceneLoaded();
+  bool      IsMaterialLoaded();
+
+  bool      LoadObject( char* objBuffer, std::streampos fileSize );
+
+  void      LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl,
+                          std::string& normalTextureUrl, std::string& glossTextureUrl );
+
+  Geometry  CreateGeometry( int objectProperties, bool useSoftNormals );
+
+  Vector3   GetCenter();
+  Vector3   GetSize();
+
+  void      ClearArrays();
+
+  bool      IsTexturePresent();
+  bool      IsDiffuseMapPresent();
+  bool      IsNormalMapPresent();
+  bool      IsSpecularMapPresent();
+
+private:
+
+  BoundingVolume mSceneAABB;
+
+  bool mSceneLoaded;
+  bool mMaterialLoaded;
+  bool mHasTexturePoints;
+
+  //Material file properties.
+  bool mHasDiffuseMap;
+  bool mHasNormalMap;
+  bool mHasSpecularMap;
+
+  Dali::Vector<Vector3>  mPoints;
+  Dali::Vector<Vector2>  mTextures;
+  Dali::Vector<Vector2>  mTextures2;
+  Dali::Vector<Vector3>  mNormals;
+  Dali::Vector<Vector3>  mTangents;
+  Dali::Vector<Vector3>  mBiTangents;
+  Dali::Vector<TriIndex> mTriangles;
+
+  /**
+   * @brief Calculates normals for each point on a per-face basis.
+   *
+   * There are multiple normals per point, each corresponding to the normal of a face connecting to the point.
+   *
+   * @param[in] vertices The vertices of the object.
+   * @param[in, out] triangles The triangles that form the faces. The normals of each triangle will be updated.
+   * @param[in, out] normals The normals to be calculated.
+   */
+  void CalculateHardFaceNormals( const Dali::Vector<Vector3>& vertices,
+                                 Dali::Vector<TriIndex>& triangles,
+                                 Dali::Vector<Vector3>& normals );
+
+  /**
+   * @brief Calculates smoothed normals for each point.
+   *
+   * There is one normal per point, an average of the connecting faces.
+   *
+   * @param[in] vertices The vertices of the object.
+   * @param[in, out] triangles The triangles that form the faces. The normals of each triangle will be updated.
+   * @param[in, out] normals The normals to be calculated.
+   */
+  void CalculateSoftFaceNormals( const Dali::Vector<Vector3>& vertices,
+                                 Dali::Vector<TriIndex>& triangles,
+                                 Dali::Vector<Vector3>& normals );
+
+  /**
+   * @brief Calculates tangents and bitangents for each point of the object.
+   *
+   * These are calculated using the object's points, texture coordinates and normals, so these must be initialised first.
+   */
+  void CalculateTangentFrame();
+
+  void CenterAndScale( bool center, Dali::Vector<Vector3>& points );
+
+  /**
+   * @brief Using the data loaded from the file, create arrays of data to be used in creating the geometry.
+   *
+   * @param[in] vertices The vertices of the object.
+   * @param[in] textures The texture coordinates of the object.
+   * @param[in] verticesExt Extension to vertices, storing tangents and bitangents.
+   * @param[in] indices Indices of corresponding values to match triangles to their respective data.
+   * @param[in] useSoftNormals Indicates whether we should average the normals at each point to smooth the surface or not.
+   */
+  void CreateGeometryArray( Dali::Vector<Vertex> & vertices,
+                            Dali::Vector<Vector2> & textures,
+                            Dali::Vector<VertexExt> & verticesExt,
+                            Dali::Vector<unsigned short> & indices,
+                            bool useSoftNormals );
+
+};
+
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+
+
+#endif // DALI_TOOLKIT_INTERNAL_OBJ_LOADER_H
diff --git a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp
new file mode 100644 (file)
index 0000000..5ddf48c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017 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 "navigation-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // to register type
+{
+
+BaseHandle Create()
+{
+  return Toolkit::NavigationView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::NavigationView, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+NavigationView::NavigationView()
+: Control(ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) )
+{
+}
+
+NavigationView::~NavigationView()
+{
+  // Clear all the items in the stack, forces their destruction before NavigationView is destroyed.
+  mContentStack.clear();
+}
+
+Toolkit::NavigationView NavigationView::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< NavigationView > internalNavigationView = new NavigationView();
+
+  // Pass ownership to CustomActor handle
+  Toolkit::NavigationView navigationView( *internalNavigationView );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalNavigationView->Initialize();
+
+  return navigationView;
+}
+
+void NavigationView::OnStageConnection( int depth )
+{
+  Self().SetSensitive(true);
+
+  Control::OnStageConnection( depth );
+}
+
+void NavigationView::Push( Actor& actor )
+{
+  // check the uninitialized item
+  // check the duplicated push for the top item
+  if(!actor )
+  {
+    return;
+  }
+
+  if( mContentStack.size() > 0 )
+  {
+    Self().Remove( mContentStack.back()  );
+  }
+
+  //push the new item into the stack and show it
+  mContentStack.push_back(actor);
+  Self().Add(actor);
+}
+
+Actor NavigationView::Pop()
+{
+  // cannot pop out the bottom-most item
+  Actor poppedItem;
+  if( mContentStack.size() > 1 )
+  {
+    // pop out the top item of the stack and show the new item right under the old one.
+    Self().Remove(mContentStack.back());
+    poppedItem = mContentStack.back();
+    mContentStack.pop_back();
+    Self().Add(mContentStack.back());
+  }
+
+  return poppedItem;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h
new file mode 100644 (file)
index 0000000..0222144
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef DALI_TOOLKIT_INTERNAL_NAVIGATION_CONTROL_H
+#define DALI_TOOLKIT_INTERNAL_NAVIGATION_CONTROL_H
+
+/*
+ * Copyright (c) 2019 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 <list>
+#include <dali/public-api/actors/layer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/navigation-view/navigation-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class NavigationView;
+
+namespace Internal
+{
+
+class NavigationBar;
+
+/**
+ * @brief
+ *
+ * NavigationView implements a controller than manages the navigation of hierarchical contents.
+ */
+
+class NavigationView : public Control
+{
+public:
+
+  /**
+   * Create an initialized NavigationView.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static Toolkit::NavigationView New();
+
+  /**
+   * @copydoc Dali::Toolkit::NavigationView::Push()
+   */
+  void Push( Actor& actor );
+
+  /**
+   * @copydoc Dali::Toolkit::NavigationView::Pop()
+   */
+  Actor Pop();
+
+  /**
+   * Performs actions as requested using the action name.
+   * @param[in] object The object on which to perform the action.
+   * @param[in] actionName The action to perform.
+   * @param[in] properties The properties with which to perform this action.
+   * @return true if action has been accepted by this control
+   */
+  //static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& properties );
+
+
+private: // override functions from Control
+
+  /**
+   * @copydoc Control::OnStageConnection( int depth  )
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Control::OnRelayout()
+   */
+  //virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+protected:
+
+  /**
+   * Constructor.
+   * It initializes the NavigationView members
+   */
+  NavigationView();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~NavigationView();
+
+private:
+
+  // Undefined
+  NavigationView(const NavigationView&);
+
+  // Undefined
+  NavigationView& operator=(const NavigationView& rhs);
+
+private:
+
+  std::vector< Actor >         mContentStack;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::NavigationView& GetImpl( Toolkit::NavigationView& navigationView )
+{
+  DALI_ASSERT_ALWAYS( navigationView );
+
+  Dali::RefObject& handle = navigationView.GetImplementation();
+
+  return static_cast<Toolkit::Internal::NavigationView&>( handle );
+}
+
+inline const Toolkit::Internal::NavigationView& GetImpl( const Toolkit::NavigationView& navigationView )
+{
+  DALI_ASSERT_ALWAYS( navigationView );
+
+  const Dali::RefObject& handle = navigationView.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::NavigationView&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_NAVIGATION_CONTROL_H
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h b/dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h
new file mode 100644 (file)
index 0000000..100c2c8
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_PAGE_TURN_BOOK_SPINE_EFFECT_H
+#define DALI_PAGE_TURN_BOOK_SPINE_EFFECT_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+#define DALI_COMPOSE_SHADER(STR) #STR
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Creates a new PageTurnBookSpineEffect
+ * This is an assisting effect of PageTurnEffect to display a book spine on _static_ pages, and also to flip the image horizontally when needed.
+ *
+ * When the page is turned over in landscape, call
+ * SetIsBackImageVisible(true), this effect can display the back image
+ * 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.
+ *
+ * Animatable/Constrainable uniforms:
+ *  "uSpineShadowParameter" - The two parameters are the major&minor radius (in pixels) to form an ellipse shape. The top-left
+ *                            quarter of this ellipse is used to calculate spine normal for simulating shadow *
+ *  "uTextureWidth" - 1.0 for single sided page,
+ *                    2.0 for double sided image which has left half part as page front side and right half part as page back side.
+ *
+ * @return The newly created Property::Map with the page turn book spine effect
+ **/
+inline Property::Map CreatePageTurnBookSpineEffect()
+{
+  const char* vertexSource = DALI_COMPOSE_SHADER(
+      precision mediump float;\n
+      attribute mediump vec2 aPosition;\n
+      uniform mediump mat4 uMvpMatrix;\n
+      uniform vec3 uSize;\n
+      uniform float uTextureWidth;\n
+      varying vec2 vTexCoord;\n
+      void main()\n
+      {\n
+        mediump vec4 vertexPosition = vec4(aPosition*uSize.xy, 0.0, 1.0);\n
+        gl_Position = uMvpMatrix * vertexPosition;\n
+        vTexCoord = aPosition + vec2(0.5);\n
+        vTexCoord.x /= uTextureWidth;
+      }\n);
+
+  // the simplified version of the fragment shader of page turn effect
+  const char* fragmentSource = DALI_COMPOSE_SHADER(
+      precision mediump float;\n
+      varying mediump vec2 vTexCoord;\n
+      uniform vec3 uSize;\n
+      uniform vec2 uSpineShadowParameter;\n
+      uniform sampler2D sTexture;\n
+      uniform lowp vec4 uColor;\n
+
+      void main()\n
+      {\n
+        if( gl_FrontFacing )\n // display front side
+        {\n
+          gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+        }\n
+        else\n // display back side, flip the image horizontally by changing the x component of the texture coordinate
+        {\n
+          gl_FragColor = texture2D( sTexture, vec2( 1.0 - vTexCoord.x, vTexCoord.y ) ) * uColor;\n
+        }\n
+        // display book spine, a stripe of shadowed texture
+        float pixelPos = vTexCoord.x * uSize.x;\n
+        if( pixelPos < uSpineShadowParameter.x )\n
+        {\n
+          float x = pixelPos - uSpineShadowParameter.x;\n
+          float y = sqrt( uSpineShadowParameter.x*uSpineShadowParameter.x - x*x );\n
+          vec2 spineNormal = normalize(vec2(uSpineShadowParameter.y*x/uSpineShadowParameter.x, y));\n
+          gl_FragColor.rgb *= spineNormal.y; \n
+        }\n
+      } );
+
+  Property::Map map;
+
+  Property::Map customShader;
+
+  customShader[ Toolkit::Visual::Shader::Property::VERTEX_SHADER ] = vertexSource;
+  customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentSource;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+}
+
+} //namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_PAGE_TURN_BOOK_SPINE_EFFECT_H
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.cpp
new file mode 100644 (file)
index 0000000..15a48da
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017 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.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+#define DALI_COMPOSE_SHADER(STR) #STR
+const char * const PROPERTY_COMMON_PARAMETERS( "uCommonParameters" );
+const char * const PROPERTY_ORIGINAL_CENTER( "originalCenter" );
+const char * const PROPERTY_CURRENT_CENTER( "currentCenter" );
+}
+
+/**
+ * This constraint updates the common parameter values used by every vertex.
+ * By using constraint, they are calculate once in CPU then pass into the vertex shader as uniforms
+ */
+struct CommonParametersConstraint
+{
+  CommonParametersConstraint( float pageHeight )
+  : mPageHeight( pageHeight )
+  {}
+
+  void operator()( Dali::Matrix& current, const PropertyInputContainer& inputs )
+  {
+    const Vector2& originalCenter = inputs[0]->GetVector2();
+    Vector2 currentCenter = inputs[1]->GetVector2();
+
+    // calculate the curve direction and the vanishing point
+    // here, the vanishing point is the intersection of spine with the line passing through original center and vertical to curve direction
+    Vector2 curveDirection( currentCenter - originalCenter );
+    curveDirection.Normalize();
+    if( fabs(curveDirection.y) < 0.01f) // eliminate the possibility of division by zero in the next step
+    {
+      curveDirection.y = 0.01f;
+    }
+    float vanishingPointY = originalCenter.y + curveDirection.x * originalCenter.x / curveDirection.y;
+
+    float curveEndY, cosTheta ,sinTheta ,translateX, translateY;
+    // when the vanishing point is very far away, make it infinitely, in this case, the page bent horizontally
+    const float THRESHOLD(20.0);
+    if( fabs(vanishingPointY-mPageHeight*0.5f) >= mPageHeight*THRESHOLD )
+    {
+      curveDirection = Vector2(-1.f,0.f);
+      currentCenter.y = originalCenter.y;
+
+      curveEndY = originalCenter.y;
+      cosTheta = 1.f;
+      sinTheta = 0.f;
+      translateX = currentCenter.x - originalCenter.x;
+      translateY = vanishingPointY;
+    }
+    else
+    {
+      curveEndY = currentCenter.y - curveDirection.y * (currentCenter.x/curveDirection.x) ;
+      Vector2 v1( currentCenter.x, currentCenter.y - vanishingPointY );
+      v1.Normalize();
+      Vector2 v2( originalCenter.x, originalCenter.y - vanishingPointY );
+      v2.Normalize();
+      cosTheta = v1.x*v2.x + v1.y*v2.y;
+      sinTheta = ( vanishingPointY > mPageHeight*0.5f ) ? sqrt(1.0-cosTheta*cosTheta) : -sqrt(1.0-cosTheta*cosTheta);
+      translateX = currentCenter.x - cosTheta*originalCenter.x - sinTheta*( originalCenter.y-vanishingPointY );
+      translateY = currentCenter.y + sinTheta*originalCenter.x - cosTheta*( originalCenter.y-vanishingPointY );
+    }
+
+    float originalLength = fabs(originalCenter.x/curveDirection.x);
+    float currentLength = fabs(currentCenter.x/curveDirection.x);
+    float curveHeight = 0.45f*sqrt(originalLength*originalLength - currentLength*currentLength);
+
+    float* parameterArray = current.AsFloat();
+    parameterArray[0] = cosTheta;
+    parameterArray[1] = -sinTheta;
+    parameterArray[2] = originalCenter.x;
+    parameterArray[3] = originalCenter.y;
+    parameterArray[4] = sinTheta;
+    parameterArray[5] = cosTheta;
+    parameterArray[6] = currentCenter.x;
+    parameterArray[7] = currentCenter.y;
+    parameterArray[8] = translateX;
+    parameterArray[9] = translateY;
+    parameterArray[10] = vanishingPointY;
+    parameterArray[11] = curveEndY;
+    parameterArray[12] = curveDirection.x;
+    parameterArray[13] = curveDirection.y;
+    parameterArray[14] = curveHeight;
+    parameterArray[15] = currentLength;
+  }
+
+  float mPageHeight;
+};
+
+void Dali::Toolkit::Internal::PageTurnApplyInternalConstraint( Actor& actor, float pageHeight )
+{
+  Constraint constraint = Constraint::New<Dali::Matrix>( actor, actor.GetPropertyIndex( PROPERTY_COMMON_PARAMETERS ) , CommonParametersConstraint( pageHeight ) );
+  constraint.AddSource( LocalSource( actor.GetPropertyIndex( PROPERTY_ORIGINAL_CENTER ) ) );
+  constraint.AddSource( LocalSource( actor.GetPropertyIndex( PROPERTY_CURRENT_CENTER ) ) );
+  constraint.Apply();
+}
+
+Property::Map Dali::Toolkit::Internal::CreatePageTurnEffect()
+{
+  const char* vertexShader = DALI_COMPOSE_SHADER(
+      /*
+       * The common parameters for all the vertices, calculate in CPU then pass into the shader as uniforms
+       *
+       *  first part of the page, (outside the the line passing through original center and vertical to curve direction)
+       * no Z change, only 2D rotation and translation
+       * ([0][0],[0][1],[1][0],[1][1]) mat2 rotateMatrix
+       * ([2][0],[2][1]) vec2 translationVector
+       *
+       * ([0][2],[0][3]) vec2 originalCenter: Typically the press down position of the Pan Gesture
+       * ([1][2],[1][3]) vec2 currentCenter: Typically the current position of the Pan Gesture
+       * ([3][0],[3][1]) vec2 curveDirection: The normalized vector pointing from original center to current center
+       * ([2][2]) float vanishingPointY: The Y coordinate of the intersection of the spine
+       *                                 and the line which goes through the original center and is vertical to the curveDirection
+       * ([2][3]) float curveEndY: The Y coordinate of intersection of the spine and the line through both original and current center
+       * ([3][2]) float curveHeight: The height of the interpolated hermite curve.
+       * ([3][3]) float currentLength: The length from the current center to the curveEnd.
+       */
+      precision mediump float;\n
+      \n
+      attribute mediump vec2 aPosition;\n
+      \n
+      uniform mediump mat4 uMvpMatrix;\n
+      uniform mediump mat3 uNormalMatrix;\n
+      uniform mediump mat4 uModelView;\n
+      \n
+      uniform mat4 uCommonParameters;\n
+      \n
+      uniform vec3 uSize;\n
+      uniform float uIsTurningBack;\n
+      uniform float uTextureWidth;\n
+      varying vec3 vNormal;\n
+      varying vec4 vPosition;\n
+      varying mediump vec2 vTexCoord;\n
+      \n
+      void main()\n
+      {\n
+        vec4 position = vec4( aPosition*uSize.xy, 0.0, 1.0);\n
+        vec2 currentCenter = vec2( uCommonParameters[1][2], uCommonParameters[1][3]);\n
+        vec2 originalCenter = vec2( uCommonParameters[0][2], uCommonParameters[0][3]);\n
+        vec3 normal = vec3(0.0,0.0,1.0);\n
+        \n
+        if(currentCenter.x < originalCenter.x)\n
+        {\n
+          // change the coordinate origin from the center of the page to its top-left
+          position.xy += uSize.xy * 0.5;\n
+          vec2 curveDirection = vec2( uCommonParameters[3]);\n
+          vec3 vanishingPoint = vec3(0.0, uCommonParameters[2][2], 0.0);\n
+          // first part of the page, (outside the the line passing through original center and vertical to curve direction)
+          //no Z change, only 2D rotation and translation
+          if( dot(curveDirection, position.xy - originalCenter) < 0.0 )
+          {\n
+            position.y -= vanishingPoint.y;\n
+            position.xy = mat2(uCommonParameters)*position.xy + vec2( uCommonParameters[2]);\n
+          }\n
+          // second part of the page, bent as a ruled surface
+          else\n
+          {\n
+            // calculate on the flat plane, between
+            // the first line passing through current vertex and vanishing point
+            // the second line passing through original center and current center
+            vec2 curveEnd = vec2( 0.0, uCommonParameters[2][3] );\n
+            vec2 curFlatDirection = vec2(0.0,1.0);\n
+            float lengthFromCurve = position.y - originalCenter.y;\n
+            float lengthOnCurve = position.x;\n
+            if(currentCenter.y != originalCenter.y)\n
+            {\n
+              curFlatDirection = normalize(position.xy - vanishingPoint.xy);\n
+              lengthFromCurve = (curveEnd.x*curveDirection.y-curveEnd.y*curveDirection.x-position.x*curveDirection.y+position.y*curveDirection.x)
+              / (curFlatDirection.x*curveDirection.y-curFlatDirection.y*curveDirection.x);\n
+              lengthOnCurve = length(position.xy+lengthFromCurve*curFlatDirection-curveEnd);\n
+            }\n
+            \n
+            // define the control points of hermite curve, composed with two segments
+            // calculation is carried out on the 2D plane which is passing through both current and original center and vertical to the image plane
+            float currentLength = uCommonParameters[3][3];\n
+            float originalLength =  abs(originalCenter.x/curveDirection.x);\n
+            float height = uCommonParameters[3][2];\n
+            float percentage = currentLength/originalLength;\n
+            //vec2 SegmentOneControlPoint0 = vec2(0.0, 0.0);
+            vec2 SegmentOneControlPoint1 = vec2((0.65*percentage - 0.15)*originalLength, (0.8 + 0.2 * percentage)*height); \n
+            vec2 SegmentTwoControlPoint0 = SegmentOneControlPoint1;\n
+            vec2 SegmentTwoControlPoint1 = vec2(currentLength, 0.0); \n
+            vec2 SegmentOneTangentVector0 = SegmentOneControlPoint1;\n
+            vec2 SegmentOneTangentVector1 = vec2(0.5*originalLength,0.0);\n
+            vec2 SegmentTwoTangentVector0 = SegmentOneTangentVector1;\n
+            vec2 SegmentTwoTangentVector1 = SegmentOneTangentVector1;\n
+            \n
+            // calculate the corresponding curve point position and its tangent vector
+            // it is a linear mapping onto nonlinear curves, might cause some unwanted deformation
+            // but as there are no analytical method to calculate the curve length on arbitrary segment
+            // no efficient way to solve this nonlinear mapping, Numerical approximation would cost too much computation in shader
+            vec2 curvePoint2D;\n
+            vec2 tangent;\n
+            float t0 = lengthOnCurve / originalLength;\n
+            if(t0<=0.5)\n
+            {\n
+              float t = 2.0*t0;\n
+              float t_2 = t*t;\n
+              float t_3 = t*t_2;\n
+              curvePoint2D = (-2.0*t_3+3.0*t_2)*SegmentOneControlPoint1
+              + (t_3-2.0*t_2+t)*SegmentOneTangentVector0 + (t_3-t_2)*SegmentOneTangentVector1;\n
+              tangent = (-6.0*t_2+6.0*t)*SegmentOneControlPoint1
+              + (3.0*t_2-4.0*t+1.0)*SegmentOneTangentVector0 + (3.0*t_2-2.0*t)*SegmentOneTangentVector1;\n
+            }\n
+            else\n
+            {\n
+              float t = 2.0*t0-1.0;\n
+              float t_2 = t*t;\n
+              float t_3 = t*t_2;\n
+              curvePoint2D = (2.0*t_3-3.0*t_2+1.0)*SegmentTwoControlPoint0 + (-2.0*t_3+3.0*t_2)*SegmentTwoControlPoint1
+              + (t_3-2.0*t_2+t)*SegmentTwoTangentVector0 + (t_3-t_2)*SegmentTwoTangentVector1;\n
+              tangent = (6.0*t_2-6.0*t)*SegmentTwoControlPoint0 + (-6.0*t_2+6.0*t)*SegmentTwoControlPoint1
+              + (3.0*t_2-4.0*t+1.0)*SegmentTwoTangentVector0 + (3.0*t_2-2.0*t)*SegmentTwoTangentVector1;\n
+              // a trick to eliminate some optical illusion caused by the gradient matter of normal in per-fragment shading
+              // which is caused by linear interpolation of normal vs. nonlinear lighting
+              // will notice some artifact in the areas with dramatically normal changes, so compress the normal differences here
+              tangent.y *=  min(1.0, length(position.xyz - vanishingPoint) / uSize.y ); \n
+            }\n
+            vec3 curvePoint = vec3(curveEnd - curvePoint2D.x*curveDirection,max(0.0,curvePoint2D.y));\n
+            vec3 tangentVector = vec3(-tangent.x*curveDirection,tangent.y);\n
+            \n
+            // locate the new vertex position on the line passing through both vanishing point and the calculated curve point position
+            vec3 curLiftDirection = vec3(0.0,-1.0,0.0);\n
+            if(currentCenter.y != originalCenter.y)\n
+            {\n
+              curLiftDirection = normalize(curvePoint - vanishingPoint);\n
+              tangentVector *= (curveDirection.y > 0.0) ? -1.0 : 1.0;\n
+              // an heuristic adjustment here, to compensate the linear parameter mapping onto the nonlinear curve
+              float Y0 = position.y - curveDirection.y * (position.x/curveDirection.x); \n
+              float proportion;
+              float refLength;\n
+              if(abs(Y0-vanishingPoint.y) > abs(curveEnd.y-vanishingPoint.y)) \n
+              {\n
+                proportion = abs(curveEnd.y - Y0) / (abs(curveEnd.y-Y0)+abs(curveEnd.y - vanishingPoint.y)); \n
+                refLength = proportion*length(originalCenter-vanishingPoint.xy) / (proportion-1.0); \n
+              }\n
+              else\n
+              {\n
+                proportion = abs(curveEnd.y - Y0) / abs(curveEnd.y - vanishingPoint.y);\n
+                refLength = proportion*length(originalCenter-vanishingPoint.xy); \n
+              }\n
+              float Y1 = currentCenter.y - (normalize(currentCenter-vanishingPoint.xy)).y * refLength; \n
+              position.y = mix(Y0, Y1, t0); \n
+            }\n
+            position.xz = curvePoint.xz - lengthFromCurve*curLiftDirection.xz;\n
+            // calculate the normal vector, will be used for lighting
+            normal = cross(curLiftDirection, normalize(tangentVector));\n
+            // the signature of Z is decided by the page turning direction:
+            // from left to right(negative); from right to left (positive)
+            position.z *= -uIsTurningBack;\n
+            normal.xy *= -uIsTurningBack;\n
+          }\n
+          // change the coordinate origin from the top-left of the page to its center
+          position.xy -= uSize.xy * 0.5; \n
+        }\n
+        vNormal =  uNormalMatrix * normal;\n
+        gl_Position = uMvpMatrix * position;
+        // varying parameters for fragment shader
+        vTexCoord = aPosition + vec2(0.5);\n
+        vTexCoord.x /= uTextureWidth;
+        vPosition = uModelView * position;\n
+      }\n
+  );
+
+  const char* fragmentShader = DALI_COMPOSE_SHADER(
+      precision mediump float;\n
+      \n
+      varying mediump vec2 vTexCoord;\n
+      \n
+      uniform sampler2D sTexture;\n
+      uniform lowp vec4 uColor;\n
+      uniform vec3 uSize;\n
+      uniform vec2 uSpineShadowParameter;\n
+      varying vec3 vNormal;\n
+      varying vec4 vPosition;\n
+      \n
+      void main()\n
+      {\n
+        // need to re-normalize the interpolated normal
+        vec3 normal = normalize( vNormal );\n
+        // display page content
+        vec4 texel;
+        // display back image of the page, flip the texture
+        if(  dot(vPosition.xyz, normal) > 0.0 ) texel = texture2D( sTexture, vec2( 1.0 - vTexCoord.x, vTexCoord.y ) );\n
+        // display front image of the page
+        else texel = texture2D( sTexture, vTexCoord );\n
+
+        // display book spine, a stripe of shadowed texture
+        float pixelPos = vTexCoord.x * uSize.x; \n
+        float spineShadowCoef = 1.0; \n
+        if( pixelPos < uSpineShadowParameter.x ) \n
+        {\n
+          float x = pixelPos - uSpineShadowParameter.x;\n
+          float y = sqrt( uSpineShadowParameter.x*uSpineShadowParameter.x - x*x );\n
+          spineShadowCoef = normalize( vec2( uSpineShadowParameter.y*x/uSpineShadowParameter.x, y ) ).y;\n
+        }\n
+        // calculate the lighting
+        // set the ambient color as vec3(0.4);
+        float lightColor = abs( normal.z ) * 0.6 + 0.4;\n
+        gl_FragColor = vec4( ( spineShadowCoef * lightColor ) * texel.rgb , texel.a ) * uColor;\n
+      }
+  );
+
+  Property::Map map;
+
+  Property::Map customShader;
+
+  customShader[ Toolkit::Visual::Shader::Property::VERTEX_SHADER ] = vertexShader;
+  customShader[ Toolkit::Visual::Shader::Property::FRAGMENT_SHADER ] = fragmentShader;
+  customShader[ Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X ] = 20;
+  customShader[ Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y ] = 20;
+
+  map[ Toolkit::Visual::Property::SHADER ] = customShader;
+  return map;
+
+}
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h b/dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h
new file mode 100644 (file)
index 0000000..fba77c5
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef DALI_PAGE_TURN_EFFECT_H
+#define DALI_PAGE_TURN_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+
+/**
+ * @brief Re-applies PageTurnEffect internal constraints
+ * The internal constraint uses the OriginalCenter property and the CURRENT_CENTER Property
+ * to update the variety of common parameters which are with the same value for all the vertices.
+ * Note: For each actor, the constraints are applied in the same order as the calls to Actor::ApplyConstraint().
+ * So if there are other contraints applied to the ORIGINAL_CENTER or CURRENT_CENTER while when using this effect,
+ * call this method to get the internal constraints and re-apply it afterwards.
+ *
+ * @param[in] actor The page turn actor to which internal constraints should be re-applied
+ * @param[in] pageHeight The page height.
+ */
+void PageTurnApplyInternalConstraint( Actor& actor, float pageHeight );
+
+/**
+ * @brief Create a new PageTurnEffect
+ * PageTurnEffect is a custom shader to achieve page turn effect for image views.
+ *
+ * Usage example:-
+ *
+ * // create shader used for doing page-turn effect\n
+ * Property::Map pageTurnEffect = CreatePageTurnEffect();
+ *
+ * // set image view custom shader to the page-turn one\n
+ * // for portrait view, the image is rendered as the front side of  page\n
+ * // for landscape view, the back side becomes visible when the page is turned over. \n
+ * //     in this case, the left and right half of the image are renderer as the front and back side separately. \n
+ * ImageView page = ImageView::New(....); \n
+ * page.SetProperty ( ImageView::Property::IMAGE, pageTurnEffect ); \n
+ *
+ * //set initial values
+ * page.SetProperty( page.GetPropertyIndex("uIsTurningBack",) bool );\n
+ * page.SetProperty( page.GetPropertyIndex("uSpineShadowParameter",) Vector2 );\n
+ * page.SetProperty( page.GetPropertyIndex("ORIGINAL_CENTER"), Vector2 );\n
+ * page.SetProperty( page.GetPropertyIndex("CURRENT_CENTER"), Vector2 );\n
+ * page.SetProperty( page.GetPropertyIndex("uCommonParameters"), Matrix );\n
+ * page.SetProperty( page.GetPropertyIndex("uTextureWidth"), float ); // Set to 1.0 for single-sided or 2.0 for double-sided \n
+ * PageTurnApplyInternalConstraint( page );\n
+ *
+ * //Animate it with the current center property\n
+ * Animation animation = Animation::New( ... );\n
+ * animation.AnimateTo(Property( page, "CURRENT_CENTER" ),
+ *                               currentCenter,
+ *                               AlphaFunction::...);\n
+ * animation.Play(); \n
+ *
+ */
+Property::Map CreatePageTurnEffect();
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_PAGE_TURN_EFFECT_H
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.cpp
new file mode 100644 (file)
index 0000000..5bc97dc
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::PageTurnLandscapeView, Toolkit::PageTurnView, NULL )
+DALI_TYPE_REGISTRATION_END()
+
+}
+
+PageTurnLandscapeView::PageTurnLandscapeView( PageFactory& pageFactory, const Vector2& viewPageSize )
+: PageTurnView( pageFactory, viewPageSize )
+{
+}
+
+PageTurnLandscapeView::~PageTurnLandscapeView()
+{}
+
+Toolkit::PageTurnLandscapeView PageTurnLandscapeView::New( PageFactory& pageFactory, const Vector2& viewPageSize )
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< PageTurnLandscapeView > internalPageTurnView = new PageTurnLandscapeView( pageFactory, viewPageSize );
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::PageTurnLandscapeView pageTurnView( *internalPageTurnView );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalPageTurnView->Initialize();
+
+  return pageTurnView;
+}
+
+void PageTurnLandscapeView::OnPageTurnViewInitialize()
+{
+  mTurnEffectShader.RegisterProperty(PROPERTY_TEXTURE_WIDTH, 2.f );
+  mSpineEffectShader.RegisterProperty(PROPERTY_TEXTURE_WIDTH, 2.f );
+
+  mControlSize = Vector2( mPageSize.width * 2.f,  mPageSize.height  );
+  Self().SetSize( mControlSize );
+  mTurningPageLayer.SetParentOrigin( ParentOrigin::CENTER );
+}
+
+void PageTurnLandscapeView::OnAddPage( Actor newPage, bool isLeftSide )
+{
+  newPage.SetParentOrigin( ParentOrigin::CENTER );
+}
+
+Vector2 PageTurnLandscapeView::SetPanPosition( const Vector2& gesturePosition )
+{
+  if( mPages[mIndex].isTurnBack )
+  {
+    return Vector2( mPageSize.width - gesturePosition.x, gesturePosition.y );
+  }
+  else
+  {
+    return Vector2( gesturePosition.x - mPageSize.width, gesturePosition.y );
+  }
+}
+
+void PageTurnLandscapeView::SetPanActor( const Vector2& panPosition )
+{
+  if( panPosition.x > mPageSize.width  && mCurrentPageIndex < mTotalPageCount )
+  {
+    mTurningPageIndex = mCurrentPageIndex;
+  }
+  else if( panPosition.x <= mPageSize.width && mCurrentPageIndex > 0 )
+  {
+    mTurningPageIndex = mCurrentPageIndex - 1;
+  }
+  else
+  {
+    mTurningPageIndex = -1;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.h b/dali-toolkit/internal/controls/page-turn-view/page-turn-landscape-view-impl.h
new file mode 100644 (file)
index 0000000..aee1d5e
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PAGE_TURN_LANDSCAPE_VIEW_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_PAGE_TURN_LANDSCAPE_VIEW_IMPL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-landscape-view.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class PageTurnLandscapeView : public PageTurnView
+{
+public:
+
+  /**
+   * @copydoc Toolkit::PageTurnLandscapeView::New( PageFactory&, const Vector2& )
+   */
+  static Toolkit::PageTurnLandscapeView New( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+protected:
+  /**
+   * Constructor.
+   * It initializes the PageTurnPortraitView members
+   * @param[in] pageFactory The factory which provides image to PageTurnView as the page content.
+   * @param[in] viewPageSize The size of the page
+   */
+  PageTurnLandscapeView( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PageTurnLandscapeView();
+
+protected: // From PageTurnView
+
+  /**
+   * @copydoc PageTurnView::OnPageTurnViewInitialize
+   */
+  virtual void OnPageTurnViewInitialize();
+
+  /**
+   * @copydoc PageTurnView::OnAddPage
+   */
+  virtual void OnAddPage( Actor newPage, bool isLeftSide );
+
+  /**
+   * @copydoc PageTurnView::SetPanPosition
+   */
+  virtual Vector2 SetPanPosition( const Vector2& gesturePosition );
+
+  /**
+   * @copydoc PageTurnView::SetPanActor
+   */
+  virtual void SetPanActor( const Vector2& panPosition );
+
+private:
+
+  //Undefined
+  PageTurnLandscapeView( const PageTurnLandscapeView& );
+
+  //undefined
+  PageTurnLandscapeView& operator=(const PageTurnLandscapeView& rhs);
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_PAGE_TURN_LANDSCAPE_VIEW_IMPL_H
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.cpp
new file mode 100644 (file)
index 0000000..4bde36a
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::PageTurnPortraitView, Toolkit::PageTurnView, NULL )
+DALI_TYPE_REGISTRATION_END()
+
+// the panning speed threshold, no matter how far is the pan displacement, pan fast to left/right quickly (speed > 0.3) will turn over/back the page
+const float GESTURE_SPEED_THRESHOLD(0.3f);
+
+// the animation duration of turning the previous page back when an outwards flick is detected
+const float PAGE_TURN_OVER_ANIMATION_DURATION(0.5f);
+
+}
+
+PageTurnPortraitView::PageTurnPortraitView( PageFactory& pageFactory, const Vector2& viewPageSize )
+: PageTurnView( pageFactory, viewPageSize )
+{
+}
+
+PageTurnPortraitView::~PageTurnPortraitView()
+{
+}
+
+Toolkit::PageTurnPortraitView PageTurnPortraitView::New( PageFactory& pageFactory, const Vector2& viewPageSize )
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< PageTurnPortraitView > internalPageTurnView = new PageTurnPortraitView( pageFactory, viewPageSize );
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::PageTurnPortraitView pageTurnView( *internalPageTurnView );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalPageTurnView->Initialize();
+
+  return pageTurnView;
+}
+
+void PageTurnPortraitView::OnPageTurnViewInitialize()
+{
+  mTurnEffectShader.RegisterProperty(PROPERTY_TEXTURE_WIDTH, 1.f );
+  mSpineEffectShader.RegisterProperty(PROPERTY_TEXTURE_WIDTH, 1.f );
+
+  mControlSize = mPageSize;
+  Self().SetSize( mPageSize );
+  mTurningPageLayer.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+}
+
+Vector2 PageTurnPortraitView::SetPanPosition( const Vector2& gesturePosition )
+{
+  return gesturePosition;
+}
+
+void PageTurnPortraitView::SetPanActor( const Vector2& panPosition )
+{
+  if( mCurrentPageIndex < mTotalPageCount )
+  {
+    mTurningPageIndex = mCurrentPageIndex;
+  }
+  else
+  {
+    mTurningPageIndex = -1;
+  }
+}
+
+void PageTurnPortraitView::OnPossibleOutwardsFlick( const Vector2& panPosition, float gestureSpeed )
+{
+  Vector2 offset = panPosition - mPressDownPosition;
+  // There is previous page and an outwards flick is detected
+  if( mCurrentPageIndex > 0 && gestureSpeed > GESTURE_SPEED_THRESHOLD && offset.x > fabs( offset.y ))
+  {
+    int actorIndex = (mCurrentPageIndex-1) % NUMBER_OF_CACHED_PAGES;
+    Actor actor = mPages[ actorIndex ].actor;
+    if(actor.GetParent() != Self())
+    {
+      return;
+    }
+
+    // Guard against destruction during signal emission
+    //Emit signal, to notify that page[mCurrentPageIndex-1] is turning backwards
+    Toolkit::PageTurnView handle( GetOwner() );
+    mTurningPageIndex = mCurrentPageIndex-1;
+    mPageTurnStartedSignal.Emit( handle, static_cast<unsigned int>(mTurningPageIndex), false );
+
+    //update pages
+    mCurrentPageIndex--;
+    RemovePage( mCurrentPageIndex+NUMBER_OF_CACHED_PAGES_EACH_SIDE );
+    AddPage( mCurrentPageIndex-NUMBER_OF_CACHED_PAGES_EACH_SIDE );
+    OrganizePageDepth();
+    mPageUpdated = true;
+
+    actor.SetVisible(true);
+
+    // Add the page to tuning page layer and set up PageTurnEffect
+    mShadowView.Add( actor );
+    mPages[actorIndex].UseEffect( mTurnEffectShader );
+    mAnimatingCount++;
+    Vector2 originalCenter( mPageSize.width*1.5f, 0.5f*mPageSize.height );
+    mPages[actorIndex].SetOriginalCenter( originalCenter );
+    mPages[actorIndex].SetCurrentCenter( Vector2( mPageSize.width*0.5f, mPageSize.height*0.5f ) );
+    PageTurnApplyInternalConstraint(actor, mPageSize.height);
+
+    // Start an animation to turn the previous page back
+    Animation animation = Animation::New( PAGE_TURN_OVER_ANIMATION_DURATION );
+    mAnimationPageIdPair[animation] = mCurrentPageIndex;
+
+    animation.AnimateTo( Property( actor, mPages[actorIndex].propertyCurrentCenter ),
+                         originalCenter,
+                         AlphaFunction::EASE_OUT, TimePeriod(PAGE_TURN_OVER_ANIMATION_DURATION*0.75f) );
+    animation.AnimateBy( Property( actor, Actor::Property::ORIENTATION ), AngleAxis( Degree( 180.0f ), Vector3::YAXIS ) ,AlphaFunction::EASE_OUT );
+    animation.Play();
+
+    animation.FinishedSignal().Connect( this, &PageTurnPortraitView::TurnedOverBackwards );
+  }
+}
+
+void PageTurnPortraitView::OnTurnedOver( Actor actor, bool isLeftSide )
+{
+  if( isLeftSide )
+  {
+    actor.SetVisible( false );
+  }
+}
+
+void PageTurnPortraitView::TurnedOverBackwards( Animation& animation )
+{
+  TurnedOver( animation );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.h b/dali-toolkit/internal/controls/page-turn-view/page-turn-portrait-view-impl.h
new file mode 100644 (file)
index 0000000..3cf9ef4
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PAGE_TURN_PORTRAIT_VIEW_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_PAGE_TURN_PORTRAIT_VIEW_IMPL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-portrait-view.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation class of the PageTurnView in portrait mode
+ */
+class PageTurnPortraitView : public PageTurnView
+{
+public:
+
+  /**
+   * @copydoc Toolkit::PageTurnPortraitView::New( PageFactory&, const Vector2& )
+   */
+  static Toolkit::PageTurnPortraitView New( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+protected:
+
+  /**
+   * Constructor.
+   * It initializes the PageTurnPortraitView members
+   * @param[in] pageFactory The factory which provides image to PageTurnView as the page content.
+   * @param[in] viewPageSize The size of the page
+   */
+  PageTurnPortraitView( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PageTurnPortraitView();
+
+protected: // From PageTurnView
+
+  /**
+   * @copydoc PageTurnView::OnPageTurnViewInitialize
+   */
+  virtual void OnPageTurnViewInitialize();
+
+  /**
+   * @copydoc PageTurnView::SetPanPosition
+   */
+  virtual Vector2 SetPanPosition( const Vector2& gesturePosition );
+
+  /**
+   * @copydoc PageTurnView::SetPanActor
+   */
+  virtual void SetPanActor( const Vector2& panPosition );
+
+  /**
+   * @copydoc PageTurnView::OnPossibleOutwardsFlick
+   */
+  virtual void OnPossibleOutwardsFlick( const Vector2& panPosition, float gestureSpeed );
+
+  /**
+   * @copydoc PageTurnView::OnTurnedOver
+   */
+  virtual void OnTurnedOver( Actor actor, bool isLeftSide );
+
+private:
+
+  /**
+   * @copydoc PageTurnView::TurnedOver
+   */
+  void TurnedOverBackwards( Animation& animation );
+
+private:
+
+  //Undefined
+  PageTurnPortraitView( const PageTurnPortraitView& );
+
+  //undefined
+  PageTurnPortraitView& operator=(const PageTurnPortraitView& rhs);
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_PAGE_TURN_PORTRAIT_VIEW_IMPL_H
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp
new file mode 100644 (file)
index 0000000..7a00f87
--- /dev/null
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-effect.h>
+#include <dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+using namespace Dali;
+
+namespace //Unnamed namespace
+{
+// properties set on shader, these properties have the constant value in regardless of the page status
+const char * const PROPERTY_SPINE_SHADOW ( "uSpineShadowParameter" ); // uniform for both spine and turn effect
+
+// properties set on actor, the value of these properties varies depending on the page status
+//    properties used in turn effect
+const char * const PROPERTY_TURN_DIRECTION( "uIsTurningBack" ); // uniform
+const char * const PROPERTY_COMMON_PARAMETERS( "uCommonParameters" ); //uniform
+
+const char * const PROPERTY_PAN_DISPLACEMENT( "panDisplacement" );// property used to constrain the uniforms
+const char * const PROPERTY_PAN_CENTER( "panCenter" );// property used to constrain the uniforms
+
+// default grid density for page turn effect, 20 pixels by 20 pixels
+const float DEFAULT_GRID_DENSITY(20.0f);
+
+// to bent the page, the minimal horizontal pan start position is viewPageSize.x * MINIMUM_START_POSITION_RATIO
+const float MINIMUM_START_POSITION_RATIO(0.6f);
+
+// the maximum vertical displacement of pan gesture, if exceed, will reduce it: viewPageSize.y * MAXIMUM_VERTICAL_MOVEMENT_RATIO
+const float MAXIMUM_VERTICAL_MOVEMENT_RATIO(0.15f);
+
+// when the x component of pan position reaches viewPageSize.x * PAGE_TURN_OVER_THRESHOLD_RATIO, page starts to turn over
+const float PAGE_TURN_OVER_THRESHOLD_RATIO(0.5f);
+
+// duration of animation, shorter for faster speed
+const float PAGE_SLIDE_BACK_ANIMATION_DURATION(1.0f);
+const float PAGE_TURN_OVER_ANIMATION_DURATION(1.2f);
+
+// the major&minor radius (in pixels) to form an ellipse shape
+// the top-left quarter of this ellipse is used to calculate spine normal for simulating shadow
+const Vector2 DEFAULT_SPINE_SHADOW_PARAMETER(50.0f, 20.0f);
+
+// constants for shadow casting
+const float POINT_LIGHT_HEIGHT_RATIO(2.f);
+const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.5f);
+
+// constraints ////////////////////////////////////////////////////////////////
+/**
+ * Original Center Constraint
+ *
+ * This constraint adjusts the original center property of the page turn shader effect
+ * based on the X-direction displacement of the pan gesture
+ */
+struct OriginalCenterConstraint
+{
+  OriginalCenterConstraint(const Vector2& originalCenter, const Vector2& offset)
+  : mOldCenter( originalCenter )
+  {
+    mNewCenter = originalCenter + offset;
+    mDistance = offset.Length() * 0.5f;
+    mDirection = offset  / mDistance;
+  }
+
+  void operator()( Vector2& current, const PropertyInputContainer& inputs )
+  {
+    float displacement = inputs[0]->GetFloat();
+
+    if( displacement < mDistance )
+    {
+      current = mOldCenter + mDirection * displacement;
+    }
+    else
+    {
+      current = mNewCenter + Vector2(0.25f*(displacement-mDistance), 0.f);
+    }
+  }
+
+  Vector2 mOldCenter;
+  Vector2 mNewCenter;
+  float mDistance;
+  Vector2 mDirection;
+};
+
+/**
+ * Rotation Constraint
+ *
+ * This constraint adjusts the rotation property of the page actor
+ * based on the X-direction displacement of the pan gesture
+ */
+struct RotationConstraint
+{
+  RotationConstraint( float distance, float pageWidth, bool isTurnBack )
+  : mDistance( distance*0.5f )
+  {
+    mStep = 1.f / pageWidth;
+    mSign = isTurnBack ? -1.0f : 1.0f;
+    mConst = isTurnBack ? -1.0f : 0.f;
+    mRotation = isTurnBack ? Quaternion( Radian( -Math::PI ), Vector3::YAXIS ) : Quaternion( Radian(0.f), Vector3::YAXIS );
+  }
+
+  void operator()( Quaternion& current, const PropertyInputContainer& inputs )
+  {
+    float displacement = inputs[0]->GetFloat();
+    if( displacement < mDistance)
+    {
+      current = mRotation;
+    }
+    else
+    {
+      float coef = std::max(-1.0f, mStep*(mDistance-displacement));
+      float angle = Math::PI * ( mConst + mSign * coef );
+      current = Quaternion( Radian( angle ), Vector3::YAXIS );
+    }
+  }
+
+  float mDistance;
+  float mStep;
+  float mConst;
+  float mSign;
+  Quaternion mRotation;
+};
+
+/**
+ * Current Center Constraint
+ *
+ * This constraint adjusts the current center property of the page turn shader effect
+ * based on the pan position and the original center position
+ */
+struct CurrentCenterConstraint
+{
+  CurrentCenterConstraint( float pageWidth )
+  : mPageWidth( pageWidth )
+  {
+    mThres = pageWidth * PAGE_TURN_OVER_THRESHOLD_RATIO * 0.5f;
+  }
+
+  void operator()( Vector2& current, const PropertyInputContainer& inputs )
+  {
+    const Vector2& centerPosition = inputs[0]->GetVector2();
+    if( centerPosition.x > 0.f )
+    {
+      current.x = mThres+centerPosition.x * 0.5f;
+      current.y = centerPosition.y;
+    }
+    else
+    {
+      const Vector2& centerOrigin = inputs[1]->GetVector2();
+      Vector2 direction = centerOrigin - Vector2(mThres, centerPosition.y);
+      float coef = 1.f+(centerPosition.x*2.f / mPageWidth);
+      // when coef <= 0, the page is flat, slow down the last moment of the page stretch by 10 times to avoid a small bounce
+      if(coef < 0.025f)
+      {
+        coef = (coef+0.225f)/10.0f;
+      }
+      current = centerOrigin - direction * coef;
+    }
+  }
+
+  float mPageWidth;
+  float mThres;
+};
+
+struct ShadowBlurStrengthConstraint
+{
+  ShadowBlurStrengthConstraint( float thres )
+  : mThres( thres )
+  {}
+
+  void operator()( float& blurStrength,  const PropertyInputContainer& inputs )
+  {
+    float displacement = inputs[2]->GetFloat();
+    if( EqualsZero(displacement))
+    {
+      const Vector2& cur = inputs[0]->GetVector2();
+      const Vector2& ori = inputs[1]->GetVector2();
+      blurStrength =  5.f*(ori-cur).Length() / mThres;
+    }
+    else
+    {
+      blurStrength =  1.f - (displacement-2.f*mThres)/mThres;
+    }
+
+    blurStrength = blurStrength > 1.f ? 1.f : ( blurStrength < 0.f ? 0.f : blurStrength );
+  }
+
+  float mThres;
+};
+
+} //unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  // empty handle as we cannot create PageTurnView(but type registered for page turn signal)
+  return BaseHandle();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::PageTurnView, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, PageTurnView, "viewPageSize",        VECTOR2, VIEW_PAGE_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, PageTurnView, "currentPageId",   INTEGER, CURRENT_PAGE_ID )
+DALI_PROPERTY_REGISTRATION( Toolkit, PageTurnView, "spineShadow",     VECTOR2, SPINE_SHADOW )
+
+DALI_SIGNAL_REGISTRATION( Toolkit, PageTurnView, "pageTurnStarted",    SIGNAL_PAGE_TURN_STARTED )
+DALI_SIGNAL_REGISTRATION( Toolkit, PageTurnView, "pageTurnFinished",   SIGNAL_PAGE_TURN_FINISHED )
+DALI_SIGNAL_REGISTRATION( Toolkit, PageTurnView, "pagePanStarted",     SIGNAL_PAGE_PAN_STARTED )
+DALI_SIGNAL_REGISTRATION( Toolkit, PageTurnView, "pagePanFinished",    SIGNAL_PAGE_PAN_FINISHED )
+
+DALI_TYPE_REGISTRATION_END()
+
+}
+
+// these several constants are also used in the derived classes
+const char * const PageTurnView::PROPERTY_TEXTURE_WIDTH( "uTextureWidth" ); // uniform name
+const char * const PageTurnView::PROPERTY_ORIGINAL_CENTER( "originalCenter" ); // property used to constrain the uniform
+const char * const PageTurnView::PROPERTY_CURRENT_CENTER( "currentCenter" );// property used to constrain the uniform
+const int PageTurnView::MAXIMUM_TURNING_NUM = 4;
+const int PageTurnView::NUMBER_OF_CACHED_PAGES_EACH_SIDE = MAXIMUM_TURNING_NUM + 1;
+const int PageTurnView::NUMBER_OF_CACHED_PAGES = NUMBER_OF_CACHED_PAGES_EACH_SIDE*2;
+const float PageTurnView::STATIC_PAGE_INTERVAL_DISTANCE = 1.0f;
+
+PageTurnView::Page::Page()
+: isTurnBack( false )
+{
+  actor = Actor::New();
+  actor.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+  actor.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  actor.SetVisible( false );
+
+  propertyPanDisplacement = actor.RegisterProperty( PROPERTY_PAN_DISPLACEMENT, 0.f );
+  propertyPanCenter = actor.RegisterProperty(PROPERTY_PAN_CENTER, Vector2::ZERO);
+
+  propertyOriginalCenter = actor.RegisterProperty(PROPERTY_ORIGINAL_CENTER, Vector2::ZERO);
+  propertyCurrentCenter = actor.RegisterProperty(PROPERTY_CURRENT_CENTER, Vector2::ZERO);
+  Matrix zeroMatrix(true);
+  actor.RegisterProperty(PROPERTY_COMMON_PARAMETERS, zeroMatrix);
+  propertyTurnDirection = actor.RegisterProperty(PROPERTY_TURN_DIRECTION, -1.f);
+}
+
+void PageTurnView::Page::SetTexture( Texture texture )
+{
+  if( !textureSet )
+  {
+    textureSet = TextureSet::New();
+  }
+  textureSet.SetTexture( 0u, texture );
+}
+
+void PageTurnView::Page::UseEffect(Shader newShader)
+{
+  shader = newShader;
+  if( renderer )
+  {
+    renderer.SetShader( shader );
+  }
+}
+
+void PageTurnView::Page::UseEffect(Shader newShader, Geometry geometry)
+{
+  UseEffect( newShader );
+
+  if( !renderer )
+  {
+    renderer = Renderer::New( geometry, shader );
+
+    if( !textureSet )
+    {
+      textureSet = TextureSet::New();
+    }
+
+    renderer.SetTextures( textureSet );
+    renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+    actor.AddRenderer( renderer );
+  }
+}
+
+void PageTurnView::Page::ChangeTurnDirection()
+{
+  isTurnBack = !isTurnBack;
+  actor.SetProperty( propertyTurnDirection, isTurnBack ? 1.f : -1.f );
+}
+
+void PageTurnView::Page::SetPanDisplacement(float value)
+{
+ actor.SetProperty( propertyPanDisplacement, value );
+}
+
+void PageTurnView::Page::SetPanCenter( const Vector2& value )
+{
+  actor.SetProperty( propertyPanCenter, value );
+}
+
+void PageTurnView::Page::SetOriginalCenter( const Vector2& value )
+{
+  actor.SetProperty( propertyOriginalCenter, value );
+}
+
+void PageTurnView::Page::SetCurrentCenter( const Vector2& value )
+{
+  actor.SetProperty( propertyCurrentCenter, value );
+}
+
+PageTurnView::PageTurnView( PageFactory& pageFactory, const Vector2& viewPageSize )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mPageFactory( &pageFactory ),
+  mPageSize( viewPageSize ),
+  mSpineShadowParameter( DEFAULT_SPINE_SHADOW_PARAMETER ),
+  mDistanceUpCorner( 0.f ),
+  mDistanceBottomCorner( 0.f ),
+  mPanDisplacement( 0.f ),
+  mTotalPageCount( 0 ),
+  mCurrentPageIndex( 0 ),
+  mTurningPageIndex( 0 ),
+  mIndex( 0 ),
+  mSlidingCount( 0 ),
+  mAnimatingCount( 0 ),
+  mConstraints( false ),
+  mPress( false ),
+  mPageUpdated( true ),
+  mPageTurnStartedSignal(),
+  mPageTurnFinishedSignal(),
+  mPagePanStartedSignal(),
+  mPagePanFinishedSignal()
+{
+}
+
+PageTurnView::~PageTurnView()
+{
+}
+
+void PageTurnView::OnInitialize()
+{
+   // create the book spine effect for static pages
+  Property::Map spineEffectMap = CreatePageTurnBookSpineEffect();
+  mSpineEffectShader = CreateShader( spineEffectMap );
+  mSpineEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter );
+  // create the turn effect for turning pages
+  Property::Map turnEffectMap = CreatePageTurnEffect();
+  mTurnEffectShader = CreateShader( turnEffectMap );
+  mTurnEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter );
+
+  // create the grid geometry for pages
+  uint16_t width = static_cast<uint16_t>(mPageSize.width / DEFAULT_GRID_DENSITY + 0.5f);
+  uint16_t height = static_cast<uint16_t>(mPageSize.height / DEFAULT_GRID_DENSITY + 0.5f);
+  mGeometry = VisualFactoryCache::CreateGridGeometry( Uint16Pair( width, height ) );
+
+  mPages.reserve( NUMBER_OF_CACHED_PAGES );
+  for( int i = 0; i < NUMBER_OF_CACHED_PAGES; i++ )
+  {
+    mPages.push_back( Page() );
+    mPages[i].actor.SetSize( mPageSize );
+    Self().Add( mPages[i].actor );
+  }
+
+  // create the layer for turning pages
+  mTurningPageLayer = Layer::New();
+  mTurningPageLayer.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+  mTurningPageLayer.SetBehavior(Layer::LAYER_3D);
+  mTurningPageLayer.Raise();
+
+  // Set control size and the parent origin of page layers
+  OnPageTurnViewInitialize();
+
+  Self().Add(mTurningPageLayer);
+
+  mTotalPageCount = static_cast<int>( mPageFactory->GetNumberOfPages() );
+  // add pages to the scene, and set depth for the stacked pages
+  for( int i = 0; i < NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++ )
+  {
+    AddPage( i );
+    mPages[i].actor.SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
+  }
+  mPages[0].actor.SetVisible(true);
+
+  // enable the pan gesture which is attached to the control
+  EnableGestureDetection(Gesture::Type(Gesture::Pan));
+}
+
+Shader PageTurnView::CreateShader( const Property::Map& shaderMap )
+{
+  Shader shader;
+  Property::Value* shaderValue = shaderMap.Find( Toolkit::Visual::Property::SHADER, CUSTOM_SHADER );
+  Property::Map shaderSource;
+  if( shaderValue && shaderValue->Get( shaderSource ) )
+  {
+    std::string vertexShader;
+    Property::Value* vertexShaderValue = shaderSource.Find( Toolkit::Visual::Shader::Property::VERTEX_SHADER, CUSTOM_VERTEX_SHADER );
+    if( !vertexShaderValue || !vertexShaderValue->Get( vertexShader ) )
+    {
+      DALI_LOG_ERROR("PageTurnView::CreateShader failed: vertex shader source is not available.\n");
+    }
+    std::string fragmentShader;
+    Property::Value* fragmentShaderValue = shaderSource.Find( Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, CUSTOM_FRAGMENT_SHADER );
+    if( !fragmentShaderValue || !fragmentShaderValue->Get( fragmentShader ) )
+    {
+      DALI_LOG_ERROR("PageTurnView::CreateShader failed: fragment shader source is not available.\n");
+    }
+    shader = Shader::New( vertexShader, fragmentShader );
+  }
+  else
+  {
+    DALI_LOG_ERROR("PageTurnView::CreateShader failed: shader source is not available.\n");
+  }
+
+  return shader;
+}
+
+void PageTurnView::SetupShadowView()
+{
+  mShadowView = Toolkit::ShadowView::New( 0.25f, 0.25f );
+  Vector3 origin = mTurningPageLayer.GetCurrentParentOrigin();
+  mShadowView.SetParentOrigin( origin );
+  mShadowView.SetAnchorPoint( origin );
+  mShadowView.SetPointLightFieldOfView( Math::PI / 2.0f);
+  mShadowView.SetShadowColor(DEFAULT_SHADOW_COLOR);
+
+  mShadowPlaneBackground = Actor::New();
+  mShadowPlaneBackground.SetParentOrigin( ParentOrigin::CENTER );
+  mShadowPlaneBackground.SetSize( mControlSize );
+  Self().Add( mShadowPlaneBackground );
+  mShadowView.SetShadowPlaneBackground( mShadowPlaneBackground );
+
+  mPointLight = Actor::New();
+  mPointLight.SetAnchorPoint( origin );
+  mPointLight.SetParentOrigin( origin );
+  mPointLight.SetPosition( 0.f, 0.f, mPageSize.width*POINT_LIGHT_HEIGHT_RATIO );
+  Self().Add( mPointLight );
+  mShadowView.SetPointLight( mPointLight );
+
+  mTurningPageLayer.Add( mShadowView );
+  mShadowView.Activate();
+}
+
+void PageTurnView::OnStageConnection( int depth )
+{
+  SetupShadowView();
+
+  Control::OnStageConnection( depth );
+}
+
+void PageTurnView::OnStageDisconnection()
+{
+  if(mShadowView)
+  {
+    mShadowView.RemoveConstraints();
+    mPointLight.Unparent();
+    mShadowPlaneBackground.Unparent();
+    mShadowView.Unparent();
+  }
+
+  // make sure the status of the control is updated correctly when the pan gesture is interrupted
+  StopTurning();
+
+  Control::OnStageDisconnection();
+}
+
+void PageTurnView::SetPageSize( const Vector2& viewPageSize )
+{
+  mPageSize = viewPageSize;
+
+  if( mPointLight )
+  {
+    mPointLight.SetPosition( 0.f, 0.f, mPageSize.width*POINT_LIGHT_HEIGHT_RATIO );
+  }
+
+  for( size_t i=0; i<mPages.size(); i++ )
+  {
+    mPages[i].actor.SetSize( mPageSize );
+  }
+
+  OnPageTurnViewInitialize();
+
+  if( mShadowPlaneBackground )
+  {
+    mShadowPlaneBackground.SetSize( mControlSize );
+  }
+}
+
+Vector2 PageTurnView::GetPageSize()
+{
+  return mPageSize;
+}
+
+void PageTurnView::SetSpineShadowParameter( const Vector2& spineShadowParameter )
+{
+  mSpineShadowParameter = spineShadowParameter;
+
+  // set spine shadow parameter to all the shader effects
+  mSpineEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter );
+  mTurnEffectShader.RegisterProperty(PROPERTY_SPINE_SHADOW, mSpineShadowParameter );
+}
+
+Vector2 PageTurnView::GetSpineShadowParameter()
+{
+  return mSpineShadowParameter;
+}
+
+void PageTurnView::GoToPage( unsigned int pageId )
+{
+  int pageIdx = Clamp( static_cast<int>(pageId), 0, mTotalPageCount-1);
+
+  if( mCurrentPageIndex == pageIdx  )
+  {
+    return;
+  }
+
+  // if any animation ongoing, stop it.
+  StopTurning();
+
+  // record the new current page index
+  mCurrentPageIndex = pageIdx;
+
+
+  // add the current page and the pages right before and after it
+  for( int i = pageIdx - NUMBER_OF_CACHED_PAGES_EACH_SIDE; i < pageIdx + NUMBER_OF_CACHED_PAGES_EACH_SIDE; i++ )
+  {
+    AddPage( i );
+  }
+
+  mPages[pageId%NUMBER_OF_CACHED_PAGES].actor.SetVisible(true);
+  if( pageId > 0 )
+  {
+    mPages[(pageId-1)%NUMBER_OF_CACHED_PAGES].actor.SetVisible(true);
+  }
+  // set ordered depth to the stacked pages
+  OrganizePageDepth();
+}
+
+unsigned int PageTurnView::GetCurrentPage()
+{
+  DALI_ASSERT_ALWAYS( mCurrentPageIndex >= 0 );
+  return static_cast< unsigned int >( mCurrentPageIndex );
+}
+
+void PageTurnView::AddPage( int pageIndex )
+{
+  if(pageIndex > -1  && pageIndex < mTotalPageCount) // whether the page is available from the page factory
+  {
+    int index = pageIndex % NUMBER_OF_CACHED_PAGES;
+
+    Texture newPage;
+    newPage = mPageFactory->NewPage( pageIndex );
+    DALI_ASSERT_ALWAYS( newPage && "must pass in valid texture" );
+
+    bool isLeftSide = ( pageIndex < mCurrentPageIndex );
+    if( mPages[index].isTurnBack != isLeftSide )
+    {
+      mPages[index].ChangeTurnDirection();
+    }
+
+    float degree = isLeftSide ? 180.f :0.f;
+    mPages[index].actor.SetOrientation( Degree( degree ), Vector3::YAXIS );
+    mPages[index].actor.SetVisible( false );
+    mPages[index].UseEffect( mSpineEffectShader, mGeometry );
+    mPages[index].SetTexture( newPage );
+
+    // For Portrait, nothing to do
+    // For Landscape, set the parent origin to CENTER
+    OnAddPage( mPages[index].actor, isLeftSide );
+  }
+}
+
+void PageTurnView::RemovePage( int pageIndex )
+{
+  if( pageIndex > -1 && pageIndex < mTotalPageCount)
+  {
+    int index = pageIndex % NUMBER_OF_CACHED_PAGES;
+    mPages[index].actor.SetVisible(false);
+  }
+}
+
+void PageTurnView::OnPan( const PanGesture& gesture )
+{
+  // the pan gesture is attached to control itself instead of each page
+  switch( gesture.state )
+  {
+    case Gesture::Started:
+    {
+      // check whether the undergoing turning page number already reaches the maximum allowed
+      if( mPageUpdated && mAnimatingCount< MAXIMUM_TURNING_NUM && mSlidingCount < 1 )
+      {
+        SetPanActor( gesture.position ); // determine which page actor is panned
+        if( mTurningPageIndex != -1 && mPages[mTurningPageIndex % NUMBER_OF_CACHED_PAGES].actor.GetParent() != Self()) // if the page is added to turning layer,it is undergoing an animation currently
+        {
+          mTurningPageIndex = -1;
+        }
+        PanStarted( SetPanPosition( gesture.position ) );  // pass in the pan position in the local page coordinate
+      }
+      else
+      {
+        mTurningPageIndex = -1;
+      }
+      break;
+    }
+    case Gesture::Continuing:
+    {
+      PanContinuing( SetPanPosition( gesture.position ) ); // pass in the pan position in the local page coordinate
+      break;
+    }
+    case Gesture::Finished:
+    case Gesture::Cancelled:
+    {
+      PanFinished( SetPanPosition( gesture.position ), gesture.GetSpeed() );
+      break;
+    }
+    case Gesture::Clear:
+    case Gesture::Possible:
+    default:
+    {
+      break;
+    }
+  }
+}
+
+void PageTurnView::PanStarted( const Vector2& gesturePosition )
+{
+  mPressDownPosition = gesturePosition;
+
+  if( mTurningPageIndex == -1 )
+  {
+    return;
+  }
+
+  mIndex = mTurningPageIndex % NUMBER_OF_CACHED_PAGES;
+
+  mOriginalCenter = gesturePosition;
+  mPress = false;
+  mPageUpdated = false;
+
+  // Guard against destruction during signal emission
+  Toolkit::PageTurnView handle( GetOwner() );
+  mPagePanStartedSignal.Emit( handle );
+}
+
+void PageTurnView::PanContinuing( const Vector2& gesturePosition )
+{
+  if( mTurningPageIndex == -1  )
+  {
+    return;
+  }
+
+  // Guard against destruction during signal emission
+  Toolkit::PageTurnView handle( GetOwner() );
+
+  if(!mPress)
+  {
+    // when the touch down position is near the spine
+    // or when the panning goes outwards or some other position which would tear the paper in real situation
+    // we change the start position into the current panning position and update the shader parameters
+    if( mOriginalCenter.x <  mPageSize.width*MINIMUM_START_POSITION_RATIO
+        || gesturePosition.x > mOriginalCenter.x-1.0f
+        || ( ( gesturePosition.x/mOriginalCenter.x > gesturePosition.y/mOriginalCenter.y ) &&
+             ( gesturePosition.x/mOriginalCenter.x > (gesturePosition.y-mPageSize.height )/(mOriginalCenter.y-mPageSize.height ) ) ) )
+    {
+      mOriginalCenter = gesturePosition;
+    }
+    else
+    {
+      mDistanceUpCorner = mOriginalCenter.Length();
+      mDistanceBottomCorner = ( mOriginalCenter - Vector2( 0.0f, mPageSize.height ) ).Length();
+      mShadowView.Add( mPages[mIndex].actor );
+      mPages[mIndex].UseEffect( mTurnEffectShader );
+      mPages[mIndex].SetOriginalCenter( mOriginalCenter );
+      mCurrentCenter = mOriginalCenter;
+      mPages[mIndex].SetCurrentCenter( mCurrentCenter );
+      mPanDisplacement = 0.f;
+      mConstraints = false;
+      mPress = true;
+      mAnimatingCount++;
+
+      mPageTurnStartedSignal.Emit( handle, static_cast<unsigned int>(mTurningPageIndex), !mPages[mIndex].isTurnBack );
+      int id = mTurningPageIndex + (mPages[mIndex].isTurnBack ? -1 : 1);
+      if( id >=0 && id < mTotalPageCount )
+      {
+        mPages[id%NUMBER_OF_CACHED_PAGES].actor.SetVisible(true);
+      }
+
+      mShadowView.RemoveConstraints();
+      Actor self = Self();
+      mPages[mIndex].SetPanDisplacement( 0.f );
+
+      Constraint shadowBlurStrengthConstraint = Constraint::New<float>( mShadowView, mShadowView.GetBlurStrengthPropertyIndex(), ShadowBlurStrengthConstraint( mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO ) );
+      shadowBlurStrengthConstraint.AddSource( Source(mPages[mIndex].actor,  mPages[mIndex].propertyCurrentCenter) );
+      shadowBlurStrengthConstraint.AddSource( Source(mPages[mIndex].actor,  mPages[mIndex].propertyOriginalCenter) );
+      shadowBlurStrengthConstraint.AddSource( Source(mPages[mIndex].actor,  mPages[mIndex].propertyPanDisplacement) );
+      shadowBlurStrengthConstraint.Apply();
+    }
+  }
+  else
+  {
+    Vector2 currentCenter = gesturePosition;
+
+    // Test whether the new current center would tear the paper from the top pine in real situation
+    // we do not forbid this totally, which would restrict the panning gesture too much
+    // instead, set it to the nearest allowable position
+    float distanceUpCorner = currentCenter.Length();
+    float distanceBottomCorner = ( currentCenter-Vector2( 0.0f, mPageSize.height ) ).Length();
+    if( distanceUpCorner > mDistanceUpCorner )
+    {
+      currentCenter = currentCenter*mDistanceUpCorner/distanceUpCorner;
+    }
+    // would tear the paper from the bottom spine in real situation
+    if( distanceBottomCorner > mDistanceBottomCorner )
+    {
+      currentCenter = ( ( currentCenter - Vector2( 0.0f, mPageSize.height ) )*mDistanceBottomCorner/distanceBottomCorner + Vector2(0.0f,mPageSize.height ) );
+    }
+    // If direction has a very high y component, reduce it.
+    Vector2 curveDirection = currentCenter - mOriginalCenter;
+    if( fabs( curveDirection.y ) > fabs( curveDirection.x ) )
+    {
+      currentCenter.y = mOriginalCenter.y + ( currentCenter.y - mOriginalCenter.y ) * fabs( curveDirection.x/curveDirection.y );
+    }
+    // If the vertical distance is high, reduce it
+    float yShift = currentCenter.y - mOriginalCenter.y;
+    if( fabs( yShift ) > mPageSize.height * MAXIMUM_VERTICAL_MOVEMENT_RATIO )
+    {
+      currentCenter.y = mOriginalCenter.y + yShift*mPageSize.height*MAXIMUM_VERTICAL_MOVEMENT_RATIO/fabs(yShift );
+    }
+
+    // use contraints to control the page shape and rotation when the pan position is near the spine
+    if( currentCenter.x <= mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO && mOriginalCenter.x > mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO )
+    {
+      // set the property values used by the constraints
+      mPanDisplacement = mPageSize.width*PAGE_TURN_OVER_THRESHOLD_RATIO - currentCenter.x;
+      mPages[mIndex].SetPanDisplacement( mPanDisplacement );
+      mPages[mIndex].SetPanCenter( currentCenter );
+
+      // set up the OriginalCenterConstraint and CurrentCebterConstraint to the PageTurnEdffect
+      // also set up the RotationConstraint to the page actor
+      if( !mConstraints )
+      {
+        Vector2 corner;
+        // the corner position need to be a little far away from the page edge to ensure the whole page is lift up
+        if( currentCenter.y >= mOriginalCenter.y )
+        {
+          corner = Vector2( 1.1f*mPageSize.width, 0.f );
+        }
+        else
+        {
+          corner = mPageSize*1.1f;
+        }
+
+        Vector2 offset( currentCenter-mOriginalCenter );
+        float k = - ( (mOriginalCenter.x-corner.x)*offset.x + (mOriginalCenter.y-corner.y)*offset.y )
+                   /( offset.x*offset.x + offset.y*offset.y );
+        offset *= k;
+        Actor self = Self();
+
+        Constraint originalCenterConstraint = Constraint::New<Vector2>( mPages[mIndex].actor, mPages[mIndex].propertyOriginalCenter, OriginalCenterConstraint( mOriginalCenter, offset ));
+        originalCenterConstraint.AddSource( Source( mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement ) );
+        originalCenterConstraint.Apply();
+
+        Constraint currentCenterConstraint = Constraint::New<Vector2>( mPages[mIndex].actor, mPages[mIndex].propertyCurrentCenter, CurrentCenterConstraint(mPageSize.width));
+        currentCenterConstraint.AddSource( Source( mPages[mIndex].actor, mPages[mIndex].propertyPanCenter ) );
+        currentCenterConstraint.AddSource( Source( mPages[mIndex].actor, mPages[mIndex].propertyOriginalCenter ) );
+        currentCenterConstraint.Apply();
+
+        PageTurnApplyInternalConstraint( mPages[mIndex].actor, mPageSize.height );
+
+        float distance = offset.Length();
+        Constraint rotationConstraint = Constraint::New<Quaternion>( mPages[mIndex].actor, Actor::Property::ORIENTATION, RotationConstraint(distance, mPageSize.width, mPages[mIndex].isTurnBack));
+        rotationConstraint.AddSource( Source( mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement ) );
+        rotationConstraint.Apply();
+
+        mConstraints = true;
+      }
+    }
+    else
+    {
+      if(mConstraints) // remove the constraint is the pan position move back to far away from the spine
+      {
+        mPages[mIndex].actor.RemoveConstraints();
+        mPages[mIndex].SetOriginalCenter(mOriginalCenter );
+        mConstraints = false;
+        mPanDisplacement = 0.f;
+      }
+
+      mPages[mIndex].SetCurrentCenter( currentCenter );
+      mCurrentCenter = currentCenter;
+      PageTurnApplyInternalConstraint(mPages[mIndex].actor, mPageSize.height );
+    }
+  }
+}
+
+void PageTurnView::PanFinished( const Vector2& gesturePosition, float gestureSpeed )
+{
+  // Guard against destruction during signal emission
+  Toolkit::PageTurnView handle( GetOwner() );
+
+  if( mTurningPageIndex == -1  )
+  {
+    if( mAnimatingCount< MAXIMUM_TURNING_NUM && mSlidingCount < 1)
+    {
+      OnPossibleOutwardsFlick( gesturePosition, gestureSpeed );
+    }
+
+    return;
+  }
+
+  mPagePanFinishedSignal.Emit( handle );
+
+  if(mPress)
+  {
+    if(mConstraints) // if with constraints, the pan finished position is near spine, set up an animation to turn the page over
+    {
+      // update the pages here instead of in the TurnedOver callback function
+      // as new page is allowed to respond to the pan gesture before other pages finishing animation
+      if(mPages[mIndex].isTurnBack)
+      {
+        mCurrentPageIndex--;
+        RemovePage( mCurrentPageIndex+NUMBER_OF_CACHED_PAGES_EACH_SIDE );
+        AddPage( mCurrentPageIndex-NUMBER_OF_CACHED_PAGES_EACH_SIDE );
+      }
+      else
+      {
+        mCurrentPageIndex++;
+        RemovePage( mCurrentPageIndex-NUMBER_OF_CACHED_PAGES_EACH_SIDE-1 );
+        AddPage( mCurrentPageIndex+NUMBER_OF_CACHED_PAGES_EACH_SIDE-1 );
+      }
+      OrganizePageDepth();
+
+      // set up an animation to turn the page over
+      float width = mPageSize.width*(1.f+PAGE_TURN_OVER_THRESHOLD_RATIO);
+      Animation animation = Animation::New( std::max(0.1f,PAGE_TURN_OVER_ANIMATION_DURATION * (1.0f - mPanDisplacement / width)) );
+      animation.AnimateTo( Property(mPages[mIndex].actor, mPages[mIndex].propertyPanDisplacement),
+                           width,AlphaFunction::EASE_OUT_SINE);
+      animation.AnimateTo( Property(mPages[mIndex].actor, mPages[mIndex].propertyPanCenter),
+                           Vector2(-mPageSize.width*1.1f, 0.5f*mPageSize.height), AlphaFunction::EASE_OUT_SINE);
+      mAnimationPageIdPair[animation] = mTurningPageIndex;
+      animation.Play();
+      animation.FinishedSignal().Connect( this, &PageTurnView::TurnedOver );
+    }
+    else // the pan finished position is far away from the spine, set up an animation to slide the page back instead of turning over
+    {
+      Animation animation= Animation::New( PAGE_SLIDE_BACK_ANIMATION_DURATION * (mOriginalCenter.x - mCurrentCenter.x) / mPageSize.width / PAGE_TURN_OVER_THRESHOLD_RATIO );
+      animation.AnimateTo( Property( mPages[mIndex].actor, mPages[mIndex].propertyCurrentCenter ),
+                           mOriginalCenter, AlphaFunction::LINEAR );
+      mAnimationPageIdPair[animation] = mTurningPageIndex;
+      animation.Play();
+      mSlidingCount++;
+      animation.FinishedSignal().Connect( this, &PageTurnView::SliddenBack );
+
+      mPageTurnStartedSignal.Emit( handle, static_cast<unsigned int>(mTurningPageIndex), mPages[mIndex].isTurnBack );
+    }
+  }
+  else
+  {
+    // In portrait view, an outwards flick should turn the previous page back
+    // In landscape view, nothing to do
+    OnPossibleOutwardsFlick( gesturePosition, gestureSpeed );
+  }
+  mPageUpdated = true;
+}
+
+void PageTurnView::TurnedOver( Animation& animation )
+{
+  int pageId = mAnimationPageIdPair[animation];
+  int index = pageId%NUMBER_OF_CACHED_PAGES;
+
+  mPages[index].ChangeTurnDirection();
+  mPages[index].actor.RemoveConstraints();
+  Self().Add(mPages[index].actor);
+  mAnimatingCount--;
+  mAnimationPageIdPair.erase( animation );
+
+  float degree = mPages[index].isTurnBack ? 180.f : 0.f;
+  mPages[index].actor.SetOrientation( Degree(degree), Vector3::YAXIS );
+  mPages[index].UseEffect( mSpineEffectShader );
+
+  int id = pageId + (mPages[index].isTurnBack ? -1 : 1);
+  if( id >=0 && id < mTotalPageCount )
+  {
+    mPages[id%NUMBER_OF_CACHED_PAGES].actor.SetVisible(false);
+  }
+
+  OnTurnedOver( mPages[index].actor, mPages[index].isTurnBack );
+
+  // Guard against destruction during signal emission
+  Toolkit::PageTurnView handle( GetOwner() );
+  mPageTurnFinishedSignal.Emit( handle, static_cast<unsigned int>(pageId), mPages[index].isTurnBack );
+}
+
+void PageTurnView::SliddenBack( Animation& animation )
+{
+  int pageId = mAnimationPageIdPair[animation];
+  int index = pageId%NUMBER_OF_CACHED_PAGES;
+  Self().Add(mPages[index].actor);
+  mSlidingCount--;
+  mAnimatingCount--;
+  mAnimationPageIdPair.erase( animation );
+
+  mPages[index].UseEffect( mSpineEffectShader );
+
+  int id = pageId + (mPages[index].isTurnBack ? -1 : 1);
+  if( id >=0 && id < mTotalPageCount )
+  {
+    mPages[id%NUMBER_OF_CACHED_PAGES].actor.SetVisible(false);
+  }
+
+  // Guard against destruction during signal emission
+  Toolkit::PageTurnView handle( GetOwner() );
+  mPageTurnFinishedSignal.Emit( handle, static_cast<unsigned int>(pageId), mPages[index].isTurnBack );
+}
+
+void PageTurnView::OrganizePageDepth()
+{
+  for( int i=0; i<NUMBER_OF_CACHED_PAGES_EACH_SIDE;i++ )
+  {
+    if(mCurrentPageIndex+i < mTotalPageCount)
+    {
+      mPages[( mCurrentPageIndex+i )%NUMBER_OF_CACHED_PAGES].actor.SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
+    }
+    if( mCurrentPageIndex >= i + 1 )
+    {
+      mPages[( mCurrentPageIndex-i-1 )%NUMBER_OF_CACHED_PAGES].actor.SetZ( -static_cast<float>( i )*STATIC_PAGE_INTERVAL_DISTANCE );
+    }
+  }
+}
+
+void PageTurnView::StopTurning()
+{
+  mAnimatingCount = 0;
+  mSlidingCount = 0;
+
+  if( !mPageUpdated )
+  {
+    int index = mTurningPageIndex % NUMBER_OF_CACHED_PAGES;
+    Self().Add( mPages[ index ].actor );
+    mPages[ index ].actor.RemoveConstraints();
+    mPages[ index ].UseEffect( mSpineEffectShader );
+    float degree = mTurningPageIndex==mCurrentPageIndex ? 0.f :180.f;
+    mPages[index].actor.SetOrientation( Degree(degree), Vector3::YAXIS );
+    mPageUpdated = true;
+  }
+
+  if( !mAnimationPageIdPair.empty() )
+  {
+    for (std::map<Animation,int>::iterator it=mAnimationPageIdPair.begin(); it!=mAnimationPageIdPair.end(); ++it)
+    {
+      static_cast<Animation>(it->first).SetCurrentProgress( 1.f );
+    }
+  }
+}
+
+Toolkit::PageTurnView::PageTurnSignal& PageTurnView::PageTurnStartedSignal()
+{
+  return mPageTurnStartedSignal;
+}
+
+Toolkit::PageTurnView::PageTurnSignal& PageTurnView::PageTurnFinishedSignal()
+{
+  return mPageTurnFinishedSignal;
+}
+
+Toolkit::PageTurnView::PagePanSignal& PageTurnView::PagePanStartedSignal()
+{
+  return mPagePanStartedSignal;
+}
+
+Toolkit::PageTurnView::PagePanSignal& PageTurnView::PagePanFinishedSignal()
+{
+  return mPagePanFinishedSignal;
+}
+
+bool PageTurnView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_PAGE_TURN_STARTED ) )
+  {
+    pageTurnView.PageTurnStartedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_PAGE_TURN_FINISHED ) )
+  {
+    pageTurnView.PageTurnFinishedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_PAGE_PAN_STARTED ) )
+  {
+    pageTurnView.PagePanStartedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_PAGE_PAN_FINISHED ) )
+  {
+    pageTurnView.PagePanFinishedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void PageTurnView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast( Dali::BaseHandle( object ) );
+
+  if( pageTurnView )
+  {
+    PageTurnView& pageTurnViewImpl( GetImplementation( pageTurnView ) );
+
+    switch( index )
+    {
+      case Toolkit::PageTurnView::Property::VIEW_PAGE_SIZE:
+      {
+        pageTurnViewImpl.SetPageSize( value.Get<Vector2>() );
+        break;
+      }
+      case Toolkit::PageTurnView::Property::CURRENT_PAGE_ID:
+      {
+        pageTurnViewImpl.GoToPage( value.Get<int>() );
+        break;
+      }
+      case Toolkit::PageTurnView::Property::SPINE_SHADOW:
+      {
+        pageTurnViewImpl.SetSpineShadowParameter( value.Get<Vector2>() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value PageTurnView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::PageTurnView pageTurnView = Toolkit::PageTurnView::DownCast( Dali::BaseHandle( object ) );
+
+  if( pageTurnView )
+  {
+    PageTurnView& pageTurnViewImpl( GetImplementation( pageTurnView ) );
+
+    switch( index )
+    {
+      case Toolkit::PageTurnView::Property::VIEW_PAGE_SIZE:
+      {
+        value = pageTurnViewImpl.GetPageSize();
+        break;
+      }
+      case Toolkit::PageTurnView::Property::CURRENT_PAGE_ID:
+      {
+        value = static_cast<int>( pageTurnViewImpl.GetCurrentPage() );
+        break;
+      }
+      case Toolkit::PageTurnView::Property::SPINE_SHADOW:
+      {
+        value = pageTurnViewImpl.GetSpineShadowParameter();
+        break;
+      }
+    }
+  }
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h b/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.h
new file mode 100644 (file)
index 0000000..b553dca
--- /dev/null
@@ -0,0 +1,458 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PAGE_TURN_VIEW_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_PAGE_TURN_VIEW_IMPL_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-turn-view.h>
+#include <dali-toolkit/devel-api/controls/page-turn-view/page-factory.h>
+#include <dali-toolkit/devel-api/controls/shadow-view/shadow-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class PageTurnView : public Control
+{
+protected:
+
+  /**
+   * The book page class
+   */
+  struct Page
+  {
+    /**
+     * Constructor
+     */
+    Page();
+    /**
+     * Destructor
+     */
+    ~Page(){};
+
+    /**
+     * Set the page texture content
+     * @param[in] texture The content of the page.
+     */
+    void SetTexture( Texture texture );
+
+    /**
+     * Apply an effect onto the page actor.
+     * @param[in] newShader The shader for rendering effect.
+     */
+    void UseEffect(Shader newShader);
+
+    /**
+     * Apply an effect onto the page actor.
+     * @param[in] newShader The shader for rendering effect.
+     * @param[in] geometry The geometry for rendering effect.
+     */
+    void UseEffect(Shader newShader, Geometry geometry);
+
+    /**
+     * Change the page turning direction.
+     */
+    void ChangeTurnDirection();
+
+    /**
+     * Set the pan displacement property
+     * @param[in] value The property value
+     */
+    void SetPanDisplacement(float value);
+
+    /**
+     * Set the pan center property
+     * @param[in] value The property value
+     */
+    void SetPanCenter( const Vector2& value );
+
+    /**
+     * Set the original center property to be used by shader
+     * @param[in] value The property value
+     */
+    void SetOriginalCenter( const Vector2& value );
+
+    /**
+     * Set the current center property to be used by shader
+     * @param[in] value The property value
+     */
+    void SetCurrentCenter( const Vector2& value );
+
+    Actor actor;                              ///< The page actor
+    Shader shader;                            ///< The shader used by the actor
+    TextureSet textureSet;                    ///< The set of textures used by the actor
+    Renderer renderer;                        ///< The renderer of the actor
+    bool isTurnBack;                          ///< The turning direction
+    Property::Index propertyPanDisplacement;  ///< The horizontal displacement of the pan
+    Property::Index propertyPanCenter;        ///< The current pan position
+    Property::Index propertyOriginalCenter;   ///< The original center to be used by the shader
+    Property::Index propertyCurrentCenter;    ///< The current center to be used by the shader
+    Property::Index propertyTurnDirection;    ///< The turning direction property
+  };
+
+
+protected:
+
+  /**
+   * Constructor.
+   * It initializes the PageTurnView members
+   */
+  PageTurnView( PageFactory& pageFactory, const Vector2& viewPageSize );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PageTurnView();
+
+public:
+
+  /**
+   * Set the page size
+   * @param[in] viewPageSize The size of pages
+   */
+  void SetPageSize( const Vector2& viewPageSize );
+
+  /**
+   * Retrieve the page size.
+   * @return The page size.
+   */
+  Vector2 GetPageSize();
+
+  /**
+   * Set the spine shadow parameter to the shader effects.
+   * The two parameters are the major&minor radius (in pixels) to form an ellipse shape.
+   * The top-left quarter of this ellipse is used to calculate spine normal for simulating shadow.
+   * @param [in] spineShadowParameter The major&minor ellipse radius for the simulated spine shadow.
+   */
+  void SetSpineShadowParameter( const Vector2& spineShadowParameter );
+
+  /**
+   * Retrieve the spine shadow parameter of the shader effects.
+   * @return The spine shadow parameter.
+   */
+  Vector2 GetSpineShadowParameter();
+
+  /*
+   * Jump to a given page.
+   * @param[in] pageId The new current page id.
+   */
+  void GoToPage( unsigned int pageId );
+
+  /**
+   * Retrieve the id of the current Page.
+   * @return The current page id.
+   */
+  unsigned int GetCurrentPage();
+
+protected:
+
+  /**
+   * This method gets a page from the factory and add to the control
+   * to keep NUMBER_OF_CACHED_PAGES_EACH_SIDE pages available in each side
+   * @param[in] pageIndex The index of the page to be added
+   */
+  void AddPage( int pageIndex );
+
+  /**
+   * This method removes a page from the control
+   * to keep only NUMBER_OF_CACHED_PAGES_EACH_SIDE pages available in each side
+   * @param[in] pageIndex The index of the page to be removed
+   */
+  void RemovePage( int pageIndex );
+
+  /**
+   * This method updates the actor and animation states after one page is turned over
+   * This method is a callback, connected when receiving the finished signal of a page turning over animation.
+   * @param [in] the page turning over animation handle
+   */
+  void TurnedOver( Animation& animation );
+
+  /**
+   * This method organize the depth of the pages on stage
+   * It is called when there is page added or removed from the control
+   */
+  void OrganizePageDepth();
+
+private:
+
+  /**
+   * Create shader from a property map.
+   * @param[in] shaderMap The shader property map;
+   * @return The created shader.
+   */
+  Shader CreateShader( const Property::Map& shaderMap );
+
+ /**
+  * Set up the shadow view control to cast shadow
+  */
+  void SetupShadowView();
+
+  /**
+   * This method defines the processes when the pan started, gets called by OnPan( .. )
+   * @param[in] gesturePosition The current touch position in local page actor coordinates.
+   */
+  void PanStarted( const Vector2& gesturePosition );
+
+  /**
+   * This method defines the processes when the pan continuing, gets called by OnPan( .. )
+   * @param[in] gesturePosition The current touch position in local page actor coordinates.
+   */
+  void PanContinuing( const Vector2& gesturePosition );
+
+  /**
+   * This method defines the processes when the pan finished, gets called by OnPanGesture( .. )
+   * @param[in] gesturePosition The current touch position in local page actor coordinates.
+   * @param[in] gestureSpeed The speed of the pan ( in pixels per millisecond )
+   */
+  void PanFinished( const Vector2& gesturePosition, float gestureSpeed );
+
+  /**
+   * This method updates the actor and the animation states after one page is slidden back instead of turned over
+   * This method is a callback, connected when receiving the finished signal of a page sliding back animation.
+   * @param [in] the page sliding back animation handle
+   */
+  void SliddenBack( Animation& animation );
+
+  /**
+   * Stop the page turning animation and contraint.
+   * This method should be called when taking off stage or jump to a specified page.
+   */
+  void StopTurning();
+
+private: // from Control
+
+  /**
+   * @copydoc Toolkit::Control::OnPan
+   */
+  virtual void OnPan( const PanGesture& gesture );
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+private: // implemented differently by PageTurnLandscapeView and PageTurnPortraitView
+
+  /**
+   * This method is called after the pageTurnView initialization.
+   * To set the size of the control size and the parent origin of turning page layer
+   * Implemented in subclasses to provide specific behaviour.
+   */
+  virtual void OnPageTurnViewInitialize() = 0;
+
+  /**
+   * This method is called after the a new page is added to the stage.
+   * Could be re-implemented in subclasses to provide specific behaviour
+   * @param[in] newPage The added page actor
+   * @param[in] isLeftSide Which side the new page is added to
+   */
+  virtual void OnAddPage( Actor newPage, bool isLeftSide ) { }
+
+  /**
+   * This method is called when pan started or continuing
+   * to calculate the pan position in local page actor coordinate given the pan position in control coordinate
+   * Implemented in subclasses to provide specific behaviour.
+   * @param[in] gesturePosition The pan position in the control coordinate
+   * @return The pan position in the page actor local coordinate
+   */
+  virtual Vector2 SetPanPosition( const Vector2& gesturePosition ) = 0;
+
+  /**
+   * This method is called when pan started to determined which page is panned given the pan position in control coordinate
+   * Implemented in subclasses to provide specific behaviour.
+   * @param[in] gesturePosition The pan position in the control coordinate
+   */
+  virtual void SetPanActor( const Vector2& panPosition ) = 0;
+
+  /**
+   * This method is called when pan finished to detect outwards flick
+   * In portrait view, start an animation of turning previous page back when outwards flick is detected
+   * In landscape view, nothing to do
+   * @param[in] panPosition The pan position in the page actor local coordinate
+   * @param[in] gestureSpeed The speed of the pan gesture( in pixels per millisecond )
+   */
+  virtual void OnPossibleOutwardsFlick( const Vector2& panPosition, float gestureSpeed ) { }
+
+  /**
+   * This method is called when page is turned over
+   * In portrait view, the page on the left side is not rendered
+   * @param[in] actor The page actor
+   * @param[in] isLeftSide Which side the page is turned to
+   */
+  virtual void OnTurnedOver( Actor actor, bool isLeftSide ) { }
+
+public: //signal and property
+
+  /**
+   * @copydoc Toolkit::PageTurnView::PageTurnStartedSignal()
+   */
+  Toolkit::PageTurnView::PageTurnSignal& PageTurnStartedSignal();
+
+  /**
+   * @copydoc Toolkit::PageTurnView::PageTurnFinishedSignal()
+   */
+  Toolkit::PageTurnView::PageTurnSignal& PageTurnFinishedSignal();
+
+  /**
+   * @copydoc Toolkit::PageTurnView::PagePanStartSignal()
+   */
+  Toolkit::PageTurnView::PagePanSignal& PagePanStartedSignal();
+
+  /**
+   * @copydoc Toolkit::PageTurnView::PagePanFinishedSignal()
+   */
+  Toolkit::PageTurnView::PagePanSignal& PagePanFinishedSignal();
+
+  /**
+    * Connects a callback function with the object's signals.
+    * @param[in] object The object providing the signal.
+    * @param[in] tracker Used to disconnect the signal.
+    * @param[in] signalName The signal to connect to.
+    * @param[in] functor A newly allocated FunctorDelegate.
+    * @return True if the signal was connected.
+    * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+    */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+   // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+private:
+
+  //Undefined
+  PageTurnView( const PageTurnView& );
+
+  //undefined
+  PageTurnView& operator=(const PageTurnView& rhs);
+
+protected:
+
+  Layer                          mTurningPageLayer;        ///< The layer for the turning page, to avoid possible depth conflict
+  Toolkit::ShadowView            mShadowView;              ///< The shadow view control for shadow casting
+  Actor                          mShadowPlaneBackground;   ///< The plane for the shadow to cast on
+  Actor                          mPointLight;              ///< The point light used for shadow casting
+
+  PageFactory* const             mPageFactory;             ///< The factory which provides the page actors
+  Shader                         mTurnEffectShader;        ///< The group of PageTurnEffects
+  Shader                         mSpineEffectShader;       ///< The book spine shader effect
+  Geometry                       mGeometry;                ///< The grid geometry for pages
+
+  std::vector<Page>              mPages;                   ///< The vector of pages on stage
+  std::map<Animation,int>        mAnimationPageIdPair;     ///< The map to keep track which page actor is the animation act on
+
+  Vector2                        mPageSize;                ///< The page size
+  Vector2                        mControlSize;             ///< The size of the control, it is decided by the page size, the SetSize from application can not change it
+  Vector2                        mSpineShadowParameter;    ///< The spine shadow parameter for all the above shader effects
+  Vector2                        mOriginalCenter;          ///< The original center set to the PageTurnEffect
+  Vector2                        mCurrentCenter;           ///< The current center set to the PageTurnEffect
+  Vector2                        mPressDownPosition;       ///< The first press down position of the pan gesture
+
+  float                          mDistanceUpCorner;        ///< The distance between the original center of PageTurnEffect and the top-left corner of the page
+  float                          mDistanceBottomCorner;    ///< The distance between the original center of PageTurnEffect and the bottom-left corner of the page
+  float                          mPanDisplacement;         ///< The displacement of the pan after the constrains are applied
+
+  int                            mTotalPageCount;          ///< The total number of pages provided by the page factory
+  int                            mCurrentPageIndex;        ///< The index of the current page, between 0 ~ mTotalPageCount-1
+  int                            mTurningPageIndex;        ///< The index of the turning page
+  int                            mIndex;                   ///< The index to keep track which PanDisplacementProperty, CurrentCenterProperty is used for the current panning page
+  int                            mSlidingCount;            ///< The boolean vector to keep track whether there are animating pages sliding back
+  int                            mAnimatingCount;          ///< The boolean vector to keep track which PageTurnEffect, PanDisplacementProperty, CurrentCenterProperty is available for using
+
+  bool                           mConstraints;             ///< The boolean to keep track the constrains are applied or not
+  bool                           mPress;                   ///< The boolean to keep track the state of the pageTurnEffect is activated or not
+  bool                           mPageUpdated;             ///< The boolean to keep track whether is page is updated after any turning activity
+
+  Toolkit::PageTurnView::PageTurnSignal   mPageTurnStartedSignal;   ///< The signal to notify that a page has started turning
+  Toolkit::PageTurnView::PageTurnSignal   mPageTurnFinishedSignal;  ///< The signal to notify that a page has finished turning
+  Toolkit::PageTurnView::PagePanSignal    mPagePanStartedSignal;    ///< The signal to notify that a page has started panning
+  Toolkit::PageTurnView::PagePanSignal    mPagePanFinishedSignal;   ///< The signal to notify that a page has finished panning
+
+  static const char * const PROPERTY_TEXTURE_WIDTH;     ///< The uniform name of texture width
+  static const char * const PROPERTY_ORIGINAL_CENTER;   ///< The property name of original center, which is used to constrain the uniforms
+  static const char * const PROPERTY_CURRENT_CENTER;    ///< The property name of current center, which is used to constrain the uniforms
+
+  static const int               MAXIMUM_TURNING_NUM;                  ///< How many pages are allowed to animating in the same time
+  static const int               NUMBER_OF_CACHED_PAGES_EACH_SIDE;     ///< The maximum number of pages kept, (MAXIMUM_ANIMATION_NUM+1) pages for each side
+  static const int               NUMBER_OF_CACHED_PAGES;               ///< The maximum number of pages kept, (MAXIMUM_ANIMATION_NUM+1)*2 pages in total
+  static const float             STATIC_PAGE_INTERVAL_DISTANCE;        ///< The depth interval between stacked pages (static pages)
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::PageTurnView& GetImplementation(Toolkit::PageTurnView& pub)
+{
+  DALI_ASSERT_ALWAYS(pub);
+
+  Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast<Toolkit::Internal::PageTurnView&>(handle);
+}
+
+inline const Toolkit::Internal::PageTurnView& GetImplementation(const Toolkit::PageTurnView& pub)
+{
+  DALI_ASSERT_ALWAYS(pub);
+
+  const Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::PageTurnView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_PAGE_TURN_VIEW_IMPL_H
diff --git a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp
new file mode 100644 (file)
index 0000000..43758cb
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * 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 "confirmation-popup-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <cstring>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/*
+ * This struct is used to define all details required about a dynamically created signal.
+ */
+struct ControlDetailType
+{
+  const char* signalName;
+  const char* controlName;
+  const char* connectSignalPropertyName;
+};
+
+/* A table of all control details. These details are kept in one place for maintainability.
+ *  Name of the signal     | Name of the control  | Name of the property which lets the
+ *  the app-developer      | which will provide   | app developer choose which signal
+ *  can connect to.        | the signal.          | within the control to connect to.    */
+const ControlDetailType ControlDetails[] = {
+  { "controlSignalOk",       "controlOk",           "connectSignalOkSelected"     },
+  { "controlSignalCancel",   "controlCancel",       "connectSignalCancelSelected" },
+};
+const unsigned int ControlDetailsCount = sizeof( ControlDetails ) / sizeof( ControlDetails[0] );
+
+// To give sensible default behaviour to save the connect signal properties being set.
+const char* const DEFAULT_CONNECT_SIGNAL_NAME = "clicked";
+
+BaseHandle Create()
+{
+  return Toolkit::ConfirmationPopup::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ConfirmationPopup, Toolkit::Popup, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[0].connectSignalPropertyName, STRING, CONNECT_SIGNAL_OK_SELECTED     )
+DALI_PROPERTY_REGISTRATION( Toolkit, ConfirmationPopup, ControlDetails[1].connectSignalPropertyName, STRING, CONNECT_SIGNAL_CANCEL_SELECTED )
+
+// Note: We do not use the macros for signal registration as we do not want to redefine the signal name strings.
+// We have predefined them for optimal signal name to control name lookup.
+SignalConnectorType signalConnector1( typeRegistration, ControlDetails[0].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal );
+SignalConnectorType signalConnector2( typeRegistration, ControlDetails[1].signalName, &Toolkit::Internal::ConfirmationPopup::DoConnectSignal );
+
+DALI_TYPE_REGISTRATION_END()
+
+} // Unnamed namespace
+
+Dali::Toolkit::ConfirmationPopup ConfirmationPopup::New()
+{
+  // Create the implementation, temporarily owned on stack.
+  IntrusivePtr< ConfirmationPopup > internalConfirmationPopup = new ConfirmationPopup();
+
+  // Pass ownership to CustomActor
+  Dali::Toolkit::ConfirmationPopup confirmationPopup( *internalConfirmationPopup );
+
+  // Second-phase initialisation of the implementation.
+  // This can only be done after the CustomActor connection has been made...
+  internalConfirmationPopup->Initialize();
+
+  return confirmationPopup;
+}
+
+ConfirmationPopup::ConfirmationPopup()
+: Toolkit::Internal::Popup()
+{
+  mControlSignals.reserve( MAXIMUM_NUMBER_OF_CONTROLS );
+  mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_OK ] = DEFAULT_CONNECT_SIGNAL_NAME;
+  mControlSignalNames[ Toolkit::ConfirmationPopup::CONTROL_CANCEL ] = DEFAULT_CONNECT_SIGNAL_NAME;
+}
+
+ConfirmationPopup::~ConfirmationPopup()
+{
+  for( SignalContainerType::iterator i = mControlSignals.begin(); i != mControlSignals.end(); ++i )
+  {
+    delete ( i->second );
+  }
+  mControlSignals.clear();
+}
+
+void ConfirmationPopup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) );
+
+  if ( popup )
+  {
+    ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED:
+      {
+        popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK, value.Get< std::string >() );
+        break;
+      }
+      case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED:
+      {
+        popupImpl.SetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL, value.Get< std::string >() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value ConfirmationPopup::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( Dali::BaseHandle( object ) );
+
+  if ( popup )
+  {
+    ConfirmationPopup& popupImpl( GetDerivedImplementation( popup ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_OK_SELECTED:
+      {
+        value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_OK );
+        break;
+      }
+      case Toolkit::ConfirmationPopup::Property::CONNECT_SIGNAL_CANCEL_SELECTED:
+      {
+        value = popupImpl.GetControlSignalName( Toolkit::ConfirmationPopup::CONTROL_CANCEL );
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void ConfirmationPopup::SetControlSignalName( const unsigned int controlNumber, const std::string& signalName )
+{
+  if( controlNumber < ControlDetailsCount )
+  {
+    mControlSignalNames[ controlNumber ] = signalName;
+  }
+}
+
+std::string ConfirmationPopup::GetControlSignalName( unsigned int controlNumber ) const
+{
+  if( controlNumber < ControlDetailsCount )
+  {
+    return mControlSignalNames[ controlNumber ];
+  }
+
+  return "";
+}
+
+bool ConfirmationPopup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+  Toolkit::ConfirmationPopup popup = Toolkit::ConfirmationPopup::DownCast( handle );
+
+  // Look up the requested signal, attempting to create it dynamically if it doesn't exist.
+  SignalDelegate* signalDelegate = Dali::Toolkit::GetDerivedImplementation( popup ).GetControlSignal( signalName );
+  if( signalDelegate )
+  {
+    // The signal delegate was created successfully, attempt to connect it to a callback if specified.
+    // If none is specified, the creation is still successful as the signal delegate can connect at a later time.
+    if( functor )
+    {
+      signalDelegate->Connect( tracker, functor );
+    }
+    return true;
+  }
+
+  // The signal could not be created.
+  return false;
+}
+
+SignalDelegate* ConfirmationPopup::GetControlSignal( const std::string& signalName )
+{
+  // Check if the specified signal name already exists.
+  SignalContainerType::iterator end = mControlSignals.end();
+  for( SignalContainerType::iterator iter = mControlSignals.begin(); iter != end; ++iter )
+  {
+    // Find the first non-connected signal by matching signal name.
+    if( ( signalName == iter->first ) && ( !iter->second->IsConnected() ) )
+    {
+      // The requested signal (delegate) already exists, just return it.
+      return iter->second;
+    }
+  }
+
+  // The signal doesn't exist, or it does but it's already connected to something else.
+  // To make a new connection to an existing signal, we need a new delegate,
+  // as delegates house a signal connection functor each.
+  // Check the signal name is valid and if so create the signal dynamically.
+  for( unsigned int i = 0; i < ControlDetailsCount; ++i )
+  {
+    if( 0 == strcmp( signalName.c_str(), ControlDetails[ i ].signalName ) )
+    {
+      // The signal name is valid, check the respective actor to connect to exists.
+      Actor connectActor = Self().FindChildByName( ControlDetails[ i ].controlName );
+      if( connectActor )
+      {
+        // The actor exists, set up a signal delegate that will allow the application developer
+        // to connect the actor signal directly to their callback.
+        // Note: We don't use the GetControlSignalName() here for speedup, as we know the array bound is capped.
+        SignalDelegate* signalDelegate = new SignalDelegate( connectActor, mControlSignalNames[ i ] );
+
+        // Store the delegate with the signal name so we know what signals have been dynamically created so far.
+        mControlSignals.push_back( std::make_pair( signalName, signalDelegate ) );
+
+        // Return the delegate to allow connection to the newly created signal.
+        return signalDelegate;
+      }
+
+      // Signal name valid but could not connect to the control,
+      return NULL;
+    }
+  }
+
+  // Signal name was not found (invalid).
+  return NULL;
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.h b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.h
new file mode 100644 (file)
index 0000000..4db8bd1
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H
+#define DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/animation.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/devel-api/signals/signal-delegate.h>
+
+// INTERNAL INCLUDES
+#include "popup-impl.h"
+#include <dali-toolkit/devel-api/controls/popup/confirmation-popup.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+#define MAXIMUM_NUMBER_OF_CONTROLS 2
+
+/**
+ * ConfirmationPopup implementation class.
+ *
+ * \sa Dali::Toolkit::ConfirmationPopup
+ */
+class ConfirmationPopup : public Dali::Toolkit::Internal::Popup
+{
+public:
+
+  /**
+   * Create a new ConfirmationPopup.
+   * @return A smart-pointer to the newly allocated ConfirmationPopup.
+   */
+  static Dali::Toolkit::ConfirmationPopup New();
+
+protected:
+
+  /**
+   * Construct a new ConfirmationPopup.
+   */
+  ConfirmationPopup();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ConfirmationPopup();
+
+public:
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] propertyIndex The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] propertyIndex The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * This type houses a list of dynamically created signals.
+   */
+  typedef std::vector< std::pair< std::string, SignalDelegate* > > SignalContainerType;
+
+private:
+
+  /**
+   * Sets the name of the signal to connect to within the specified actor.
+   *
+   * @param[in] controlNumber The index of the control.
+   * @param[in] signalName The name of the signal to connect to.
+   */
+  void SetControlSignalName( const unsigned int controlNumber, const std::string& signalName );
+
+  /**
+   * Gets the name of the signal to connect to within the specified actor.
+   *
+   * @param[in] controlNumber The index of the control.
+   * @return The name of the signal to connect to.
+   */
+  std::string GetControlSignalName( unsigned int controlNumber ) const;
+
+  /**
+   * @copydoc Control::GetControlSignal()
+   */
+  SignalDelegate* GetControlSignal( const std::string& signalName );
+
+private:
+
+  // Undefined
+  ConfirmationPopup( const ConfirmationPopup& );
+
+  // Undefined
+  ConfirmationPopup& operator=( const ConfirmationPopup& );
+
+private:
+
+  // Properties:
+
+  std::string mControlSignalNames[ MAXIMUM_NUMBER_OF_CONTROLS ]; ///< Stores the names of the signals to connect to per control.
+
+  // Internal variables:
+
+  SignalContainerType mControlSignals;                           ///< Stores the dynamically created signals.
+
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ConfirmationPopup& GetDerivedImplementation( Toolkit::ConfirmationPopup& popup )
+{
+  DALI_ASSERT_ALWAYS( popup );
+
+  Dali::RefObject& handle = popup.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ConfirmationPopup&>( handle );
+}
+
+inline const Toolkit::Internal::ConfirmationPopup& GetDerivedImplementation( const Toolkit::ConfirmationPopup& popup )
+{
+  DALI_ASSERT_ALWAYS( popup );
+
+  const Dali::RefObject& handle = popup.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ConfirmationPopup&>( handle );
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CONFIRMATION_POPUP_H
diff --git a/dali-toolkit/internal/controls/popup/popup-impl.cpp b/dali-toolkit/internal/controls/popup/popup-impl.cpp
new file mode 100644 (file)
index 0000000..e11c89f
--- /dev/null
@@ -0,0 +1,1982 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/popup/popup-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/devel-api/adaptor-framework/physical-keyboard.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+/**
+ * Creation function for main Popup type.
+ * @return Handle to the new popup object.
+ */
+BaseHandle Create()
+{
+  return Toolkit::Popup::New();
+}
+
+// Toast style defaults.
+const int          DEFAULT_TOAST_AUTO_HIDE_DELAY = 3000;                                    ///< Toast will auto-hide after 3000ms (3 seconds)
+const float        DEFAULT_TOAST_TRANSITION_TIME = 0.65f;                                   ///< Default time the toast Popup will take to show and hide.
+const Vector3      DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN( 0.5f, 0.94f, 0.5f );                 ///< This is similar to BOTTOM_CENTER, but vertically higher up, as a ratio of parent height.
+const Vector3      DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO( 0.75f, 0.75f, 0.75f );               ///< Amount of the stage's width that the toast popup will take up.
+
+/**
+ * Creation function for named type "popupToast".
+ * @return Handle to the new toast popup object.
+ */
+BaseHandle CreateToast()
+{
+  Toolkit::Popup popup = Toolkit::Popup::New();
+
+  // Setup for Toast Popup type.
+  popup.SetSizeModeFactor( DEFAULT_TOAST_WIDTH_OF_STAGE_RATIO );
+  popup.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
+  popup.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+  popup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, Toolkit::Popup::NON_CONTEXTUAL );
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_DURATION, DEFAULT_TOAST_TRANSITION_TIME );
+  popup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, false );
+
+  // Disable the dimmed backing.
+  popup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false );
+
+  // The toast popup should fade in (not zoom).
+  popup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, Toolkit::Popup::FADE );
+
+  // The toast popup should auto-hide.
+  popup.SetProperty( Toolkit::Popup::Property::AUTO_HIDE_DELAY, DEFAULT_TOAST_AUTO_HIDE_DELAY );
+
+  // Align to the bottom of the screen.
+  popup.SetParentOrigin( DEFAULT_TOAST_BOTTOM_PARENT_ORIGIN );
+  popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+
+  // Let events pass through the toast popup.
+  popup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true );
+
+  return popup;
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Popup, Toolkit::Control, Create )
+
+// Main content related properties.
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "title",                             MAP,              TITLE                   )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "content",                           MAP,              CONTENT                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "footer",                            MAP,              FOOTER                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "displayState",                      STRING,           DISPLAY_STATE           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "touchTransparent",                  BOOLEAN,          TOUCH_TRANSPARENT       )
+
+// Contextual related properties.
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailVisibility",                    BOOLEAN,          TAIL_VISIBILITY         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailPosition",                      VECTOR3,          TAIL_POSITION           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "contextualMode",                    STRING,           CONTEXTUAL_MODE         )
+
+// Animation related properties.
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationDuration",                 FLOAT,            ANIMATION_DURATION      )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "animationMode",                     STRING,           ANIMATION_MODE          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "entryAnimation",                    MAP,              ENTRY_ANIMATION         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "exitAnimation",                     MAP,              EXIT_ANIMATION          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "autoHideDelay",                     INTEGER,          AUTO_HIDE_DELAY         )
+
+// Style related properties.
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingEnabled",                    BOOLEAN,          BACKING_ENABLED         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "backingColor",                      VECTOR4,          BACKING_COLOR           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundImage",              STRING,           POPUP_BACKGROUND_IMAGE  )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "popupBackgroundBorder",             RECTANGLE,        POPUP_BACKGROUND_BORDER )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailUpImage",                       STRING,           TAIL_UP_IMAGE           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailDownImage",                     STRING,           TAIL_DOWN_IMAGE         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailLeftImage",                     STRING,           TAIL_LEFT_IMAGE         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Popup, "tailRightImage",                    STRING,           TAIL_RIGHT_IMAGE        )
+
+// Signals.
+DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "touchedOutside",                                      SIGNAL_TOUCHED_OUTSIDE  )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "showing",                                             SIGNAL_SHOWING          )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "shown",                                               SIGNAL_SHOWN            )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hiding",                                              SIGNAL_HIDING           )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Popup, "hidden",                                              SIGNAL_HIDDEN           )
+
+DALI_TYPE_REGISTRATION_END()
+
+// Named type registration.
+
+// Toast Popup: Non-modal popup that displays information at the bottom of the screen.
+TypeRegistration typeRegistrationToast( "PopupToast",  typeid( Toolkit::Popup ), CreateToast );
+
+// Enumeration to / from string conversion tables
+
+const Scripting::StringEnum DisplayStateTable[] = {
+  { "SHOWING", Toolkit::Popup::SHOWING },
+  { "SHOWN",   Toolkit::Popup::SHOWN   },
+  { "HIDING",  Toolkit::Popup::HIDING  },
+  { "HIDDEN",  Toolkit::Popup::HIDDEN  },
+}; const unsigned int DisplayStateTableCount = sizeof( DisplayStateTable ) / sizeof( DisplayStateTable[0] );
+
+const Scripting::StringEnum AnimationModeTable[] = {
+  { "NONE",    Toolkit::Popup::NONE    },
+  { "ZOOM",    Toolkit::Popup::ZOOM    },
+  { "FADE",    Toolkit::Popup::FADE    },
+  { "CUSTOM",  Toolkit::Popup::CUSTOM  },
+}; const unsigned int AnimationModeTableCount = sizeof( AnimationModeTable ) / sizeof( AnimationModeTable[0] );
+
+const Scripting::StringEnum ContextualModeTable[] = {
+  { "NON_CONTEXTUAL", Toolkit::Popup::NON_CONTEXTUAL },
+  { "ABOVE",          Toolkit::Popup::ABOVE          },
+  { "RIGHT",          Toolkit::Popup::RIGHT          },
+  { "BELOW",          Toolkit::Popup::BELOW          },
+  { "LEFT",           Toolkit::Popup::LEFT           },
+}; const unsigned int ContextualModeTableCount = sizeof( ContextualModeTable ) / sizeof( ContextualModeTable[0] );
+
+// Popup defaults.
+const Vector3 DEFAULT_POPUP_PARENT_RELATIVE_SIZE( 0.75f, 1.0f, 1.0f );            ///< Default size percentage of parent.
+const float   DEFAULT_POPUP_ANIMATION_DURATION =  0.6f;                           ///< Duration of hide/show animations.
+const float   POPUP_OUT_MARGIN_WIDTH =            16.f;                           ///< Space between the screen edge and the popup edge in the horizontal dimension.
+const float   POPUP_OUT_MARGIN_HEIGHT =           36.f;                           ///< Space between the screen edge and the popup edge in the vertical dimension.
+const Vector3 DEFAULT_TAIL_POSITION( 0.5f, 1.0f, 0.0f );                          ///< Position the tail will be displayed when enabled without setting the position.
+
+// Contextual defaults.
+const Vector2 DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN( 10.0f, 10.0f );                ///< How close the Popup will be to it's contextual parent.
+const Vector2 DEFAULT_CONTEXTUAL_STAGE_BORDER( 15.0f, 15.0f );                    ///< How close the Popup can be to the stage edges.
+
+// Popup style defaults.
+const char*   DEFAULT_BACKGROUND_IMAGE_FILE_NAME =     "00_popup_bg.9.png";       ///< Background image.
+const char*   DEFAULT_TAIL_UP_IMAGE_FILE_NAME =        "popup_tail_up.png";       ///< Tail up image.
+const char*   DEFAULT_TAIL_DOWN_IMAGE_FILE_NAME =      "popup_tail_down.png";     ///< Tail down image.
+const char*   DEFAULT_TAIL_LEFT_IMAGE_FILE_NAME =      "popup_tail_left.png";     ///< Tail left image.
+const char*   DEFAULT_TAIL_RIGHT_IMAGE_FILE_NAME =     "popup_tail_right.png";    ///< Tail right image.
+
+const Vector4 DEFAULT_BACKING_COLOR( 0.0f, 0.0f, 0.0f, 0.5f );                    ///< Color of the dimmed backing.
+const Rect<int> DEFAULT_BACKGROUND_BORDER( 17, 17, 13, 13 );                      ///< Default border of the background.
+const Rect<float>  DEFAULT_TITLE_PADDING( 20.0f, 20.0f, 20.0f, 20.0f );           ///< Title padding used on popups with content and/or controls (from Tizen GUI UX).
+const Rect<float>  DEFAULT_TITLE_ONLY_PADDING( 8.0f, 8.0f, 8.0f, 8.0f );          ///< Title padding used on popups with a title only (like toast popups).
+const Vector3 FOOTER_SIZE( 620.0f, 96.0f,0.0f );                                  ///< Default size of the bottom control area.
+const float   DEFAULT_RELATIVE_PARENT_WIDTH =     0.75f;                          ///< If width is not fixed, relative size to parent is used by default.
+
+} // Unnamed namespace
+
+/*
+ * Implementation.
+ */
+
+Dali::Toolkit::Popup Popup::New()
+{
+  // Create the implementation
+  PopupPtr popup( new Popup() );
+
+  // Pass ownership to CustomActor via derived handle.
+  Dali::Toolkit::Popup handle( *popup );
+
+  // Second-phase initialisation of the implementation.
+  // This can only be done after the CustomActor connection has been made.
+  popup->Initialize();
+
+  return handle;
+}
+
+Popup::Popup()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mTouchedOutsideSignal(),
+  mShowingSignal(),
+  mShownSignal(),
+  mHidingSignal(),
+  mHiddenSignal(),
+  mLayer(),
+  mPopupLayout(),
+  mBacking(),
+  mPreviousFocusedActor(),
+  mTailImage(),
+  mPopupContainer(),
+  mAnimation(),
+  mAlterAddedChild( false ),
+  mLayoutDirty( true ),
+  mAutoHideTimer(),
+  mTouchTransparent( false ),
+  mTitle(),
+  mContent(),
+  mFooter(),
+  mDisplayState( Toolkit::Popup::HIDDEN ), // Hidden until shown with SetDisplayState()
+  mTailVisible( false ),
+  mTailPosition( DEFAULT_TAIL_POSITION ),
+  mContextualMode( Toolkit::Popup::NON_CONTEXTUAL ),
+  mAnimationDuration( DEFAULT_POPUP_ANIMATION_DURATION ),
+  mAnimationMode( Toolkit::Popup::FADE ),
+  mEntryAnimationData(),
+  mExitAnimationData(),
+  mAutoHideDelay( 0 ),
+  mBackingEnabled( true ),
+  mBackingColor( DEFAULT_BACKING_COLOR ),
+  mPopupBackgroundImage(),
+  mBackgroundBorder( DEFAULT_BACKGROUND_BORDER ),
+  mMargin(),
+  mTailUpImage(),
+  mTailDownImage(),
+  mTailLeftImage(),
+  mTailRightImage()
+{
+  SetKeyboardNavigationSupport( true );
+
+  const std::string imageDirPath = AssetManager::GetDaliImagePath();
+  mTailUpImage = imageDirPath + DEFAULT_TAIL_UP_IMAGE_FILE_NAME;
+  mTailDownImage = imageDirPath + DEFAULT_TAIL_DOWN_IMAGE_FILE_NAME;
+  mTailLeftImage = imageDirPath + DEFAULT_TAIL_LEFT_IMAGE_FILE_NAME;
+  mTailRightImage = imageDirPath + DEFAULT_TAIL_RIGHT_IMAGE_FILE_NAME;
+}
+
+void Popup::OnInitialize()
+{
+  Actor self = Self();
+  self.SetName( "popup" );
+
+  // Apply some default resizing rules.
+  self.SetParentOrigin( ParentOrigin::CENTER );
+  self.SetAnchorPoint( AnchorPoint::CENTER );
+
+  self.SetSizeModeFactor( DEFAULT_POPUP_PARENT_RELATIVE_SIZE );
+  self.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::WIDTH );
+  self.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+
+  // Create a new layer so all Popup components can appear above all other actors.
+  mLayer = Layer::New();
+  mLayer.SetName( "popupLayer" );
+
+  mLayer.SetParentOrigin( ParentOrigin::CENTER );
+  mLayer.SetAnchorPoint( AnchorPoint::CENTER );
+  mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  // Important to set as invisible as otherwise, if the popup is parented,
+  // but not shown yet it will appear statically on the screen.
+  mLayer.SetVisible( false );
+
+  // Add the layer to the hierarchy.
+  self.Add( mLayer );
+
+  // Add Backing (Dimmed effect).
+  mBacking = CreateBacking();
+  mLayer.Add( mBacking );
+
+  mPopupContainer = Actor::New();
+  mPopupContainer.SetName( "popupContainer" );
+  mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
+  mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
+  mPopupContainer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  mLayer.Add( mPopupContainer );
+
+  // Create the Popup layout to contain all main content.
+  mPopupLayout = Toolkit::TableView::New( 3, 1 );
+
+  // Adds the default background image.
+  const std::string imageDirPath = AssetManager::GetDaliImagePath();
+  SetPopupBackgroundImage( Toolkit::ImageView::New( imageDirPath + DEFAULT_BACKGROUND_IMAGE_FILE_NAME ) );
+
+  mPopupLayout.SetName( "popupLayoutTable" );
+  mPopupLayout.SetParentOrigin( ParentOrigin::CENTER );
+  mPopupLayout.SetAnchorPoint( AnchorPoint::CENTER );
+
+  mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
+  mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+  mPopupLayout.SetSize( Stage::GetCurrent().GetSize().x * DEFAULT_RELATIVE_PARENT_WIDTH, 0.0f );
+
+  mPopupLayout.SetFitHeight( 0 ); // Set row to fit.
+  mPopupLayout.SetFitHeight( 1 ); // Set row to fit.
+
+  mPopupLayout.TouchSignal().Connect( this, &Popup::OnDialogTouched );
+
+  mPopupContainer.Add( mPopupLayout );
+
+  // Any content after this point which is added to Self() will be re-parented to mContent.
+  mAlterAddedChild = true;
+
+  SetAsKeyboardFocusGroup( true );
+}
+
+Popup::~Popup()
+{
+  mEntryAnimationData.Clear();
+  mExitAnimationData.Clear();
+}
+
+void Popup::LayoutAnimation()
+{
+  // Perform setup based on the currently selected animation.
+  switch( mAnimationMode )
+  {
+    case Toolkit::Popup::ZOOM:
+    {
+      // Zoom animations start fully zoomed out.
+      mPopupContainer.SetScale( Vector3::ZERO );
+      break;
+    }
+
+    case Toolkit::Popup::FADE:
+    {
+      // Fade animations start transparent.
+      mPopupContainer.SetOpacity( 0.0f );
+      break;
+    }
+
+    case Toolkit::Popup::CUSTOM:
+    {
+      // Initialise the custom animation by playing to the end of it's exit animation instantly.
+      // EG. If it was zooming in, then we zoom out fully instantly so the zoom in works.
+      StartTransitionAnimation( false, true );
+      break;
+    }
+
+    case Toolkit::Popup::NONE:
+    {
+      break;
+    }
+  }
+}
+
+void Popup::StartTransitionAnimation( bool transitionIn, bool instantaneous /* false */ )
+{
+  // Stop and recreate animation.
+  if ( mAnimation )
+  {
+    mAnimation.Stop();
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+  float duration = GetAnimationDuration();
+
+  // Setup variables ready to start the animations.
+  // If we are performing the animation instantaneously, we do not want to emit a signal.
+  if( !instantaneous )
+  {
+    if( transitionIn )
+    {
+      // Setup variables and signal that we are starting the transition.
+      // Note: We signal even if the transition is instant so signal order is consistent.
+      mShowingSignal.Emit();
+    }
+    else
+    {
+      mHidingSignal.Emit();
+    }
+  }
+
+  // Perform chosen animation for the Popup.
+  switch( mAnimationMode )
+  {
+    case Toolkit::Popup::NONE:
+    {
+      mAnimation = Animation::New( 0.0f );
+      break;
+    }
+
+    case Toolkit::Popup::ZOOM:
+    {
+      mAnimation = Animation::New( duration );
+      if( duration > Math::MACHINE_EPSILON_0 )
+      {
+        if( transitionIn )
+        {
+          mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ONE, AlphaFunction::EASE_IN_OUT, TimePeriod( duration * 0.25f, duration * 0.75f ) );
+        }
+        else
+        {
+          // Zoom out animation is twice the speed. Modify the duration variable so the backing animation speed is modified also.
+          duration /= 2.0f;
+          mAnimation.SetDuration( duration );
+          mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::SCALE ), Vector3::ZERO, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration ) );
+        }
+      }
+      else
+      {
+        mPopupContainer.SetScale( transitionIn ? Vector3::ONE : Vector3::ZERO );
+      }
+      break;
+    }
+
+    case Toolkit::Popup::FADE:
+    {
+      mAnimation = Animation::New( duration );
+      if( duration > Math::MACHINE_EPSILON_0 )
+      {
+        if( transitionIn )
+        {
+          mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 1.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
+        }
+        else
+        {
+          mAnimation.AnimateTo( Property( mPopupContainer, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
+        }
+      }
+      else
+      {
+        mPopupContainer.SetOpacity( transitionIn ? 1.0f : 0.0f );
+      }
+      break;
+    }
+
+    case Toolkit::Popup::CUSTOM:
+    {
+      // Use a user specified animation for in and out.
+      // Read the correct animation depending on entry or exit.
+      // Attempt to use animation data defined from script data.
+      Dali::AnimationData* animationData = transitionIn ? &mEntryAnimationData : &mExitAnimationData;
+
+      // Create a new animation from the pre-defined data in the AnimationData class.
+      // If there is no data, mAnimation is invalidated.
+      mAnimation = animationData->CreateAnimation( mPopupContainer, duration );
+
+      // If we don't have a valid animation, provide a blank one so play() can still function generically.
+      if( !mAnimation )
+      {
+        // No animation was configured (even though custom mode was specified). Create a dummy animation to avoid an exception.
+        mAnimation = Animation::New( 0.0f );
+      }
+
+      break;
+    }
+  }
+
+  // Animate the backing, if enabled.
+  // This is set up last so that different animation modes can have an effect on the backing animation speed.
+  if( mBackingEnabled )
+  {
+    // Use the alpha from the user-specified color.
+    float targetAlpha = mBackingColor.a;
+    if( duration > Math::MACHINE_EPSILON_0 )
+    {
+      if( transitionIn )
+      {
+        mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), targetAlpha, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.0f, duration * 0.70f ) );
+      }
+      else
+      {
+        mAnimation.AnimateTo( Property( mBacking, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN_OUT, TimePeriod( 0.30f, duration * 0.70f ) );
+      }
+    }
+    else
+    {
+      mBacking.SetProperty( Actor::Property::COLOR_ALPHA, transitionIn ? targetAlpha : 0.0f );
+    }
+  }
+
+  // If we are performing the animation instantaneously, jump to the position directly and do not signal.
+  if( instantaneous )
+  {
+    mAnimation.SetCurrentProgress( 1.0f );
+    mAnimation.Play();
+  }
+  else if( duration > Math::MACHINE_EPSILON_0 )
+  {
+    // Run the animation.
+    mAnimation.FinishedSignal().Connect( this, &Popup::OnDisplayChangeAnimationFinished );
+    mAnimation.Play();
+  }
+  else
+  {
+    // We did not use an animation to achive the transition.
+    // Trigger the state change directly.
+    DisplayStateChangeComplete();
+  }
+}
+
+void Popup::OnDisplayChangeAnimationFinished( Animation& source )
+{
+  DisplayStateChangeComplete();
+}
+
+void Popup::DisplayStateChangeComplete()
+{
+  // Remove contents from stage if completely hidden.
+  if( mDisplayState == Toolkit::Popup::HIDING )
+  {
+    mDisplayState = Toolkit::Popup::HIDDEN;
+
+    mLayer.SetVisible( false );
+    mPopupLayout.SetSensitive( false );
+
+    // Guard against destruction during signal emission.
+    Toolkit::Popup handle( GetOwner() );
+    mHiddenSignal.Emit();
+  }
+  else if( mDisplayState == Toolkit::Popup::SHOWING )
+  {
+    mDisplayState = Toolkit::Popup::SHOWN;
+    Toolkit::Popup handle( GetOwner() );
+    mShownSignal.Emit();
+
+    // Start a timer to auto-hide if enabled.
+    if( mAutoHideDelay > 0u )
+    {
+      mAutoHideTimer = Timer::New( mAutoHideDelay );
+      mAutoHideTimer.TickSignal().Connect( this, &Popup::OnAutoHideTimeReached );
+      mAutoHideTimer.Start();
+    }
+  }
+}
+
+bool Popup::OnAutoHideTimeReached()
+{
+  // Display timer has expired, auto hide the popup exactly as if the user had clicked outside.
+  SetDisplayState( Toolkit::Popup::HIDDEN );
+
+  if( mAutoHideTimer )
+  {
+    mAutoHideTimer.Stop();
+    mAutoHideTimer.TickSignal().Disconnect( this, &Popup::OnAutoHideTimeReached );
+    mAutoHideTimer.Reset();
+  }
+  return true;
+}
+
+void Popup::SetPopupBackgroundImage( Actor image )
+{
+  // Removes any previous background.
+  if( mPopupBackgroundImage )
+  {
+    mPopupBackgroundImage.Unparent();
+    if( mTailImage )
+    {
+      mTailImage.Unparent();
+    }
+  }
+
+  // Adds new background to the dialog.
+  mPopupBackgroundImage = image;
+  mPopupBackgroundImage.SetName( "popupBackgroundImage" );
+  mPopupBackgroundImage.SetAnchorPoint( AnchorPoint::CENTER );
+  mPopupBackgroundImage.SetParentOrigin( ParentOrigin::CENTER );
+
+  // OnDialogTouched only consumes the event. It prevents the touch event to be caught by the backing.
+  mPopupBackgroundImage.TouchSignal().Connect( this, &Popup::OnDialogTouched );
+
+  // Set the popup border to be slightly larger than the layout contents.
+  UpdateBackgroundPositionAndSize();
+
+  const bool prevAlter = mAlterAddedChild;
+  mAlterAddedChild = false;
+  mPopupContainer.Add( mPopupBackgroundImage );
+  mPopupBackgroundImage.LowerToBottom();
+  mAlterAddedChild = prevAlter;
+
+  if( mTailImage )
+  {
+    mPopupBackgroundImage.Add( mTailImage );
+  }
+
+  mLayoutDirty = true;
+}
+
+Actor Popup::GetPopupBackgroundImage() const
+{
+  return mPopupBackgroundImage;
+}
+
+void Popup::SetTitle( Actor titleActor )
+{
+  // Replaces the current title actor.
+  if( !mPopupLayout )
+  {
+    return;
+  }
+
+  if( mTitle )
+  {
+    mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 0, 0) );
+  }
+  mTitle = titleActor;
+
+  if( mTitle )
+  {
+    // Set up padding to give sensible default behaviour
+    // (an application developer can later override this if they wish).
+    mTitle.SetPadding( DEFAULT_TITLE_PADDING );
+
+    mPopupLayout.AddChild( mTitle, Toolkit::TableView::CellPosition( 0, 0 ) );
+  }
+
+  mLayoutDirty = true;
+  RelayoutRequest();
+}
+
+Actor Popup::GetTitle() const
+{
+  return mTitle;
+}
+
+void Popup::SetContent( Actor content )
+{
+  // Remove previous content actor.
+  if( mPopupLayout )
+  {
+    mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 1, 0 ) );
+  }
+   // Keep a handle to the new content.
+  mContent = content;
+
+  if( mContent )
+  {
+    mContent.SetName( "popupContent" );
+
+    mPopupLayout.AddChild( mContent, Toolkit::TableView::CellPosition( 1, 0 ) );
+  }
+
+  mLayoutDirty = true;
+  RelayoutRequest();
+}
+
+Actor Popup::GetContent() const
+{
+  return mContent;
+}
+
+void Popup::SetFooter( Actor footer )
+{
+  // Remove previous content actor.
+  if( mPopupLayout )
+  {
+    mPopupLayout.RemoveChildAt( Toolkit::TableView::CellPosition( 2, 0 ) );
+  }
+
+  // Keep a handle to the new content.
+  mFooter = footer;
+
+  if( mFooter )
+  {
+    mFooter.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+
+    // The control container has a fixed height.
+    mPopupLayout.SetFitHeight( 2u );
+    mPopupLayout.AddChild( footer, Toolkit::TableView::CellPosition( 2, 0 ) );
+  }
+
+  mLayoutDirty = true;
+  RelayoutRequest();
+}
+
+Actor Popup::GetFooter() const
+{
+  return mFooter;
+}
+
+void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState )
+{
+  // Convert the 4-way state to a bool, true for show, false for hide.
+  bool display = ( displayState == Toolkit::Popup::SHOWING ) || ( displayState == Toolkit::Popup::SHOWN );
+
+  // Ignore if we are already at the target display state.
+  if( display == ( ( mDisplayState == Toolkit::Popup::SHOWING ) || ( mDisplayState == Toolkit::Popup::SHOWN ) ) )
+  {
+    return;
+  }
+
+  // Convert the bool state to the actual display state to use.
+  mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING;
+
+  if ( display )
+  {
+    // Update the state to indicate the current intent.
+    mDisplayState = Toolkit::Popup::SHOWING;
+
+    // We want the popup to have key input focus when it is displayed
+    SetKeyInputFocus();
+
+    // We are displaying so bring the popup layer to the front, and set it visible so it is rendered.
+    mLayer.RaiseToTop();
+    mLayer.SetVisible( true );
+
+    // Set up the layout if this is the first display or the layout has become dirty.
+    if( mLayoutDirty )
+    {
+      // Bake-in any style and layout options to create the Popup layout.
+      LayoutPopup();
+    }
+
+    // Allow the popup to catch events.
+    mPopupLayout.SetSensitive( true );
+
+    // Handle the keyboard focus when popup is shown.
+    Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+    if( keyboardFocusManager )
+    {
+      mPreviousFocusedActor = keyboardFocusManager.GetCurrentFocusActor();
+
+      if( Self().IsKeyboardFocusable() )
+      {
+        // Setup the actgor to start focus from.
+        Actor focusActor;
+        if( mContent && mContent.IsKeyboardFocusable() )
+        {
+          // If the content is focusable, move the focus to the content.
+          focusActor = mContent;
+        }
+        else if( mFooter && mFooter.IsKeyboardFocusable() )
+        {
+          // If the footer is focusable, move the focus to the footer.
+          focusActor = mFooter;
+        }
+        else
+        {
+          DALI_LOG_WARNING( "There is no focusable in popup\n" );
+        }
+
+        if( focusActor )
+        {
+          keyboardFocusManager.SetCurrentFocusActor( focusActor );
+        }
+      }
+    }
+  }
+  else // Not visible.
+  {
+    mDisplayState = Toolkit::Popup::HIDING;
+    ClearKeyInputFocus();
+
+    // Restore the keyboard focus when popup is hidden.
+    if( mPreviousFocusedActor && mPreviousFocusedActor.IsKeyboardFocusable() )
+    {
+      Dali::Toolkit::KeyboardFocusManager keyboardFocusManager = Dali::Toolkit::KeyboardFocusManager::Get();
+      if( keyboardFocusManager )
+      {
+        keyboardFocusManager.SetCurrentFocusActor( mPreviousFocusedActor );
+      }
+    }
+  }
+
+  // Perform animation.
+  StartTransitionAnimation( display );
+}
+
+Toolkit::Popup::DisplayState Popup::GetDisplayState() const
+{
+  return mDisplayState;
+}
+
+void Popup::LayoutPopup()
+{
+  mLayoutDirty = false;
+
+  /* When animating in, we want to respect the origin applied to Self().
+   * For example, if zooming, not only will the final result be anchored to the
+   * selected point, but the zoom will originate from this point also.
+   *
+   * EG: ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT :
+   *
+   *       --------                --------
+   *       |X|                     |XXX|
+   *       |``        Animates     |XXX|
+   *       |             to:       |XXX|
+   *       |                       |````
+   *       |                       |
+   */
+  mPopupContainer.SetParentOrigin( Self().GetCurrentParentOrigin() );
+  mPopupContainer.SetAnchorPoint( Self().GetCurrentAnchorPoint() );
+
+  // If there is only a title, use less padding.
+  if( mTitle )
+  {
+    if( !mContent && !mFooter )
+    {
+      mTitle.SetPadding( DEFAULT_TITLE_ONLY_PADDING );
+    }
+    else
+    {
+      mTitle.SetPadding( DEFAULT_TITLE_PADDING );
+    }
+  }
+
+  // Allow derived classes to perform any layout they may need to do.
+  OnLayoutSetup();
+
+  // Update background visibility.
+  mPopupContainer.SetVisible( !( !mFooter && mPopupLayout.GetChildCount() == 0 ) );
+
+  // Create / destroy / position the tail as needed.
+  LayoutTail();
+
+  // Setup any layout and initialisation required for the selected animation.
+  LayoutAnimation();
+
+  RelayoutRequest();
+}
+
+void Popup::LayoutTail()
+{
+  // Removes the tail actor.
+  if( mTailImage && mTailImage.GetParent() )
+  {
+    mTailImage.GetParent().Remove( mTailImage );
+    mTailImage.Reset();
+  }
+
+  if( !mTailVisible )
+  {
+    return;
+  }
+
+  const Vector3& parentOrigin = GetTailPosition();
+  Vector3 position;
+  std::string image;
+  Vector3 anchorPoint;
+
+  // depending on position of tail around ParentOrigin, a different tail image is used...
+  if( parentOrigin.y < Math::MACHINE_EPSILON_1 )
+  {
+    image = mTailUpImage;
+    anchorPoint = AnchorPoint::BOTTOM_CENTER;
+    position.y = mBackgroundBorder.top;
+  }
+  else if( parentOrigin.y > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
+  {
+    image = mTailDownImage;
+    anchorPoint = AnchorPoint::TOP_CENTER;
+    position.y = - mBackgroundBorder.bottom;
+  }
+  else if( parentOrigin.x < Math::MACHINE_EPSILON_1 )
+  {
+    image = mTailLeftImage;
+    anchorPoint = AnchorPoint::CENTER_RIGHT;
+    position.x = mBackgroundBorder.left;
+  }
+  else if( parentOrigin.x > ( 1.0f - Math::MACHINE_EPSILON_1 ) )
+  {
+    image = mTailRightImage;
+    anchorPoint = AnchorPoint::CENTER_LEFT;
+    position.x = - mBackgroundBorder.right;
+  }
+
+  if( !image.empty() )
+  {
+    // Adds the tail actor.
+    mTailImage = Toolkit::ImageView::New( image );
+    mTailImage.SetName( "tailImage" );
+    mTailImage.SetParentOrigin( parentOrigin );
+    mTailImage.SetAnchorPoint( anchorPoint );
+    mTailImage.SetPosition( position );
+
+    if( mPopupBackgroundImage )
+    {
+      mPopupBackgroundImage.Add( mTailImage );
+    }
+  }
+}
+
+void Popup::SetContextualMode( Toolkit::Popup::ContextualMode mode )
+{
+  mContextualMode = mode;
+  mLayoutDirty = true;
+}
+
+Toolkit::Popup::ContextualMode Popup::GetContextualMode() const
+{
+  return mContextualMode;
+}
+
+Toolkit::Control Popup::CreateBacking()
+{
+  Toolkit::Control backing = Control::New();
+  backing.SetProperty( Toolkit::Control::Property::BACKGROUND,
+                       Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR )
+                                      .Add( Toolkit::ColorVisual::Property::MIX_COLOR, Vector4( mBackingColor.r, mBackingColor.g, mBackingColor.b, 1.0f ) ) );
+  backing.SetName( "popupBacking" );
+
+  // Must always be positioned top-left of stage, regardless of parent.
+  backing.SetInheritPosition(false);
+
+  // Always the full size of the stage.
+  backing.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+  backing.SetSize( Stage::GetCurrent().GetSize() );
+
+  // Catch events.
+  backing.SetSensitive( true );
+
+  // Default to being transparent.
+  backing.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
+  backing.TouchSignal().Connect( this, &Popup::OnBackingTouched );
+  backing.WheelEventSignal().Connect( this, &Popup::OnBackingWheelEvent );
+  return backing;
+}
+
+Toolkit::Popup::TouchedOutsideSignalType& Popup::OutsideTouchedSignal()
+{
+  return mTouchedOutsideSignal;
+}
+
+Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShowingSignal()
+{
+  return mShowingSignal;
+}
+
+Toolkit::Popup::DisplayStateChangeSignalType& Popup::ShownSignal()
+{
+  return mShownSignal;
+}
+
+Toolkit::Popup::DisplayStateChangeSignalType& Popup::HidingSignal()
+{
+  return mHidingSignal;
+}
+
+Toolkit::Popup::DisplayStateChangeSignalType& Popup::HiddenSignal()
+{
+  return mHiddenSignal;
+}
+
+void Popup::SetTailVisibility( bool visible )
+{
+  mTailVisible = visible;
+  mLayoutDirty = true;
+}
+
+const bool Popup::IsTailVisible() const
+{
+  return mTailVisible;
+}
+
+void Popup::SetTailPosition( Vector3 position )
+{
+  mTailPosition = position;
+  mLayoutDirty = true;
+}
+
+const Vector3& Popup::GetTailPosition() const
+{
+  return mTailPosition;
+}
+
+void Popup::SetAnimationDuration( float duration )
+{
+  mAnimationDuration = duration;
+  mLayoutDirty = true;
+}
+
+float Popup::GetAnimationDuration() const
+{
+  return mAnimationDuration;
+}
+
+void Popup::SetAnimationMode( Toolkit::Popup::AnimationMode animationMode )
+{
+  mAnimationMode = animationMode;
+  mLayoutDirty = true;
+}
+
+Toolkit::Popup::AnimationMode Popup::GetAnimationMode() const
+{
+  return mAnimationMode;
+}
+
+void Popup::SetEntryAnimationData( const Property::Map& map )
+{
+  mEntryAnimationData.Clear();
+  Scripting::NewAnimation( map, mEntryAnimationData );
+}
+
+void Popup::SetExitAnimationData( const Property::Map& map )
+{
+  mExitAnimationData.Clear();
+  Scripting::NewAnimation( map, mExitAnimationData );
+}
+
+void Popup::UpdateBackgroundPositionAndSize()
+{
+  if( mPopupBackgroundImage )
+  {
+    mPopupBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
+    mPopupBackgroundImage.SetSizeModeFactor( Vector3( mBackgroundBorder.left + mBackgroundBorder.right, mBackgroundBorder.top + mBackgroundBorder.bottom, 0.0f ) );
+
+    // Adjust the position of the background so the transparent areas are set appropriately
+    mPopupBackgroundImage.SetPosition( ( mBackgroundBorder.right - mBackgroundBorder.left ) * 0.5f, ( mBackgroundBorder.bottom - mBackgroundBorder.top ) * 0.5f );
+  }
+}
+
+void Popup::SetAutoHideDelay( int delay )
+{
+  mAutoHideDelay = delay;
+}
+
+int Popup::GetAutoHideDelay() const
+{
+  return mAutoHideDelay;
+}
+
+void Popup::SetBackingEnabled( bool enabled )
+{
+  mBackingEnabled = enabled;
+  mLayoutDirty = true;
+}
+
+const bool Popup::IsBackingEnabled() const
+{
+  return mBackingEnabled;
+}
+
+void Popup::SetBackingColor( Vector4 color )
+{
+  mBackingColor = color;
+  mBacking.SetBackgroundColor( Vector4( color.r, color.g, color.b, 1.0f ) );
+  mLayoutDirty = true;
+}
+
+const Vector4& Popup::GetBackingColor() const
+{
+  return mBackingColor;
+}
+
+void Popup::SetTailUpImage( std::string image )
+{
+  mTailUpImage = image;
+  mLayoutDirty = true;
+  LayoutTail();
+}
+
+const std::string& Popup::GetTailUpImage() const
+{
+  return mTailUpImage;
+}
+
+void Popup::SetTailDownImage( std::string image )
+{
+  mTailDownImage = image;
+  mLayoutDirty = true;
+  LayoutTail();
+}
+
+const std::string& Popup::GetTailDownImage() const
+{
+  return mTailDownImage;
+}
+
+void Popup::SetTailLeftImage( std::string image )
+{
+  mTailLeftImage = image;
+  mLayoutDirty = true;
+  LayoutTail();
+}
+
+const std::string& Popup::GetTailLeftImage() const
+{
+  return mTailLeftImage;
+}
+
+void Popup::SetTailRightImage( std::string image )
+{
+  mTailRightImage = image;
+  mLayoutDirty = true;
+  LayoutTail();
+}
+
+const std::string& Popup::GetTailRightImage() const
+{
+  return mTailRightImage;
+}
+
+void Popup::SetTouchTransparent( bool enabled )
+{
+  mTouchTransparent = enabled;
+}
+
+const bool Popup::IsTouchTransparent() const
+{
+  return mTouchTransparent;
+}
+
+void Popup::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
+
+  if ( popup )
+  {
+    Popup& popupImpl( GetImpl( popup ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::Popup::Property::TITLE:
+      {
+        Property::Map valueMap;
+        if( value.Get( valueMap ) )
+        {
+          popupImpl.SetTitle( Scripting::NewActor( valueMap ) );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::CONTENT:
+      {
+        Property::Map valueMap;
+        if( value.Get( valueMap ) )
+        {
+          popupImpl.SetContent( Scripting::NewActor( valueMap ) );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::FOOTER:
+      {
+        Property::Map valueMap;
+        if( value.Get( valueMap ) )
+        {
+          popupImpl.SetFooter( Scripting::NewActor( valueMap ) );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::DISPLAY_STATE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          Toolkit::Popup::DisplayState displayState( Toolkit::Popup::HIDDEN );
+          if( Scripting::GetEnumeration< Toolkit::Popup::DisplayState >( valueString.c_str(), DisplayStateTable, DisplayStateTableCount, displayState ) )
+          {
+            popupImpl.SetDisplayState( displayState );
+          }
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
+      {
+        bool valueBool;
+        if( value.Get( valueBool ) )
+        {
+          popupImpl.SetTouchTransparent( valueBool );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_VISIBILITY:
+      {
+        bool valueBool;
+        if( value.Get( valueBool ) )
+        {
+          popupImpl.SetTailVisibility( valueBool );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_POSITION:
+      {
+        Vector3 valueVector3;
+        if( value.Get( valueVector3 ) )
+        {
+          popupImpl.SetTailPosition( valueVector3 );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::CONTEXTUAL_MODE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          Toolkit::Popup::ContextualMode contextualMode( Toolkit::Popup::BELOW );
+          if( Scripting::GetEnumeration< Toolkit::Popup::ContextualMode >( valueString.c_str(), ContextualModeTable, ContextualModeTableCount, contextualMode ) )
+          {
+            popupImpl.SetContextualMode( contextualMode );
+          }
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::ANIMATION_DURATION:
+      {
+        float valueFloat;
+        if( value.Get( valueFloat ) )
+        {
+          popupImpl.SetAnimationDuration( valueFloat );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::ANIMATION_MODE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          Toolkit::Popup::AnimationMode animationMode( Toolkit::Popup::FADE );
+          if( Scripting::GetEnumeration< Toolkit::Popup::AnimationMode >( valueString.c_str(), AnimationModeTable, AnimationModeTableCount, animationMode ) )
+          {
+            popupImpl.SetAnimationMode( animationMode );
+          }
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::ENTRY_ANIMATION:
+      {
+        Property::Map valueMap;
+        if( value.Get( valueMap ) )
+        {
+          popupImpl.SetEntryAnimationData( valueMap );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::EXIT_ANIMATION:
+      {
+        Property::Map valueMap;
+        if( value.Get( valueMap ) )
+        {
+          popupImpl.SetExitAnimationData( valueMap );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
+      {
+        int valueInt;
+        if( value.Get( valueInt ) )
+        {
+          popupImpl.SetAutoHideDelay( valueInt );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::BACKING_ENABLED:
+      {
+        bool valueBool;
+        if( value.Get( valueBool ) )
+        {
+          popupImpl.SetBackingEnabled( valueBool );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::BACKING_COLOR:
+      {
+        Vector4 valueVector4;
+        if( value.Get( valueVector4 ) )
+        {
+          popupImpl.SetBackingColor( valueVector4 );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          Toolkit::ImageView actor = Toolkit::ImageView::New( valueString );
+          popupImpl.SetPopupBackgroundImage( actor );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
+      {
+        bool valueUpdated = false;
+
+        Vector4 valueVector4;
+        if( value.Get( popupImpl.mBackgroundBorder ) )
+        {
+          valueUpdated = true;
+        }
+        else if( value.Get( valueVector4 ) )
+        {
+          popupImpl.mBackgroundBorder.left   = valueVector4.x;
+          popupImpl.mBackgroundBorder.right  = valueVector4.y;
+          popupImpl.mBackgroundBorder.bottom = valueVector4.z;
+          popupImpl.mBackgroundBorder.top    = valueVector4.w;
+          valueUpdated = true;
+        }
+
+        if( valueUpdated )
+        {
+          popupImpl.LayoutTail(); // Update the tail if required
+          popupImpl.UpdateBackgroundPositionAndSize(); // Update the background's size and position
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_UP_IMAGE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          popupImpl.SetTailUpImage( valueString );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          popupImpl.SetTailDownImage( valueString );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          popupImpl.SetTailLeftImage( valueString );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
+      {
+        std::string valueString;
+        if( value.Get( valueString ) )
+        {
+          popupImpl.SetTailRightImage( valueString );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Popup::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( Dali::BaseHandle( object ) );
+
+  if ( popup )
+  {
+    Popup& popupImpl( GetImpl( popup ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::Popup::Property::TITLE:
+      {
+        Property::Map map;
+        Scripting::CreatePropertyMap( popupImpl.GetTitle(), map );
+        value = map;
+        break;
+      }
+      case Toolkit::Popup::Property::CONTENT:
+      {
+        Property::Map map;
+        Scripting::CreatePropertyMap( popupImpl.GetContent(), map );
+        value = map;
+        break;
+      }
+      case Toolkit::Popup::Property::FOOTER:
+      {
+        Property::Map map;
+        Scripting::CreatePropertyMap( popupImpl.GetFooter(), map );
+        value = map;
+        break;
+      }
+      case Toolkit::Popup::Property::DISPLAY_STATE:
+      {
+        value = Scripting::GetLinearEnumerationName< Toolkit::Popup::DisplayState >( popupImpl.GetDisplayState(), DisplayStateTable, DisplayStateTableCount );
+        break;
+      }
+      case Toolkit::Popup::Property::TOUCH_TRANSPARENT:
+      {
+        value = popupImpl.IsTouchTransparent();
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_VISIBILITY:
+      {
+        value = popupImpl.IsTailVisible();
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_POSITION:
+      {
+        value = popupImpl.GetTailPosition();
+        break;
+      }
+      case Toolkit::Popup::Property::CONTEXTUAL_MODE:
+      {
+        value = Scripting::GetLinearEnumerationName< Toolkit::Popup::ContextualMode >( popupImpl.GetContextualMode(), ContextualModeTable, ContextualModeTableCount );
+        break;
+      }
+      case Toolkit::Popup::Property::ANIMATION_DURATION:
+      {
+        value = popupImpl.GetAnimationDuration();
+        break;
+      }
+      case Toolkit::Popup::Property::ANIMATION_MODE:
+      {
+        value = Scripting::GetLinearEnumerationName< Toolkit::Popup::AnimationMode >( popupImpl.GetAnimationMode(), AnimationModeTable, AnimationModeTableCount );
+        break;
+      }
+      case Toolkit::Popup::Property::ENTRY_ANIMATION:
+      {
+        // Note: Cannot retrieve property map from animation.
+        Property::Map map;
+        value = map;
+        break;
+      }
+      case Toolkit::Popup::Property::EXIT_ANIMATION:
+      {
+        // Note: Cannot retrieve property map from animation.
+        Property::Map map;
+        value = map;
+        break;
+      }
+      case Toolkit::Popup::Property::AUTO_HIDE_DELAY:
+      {
+        value = popupImpl.GetAutoHideDelay();
+        break;
+      }
+      case Toolkit::Popup::Property::BACKING_ENABLED:
+      {
+        value = popupImpl.IsBackingEnabled();
+        break;
+      }
+      case Toolkit::Popup::Property::BACKING_COLOR:
+      {
+        value = popupImpl.GetBackingColor();
+        break;
+      }
+      case Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE:
+      {
+        Toolkit::ImageView imageView = Toolkit::ImageView::DownCast( popupImpl.GetPopupBackgroundImage() );
+        if( imageView )
+        {
+          value = imageView.GetProperty( Toolkit::ImageView::Property::IMAGE );
+        }
+        break;
+      }
+      case Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER:
+      {
+        value = popupImpl.mBackgroundBorder;
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_UP_IMAGE:
+      {
+        value = popupImpl.GetTailUpImage();
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_DOWN_IMAGE:
+      {
+        value = popupImpl.GetTailDownImage();
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_LEFT_IMAGE:
+      {
+        value = popupImpl.GetTailLeftImage();
+        break;
+      }
+      case Toolkit::Popup::Property::TAIL_RIGHT_IMAGE:
+      {
+        value = popupImpl.GetTailRightImage();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+bool Popup::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::Popup popup = Toolkit::Popup::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TOUCHED_OUTSIDE ) )
+  {
+    popup.OutsideTouchedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWING ) )
+  {
+    popup.ShowingSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_SHOWN ) )
+  {
+    popup.ShownSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDING ) )
+  {
+    popup.HidingSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_HIDDEN ) )
+  {
+    popup.HiddenSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+bool Popup::OnBackingTouched( Actor actor, const TouchData& touch )
+{
+  // Allow events to pass through if touch transparency is enabled.
+  if( mTouchTransparent )
+  {
+    return false;
+  }
+
+  if( touch.GetPointCount() > 0 )
+  {
+    if( touch.GetState( 0 ) == PointState::DOWN )
+    {
+      // Guard against destruction during signal emission.
+      Toolkit::Popup handle( GetOwner() );
+
+      mTouchedOutsideSignal.Emit();
+    }
+  }
+
+  // Block anything behind backing becoming touched.
+  mLayer.SetTouchConsumed( true );
+  return true;
+}
+
+bool Popup::OnBackingWheelEvent( Actor actor, const WheelEvent& event )
+{
+  // Allow events to pass through if touch transparency is enabled.
+  if( mTouchTransparent )
+  {
+    return false;
+  }
+
+  // Consume wheel event in dimmed backing actor.
+  mLayer.SetTouchConsumed( true );
+  return true;
+}
+
+bool Popup::OnDialogTouched( Actor actor, const TouchData& touch )
+{
+  // Allow events to pass through if touch transparency is enabled.
+  if( mTouchTransparent )
+  {
+    return false;
+  }
+
+  // Consume event (stops backing actor receiving touch events)
+  mLayer.SetTouchConsumed( true );
+  return true;
+}
+
+void Popup::OnStageConnection( int depth )
+{
+  mLayoutDirty = true;
+  RelayoutRequest();
+
+  Control::OnStageConnection( depth );
+}
+
+void Popup::OnChildAdd( Actor& child )
+{
+  // Re-parent any children added by user to the body layer.
+  if( mAlterAddedChild )
+  {
+    SetContent( child );
+  }
+  else
+  {
+    mLayoutDirty = true;
+    RelayoutRequest();
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void Popup::LayoutContext( const Vector2& size )
+{
+  // Do nothing if not in a contextual mode (or there is no parent context).
+  Actor self = Self();
+  Actor parent = self.GetParent();
+  if( ( mContextualMode == Toolkit::Popup::NON_CONTEXTUAL ) || !parent )
+  {
+    return;
+  }
+
+  mPopupContainer.SetParentOrigin( ParentOrigin::CENTER );
+  // We always anchor to the CENTER, rather than a different anchor point for each contextual
+  // mode to allow code-reuse of the bound checking code (for maintainability).
+  mPopupContainer.SetAnchorPoint( AnchorPoint::CENTER );
+
+  // Setup with some pre-calculations for speed.
+  Vector3 halfStageSize( Stage().GetCurrent().GetSize() / 2.0f );
+  Vector3 parentPosition( parent.GetCurrentPosition() );
+  Vector2 halfSize( size / 2.0f );
+  Vector2 halfParentSize( parent.GetRelayoutSize( Dimension::WIDTH ) / 2.0f, parent.GetRelayoutSize( Dimension::HEIGHT ) / 2.0f );
+  Vector3 newPosition( Vector3::ZERO );
+
+  // Perform different positioning based on the specified contextual layout mode.
+  switch( mContextualMode )
+  {
+    case Toolkit::Popup::BELOW:
+    {
+      newPosition.x += halfSize.x - halfParentSize.x;
+      newPosition.y += halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
+      break;
+    }
+    case Toolkit::Popup::ABOVE:
+    {
+      newPosition.x += halfSize.x - halfParentSize.x;
+      newPosition.y -= halfSize.y + halfParentSize.y + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.y;
+      break;
+    }
+    case Toolkit::Popup::RIGHT:
+    {
+      newPosition.x += halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
+      newPosition.y += halfSize.y - halfParentSize.y;
+      break;
+    }
+    case Toolkit::Popup::LEFT:
+    {
+      newPosition.x -= halfSize.x + halfParentSize.x + DEFAULT_CONTEXTUAL_ADJACENCY_MARGIN.x;
+      newPosition.y += halfSize.y - halfParentSize.y;
+      break;
+    }
+    case Toolkit::Popup::NON_CONTEXTUAL:
+    {
+      // Code won't reach here (caught earlier).
+      break;
+    }
+  }
+
+  // On-screen position checking.
+  // Check new position is not too far right. If so, correct it.
+  // Note: Check for right rather than left first, so if popup is too wide, the left check overrides
+  // the right check and we at least see the left portion of the popup (as this is more useful).
+  if( newPosition.x >= ( halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x ) )
+  {
+    newPosition.x = halfStageSize.x - parentPosition.x - halfSize.x - DEFAULT_CONTEXTUAL_STAGE_BORDER.x;
+  }
+  // Check new position is not too far left. If so, correct it.
+  if( newPosition.x < halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x )
+  {
+    newPosition.x = halfSize.x - ( parentPosition.x + halfStageSize.x ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.x;// - parentSize.x;
+  }
+  // Check new position is not too far down. If so, correct it.
+  if( newPosition.y >= ( halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y ) )
+  {
+    newPosition.y = halfStageSize.y - parentPosition.y - halfSize.y - DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
+  }
+  // Check new position is not too far up. If so, correct it.
+  if( newPosition.y < halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y )
+  {
+    newPosition.y = halfSize.y - ( parentPosition.y + halfStageSize.y ) + DEFAULT_CONTEXTUAL_STAGE_BORDER.y;
+  }
+
+  // Set the final position.
+  mPopupContainer.SetPosition( newPosition );
+}
+
+void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  Vector2 useSize( size );
+
+  // Use the Popup layouts size, unless requested to use a fixed size.
+  // In which case take the size set for the Popup itself.
+  ResizePolicy::Type widthPolicy = Self().GetResizePolicy( Dimension::WIDTH );
+  ResizePolicy::Type heightPolicy = Self().GetResizePolicy( Dimension::HEIGHT );
+
+  // Width calculations:
+  if( widthPolicy == ResizePolicy::USE_NATURAL_SIZE || widthPolicy == ResizePolicy::FIT_TO_CHILDREN )
+  {
+    // If we using a child-based policy, take the size from the popup layout.
+    mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::WIDTH );
+    useSize.width = mPopupLayout.GetRelayoutSize( Dimension::WIDTH );
+
+    mPopupLayout.SetFitWidth( 0u );
+  }
+  else
+  {
+    // If we using a parent-based policy, take the size from the popup object itself (self).
+    mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::WIDTH );
+
+    mPopupLayout.SetFixedWidth( 0u, useSize.width );
+  }
+
+  // Height calculations:
+  // Title: Let the title be as high as it needs to be.
+  mPopupLayout.SetFitHeight( 0u );
+
+  // Footer: Convert the footer's resize policy to a TableView row policy.
+  if( mFooter )
+  {
+    ResizePolicy::Type footerHeightPolicy = mFooter.GetResizePolicy( Dimension::HEIGHT );
+    if( ( footerHeightPolicy == ResizePolicy::USE_NATURAL_SIZE ) ||
+        ( footerHeightPolicy == ResizePolicy::FIT_TO_CHILDREN ) )
+    {
+      mPopupLayout.SetFitHeight( 2u );
+    }
+    else if( footerHeightPolicy == ResizePolicy::FIXED )
+    {
+      mPopupLayout.SetFixedHeight( 2u, mFooter.GetRelayoutSize( Dimension::HEIGHT) );
+    }
+    else
+    {
+      mPopupLayout.SetRelativeHeight( 2u, 1.0f );
+    }
+  }
+  else
+  {
+    mPopupLayout.SetFixedHeight( 2u, 0.0f );
+  }
+
+  // Popup contents: Adjust the tableview's policies based on the popup's policies.
+  if( heightPolicy == ResizePolicy::USE_NATURAL_SIZE || heightPolicy == ResizePolicy::FIT_TO_CHILDREN )
+  {
+    mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+
+    // Let both the contents expand as necessary.
+    mPopupLayout.SetFitHeight( 1u );
+    useSize.height = mPopupLayout.GetRelayoutSize( Dimension::HEIGHT );
+  }
+  else
+  {
+    mPopupLayout.SetResizePolicy( heightPolicy, Dimension::HEIGHT );
+
+    // Let the content expand to fill the remaining space.
+    mPopupLayout.SetRelativeHeight( 1u, 1.0f );
+    mPopupLayout.SetResizePolicy( ResizePolicy::USE_ASSIGNED_SIZE, Dimension::HEIGHT );
+  }
+
+  // Relayout the popup-layout to give it it's new size this frame.
+  container.Add( mPopupLayout, useSize );
+
+  if( mContent )
+  {
+    container.Add( mContent, Vector2( mContent.GetRelayoutSize( Dimension::WIDTH ), mContent.GetRelayoutSize( Dimension::HEIGHT ) ) );
+  }
+
+  // Perform contextual layout setup if required.
+  // This is done each time in case the parent moves.
+  // This will have no effect if no contextual mode is selected.
+  LayoutContext( useSize );
+}
+
+void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+{
+  // To get the popup to emulate fit-to-children, we need to actually set use-natural-size.
+  if( ( dimension & Dimension::HEIGHT ) && ( policy == ResizePolicy::FIT_TO_CHILDREN ) )
+  {
+    Self().SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+  }
+
+  mLayoutDirty = true;
+  return;
+}
+
+Vector3 Popup::GetNaturalSize()
+{
+  return mPopupLayout.GetNaturalSize();
+}
+
+float Popup::GetHeightForWidth( float width )
+{
+  return mPopupLayout.GetHeightForWidth( width );
+}
+
+float Popup::GetWidthForHeight( float height )
+{
+  return mPopupLayout.GetWidthForHeight( height );
+}
+
+bool Popup::OnKeyEvent( const KeyEvent& event )
+{
+  // Allow events to pass through if touch transparency is enabled.
+  if( mTouchTransparent )
+  {
+    return false;
+  }
+
+  bool consumed = false;
+
+  if( event.state == KeyEvent::Down )
+  {
+    if (event.keyCode == Dali::DALI_KEY_ESCAPE || event.keyCode == Dali::DALI_KEY_BACK)
+    {
+      SetDisplayState( Toolkit::Popup::HIDDEN );
+      consumed = true;
+    }
+  }
+
+  return consumed;
+}
+
+void Popup::AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors )
+{
+  if( parent )
+  {
+    Toolkit::Control control = Toolkit::Control::DownCast( parent );
+    bool layoutControl = control && GetImplementation( control ).IsKeyboardNavigationSupported();
+
+    if( parent.IsKeyboardFocusable() || layoutControl )
+    {
+      focusableActors.push_back( parent );
+
+      if( !layoutControl )
+      {
+        for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
+        {
+          Actor child( parent.GetChildAt( i ) );
+          AddFocusableChildrenRecursive( child, focusableActors );
+        }
+      }
+    }
+  }
+}
+
+void Popup::AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors )
+{
+  if( parent )
+  {
+    Toolkit::Control control = Toolkit::Control::DownCast( parent );
+    if( !GetImplementation( control ).IsKeyboardNavigationSupported() )
+    {
+      for( unsigned int i = 0, numberChildren = parent.GetChildCount(); i < numberChildren; ++i )
+      {
+        Actor child( parent.GetChildAt( i ) );
+        AddFocusableChildrenRecursive( child, focusableActors );
+      }
+    }
+    else
+    {
+      focusableActors.push_back( parent );
+    }
+  }
+}
+
+Actor Popup::GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled )
+{
+  std::string currentStr;
+  if( currentFocusedActor )
+  {
+    currentStr = currentFocusedActor.GetName();
+  }
+
+  Actor nextFocusableActor( currentFocusedActor );
+  Actor currentFocusGroup;
+  if( currentFocusedActor )
+  {
+    currentFocusGroup = KeyboardFocusManager::Get().GetFocusGroup( currentFocusedActor );
+  }
+
+  // TODO: Needs to be optimised
+  // The following statement checks that if we have a current focused actor, then the current focus group is not the popup content or footer.
+  // This is to detect if the focus is currently outside the popup, and if so, move it inside.
+  if( !currentFocusedActor ||
+    ( currentFocusedActor && ( ( !mContent || ( currentFocusGroup != mContent ) ) && ( !mFooter || ( currentFocusGroup != mFooter ) ) ) ) )
+  {
+    // The current focused actor is not within popup.
+    if( mContent && mContent.IsKeyboardFocusable() )
+    {
+      // If the content is focusable, move the focus to the content.
+      nextFocusableActor = mContent;
+    }
+    else if( mFooter && mFooter.IsKeyboardFocusable() )
+    {
+      // If the footer is focusable, move the focus to the footer.
+      nextFocusableActor = mFooter;
+    }
+  }
+  else
+  {
+    // Rebuild the focus chain because controls or content can be added or removed dynamically
+    std::vector< Actor > focusableActors;
+
+    AddFocusableChildren( mContent, focusableActors );
+    AddFocusableChildren( mFooter, focusableActors );
+
+    std::vector< Actor >::iterator endIterator = focusableActors.end();
+    std::vector< Actor >::iterator currentIterator = focusableActors.begin();
+    for( std::vector< Actor >::iterator iterator = focusableActors.begin(); iterator != endIterator; ++iterator )
+    {
+      if( currentFocusedActor == *iterator )
+      {
+        currentIterator = iterator;
+      }
+    }
+
+    if( currentIterator != endIterator )
+    {
+      switch( direction )
+      {
+        case Toolkit::Control::KeyboardFocus::LEFT:
+        {
+          if( currentIterator == focusableActors.begin() )
+          {
+            nextFocusableActor = *( endIterator - 1 );
+          }
+          else
+          {
+            nextFocusableActor = *( currentIterator - 1 );
+          }
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::RIGHT:
+        {
+          if( currentIterator == endIterator - 1 )
+          {
+            nextFocusableActor = *( focusableActors.begin() );
+          }
+          else
+          {
+            nextFocusableActor = *( currentIterator + 1 );
+          }
+          break;
+        }
+
+        case Toolkit::Control::KeyboardFocus::UP:
+        {
+          nextFocusableActor = *(  focusableActors.begin() );
+          break;
+        }
+
+        case Toolkit::Control::KeyboardFocus::DOWN:
+        {
+          nextFocusableActor = *( endIterator - 1 );
+          break;
+        }
+
+        default:
+        {
+          break;
+        }
+      }
+
+      if( !nextFocusableActor )
+      {
+        DALI_LOG_WARNING( "Can not decide next focusable actor\n" );
+      }
+    }
+  }
+
+  return nextFocusableActor;
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/popup/popup-impl.h b/dali-toolkit/internal/controls/popup/popup-impl.h
new file mode 100755 (executable)
index 0000000..6b2c19a
--- /dev/null
@@ -0,0 +1,584 @@
+#ifndef DALI_TOOLKIT_INTERNAL_POPUP_H
+#define DALI_TOOLKIT_INTERNAL_POPUP_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/devel-api/animation/animation-data.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Popup;
+
+typedef IntrusivePtr< Popup > PopupPtr;
+
+/**
+ * @copydoc Toolkit::Popup
+ */
+class Popup : public Control
+{
+public:
+
+  /**
+   * Create a new Popup.
+   * @return A public handle to the newly allocated Popup.
+   */
+  static Dali::Toolkit::Popup New();
+
+public:
+
+  /**
+   * @copydoc Toolkit::Popup::SetPopupBackgroundImage
+   */
+  void SetPopupBackgroundImage( Actor image );
+
+  /**
+   * @copydoc Toolkit::Popup::GetPopupBackgroundImage
+   */
+  Actor GetPopupBackgroundImage() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTitle( Actor titleActor )
+   */
+  void SetTitle( Actor titleActor );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTitle
+   */
+  Actor GetTitle() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetContent
+   */
+  void SetContent( Actor content );
+
+  /**
+   * @copydoc Toolkit::Popup::GetContent
+   */
+  Actor GetContent() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetFooter
+   */
+  void SetFooter( Actor control );
+
+  /**
+   * @copydoc Toolkit::Popup::GetFooter
+   */
+  Actor GetFooter() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetDisplayState
+   */
+  void SetDisplayState( Toolkit::Popup::DisplayState displayState );
+
+  /**
+   * @copydoc Toolkit::Popup::GetDisplayState
+   */
+  Toolkit::Popup::DisplayState GetDisplayState() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailVisibility
+   */
+  void SetTailVisibility( bool visible );
+
+  /**
+   * @copydoc Toolkit::Popup::IsTailVisible
+   */
+  const bool IsTailVisible() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailPosition
+   */
+  void SetTailPosition( Vector3 position );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTailPosition
+   */
+  const Vector3& GetTailPosition() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetContextualMode
+   */
+  void SetContextualMode( Toolkit::Popup::ContextualMode mode );
+
+  /**
+   * @copydoc Toolkit::Popup::GetContextualMode
+   */
+  Toolkit::Popup::ContextualMode GetContextualMode() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetAnimationDuration
+   */
+  void SetAnimationDuration( float duration );
+
+  /**
+   * @copydoc Toolkit::Popup::GetAnimationDuration
+   */
+  float GetAnimationDuration() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetAnimationMode
+   */
+  void SetAnimationMode( Toolkit::Popup::AnimationMode animationMode );
+
+  /**
+   * @copydoc Toolkit::Popup::GetAnimationMode
+   */
+  Toolkit::Popup::AnimationMode GetAnimationMode() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetAutoHideDelay
+   */
+  void SetAutoHideDelay( int delay );
+
+  /**
+   * @copydoc Toolkit::Popup::GetAutoHideDelay
+   */
+  int GetAutoHideDelay() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetBackingEnabled
+   */
+  void SetBackingEnabled( bool enabled );
+
+  /**
+   * @copydoc Toolkit::Popup::IsBackingEnabled
+   */
+  const bool IsBackingEnabled() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetBackingColor
+   */
+  void SetBackingColor( Vector4 color );
+
+  /**
+   * @copydoc Toolkit::Popup::GetBackingColor
+   */
+  const Vector4& GetBackingColor() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailUpImage
+   */
+  void SetTailUpImage( std::string image );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTailUpImage
+   */
+  const std::string& GetTailUpImage() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailDownImage
+   */
+  void SetTailDownImage( std::string image );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTailDownImage
+   */
+  const std::string& GetTailDownImage() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailLeftImage
+   */
+  void SetTailLeftImage( std::string image );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTailLeftImage
+   */
+  const std::string& GetTailLeftImage() const;
+
+  /**
+   * @copydoc Toolkit::Popup::SetTailRightImage
+   */
+  void SetTailRightImage( std::string image );
+
+  /**
+   * @copydoc Toolkit::Popup::GetTailRightImage
+   */
+  const std::string& GetTailRightImage() const;
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] propertyIndex The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] propertyIndex The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+protected:
+
+  /**
+   * Construct a new Popup.
+   */
+  Popup();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Popup();
+
+private:
+
+  /**
+   * @brief Creates the layout of the popup, to be done just before showing for the first time.
+   * Also calls OnLayoutSetup() to allow derived classes to perform layout at this stage.
+   */
+  void LayoutPopup();
+
+  /**
+   * @brief Creates or destroys the popup tail based on the current TAIL_DISPLAYED property.
+   * Also uses the TAIL_POSITION property to position it.
+   */
+  void LayoutTail();
+
+  /**
+   * @brief Performs any relative positioning required based on the current contextual mode, if set.
+   * If contextual mode is not enabled, this method has no effect.
+   * @param[in] size The Popups current size (can be accessed from within the OnRelayout() method).
+   */
+  void LayoutContext( const Vector2& size );
+
+  /**
+   * @brief All transition-in animation setup and layout is done here.
+   * Different types of animation mode require different layouts to work,
+   * this function encapsulates anything animation-mode specific.
+   * This is called once for multiple displays/hides of the pops.
+   * It is only re-called when the layout becomes dirty.
+   */
+  void LayoutAnimation();
+
+  /**
+   * @brief Initiates a transition-in or transition-out animation based
+   * on the current animation settings.
+   * @param[in] transitionIn True to perform a transition-in, false for transition out.
+   * @param[in] instantaneous Optional - If set to true will override the duration to provide an instant animation.
+   */
+  void StartTransitionAnimation( bool transitionIn, bool instantaneous = false );
+
+  /**
+   * @brief Invoked once a display state change has completed.
+   */
+  void DisplayStateChangeComplete();
+
+  /**
+   * @brief This is called when the auto-hide timer finishes.
+   * It performs a display-state change to HIDDEN.
+   * @return True as signal is consumed.
+   */
+  bool OnAutoHideTimeReached();
+
+  /**
+   * @brief Create Dimmed Backing (covers all content behind the dialog).
+   *
+   * @return The backing control.
+   */
+  Toolkit::Control CreateBacking();
+
+  /**
+   * @brief Creates the lower area within the popup.
+   */
+  void CreateFooter();
+
+  /**
+   * @brief Sets if the popup allows touch events to pass through or not.
+   *
+   * @param[in] enabled Set to true to make the popup touch-transparent.
+   */
+  void SetTouchTransparent( bool enabled );
+
+  /**
+   * @brief Returns if the popup allows touch events to pass through or not.
+   *
+   * @return True if the popup is touch-transparent.
+   */
+  const bool IsTouchTransparent() const;
+
+  /**
+   * @brief Allows the popup entry animation to be setup from a Property::Map that could
+   * originate, for example, from a JSON file.
+   *
+   * @param[in] map A Property::Map containing a description of an animation
+   */
+  void SetEntryAnimationData( const Property::Map& map );
+
+  /**
+   * @brief Allows the popup exit animation to be setup from a Property::Map that could
+   * originate, for example, from a JSON file.
+   *
+   * @param[in] map A Property::Map containing a description of an animation
+   */
+  void SetExitAnimationData( const Property::Map& map );
+
+  /**
+   * @briefs Updates the popup background's position and size.
+   */
+  void UpdateBackgroundPositionAndSize();
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Toolkit::Popup::OutsideTouchedSignal()
+   */
+  Toolkit::Popup::TouchedOutsideSignalType& OutsideTouchedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Popup::ShowingSignal()
+   */
+  Toolkit::Popup::DisplayStateChangeSignalType& ShowingSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Popup::ShownSignal()
+   */
+  Toolkit::Popup::DisplayStateChangeSignalType& ShownSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Popup::HidingSignal()
+   */
+  Toolkit::Popup::DisplayStateChangeSignalType& HidingSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Popup::HiddenSignal()
+   */
+  Toolkit::Popup::DisplayStateChangeSignalType& HiddenSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * Signal occurs when the State animation (transition from hide <-> show) finishes.
+   * @param[in] source The animation that just finished.
+   */
+  void OnDisplayChangeAnimationFinished( Animation& source );
+
+  /**
+   * Signal occurs when the dimmed backing for the Popup is touched.
+   * @param[in] actor The Actor Touched
+   * @param[in] touch The Touch Data.
+   * @return Whether to consume event or not.
+   */
+  bool OnBackingTouched(Actor actor, const TouchData& touch);
+
+  /**
+   * Signal occurs when a mouse wheel event occurs on the dimmed backing.
+   * @param[in] actor The Actor that got the wheel event.
+   * @param[in] event The Wheel Event.
+   * @return Whether to consume event or not.
+   */
+  bool OnBackingWheelEvent(Actor actor, const WheelEvent& event);
+
+  /**
+   * Signal occurs when the dialog has been touched.
+   * @param[in] actor The Actor Touched
+   * @param[in] touch The Touch Data.
+   * @return Whether to consume event or not.
+   */
+  bool OnDialogTouched( Actor actor, const TouchData& touch );
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * Called whenever the popup layout is re-set up.
+   * Normally due to a change in contents.
+   * Note: This is only done when the popup is shown.
+   */
+  virtual void OnLayoutSetup() {}
+
+  /**
+   * Called when the popup is directly or indirectly parented to the stage.
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * From Control; called after a child has been added to the owning actor.
+   * @param[in] child The child which has been added.
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnRelayOut()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc Control::OnSetResizePolicy()
+   */
+  virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension );
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Control::GetWidthForHeight()
+   */
+  virtual float GetWidthForHeight( float height );
+
+  /**
+   * @copydoc Control::OnKeyEvent()
+   */
+  virtual bool OnKeyEvent( const KeyEvent& event );
+
+  /**
+   * @copydoc Control::GetNextKeyboardFocusableActor()
+   */
+  Actor GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled );
+
+private:
+
+  /**
+   * Recursively add any focusable actors or layout containers to the provided vector.
+   * Include the top level actor if it is a layout container.
+   *
+   * @param[in]     parent          The actor to start from
+   * @param[in/out] focusableActors The vector to add focusable actors to
+   */
+  void AddFocusableChildren( Actor parent, std::vector< Actor >& focusableActors );
+
+  /**
+   * Recursively add any focusable actors or layout containers to the provided vector.
+   *
+   * @param[in]     parent          The actor to start from
+   * @param[in/out] focusableActors The vector to add focusable actors to
+   */
+  void AddFocusableChildrenRecursive( Actor parent, std::vector< Actor >& focusableActors );
+
+private:
+
+  // Undefined.
+  Popup(const Popup&);
+
+  // Undefined.
+  Popup& operator=(const Popup& rhs);
+
+private:
+
+  Toolkit::Popup::TouchedOutsideSignalType     mTouchedOutsideSignal;
+  Toolkit::Popup::DisplayStateChangeSignalType mShowingSignal;
+  Toolkit::Popup::DisplayStateChangeSignalType mShownSignal;
+  Toolkit::Popup::DisplayStateChangeSignalType mHidingSignal;
+  Toolkit::Popup::DisplayStateChangeSignalType mHiddenSignal;
+
+  Layer mLayer;                                      ///< Popup Layer (i.e. Dim backing and PopupBg reside in this).
+  Toolkit::TableView mPopupLayout;                   ///< Popup Background (i.e. dialog reside in this).
+  Toolkit::Control mBacking;                         ///< Backing actor (dim effect).
+  Actor mPreviousFocusedActor;                       ///< Store the previous focused actor to restore the focus when popup hide.
+  Actor mTailImage;                                  ///< Stores the tail image.
+  Actor mPopupContainer;                             ///< This actor is used to house the background image and the main popup layout.
+  Animation mAnimation;                              ///< The current animation in use used to manage display state changing.
+  bool mAlterAddedChild;                             ///< Flag used to control whether children are reparented or not.
+  bool mLayoutDirty;                                 ///< Set to true whenever any property that would require a layout update is modified.
+  Timer mAutoHideTimer;                              ///< Used to perform an auto-hide of the popup if desired.
+  bool mTouchTransparent;                            ///< Allows all events to pass through the popup.
+
+  // Main Content related properties:
+  Actor mTitle;                                      ///< Stores the text title.
+  Actor mContent;                                    ///< Stores the unselected content.
+  Actor mFooter;                                     ///< Stores the footer content (typically controls).
+
+  // Display related properties.
+  Toolkit::Popup::DisplayState mDisplayState;        ///< The current display state of the popup.
+  bool mTailVisible;                                 ///< True if the popup tail should be visible.
+  Vector3 mTailPosition;                             ///< The position of the tail.
+  Toolkit::Popup::ContextualMode mContextualMode;    ///< Allows the popup to be layed out adjacent to its parent in different directions.
+  float mAnimationDuration;                          ///< The duration of the transition in and out animations.
+  Toolkit::Popup::AnimationMode mAnimationMode;      ///< The animation to use to transition in and out.
+  Dali::AnimationData mEntryAnimationData;           ///< Stores description data that can be used for generating a custom entry animation.
+  Dali::AnimationData mExitAnimationData;            ///< Stores description data that can be used for generating a custom exit animation.
+  unsigned int mAutoHideDelay;                       ///< If set, will auto-hide the popup after a specified amount of time.
+
+  // Style related properties:
+  bool mBackingEnabled;                              ///< True if a dimmed backing will be used.
+  Vector4 mBackingColor;                             ///< The color of the backing.
+  Actor mPopupBackgroundImage;                       ///< Stores the background image.
+  Rect<int> mBackgroundBorder;                       ///< Background border.
+  float mMargin;                                     ///< Internal margin for popup contents.
+  std::string mTailUpImage;                          ///< Image used for the tail for the up direction.
+  std::string mTailDownImage;                        ///< Image used for the tail for the down direction.
+  std::string mTailLeftImage;                        ///< Image used for the tail for the left direction.
+  std::string mTailRightImage;                       ///< Image used for the tail for the right direction.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Popup& GetImpl( Toolkit::Popup& publicObject )
+{
+  DALI_ASSERT_ALWAYS( publicObject );
+
+  Dali::RefObject& handle = publicObject.GetImplementation();
+
+  return static_cast<Toolkit::Internal::Popup&>( handle );
+}
+
+inline const Toolkit::Internal::Popup& GetImpl( const Toolkit::Popup& publicObject )
+{
+  DALI_ASSERT_ALWAYS( publicObject );
+
+  const Dali::RefObject& handle = publicObject.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::Popup&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_POPUP_H
diff --git a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp
new file mode 100755 (executable)
index 0000000..2b89fed
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <sstream>
+#include <algorithm>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/public-api/math/math-utils.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // Unnamed namespace
+{
+
+BaseHandle Create()
+{
+  return Dali::Toolkit::ProgressBar::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ProgressBar, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressValue",                     FLOAT,    PROGRESS_VALUE                   )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "secondaryProgressValue",            FLOAT,    SECONDARY_PROGRESS_VALUE         )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminate",                     BOOLEAN,  INDETERMINATE                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "trackVisual",                       MAP,      TRACK_VISUAL                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "progressVisual",                    MAP,      PROGRESS_VISUAL                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "secondaryProgressVisual",           MAP,      SECONDARY_PROGRESS_VISUAL        )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminateVisual",               MAP,      INDETERMINATE_VISUAL             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "indeterminateVisualAnimation",      ARRAY,    INDETERMINATE_VISUAL_ANIMATION   )
+DALI_PROPERTY_REGISTRATION( Toolkit, ProgressBar, "labelVisual",                       MAP,      LABEL_VISUAL                     )
+DALI_SIGNAL_REGISTRATION(   Toolkit, ProgressBar, "valueChanged",                      SIGNAL_VALUE_CHANGED                       )
+
+DALI_TYPE_REGISTRATION_END()
+
+struct ProgressDepthIndex
+{
+  // Enum to make sure the visual order
+  enum
+  {
+    TRACK_VISUAL,
+    SECONDARY_PROGRESS_VISUAL,
+    PROGRESS_VISUAL,
+    LABEL_VISUAL,
+    INDETERMINATE_VISUAL
+  };
+};
+
+float DEFAULT_VALUE = 0.0f;
+float DEFAULT_LOWER_BOUND = 0.0f;
+float DEFAULT_UPPER_BOUND = 1.0f;
+float DEFAULT_FONT_SIZE = 12.0f;
+
+} // Unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ProgressBar
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Dali::Toolkit::ProgressBar ProgressBar::New()
+{
+  // Create the implementation
+  ProgressBarPtr progressBar( new ProgressBar() );
+
+  // Pass ownership to CustomActor via derived handle
+  Dali::Toolkit::ProgressBar handle( *progressBar );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  progressBar->Initialize();
+
+  return handle;
+}
+
+ProgressBar::ProgressBar()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mProgressValue( DEFAULT_VALUE ),
+  mSecondaryProgressValue( DEFAULT_VALUE ),
+  mIndeterminate( false )
+{
+}
+
+ProgressBar::~ProgressBar()
+{
+}
+
+void ProgressBar::OnInitialize()
+{
+}
+
+void ProgressBar::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+
+  Vector2 trackSize( size );
+  mDomain = CalcDomain( size );
+
+  trackSize.width = std::max( 0.0f, size.width ); // Ensure we don't go negative
+
+  Toolkit::Visual::Base trackVisual = DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::TRACK_VISUAL );
+  Toolkit::Visual::Base secondProgressVisual = DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL );
+  Toolkit::Visual::Base progressVisual = DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::PROGRESS_VISUAL );
+  Toolkit::Visual::Base labelVisual = DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::LABEL_VISUAL );
+  Toolkit::Visual::Base indeterminateVisual = DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL );
+
+  if( trackVisual )
+  {
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, trackSize )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+
+    trackVisual.SetTransformAndSize( visualTransform, trackSize );
+  }
+
+  if( secondProgressVisual )
+  {
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, Vector2( mDomain.from.x + mSecondaryProgressValue * ( mDomain.to.x - mDomain.from.x ), trackSize.height  ) )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                   .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
+    secondProgressVisual.SetTransformAndSize( visualTransform, trackSize );
+  }
+
+  if( progressVisual )
+  {
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, Vector2( mDomain.from.x + mProgressValue * ( mDomain.to.x - mDomain.from.x ), trackSize.height ) )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                   .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
+    progressVisual.SetTransformAndSize( visualTransform, trackSize );
+  }
+
+  if( labelVisual )
+  {
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, trackSize )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+    labelVisual.SetTransformAndSize( visualTransform, trackSize );
+  }
+
+  if( indeterminateVisual )
+  {
+    Property::Map visualTransform;
+
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, trackSize )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) );
+    indeterminateVisual.SetTransformAndSize( visualTransform, trackSize );
+  }
+
+}
+
+Vector3 ProgressBar::GetNaturalSize()
+{
+  // Return the bigger size after comparing trackVisual naturalSize and labelVisual naturalSize
+  Toolkit::Visual::Base trackVisual =  DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::TRACK_VISUAL );
+  Toolkit::Visual::Base labelVisual =  DevelControl::GetVisual( *this, Toolkit::ProgressBar::Property::LABEL_VISUAL );
+
+  Size trackSize;
+  Size labelSize;
+
+  if ( trackVisual )
+  {
+    trackVisual.GetNaturalSize( trackSize );
+  }
+  if ( labelVisual )
+  {
+    labelVisual.GetNaturalSize( labelSize );
+  }
+
+  Vector3 naturalSize;
+  naturalSize.width = ( trackSize.width > labelSize.width ) ? trackSize.width: labelSize.width;
+  naturalSize.height = ( trackSize.height > labelSize.height ) ? trackSize.height: labelSize.height;
+
+  return naturalSize;
+}
+
+ProgressBar::Domain ProgressBar::CalcDomain( const Vector2& currentSize )
+{
+   return Domain( Vector2( 0.0f, 0.0f ), currentSize );
+}
+
+Toolkit::ProgressBar::ValueChangedSignalType& ProgressBar::ValueChangedSignal()
+{
+  return mValueChangedSignal;
+}
+
+void ProgressBar::SetProgressValue( float value )
+{
+  // update the progress bar value (taking float precision errors into account)
+  // TODO : it seems 0.0f cannot into this statement.
+  if( ( mProgressValue != value ) &&
+      ( ( value >= DEFAULT_LOWER_BOUND ) || ( Equals( value, DEFAULT_LOWER_BOUND ) ) ) &&
+      ( ( value <= DEFAULT_UPPER_BOUND ) || ( Equals( value, DEFAULT_UPPER_BOUND ) ) ) )
+  {
+    mProgressValue = Clamp( value, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND );
+
+    Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() );
+    mValueChangedSignal.Emit( self, mProgressValue, mSecondaryProgressValue );
+    RelayoutRequest();
+  }
+}
+
+float ProgressBar::GetProgressValue() const
+{
+  return mProgressValue;
+}
+
+void ProgressBar::SetSecondaryProgressValue( float value )
+{
+  // update the progress bar value (taking float precision errors into account)
+  // TODO : it seems 0.0f cannot into this statement.
+  if( ( mSecondaryProgressValue != value ) &&
+      ( ( value >= DEFAULT_LOWER_BOUND ) || ( Equals( value, DEFAULT_LOWER_BOUND ) ) ) &&
+      ( ( value <= DEFAULT_UPPER_BOUND ) || ( Equals( value, DEFAULT_UPPER_BOUND ) ) ) )
+  {
+    mSecondaryProgressValue = Clamp( value, DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND );
+
+    Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() );
+    mValueChangedSignal.Emit( self, mProgressValue, mSecondaryProgressValue );
+
+    RelayoutRequest();
+  }
+}
+
+float ProgressBar::GetSecondaryProgressValue() const
+{
+  return mSecondaryProgressValue;
+}
+
+void ProgressBar::SetIndeterminate( bool value )
+{
+  mIndeterminate = value;
+  DevelControl::EnableVisual( *this, Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL, mIndeterminate );
+
+  if( mIndeterminate )
+  {
+    RelayoutRequest();
+    if( mIndeterminateVisualTransition )
+    {
+      PlayIndeterminateVisualTransition();
+    }
+  }
+  else
+  {
+    if( mIndeterminateVisualAni )
+    {
+      mIndeterminateVisualAni.Stop();
+    }
+  }
+}
+
+bool ProgressBar::GetIndeterminate() const
+{
+  return mIndeterminate;
+}
+
+void ProgressBar::SetIndeterminateVisualTransition( Toolkit::TransitionData transition )
+{
+  mIndeterminateVisualTransition = transition;
+  if( mIndeterminate )
+  {
+    PlayIndeterminateVisualTransition();
+  }
+}
+
+void ProgressBar::PlayIndeterminateVisualTransition()
+{
+  if( mIndeterminateVisualAni )
+  {
+    mIndeterminateVisualAni.Stop();
+    mIndeterminateVisualAni.Clear();
+  }
+
+  mIndeterminateVisualAni = DevelControl::CreateTransition( *this, mIndeterminateVisualTransition );
+
+  if( mIndeterminate && mIndeterminateVisualAni )
+  {
+    mIndeterminateVisualAni.SetLooping(true);
+    mIndeterminateVisualAni.Play();
+  }
+}
+
+Toolkit::TransitionData ProgressBar::ConvertPropertyToTransition( const Property::Value& value )
+{
+  Toolkit::TransitionData transitionData;
+
+  if( value.GetType() == Property::ARRAY )
+  {
+    transitionData = Toolkit::TransitionData::New( *value.GetArray() );
+  }
+  else if( value.GetType() == Property::MAP )
+  {
+    transitionData = Toolkit::TransitionData::New( *value.GetMap() );
+  }
+
+  return transitionData;
+}
+
+/**
+ * Create Visual for given index from a property map or url.
+ * 1) Check if value passed in is a url and create visual
+ * 2) Create visual from map if step (1) is false
+ * 3) Register visual with control with false for enable flag.
+ * 4) Unregister visual if empty map was provided. This is the method to remove a visual
+ */
+
+void ProgressBar::CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth )
+{
+  Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+  Toolkit::Visual::Base progressVisual;
+
+  std::string imageUrl;
+  if( value.Get( imageUrl ) )
+  {
+    if ( !imageUrl.empty() )
+    {
+      progressVisual = visualFactory.CreateVisual(  imageUrl, ImageDimensions()  );
+    }
+  }
+  else // Does this code make text-visual can be accepted as visual?
+  {
+    // if its not a string then get a Property::Map from the property if possible.
+    Property::Map *map = value.GetMap();
+    if( map && !map->Empty()  ) // Empty map results in current visual removal.
+    {
+      progressVisual = visualFactory.CreateVisual( *map );
+    }
+  }
+
+  if ( progressVisual )
+  {
+    if( index == Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL )
+    {
+      DevelControl::RegisterVisual( *this, index, progressVisual, mIndeterminate, visualDepth );
+    }
+    else
+    {
+      DevelControl::RegisterVisual( *this, index, progressVisual, true, visualDepth );
+    }
+  }
+  else
+  {
+    DevelControl::UnregisterVisual( *this, index );
+  }
+}
+
+bool ProgressBar::GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const
+{
+  bool success = false;
+  Toolkit::Visual::Base visual = DevelControl::GetVisual( *this, visualIndex );
+
+  if ( visual )
+  {
+    visual.CreatePropertyMap( retreivedMap );
+    success = true;
+  }
+
+  return success;
+}
+
+// Static class method to support script connecting signals
+bool ProgressBar::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected = true;
+  Toolkit::ProgressBar ProgressBar = Toolkit::ProgressBar::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
+  {
+    ProgressBar.ValueChangedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void ProgressBar::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
+
+  if ( progressBar )
+  {
+    ProgressBar& progressBarImpl( GetImpl( progressBar ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ProgressBar::Property::TRACK_VISUAL:
+      {
+        progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::TRACK_VISUAL );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL:
+      {
+        progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::SECONDARY_PROGRESS_VISUAL );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
+      {
+        progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::PROGRESS_VISUAL );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL:
+      {
+        progressBarImpl.CreateVisualsForComponent( propertyIndex, value, ProgressDepthIndex::INDETERMINATE_VISUAL );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::LABEL_VISUAL:
+      {
+        Property::Map map;
+        std::string textString;
+
+        if ( value.Get( textString ) )
+        {
+          // set new text string as TEXT property
+          Property::Map newTextMap;
+          Toolkit::Visual::Base label = DevelControl::GetVisual( progressBarImpl, Toolkit::ProgressBar::Property::LABEL_VISUAL );
+
+          if( label )
+          {
+            label.CreatePropertyMap( map );
+          }
+
+          // if LABEL_VISUAL doesn't set before, add Visual property "TYPE" to create new text Visual
+          if( map.Empty() )
+          {
+            newTextMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
+            newTextMap.Add( Toolkit::TextVisual::Property::POINT_SIZE, DEFAULT_FONT_SIZE );
+          }
+          newTextMap.Add( Toolkit::TextVisual::Property::TEXT, textString );
+
+          map.Merge( newTextMap );
+        }
+        else
+        {
+          value.Get( map );
+        }
+
+        if( !map.Empty() )
+        {
+          progressBarImpl.CreateVisualsForComponent( propertyIndex, map, ProgressDepthIndex::LABEL_VISUAL );
+        }
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
+      {
+        progressBarImpl.SetProgressValue( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VALUE:
+      {
+        progressBarImpl.SetSecondaryProgressValue( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::INDETERMINATE:
+      {
+        progressBarImpl.SetIndeterminate( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION:
+      {
+        progressBarImpl.SetIndeterminateVisualTransition( progressBarImpl.ConvertPropertyToTransition( value ) );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value ProgressBar::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::ProgressBar progressBar = Toolkit::ProgressBar::DownCast( Dali::BaseHandle( object ) );
+
+  if ( progressBar )
+  {
+    ProgressBar& progressBarImpl( GetImpl( progressBar ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::ProgressBar::Property::TRACK_VISUAL:
+      case Toolkit::ProgressBar::Property::PROGRESS_VISUAL:
+      case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VISUAL:
+      case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL:
+      case Toolkit::ProgressBar::Property::LABEL_VISUAL:
+      {
+        Property::Map visualProperty;
+        if ( progressBarImpl.GetPropertyMapForVisual( propertyIndex, visualProperty ) )
+        {
+          value = visualProperty;
+        }
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::PROGRESS_VALUE:
+      {
+        value = progressBarImpl.GetProgressValue();
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::SECONDARY_PROGRESS_VALUE:
+      {
+        value = progressBarImpl.GetSecondaryProgressValue();
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::INDETERMINATE:
+      {
+        value = progressBarImpl.GetIndeterminate();
+        break;
+      }
+
+      case Toolkit::ProgressBar::Property::INDETERMINATE_VISUAL_ANIMATION:
+      {
+        //TODO: Return INDETERMINATE_VISUAL_TRANSITION;
+      }
+    }
+  }
+
+  return value;
+}
+
+void ProgressBar::OnStageConnection( int depth )
+{
+  // Chain up first (ensures visuals are ready to draw)
+  Control::OnStageConnection( depth );
+
+  if( mIndeterminate )
+  {
+    PlayIndeterminateVisualTransition();
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h
new file mode 100755 (executable)
index 0000000..5b0ffd2
--- /dev/null
@@ -0,0 +1,287 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PROGRESS_BAR_H
+#define DALI_TOOLKIT_INTERNAL_PROGRESS_BAR_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali-toolkit/public-api/controls/progress-bar/progress-bar.h>
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ProgressBar;
+
+typedef Dali::IntrusivePtr< ProgressBar > ProgressBarPtr;
+
+/**
+ * @copydoc Toolkit::ProgressBar
+ */
+class ProgressBar : public Control
+{
+public:
+
+  /**
+   * Create a new ProgressBar.
+   *
+   * @return A public handle to the newly allocated ProgressBar.
+   */
+  static Dali::Toolkit::ProgressBar New();
+
+public:
+
+  // Properties
+
+  /**
+   * Set the value of the ProgressBar
+   *
+   * @param[in] value The value to set. Will be clamped to [lowerBound .. upperBound]
+   */
+  void SetProgressValue( float value );
+
+  /**
+   * Get the value of the ProgressBar
+   *
+   * @return The current value of the ProgressBar
+   */
+  float GetProgressValue() const;
+
+  /**
+   * Set the secondary progress value of the ProgressBar
+   *
+   * @param[in] value The secondary progress value to set. Will be clamped to [lowerBound .. upperBound]
+   */
+  void SetSecondaryProgressValue( float value );
+
+  /**
+   * Get the secondary progress value of the ProgressBar
+   *
+   * @return The current secondary progress value of the ProgressBar
+   */
+  float GetSecondaryProgressValue() const;
+
+  /**
+   * Set the indeterminate state of the ProgressBar
+   *
+   * @param[in] value The value to set.
+   */
+  void SetIndeterminate( bool value );
+
+  /**
+   * Get the indeterminate state value of the ProgressBar
+   *
+   * @return The current determined state of the ProgressBar
+   */
+  bool GetIndeterminate() const;
+
+  /**
+   * Set the indeterminate visual transition of the ProgressBar
+   *
+   * @param[in] Transition data map to set.
+   */
+  void SetIndeterminateVisualTransition( Property::Map transtion );
+
+  /**
+   * Get the indeterminate visual transition data map of the ProgressBar
+   *
+   * @return The current indeterminate visual transition data map of the ProgressBar
+   */
+  Property::Map GetIndeterminateVisualTransition() const;
+
+  /**
+   * Play the indeterminate visual transition
+   */
+  void PlayIndeterminateVisualTransition();
+
+public:
+  //Signals
+
+  /**
+   * @copydoc toolkit::progressbar::valuechangedsignal()
+   */
+  Toolkit::ProgressBar::ValueChangedSignalType& ValueChangedSignal();
+
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName,
+                               FunctorDelegate* functor );
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+protected:
+
+  /**
+   * Construct a new ProgressBar.
+   */
+  ProgressBar();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ProgressBar();
+
+  /**
+   * @copydoc CustomActorImpl::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc CustomActorImpl::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+private:
+
+  /**
+   * Domain is a from/to pair
+   */
+  struct Domain
+  {
+    Vector2 from;
+    Vector2 to;
+
+    Domain()
+    {
+    }
+    Domain( Vector2 fromVal, Vector2 toVal )
+        : from( fromVal ), to( toVal )
+    {
+    }
+  };
+
+private:
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * Get the range of the valid values the ProgressBar handle can move between
+   *
+   * @param[in] currentSize The current size of the ProgressBar
+   * @return The range as a domain pair
+   */
+  Domain CalcDomain( const Vector2& currentSize );
+
+  /**
+   * Set indeterminate visual transition animation
+   */
+  void SetIndeterminateVisualTransition( Toolkit::TransitionData transtion );
+
+  /**
+   * Convert value to transition data
+   */
+  Toolkit::TransitionData ConvertPropertyToTransition( const Property::Value& value );
+
+  /**
+   * Update progress bar label when progress value is changed
+   */
+  void CreateVisualsForComponent( Property::Index index, const Property::Value& value, const int visualDepth );
+
+  /**
+   * Update progress bar label when progress value is changed
+   */
+  bool GetPropertyMapForVisual( Property::Index visualIndex, Property::Map& retreivedMap ) const;
+
+  /**
+   * Check if we should start animating
+   */
+  virtual void OnStageConnection( int depth );
+
+private:
+
+  // Undefined
+  ProgressBar( const ProgressBar& );
+
+  // Undefined
+  ProgressBar& operator=( const ProgressBar& rhs );
+
+private:
+
+  Domain mDomain;                                                     ///< Current domain of the handle
+
+  Animation mIndeterminateVisualAni;                                  ///< Animation for indetrminate visual. Transition animation.
+  Toolkit::ProgressBar::ValueChangedSignalType mValueChangedSignal;   ///< Signal emitted when the value is changed
+
+  Toolkit::TransitionData mIndeterminateVisualTransition;             ///< Transition data map for mIndeterminateVisualAni
+  float mProgressValue;                                               ///< Current value of ProgressBar
+  float mSecondaryProgressValue;                                      ///< Current loading value of ProgressBar
+  bool mIndeterminate;                                                ///< Whether the progress state is determined or not
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ProgressBar& GetImpl( Toolkit::ProgressBar& pub )
+{
+  DALI_ASSERT_ALWAYS( pub );
+
+  Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast< Toolkit::Internal::ProgressBar& >( handle );
+}
+
+inline const Toolkit::Internal::ProgressBar& GetImpl( const Toolkit::ProgressBar& pub )
+{
+  DALI_ASSERT_ALWAYS( pub );
+
+  const Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast< const Toolkit::Internal::ProgressBar& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_PROGRESS_BAR_H
diff --git a/dali-toolkit/internal/controls/scene3d-view/gltf-loader.cpp b/dali-toolkit/internal/controls/scene3d-view/gltf-loader.cpp
new file mode 100644 (file)
index 0000000..291b95f
--- /dev/null
@@ -0,0 +1,1883 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/controls/scene3d-view/gltf-loader.h>
+#include <dali-toolkit/internal/controls/scene3d-view/gltf-shader.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace Gltf
+{
+
+namespace
+{
+
+// Utility functions
+const TreeNode* Tidx( const TreeNode *node, uint32_t index )
+{
+  uint32_t i = 0;
+  for( auto it = node->CBegin(), end = node->CEnd(); it != end; ++it, ++i )
+  {
+    if( i == index )
+    {
+      return &( ( *it ).second );
+    }
+  }
+  return NULL;
+}
+
+bool ReadBool( const TreeNode* node, bool& num )
+{
+  if( !node )
+  {
+    return false;
+  }
+  bool returnValue = false;
+
+  if( node->GetType() == TreeNode::BOOLEAN )
+  {
+    num = node->GetBoolean();
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadInt( const TreeNode* node, int32_t& num )
+{
+  if( !node )
+  {
+    return false;
+  }
+  bool returnValue = false;
+  if( node->GetType() == TreeNode::INTEGER )
+  {
+    num = node->GetInteger();
+    returnValue = true;
+  }
+  else  if( node->GetType() == TreeNode::FLOAT )
+  {
+    num = node->GetFloat();
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadFloat( const TreeNode* node, float& num )
+{
+  if( !node )
+  {
+    return false;
+  }
+  bool returnValue = false;
+
+  if( node->GetType() == TreeNode::FLOAT )
+  {
+    num = node->GetFloat();
+    returnValue = true;
+  }
+  else if( node->GetType() == TreeNode::INTEGER )
+  {
+    int32_t tempNum;
+    ReadInt( node, tempNum );
+    num = static_cast<float>( tempNum );
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadVector( const TreeNode* node, float* num, uint32_t size )
+{
+  if( !node )
+  {
+    return false;
+  }
+  bool returnValue = false;
+
+  if( ( node->Size() >= size ) && ( node->GetType() == TreeNode::ARRAY ) )
+  {
+    uint32_t offset = 0u;
+    for( auto it = node->CBegin(); offset < size; ++it, ++offset )
+    {
+      const TreeNode& coord = ( *it ).second;
+      if( !ReadFloat( &coord, *( num + offset ) ) )
+      {
+        return false;
+      }
+    }
+    returnValue = true;
+  }
+
+  return returnValue;
+}
+
+bool ReadString( const TreeNode* node, std::string& strValue )
+{
+  if( !node )
+  {
+    return false;
+  }
+  bool returnValue = false;
+  if( node->GetType() == TreeNode::STRING )
+  {
+    strValue = node->GetString();
+    returnValue = true;
+  }
+  return returnValue;
+}
+
+template <typename T>
+float IntToFloat( T element, bool normalize )
+{
+  if( !normalize )
+  {
+    return static_cast<float>( element );
+  }
+
+  if( std::is_same<T, int8_t>::value )
+  {
+    return std::max( static_cast<float>( element ) / 127.0, -1.0 );
+  }
+  if( std::is_same<T, uint8_t>::value )
+  {
+    return static_cast<float>( element ) / 255.0;
+  }
+  if( std::is_same<T, int16_t>::value )
+  {
+    return std::max( static_cast<float>( element ) / 32767.0, -1.0 );
+  }
+  if( std::is_same<T, uint16_t>::value )
+  {
+    return static_cast<float>( element ) / 65535.0;
+  }
+  return -1.0;
+}
+
+template <typename Td, typename Ts>
+void FitBuffer( Dali::Vector<Td>& bufferDestination, Dali::Vector<Ts>& bufferSource, int32_t bufferSize, int32_t elementNumOfByteStride, bool normalize )
+{
+  bufferDestination.Resize( bufferSize );
+  int32_t count = bufferSource.Size() / elementNumOfByteStride;
+  for( int32_t i = 0; i<count; ++i )
+  {
+    bufferDestination[i] = static_cast<Td>( bufferSource[i * elementNumOfByteStride] );
+  }
+}
+
+template <typename T>
+void FitBuffer( Dali::Vector<Vector2>& bufferDestination, Dali::Vector<T>& bufferSource, int32_t bufferSize, int32_t elementNumOfByteStride, bool normalize )
+{
+  bufferDestination.Resize( bufferSize );
+  int32_t count = bufferSource.Size() / elementNumOfByteStride;
+  for( int32_t i = 0; i<count; ++i )
+  {
+    bufferDestination[i].x = IntToFloat( bufferSource[i * elementNumOfByteStride], normalize );
+    bufferDestination[i].y = IntToFloat( bufferSource[i * elementNumOfByteStride + 1], normalize );
+  }
+}
+
+template <typename T>
+void FitBuffer( Dali::Vector<Vector3>& bufferDestination, Dali::Vector<T>& bufferSource, int32_t bufferSize, int32_t elementNumOfByteStride, bool normalize )
+{
+  bufferDestination.Resize( bufferSize );
+  int32_t count = bufferSource.Size() / elementNumOfByteStride;
+  for( int32_t i = 0; i<count; ++i )
+  {
+    bufferDestination[i].x = IntToFloat( bufferSource[i * elementNumOfByteStride], normalize );
+    bufferDestination[i].y = IntToFloat( bufferSource[i * elementNumOfByteStride + 1], normalize );
+    bufferDestination[i].z = IntToFloat( bufferSource[i * elementNumOfByteStride + 2], normalize );
+  }
+}
+
+template <typename T>
+void FitBuffer( Dali::Vector<Vector4>& bufferDestination, Dali::Vector<T>& bufferSource, int32_t bufferSize, int32_t elementNumOfByteStride, bool normalize )
+{
+  bufferDestination.Resize( bufferSize );
+  int32_t count = bufferSource.Size() / elementNumOfByteStride;
+  for( int32_t i = 0; i<count; ++i )
+  {
+    bufferDestination[i].x = IntToFloat( bufferSource[i * elementNumOfByteStride], normalize );
+    bufferDestination[i].y = IntToFloat( bufferSource[i * elementNumOfByteStride + 1], normalize );
+    bufferDestination[i].z = IntToFloat( bufferSource[i * elementNumOfByteStride + 2], normalize );
+    bufferDestination[i].w = IntToFloat( bufferSource[i * elementNumOfByteStride + 3], normalize );
+  }
+}
+
+// Template functions
+template <typename T>
+bool ReadBinFile( Vector<T> &dataBuffer, std::string url, int32_t offset, int32_t count )
+{
+  Dali::FileStream fileStream( url, FileStream::READ | FileStream::BINARY );
+  FILE* fp = fileStream.GetFile();
+  if( !fp )
+  {
+    return false;
+  }
+
+  dataBuffer.Resize( count );
+  ssize_t result = -1;
+  if( !fseek( fp, offset, SEEK_SET ) )
+  {
+    result = fread( &dataBuffer[0], sizeof( T ), count, fp );
+  }
+
+  return ( result >= 0 );
+}
+
+template <typename T>
+void LoadDataFromAccessor( int32_t accessorIdx, Dali::Vector<T>& bufferData, std::string path, std::vector<AccessorInfo>& accessorArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<BufferInfo>& bufferArray )
+{
+  AccessorInfo accessor = accessorArray[accessorIdx];
+  BufferViewInfo bufferView = bufferViewArray[accessor.bufferView];
+  std::string load_uri = bufferArray[bufferView.buffer].uri;
+
+  // In the glTF 2.0 Specification, 5121 is UNSIGNED BYTE, 5123 is UNSIGNED SHORT
+  int32_t elementByteSize = ( accessor.componentType <= 5121 ) ? 1 :
+    ( ( accessor.componentType <= 5123 ) ? 2 : 4 );
+  int32_t elementNum = 1;
+  if( accessor.type == "VEC2" )
+  {
+    elementNum = 2;
+  }
+  else if( accessor.type == "VEC3" )
+  {
+    elementNum = 3;
+  }
+  else if( accessor.type == "VEC4" || accessor.type == "MAT2" )
+  {
+    elementNum = 4;
+  }
+  else if( accessor.type == "MAT3" )
+  {
+    elementNum = 9;
+  }
+  else if( accessor.type == "MAT4" )
+  {
+    elementNum = 16;
+  }
+  else
+  {
+    elementNum = 1;
+  }
+  int32_t elementNumOfByteStride = elementNum;
+  if( bufferView.byteStride > 0 )
+  {
+    elementNumOfByteStride = bufferView.byteStride / elementByteSize;
+  }
+
+  /**
+   * glTF 2.0 Specification
+   * Component Type
+   * 5120 : BYTE
+   * 5121 : UNSIGNED_BYTE
+   * 5122 : SHORT
+   * 5123 : UNSIGNED_SHORT
+   * 5125 : UNSIGNED_INT
+   * 5126 : FLOAT
+   */
+  if( accessor.componentType == 5120 )
+  {
+    Dali::Vector<int8_t> inputBufferData;
+    ReadBinFile<int8_t>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+  else if( accessor.componentType == 5121 )
+  {
+    Dali::Vector<uint8_t> inputBufferData;
+    ReadBinFile<uint8_t>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+  else if( accessor.componentType == 5122 )
+  {
+    Dali::Vector<int16_t> inputBufferData;
+    ReadBinFile<int16_t>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+  else if( accessor.componentType == 5123 )
+  {
+    Dali::Vector<uint16_t> inputBufferData;
+    ReadBinFile<uint16_t>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+  else if( accessor.componentType == 5125 )
+  {
+    Dali::Vector<uint32_t> inputBufferData;
+    ReadBinFile<uint32_t>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+  else if( accessor.componentType == 5126 )
+  {
+    Dali::Vector<float> inputBufferData;
+    ReadBinFile<float>( inputBufferData, path + load_uri, bufferView.byteOffset + accessor.byteOffset, elementNumOfByteStride * accessor.count );
+    FitBuffer( bufferData, inputBufferData, accessor.count, elementNumOfByteStride, accessor.normalized );
+  }
+}
+
+void SetMeshInfoAndCanonize( MeshInfo& meshInfo, Dali::Vector<Dali::Vector3> &vertexBufferData )
+{
+  Vector3 pointMin( std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max() );
+  Vector3 pointMax( std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min() );
+  for( auto&& data : vertexBufferData )
+  {
+    pointMin.x = std::min( data.x, pointMin.x );
+    pointMin.y = std::min( data.y, pointMin.y );
+    pointMin.z = std::min( data.z, pointMin.z );
+
+    pointMax.x = std::max( data.x, pointMax.x );
+    pointMax.y = std::max( data.y, pointMax.y );
+    pointMax.z = std::max( data.z, pointMax.z );
+  }
+  meshInfo.size = pointMax - pointMin;
+  meshInfo.pivot.x = ( -pointMin.x ) / ( pointMax.x - pointMin.x );
+  meshInfo.pivot.y = ( -pointMin.y ) / ( pointMax.y - pointMin.y );
+  meshInfo.pivot.z = ( -pointMin.z ) / ( pointMax.z - pointMin.z );
+
+  Vector3 center = meshInfo.size * 0.5 + pointMin;
+  for( auto&& data : vertexBufferData )
+  {
+    data   = data - center;
+    data.x = data.x / meshInfo.size.x;
+    data.y = data.y / meshInfo.size.y;
+    data.z = data.z / meshInfo.size.z;
+  }
+}
+
+template <typename T>
+PropertyBuffer CreatePropertyBuffer( Vector<T> bufferData, std::string map, int32_t type )
+{
+  Property::Map positionMap;
+  positionMap[map] = type;
+
+  PropertyBuffer propertyBuffer = PropertyBuffer::New( positionMap );
+  propertyBuffer.SetData( bufferData.Begin(), bufferData.Count() );
+  return propertyBuffer;
+}
+
+void SetVertexBufferData( MeshInfo& meshInfo, std::string path, std::vector<AccessorInfo>& accessorArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<BufferInfo>& bufferArray, int32_t accessorIdx, std::string map, int32_t type )
+{
+  if( accessorIdx >= 0 )
+  {
+    Dali::Vector<Vector3> bufferData;
+    LoadDataFromAccessor( accessorIdx, bufferData, path, accessorArray, bufferViewArray, bufferArray );
+    SetMeshInfoAndCanonize( meshInfo, bufferData );
+
+    PropertyBuffer propertyBuffer = CreatePropertyBuffer<Vector3>( bufferData, map, type );
+    meshInfo.geometry.AddVertexBuffer( propertyBuffer );
+  }
+}
+
+template <typename T>
+void SetAttributeBufferData( MeshInfo& meshInfo, std::string path, std::vector<AccessorInfo>& accessorArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<BufferInfo>& bufferArray, int32_t accessorIdx, std::string map, int32_t type )
+{
+  if( accessorIdx >= 0 )
+  {
+    Dali::Vector<T> bufferData;
+    LoadDataFromAccessor( accessorIdx, bufferData, path, accessorArray, bufferViewArray, bufferArray );
+
+    PropertyBuffer propertyBuffer = CreatePropertyBuffer<T>( bufferData, map, type );
+    meshInfo.geometry.AddVertexBuffer( propertyBuffer );
+  }
+}
+
+void SetIndexBuffersData( MeshInfo& meshInfo, std::string path, std::vector<AccessorInfo>& accessorArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<BufferInfo>& bufferArray, int32_t indexIdx )
+{
+  Dali::Vector<uint16_t> indexBufferData;
+  LoadDataFromAccessor( indexIdx, indexBufferData, path, accessorArray, bufferViewArray, bufferArray );
+  meshInfo.geometry.SetIndexBuffer( &indexBufferData[0], indexBufferData.Size() );
+}
+
+template<typename T>
+float LoadKeyFrames( const AnimationSamplerInfo& currentSampler, const Property::Index propIndex, KeyFrames& keyframes, std::string path, std::vector<AccessorInfo>& accessorArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<BufferInfo>& bufferArray )
+{
+  Dali::Vector<float> inputBufferData;
+  Dali::Vector<T> outputBufferData;
+
+  LoadDataFromAccessor<float>( currentSampler.input, inputBufferData, path, accessorArray, bufferViewArray, bufferArray );
+  LoadDataFromAccessor<T>( currentSampler.output, outputBufferData, path, accessorArray, bufferViewArray, bufferArray );
+
+  uint32_t keyframeNum = inputBufferData.Size();
+  float lengthAnimation = inputBufferData[inputBufferData.Size() - 1];
+  for( uint32_t i = 0; i < keyframeNum; i++ )
+  {
+    if( propIndex == Dali::Actor::Property::ORIENTATION )
+    {
+      Vector4 vectorOrientation( outputBufferData[i] );
+      float vW = vectorOrientation.w;
+      vW = ( vW < 0.0f ) ? std::max( vW, -1.0f ) : std::min( vW, 1.0f );
+      vectorOrientation.w = vW;
+      keyframes.Add( inputBufferData[i] / lengthAnimation, Quaternion( Vector4( vectorOrientation ) ) );
+    }
+    else if( propIndex == Dali::Actor::Property::POSITION )
+    {
+      keyframes.Add( inputBufferData[i] / lengthAnimation, Vector3( outputBufferData[i] ) );
+    }
+    else if( propIndex == Dali::Actor::Property::SCALE )
+    {
+      keyframes.Add( inputBufferData[i] / lengthAnimation, Vector3( outputBufferData[i] ) );
+    }
+  }
+  return lengthAnimation;
+}
+
+bool LoadBuffer( const TreeNode& buffer, std::vector<BufferInfo>& bufferArray )
+{
+  BufferInfo bufferInfo;
+
+  const TreeNode* uriNode = buffer.GetChild( "uri" );
+  if( uriNode )
+  {
+    ReadString( uriNode, bufferInfo.uri );
+  }
+
+  const TreeNode* byteLengthNode = buffer.GetChild( "byteLength" );
+  if( byteLengthNode )
+  {
+    ReadInt( byteLengthNode, bufferInfo.byteLength );
+    if( bufferInfo.byteLength < 0 )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* nameNode = buffer.GetChild( "name" );
+  if( nameNode )
+  {
+    ReadString( nameNode, bufferInfo.name );
+  }
+
+  bufferArray.push_back( bufferInfo );
+
+  return true;
+}
+
+bool LoadBufferView( const TreeNode& buffer, std::vector<BufferViewInfo>& bufferViewArray )
+{
+  BufferViewInfo bufferViewInfo;
+
+  const TreeNode* bufferNode = buffer.GetChild( "buffer" );
+  if( bufferNode )
+  {
+    ReadInt( bufferNode, bufferViewInfo.buffer );
+    if( bufferViewInfo.buffer < 0 )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* byteOffsetNode = buffer.GetChild( "byteOffset" );
+  if( byteOffsetNode )
+  {
+    ReadInt( byteOffsetNode, bufferViewInfo.byteOffset );
+  }
+
+  const TreeNode* byteLengthNode = buffer.GetChild( "byteLength" );
+  if( byteLengthNode )
+  {
+    ReadInt( byteLengthNode, bufferViewInfo.byteLength );
+    if( bufferViewInfo.byteLength < 0 )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* byteStrideNode = buffer.GetChild( "byteStride" );
+  if( byteStrideNode )
+  {
+    ReadInt( byteStrideNode, bufferViewInfo.byteStride );
+  }
+
+  const TreeNode* targetNode = buffer.GetChild( "target" );
+  if( targetNode )
+  {
+    ReadInt( targetNode, bufferViewInfo.target );
+  }
+
+  const TreeNode* nameNode = buffer.GetChild( "name" );
+  if( nameNode )
+  {
+    ReadString( nameNode, bufferViewInfo.name );
+  }
+
+  bufferViewArray.push_back( bufferViewInfo );
+
+  return true;
+}
+
+bool LoadAccessor( const TreeNode& buffer, std::vector<AccessorInfo>& accessorArray )
+{
+  AccessorInfo accessorInfo;
+
+  const TreeNode* bufferViewNode = buffer.GetChild( "bufferView" );
+  if( bufferViewNode )
+  {
+    ReadInt( bufferViewNode, accessorInfo.bufferView );
+  }
+
+  const TreeNode* byteOffsetNode = buffer.GetChild( "byteOffset" );
+  if( byteOffsetNode )
+  {
+    ReadInt( byteOffsetNode, accessorInfo.byteOffset );
+  }
+
+  const TreeNode* componentTypeNode = buffer.GetChild( "componentType" );
+  if( componentTypeNode )
+  {
+    ReadInt( componentTypeNode, accessorInfo.componentType );
+    if( accessorInfo.componentType < 0 )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* normalizedNode = buffer.GetChild( "normalized" );
+  if( normalizedNode )
+  {
+    ReadBool( normalizedNode, accessorInfo.normalized );
+  }
+
+  const TreeNode* countNode = buffer.GetChild( "count" );
+  if( countNode )
+  {
+    ReadInt( countNode, accessorInfo.count );
+    if( accessorInfo.count < 0 )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* typeNode = buffer.GetChild( "type" );
+  if( typeNode )
+  {
+    ReadString( typeNode, accessorInfo.type );
+    if( accessorInfo.type == "" )
+    {
+      return false;
+    }
+  }
+
+  const TreeNode* maxNode = buffer.GetChild( "max" );
+  if( maxNode )
+  {
+    ReadInt( maxNode, accessorInfo.max );
+  }
+
+  const TreeNode* minNode = buffer.GetChild( "min" );
+  if( minNode )
+  {
+    ReadInt( minNode, accessorInfo.min );
+  }
+
+  const TreeNode* nameNode = buffer.GetChild( "name" );
+  if( nameNode )
+  {
+    ReadString( nameNode, accessorInfo.name );
+  }
+
+  accessorArray.push_back( accessorInfo );
+
+  return true;
+}
+
+bool LoadBinaryData( const TreeNode& root, std::vector<BufferInfo>& bufferArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<AccessorInfo>& accessorArray )
+{
+  const TreeNode* buffersNode = root.GetChild( "buffers" );
+  if( !buffersNode )
+  {
+    return false;
+  }
+  for( auto bufferIter = buffersNode->CBegin(), end = buffersNode->CEnd(); bufferIter != end; ++bufferIter )
+  {
+    LoadBuffer( ( *bufferIter ).second, bufferArray );
+  }
+
+  const TreeNode* bufferViewsNode = root.GetChild( "bufferViews" );
+  if( !bufferViewsNode )
+  {
+    return false;
+  }
+  for( auto bufferViewIter = bufferViewsNode->CBegin(), end = bufferViewsNode->CEnd(); bufferViewIter != end; ++bufferViewIter )
+  {
+    LoadBufferView( ( *bufferViewIter ).second, bufferViewArray );
+  }
+
+  const TreeNode* accessorsNode = root.GetChild( "accessors" );
+  if( !accessorsNode )
+  {
+    return false;
+  }
+  for( auto accesorIter = accessorsNode->CBegin(), end = accessorsNode->CEnd(); accesorIter != end; ++accesorIter )
+  {
+    LoadAccessor( ( *accesorIter ).second, accessorArray );
+  }
+
+  return true;
+}
+
+FilterMode::Type GetFilterMode( uint32_t mode )
+{
+  FilterMode::Type retValue = FilterMode::DEFAULT;
+  /**
+   * glTF 2.0 Specification
+   * Filter Code
+   * 9728 : NEAREST
+   * 9729 : LINEAR
+   * 9984 : NEAREST_MIPMAP_NEAREST
+   * 9985 : LINEAR_MIPMAP_NEAREST
+   * 9986 : NEAREST_MIPMAP_LINEAR
+   * 9987 : LINEAR_MIPMAP_LINEAR
+   */
+  switch( mode )
+  {
+    case 9728:
+    {
+      retValue = FilterMode::NEAREST;
+      break;
+    }
+    case 9729:
+    {
+      retValue = FilterMode::LINEAR;
+      break;
+    }
+    case 9984:
+    {
+      retValue = FilterMode::NEAREST_MIPMAP_NEAREST;
+      break;
+    }
+    case 9985:
+    {
+      retValue = FilterMode::LINEAR_MIPMAP_NEAREST;
+      break;
+    }
+    case 9986:
+    {
+      retValue = FilterMode::NEAREST_MIPMAP_LINEAR;
+      break;
+    }
+    case 9987:
+    {
+      retValue = FilterMode::LINEAR_MIPMAP_LINEAR;
+      break;
+    }
+  }
+
+  return retValue;
+}
+
+WrapMode::Type GetWrapMode( uint32_t mode )
+{
+  WrapMode::Type retValue = WrapMode::REPEAT;
+  /**
+   * glTF 2.0 Specification
+   * Wrapping mode Code
+   * 33071 : CLAMP_TO_EDGE
+   * 33648 : MIRRORED_REPEAT
+   * 10497 : REPEAT
+   */
+  switch( mode )
+  {
+    case 33071:
+    {
+      retValue = WrapMode::CLAMP_TO_EDGE;
+      break;
+    }
+    case 33648:
+    {
+      retValue = WrapMode::MIRRORED_REPEAT;
+      break;
+    }
+    case 10497:
+    {
+      retValue = WrapMode::REPEAT;
+      break;
+    }
+  }
+
+  return retValue;
+}
+
+Texture LoadTexture( const char* imageUrl, bool generateMipmaps )
+{
+  Texture texture;
+  Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
+  if( pixelBuffer )
+  {
+    texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+    PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+    texture.Upload( pixelData );
+
+    if( generateMipmaps )
+    {
+      texture.GenerateMipmaps();
+    }
+  }
+
+  return texture;
+}
+
+Sampler LoadSampler( const TreeNode& samplerNode )
+{
+  Sampler sampler = Sampler::New();
+
+  FilterMode::Type minFilter = FilterMode::DEFAULT;
+  FilterMode::Type magFilter = FilterMode::DEFAULT;
+  const TreeNode* magFilterNode = samplerNode.GetChild( "magFilter" );
+  if( magFilterNode )
+  {
+    int32_t magFilter_integer = 0;
+    ReadInt( magFilterNode, magFilter_integer );
+    magFilter = GetFilterMode( magFilter_integer );
+  }
+
+  const TreeNode* minFilterNode = samplerNode.GetChild( "minFilter" );
+  if( minFilterNode )
+  {
+    int32_t minFilter_integer = 0;
+    ReadInt( minFilterNode, minFilter_integer );
+    minFilter = GetFilterMode( minFilter_integer );
+  }
+
+  WrapMode::Type wrapR = WrapMode::REPEAT;
+  WrapMode::Type wrapS = WrapMode::REPEAT;
+  WrapMode::Type wrapT = WrapMode::REPEAT;
+  const TreeNode* wrapNode = samplerNode.GetChild( "wrapS" );
+  if( wrapNode )
+  {
+    wrapS = GetWrapMode( wrapNode->GetInteger() );
+  }
+
+  wrapNode = samplerNode.GetChild( "wrapT" );
+  if( wrapNode )
+  {
+    wrapT = GetWrapMode( wrapNode->GetInteger() );
+  }
+
+  sampler.SetFilterMode( minFilter, magFilter );
+  sampler.SetWrapMode( wrapR, wrapS, wrapT );
+
+  return sampler;
+}
+
+bool LoadTextureArray( const TreeNode& root, std::string path, std::vector<Texture>& sourceArray, std::vector<Sampler>& samplerArray, std::vector<TextureInfo>& textureArray )
+{
+  const TreeNode* imagesNode = root.GetChild( "images" );
+  if( imagesNode )
+  {
+    for( auto imageIter = imagesNode->CBegin(), end = imagesNode->CEnd(); imageIter != end; ++imageIter )
+    {
+      std::string imageUrl;
+      const TreeNode* uriNode = ( &( ( *imageIter ).second ) )->GetChild( "uri" );
+      if( uriNode )
+      {
+        std::string uri;
+        ReadString( uriNode, uri );
+        imageUrl = path + uri;
+      }
+
+      sourceArray.push_back( LoadTexture( imageUrl.c_str(), true ) );
+    }
+  }
+
+  const TreeNode* samplersNode = root.GetChild( "samplers" );
+  if( samplersNode )
+  {
+    for( auto samplerIter = samplersNode->CBegin(), end = samplersNode->CEnd(); samplerIter != end; ++samplerIter )
+    {
+      samplerArray.push_back( LoadSampler( ( ( *samplerIter ).second ) ) );
+    }
+  }
+
+  const TreeNode* texturesNode = root.GetChild( "textures" );
+  if( texturesNode )
+  {
+    for( auto textureIter = texturesNode->CBegin(), end = texturesNode->CEnd(); textureIter != end; ++textureIter )
+    {
+      const TreeNode* TextureNode = &( ( *textureIter ).second );
+
+      TextureInfo texture;
+      const TreeNode* sourceNode = TextureNode->GetChild( "source" );
+      if( sourceNode )
+      {
+        ReadInt( sourceNode, texture.sourceIdx );
+      }
+
+      const TreeNode* samplerNode = TextureNode->GetChild( "sampler" );
+      if( samplerNode )
+      {
+        ReadInt( samplerNode, texture.samplerIdx );
+      }
+
+      textureArray.push_back( texture );
+    }
+  }
+  return true;
+}
+
+bool LoadPbrMetallicRoughness( const TreeNode& material, MaterialInfo& materialInfo )
+{
+  float floatVec[4];
+  const TreeNode* pbrMetallicRoughnessNode = material.GetChild( "pbrMetallicRoughness" );
+  if( !pbrMetallicRoughnessNode )
+  {
+    return true;
+  }
+
+  const TreeNode* tempNode;
+  tempNode = pbrMetallicRoughnessNode->GetChild( "metallicFactor" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, materialInfo.metallicFactor );
+  }
+
+  tempNode = pbrMetallicRoughnessNode->GetChild( "roughnessFactor" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, materialInfo.roughnessFactor );
+  }
+
+  tempNode = pbrMetallicRoughnessNode->GetChild( "baseColorFactor" );
+  if( tempNode && ReadVector( tempNode, floatVec, 4 ) )
+  {
+    materialInfo.baseColorFactor = Vector4( floatVec[0], floatVec[1], floatVec[2], floatVec[3] );
+  }
+
+  const TreeNode* baseColorTextureNode = pbrMetallicRoughnessNode->GetChild( "baseColorTexture" );
+  if( baseColorTextureNode )
+  {
+    tempNode = baseColorTextureNode->GetChild( "index" );
+    if( tempNode )
+    {
+      materialInfo.baseColorTexture.index = tempNode->GetInteger();
+    }
+
+    tempNode = baseColorTextureNode->GetChild( "texCoord" );
+    if( tempNode )
+    {
+      materialInfo.baseColorTexture.texCoord = tempNode->GetInteger();
+    }
+  }
+
+  const TreeNode* metallicRoughnessTextureNode = pbrMetallicRoughnessNode->GetChild( "metallicRoughnessTexture" );
+  if( metallicRoughnessTextureNode )
+  {
+    tempNode = metallicRoughnessTextureNode->GetChild( "index" );
+    if( tempNode )
+    {
+      materialInfo.metallicRoughnessTexture.index = tempNode->GetInteger();
+    }
+
+    tempNode = metallicRoughnessTextureNode->GetChild( "texCoord" );
+    if( tempNode )
+    {
+      materialInfo.metallicRoughnessTexture.texCoord = tempNode->GetInteger();
+    }
+  }
+
+  return true;
+}
+
+bool LoadMaterialSetArray( const TreeNode& root, std::vector<MaterialInfo>& materialArray )
+{
+  const TreeNode* materialsNode = root.GetChild( "materials" );
+  if( !materialsNode )
+  {
+    return false;
+  }
+
+  for( auto materialIter = materialsNode->CBegin(), end = materialsNode->CEnd(); materialIter != end; ++materialIter )
+  {
+    MaterialInfo materialInfo;
+    LoadPbrMetallicRoughness( ( ( *materialIter ).second ), materialInfo );
+
+    const TreeNode* materialNode = &( ( *materialIter ).second );
+    const TreeNode* tempNode = materialNode->GetChild( "name" );
+    if( tempNode )
+    {
+      ReadString( tempNode, materialInfo.name );
+    }
+
+    materialInfo.alphaMode = "OPAQUE";
+    tempNode = materialNode->GetChild( "alphaMode" );
+    if( tempNode )
+    {
+      ReadString( tempNode, materialInfo.alphaMode );
+    }
+
+    materialInfo.alphaCutoff = 1.0;
+    tempNode = materialNode->GetChild( "alphaCutoff" );
+    if( tempNode )
+    {
+      ReadFloat( tempNode, materialInfo.alphaCutoff );
+    }
+
+    materialInfo.doubleSided = false;
+    tempNode = materialNode->GetChild( "doubleSided" );
+    if( tempNode )
+    {
+      ReadBool( tempNode, materialInfo.doubleSided );
+    }
+
+    float floatVec[3];
+    tempNode = materialNode->GetChild( "emissiveFactor" );
+    if( tempNode && ReadVector( tempNode, floatVec, 3 ) )
+    {
+      materialInfo.emissiveFactor = Vector3( floatVec[0], floatVec[1], floatVec[2] );
+    }
+
+    const TreeNode* texture = materialNode->GetChild( "normalTexture" );
+    if( texture )
+    {
+      tempNode = texture->GetChild( "index" );
+      if( tempNode )
+      {
+        materialInfo.normalTexture.index = tempNode->GetInteger();
+      }
+
+      tempNode = texture->GetChild( "texCoord" );
+      if( tempNode )
+      {
+        materialInfo.normalTexture.texCoord = tempNode->GetInteger();
+      }
+
+      materialInfo.normalTexture.value = 1.0;
+      tempNode = texture->GetChild( "scale" );
+      if( tempNode )
+      {
+        ReadFloat( tempNode, materialInfo.normalTexture.value );
+      }
+    }
+
+    texture = materialNode->GetChild( "occlusionTexture" );
+    if( texture )
+    {
+      tempNode = texture->GetChild( "index" );
+      if( tempNode )
+      {
+        materialInfo.occlusionTexture.index = tempNode->GetInteger();
+      }
+
+      tempNode = texture->GetChild( "texCoord" );
+      if( tempNode )
+      {
+        materialInfo.occlusionTexture.texCoord = tempNode->GetInteger();
+      }
+
+
+      tempNode = texture->GetChild( "strength" );
+      if( tempNode )
+      {
+        ReadFloat( tempNode, materialInfo.occlusionTexture.value );
+      }
+    }
+
+    texture = materialNode->GetChild( "emissiveTexture" );
+    if( texture )
+    {
+      tempNode = texture->GetChild( "index" );
+      if( tempNode )
+      {
+        materialInfo.emissiveTexture.index = tempNode->GetInteger();
+      }
+
+      tempNode = texture->GetChild( "texCoord" );
+      if( tempNode )
+      {
+        materialInfo.emissiveTexture.texCoord = tempNode->GetInteger();
+      }
+    }
+    materialArray.push_back( materialInfo );
+  }
+  return true;
+}
+
+bool LoadAttribute( const TreeNode* primitive, MeshInfo& meshInfo )
+{
+  const TreeNode* attrbuteNode = primitive->GetChild( "attributes" );
+  if( !attrbuteNode )
+  {
+    return false;
+  }
+
+  const TreeNode* tempNode;
+  tempNode = attrbuteNode->GetChild( "POSITION" );
+  if( tempNode )
+  {
+    meshInfo.attribute.POSITION = tempNode->GetInteger();
+  }
+
+  tempNode = attrbuteNode->GetChild( "NORMAL" );
+  if( tempNode )
+  {
+    meshInfo.attribute.NORMAL = tempNode->GetInteger();
+  }
+
+  tempNode = attrbuteNode->GetChild( "TANGENT" );
+  if( tempNode )
+  {
+    meshInfo.attribute.TANGENT = tempNode->GetInteger();
+  }
+
+  uint32_t index = 0;
+  meshInfo.attribute.TEXCOORD.clear();
+  tempNode = attrbuteNode->GetChild( "TEXCOORD_" + std::to_string( index ) );
+  while( tempNode )
+  {
+    uint32_t value = tempNode->GetInteger();
+    meshInfo.attribute.TEXCOORD.push_back( value );
+    tempNode = attrbuteNode->GetChild( "TEXCOORD_" + std::to_string( ++index ) );
+  }
+
+  index = 0;
+  meshInfo.attribute.COLOR.clear();
+  tempNode = attrbuteNode->GetChild( "COLOR_" + std::to_string( index ) );
+  while( tempNode )
+  {
+    uint32_t value = tempNode->GetInteger();
+    meshInfo.attribute.COLOR.push_back( value );
+    tempNode = attrbuteNode->GetChild( "COLOR" + std::to_string( ++index ) );
+  }
+
+  return true;
+}
+
+bool LoadPrimitive( const TreeNode& mesh, MeshInfo& meshInfo )
+{
+  const TreeNode* primitivesNode = mesh.GetChild( "primitives" );
+  if( !primitivesNode )
+  {
+    return false;
+  }
+
+  for( auto primitiveIter = primitivesNode->CBegin(), end = primitivesNode->CEnd(); primitiveIter != end; ++primitiveIter )
+  {
+    const TreeNode* primitiveNode = ( &( *primitiveIter ).second );
+    const TreeNode* tempNode;
+
+    tempNode = primitiveNode->GetChild( "indices" );
+    if( tempNode )
+    {
+      meshInfo.indicesIdx = tempNode->GetInteger();
+    }
+
+    tempNode = primitiveNode->GetChild( "material" );
+    if( tempNode )
+    {
+      meshInfo.materialsIdx = tempNode->GetInteger();
+    }
+
+    tempNode = primitiveNode->GetChild( "mode" );
+    if( tempNode )
+    {
+      meshInfo.mode = tempNode->GetInteger();
+    }
+
+    LoadAttribute( primitiveNode, meshInfo );
+  }
+
+  return true;
+}
+
+bool SetGeometry( MeshInfo& meshInfo, std::string path, std::vector<BufferInfo>& bufferArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<AccessorInfo>& accessorArray )
+{
+  int32_t indicesIdx = meshInfo.indicesIdx;
+
+  if( meshInfo.mode != 0 )
+  {
+    meshInfo.geometry.SetType( ( Dali::Geometry::Type )meshInfo.mode );
+  }
+
+  if( indicesIdx >= 0 )
+  {
+    SetIndexBuffersData( meshInfo, path, accessorArray, bufferViewArray, bufferArray, indicesIdx );
+  }
+
+  SetVertexBufferData( meshInfo, path, accessorArray, bufferViewArray, bufferArray, meshInfo.attribute.POSITION, "aPosition", Property::VECTOR3 );
+  SetAttributeBufferData<Vector3>( meshInfo, path, accessorArray, bufferViewArray, bufferArray, meshInfo.attribute.NORMAL, "aNormal", Property::VECTOR3 );
+  SetAttributeBufferData<Vector4>( meshInfo, path, accessorArray, bufferViewArray, bufferArray, meshInfo.attribute.TANGENT, "aTangent", Property::VECTOR4 );
+
+  for( uint32_t i = 0; i < meshInfo.attribute.TEXCOORD.size(); ++i )
+  {
+    int32_t accessorIdx = meshInfo.attribute.TEXCOORD[i];
+    std::ostringstream texCoordString;
+    texCoordString << "aTexCoord" << i;
+    SetAttributeBufferData<Vector2>( meshInfo, path, accessorArray, bufferViewArray, bufferArray, accessorIdx, texCoordString.str(), Property::VECTOR2 );
+  }
+
+  for( auto&& accessorIdx : meshInfo.attribute.COLOR )
+  {
+    if( accessorIdx < 0 )
+    {
+      break;
+    }
+
+    if( accessorArray[accessorIdx].type == "VEC3" )
+    {
+      Dali::Vector<Vector3> inputBufferData;
+      LoadDataFromAccessor( accessorIdx, inputBufferData, path, accessorArray, bufferViewArray, bufferArray );
+
+      Dali::Vector<Vector4> bufferData;
+      bufferData.Resize( inputBufferData.Size() );
+      for( uint32_t i = 0; i<inputBufferData.Size(); ++i )
+      {
+        bufferData[i].x = inputBufferData[i].x;
+        bufferData[i].y = inputBufferData[i].y;
+        bufferData[i].z = inputBufferData[i].z;
+        bufferData[i].w = 1.0;
+      }
+      PropertyBuffer propertyBuffer = CreatePropertyBuffer<Vector4>( bufferData, "aVertexColor", Property::VECTOR4 );
+      meshInfo.geometry.AddVertexBuffer( propertyBuffer );
+    }
+    else if( accessorArray[accessorIdx].type == "VEC4" )
+    {
+      SetAttributeBufferData<Vector4>( meshInfo, path, accessorArray, bufferViewArray, bufferArray, accessorIdx, "aVertexColor", Property::VECTOR4 );
+    }
+  }
+  return true;
+}
+
+bool LoadMeshArray( const TreeNode& root, std::string path, std::vector<MeshInfo>& meshArray, std::vector<BufferInfo>& bufferArray, std::vector<BufferViewInfo>& bufferViewArray, std::vector<AccessorInfo>& accessorArray )
+{
+  const TreeNode* meshesNode = root.GetChild( "meshes" );
+  if( !meshesNode )
+  {
+    return false;
+  }
+
+  for( auto meshIter = meshesNode->CBegin(), end = meshesNode->CEnd(); meshIter != end; ++meshIter )
+  {
+    MeshInfo meshInfo;
+    const TreeNode* nameNode = ( &( *meshIter ).second )->GetChild( "name" );
+    if( nameNode )
+    {
+      ReadString( nameNode, meshInfo.name );
+    }
+    meshInfo.geometry = Geometry::New();
+
+    //Need to add weights for Morph targets.
+    LoadPrimitive( ( *meshIter ).second, meshInfo );
+    SetGeometry( meshInfo, path, bufferArray, bufferViewArray, accessorArray );
+    meshArray.push_back( meshInfo );
+  }
+
+  return true;
+}
+
+} // namespace
+
+Loader::Loader()
+  : mNodes( NULL ),
+  mRoot( NULL )
+{
+}
+
+Loader::~Loader()
+{
+}
+
+bool Loader::LoadScene( const std::string& filePath, Internal::Scene3dView& scene3dView )
+{
+  // Extracting directory path from full path to load resources.
+  if( std::string::npos != filePath.rfind('/') )
+  {
+    mPath = filePath.substr( 0, filePath.rfind('/') ) + "/";
+  }
+
+  if( !ParseGltf( filePath ) )
+  {
+    DALI_LOG_ERROR( "Fail to parse json file\n" );
+    return false;
+  }
+
+  mRoot = mParser.GetRoot();
+  if( mRoot &&
+      LoadAssets() &&
+      CreateScene( scene3dView ) )
+  {
+    return true;
+  }
+  return false;
+}
+
+bool Loader::ParseGltf( const std::string& filePath )
+{
+  std::streampos bufferSize = 0;
+  Dali::Vector<char> buffer;
+  std::string fileBuffer;
+  if( !Dali::FileLoader::ReadFile( filePath, bufferSize, buffer, FileLoader::FileType::BINARY ) )
+  {
+    return false;
+  }
+
+  fileBuffer.assign( &buffer[0], bufferSize );
+  mParser = Dali::Toolkit::JsonParser::New();
+  return mParser.Parse( fileBuffer );
+}
+
+bool Loader::LoadAssets()
+{
+  if( LoadBinaryData( *mRoot, mBufferArray, mBufferViewArray, mAccessorArray ) &&
+      LoadTextureArray( *mRoot, mPath, mSourceArray, mSamplerArray, mTextureArray ) &&
+      LoadMaterialSetArray( *mRoot, mMaterialArray ) &&
+      LoadMeshArray( *mRoot, mPath, mMeshArray, mBufferArray, mBufferViewArray, mAccessorArray )
+    )
+  {
+    return true;
+  }
+  return false;
+}
+
+bool Loader::CreateScene( Internal::Scene3dView& scene3dView )
+{
+  scene3dView.SetDefaultCamera( Dali::Camera::LOOK_AT_TARGET, 0.01, Vector3::ZERO );
+  LoadCamera( scene3dView );
+
+  if( LoadSceneNodes( scene3dView ) &&
+      LoadAnimation( scene3dView ) )
+  {
+    return true;
+  }
+  return false;
+}
+
+void Loader::LoadCamera( Scene3dView& scene3dView )
+{
+  const TreeNode* camerasNode = mRoot->GetChild( "cameras" );
+  if( !camerasNode )
+  {
+    return;
+  }
+
+  for( auto cameraIter = camerasNode->CBegin(), end = camerasNode->CEnd(); cameraIter != end; ++cameraIter )
+  {
+    const TreeNode* tempNode = ( &( *cameraIter ).second )->GetChild( "name" );
+    CameraInfo cameraInfo;
+    if( tempNode )
+    {
+      ReadString( tempNode, cameraInfo.name );
+    }
+
+    tempNode = ( &( *cameraIter ).second )->GetChild( "type" );
+    if( tempNode )
+    {
+      ReadString( tempNode, cameraInfo.type );
+    }
+
+    CameraActor cameraActor = CameraActor::New();
+    cameraActor.SetParentOrigin( ParentOrigin::CENTER );
+    cameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+
+    if( cameraInfo.type == "orthographic" )
+    {
+      LoadOrthoGraphic( ( *cameraIter ).second, cameraInfo );
+      float xMag_2 = cameraInfo.orthographic.xmag / 2.0;
+      float yMag_2 = cameraInfo.orthographic.ymag / 2.0;
+      cameraActor.SetOrthographicProjection( -xMag_2, xMag_2, yMag_2, -yMag_2,
+                                             cameraInfo.orthographic.znear, cameraInfo.orthographic.zfar );
+    }
+    else if( cameraInfo.type == "perspective" )
+    {
+      if( !LoadPerspective( ( *cameraIter ).second, cameraInfo ) )
+      {
+        return;
+      }
+      cameraActor.SetProjectionMode( Dali::Camera::PERSPECTIVE_PROJECTION );
+      cameraActor.SetFieldOfView( cameraInfo.perspective.yfov );
+      cameraActor.SetNearClippingPlane( cameraInfo.perspective.znear );
+
+      if( cameraInfo.perspective.zfar > 0.0 )
+      {
+        cameraActor.SetFarClippingPlane( cameraInfo.perspective.zfar );
+      }
+      if( cameraInfo.perspective.aspectRatio > 0.0 )
+      {
+        cameraActor.SetAspectRatio( cameraInfo.perspective.aspectRatio );
+      }
+    }
+
+    scene3dView.AddCamera( cameraActor );
+  }
+}
+
+bool Loader::LoadOrthoGraphic( const TreeNode& camera, CameraInfo& cameraInfo )
+{
+  const TreeNode* orthographicNode = camera.GetChild( "orthographic" );
+  if( !orthographicNode )
+  {
+    return false;
+  }
+
+  const TreeNode* tempNode;
+  tempNode = orthographicNode->GetChild( "xmag" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.orthographic.xmag );
+  }
+
+  tempNode = orthographicNode->GetChild( "ymag" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.orthographic.ymag );
+  }
+
+  tempNode = orthographicNode->GetChild( "zfar" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.orthographic.zfar );
+  }
+
+  tempNode = orthographicNode->GetChild( "znear" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.orthographic.znear );
+  }
+
+  return true;
+}
+
+bool Loader::LoadPerspective( const TreeNode& camera, CameraInfo& cameraInfo )
+{
+  const TreeNode* perspectiveNode = camera.GetChild( "perspective" );
+  if( !perspectiveNode )
+  {
+    return false;
+  }
+
+  const TreeNode* tempNode;
+  tempNode = perspectiveNode->GetChild( "aspectRatio" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.perspective.aspectRatio );
+  }
+
+  tempNode = perspectiveNode->GetChild( "yfov" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.perspective.yfov );
+  }
+
+  tempNode = perspectiveNode->GetChild( "zfar" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.perspective.zfar );
+  }
+
+  tempNode = perspectiveNode->GetChild( "znear" );
+  if( tempNode )
+  {
+    ReadFloat( tempNode, cameraInfo.perspective.znear );
+  }
+
+  return true;
+}
+
+bool Loader::LoadSceneNodes( Scene3dView& scene3dView )
+{
+  const TreeNode* sceneNode = mRoot->GetChild( "scene" );
+  uint32_t sceneNum = 0;
+  if( sceneNode )
+  {
+    sceneNum = sceneNode->GetInteger();
+  }
+
+  const TreeNode* scenesNode = mRoot->GetChild( "scenes" );
+  if( !( scenesNode && ( mNodes = mRoot->GetChild( "nodes" ) ) ) )
+  {
+    return false;
+  }
+
+  const TreeNode* tempNode = Tidx( scenesNode, sceneNum );
+  if( !tempNode )
+  {
+    return false;
+  }
+
+  tempNode = tempNode->GetChild( "nodes" );
+  if( !tempNode )
+  {
+    return false;
+  }
+
+  for( auto nodeIter = tempNode->CBegin(), end = tempNode->CEnd(); nodeIter != end; ++nodeIter )
+  {
+    Actor actor = AddNode( scene3dView, ( ( *nodeIter ).second ).GetInteger() );
+    actor.SetParentOrigin( ParentOrigin::CENTER );
+    scene3dView.GetRoot().Add( actor );
+  }
+
+  return true;
+}
+
+Actor Loader::AddNode( Scene3dView& scene3dView, uint32_t index )
+{
+  const TreeNode* node = Tidx( mNodes, index );
+  Actor actor = Actor::New();
+  Vector3 actorSize( Vector3::ONE );
+
+  Vector3 translation = Vector3( 0.0, 0.0, 0.0 );
+  Vector3 scale = Vector3( 1.0, 1.0, 1.0 );
+  Quaternion orientation( Vector4( 0.0, 0.0, 0.0, 1.0 ) );
+
+  Vector3 anchorPoint = AnchorPoint::CENTER;
+
+  const TreeNode* tempNode = NULL;
+  if( ( tempNode = node->GetChild( "translation" ) ) )
+  {
+    float floatVec[3] = { 0.0, 0.0, 0.0 };
+    if( tempNode && ReadVector( tempNode, floatVec, 3 ) )
+    {
+      translation = Vector3( floatVec[0], floatVec[1], floatVec[2] );
+    }
+  }
+
+  if( ( tempNode = node->GetChild( "scale" ) ) )
+  {
+    float floatVec[3] = { 1.0, 1.0, 1.0 };
+    if( tempNode && ReadVector( tempNode, floatVec, 3 ) )
+    {
+      scale = Vector3( floatVec[0], floatVec[1], floatVec[2] );
+    }
+  }
+
+  if( ( tempNode = node->GetChild( "rotation" ) ) )
+  {
+    float floatVec[4] = { 0.0, 0.0, 0.0, 1.0 };
+    if( tempNode && ReadVector( tempNode, floatVec, 4 ) )
+    {
+      orientation = Quaternion( Vector4( floatVec[0], floatVec[1], floatVec[2], floatVec[3] ) );
+    }
+  }
+
+  if( ( tempNode = node->GetChild( "matrix" ) ) )
+  {
+    float floatVec[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 };
+    if( tempNode && ReadVector( tempNode, floatVec, 16 ) )
+    {
+      Matrix nodeMatrix = Matrix( floatVec );
+      nodeMatrix.GetTransformComponents( translation, orientation, scale );
+    }
+  }
+
+  if( ( tempNode = node->GetChild( "mesh" ) ) )
+  {
+    MeshInfo meshInfo = mMeshArray[tempNode->GetInteger()];
+    bool isMaterial = ( meshInfo.materialsIdx >= 0 );
+
+    TextureSet textureSet;
+    textureSet = TextureSet::New();
+
+    int32_t addIdx = 0;
+    int32_t shaderTypeIndex = 0;
+    int32_t maxMipmapLevel = 0;
+    bool isBaseColorTexture = false;
+    bool isMetallicRoughnessTexture = false;
+    bool isNormalTexture = false;
+    bool isOcclusionTexture = false;
+    bool isEmissiveTexture = false;
+
+    std::string VERTEX_SHADER, FRAGMENT_SHADER;
+    VERTEX_SHADER = GLES_VERSION_300;
+    VERTEX_SHADER += PHYSICALLY_BASED_VERTEX_SHADER;
+    FRAGMENT_SHADER = GLES_VERSION_300;
+
+    bool useIBL = ( scene3dView.GetLightType() >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT );
+    if( isMaterial )
+    {
+      MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
+      if( SetTextureAndSampler( textureSet, materialInfo.baseColorTexture.index, FRAGMENT_SHADER, DEFINE_BASECOLOR_TEXTURE, addIdx ) )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::BASECOLOR_SHADER );
+        isBaseColorTexture = true;
+      }
+      if( SetTextureAndSampler( textureSet, materialInfo.metallicRoughnessTexture.index, FRAGMENT_SHADER, DEFINE_METALLICROUGHNESS_TEXTURE, addIdx ) )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::METALLICROUGHNESS_SHADER );
+        isMetallicRoughnessTexture = true;
+      }
+      if( SetTextureAndSampler( textureSet, materialInfo.normalTexture.index, FRAGMENT_SHADER, DEFINE_NORMAL_TEXTURE, addIdx ) )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::NORMAL_SHADER );
+        isNormalTexture = true;
+      }
+      if( SetTextureAndSampler( textureSet, materialInfo.occlusionTexture.index, FRAGMENT_SHADER, DEFINE_OCCLUSION_TEXTURE, addIdx ) )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::OCCLUSION_SHADER );
+        isOcclusionTexture = true;
+      }
+      if( SetTextureAndSampler( textureSet, materialInfo.emissiveTexture.index, FRAGMENT_SHADER, DEFINE_EMIT_TEXTURE, addIdx ) )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::EMIT_SHADER );
+        isEmissiveTexture = true;
+      }
+
+      if( useIBL )
+      {
+        shaderTypeIndex += static_cast<int32_t>( ShaderType::IBL_SHADER );
+        FRAGMENT_SHADER += DEFINE_IBL_TEXTURE;
+
+        Sampler sampler = Sampler::New();
+        sampler.SetFilterMode( FilterMode::DEFAULT, FilterMode::DEFAULT );
+        sampler.SetWrapMode( WrapMode::REPEAT, WrapMode::REPEAT, WrapMode::REPEAT );
+
+        textureSet.SetTexture( addIdx, scene3dView.GetBRDFTexture() );
+        textureSet.SetSampler( addIdx++, sampler );
+        Sampler samplerIBL = Sampler::New();
+        samplerIBL.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR );
+        samplerIBL.SetWrapMode( WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE, WrapMode::CLAMP_TO_EDGE );
+        textureSet.SetTexture( addIdx, scene3dView.GetDiffuseTexture() );
+        textureSet.SetSampler( addIdx++, samplerIBL );
+        Texture specularTexture = scene3dView.GetSpecularTexture();
+        textureSet.SetTexture( addIdx, specularTexture );
+        textureSet.SetSampler( addIdx++, samplerIBL );
+
+        int32_t textureSize = std::min( specularTexture.GetWidth(), specularTexture.GetHeight() );
+        maxMipmapLevel = 0;
+        while( textureSize >= 1 )
+        {
+          maxMipmapLevel++;
+          textureSize /= 2;
+        }
+      }
+    }
+
+    FRAGMENT_SHADER += PHYSICALLY_BASED_FRAGMENT_SHADER;
+    if( !mShaderCache[shaderTypeIndex] )
+    {
+      mShaderCache[shaderTypeIndex] = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+      scene3dView.AddShader( mShaderCache[shaderTypeIndex] );
+    }
+    Shader shader = mShaderCache[shaderTypeIndex];
+
+    Renderer renderer = Renderer::New( meshInfo.geometry, shader );
+    renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+    renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
+    renderer.SetTextures( textureSet );
+
+    anchorPoint = meshInfo.pivot;
+    actor.SetAnchorPoint( anchorPoint );
+
+    actor.SetSize( Vector3( meshInfo.size.x, meshInfo.size.y, meshInfo.size.z ) );
+    actor.AddRenderer( renderer );
+
+    actor.SetScale( scale );
+    actor.RotateBy( orientation );
+    actor.SetPosition( translation );
+
+    shader.RegisterProperty( "uLightType", ( scene3dView.GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT ) );
+    shader.RegisterProperty( "uLightVector", scene3dView.GetLightVector() );
+    shader.RegisterProperty( "uLightColor", scene3dView.GetLightColor() );
+
+    actor.RegisterProperty( "uIsColor", meshInfo.attribute.COLOR.size() > 0 );
+    if( isMaterial )
+    {
+      MaterialInfo materialInfo = mMaterialArray[meshInfo.materialsIdx];
+      actor.RegisterProperty( "uBaseColorFactor", materialInfo.baseColorFactor );
+      actor.RegisterProperty( "uMetallicRoughnessFactors", Vector2( materialInfo.metallicFactor, materialInfo.roughnessFactor ) );
+
+      if( materialInfo.alphaMode == "OPAQUE" )
+      {
+        actor.RegisterProperty( "alphaMode", 0 );
+      }
+      else if( materialInfo.alphaMode == "MASK" )
+      {
+        actor.RegisterProperty( "alphaMode", 1 );
+      }
+      else
+      {
+        actor.RegisterProperty( "alphaMode", 2 );
+      }
+      actor.RegisterProperty( "alphaCutoff", materialInfo.alphaCutoff );
+
+      if( isBaseColorTexture )
+      {
+        actor.RegisterProperty( "uBaseColorTexCoordIndex", materialInfo.baseColorTexture.texCoord );
+      }
+      if( isMetallicRoughnessTexture )
+      {
+        actor.RegisterProperty( "uMetallicRoughnessTexCoordIndex", materialInfo.metallicRoughnessTexture.texCoord );
+      }
+      if( isNormalTexture )
+      {
+        actor.RegisterProperty( "uNormalScale", materialInfo.normalTexture.value );
+        actor.RegisterProperty( "uNormalTexCoordIndex", materialInfo.normalTexture.texCoord );
+      }
+      if( isOcclusionTexture )
+      {
+        actor.RegisterProperty( "uOcclusionTexCoordIndex", materialInfo.occlusionTexture.texCoord );
+        actor.RegisterProperty( "uOcclusionStrength", materialInfo.occlusionTexture.value );
+      }
+      if( isEmissiveTexture )
+      {
+        actor.RegisterProperty( "uEmissiveTexCoordIndex", materialInfo.emissiveTexture.texCoord );
+        actor.RegisterProperty( "uEmissiveFactor", materialInfo.emissiveFactor );
+      }
+    }
+
+    if( isMaterial && useIBL )
+    {
+      actor.RegisterProperty( "uScaleIBLAmbient", scene3dView.GetIBLScaleFactor() );
+      actor.RegisterProperty( "uMipmapLevel", static_cast<float>( maxMipmapLevel ) );
+    }
+  }
+  else
+  {
+    actor.SetAnchorPoint( AnchorPoint::CENTER );
+    actor.SetPosition( translation );
+    actor.RotateBy( orientation );
+    actor.SetSize( actorSize );
+  }
+
+  tempNode = node->GetChild( "camera" );
+  if( tempNode )
+  {
+    int32_t cameraNum = tempNode->GetInteger();
+    CameraActor cameraActor = scene3dView.GetCamera( cameraNum );
+    if( cameraActor )
+    {
+      actor.Add( cameraActor );
+    }
+  }
+
+  tempNode = node->GetChild( "name" );
+  if( tempNode )
+  {
+    std::string nameString;
+    ReadString( tempNode, nameString );
+    actor.SetName( nameString );
+  }
+
+  SetActorCache( actor, index );
+  if( ( tempNode = node->GetChild( "children" ) ) )
+  {
+    for( auto childIter = tempNode->CBegin(), end = tempNode->CEnd(); childIter != end; ++childIter )
+    {
+      Actor childActor = AddNode( scene3dView, ( ( *childIter ).second ).GetInteger() );
+      childActor.SetParentOrigin( anchorPoint );
+      actor.Add( childActor );
+    }
+  }
+
+  return actor;
+}
+
+void Loader::SetActorCache( Actor& actor, uint32_t index )
+{
+  if( mActorCache.size() < index + 1 )
+  {
+    mActorCache.resize( index + 1 );
+  }
+  mActorCache[index] = actor;
+}
+
+bool Loader::SetTextureAndSampler( TextureSet& textureSet, int32_t textureIdx, std::string& toShader, std::string shader, int32_t& addIdx )
+{
+  if( textureIdx >= 0 )
+  {
+    toShader += shader;
+    TextureInfo textureInfo = mTextureArray[textureIdx];
+    if( textureInfo.sourceIdx >= 0 )
+    {
+      textureSet.SetTexture( addIdx, mSourceArray[textureInfo.sourceIdx] );
+    }
+    if( textureInfo.samplerIdx >= 0 )
+    {
+      textureSet.SetSampler( addIdx, mSamplerArray[textureInfo.samplerIdx] );
+    }
+    else
+    {
+      Sampler sampler = Sampler::New();
+      sampler.SetFilterMode( FilterMode::DEFAULT, FilterMode::DEFAULT );
+      sampler.SetWrapMode( WrapMode::REPEAT, WrapMode::REPEAT, WrapMode::REPEAT );
+      textureSet.SetSampler( addIdx, sampler );
+    }
+    addIdx++;
+    return true;
+  }
+  return false;
+}
+
+bool Loader::LoadAnimation( Scene3dView& scene3dView )
+{
+  const TreeNode* animationsNode = mRoot->GetChild( "animations" );
+  if( !animationsNode )
+  {
+    return true;
+  }
+
+  for( auto animationIter = animationsNode->CBegin(), end = animationsNode->CEnd(); animationIter != end; ++animationIter )
+  {
+    const TreeNode* nameNode = ( &( *animationIter ).second )->GetChild( "name" );
+    AnimationInfo animationInfo;
+    if( nameNode )
+    {
+      ReadString( nameNode, animationInfo.name );
+    }
+
+    Property::Index propIndex = Property::INVALID_INDEX;
+    LoadAnimationChannels( ( *animationIter ).second, animationInfo );
+    if( animationInfo.channelArray.size() == 0 )
+    {
+      continue;
+    }
+
+    LoadAnimationSamplers( ( *animationIter ).second, animationInfo );
+
+    for( auto&& currentChannel : animationInfo.channelArray )
+    {
+      if( currentChannel.path == "rotation" )
+      {
+        propIndex = Dali::Actor::Property::ORIENTATION;
+      }
+      else if( currentChannel.path == "translation" )
+      {
+        propIndex = Dali::Actor::Property::POSITION;
+      }
+      else if( currentChannel.path == "scale" )
+      {
+        propIndex = Dali::Actor::Property::SCALE;
+      }
+
+      float duration = 0.0f;
+      KeyFrames keyframes = KeyFrames::New();
+      if( propIndex == Dali::Actor::Property::ORIENTATION )
+      {
+        duration = LoadKeyFrames<Vector4>( animationInfo.samplerArray[currentChannel.sampler], propIndex, keyframes, mPath, mAccessorArray, mBufferViewArray, mBufferArray );
+      }
+      else
+      {
+        duration = LoadKeyFrames<Vector3>( animationInfo.samplerArray[currentChannel.sampler], propIndex, keyframes, mPath, mAccessorArray, mBufferViewArray, mBufferArray );
+      }
+
+      Animation animation = Animation::New( duration );
+      Animation::Interpolation interpolation = Animation::Interpolation::Linear;
+      if( animationInfo.samplerArray[currentChannel.sampler].interpolation == "CUBICSPLINE" )
+      {
+        interpolation = Animation::Interpolation::Cubic;
+      }
+      if( animationInfo.samplerArray[currentChannel.sampler].interpolation == "STEP" )
+      {
+      }
+
+      animation.AnimateBetween( Property( mActorCache[currentChannel.targetNode], propIndex ), keyframes, interpolation );
+
+      animation.SetLooping( false );
+      scene3dView.AddAnimation( animation );
+    }
+  }
+
+  return true;
+}
+
+bool Loader::LoadAnimationChannels( const TreeNode& animation, AnimationInfo& animationInfo )
+{
+  const TreeNode* channelsNode = animation.GetChild( "channels" );
+  if( !channelsNode )
+  {
+    return false;
+  }
+
+  for( auto channelIter = channelsNode->CBegin(), end = channelsNode->CEnd(); channelIter != end; ++channelIter )
+  {
+    AnimationChannelInfo animationChannelInfo;
+    const TreeNode* channelNode = ( &( *channelIter ).second );
+    const TreeNode* samplerNode = channelNode->GetChild( "sampler" );
+    if( samplerNode )
+    {
+      animationChannelInfo.sampler = samplerNode->GetInteger();
+    }
+
+    const TreeNode* targetNode = channelNode->GetChild( "target" );
+    if( targetNode )
+    {
+      const TreeNode* tempNode = targetNode->GetChild( "node" );
+      if( tempNode )
+      {
+        animationChannelInfo.targetNode = tempNode->GetInteger();
+      }
+      else
+      {
+        continue;
+      }
+
+      tempNode = targetNode->GetChild( "path" );
+      if( tempNode )
+      {
+        ReadString( tempNode, animationChannelInfo.path );
+      }
+    }
+
+    animationInfo.channelArray.push_back( animationChannelInfo );
+  }
+  return true;
+}
+
+bool Loader::LoadAnimationSamplers( const TreeNode& animation, AnimationInfo& animationInfo )
+{
+  const TreeNode* samplersNode = animation.GetChild( "samplers" );
+  if( !samplersNode )
+  {
+    return false;
+  }
+
+  for( auto sampler = samplersNode->CBegin(), end = samplersNode->CEnd(); sampler != end; ++sampler )
+  {
+    AnimationSamplerInfo animationSamplerInfo;
+    const TreeNode* samplerNode = ( &( *sampler ).second );
+    const TreeNode* tempNode = samplerNode->GetChild( "input" );
+    if( tempNode )
+    {
+      animationSamplerInfo.input = tempNode->GetInteger();
+    }
+
+    tempNode = samplerNode->GetChild( "output" );
+    if( tempNode )
+    {
+      animationSamplerInfo.output = tempNode->GetInteger();
+    }
+
+    tempNode = samplerNode->GetChild( "interpolation" );
+    if( tempNode )
+    {
+      ReadString( tempNode, animationSamplerInfo.interpolation );
+    }
+
+    animationInfo.samplerArray.push_back( animationSamplerInfo );
+  }
+
+  return true;
+}
+
+}//namespace Gltf
+
+}//namespace Internal
+
+}//namespace Toolkit
+
+}//namespace Dali
diff --git a/dali-toolkit/internal/controls/scene3d-view/gltf-loader.h b/dali-toolkit/internal/controls/scene3d-view/gltf-loader.h
new file mode 100644 (file)
index 0000000..42ee4dd
--- /dev/null
@@ -0,0 +1,496 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H\r
+#define DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H\r
+\r
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/actors/layer.h>\r
+#include <dali/public-api/rendering/renderer.h>\r
+#include <dali/public-api/rendering/shader.h>\r
+#include <dali/public-api/animation/animation.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/devel-api/builder/json-parser.h>\r
+#include <dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h>\r
+\r
+using namespace Dali;\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Toolkit\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Gltf\r
+{\r
+\r
+enum ShaderType\r
+{\r
+  NO_TEXTURE_SHADER,\r
+  BASECOLOR_SHADER,\r
+  METALLICROUGHNESS_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_SHADER,\r
+  NORMAL_SHADER,\r
+  BASECOLOR_NORMAL_SHADER,\r
+  METALLICROUGHNESS_NORMAL_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_NORMAL_SHADER,\r
+  OCCLUSION_SHADER,\r
+  BASECOLOR_OCCLUSION_SHADER,\r
+  METALLICROUGHNESS_OCCLUSION_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_OCCLUSION_SHADER,\r
+  NORMAL_OCCLUSION_SHADER,\r
+  BASECOLOR_NORMAL_OCCLUSION_SHADER,\r
+  METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER,\r
+  EMIT_SHADER,\r
+  BASECOLOR_EMIT_SHADER,\r
+  METALLICROUGHNESS_EMIT_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_EMIT_SHADER,\r
+  NORMAL_EMIT_SHADER,\r
+  BASECOLOR_NORMAL_EMIT_SHADER,\r
+  METALLICROUGHNESS_NORMAL_EMIT_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_NORMAL_EMIT_SHADER,\r
+  OCCLUSION_EMIT_SHADER,\r
+  BASECOLOR_OCCLUSION_EMIT_SHADER,\r
+  METALLICROUGHNESS_OCCLUSION_EMIT_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER,\r
+  NORMAL_OCCLUSION_EMIT_SHADER,\r
+  BASECOLOR_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  IBL_SHADER,\r
+  IBL_BASECOLOR_SHADER,\r
+  IBL_METALLICROUGHNESS_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_SHADER,\r
+  IBL_NORMAL_SHADER,\r
+  IBL_BASECOLOR_NORMAL_SHADER,\r
+  IBL_METALLICROUGHNESS_NORMAL_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_SHADER,\r
+  IBL_OCCLUSION_SHADER,\r
+  IBL_BASECOLOR_OCCLUSION_SHADER,\r
+  IBL_METALLICROUGHNESS_OCCLUSION_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_OCCLUSION_SHADER,\r
+  IBL_NORMAL_OCCLUSION_SHADER,\r
+  IBL_BASECOLOR_NORMAL_OCCLUSION_SHADER,\r
+  IBL_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_SHADER,\r
+  IBL_EMIT_SHADER,\r
+  IBL_BASECOLOR_EMIT_SHADER,\r
+  IBL_METALLICROUGHNESS_EMIT_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_EMIT_SHADER,\r
+  IBL_NORMAL_EMIT_SHADER,\r
+  IBL_BASECOLOR_NORMAL_EMIT_SHADER,\r
+  IBL_METALLICROUGHNESS_NORMAL_EMIT_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_EMIT_SHADER,\r
+  IBL_OCCLUSION_EMIT_SHADER,\r
+  IBL_BASECOLOR_OCCLUSION_EMIT_SHADER,\r
+  IBL_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_OCCLUSION_EMIT_SHADER,\r
+  IBL_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  IBL_BASECOLOR_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  IBL_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER,\r
+  SHADER_TYPE_MAX = IBL_BASECOLOR_METALLICROUGHNESS_NORMAL_OCCLUSION_EMIT_SHADER\r
+};\r
+\r
+struct BufferInfo\r
+{\r
+  BufferInfo()\r
+    : byteLength( -1 ),\r
+    uri( "" ),\r
+    name( "" )\r
+  {\r
+  }\r
+\r
+  ~BufferInfo()\r
+  {\r
+  }\r
+\r
+  int32_t byteLength;\r
+  std::string uri;\r
+  std::string name;\r
+};\r
+\r
+struct BufferViewInfo\r
+{\r
+  BufferViewInfo()\r
+    : buffer( -1 ),\r
+    byteOffset( 0 ),\r
+    byteLength( 0 ),\r
+    byteStride( 0 ),\r
+    target( 0 ),\r
+    name( "" )\r
+  {\r
+  }\r
+\r
+  ~BufferViewInfo()\r
+  {\r
+  }\r
+\r
+  int32_t buffer;\r
+  int32_t byteOffset;\r
+  int32_t byteLength;\r
+  int32_t byteStride;\r
+  int32_t target;\r
+  std::string name;\r
+};\r
+\r
+struct TextureInfo\r
+{\r
+  TextureInfo()\r
+    : sourceIdx( -1 ),\r
+    samplerIdx( -1 )\r
+  {\r
+  }\r
+\r
+  ~TextureInfo()\r
+  {\r
+  }\r
+  int32_t sourceIdx;\r
+  int32_t samplerIdx;\r
+};\r
+\r
+struct PbrTextureInfo\r
+{\r
+  PbrTextureInfo()\r
+    : index( -1 ),\r
+    texCoord( 0 ),\r
+    value( 0.0 )\r
+  {\r
+  }\r
+  ~PbrTextureInfo()\r
+  {\r
+  }\r
+\r
+  int32_t index;\r
+  int32_t texCoord;\r
+  float value;\r
+};\r
+\r
+struct MaterialInfo\r
+{\r
+  MaterialInfo()\r
+    : baseColorFactor( 1, 1, 1, 1 ),\r
+    metallicFactor( 1.0 ),\r
+    roughnessFactor( 1.0 ),\r
+    emissiveFactor( 0.0, 0.0, 0.0 ),\r
+    alphaMode( "OPAQUE" ),\r
+    alphaCutoff( 0.5 ),\r
+    doubleSided( false ),\r
+    name( "" )\r
+  {\r
+  }\r
+\r
+  ~MaterialInfo()\r
+  {\r
+  }\r
+\r
+  Vector4 baseColorFactor;\r
+  float metallicFactor;\r
+  float roughnessFactor;\r
+  Vector3 emissiveFactor;\r
+  std::string alphaMode;\r
+  float alphaCutoff;\r
+  bool doubleSided;\r
+\r
+  PbrTextureInfo baseColorTexture;\r
+  PbrTextureInfo metallicRoughnessTexture;\r
+  PbrTextureInfo normalTexture;\r
+  PbrTextureInfo occlusionTexture;\r
+  PbrTextureInfo emissiveTexture;\r
+\r
+  std::string name;\r
+  //need to add max, min\r
+};\r
+\r
+struct AccessorInfo\r
+{\r
+  AccessorInfo()\r
+    : bufferView( -1 ),\r
+    byteOffset( 0 ),\r
+    componentType( -1 ),\r
+    normalized( false ),\r
+    count( 0 ),\r
+    type( "" ),\r
+    max( 0 ),\r
+    min( 0 ),\r
+    name( "" )\r
+  {\r
+  }\r
+\r
+  ~AccessorInfo()\r
+  {\r
+  }\r
+\r
+  int32_t bufferView;\r
+  int32_t byteOffset;\r
+  int32_t componentType;\r
+  bool normalized;\r
+  int32_t count;\r
+  std::string type;\r
+  int32_t max;\r
+  int32_t min;\r
+  std::string name;\r
+  //need to add max, min\r
+};\r
+\r
+struct Attribute\r
+{\r
+  Attribute()\r
+    : POSITION( -1 ),\r
+    NORMAL( -1 ),\r
+    TANGENT( -1 )\r
+  {\r
+  }\r
+\r
+  ~Attribute()\r
+  {\r
+  }\r
+\r
+  int32_t POSITION;\r
+  int32_t NORMAL;\r
+  int32_t TANGENT;\r
+\r
+  std::vector<int32_t> TEXCOORD;\r
+  std::vector<int32_t> COLOR;\r
+};\r
+\r
+struct MeshInfo\r
+{\r
+  MeshInfo()\r
+    : indicesIdx( -1 ),\r
+    materialsIdx( -1 ),\r
+    mode( 4 )\r
+  {\r
+  }\r
+\r
+  ~MeshInfo()\r
+  {\r
+  }\r
+  Geometry geometry;\r
+  std::string name;\r
+\r
+  int32_t indicesIdx;\r
+  int32_t materialsIdx;\r
+  int32_t mode;\r
+\r
+  Vector3 size;\r
+  Vector3 pivot;\r
+\r
+  Attribute attribute;\r
+  //need to add max, min\r
+};\r
+\r
+struct AnimationChannelInfo\r
+{\r
+  AnimationChannelInfo()\r
+    : sampler( -1 ),\r
+    targetNode( -1 ),\r
+    path( "" )\r
+  {\r
+  }\r
+\r
+  ~AnimationChannelInfo()\r
+  {\r
+  }\r
+\r
+  int32_t sampler;\r
+  int32_t targetNode;\r
+  std::string path;\r
+\r
+};\r
+\r
+struct AnimationSamplerInfo\r
+{\r
+  AnimationSamplerInfo()\r
+    : input( -1 ),\r
+    output( -1 ),\r
+    interpolation( "" )\r
+  {\r
+  }\r
+\r
+  ~AnimationSamplerInfo()\r
+  {\r
+  }\r
+\r
+  int32_t input;\r
+  int32_t output;\r
+  std::string interpolation;\r
+};\r
+\r
+struct AnimationInfo\r
+{\r
+  AnimationInfo()\r
+    : name( "" )\r
+  {\r
+  }\r
+\r
+  ~AnimationInfo()\r
+  {\r
+  }\r
+\r
+  std::string name;\r
+  std::vector<AnimationChannelInfo> channelArray;\r
+  std::vector<AnimationSamplerInfo> samplerArray;\r
+};\r
+\r
+struct OrthographicInfo\r
+{\r
+  OrthographicInfo()\r
+    : xmag( 0.0f ),\r
+    ymag( 0.0f ),\r
+    zfar( 0.0f ),\r
+    znear( 0.0f )\r
+  {\r
+  }\r
+\r
+  ~OrthographicInfo()\r
+  {\r
+  }\r
+\r
+  float xmag;\r
+  float ymag;\r
+  float zfar;\r
+  float znear;\r
+};\r
+\r
+struct PerspectiveInfo\r
+{\r
+  PerspectiveInfo()\r
+    : aspectRatio( 0.0f ),\r
+    yfov( 0.0f ),\r
+    zfar( 0.0f ),\r
+    znear( 0.0f )\r
+  {\r
+  }\r
+\r
+  ~PerspectiveInfo()\r
+  {\r
+  }\r
+\r
+  float aspectRatio;\r
+  float yfov;\r
+  float zfar;\r
+  float znear;\r
+};\r
+\r
+struct CameraInfo\r
+{\r
+  CameraInfo()\r
+    : name( "" ),\r
+    type( "" )\r
+  {\r
+  }\r
+\r
+  ~CameraInfo()\r
+  {\r
+  }\r
+\r
+  std::string name;\r
+  std::string type;\r
+  OrthographicInfo orthographic;\r
+  PerspectiveInfo perspective;\r
+};\r
+\r
+/**\r
+ *\r
+ * Loader is a class to parse glTf, to load data from file, and to generate Scene.\r
+ * This glTF loader supports glTF 2.0 features.\r
+ *\r
+ * @remarks glTF loader didn't support such features.\r
+ *  - Sparse accessor\r
+ *  - Morphing\r
+ *  - Skeletal Animation\r
+ * These features will be supported soon.\r
+ *\r
+ */\r
+class Loader\r
+{\r
+public:\r
+\r
+  /**\r
+   * @brief Create an uninitialized Loader.\r
+   */\r
+  Loader();\r
+\r
+  /**\r
+   * @brief Destructor\r
+   */\r
+  ~Loader();\r
+\r
+  /**\r
+   * @brief Load Scene3dView from scene format file(e.g., glTF).\r
+   * @param[in] filePath Path of scene format file.\r
+   * @param[in] scene3dView Scene3dView data loaded from file.\r
+   * @return true if scene is successfully loaded\r
+   */\r
+  bool LoadScene( const std::string& filePath, Internal::Scene3dView& scene3dView );\r
+\r
+private:\r
+  bool ParseGltf( const std::string& filePath );\r
+  bool LoadAssets();\r
+\r
+  bool CreateScene( Internal::Scene3dView& scene3dView );\r
+\r
+  void LoadCamera( Scene3dView& scene3dView );\r
+  bool LoadOrthoGraphic( const TreeNode& camera, CameraInfo& cameraInfo );\r
+  bool LoadPerspective( const TreeNode& camera, CameraInfo& cameraInfo );\r
+\r
+  bool LoadSceneNodes( Scene3dView& scene3dView );\r
+  Actor AddNode( Scene3dView& scene3dView, uint32_t index );\r
+  void SetActorCache( Actor& actor, uint32_t index );\r
+  bool SetTextureAndSampler( TextureSet& textureSet, int32_t textureIdx, std::string& toShader, std::string shader, int32_t& addIdx );\r
+\r
+  bool LoadAnimation( Scene3dView& scene3dView );\r
+  bool LoadAnimationChannels( const TreeNode& animation, AnimationInfo& animationInfo );\r
+  bool LoadAnimationSamplers( const TreeNode& animation, AnimationInfo& animationInfo );\r
+\r
+private:\r
+  Dali::Toolkit::JsonParser mParser;\r
+  const TreeNode* mNodes;\r
+  const TreeNode* mRoot;\r
+\r
+  std::string mPath;\r
+\r
+  std::vector<Actor> mActorCache;\r
+  Shader mShaderCache[ShaderType::SHADER_TYPE_MAX + 1];\r
+\r
+  std::vector<BufferInfo> mBufferArray;\r
+  std::vector<BufferViewInfo> mBufferViewArray;\r
+  std::vector<AccessorInfo> mAccessorArray;\r
+\r
+  std::vector<MeshInfo> mMeshArray;\r
+  std::vector<MaterialInfo> mMaterialArray;\r
+  std::vector<TextureInfo> mTextureArray;\r
+\r
+  std::vector<Texture> mSourceArray;\r
+  std::vector<Sampler> mSamplerArray;\r
+};\r
+\r
+}//namespace Gltf\r
+\r
+}//namespace Internal\r
+\r
+}//namespace Toolkit\r
+\r
+}//namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_INTERNAL_GLTF_LOADER_H\r
diff --git a/dali-toolkit/internal/controls/scene3d-view/gltf-shader.h b/dali-toolkit/internal/controls/scene3d-view/gltf-shader.h
new file mode 100644 (file)
index 0000000..e51b77c
--- /dev/null
@@ -0,0 +1,346 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H
+#define DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H
+
+/*
+ * Belows Vertex Shader and Fragment Shader code are based off glTF WebGL PBR.
+ * https://github.com/KhronosGroup/glTF-WebGL-PBR/
+ *
+ * Copyright (c) 2016-2017 Mohamad Moneimne and Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+const char* GLES_VERSION_300 = {
+  "#version 300 es\n\n"
+  "precision highp float;\n\n"
+};
+
+const char* DEFINE_BASECOLOR_TEXTURE = {
+  "#define TEXTURE_BASECOLOR\n\n"
+  "uniform sampler2D uBaseColorSampler;\n"
+  "uniform int uBaseColorTexCoordIndex;\n\n"
+};
+
+const char* DEFINE_METALLICROUGHNESS_TEXTURE = {
+  "#define TEXTURE_METALLICROUGHNESS\n\n"
+  "uniform sampler2D uMetallicRoughnessSampler;\n"
+  "uniform int uMetallicRoughnessTexCoordIndex;\n\n"
+};
+
+const char* DEFINE_NORMAL_TEXTURE = {
+  "#define TEXTURE_NORMAL\n\n"
+  "uniform sampler2D uNormalSampler;\n"
+  "uniform float uNormalScale;\n"
+  "uniform int uNormalTexCoordIndex;\n\n"
+};
+
+const char* DEFINE_OCCLUSION_TEXTURE = {
+  "#define TEXTURE_OCCLUSION\n\n"
+  "uniform sampler2D uOcclusionSampler;\n"
+  "uniform int uOcclusionTexCoordIndex;\n"
+  "uniform float uOcclusionStrength;\n\n"
+};
+
+const char* DEFINE_EMIT_TEXTURE = {
+  "#define TEXTURE_EMIT\n\n"
+  "uniform sampler2D uEmissiveSampler;\n"
+  "uniform int uEmissiveTexCoordIndex;\n"
+  "uniform vec3 uEmissiveFactor;\n\n"
+};
+
+const char* DEFINE_IBL_TEXTURE = {
+  "#define TEXTURE_IBL\n\n"
+  "uniform sampler2D ubrdfLUT;\n"
+  "uniform samplerCube uDiffuseEnvSampler;\n"
+  "uniform samplerCube uSpecularEnvSampler;\n"
+  "uniform vec4 uScaleIBLAmbient;\n"
+  "uniform highp float uMipmapLevel;\n"
+};
+
+const char* PHYSICALLY_BASED_VERTEX_SHADER = {
+  "in highp vec3 aPosition;\n"
+  "in mediump vec2 aTexCoord0;\n"
+  "in mediump vec2 aTexCoord1;\n"
+  "in lowp vec3 aNormal;\n"
+  "in lowp vec4 aTangent;\n"
+  "in lowp vec4 aVertexColor;\n"
+
+  "uniform mediump vec3 uSize;\n"
+  "uniform mediump mat4 uModelMatrix;\n"
+  "uniform mediump mat4 uViewMatrix;\n"
+  "uniform mediump mat4 uProjection;\n"
+  "uniform lowp int uLightType;\n"
+  "uniform mediump vec3 uLightVector;\n"
+  "uniform lowp int uIsColor;\n"
+
+  "out lowp vec2 vUV[2];\n"
+  "out lowp mat3 vTBN;\n"
+  "out lowp vec4 vColor;\n"
+  "flat out int visLight;\n"
+  "out highp vec3 vLightDirection;\n"
+  "out highp vec3 vPositionToCamera;\n"
+
+  "void main()\n"
+  "{\n"
+  "  highp vec4 invY = vec4(1.0, -1.0, 1.0, 1.0);\n"
+  "  highp vec4 positionW = uModelMatrix * vec4( aPosition * uSize, 1.0 );\n"
+  "  highp vec4 positionV = uViewMatrix * ( invY * positionW );\n"
+
+  "  vPositionToCamera = transpose( mat3( uViewMatrix ) ) * ( -vec3( positionV.xyz / positionV.w ) );\n"
+  "  vPositionToCamera *= invY.xyz;\n"
+
+  "  lowp vec3 bitangent = cross(aNormal, aTangent.xyz) * aTangent.w;\n"
+  "  vTBN = mat3( uModelMatrix ) * mat3(aTangent.xyz, bitangent, aNormal);\n"
+
+  "  vUV[0] = aTexCoord0;\n"
+  "  vUV[1] = aTexCoord1;\n"
+
+  "  visLight = 1;\n"
+  "  if( uLightType == 1 )\n"
+  "  {\n"
+  "    vLightDirection = ( invY.xyz * uLightVector ) - ( positionW.xyz / positionW.w );\n"
+  "  }\n"
+  "  else if( uLightType == 2 )\n"
+  "  {\n"
+  "    vLightDirection = -( invY.xyz * uLightVector );\n"
+  "  }\n"
+  "  else\n"
+  "  {\n"
+  "    visLight = 0;\n"
+  "  }\n"
+
+  "  vColor = vec4( 1.0 );\n"
+  "  if( uIsColor == 1 )\n"
+  "  {\n"
+  "    vColor = aVertexColor;\n"
+  "  }\n"
+
+  "  gl_Position = uProjection * positionV;\n" // needs w for proper perspective correction
+  "  gl_Position = gl_Position/gl_Position.w;\n"
+  "}\n"
+};
+
+const char* PHYSICALLY_BASED_FRAGMENT_SHADER = {
+  "uniform lowp vec3 uLightColor;\n"
+  "uniform lowp vec4 uBaseColorFactor;\n"
+  "uniform lowp vec2 uMetallicRoughnessFactors;\n"
+  "uniform lowp int alphaMode;\n"
+  "uniform lowp float alphaCutoff;\n"
+
+  "in lowp vec2 vUV[2];\n"
+  "in lowp mat3 vTBN;\n"
+  "in lowp vec4 vColor;\n"
+  "flat in int visLight;\n"
+  "in highp vec3 vLightDirection;\n"
+  "in highp vec3 vPositionToCamera;\n"
+
+  "out vec4 FragColor;"
+
+  "struct PBRInfo\n"
+  "{\n"
+  "  mediump float NdotL;\n"                  // cos angle between normal and light direction
+  "  mediump float NdotV;\n"                  // cos angle between normal and view direction
+  "  mediump float NdotH;\n"                  // cos angle between normal and half vector
+  "  mediump float VdotH;\n"                  // cos angle between view direction and half vector
+  "  mediump vec3 reflectance0;\n"            // full reflectance color (normal incidence angle)
+  "  mediump vec3 reflectance90;\n"           // reflectance color at grazing angle
+  "  lowp float alphaRoughness;\n"         // roughness mapped to a more linear change in the roughness (proposed by [2])
+  "};\n"
+
+  "const float M_PI = 3.141592653589793;\n"
+  "const float c_MinRoughness = 0.04;\n"
+
+  "vec3 getNormal()\n"
+  "{\n"
+  "#ifdef TEXTURE_NORMAL\n"
+  "  lowp vec3 n = texture( uNormalSampler, vUV[uNormalTexCoordIndex] ).rgb;\n"
+  "  n = normalize( vTBN * ( ( 2.0 * n - 1.0 ) * vec3( uNormalScale, uNormalScale, 1.0 ) ) );\n"
+  "#else\n"
+  "  lowp vec3 n = normalize( vTBN[2].xyz );\n"
+  "#endif\n"
+  "  return n;\n"
+  "}\n"
+
+  "vec3 specularReflection( PBRInfo pbrInputs )\n"
+  "{\n"
+  "  return pbrInputs.reflectance0 + ( pbrInputs.reflectance90 - pbrInputs.reflectance0 ) * pow( clamp( 1.0 - pbrInputs.VdotH, 0.0, 1.0 ), 5.0 );\n"
+  "}\n"
+
+  "float geometricOcclusion( PBRInfo pbrInputs )\n"
+  "{\n"
+  "  mediump float NdotL = pbrInputs.NdotL;\n"
+  "  mediump float NdotV = pbrInputs.NdotV;\n"
+  "  lowp float r = pbrInputs.alphaRoughness;\n"
+
+  "  lowp float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));\n"
+  "  lowp float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));\n"
+  "  return attenuationL * attenuationV;\n"
+  "}\n"
+
+  "float microfacetDistribution(PBRInfo pbrInputs)\n"
+  "{\n"
+  "  mediump float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;\n"
+  "  lowp float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;\n"
+  "  return roughnessSq / (M_PI * f * f);\n"
+  "}\n"
+
+  "vec3 linear( vec3 color )\n"
+  "{\n"
+  "  return pow(color,vec3(2.2));\n"
+  "}\n"
+
+  "void main()\n"
+  "{\n"
+  // Metallic and Roughness material properties are packed together
+  // In glTF, these factors can be specified by fixed scalar values
+  // or from a metallic-roughness map
+  "  lowp float metallic = uMetallicRoughnessFactors.x;\n"
+  "  lowp float perceptualRoughness = uMetallicRoughnessFactors.y;\n"
+
+  // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
+  // This layout intentionally reserves the 'r' channel for (optional) occlusion map data
+  "#ifdef TEXTURE_METALLICROUGHNESS\n"
+  "  lowp vec4 metrou = texture(uMetallicRoughnessSampler, vUV[uMetallicRoughnessTexCoordIndex]);\n"
+  "  metallic = metrou.b * metallic;\n"
+  "  perceptualRoughness = metrou.g * perceptualRoughness;\n"
+  "#endif\n"
+
+  "  metallic = clamp(metallic, 0.0, 1.0);\n"
+  "  perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);\n"
+  // Roughness is authored as perceptual roughness; as is convention,
+  // convert to material roughness by squaring the perceptual roughness [2].
+  "  lowp float alphaRoughness = perceptualRoughness * perceptualRoughness;\n"
+
+  "#ifdef TEXTURE_BASECOLOR\n"
+  // The albedo may be defined from a base texture or a flat color
+  "  lowp vec4 baseColor = texture(uBaseColorSampler, vUV[uBaseColorTexCoordIndex]) * uBaseColorFactor;\n"
+  "  baseColor = vec4(linear(baseColor.rgb), baseColor.w);\n"
+  "#else\n"
+  "  lowp vec4 baseColor = vColor * uBaseColorFactor;\n"
+  "#endif\n"
+
+  "  if( alphaMode == 0 )\n"
+  "  {\n"
+  "    baseColor.w = 1.0;\n"
+  "  }\n"
+  "  else if( alphaMode == 1 )\n"
+  "  {\n"
+  "    if( baseColor.w >= alphaCutoff )"
+  "    {\n"
+  "      baseColor.w = 1.0;\n"
+  "    }\n"
+  "    else\n"
+  "    {\n"
+  "      baseColor.w = 0.0;\n"
+  "    }\n"
+  "  }\n"
+
+  "  lowp vec3 f0 = vec3(0.04);\n"
+  "  lowp vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);\n"
+  "  diffuseColor *= ( 1.0 - metallic );\n"
+  "  lowp vec3 specularColor = mix(f0, baseColor.rgb, metallic);\n"
+
+  // Compute reflectance.
+  "  lowp float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n"
+
+  // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+  // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+  "  lowp float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);\n"
+  "  lowp vec3 specularEnvironmentR0 = specularColor.rgb;\n"
+  "  lowp vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;\n"
+
+  "  mediump vec3 n = getNormal();\n"                            // normal at surface point
+  "  mediump vec3 v = normalize(vPositionToCamera);\n"           // Vector from surface point to camera
+  "  mediump vec3 l = normalize(vLightDirection);\n"             // Vector from light to surface point
+  "  mediump vec3 h = normalize(l+v);\n"                         // Half vector between both l and v
+  "  mediump vec3 reflection = -normalize(reflect(v, n));\n"
+
+  "  mediump float NdotL = clamp(dot(n, l), 0.001, 1.0);\n"
+  "  mediump float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);\n"
+  "  mediump float NdotH = dot(n, h);\n"
+  "  mediump float LdotH = dot(l, h);\n"
+  "  mediump float VdotH = dot(v, h);\n"
+
+  "  PBRInfo pbrInputs = PBRInfo(\n"
+  "    NdotL,\n"
+  "    NdotV,\n"
+  "    NdotH,\n"
+  "    VdotH,\n"
+  "    specularEnvironmentR0,\n"
+  "    specularEnvironmentR90,\n"
+  "    alphaRoughness\n"
+  "  );\n"
+
+  // Calculate the shading terms for the microfacet specular shading model
+  "  lowp vec3 color = vec3(0.0);\n"
+  "  if( visLight == 1 )\n"
+  "  {\n"
+  "    lowp vec3 F = specularReflection( pbrInputs );\n"
+  "    lowp float G = geometricOcclusion( pbrInputs );\n"
+  "    lowp float D = microfacetDistribution( pbrInputs );\n"
+
+  // Calculation of analytical lighting contribution
+  "    lowp vec3 diffuseContrib = ( 1.0 - F ) * ( diffuseColor / M_PI );\n"
+  "    lowp vec3 specContrib = F * G * D / ( 4.0 * NdotL * NdotV );\n"
+  // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law)
+  "    color = NdotL * uLightColor * (diffuseContrib + specContrib);\n"
+  "  }\n"
+
+  "#ifdef TEXTURE_IBL\n"
+  "  lowp float lod = ( perceptualRoughness * uMipmapLevel );\n"
+  // retrieve a scale and bias to F0. See [1], Figure 3
+  "  lowp vec3 brdf = linear( texture( ubrdfLUT, vec2( NdotV, 1.0 - perceptualRoughness ) ).rgb );\n"
+  "  lowp vec3 diffuseLight = linear( texture( uDiffuseEnvSampler, n ).rgb );\n"
+  "  lowp vec3 specularLight = linear( textureLod( uSpecularEnvSampler, reflection, lod ).rgb );\n"
+
+  "  lowp vec3 diffuse = diffuseLight * diffuseColor * uScaleIBLAmbient.x;\n"
+  "  lowp vec3 specular = specularLight * ( specularColor * brdf.x + brdf.y ) * uScaleIBLAmbient.y;\n"
+  "  color += ( diffuse + specular );\n"
+  "#endif\n"
+
+  "#ifdef TEXTURE_OCCLUSION\n"
+  "  lowp float ao = texture( uOcclusionSampler, vUV[uOcclusionTexCoordIndex] ).r;\n"
+  "  color = mix( color, color * ao, uOcclusionStrength );\n"
+  "#endif\n"
+
+  "#ifdef TEXTURE_EMIT\n"
+  "  lowp vec3 emissive = linear( texture( uEmissiveSampler, vUV[uEmissiveTexCoordIndex] ).rgb ) * uEmissiveFactor;\n"
+  "  color += emissive;\n"
+  "#endif\n"
+
+  "  FragColor = vec4( pow( color,vec3( 1.0 / 2.2 ) ), baseColor.a );\n"
+  "}\n"
+};
+
+} // namespace internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GLTF_SHADER_H
\ No newline at end of file
diff --git a/dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.cpp b/dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.cpp
new file mode 100644 (file)
index 0000000..990aedf
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const char* const IMAGE_BRDF_FILE_NAME = "brdfLUT.png";
+
+// glTF file extension
+const std::string GLTF_EXT( ".gltf" );
+
+/**
+ * cube map face index
+ */
+const uint32_t CUBEMAP_INDEX_X[2][6] = { { 2, 0, 1, 1, 1, 3 }, { 0, 1, 2, 3, 4, 5 } };
+const uint32_t CUBEMAP_INDEX_Y[2][6] = { { 1, 1, 0, 2, 1, 1 }, { 0, 0, 0, 0, 0, 0 } };
+
+}//namespace
+
+Scene3dView::Scene3dView()
+  : Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mRoot( Actor::New() ),
+  mShaderArray(),
+  mCameraActorArray(),
+  mDefaultCamera( CameraActor::New() ),
+  mAnimationArray(),
+  mLightType( Toolkit::Scene3dView::LightType::NONE ),
+  mLightVector( Vector3::ONE ),
+  mLightColor( Vector3::ONE )
+{
+}
+
+Scene3dView::~Scene3dView()
+{
+}
+
+Toolkit::Scene3dView Scene3dView::New( const std::string& filePath )
+{
+  Scene3dView* impl = new Scene3dView();
+
+  Dali::Toolkit::Scene3dView handle = Dali::Toolkit::Scene3dView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->mFilePath = filePath;
+  impl->Initialize();
+
+  return handle;
+}
+
+Toolkit::Scene3dView Scene3dView::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor )
+{
+  Scene3dView* impl = new Scene3dView();
+
+  Dali::Toolkit::Scene3dView handle = Dali::Toolkit::Scene3dView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->mFilePath = filePath;
+  impl->SetCubeMap( diffuseTexturePath, specularTexturePath, scaleFactor );
+  impl->Initialize();
+
+  return handle;
+}
+
+bool Scene3dView::CreateScene()
+{
+  if( std::string::npos != mFilePath.rfind( GLTF_EXT ) )
+  {
+    Internal::Gltf::Loader gltfloader;
+    return( gltfloader.LoadScene( mFilePath, *this ) );
+  }
+
+  return false;
+}
+
+uint32_t Scene3dView::GetAnimationCount()
+{
+  return mAnimationArray.size();
+}
+
+bool Scene3dView::PlayAnimation( uint32_t index )
+{
+  if( GetAnimationCount() <= index )
+  {
+    return false;
+  }
+
+  mAnimationArray[index].Play();
+  return true;
+}
+
+bool Scene3dView::PlayAnimations()
+{
+  for( auto&& animation : mAnimationArray )
+  {
+    animation.Play();
+  }
+
+  return true;
+}
+
+bool Scene3dView::SetLight( Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor )
+{
+  if( type > Toolkit::Scene3dView::LightType::DIRECTIONAL_LIGHT )
+  {
+    return false;
+  }
+
+  mLightType = static_cast<Toolkit::Scene3dView::LightType>(
+               ( mLightType >= Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT ) ?
+               Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT + type :
+               type );
+
+  mLightVector = lightVector;
+  mLightColor = lightColor;
+
+  for( auto&& shader : mShaderArray )
+  {
+    shader.RegisterProperty( "uLightType", ( GetLightType() & ~Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT ) );
+    shader.RegisterProperty( "uLightVector", lightVector );
+    shader.RegisterProperty( "uLightColor", lightColor );
+  }
+
+  return true;
+}
+
+uint8_t* Scene3dView::GetCroppedBuffer( uint8_t* sourceBuffer, uint32_t bytesPerPixel, uint32_t width, uint32_t height, uint32_t xOffset, uint32_t yOffset, uint32_t xFaceSize, uint32_t yFaceSize )
+{
+  uint32_t byteSize = bytesPerPixel * xFaceSize * yFaceSize;
+  uint8_t* destBuffer = reinterpret_cast<uint8_t*>( malloc( byteSize + 4u ) );
+
+  int32_t srcStride = width * bytesPerPixel;
+  int32_t destStride = xFaceSize * bytesPerPixel;
+  int32_t srcOffset = xOffset * bytesPerPixel + yOffset * srcStride;
+  int32_t destOffset = 0;
+  for( uint16_t row = yOffset; row < yOffset + yFaceSize; ++row )
+  {
+    memcpy( destBuffer + destOffset, sourceBuffer + srcOffset, destStride );
+    srcOffset += srcStride;
+    destOffset += destStride;
+  }
+
+  return destBuffer;
+}
+
+void Scene3dView::UploadTextureFace( Texture& texture, Devel::PixelBuffer pixelBuffer, uint32_t faceIndex )
+{
+  uint8_t* imageBuffer = pixelBuffer.GetBuffer();
+  uint32_t bytesPerPixel = Pixel::GetBytesPerPixel( pixelBuffer.GetPixelFormat() );
+  uint32_t imageWidth = pixelBuffer.GetWidth();
+  uint32_t imageHeight = pixelBuffer.GetHeight();
+
+  CubeType cubeType = ( imageWidth / 4 == imageHeight / 3 ) ? CROSS_HORIZONTAL :
+    ( ( imageWidth / 6 == imageHeight ) ? ARRAY_HORIZONTAL : NONE );
+
+  uint32_t faceSize = 0;
+  if( cubeType == CROSS_HORIZONTAL )
+  {
+    faceSize = imageWidth / 4;
+  }
+  else if( cubeType == ARRAY_HORIZONTAL )
+  {
+    faceSize = imageWidth / 6;
+  }
+  else
+  {
+    return;
+  }
+
+  uint32_t xOffset = CUBEMAP_INDEX_X[cubeType][faceIndex] * faceSize;
+  uint32_t yOffset = CUBEMAP_INDEX_Y[cubeType][faceIndex] * faceSize;
+
+  uint8_t* tempImageBuffer = GetCroppedBuffer( imageBuffer, bytesPerPixel, imageWidth, imageHeight, xOffset, yOffset, faceSize, faceSize );
+  PixelData pixelData = PixelData::New( tempImageBuffer, faceSize * faceSize * bytesPerPixel, faceSize, faceSize, pixelBuffer.GetPixelFormat(), PixelData::FREE );
+  texture.Upload( pixelData, CubeMapLayer::POSITIVE_X + faceIndex, 0, 0, 0, faceSize, faceSize );
+}
+
+void Scene3dView::SetCubeMap( const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor )
+{
+  mLightType = Toolkit::Scene3dView::LightType::IMAGE_BASED_LIGHT;
+
+  // BRDF texture
+  const std::string imageDirPath = AssetManager::GetDaliImagePath();
+  const std::string imageBrdfUrl = imageDirPath + IMAGE_BRDF_FILE_NAME;
+  mBRDFTexture = LoadTexture( imageBrdfUrl.c_str(), true );
+  if( !mBRDFTexture )
+  {
+    return;
+  }
+
+  // Diffuse Cube Map
+  Devel::PixelBuffer diffusePixelBuffer = LoadImageFromFile( diffuseTexturePath );
+  uint32_t diffuseFaceSize = diffusePixelBuffer.GetWidth() / 4;
+  mDiffuseTexture = Texture::New( TextureType::TEXTURE_CUBE, diffusePixelBuffer.GetPixelFormat(), diffuseFaceSize, diffuseFaceSize );
+  for( uint32_t i = 0; i < 6; ++i )
+  {
+    UploadTextureFace( mDiffuseTexture, diffusePixelBuffer, i );
+  }
+  mDiffuseTexture.GenerateMipmaps();
+
+  // Specular Cube Map
+  Devel::PixelBuffer specularPixelBuffer = LoadImageFromFile( specularTexturePath );
+  uint32_t specularFaceSize = specularPixelBuffer.GetWidth() / 4;
+  mSpecularTexture = Texture::New( TextureType::TEXTURE_CUBE, specularPixelBuffer.GetPixelFormat(), specularFaceSize, specularFaceSize );
+  for( uint32_t i = 0; i < 6; ++i )
+  {
+    UploadTextureFace( mSpecularTexture, specularPixelBuffer, i );
+  }
+  mSpecularTexture.GenerateMipmaps();
+
+  mIBLScaleFactor = scaleFactor;
+}
+
+bool Scene3dView::SetDefaultCamera( const Dali::Camera::Type type, const float nearPlane, const Vector3 cameraPosition )
+{
+  mDefaultCamera.SetParentOrigin( ParentOrigin::CENTER );
+  mDefaultCamera.SetAnchorPoint( AnchorPoint::CENTER );
+  mDefaultCamera.SetType( type );
+  mDefaultCamera.SetNearClippingPlane( nearPlane );
+  mDefaultCamera.SetPosition( cameraPosition );
+  return true;
+}
+
+void Scene3dView::AddCamera( CameraActor cameraActor )
+{
+  mCameraActorArray.push_back( cameraActor );
+}
+
+void Scene3dView::AddAnimation( Animation animation )
+{
+  mAnimationArray.push_back( animation );
+}
+
+void Scene3dView::AddShader( Shader shader )
+{
+  mShaderArray.push_back( shader );
+}
+
+Actor Scene3dView::GetRoot()
+{
+  return mRoot;
+}
+
+CameraActor Scene3dView::GetDefaultCamera()
+{
+  return mDefaultCamera;
+}
+
+uint32_t Scene3dView::GetCameraCount()
+{
+  return mCameraActorArray.size();
+}
+
+CameraActor Scene3dView::GetCamera( uint32_t cameraIndex )
+{
+  CameraActor cameraActor;
+  if( cameraIndex >= mCameraActorArray.size() )
+  {
+    return cameraActor;
+  }
+  cameraActor = mCameraActorArray[cameraIndex];
+  return cameraActor;
+}
+
+Toolkit::Scene3dView::LightType Scene3dView::GetLightType()
+{
+  return mLightType;
+}
+
+Vector3 Scene3dView::GetLightVector()
+{
+  return mLightVector;
+}
+
+Vector3 Scene3dView::GetLightColor()
+{
+  return mLightColor;
+}
+
+Vector4 Scene3dView::GetIBLScaleFactor()
+{
+  return mIBLScaleFactor;
+}
+
+Texture Scene3dView::GetBRDFTexture()
+{
+  return mBRDFTexture;
+}
+
+Texture Scene3dView::GetSpecularTexture()
+{
+  return mSpecularTexture;
+}
+
+Texture Scene3dView::GetDiffuseTexture()
+{
+  return mDiffuseTexture;
+}
+
+Texture Scene3dView::LoadTexture( const char *imageUrl, bool generateMipmaps )
+{
+  Texture texture;
+
+  Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
+  if( pixelBuffer )
+  {
+    texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+    PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+    texture.Upload( pixelData );
+
+    if( generateMipmaps )
+    {
+      texture.GenerateMipmaps();
+    }
+  }
+
+  return texture;
+}
+
+void Scene3dView::OnInitialize()
+{
+  mRoot.SetParentOrigin( ParentOrigin::CENTER );
+  mRoot.SetAnchorPoint( AnchorPoint::CENTER );
+
+  Layer layer = Layer::New();
+  layer.SetBehavior( Layer::LAYER_3D );
+  layer.SetParentOrigin( ParentOrigin::CENTER );
+  layer.SetAnchorPoint( AnchorPoint::CENTER );
+  layer.Add( mRoot );
+
+  Actor self = Self();
+  // Apply some default resizing rules.
+  self.SetParentOrigin( ParentOrigin::CENTER );
+  self.SetAnchorPoint( AnchorPoint::CENTER );
+  self.Add( layer );
+
+  CreateScene();
+}
+
+}//namespace Internal
+
+}//namespace Toolkit
+
+}//namespace Dali
+
diff --git a/dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h b/dali-toolkit/internal/controls/scene3d-view/scene3d-view-impl.h
new file mode 100644 (file)
index 0000000..afe95fd
--- /dev/null
@@ -0,0 +1,276 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCENE3D_VIEW_H\r
+#define DALI_TOOLKIT_INTERNAL_SCENE3D_VIEW_H\r
+\r
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <cstring>\r
+#include <dali/public-api/object/base-object.h>\r
+#include <dali/public-api/rendering/shader.h>\r
+#include <dali/devel-api/adaptor-framework/image-loading.h>\r
+#include <dali/devel-api/adaptor-framework/file-loader.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali-toolkit/public-api/controls/control-impl.h>\r
+#include <dali-toolkit/devel-api/controls/scene3d-view/scene3d-view.h>\r
+#include <dali-toolkit/internal/controls/scene3d-view/gltf-loader.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Toolkit\r
+{\r
+\r
+class Scene3dView;\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Gltf\r
+{\r
+\r
+class Loader;\r
+\r
+}\r
+\r
+/**\r
+ * Scene3dView implementation class\r
+ */\r
+class Scene3dView : public Control\r
+{\r
+public:\r
+\r
+  enum CubeType\r
+  {\r
+    CROSS_HORIZONTAL = 0,                 // Cross horizontal style cube map\r
+    ARRAY_HORIZONTAL,                     // array horizontal style cube map\r
+    NONE\r
+  };\r
+\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::Scene3dView\r
+   */\r
+  Scene3dView();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::~Scene3dView\r
+   */\r
+  virtual ~Scene3dView();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::New( const std::string& filePath )\r
+   */\r
+  static Dali::Toolkit::Scene3dView New( const std::string& filePath );\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor )\r
+   */\r
+  static Dali::Toolkit::Scene3dView New( const std::string& filePath, const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor );\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::CreateScene()\r
+   */\r
+  bool CreateScene();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::GetAnimationCount()\r
+   */\r
+  uint32_t GetAnimationCount();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::PlayAnimation()\r
+   */\r
+  bool PlayAnimation( uint32_t index );\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::PlayAnimations()\r
+   */\r
+  bool PlayAnimations();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::SetLight( Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor )\r
+   */\r
+  bool SetLight( Toolkit::Scene3dView::LightType type, Vector3 lightVector, Vector3 lightColor );\r
+\r
+  /**\r
+   * @brief Set default CameraActor specified in the each scene format specification.\r
+   * Default input values are derived from glTF default camera format.\r
+   * with Dali::Camera::Type = Dali::Camera::LOOK_AT_TARGET,\r
+   * near clipping plane = 0.1,\r
+   * and camera position = Vector3( 0.0, 0.0, 0.0 ).\r
+   */\r
+  bool SetDefaultCamera( const Dali::Camera::Type type = Dali::Camera::LOOK_AT_TARGET, const float nearPlane = 0.1, const Vector3 cameraPosition = Vector3( 0.0, 0.0, 0.0 ) );\r
+\r
+  /**\r
+   * @brief Add CameraActor loaded from scene format file.\r
+   */\r
+  void AddCamera( CameraActor cameraActor );\r
+\r
+  /**\r
+   * @brief Add Animation loaded from scene format file.\r
+   */\r
+  void AddAnimation( Animation animation );\r
+\r
+  /**\r
+   * @brief Add new Shader.\r
+   * Actors can share same Shader if they use same properties.\r
+   * If a property changes in a shader, then the property of all actors that use the shader change.\r
+   */\r
+  void AddShader( Shader shader );\r
+\r
+  /**\r
+   * @brief Get Root Actor.\r
+   */\r
+  Actor GetRoot();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::GetDefaultCamera()\r
+   */\r
+  CameraActor GetDefaultCamera();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::GetCameraCount()\r
+   */\r
+  uint32_t GetCameraCount();\r
+\r
+  /**\r
+   * @copydoc Dali::Toolkit::Scene3dView::GetCamera( uint32_t cameraIndex )\r
+   */\r
+  CameraActor GetCamera( uint32_t cameraIndex );\r
+\r
+  /**\r
+   * @brief Get light type.\r
+   */\r
+  Toolkit::Scene3dView::LightType GetLightType();\r
+\r
+  /**\r
+   * @brief Get light vector.\r
+   * Return light position when light type is LightType::POINT_LIGHT\r
+   * Return light direction when light type is LightType::DIRECTIONAL_LIGHT\r
+   */\r
+  Vector3 GetLightVector();\r
+\r
+  /**\r
+   * @brief Get light color.\r
+   */\r
+  Vector3 GetLightColor();\r
+\r
+  /**\r
+   * @brief Get Scaling factor of IBL.\r
+   */\r
+  Vector4 GetIBLScaleFactor();\r
+\r
+  /**\r
+   * @brief Get BRDF Texture.\r
+   */\r
+  Texture GetBRDFTexture();\r
+\r
+  /**\r
+   * @brief Get diffuse cube map texture.\r
+   */\r
+  Texture GetDiffuseTexture();\r
+\r
+  /**\r
+   * @brief Get specular cube map texture.\r
+   */\r
+  Texture GetSpecularTexture();\r
+\r
+private:\r
+  /**\r
+   * @brief Get Cropped image buffer.\r
+   * For each direction, Offset + faceSize must be width or height or less then them.\r
+   */\r
+  uint8_t* GetCroppedBuffer( uint8_t* sourceBuffer, uint32_t bytesPerPixel, uint32_t width, uint32_t height, uint32_t xOffset, uint32_t yOffset, uint32_t xFaceSize, uint32_t yFaceSize );\r
+\r
+  /**\r
+   * @brief Upload cube map texture.\r
+   */\r
+  void UploadTextureFace( Texture& texture, Devel::PixelBuffer pixelBuffer, uint32_t faceIndex );\r
+\r
+  /**\r
+   * @brief Set diffuse and specular cube map textures.\r
+   */\r
+  void SetCubeMap( const std::string& diffuseTexturePath, const std::string& specularTexturePath, Vector4 scaleFactor = Vector4( 1.0, 1.0, 1.0, 1.0 ) );\r
+\r
+  virtual void OnInitialize();\r
+\r
+\r
+  /**\r
+   * @brief Load 2D texture.\r
+   * @param[in] imageUrl Image URL of the texture.\r
+   * @param[in] generateMipmaps If generateMipmaps is true, then generate mipmap of this texture.\r
+   * @return Texture loaded from imageUrl.\r
+   */\r
+  Texture LoadTexture( const char *imageUrl, bool generateMipmaps );\r
+\r
+private:\r
+  Actor mRoot; // Root actor that contains scene graph\r
+  std::string mFilePath; // Full file path of scene file\r
+\r
+  std::vector<Shader> mShaderArray; // Shader Array to change properties of scene such as lighting.\r
+\r
+  std::vector<CameraActor> mCameraActorArray; // CameraActer array loaded from scene format file.\r
+  CameraActor mDefaultCamera; // Default CameraActor for the empty mCameraActorArray.\r
+\r
+  std::vector<Animation> mAnimationArray; // Animation array loaded from scene format file.\r
+\r
+  Toolkit::Scene3dView::LightType mLightType; // Light type\r
+  Vector3 mLightVector; // Light position when mLightType is LightType::POINT_LIGHT\r
+                        // Light direction when mLightType is LightType::DIRECTIONAL_LIGHT\r
+  Vector3 mLightColor; // Light color\r
+\r
+  Vector4 mIBLScaleFactor; // IBL scaling factor for the IBL rendering\r
+  Texture mBRDFTexture; // BRDF texture for the PBR rendering\r
+  Texture mSpecularTexture; // Specular cube map texture\r
+  Texture mDiffuseTexture; // Diffuse cube map texture\r
+\r
+private:\r
+\r
+  // Undefined copy constructor.\r
+  Scene3dView( const Scene3dView& );\r
+\r
+  // Undefined assignment operator.\r
+  Scene3dView& operator=( const Scene3dView& );\r
+};\r
+\r
+} // namespace Internal\r
+\r
+  // Helpers for public-api forwarding methods\r
+inline const Internal::Scene3dView& GetImpl( const Toolkit::Scene3dView& scene3dView )\r
+{\r
+  DALI_ASSERT_ALWAYS( scene3dView && "Scene3dView handle is empty" );\r
+  const Dali::RefObject& handle = scene3dView.GetImplementation();\r
+\r
+  return static_cast<const Toolkit::Internal::Scene3dView&>( handle );\r
+}\r
+\r
+inline Internal::Scene3dView& GetImpl( Toolkit::Scene3dView& scene3dView )\r
+{\r
+  DALI_ASSERT_ALWAYS( scene3dView && "Scene3dView handle is empty" );\r
+\r
+  Dali::RefObject& handle = scene3dView.GetImplementation();\r
+\r
+  return static_cast<Toolkit::Internal::Scene3dView&>( handle );\r
+}\r
+\r
+}//namespace Toolkit\r
+\r
+}//namespace Dali\r
+\r
+#endif // DALI_TOOLKIT_INTERNAL_SCENE3D_VIEW_H\r
diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp
new file mode 100755 (executable)
index 0000000..6b842fe
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+using namespace Dali;
+
+namespace
+{
+
+const char* DEFAULT_INDICATOR_IMAGE_FILE_NAME = "popup_scroll.9.png";
+const float DEFAULT_SLIDER_DEPTH(1.0f);
+const float DEFAULT_INDICATOR_SHOW_DURATION(0.5f);
+const float DEFAULT_INDICATOR_HIDE_DURATION(0.5f);
+const float DEFAULT_PAN_GESTURE_PROCESS_TIME(16.7f); // 16.7 milliseconds, i.e. one frame
+const float DEFAULT_INDICATOR_FIXED_HEIGHT(80.0f);
+const float DEFAULT_INDICATOR_MINIMUM_HEIGHT(0.0f);
+const float DEFAULT_INDICATOR_START_PADDING(0.0f);
+const float DEFAULT_INDICATOR_END_PADDING(0.0f);
+const float DEFAULT_INDICATOR_TRANSIENT_DURATION(1.0f);
+
+/**
+ * Indicator size constraint
+ * Indicator size depends on both indicator's parent size and the scroll content size
+ */
+struct IndicatorSizeConstraint
+{
+  /**
+   * @param[in] minimumHeight The minimum height for the indicator
+   * @param[in] padding The sum of the padding at the start & end of the indicator
+   */
+  IndicatorSizeConstraint( float minimumHeight, float padding )
+  : mMinimumHeight( minimumHeight ),
+    mPadding( padding )
+  {
+  }
+
+  /**
+   * Constraint operator
+   * @param[in] current The current indicator size
+   * @param[in] parentSizeProperty The parent size of scroll indicator.
+   * @return The new scroll indicator size.
+   */
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    const Vector3& parentSize = inputs[0]->GetVector3();
+    const float contentSize = inputs[1]->GetFloat();
+
+    // Take into account padding that may exist at the beginning and end of the indicator.
+    const float parentHeightMinusPadding = parentSize.height - mPadding;
+
+    float height = contentSize > parentHeightMinusPadding ?
+                   parentHeightMinusPadding * ( parentHeightMinusPadding / contentSize ) :
+                   parentHeightMinusPadding * ( ( parentHeightMinusPadding - contentSize * 0.5f ) / parentHeightMinusPadding );
+
+    current.y = std::max( mMinimumHeight, height );
+  }
+
+  float mMinimumHeight;
+  float mPadding;
+};
+
+/**
+ * Indicator position constraint
+ * Positions the indicator to reflect the current scroll position within the scroll domain.
+ */
+struct IndicatorPositionConstraint
+{
+  /**
+   * @param[in] startPadding The padding at the start of the indicator
+   * @param[in] endPadding The padding at the end of the indicator
+   */
+  IndicatorPositionConstraint( float startPadding, float endPadding )
+  : mStartPadding( startPadding ),
+    mEndPadding( endPadding )
+  {
+  }
+
+  /**
+   * Constraint operator
+   * @param[in,out] current The current indicator position
+   * @param[in] inputs Contains the size of indicator, the size of indicator's parent, and the scroll position of the scrollable container (from 0.0 -> 1.0 in each axis)
+   * @return The new indicator position is returned.
+   */
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    const Vector3& indicatorSize = inputs[0]->GetVector3();
+    const Vector3& parentSize = inputs[1]->GetVector3();
+    const float scrollPosition = -inputs[2]->GetFloat();
+    const float minimumScrollPosition = inputs[3]->GetFloat();
+    const float maximumScrollPosition = inputs[4]->GetFloat();
+
+    // Take into account padding that may exist at the beginning and end of the indicator.
+    const float parentHeightMinusPadding = parentSize.height - ( mStartPadding + mEndPadding );
+
+    float relativePosition = std::max( 0.0f, std::min( 1.0f, ( scrollPosition - minimumScrollPosition ) / ( maximumScrollPosition - minimumScrollPosition ) ) );
+    current.y = mStartPadding + ( parentHeightMinusPadding - indicatorSize.height ) * relativePosition;
+    current.z = DEFAULT_SLIDER_DEPTH;
+  }
+
+  float mStartPadding;
+  float mEndPadding;
+};
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+using namespace Dali;
+
+BaseHandle Create()
+{
+  return Toolkit::ScrollBar::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ScrollBar, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollDirection",                   STRING, SCROLL_DIRECTION             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHeightPolicy",             STRING, INDICATOR_HEIGHT_POLICY      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorFixedHeight",              FLOAT,  INDICATOR_FIXED_HEIGHT       )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorShowDuration",             FLOAT,  INDICATOR_SHOW_DURATION      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorHideDuration",             FLOAT,  INDICATOR_HIDE_DURATION      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "scrollPositionIntervals",           ARRAY,  SCROLL_POSITION_INTERVALS    )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorMinimumHeight",            FLOAT,  INDICATOR_MINIMUM_HEIGHT     )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorStartPadding",             FLOAT,  INDICATOR_START_PADDING      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorEndPadding",               FLOAT,  INDICATOR_END_PADDING        )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollBar, "indicatorTransientDuration",        FLOAT,  INDICATOR_TRANSIENT_DURATION )
+
+DALI_SIGNAL_REGISTRATION(   Toolkit, ScrollBar, "panFinished",                       PAN_FINISHED_SIGNAL                     )
+DALI_SIGNAL_REGISTRATION(   Toolkit, ScrollBar, "scrollPositionIntervalReached",     SCROLL_POSITION_INTERVAL_REACHED_SIGNAL )
+
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "ShowIndicator",                     ACTION_SHOW_INDICATOR                   )
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "HideIndicator",                     ACTION_HIDE_INDICATOR                   )
+DALI_ACTION_REGISTRATION(   Toolkit, ScrollBar, "ShowTransientIndicator",            ACTION_SHOW_TRANSIENT_INDICATOR         )
+
+DALI_TYPE_REGISTRATION_END()
+
+const char* SCROLL_DIRECTION_NAME[] = {"Vertical", "Horizontal"};
+const char* INDICATOR_HEIGHT_POLICY_NAME[] = {"Variable", "Fixed"};
+
+}
+
+ScrollBar::ScrollBar(Toolkit::ScrollBar::Direction direction)
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mIndicatorShowAlpha(1.0f),
+  mDirection(direction),
+  mScrollableObject(WeakHandleBase()),
+  mPropertyScrollPosition(Property::INVALID_INDEX),
+  mPropertyMinScrollPosition(Property::INVALID_INDEX),
+  mPropertyMaxScrollPosition(Property::INVALID_INDEX),
+  mPropertyScrollContentSize(Property::INVALID_INDEX),
+  mIndicatorShowDuration(DEFAULT_INDICATOR_SHOW_DURATION),
+  mIndicatorHideDuration(DEFAULT_INDICATOR_HIDE_DURATION),
+  mTransientIndicatorDuration(DEFAULT_INDICATOR_TRANSIENT_DURATION),
+  mScrollStart(0.0f),
+  mGestureDisplacement( Vector3::ZERO ),
+  mCurrentScrollPosition(0.0f),
+  mIndicatorHeightPolicy(Toolkit::ScrollBar::Variable),
+  mIndicatorFixedHeight(DEFAULT_INDICATOR_FIXED_HEIGHT),
+  mIndicatorMinimumHeight(DEFAULT_INDICATOR_MINIMUM_HEIGHT),
+  mIndicatorStartPadding(DEFAULT_INDICATOR_START_PADDING),
+  mIndicatorEndPadding(DEFAULT_INDICATOR_END_PADDING),
+  mIsPanning(false),
+  mIndicatorFirstShow(true)
+{
+}
+
+ScrollBar::~ScrollBar()
+{
+}
+
+void ScrollBar::OnInitialize()
+{
+  CreateDefaultIndicatorActor();
+  Self().SetDrawMode(DrawMode::OVERLAY_2D);
+}
+
+void ScrollBar::SetScrollPropertySource( Handle handle, Property::Index propertyScrollPosition, Property::Index propertyMinScrollPosition, Property::Index propertyMaxScrollPosition, Property::Index propertyScrollContentSize )
+{
+  if( handle
+      && propertyScrollPosition != Property::INVALID_INDEX
+      && propertyMinScrollPosition != Property::INVALID_INDEX
+      && propertyMaxScrollPosition != Property::INVALID_INDEX
+      && propertyScrollContentSize != Property::INVALID_INDEX )
+  {
+    mScrollableObject = WeakHandleBase(handle);
+    mPropertyScrollPosition = propertyScrollPosition;
+    mPropertyMinScrollPosition = propertyMinScrollPosition;
+    mPropertyMaxScrollPosition = propertyMaxScrollPosition;
+    mPropertyScrollContentSize = propertyScrollContentSize;
+
+    ApplyConstraints();
+  }
+  else
+  {
+    DALI_LOG_ERROR("Can not set empty handle of source object or invalid source property index\n");
+  }
+}
+
+void ScrollBar::CreateDefaultIndicatorActor()
+{
+  const std::string imageDirPath = AssetManager::GetDaliImagePath();
+  Toolkit::ImageView indicator = Toolkit::ImageView::New( imageDirPath + DEFAULT_INDICATOR_IMAGE_FILE_NAME );
+  indicator.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  indicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  indicator.SetStyleName( "ScrollBarIndicator" );
+  indicator.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+  SetScrollIndicator(indicator);
+}
+
+void ScrollBar::SetScrollIndicator( Actor indicator )
+{
+  // Don't allow empty handle
+  if( indicator )
+  {
+    // Remove current Indicator
+    if( mIndicator )
+    {
+      Self().Remove( mIndicator );
+    }
+    mIndicator = indicator;
+
+    mIndicatorFirstShow = true;
+    Self().Add( mIndicator );
+
+    EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
+
+    PanGestureDetector detector( GetPanGestureDetector() );
+    detector.DetachAll();
+    detector.Attach( mIndicator );
+
+    unsigned int childCount = mIndicator.GetChildCount();
+    for ( unsigned int index = 0; index < childCount; index++ )
+    {
+      Actor child = mIndicator.GetChildAt( index );
+      if ( child )
+      {
+        detector.Attach( child );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("Empty handle of scroll indicator\n");
+  }
+}
+
+Actor ScrollBar::GetScrollIndicator()
+{
+  return mIndicator;
+}
+
+void ScrollBar::ApplyConstraints()
+{
+  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+
+  if( scrollableHandle )
+  {
+    if(mIndicatorSizeConstraint)
+    {
+      mIndicatorSizeConstraint.Remove();
+    }
+
+    // Set indicator height according to the indicator's height policy
+    if(mIndicatorHeightPolicy == Toolkit::ScrollBar::Fixed)
+    {
+      mIndicator.SetSize(Self().GetCurrentSize().width, mIndicatorFixedHeight);
+    }
+    else
+    {
+      mIndicatorSizeConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::SIZE,
+                                                           IndicatorSizeConstraint( mIndicatorMinimumHeight, mIndicatorStartPadding + mIndicatorEndPadding ) );
+      mIndicatorSizeConstraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+      mIndicatorSizeConstraint.AddSource( Source( scrollableHandle, mPropertyScrollContentSize ) );
+      mIndicatorSizeConstraint.Apply();
+    }
+
+    if(mIndicatorPositionConstraint)
+    {
+      mIndicatorPositionConstraint.Remove();
+    }
+
+    mIndicatorPositionConstraint = Constraint::New<Vector3>( mIndicator, Actor::Property::POSITION,
+                                                             IndicatorPositionConstraint( mIndicatorStartPadding, mIndicatorEndPadding ) );
+    mIndicatorPositionConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+    mIndicatorPositionConstraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    mIndicatorPositionConstraint.AddSource( Source( scrollableHandle, mPropertyScrollPosition ) );
+    mIndicatorPositionConstraint.AddSource( Source( scrollableHandle, mPropertyMinScrollPosition ) );
+    mIndicatorPositionConstraint.AddSource( Source( scrollableHandle, mPropertyMaxScrollPosition ) );
+    mIndicatorPositionConstraint.Apply();
+  }
+}
+
+void ScrollBar::SetScrollPositionIntervals( const Dali::Vector<float>& positions )
+{
+  mScrollPositionIntervals = positions;
+
+  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+
+  if( scrollableHandle )
+  {
+    if( mPositionNotification )
+    {
+      scrollableHandle.RemovePropertyNotification(mPositionNotification);
+    }
+
+    mPositionNotification = scrollableHandle.AddPropertyNotification( mPropertyScrollPosition, VariableStepCondition(mScrollPositionIntervals) );
+    mPositionNotification.NotifySignal().Connect( this, &ScrollBar::OnScrollPositionIntervalReached );
+  }
+}
+
+Dali::Vector<float> ScrollBar::GetScrollPositionIntervals() const
+{
+  return mScrollPositionIntervals;
+}
+
+void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source)
+{
+  // Emit the signal to notify the scroll position crossing
+  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  if(scrollableHandle)
+  {
+    mScrollPositionIntervalReachedSignal.Emit( scrollableHandle.GetCurrentProperty< float >( mPropertyScrollPosition ) );
+  }
+}
+
+void ScrollBar::ShowIndicator()
+{
+  // Cancel any animation
+  if(mAnimation)
+  {
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+
+  if( mIndicatorFirstShow )
+  {
+    // Preserve the alpha value from the stylesheet
+    mIndicatorShowAlpha = Self().GetCurrentColor().a;
+    mIndicatorFirstShow = false;
+  }
+
+  if(mIndicatorShowDuration > 0.0f)
+  {
+    mAnimation = Animation::New( mIndicatorShowDuration );
+    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ), mIndicatorShowAlpha, AlphaFunction::EASE_IN );
+    mAnimation.Play();
+  }
+  else
+  {
+    mIndicator.SetOpacity(mIndicatorShowAlpha);
+  }
+}
+
+void ScrollBar::HideIndicator()
+{
+  // Cancel any animation
+  if(mAnimation)
+  {
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+
+  if(mIndicatorHideDuration > 0.0f)
+  {
+    mAnimation = Animation::New( mIndicatorHideDuration );
+    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN );
+    mAnimation.Play();
+  }
+  else
+  {
+    mIndicator.SetOpacity(0.0f);
+  }
+}
+
+void ScrollBar::ShowTransientIndicator()
+{
+  // Cancel any animation
+  if(mAnimation)
+  {
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+
+  mAnimation = Animation::New( mIndicatorShowDuration + mTransientIndicatorDuration + mIndicatorHideDuration );
+  if(mIndicatorShowDuration > 0.0f)
+  {
+    mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ),
+                          mIndicatorShowAlpha, AlphaFunction::EASE_IN, TimePeriod(0, mIndicatorShowDuration) );
+  }
+  else
+  {
+    mIndicator.SetOpacity(mIndicatorShowAlpha);
+  }
+  mAnimation.AnimateTo( Property( mIndicator, Actor::Property::COLOR_ALPHA ),
+                        0.0f, AlphaFunction::EASE_IN, TimePeriod((mIndicatorShowDuration + mTransientIndicatorDuration), mIndicatorHideDuration) );
+  mAnimation.Play();
+}
+
+bool ScrollBar::OnPanGestureProcessTick()
+{
+  // Update the scroll position property.
+  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+  if( scrollableHandle )
+  {
+    scrollableHandle.SetProperty(mPropertyScrollPosition, mCurrentScrollPosition);
+  }
+
+  return true;
+}
+
+void ScrollBar::OnPan( const PanGesture& gesture )
+{
+  Handle scrollableHandle = mScrollableObject.GetBaseHandle();
+
+  if(scrollableHandle)
+  {
+    Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast(scrollableHandle);
+
+    switch(gesture.state)
+    {
+      case Gesture::Started:
+      {
+        if( !mPanProcessTimer )
+        {
+          // Make sure the pan gesture is only being processed once per frame.
+          mPanProcessTimer = Timer::New( DEFAULT_PAN_GESTURE_PROCESS_TIME );
+          mPanProcessTimer.TickSignal().Connect( this, &ScrollBar::OnPanGestureProcessTick );
+          mPanProcessTimer.Start();
+        }
+
+        ShowIndicator();
+        mScrollStart = scrollableHandle.GetCurrentProperty< float >( mPropertyScrollPosition );
+        mGestureDisplacement = Vector3::ZERO;
+        mIsPanning = true;
+
+        break;
+      }
+      case Gesture::Continuing:
+      {
+        mGestureDisplacement.x += gesture.displacement.x;
+        mGestureDisplacement.y += gesture.displacement.y;
+
+        float minScrollPosition = scrollableHandle.GetCurrentProperty<float>( mPropertyMinScrollPosition );
+        float maxScrollPosition = scrollableHandle.GetCurrentProperty<float>( mPropertyMaxScrollPosition );
+
+        // The domain size is the internal range
+        float domainSize = maxScrollPosition - minScrollPosition;
+        float logicalSize = Self().GetCurrentSize().y - ( mIndicator.GetCurrentSize().y + mIndicatorStartPadding + mIndicatorEndPadding );
+
+        mCurrentScrollPosition = mScrollStart - ( ( mGestureDisplacement.y * domainSize ) / logicalSize );
+        mCurrentScrollPosition = -std::min( maxScrollPosition, std::max( -mCurrentScrollPosition, minScrollPosition ) );
+
+        break;
+      }
+      default:
+      {
+        mIsPanning = false;
+
+        if( mPanProcessTimer )
+        {
+          // Destroy the timer when pan gesture is finished.
+          mPanProcessTimer.Stop();
+          mPanProcessTimer.TickSignal().Disconnect( this, &ScrollBar::OnPanGestureProcessTick );
+          mPanProcessTimer.Reset();
+        }
+
+        if(itemView)
+        {
+          // Refresh the ItemView cache with extra items
+          GetImpl(itemView).DoRefresh(mCurrentScrollPosition, true);
+        }
+
+        mPanFinishedSignal.Emit();
+
+        break;
+      }
+    }
+
+    if(itemView)
+    {
+      // Disable automatic refresh in ItemView during fast scrolling
+      GetImpl(itemView).SetRefreshEnabled(!mIsPanning);
+    }
+  }
+}
+
+void ScrollBar::OnSizeSet( const Vector3& size )
+{
+  if(mIndicatorHeightPolicy == Toolkit::ScrollBar::Fixed)
+  {
+    mIndicator.SetSize(size.width, mIndicatorFixedHeight);
+  }
+
+  Control::OnSizeSet( size );
+}
+
+void ScrollBar::SetScrollDirection( Toolkit::ScrollBar::Direction direction )
+{
+  mDirection = direction;
+}
+
+Toolkit::ScrollBar::Direction ScrollBar::GetScrollDirection() const
+{
+  return mDirection;
+}
+
+void ScrollBar::SetIndicatorHeightPolicy( Toolkit::ScrollBar::IndicatorHeightPolicy policy )
+{
+  if( policy != mIndicatorHeightPolicy )
+  {
+    mIndicatorHeightPolicy = policy;
+    ApplyConstraints();
+  }
+}
+
+Toolkit::ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy() const
+{
+  return mIndicatorHeightPolicy;
+}
+
+void ScrollBar::SetIndicatorFixedHeight( float height )
+{
+  mIndicatorFixedHeight = height;
+
+  if(mIndicatorHeightPolicy == Toolkit::ScrollBar::Fixed)
+  {
+    mIndicator.SetSize(Self().GetCurrentSize().width, mIndicatorFixedHeight);
+  }
+}
+
+float ScrollBar::GetIndicatorFixedHeight() const
+{
+  return mIndicatorFixedHeight;
+}
+
+void ScrollBar::SetIndicatorShowDuration( float durationSeconds )
+{
+  mIndicatorShowDuration = durationSeconds;
+}
+
+float ScrollBar::GetIndicatorShowDuration() const
+{
+  return mIndicatorShowDuration;
+}
+
+void ScrollBar::SetIndicatorHideDuration( float durationSeconds )
+{
+  mIndicatorHideDuration = durationSeconds;
+}
+
+float ScrollBar::GetIndicatorHideDuration() const
+{
+  return mIndicatorHideDuration;
+}
+
+void ScrollBar::OnScrollDirectionPropertySet( Property::Value propertyValue )
+{
+  std::string directionName( propertyValue.Get<std::string>() );
+  if(directionName == "Vertical")
+  {
+    SetScrollDirection(Toolkit::ScrollBar::Vertical);
+  }
+  else if(directionName == "Horizontal")
+  {
+    SetScrollDirection(Toolkit::ScrollBar::Horizontal);
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( !"ScrollBar::OnScrollDirectionPropertySet(). Invalid Property value." );
+  }
+}
+
+void ScrollBar::OnIndicatorHeightPolicyPropertySet( Property::Value propertyValue )
+{
+  std::string policyName( propertyValue.Get<std::string>() );
+  if(policyName == "Variable")
+  {
+    SetIndicatorHeightPolicy(Toolkit::ScrollBar::Variable);
+  }
+  else if(policyName == "Fixed")
+  {
+    SetIndicatorHeightPolicy(Toolkit::ScrollBar::Fixed);
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( !"ScrollBar::OnIndicatorHeightPolicyPropertySet(). Invalid Property value." );
+  }
+}
+
+bool ScrollBar::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), PAN_FINISHED_SIGNAL ) )
+  {
+    scrollBar.PanFinishedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SCROLL_POSITION_INTERVAL_REACHED_SIGNAL ) )
+  {
+    scrollBar.ScrollPositionIntervalReachedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void ScrollBar::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollBar )
+  {
+    ScrollBar& scrollBarImpl( GetImpl( scrollBar ) );
+    switch( index )
+    {
+      case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
+      {
+        scrollBarImpl.OnScrollDirectionPropertySet( value );
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
+      {
+        scrollBarImpl.OnIndicatorHeightPolicyPropertySet( value );
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
+      {
+        scrollBarImpl.SetIndicatorFixedHeight(value.Get<float>());
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
+      {
+        scrollBarImpl.SetIndicatorShowDuration(value.Get<float>());
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
+      {
+        scrollBarImpl.SetIndicatorHideDuration(value.Get<float>());
+        break;
+      }
+      case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
+      {
+        Property::Array* array = value.GetArray();
+        if( array )
+        {
+          Dali::Vector<float> positions;
+          size_t positionCount = array->Count();
+          positions.Resize( positionCount );
+          for( size_t i = 0; i != positionCount; ++i )
+          {
+            array->GetElementAt( i ).Get( positions[i] );
+          }
+
+          scrollBarImpl.SetScrollPositionIntervals(positions);
+        }
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
+      {
+        scrollBarImpl.mIndicatorMinimumHeight = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
+      {
+        scrollBarImpl.mIndicatorStartPadding = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
+      {
+        scrollBarImpl.mIndicatorEndPadding = value.Get<float>();
+        scrollBarImpl.ApplyConstraints();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
+      {
+        scrollBarImpl.mTransientIndicatorDuration = value.Get<float>();
+        break;
+      }
+    }
+  }
+}
+
+Property::Value ScrollBar::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollBar )
+  {
+    ScrollBar& scrollBarImpl( GetImpl( scrollBar ) );
+    switch( index )
+    {
+      case Toolkit::ScrollBar::Property::SCROLL_DIRECTION:
+      {
+        value = SCROLL_DIRECTION_NAME[ scrollBarImpl.GetScrollDirection() ];
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_HEIGHT_POLICY:
+      {
+        value = INDICATOR_HEIGHT_POLICY_NAME[ scrollBarImpl.GetIndicatorHeightPolicy() ];
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_FIXED_HEIGHT:
+      {
+        value = scrollBarImpl.GetIndicatorFixedHeight();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_SHOW_DURATION:
+      {
+        value = scrollBarImpl.GetIndicatorShowDuration();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_HIDE_DURATION:
+      {
+        value = scrollBarImpl.GetIndicatorHideDuration();
+        break;
+      }
+      case Toolkit::ScrollBar::Property::SCROLL_POSITION_INTERVALS:
+      {
+        Property::Value tempValue( Property::ARRAY );
+        Property::Array* array = tempValue.GetArray();
+
+        if( array )
+        {
+          Dali::Vector<float> positions = scrollBarImpl.GetScrollPositionIntervals();
+          size_t positionCount( positions.Count() );
+
+          for( size_t i( 0 ); i != positionCount; ++i )
+          {
+            array->PushBack( positions[i] );
+          }
+
+          value = tempValue;
+        }
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_MINIMUM_HEIGHT:
+      {
+        value = scrollBarImpl.mIndicatorMinimumHeight;
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_START_PADDING:
+      {
+        value = scrollBarImpl.mIndicatorStartPadding;
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_END_PADDING:
+      {
+        value = scrollBarImpl.mIndicatorEndPadding;
+        break;
+      }
+      case Toolkit::ScrollBar::Property::INDICATOR_TRANSIENT_DURATION:
+      {
+        value = scrollBarImpl.mTransientIndicatorDuration;
+        break;
+      }
+    }
+  }
+  return value;
+}
+
+bool ScrollBar::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  Dali::BaseHandle handle( object );
+
+  Toolkit::ScrollBar scrollBar = Toolkit::ScrollBar::DownCast( handle );
+
+  DALI_ASSERT_DEBUG( scrollBar );
+
+  if( scrollBar )
+  {
+    if( 0 == strcmp( actionName.c_str(), ACTION_SHOW_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).ShowIndicator();
+      ret = true;
+    }
+    else if( 0 == strcmp( actionName.c_str(), ACTION_HIDE_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).HideIndicator();
+      ret = true;
+    }
+    else if( 0 == strcmp( actionName.c_str(), ACTION_SHOW_TRANSIENT_INDICATOR ) )
+    {
+      GetImpl( scrollBar ).ShowTransientIndicator();
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+Toolkit::ScrollBar ScrollBar::New(Toolkit::ScrollBar::Direction direction)
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< ScrollBar > impl = new ScrollBar(direction);
+
+  // Pass ownership to CustomActor handle
+  Toolkit::ScrollBar handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h
new file mode 100755 (executable)
index 0000000..a46808c
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_BAR_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_BAR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ScrollBar;
+
+typedef IntrusivePtr<ScrollBar> ScrollBarPtr;
+
+/**
+ * ScrollBar is a UI component that can be added to the scrollable controls
+ * indicating the current scroll position of the scrollable content.
+ */
+class ScrollBar : public Control
+{
+
+public:
+
+  // Signals
+  typedef Toolkit::ScrollBar::PanFinishedSignalType PanFinishedSignalType;
+  typedef Toolkit::ScrollBar::ScrollPositionIntervalReachedSignalType ScrollPositionIntervalReachedSignalType;
+
+public:
+
+  /**
+   * @copydoc Toolkit::ScrollBar::New()
+   */
+  static Toolkit::ScrollBar New(Toolkit::ScrollBar::Direction direction);
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetScrollPropertySource()
+   */
+  void SetScrollPropertySource( Handle handle, Property::Index propertyScrollPosition, Property::Index propertyMinScrollPosition, Property::Index propertyMaxScrollPosition, Property::Index propertyScrollContentSize );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetScrollIndicator()
+   */
+  void SetScrollIndicator( Actor indicator );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetScrollIndicator()
+   */
+  Actor GetScrollIndicator();
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetScrollPositionIntervals()
+   */
+  void SetScrollPositionIntervals( const Dali::Vector<float>& positions );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetScrollPositionIntervals()
+   */
+  Dali::Vector<float> GetScrollPositionIntervals() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetScrollDirection()
+   */
+  void SetScrollDirection( Toolkit::ScrollBar::Direction direction );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetScrollDirection()
+   */
+  Toolkit::ScrollBar::Direction GetScrollDirection() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetIndicatorHeightPolicy()
+   */
+  void SetIndicatorHeightPolicy( Toolkit::ScrollBar::IndicatorHeightPolicy policy );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetIndicatorHeightPolicy()
+   */
+  Toolkit::ScrollBar::IndicatorHeightPolicy GetIndicatorHeightPolicy() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetIndicatorFixedHeight()
+   */
+  void SetIndicatorFixedHeight( float height );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetIndicatorFixedHeight()
+   */
+  float GetIndicatorFixedHeight() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetIndicatorShowDuration()
+   */
+  void SetIndicatorShowDuration( float durationSeconds );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetIndicatorShowDuration()
+   */
+  float GetIndicatorShowDuration() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::SetIndicatorHideDuration()
+   */
+  void SetIndicatorHideDuration( float durationSeconds );
+
+  /**
+   * @copydoc Toolkit::ScrollBar::GetIndicatorHideDuration()
+   */
+  float GetIndicatorHideDuration() const;
+
+  /**
+   * @copydoc Toolkit::ScrollBar::ShowIndicator()
+   */
+  void ShowIndicator();
+
+  /**
+   * @copydoc Toolkit::ScrollBar::HideIndicator()
+   */
+  void HideIndicator();
+
+  /**
+   * @brief Shows indicator until the transient duration has expired
+   */
+  void ShowTransientIndicator();
+
+ /**
+  * @copydoc Toolkit::ScrollBar::PanFinishedSignal()
+  */
+ PanFinishedSignalType& PanFinishedSignal()
+ {
+   return mPanFinishedSignal;
+ }
+
+ /**
+  * @copydoc Toolkit::ScrollBar::ScrollPositionIntervalReachedSignal()
+  */
+ ScrollPositionIntervalReachedSignalType& ScrollPositionIntervalReachedSignal()
+ {
+   return mScrollPositionIntervalReachedSignal;
+ }
+
+ /**
+  * Connects a callback function with the object's signals.
+  * @param[in] object The object providing the signal.
+  * @param[in] tracker Used to disconnect the signal.
+  * @param[in] signalName The signal to connect to.
+  * @param[in] functor A newly allocated FunctorDelegate.
+  * @return True if the signal was connected.
+  * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+  */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+ // Properties
+
+ /**
+  * Called when a property of an object of this type is set.
+  * @param[in] object The object whose property is set.
+  * @param[in] index The property index.
+  * @param[in] value The new property value.
+  */
+ static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+ /**
+  * Called to retrieve a property of an object of this type.
+  * @param[in] object The object whose property is to be retrieved.
+  * @param[in] index The property index.
+  * @return The current value of the property.
+  */
+ static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+ /**
+  * Performs actions as requested using the action name.
+  * @param[in] object The object on which to perform the action.
+  * @param[in] actionName The action to perform.
+  * @param[in] attributes The attributes with which to perfrom this action.
+  * @return true if action has been accepted by this control
+  */
+ static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes );
+
+private: // from Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::OnPan
+   */
+  virtual void OnPan( const PanGesture& gesture );
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet( const Vector3& size )
+   */
+  virtual void OnSizeSet( const Vector3& size );
+
+private:
+
+  /**
+   * Create the default indicator actor.
+   */
+  void CreateDefaultIndicatorActor();
+
+  /**
+   * Apply constraints for background and indicator.
+   * These constraints are based on values from the scroll connector.
+   */
+  void ApplyConstraints();
+
+  /**
+   * Callback when the current scroll position of the scrollable content goes above or
+   * below the values specified by SetScrollPositionIntervals().
+   * @param[in] source the property notification that triggered this callback
+   */
+  void OnScrollPositionIntervalReached(PropertyNotification& source);
+
+  /**
+   * Process the pan gesture per predefined timeout until the gesture is finished.
+   * @return True if the timer should be kept running.
+   */
+  bool OnPanGestureProcessTick();
+
+  /**
+   * Handle SetProperty for scroll direction.
+   * @param[in] propertyValue The new property value.
+   */
+  void OnScrollDirectionPropertySet(Property::Value propertyValue);
+
+  /**
+   * Handle SetProperty for scroll indicator height policy.
+   * @param[in] propertyValue The new property value.
+   */
+  void OnIndicatorHeightPolicyPropertySet(Property::Value propertyValue);
+
+private:
+
+  /**
+   * Constructor.
+   * It initializes ScrollBar members.
+   */
+  ScrollBar( Toolkit::ScrollBar::Direction direction );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ScrollBar();
+
+private:
+
+  Actor mIndicator;                                                  ///< Image of scroll indicator.
+  float mIndicatorShowAlpha;                                         ///< The alpha value when the indicator is fully shown
+  Animation mAnimation;                                              ///< Scroll indicator Show/Hide Animation.
+
+  Toolkit::ScrollBar::Direction mDirection;                          ///< The direction of scroll bar (vertical or horizontal)
+
+  WeakHandleBase mScrollableObject;                                  ///< Object to be scrolled
+
+  Property::Index mPropertyScrollPosition;                           ///< Index of scroll position property owned by the object to be scrolled
+  Property::Index mPropertyMinScrollPosition;                        ///< Index of minimum scroll position property owned by the object to be scrolled
+  Property::Index mPropertyMaxScrollPosition;                        ///< Index of maximum scroll position property owned by the object to be scrolled
+  Property::Index mPropertyScrollContentSize;                        ///< Index of scroll content size property owned by the object to be scrolled
+
+  float mIndicatorShowDuration;                                      ///< The duration of scroll indicator show animation
+  float mIndicatorHideDuration;                                      ///< The duration of scroll indicator hide animation
+  float mTransientIndicatorDuration;                                 ///< The duration before hiding transient indicator
+
+  float mScrollStart;                                                ///< Scroll Start position (start of drag)
+  Vector3 mGestureDisplacement;                                      ///< Gesture Displacement.
+
+  float mCurrentScrollPosition;                                      ///< The current scroll position updated by the pan gesture
+
+  Toolkit::ScrollBar::IndicatorHeightPolicy mIndicatorHeightPolicy;  ///< The height policy of scroll indicator (variable or fixed)
+  float mIndicatorFixedHeight;                                       ///< The fixed height of scroll indicator
+  float mIndicatorMinimumHeight;                                     ///< The minimum height for a variable size indicator
+  float mIndicatorStartPadding;                                      ///< The padding at the start of the indicator
+  float mIndicatorEndPadding;                                        ///< The padding at the end of the indicator
+
+  Timer mContractDelayTimer;                                         ///< Timer guarantee contract delay time.
+  Timer mPanProcessTimer;                                            ///< The timer to process the pan gesture after the gesture is started.
+
+  Dali::Vector<float> mScrollPositionIntervals;                      ///< List of values to receive notification for when the current scroll position goes above or below them
+  PropertyNotification mPositionNotification;                        ///< Stores the property notification used for scroll position changes
+
+  PanFinishedSignalType mPanFinishedSignal;
+  ScrollPositionIntervalReachedSignalType mScrollPositionIntervalReachedSignal;
+
+  Constraint mIndicatorPositionConstraint;
+  Constraint mIndicatorSizeConstraint;
+
+  bool mIsPanning                 : 1;                               ///< Whether the scroll bar is being panned.
+  bool mIndicatorFirstShow        : 1;                               ///< True if the indicator has never been shown
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ScrollBar& GetImpl(Toolkit::ScrollBar& scrollBar)
+{
+  DALI_ASSERT_ALWAYS(scrollBar);
+
+  Dali::RefObject& handle = scrollBar.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ScrollBar&>(handle);
+}
+
+inline const Toolkit::Internal::ScrollBar& GetImpl(const Toolkit::ScrollBar& scrollBar)
+{
+  DALI_ASSERT_ALWAYS(scrollBar);
+
+  const Dali::RefObject& handle = scrollBar.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ScrollBar&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_BAR_H
diff --git a/dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.cpp b/dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.cpp
new file mode 100644 (file)
index 0000000..1b9c422
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector3.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/property-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/public-api/rendering/texture-set.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+// Bouncing effect is presented by stacked three layers with same color and opacity
+const float LAYER_HEIGHTS[5] =
+{
+  1.f,
+  26.f * 4.f/ 130.f,
+  26.f * 3.f / 130.f,
+  26.f * 2.f / 130.f,
+  26.f / 130.f
+};
+
+#define MAKE_SHADER(A)#A
+
+// Modify the vertex position according to the bounce coefficient;
+const char* MESH_VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec3    aPosition1;\n
+attribute mediump vec3    aPosition2;\n
+uniform   mediump mat4    uMvpMatrix;\n
+uniform   mediump vec3    uSize;
+uniform   mediump float   uBounceCoefficient;\n
+\n
+void main()\n
+{\n
+  gl_Position = uMvpMatrix * vec4(mix( aPosition1, aPosition2, abs(uBounceCoefficient) )*uSize, 1.0);\n
+}
+);
+
+// use the actor color to paint every layer
+const char* MESH_FRAGMENT_SHADER = MAKE_SHADER(
+uniform lowp  vec4    uColor;\n
+void main()\n
+{\n
+  gl_FragColor = uColor;\n
+}\n
+);
+
+} // namespace Anon
+
+Actor CreateBouncingEffectActor( Property::Index& bouncePropertyIndex )
+{
+  // Create the bouncing mesh geometry
+  struct VertexPosition
+  {
+    Vector3 position1;
+    Vector3 position2;
+  };
+  // 4 vertices 2 triangles per layer. The depth interval between each layer is 0.01
+  VertexPosition vertexData[20] = {
+    // bottom layer
+    { Vector3( -0.5f, -0.5f, 0.f ),  Vector3( -0.5f, -0.5f, 0.f )  },
+    { Vector3( 0.5f, -0.5f, 0.f ),   Vector3( 0.5f, -0.5f, 0.f )   },
+    { Vector3( -0.5f, -0.5f, 0.f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[0], 0.f ) },
+    { Vector3( 0.5f, -0.5f, 0.f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[0], 0.f )   },
+    // mid-bottom layer
+    { Vector3( -0.5f, -0.5f, 0.01f ),  Vector3( -0.5f, -0.5f, 0.01f )  },
+    { Vector3( 0.5f, -0.5f, 0.01f ),   Vector3( 0.5f, -0.5f, 0.01f )   },
+    { Vector3( -0.5f, -0.5f, 0.01f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[1], 0.01f ) },
+    { Vector3( 0.5f, -0.5f, 0.01f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[1], 0.01f )   },
+    // middle layer
+    { Vector3( -0.5f, -0.5f, 0.02f ),  Vector3( -0.5f, -0.5f, 0.02f )  },
+    { Vector3( 0.5f, -0.5f, 0.02f ),   Vector3( 0.5f, -0.5f, 0.02f )   },
+    { Vector3( -0.5f, -0.5f, 0.02f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[2], 0.02f ) },
+    { Vector3( 0.5f, -0.5f, 0.02f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[2], 0.02f )   },
+    // mid-top layer
+    { Vector3( -0.5f, -0.5f, 0.03f ),  Vector3( -0.5f, -0.5f, 0.03f )  },
+    { Vector3( 0.5f, -0.5f, 0.03f ),   Vector3( 0.5f, -0.5f, 0.03f )   },
+    { Vector3( -0.5f, -0.5f, 0.03f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[3], 0.03f ) },
+    { Vector3( 0.5f, -0.5f, 0.03f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[3], 0.03f )   },
+    // top layer
+    { Vector3( -0.5f, -0.5f, 0.04f ),  Vector3( -0.5f, -0.5f, 0.04f )  },
+    { Vector3( 0.5f, -0.5f, 0.04f ),   Vector3( 0.5f, -0.5f, 0.04f )   },
+    { Vector3( -0.5f, -0.5f, 0.04f ),  Vector3( -0.5f, -0.5f + LAYER_HEIGHTS[4], 0.04f ) },
+    { Vector3( 0.5f, -0.5f, 0.04f ),   Vector3( 0.5f, -0.5f+ LAYER_HEIGHTS[4], 0.04f )   }
+  };
+  Property::Map vertexFormat;
+  vertexFormat["aPosition1"] = Property::VECTOR3;
+  vertexFormat["aPosition2"] = Property::VECTOR3;
+  PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
+  vertices.SetData( vertexData, 20u );
+
+  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( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+
+  // Create the shader
+  Shader shader = Shader::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER );
+
+  // Create renderer
+  Renderer renderer = Renderer::New( meshGeometry, shader );
+
+  // Create actor
+  Actor meshActor= Actor::New();
+  meshActor.AddRenderer( renderer );
+
+  // Register property
+  bouncePropertyIndex = meshActor.RegisterProperty("uBounceCoefficient", 0.f);
+
+  return meshActor;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h b/dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h
new file mode 100644 (file)
index 0000000..1eb7725
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BOUNCING_EFFECT_ACTOR_H
+#define DALI_TOOLKIT_INTERNAL_BOUNCING_EFFECT_ACTOR_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/object/property.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Creates a Dali::Actor to display the bouncing effect for overshoot
+ *
+ * Usage example:
+ * @code
+ *  // create the actor and get the property index for animation
+ *  Property::Index bouncePropertyIndex = Property::INVALID_INDEX;
+ *  Actor bounceActor = CreateBouncingEffectActor( bouncePropertyIndex );
+
+ *  // set size and color
+ *  bounceActor.SetSize(720.f, 42.f );
+ *  bounceActor.SetColor( Vector4( 0.0,0.64f,0.85f,0.25f ) );
+ *
+ *  // add to stage
+ *  bounceActor.SetParentOrigin(ParentOrigin::CENTER);
+ *  Stage::GetCurrent().Add(bounceActor);
+
+ *  // start the bouncing animation
+ *  Animation anim = Animation::New(2.0f);
+ *  anim.AnimateTo( Property( bounceActor, bouncePropertyIndex ), 1.f, AlphaFunction::SIN );
+ *  anim.Play();
+ * @endcode
+ *
+ * @param[out] bouncePropertyIndex The property index which controls the bouncing
+ * @return The actor which displays the bouncing effect
+ */
+Actor CreateBouncingEffectActor( Property::Index& bouncePropertyIndex);
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_INTERNAL_BOUNCING_EFFECT_ACTOR_H
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/depth-layout.cpp b/dali-toolkit/internal/controls/scrollable/item-view/depth-layout.cpp
new file mode 100755 (executable)
index 0000000..58731c8
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/constraint.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace // unnamed namespace
+{
+
+const unsigned int DEFAULT_NUMBER_OF_COLUMNS    = 3;
+const float        DEFAULT_NUMBER_OF_ROWS       = 26.0f;
+const float        DEFAULT_ROW_SPACING          = 55.0f;
+const float        DEFAULT_BOTTOM_MARGIN_FACTOR = 0.2f;
+const Radian       DEFAULT_TILT_ANGLE           ( Math::PI*0.15f );
+const Radian       DEFAULT_ITEM_TILT_ANGLE      ( -Math::PI*0.025f );
+const float        DEFAULT_SCROLL_SPEED_FACTOR  = 0.02f;
+const float        DEFAULT_MAXIMUM_SWIPE_SPEED  = 50.0f;
+const float        DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.03f;
+
+inline float GetColumnPosition( unsigned int numberOfColumns, unsigned int columnNumber, const Vector3& itemSize, float layoutWidth )
+{
+  // Share the available space between margins & column spacings
+  float availableSpace = std::max( 0.0f, ( layoutWidth - itemSize.width * numberOfColumns ) );
+
+  float leftMargin = availableSpace / numberOfColumns * 0.5f;
+
+  float columnPosition = leftMargin + itemSize.width * 0.5f + columnNumber * ( itemSize.width + availableSpace / numberOfColumns );
+
+  return columnPosition - layoutWidth * 0.5f;
+}
+
+struct DepthPositionConstraint
+{
+  DepthPositionConstraint( unsigned int itemId,
+                           unsigned int numberOfColumns,
+                           unsigned int columnNumber,
+                           const Vector3& itemSize,
+                           float heightScale,
+                           float depthScale )
+  : mItemSize( itemSize ),
+    mItemId( itemId ),
+    mNumberOfColumns( numberOfColumns ),
+    mColumnNumber( columnNumber ),
+    mHeightScale( heightScale ),
+    mDepthScale( depthScale )
+  {
+  }
+
+  inline void Orientation0( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber );
+
+    current.x = GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.width );
+    current.y = rowLayoutPositon * mHeightScale + layoutSize.height * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.height - mItemSize.height * 0.5f;
+    current.z = -rowLayoutPositon * mDepthScale;
+  }
+
+  inline void Orientation90( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber ) + mNumberOfColumns * 0.5f;
+
+    current.x = rowLayoutPositon * mHeightScale + layoutSize.width * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.width - mItemSize.height * 0.5f;
+    current.y = -GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.height );
+    current.z = -rowLayoutPositon * mDepthScale;
+  }
+
+  inline void Orientation180( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber );
+
+    current.x = -GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.width );
+    current.y = -( rowLayoutPositon * mHeightScale + layoutSize.height * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.height - mItemSize.height * 0.5f );
+    current.z = -rowLayoutPositon * mDepthScale;
+  }
+
+  inline void Orientation270( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber ) + mNumberOfColumns * 0.5f;
+
+    current.x = -( rowLayoutPositon * mHeightScale + layoutSize.width * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.width - mItemSize.height * 0.5f );
+    current.y = GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.height );
+    current.z = -rowLayoutPositon * mDepthScale;
+  }
+
+  void Orientation0( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation0( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation90( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation90( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation180( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation180( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation270( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation270( current, layoutPosition, layoutSize );
+  }
+
+  Vector3 mItemSize;
+  unsigned int mItemId;
+  unsigned int mNumberOfColumns;
+  unsigned int mColumnNumber;
+  float mHeightScale;
+  float mDepthScale;
+};
+
+struct DepthRotationConstraint
+{
+  DepthRotationConstraint( Radian angleRadians, ControlOrientation::Type orientation )
+  : mTiltAngle( angleRadians ),
+    mMultiplier( 0.0f )
+  {
+    if ( orientation == ControlOrientation::Up )
+    {
+      mMultiplier = 0.0f;
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      mMultiplier = 1.5f;
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      mMultiplier = -1.0f;
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      mMultiplier = 0.5f;
+    }
+  }
+
+  void operator()( Quaternion& current, const PropertyInputContainer& /* inputs */ )
+  {
+    current = Quaternion( Radian( mMultiplier * Math::PI ), Vector3::ZAXIS ) * Quaternion( mTiltAngle, Vector3::XAXIS );
+  }
+
+  Radian mTiltAngle;
+  float mMultiplier;
+};
+
+struct DepthColorConstraint
+{
+  DepthColorConstraint( unsigned int itemId, unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber )
+  : mItemId( itemId ),
+    mNumberOfColumns( numberOfColumns ),
+    mNumberOfRows( numberOfRows ),
+    mColumnNumber( columnNumber )
+  {
+  }
+
+  void operator()( Vector4& current, const Dali::PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float row = ( layoutPosition - static_cast<float>( mColumnNumber ) ) / mNumberOfColumns;
+
+    float darkness(1.0f);
+    float alpha(1.0f);
+
+    if (row < 0.0f)
+    {
+      darkness = alpha = std::max(0.0f, 1.0f + row);
+    }
+    else
+    {
+      if (row > mNumberOfRows)
+      {
+        darkness = 0.0f;
+      }
+      else
+      {
+        darkness = 1.0f - ( 1.0f * (row / mNumberOfRows) );
+      }
+
+      if (row > (mNumberOfRows-1.0f))
+      {
+        alpha = std::max(0.0f, 1.0f - (row-(mNumberOfRows-1.0f)));
+      }
+    }
+
+    current.r = current.g = current.b = darkness;
+    current.a *= alpha;
+  }
+
+  unsigned int mItemId;
+  unsigned int mNumberOfColumns;
+  float mNumberOfRows;
+  unsigned int mColumnNumber;
+};
+
+struct DepthVisibilityConstraint
+{
+  DepthVisibilityConstraint( unsigned int itemId, unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber )
+  : mItemId( itemId ),
+    mNumberOfColumns(numberOfColumns),
+    mNumberOfRows(numberOfRows),
+    mColumnNumber(columnNumber)
+  {
+  }
+
+  void operator()( bool& current, const Dali::PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float row = ( layoutPosition - static_cast< float >( mColumnNumber ) ) / mNumberOfColumns;
+
+    current = ( row > -1.0f ) && ( row < mNumberOfRows );
+  }
+
+  unsigned int mItemId;
+  unsigned int mNumberOfColumns;
+  float mNumberOfRows;
+  unsigned int mColumnNumber;
+};
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+struct DepthLayout::Impl
+{
+  Impl()
+  : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
+    mNumberOfRows(DEFAULT_NUMBER_OF_ROWS),
+    mRowSpacing(DEFAULT_ROW_SPACING),
+    mTiltAngle(DEFAULT_TILT_ANGLE),
+    mItemTiltAngle(DEFAULT_ITEM_TILT_ANGLE),
+    mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
+    mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
+    mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
+  {
+  }
+
+  unsigned int mNumberOfColumns;
+  unsigned int mNumberOfRows;
+
+  float mRowSpacing;
+
+  Radian mTiltAngle;
+  Radian mItemTiltAngle;
+
+  float mScrollSpeedFactor;
+  float mMaximumSwipeSpeed;
+  float mItemFlickAnimationDuration;
+};
+
+DepthLayoutPtr DepthLayout::New()
+{
+  return DepthLayoutPtr(new DepthLayout());
+}
+
+DepthLayout::~DepthLayout()
+{
+  delete mImpl;
+}
+
+void DepthLayout::SetNumberOfColumns(unsigned int columns)
+{
+  mImpl->mNumberOfColumns = columns;
+}
+
+unsigned int DepthLayout::GetNumberOfColumns() const
+{
+  return mImpl->mNumberOfColumns;
+}
+
+void DepthLayout::SetNumberOfRows(unsigned int rows)
+{
+  mImpl->mNumberOfRows = rows;
+}
+
+unsigned int DepthLayout::GetNumberOfRows() const
+{
+  return mImpl->mNumberOfRows;
+}
+
+void DepthLayout::SetRowSpacing(float spacing)
+{
+  mImpl->mRowSpacing = spacing;
+}
+
+float DepthLayout::GetRowSpacing() const
+{
+  return mImpl->mRowSpacing;
+}
+
+void DepthLayout::SetTiltAngle(Degree angle)
+{
+  mImpl->mTiltAngle = Degree( Clamp( angle, -45.0f, 45.0f ) );
+}
+
+Degree DepthLayout::GetTiltAngle() const
+{
+  return Degree( mImpl->mTiltAngle );
+}
+
+void DepthLayout::SetItemTiltAngle(Degree angle)
+{
+  mImpl->mItemTiltAngle = angle;
+}
+
+Degree DepthLayout::GetItemTiltAngle() const
+{
+  return Degree( mImpl->mItemTiltAngle );
+}
+
+void DepthLayout::SetScrollSpeedFactor(float scrollSpeed)
+{
+  mImpl->mScrollSpeedFactor = scrollSpeed;
+}
+
+void DepthLayout::SetMaximumSwipeSpeed(float speed)
+{
+  mImpl->mMaximumSwipeSpeed = speed;
+}
+
+void DepthLayout::SetItemFlickAnimationDuration(float durationSeconds)
+{
+  mImpl->mItemFlickAnimationDuration = durationSeconds;
+}
+
+float DepthLayout::GetScrollSpeedFactor() const
+{
+  return mImpl->mScrollSpeedFactor;
+}
+
+float DepthLayout::GetMaximumSwipeSpeed() const
+{
+  return mImpl->mMaximumSwipeSpeed;
+}
+
+float DepthLayout::GetItemFlickAnimationDuration() const
+{
+  return mImpl->mItemFlickAnimationDuration;
+}
+
+float DepthLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
+{
+  return static_cast<float>(mImpl->mNumberOfColumns) - static_cast<float>(numberOfItems);
+}
+
+float DepthLayout::GetClosestAnchorPosition(float layoutPosition) const
+{
+  float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
+  return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
+}
+
+float DepthLayout::GetItemScrollToPosition(unsigned int itemId) const
+{
+  float rowIndex = static_cast< float >( itemId ) / mImpl->mNumberOfColumns;
+  return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
+}
+
+ItemRange DepthLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
+{
+  float firstRow = -(firstItemPosition/mImpl->mNumberOfColumns);
+  float lastRow = firstRow + mImpl->mNumberOfRows * 0.5f;
+
+  unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, firstRow * mImpl->mNumberOfColumns));
+  unsigned int lastItem  = static_cast<unsigned int>(std::max(0.0f, lastRow  * mImpl->mNumberOfColumns));
+
+  return ItemRange(firstItem, lastItem+1);
+}
+
+unsigned int DepthLayout::GetReserveItemCount(Vector3 layoutSize) const
+{
+  float itemsWithinLayout = (layoutSize.depth * mImpl->mNumberOfColumns) / (cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing);
+
+  return static_cast<unsigned int>(itemsWithinLayout);
+}
+
+void DepthLayout::GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
+{
+  // 1x1 aspect ratio
+  itemSize.width = itemSize.height = itemSize.depth = ( IsVertical( GetOrientation() ) ? layoutSize.width : layoutSize.height ) / static_cast<float>( mImpl->mNumberOfColumns + 1 );
+}
+
+Degree DepthLayout::GetScrollDirection() const
+{
+  Degree scrollDirection(0.0f);
+  ControlOrientation::Type orientation = GetOrientation();
+
+  if ( orientation == ControlOrientation::Up )
+  {
+    scrollDirection = Degree( 180.0f );
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    scrollDirection = Degree( 270.0f );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    scrollDirection = Degree( 0.0f );
+  }
+  else // orientation == ControlOrientation::Right
+  {
+    scrollDirection = Degree( 90.0f );
+  }
+
+  return scrollDirection;
+}
+
+void DepthLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
+{
+
+  Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
+  if( itemView )
+  {
+    Vector3 itemSize;
+    GetItemSize( itemId, layoutSize, itemSize );
+
+    ControlOrientation::Type orientation = GetOrientation();
+
+    // Position constraint
+    Constraint constraint;
+    DepthPositionConstraint depthPositionStruct( itemId,
+                                                 mImpl->mNumberOfColumns,
+                                                 itemId % mImpl->mNumberOfColumns,
+                                                 itemSize,
+                                                 -sinf( mImpl->mTiltAngle ) * mImpl->mRowSpacing,
+                                                 cosf( mImpl->mTiltAngle ) * mImpl->mRowSpacing );
+    if ( orientation == ControlOrientation::Up )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation0 );
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation90 );
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation180 );
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation270 );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.Apply();
+
+    // Rotation constraint
+    constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, DepthRotationConstraint( mImpl->mItemTiltAngle, orientation ) );
+    constraint.Apply();
+
+    // Color constraint
+    constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, DepthColorConstraint( itemId, mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns ) );
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.SetRemoveAction( Dali::Constraint::Discard );
+    constraint.Apply();
+
+    // Visibility constraint
+    constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, DepthVisibilityConstraint( itemId, mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns ) );
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.SetRemoveAction( Dali::Constraint::Discard );
+    constraint.Apply();
+  }
+}
+
+void DepthLayout::SetDepthLayoutProperties(const Property::Map& properties)
+{
+  // Set any properties specified for DepthLayout.
+  for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
+  {
+    KeyValuePair propertyPair = properties.GetKeyValue( idx );
+    switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
+    {
+      case DefaultItemLayoutProperty::DEPTH_COLUMN_NUMBER:
+      {
+        SetNumberOfColumns(propertyPair.second.Get<int>());
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_ROW_NUMBER:
+      {
+        SetNumberOfRows(propertyPair.second.Get<int>());
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_ROW_SPACING:
+      {
+        SetRowSpacing(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_MAXIMUM_SWIPE_SPEED:
+      {
+        SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_SCROLL_SPEED_FACTOR:
+      {
+        SetScrollSpeedFactor(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_TILT_ANGLE:
+      {
+        SetTiltAngle(Degree(Radian(propertyPair.second.Get<float>())));
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_ITEM_TILT_ANGLE:
+      {
+        SetItemTiltAngle(Degree(Radian(propertyPair.second.Get<float>())));
+        break;
+      }
+      case DefaultItemLayoutProperty::DEPTH_ITEM_FLICK_ANIMATION_DURATION:
+      {
+        SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+Vector3 DepthLayout::GetItemPosition( int itemID, float currentLayoutPosition, const Vector3& layoutSize ) const
+{
+  Vector3 itemPosition = Vector3::ZERO;
+
+  const float heightScale = -sinf( mImpl->mTiltAngle ) * mImpl->mRowSpacing;
+  const float depthScale  =  cosf( mImpl->mTiltAngle ) * mImpl->mRowSpacing;
+
+  Vector3 itemSize;
+  GetItemSize( itemID, layoutSize, itemSize );
+  DepthPositionConstraint positionFunctor = DepthPositionConstraint( itemID,
+                                                                     mImpl->mNumberOfColumns,
+                                                                     itemID % mImpl->mNumberOfColumns,
+                                                                     itemSize,
+                                                                     heightScale,
+                                                                     depthScale );
+  ControlOrientation::Type orientation = GetOrientation();
+  if ( orientation == ControlOrientation::Up )
+  {
+    positionFunctor.Orientation0( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    positionFunctor.Orientation90( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    positionFunctor.Orientation180( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else // orientation == ControlOrientation::Right
+  {
+    positionFunctor.Orientation270( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+
+  return itemPosition;
+}
+
+DepthLayout::DepthLayout()
+: mImpl(NULL)
+{
+  mImpl = new Impl();
+}
+
+float DepthLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
+{
+  float scrollTo = currentLayoutPosition;
+  float row = (currentLayoutPosition + itemID - static_cast<float>(itemID % mImpl->mNumberOfColumns)) / mImpl->mNumberOfColumns;
+
+  // Check whether item is not within viewable area
+  if(row <= -1.0f)
+  {
+    scrollTo = GetItemScrollToPosition(itemID);
+  }
+  else if(row > mImpl->mNumberOfRows * 0.5f - 1.0f)
+  {
+    scrollTo = GetItemScrollToPosition(itemID) + (mImpl->mNumberOfRows - 1.0f) * 0.5f * mImpl->mNumberOfColumns;
+  }
+
+  return scrollTo;
+}
+
+int DepthLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  switch( direction )
+  {
+    case Toolkit::Control::KeyboardFocus::LEFT:
+    {
+      itemID--;
+      if( itemID < 0 )
+      {
+        itemID = loopEnabled ? maxItems - 1 : 0;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::UP:
+    {
+      itemID += mImpl->mNumberOfColumns;
+      if( itemID >= maxItems )
+      {
+        itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::RIGHT:
+    {
+      itemID++;
+      if( itemID >= maxItems )
+      {
+        itemID = loopEnabled ? 0 : maxItems - 1;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::DOWN:
+    {
+      itemID -= mImpl->mNumberOfColumns;
+      if( itemID < 0 )
+      {
+        itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+  return itemID;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h b/dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h
new file mode 100755 (executable)
index 0000000..0a262ed
--- /dev/null
@@ -0,0 +1,243 @@
+#ifndef DALI_TOOLKIT_DEPTH_LAYOUT_H
+#define DALI_TOOLKIT_DEPTH_LAYOUT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class DepthLayout;
+
+typedef IntrusivePtr<DepthLayout> DepthLayoutPtr;
+
+/**
+ * This layout arranges items in a grid, which scrolls along the Z-Axis.
+ */
+class DepthLayout : public ItemLayout
+{
+public:
+
+  /**
+   * Create a new spiral layout
+   */
+  static DepthLayoutPtr New();
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~DepthLayout();
+
+  /**
+   * Apply depth layout Properties.
+   * @param[in] properties The properties of the layout.
+   */
+  void SetDepthLayoutProperties(const Property::Map& properties);
+
+  /**
+   * Set the number of columns in the layout.
+   * @param[in] columns The number of columns.
+   */
+  void SetNumberOfColumns(unsigned int columns);
+
+  /**
+   * Get the number of columns in the layout.
+   * @return The number of columns.
+   */
+  unsigned int GetNumberOfColumns() const;
+
+  /**
+   * Set the number of rows in the layout.
+   * The default is 20, with 10 behind the viewable area.
+   * @param[in] rows The number-of-rows.
+   */
+  void SetNumberOfRows(unsigned int rows);
+
+  /**
+   * Get the number of rows in the layout.
+   * @return The number of rows.
+   */
+  unsigned int GetNumberOfRows() const;
+
+  /**
+   * Set the spacing between rows.
+   * @param[in] spacing The row spacing.
+   */
+  void SetRowSpacing(float spacing);
+
+  /**
+   * Get the spacing between rows.
+   * @return The row spacing.
+   */
+  float GetRowSpacing() const;
+
+  /**
+   * Set the tilt angle of the layout; this is clamped between -45 & 45 degrees.
+   * @param[in] angle The tilt angle in degrees.
+   */
+  void SetTiltAngle(Degree angle);
+
+  /**
+   * Get the tilt angle of the layout.
+   * @return The tilt angle in degrees.
+   */
+  Degree GetTiltAngle() const;
+
+  /**
+   * Set the tilt angle of the individual items in the layout.
+   * @param[in] angle The item tilt angle in degrees.
+   */
+  void SetItemTiltAngle(Degree angle);
+
+  /**
+   * Get the tilt angle of the individual items in the layout.
+   * @return The item tilt angle in degrees.
+   */
+  Degree GetItemTiltAngle() const;
+
+  /**
+   * Set the factor used to customise the scroll speed while dragging and swiping the layout.
+   * @param[in] scrollSpeed The scroll speed factor.
+   */
+  void SetScrollSpeedFactor(float scrollSpeed);
+
+  /**
+   * Set the maximum swipe speed in pixels per second.
+   * @param[in] speed The maximum swipe speed.
+   */
+  void SetMaximumSwipeSpeed(float speed);
+
+  /**
+   * Set the duration of the flick animation in second. This is the time taken to animate each
+   * item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered
+   * by a swipe gesture.
+   * @pre durationSeconds must be greater than zero.
+   * @param[in] durationSeconds The duration of flick animation in seconds.
+   */
+  void SetItemFlickAnimationDuration(float durationSeconds);
+
+  /**
+   * @copydoc ItemLayout::GetScrollSpeedFactor()
+   */
+  virtual float GetScrollSpeedFactor() const;
+
+  /**
+   * @copydoc ItemLayout::GetMaximumSwipeSpeed()
+   */
+  virtual float GetMaximumSwipeSpeed() const;
+
+  /**
+   * @copydoc ItemLayout::GetItemFlickAnimationDuration()
+   */
+  virtual float GetItemFlickAnimationDuration() const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestOnScreenLayoutPosition()
+   */
+  virtual float GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize);
+
+  /**
+   * @copydoc ItemLayout::GetNextFocusItemID()
+   */
+  virtual int GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled);
+
+private:
+
+  /**
+   * @copydoc ItemLayout::GetMinimumLayoutPosition()
+   */
+  virtual float GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestAnchorPosition()
+   */
+  virtual float GetClosestAnchorPosition(float layoutPosition) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemScrollToPosition()
+   */
+  virtual float GetItemScrollToPosition(unsigned int itemId) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemsWithinArea()
+   */
+  virtual ItemRange GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetReserveItemCount()
+   */
+  virtual unsigned int GetReserveItemCount(Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetDefaultItemSize()
+   */
+  virtual void GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const;
+
+  /**
+   * @copydoc ItemLayout::GetScrollDirection()
+   */
+  virtual Degree GetScrollDirection() const;
+
+  /**
+   * @copydoc ItemLayout::ApplyConstraints()
+   */
+  virtual void ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor );
+
+  /**
+   * @copydoc ItemLayout::GetItemPosition()
+   */
+  virtual Vector3 GetItemPosition( int itemID, float currentLayoutPosition, const Vector3& layoutSize ) const;
+
+protected:
+
+  /**
+   * Protected constructor; see also DepthLayout::New()
+   */
+  DepthLayout();
+
+private:
+
+  // Undefined
+  DepthLayout( const DepthLayout& depthLayout );
+
+  // Undefined
+  DepthLayout& operator=( const DepthLayout& depthLayout );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEPTH_LAYOUT_H
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/grid-layout.cpp b/dali-toolkit/internal/controls/scrollable/item-view/grid-layout.cpp
new file mode 100755 (executable)
index 0000000..3e28d80
--- /dev/null
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/constraint.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace // unnamed namespace
+{
+
+const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 4;
+const float DEFAULT_TOP_MARGIN     =  95.0f;
+const float DEFAULT_BOTTOM_MARGIN  =  20.0f;
+const float DEFAULT_SIDE_MARGIN    =  20.0f;
+const float DEFAULT_COLUMN_SPACING =  20.0f;
+const float DEFAULT_ROW_SPACING    =  20.0f;
+const float DEFAULT_SCROLL_SPEED_FACTOR = 0.03f;
+const float DEFAULT_MAXIMUM_SWIPE_SPEED = 100.0f;
+const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.015f;
+
+struct GridPositionConstraint
+{
+  GridPositionConstraint(
+      unsigned int itemId,
+      const unsigned int columnIndex,
+      const unsigned int numberOfColumns,
+      const float rowSpacing,
+      const float columnSpacing,
+      const float topMargin,
+      const float sideMargin,
+      const Vector3& itemSize,
+      const float gap )
+  : mItemSize( itemSize ),
+    mItemId( itemId ),
+    mColumnIndex( columnIndex ),
+    mNumberOfColumns( numberOfColumns ),
+    mRowSpacing( rowSpacing ),
+    mColumnSpacing( columnSpacing ),
+    mTopMargin( topMargin ),
+    mSideMargin( sideMargin ),
+    mZGap( gap )
+  {
+  }
+
+  inline void Orientation0( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    current.x = mSideMargin + ( mColumnIndex * ( mItemSize.x + mColumnSpacing ) ) + mItemSize.x * 0.5f - layoutSize.x * 0.5f;
+    current.y = ( ( mItemSize.y + mRowSpacing ) * ( layoutPosition - mColumnIndex) ) / mNumberOfColumns - layoutSize.height * 0.5f + mItemSize.y * 0.5f + mTopMargin;
+    current.z = mColumnIndex * mZGap;
+  }
+
+  inline void Orientation90( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    current.x = ( ( mItemSize.y + mRowSpacing ) * ( layoutPosition - mColumnIndex ) ) / mNumberOfColumns - layoutSize.width * 0.5f + mItemSize.y * 0.5f + mTopMargin;
+    current.y = -( mSideMargin + ( mColumnIndex * ( mItemSize.x + mColumnSpacing ) ) + mItemSize.x * 0.5f - layoutSize.y * 0.5f );
+    current.z = mColumnIndex * mZGap;
+  }
+
+  inline void Orientation180( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    current.x = -(mSideMargin + (mColumnIndex * (mItemSize.x + mColumnSpacing)) + mItemSize.x * 0.5f - layoutSize.x * 0.5f);
+    current.y = -( ( ( mItemSize.y + mRowSpacing ) * ( layoutPosition - mColumnIndex ) ) / mNumberOfColumns - layoutSize.height * 0.5f + mItemSize.y * 0.5f + mTopMargin );
+    current.z = mColumnIndex * mZGap;
+  }
+
+  inline void Orientation270( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    current.x = -( ( ( mItemSize.y + mRowSpacing ) * ( layoutPosition - mColumnIndex ) ) / mNumberOfColumns - layoutSize.width * 0.5f + mItemSize.y * 0.5f + mTopMargin );
+    current.y = mSideMargin + ( mColumnIndex * ( mItemSize.x + mColumnSpacing ) ) + mItemSize.x * 0.5f - layoutSize.y * 0.5f;
+    current.z = mColumnIndex * mZGap;
+  }
+
+  void Orientation0( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation0( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation90( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation90( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation180( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation180( current, layoutPosition, layoutSize );
+  }
+
+  void Orientation270( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    Orientation270( current, layoutPosition, layoutSize );
+  }
+
+public:
+
+  Vector3 mItemSize;
+  unsigned int mItemId;
+  unsigned int mColumnIndex;
+  unsigned int mNumberOfColumns;
+  float mRowSpacing;
+  float mColumnSpacing;
+  float mTopMargin;
+  float mSideMargin;
+  float mZGap;
+};
+
+void GridRotationConstraint0( Quaternion& current, const PropertyInputContainer& /* inputs */ )
+{
+  current = Quaternion( Radian( 0.0f ), Vector3::ZAXIS );
+}
+
+void GridRotationConstraint90( Quaternion& current, const PropertyInputContainer& /* inputs */ )
+{
+  current = Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS );
+}
+
+void GridRotationConstraint180( Quaternion& current, const PropertyInputContainer& /* inputs */ )
+{
+  current = Quaternion( Radian( Math::PI ), Vector3::ZAXIS );
+}
+
+void GridRotationConstraint270( Quaternion& current, const PropertyInputContainer& /* inputs */ )
+{
+  current = Quaternion( Radian( 0.5f * Math::PI ), Vector3::ZAXIS );
+}
+
+void GridColorConstraint( Vector4& current, const PropertyInputContainer& /* inputs */ )
+{
+  current.r = current.g = current.b = 1.0f;
+}
+
+struct GridVisibilityConstraint
+{
+  GridVisibilityConstraint(
+      unsigned int itemId,
+      const unsigned int columnIndex,
+      const unsigned int numberOfColumns,
+      const float rowSpacing,
+      const float columnSpacing,
+      const float sideMargin,
+      const Vector3& itemSize )
+  : mItemSize( itemSize ),
+    mItemId( itemId ),
+    mColumnIndex( columnIndex ),
+    mNumberOfColumns( numberOfColumns ),
+    mRowSpacing( rowSpacing ),
+    mColumnSpacing( columnSpacing ),
+    mSideMargin( sideMargin )
+  {
+  }
+
+  void Portrait( bool& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+
+    float row = ( layoutPosition - static_cast< float >( mColumnIndex ) ) / mNumberOfColumns;
+    int rowsPerPage = ceil( layoutSize.height / ( mItemSize.y + mRowSpacing ) );
+
+    current = ( row > -2.0f ) && ( row < rowsPerPage );
+  }
+
+  void Landscape( bool& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+
+    float row = ( layoutPosition - static_cast< float >( mColumnIndex ) ) / mNumberOfColumns;
+    int rowsPerPage = ceil( layoutSize.width / ( mItemSize.y + mRowSpacing ) );
+
+    current = ( row > -2.0f ) && ( row < rowsPerPage );
+  }
+
+public:
+
+  Vector3 mItemSize;
+  unsigned int mItemId;
+  unsigned int mColumnIndex;
+  unsigned int mNumberOfColumns;
+  float mRowSpacing;
+  float mColumnSpacing;
+  float mSideMargin;
+};
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+struct GridLayout::Impl
+{
+  Impl()
+  : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
+    mRowSpacing(DEFAULT_ROW_SPACING),
+    mColumnSpacing(DEFAULT_COLUMN_SPACING),
+    mTopMargin(DEFAULT_TOP_MARGIN),
+    mBottomMargin(DEFAULT_BOTTOM_MARGIN),
+    mSideMargin(DEFAULT_SIDE_MARGIN),
+    mZGap(0.f),
+    mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
+    mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
+    mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
+  {
+  }
+
+  unsigned int mNumberOfColumns;
+  float mRowSpacing;
+  float mColumnSpacing;
+  float mTopMargin;
+  float mBottomMargin;
+  float mSideMargin;
+  float mZGap;
+
+  float mScrollSpeedFactor;
+  float mMaximumSwipeSpeed;
+  float mItemFlickAnimationDuration;
+};
+
+GridLayoutPtr GridLayout::New()
+{
+  return GridLayoutPtr(new GridLayout());
+}
+
+GridLayout::~GridLayout()
+{
+  delete mImpl;
+}
+
+void GridLayout::SetNumberOfColumns(unsigned int columns)
+{
+  mImpl->mNumberOfColumns = columns;
+}
+
+unsigned int GridLayout::GetNumberOfColumns() const
+{
+  return mImpl->mNumberOfColumns;
+}
+
+void GridLayout::SetRowSpacing(float spacing)
+{
+  mImpl->mRowSpacing = spacing;
+}
+
+float GridLayout::GetRowSpacing() const
+{
+  return mImpl->mRowSpacing;
+}
+
+void GridLayout::SetColumnSpacing(float spacing)
+{
+  mImpl->mColumnSpacing = spacing;
+}
+
+float GridLayout::GetColumnSpacing() const
+{
+  return mImpl->mColumnSpacing;
+}
+
+void GridLayout::SetTopMargin(float margin)
+{
+  mImpl->mTopMargin = margin;
+}
+
+float GridLayout::GetTopMargin() const
+{
+  return mImpl->mTopMargin;
+}
+
+void GridLayout::SetBottomMargin(float margin)
+{
+  mImpl->mBottomMargin = margin;
+}
+
+float GridLayout::GetBottomMargin() const
+{
+  return mImpl->mBottomMargin;
+}
+
+void GridLayout::SetSideMargin(float margin)
+{
+  mImpl->mSideMargin = margin;
+}
+
+float GridLayout::GetSideMargin() const
+{
+  return mImpl->mSideMargin;
+}
+
+void GridLayout::SetZGap(float gap)
+{
+  mImpl->mZGap = gap;
+}
+
+float GridLayout::GetZGap() const
+{
+  return mImpl->mZGap;
+}
+
+void GridLayout::SetScrollSpeedFactor(float scrollSpeed)
+{
+  mImpl->mScrollSpeedFactor = scrollSpeed;
+}
+
+void GridLayout::SetMaximumSwipeSpeed(float speed)
+{
+  mImpl->mMaximumSwipeSpeed = speed;
+}
+
+void GridLayout::SetItemFlickAnimationDuration(float durationSeconds)
+{
+  mImpl->mItemFlickAnimationDuration = durationSeconds;
+}
+
+float GridLayout::GetScrollSpeedFactor() const
+{
+  return mImpl->mScrollSpeedFactor;
+}
+
+float GridLayout::GetMaximumSwipeSpeed() const
+{
+  return mImpl->mMaximumSwipeSpeed;
+}
+
+float GridLayout::GetItemFlickAnimationDuration() const
+{
+  return mImpl->mItemFlickAnimationDuration;
+}
+
+float GridLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
+{
+  float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
+
+  Vector3 itemSize;
+  GetItemSize( 0, layoutSize, itemSize );
+
+  unsigned int itemsLastRow = numberOfItems % mImpl->mNumberOfColumns;
+  if (itemsLastRow == 0)
+  {
+    itemsLastRow = mImpl->mNumberOfColumns;
+  }
+
+  float rowsLastPage = (layoutHeight - mImpl->mBottomMargin - mImpl->mTopMargin + mImpl->mRowSpacing) / (itemSize.y + mImpl->mRowSpacing);
+  float itemsLastPage = (rowsLastPage - 1.0f) * static_cast<float>(mImpl->mNumberOfColumns) + static_cast<float>(itemsLastRow);
+
+  return itemsLastPage - static_cast<float>(numberOfItems);
+}
+
+float GridLayout::GetClosestAnchorPosition(float layoutPosition) const
+{
+  float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
+  return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
+}
+
+float GridLayout::GetItemScrollToPosition(unsigned int itemId) const
+{
+  float rowIndex = static_cast< float >( itemId ) / mImpl->mNumberOfColumns;
+  return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
+}
+
+ItemRange GridLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
+{
+  float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
+
+  Vector3 itemSize;
+  GetItemSize( 0, layoutSize, itemSize );
+
+  int itemsPerPage = mImpl->mNumberOfColumns * ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
+  int firstVisibleItem = -(static_cast<int>(firstItemPosition / mImpl->mNumberOfColumns)) * mImpl->mNumberOfColumns;
+
+  int firstItemIndex = std::max(0, firstVisibleItem - static_cast<int>(mImpl->mNumberOfColumns));
+  int lastItemIndex  = std::max(0, firstVisibleItem + itemsPerPage);
+
+  return ItemRange(firstItemIndex, lastItemIndex);
+}
+
+float GridLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
+{
+  Vector3 itemPosition = GetItemPosition( itemID, currentLayoutPosition, layoutSize );
+  Vector3 itemSize;
+  ControlOrientation::Type orientation = GetOrientation();
+
+  GetItemSize(itemID, layoutSize, itemSize);
+  Vector3 onScreenArea = ( layoutSize - ( IsVertical( orientation ) ? itemSize : Vector3( itemSize.y, itemSize.x, itemSize.z ) ) ) * 0.5f;
+  if (itemPosition.x < -onScreenArea.x
+      || itemPosition.x > onScreenArea.x
+      || itemPosition.y < -onScreenArea.y
+      || itemPosition.y > onScreenArea.y)
+  {
+    // item not within viewable area
+    float rowHeight = itemSize.y + mImpl->mRowSpacing;
+    Vector3 firstItemPosition = GetItemPosition( itemID, 0.0f, layoutSize );
+    float offset = 0.0f;
+    switch( orientation )
+    {
+      case ControlOrientation::Up:
+      {
+        if(itemPosition.y > onScreenArea.y)
+        {
+          offset = ((layoutSize.y - rowHeight) * 0.5f) - firstItemPosition.y;
+        }
+        else
+        {
+          offset = ((-layoutSize.y + rowHeight) * 0.5f) - firstItemPosition.y;
+        }
+        break;
+      }
+      case ControlOrientation::Down:
+      {
+        if(itemPosition.y < -onScreenArea.y)
+        {
+          offset = ((layoutSize.y - rowHeight) * 0.5f) - firstItemPosition.y;
+        }
+        else
+        {
+          offset = ((-layoutSize.y + rowHeight) * 0.5f) - firstItemPosition.y;
+        }
+        break;
+      }
+      case ControlOrientation::Left:
+      {
+        if(itemPosition.x > onScreenArea.x)
+        {
+          offset = ((layoutSize.x - rowHeight) * 0.5f) - firstItemPosition.x;
+        }
+        else
+        {
+          offset = ((-layoutSize.x + rowHeight) * 0.5f) - firstItemPosition.x;
+        }
+        break;
+      }
+      case ControlOrientation::Right:
+      {
+        if(itemPosition.x < -onScreenArea.x)
+        {
+          offset = ((layoutSize.x - rowHeight) * 0.5f) - firstItemPosition.x;
+        }
+        else
+        {
+          offset = ((-layoutSize.x + rowHeight) * 0.5f) - firstItemPosition.x;
+        }
+        break;
+      }
+    }
+    // work out number of rows from first item position to an item aligned to bottom of screen
+    float rowDiff = offset / rowHeight;
+    float layoutPositionOffset = rowDiff * mImpl->mNumberOfColumns;
+    float scrollTo = GetItemScrollToPosition(itemID) + layoutPositionOffset;
+    return scrollTo;
+  }
+  return currentLayoutPosition;
+}
+
+unsigned int GridLayout::GetReserveItemCount(Vector3 layoutSize) const
+{
+  float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
+
+  Vector3 itemSize;
+  GetItemSize( 0, layoutSize, itemSize );
+  int itemsPerPage = mImpl->mNumberOfColumns * ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
+  return itemsPerPage;
+}
+
+void GridLayout::GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
+{
+  float layoutWidth = IsHorizontal( GetOrientation() ) ? layoutSize.height : layoutSize.width;
+  itemSize.width = ( layoutWidth - mImpl->mSideMargin * 2.0f - mImpl->mColumnSpacing * static_cast<float>( mImpl->mNumberOfColumns - 1 ) ) / static_cast<float>( mImpl->mNumberOfColumns );
+
+  // 4x3 aspect ratio
+  itemSize.height = itemSize.depth = itemSize.width * 0.75f;
+}
+
+Degree GridLayout::GetScrollDirection() const
+{
+  Degree scrollDirection(0.0f);
+  ControlOrientation::Type orientation = GetOrientation();
+
+  if ( orientation == ControlOrientation::Up )
+  {
+    scrollDirection = Degree( 0.0f );
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    scrollDirection = Degree( 90.0f );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    scrollDirection = Degree( 180.0f );
+  }
+  else // orientation == ControlOrientation::Right
+  {
+    scrollDirection = Degree( 270.0f );
+  }
+
+  return scrollDirection;
+}
+
+void GridLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
+{
+  // This just implements the default behaviour of constraint application.
+  // Custom layouts can override this function to apply their custom constraints.
+  Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
+  if( itemView )
+  {
+    Vector3 itemSize;
+    GetItemSize( itemId, layoutSize, itemSize );
+    const unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
+    const ControlOrientation::Type orientation = GetOrientation();
+
+    // Position constraint
+    GridPositionConstraint positionConstraint( itemId,
+                                               columnIndex,
+                                               mImpl->mNumberOfColumns,
+                                               mImpl->mRowSpacing,
+                                               mImpl->mColumnSpacing,
+                                               mImpl->mTopMargin,
+                                               mImpl->mSideMargin,
+                                               itemSize,
+                                               mImpl->mZGap );
+    Constraint constraint;
+    if ( orientation == ControlOrientation::Up )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation0 );
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation90 );
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation180 );
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation270 );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.Apply();
+
+    // Rotation constraint
+    if ( orientation == ControlOrientation::Up )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint0 );
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint90 );
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint180 );
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint270 );
+    }
+    constraint.Apply();
+
+    // Color constraint
+    constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, &GridColorConstraint );
+    constraint.SetRemoveAction( Dali::Constraint::Discard );
+    constraint.Apply();
+
+    // Visibility constraint
+    GridVisibilityConstraint visibilityConstraint( itemId,
+                                                   columnIndex,
+                                                   mImpl->mNumberOfColumns,
+                                                   mImpl->mRowSpacing,
+                                                   mImpl->mColumnSpacing,
+                                                   mImpl->mSideMargin,
+                                                   itemSize );
+    if ( IsVertical( orientation ) )
+    {
+      constraint = Constraint::New<bool>( actor, Actor::Property::VISIBLE, visibilityConstraint, &GridVisibilityConstraint::Portrait );
+    }
+    else // horizontal
+    {
+      constraint = Constraint::New<bool>( actor, Actor::Property::VISIBLE, visibilityConstraint, &GridVisibilityConstraint::Landscape );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.SetRemoveAction( Dali::Constraint::Discard );
+    constraint.Apply();
+  }
+}
+
+void GridLayout::SetGridLayoutProperties(const Property::Map& properties)
+{
+  // Set any properties specified for gridLayout.
+  for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
+  {
+    KeyValuePair propertyPair = properties.GetKeyValue( idx );
+    switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
+    {
+      case DefaultItemLayoutProperty::GRID_COLUMN_NUMBER:
+      {
+        SetNumberOfColumns(propertyPair.second.Get<int>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_ROW_SPACING:
+      {
+        SetRowSpacing(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_COLUMN_SPACING:
+      {
+        SetColumnSpacing(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_TOP_MARGIN:
+      {
+        SetTopMargin(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_BOTTOM_MARGIN:
+      {
+        SetBottomMargin(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_SIDE_MARGIN:
+      {
+        SetSideMargin(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_SCROLL_SPEED_FACTOR:
+      {
+        SetScrollSpeedFactor(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_MAXIMUM_SWIPE_SPEED:
+      {
+        SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::GRID_ITEM_FLICK_ANIMATION_DURATION:
+      {
+        SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+Vector3 GridLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
+{
+  Vector3 itemPosition = Vector3::ZERO;
+  const unsigned int columnIndex = itemID % mImpl->mNumberOfColumns;
+  const ControlOrientation::Type orientation = GetOrientation();
+  Vector3 itemSize;
+  GetItemSize( itemID, layoutSize, itemSize );
+
+  GridPositionConstraint positionConstraintStruct( itemID,
+                                                   columnIndex,
+                                                   mImpl->mNumberOfColumns,
+                                                   mImpl->mRowSpacing,
+                                                   mImpl->mColumnSpacing,
+                                                   mImpl->mTopMargin,
+                                                   mImpl->mSideMargin,
+                                                   itemSize,
+                                                   mImpl->mZGap );
+
+  if ( orientation == ControlOrientation::Up )
+  {
+    positionConstraintStruct.Orientation0( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    positionConstraintStruct.Orientation90( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    positionConstraintStruct.Orientation180( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else // orientation == ControlOrientation::Right
+  {
+    positionConstraintStruct.Orientation270( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+
+  return itemPosition;
+}
+
+int GridLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  switch( direction )
+  {
+    case Toolkit::Control::KeyboardFocus::LEFT:
+    {
+      itemID--;
+      if( itemID < 0 )
+      {
+        itemID = loopEnabled ? maxItems - 1 : 0;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::UP:
+    {
+      itemID -= mImpl->mNumberOfColumns;
+      if( itemID < 0 )
+      {
+        itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::RIGHT:
+    {
+      itemID++;
+      if( itemID >= maxItems )
+      {
+        itemID = loopEnabled ? 0 : maxItems - 1;
+      }
+      break;
+    }
+    case Toolkit::Control::KeyboardFocus::DOWN:
+    {
+      itemID += mImpl->mNumberOfColumns;
+      if( itemID >= maxItems )
+      {
+        itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+  return itemID;
+}
+
+GridLayout::GridLayout()
+: mImpl(NULL)
+{
+  mImpl = new Impl();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h b/dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h
new file mode 100755 (executable)
index 0000000..915e8a6
--- /dev/null
@@ -0,0 +1,287 @@
+#ifndef DALI_TOOLKIT_GRID_LAYOUT_H
+#define DALI_TOOLKIT_GRID_LAYOUT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class GridLayout;
+
+typedef IntrusivePtr<GridLayout> GridLayoutPtr; ///< Pointer to a Dali::Toolkit::GridLayout object
+
+/**
+ * @brief An ItemView layout which arranges items in a grid.
+ */
+class GridLayout : public ItemLayout
+{
+public:
+
+  /**
+   * @brief Create a new grid layout.
+   */
+  static GridLayoutPtr New();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~GridLayout();
+
+  /**
+   * Apply grid layout Properties.
+   * @param[in] properties The properties of the layout.
+   */
+  void SetGridLayoutProperties(const Property::Map& properties);
+
+  /**
+   * @brief Set the number of columns in the layout.
+   *
+   * @param[in] columns The number of columns.
+   */
+  void SetNumberOfColumns(unsigned int columns);
+
+  /**
+   * @brief Get the number of columns in the layout.
+   *
+   * @return The number of columns.
+   */
+  unsigned int GetNumberOfColumns() const;
+
+  /**
+   * @brief Set the spacing between rows.
+   *
+   * @param[in] spacing The row spacing.
+   */
+  void SetRowSpacing(float spacing);
+
+  /**
+   * @brief Get the spacing between rows.
+   *
+   * @return The row spacing.
+   */
+  float GetRowSpacing() const;
+
+  /**
+   * @brief Set the spacing between columns.
+   *
+   * @param[in] spacing The row spacing.
+   */
+  void SetColumnSpacing(float spacing);
+
+  /**
+   * @brief Get the spacing between columns.
+   *
+   * @return The row spacing.
+   */
+  float GetColumnSpacing() const;
+
+  /**
+   * @brief Set the margin in the top of the layout.
+   *
+   * @param[in] margin The layout top margin.
+   */
+  void SetTopMargin(float margin);
+
+  /**
+   * @brief Get the margin in the top of the layout.
+   *
+   * @return The layout top margin.
+   */
+  float GetTopMargin() const;
+
+  /**
+   * @brief Set the margin in the bottom of the layout.
+   *
+   * @param[in] margin The layout bottom margin.
+   */
+  void SetBottomMargin(float margin);
+
+  /**
+   * @brief Get the margin in the bottom of the layout.
+   *
+   * @return The layout bottom margin.
+   */
+  float GetBottomMargin() const;
+
+  /**
+   * @brief Set the margin in the left and right of the layout.
+   *
+   * @param[in] margin The layout side margin.
+   */
+  void SetSideMargin(float margin);
+
+  /**
+   * @brief Get the margin in the left and right of the layout.
+   *
+   * @return The layout side margin.
+   */
+  float GetSideMargin() const;
+
+  /**
+   * @brief Set the gap of items in the Z axis in different columns.
+   *
+   * @param[in] gap The gap of items.
+   */
+  void SetZGap(float gap);
+
+  /**
+   * @brief Get the gap of items in the Z axis in different columns.
+   *
+   * @return The gap of items.
+   */
+  float GetZGap() const;
+
+  /**
+   * @brief Set the factor used to customise the scroll speed while dragging and swiping the layout.
+   *
+   * @param[in] scrollSpeed The scroll speed factor.
+   */
+  void SetScrollSpeedFactor(float scrollSpeed);
+
+  /**
+   * @brief Set the maximum swipe speed in pixels per second.
+   *
+   * @param[in] speed The maximum swipe speed.
+   */
+  void SetMaximumSwipeSpeed(float speed);
+
+  /**
+   * @brief Set the duration of the flick animation in seconds.
+   *
+   * This is the time taken to animate each item to its next layout
+   * position (e.g. from 1.0 to 2.0) when a flick animation is
+   * triggered by a swipe gesture.
+   *
+   * @pre durationSeconds must be greater than zero.
+   * @param[in] durationSeconds The duration of flick animation in seconds.
+   */
+  void SetItemFlickAnimationDuration(float durationSeconds);
+
+  /**
+   * @copydoc ItemLayout::GetScrollSpeedFactor()
+   */
+  virtual float GetScrollSpeedFactor() const;
+
+  /**
+   * @copydoc ItemLayout::GetMaximumSwipeSpeed()
+   */
+  virtual float GetMaximumSwipeSpeed() const;
+
+  /**
+   * @copydoc ItemLayout::GetItemFlickAnimationDuration()
+   */
+  virtual float GetItemFlickAnimationDuration() const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestOnScreenLayoutPosition()
+   */
+  virtual float GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize);
+
+  /**
+   * @copydoc ItemLayout::GetNextFocusItemID()
+   */
+  virtual int GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled);
+
+private:
+
+  /**
+   * @copydoc ItemLayout::GetMinimumLayoutPosition()
+   */
+  virtual float GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestAnchorPosition()
+   */
+  virtual float GetClosestAnchorPosition(float layoutPosition) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemScrollToPosition()
+   */
+  virtual float GetItemScrollToPosition(unsigned int itemId) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemsWithinArea()
+   */
+  virtual ItemRange GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetReserveItemCount()
+   */
+  virtual unsigned int GetReserveItemCount(Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetDefaultItemSize()
+   */
+  virtual void GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const;
+
+  /**
+   * @copydoc ItemLayout::GetScrollDirection()
+   */
+  virtual Degree GetScrollDirection() const;
+
+  /**
+   * @copydoc ItemLayout::ApplyConstraints()
+   */
+  virtual void ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor );
+
+  /**
+   * @copydoc ItemLayout::GetItemPosition()
+   */
+  virtual Vector3 GetItemPosition( int itemID, float currentLayoutPosition, const Vector3& layoutSize ) const;
+
+protected:
+
+  /**
+   * @brief Protected constructor; see also GridLayout::New().
+   */
+  GridLayout();
+
+private:
+
+  // Undefined
+  GridLayout( const GridLayout& itemLayout );
+
+  // Undefined
+  GridLayout& operator=( const GridLayout& rhs );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_GRID_LAYOUT_H
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp
new file mode 100755 (executable)
index 0000000..b5fbc4d
--- /dev/null
@@ -0,0 +1,1969 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <algorithm>
+#include <dali/public-api/actors/layer.h>
+
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
+
+using std::string;
+using namespace Dali;
+
+namespace // Unnamed namespace
+{
+
+const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
+const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
+const float DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
+
+const float DEFAULT_MINIMUM_SWIPE_DURATION = 0.45f;
+const float DEFAULT_MAXIMUM_SWIPE_DURATION = 2.6f;
+
+const float DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS = 20.0f; // 1 updates per 20 items
+const int WHEEL_EVENT_FINISHED_TIME_OUT = 500;  // 0.5 second
+
+const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
+
+const float MILLISECONDS_PER_SECONDS = 1000.0f;
+
+const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
+const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
+const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
+
+const unsigned int OVERSHOOT_SIZE_CONSTRAINT_TAG(42);
+
+/**
+ * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction
+ */
+float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
+{
+  Radian scrollDirection(layout.GetScrollDirection());
+
+  float cosTheta = cosf(scrollDirection);
+  float sinTheta = sinf(scrollDirection);
+
+  return panDistance.x * sinTheta + panDistance.y * cosTheta;
+}
+
+// Overshoot overlay constraints
+struct OvershootOverlaySizeConstraint
+{
+  OvershootOverlaySizeConstraint( float height )
+  : mOvershootHeight( height )
+  {
+  }
+
+  void operator()( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    const Vector2& parentScrollDirection = inputs[0]->GetVector2();
+    const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
+    const Vector3& parentSize = inputs[2]->GetVector3();
+
+    if(Toolkit::IsVertical(layoutOrientation))
+    {
+      current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
+    }
+    else
+    {
+      current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
+    }
+
+    current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? mOvershootHeight : mOvershootHeight*0.5f;
+  }
+
+  float mOvershootHeight;
+};
+
+void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInputContainer& inputs )
+{
+  const Vector2& parentScrollDirection = inputs[0]->GetVector2();
+  const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[1]->GetInteger());
+  const float parentOvershoot = inputs[2]->GetFloat();
+
+  float multiplier = 0;
+  if(Toolkit::IsVertical(layoutOrientation))
+  {
+    if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
+    {
+      if( (layoutOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
+          || (layoutOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
+      {
+        multiplier = 0.5f;
+      }
+      else
+      {
+        multiplier = 1.5f;
+      }
+    }
+    else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
+          || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
+    {
+      multiplier = 0.0f;
+    }
+    else
+    {
+      multiplier = 1.0f;
+    }
+  }
+  else
+  {
+    if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
+    {
+      if( (layoutOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0)
+          ||(layoutOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) )
+      {
+        multiplier = 1.0f;
+      }
+      else
+      {
+        multiplier = 0.0f;
+      }
+    }
+    else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
+          || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
+    {
+      multiplier = 1.5f;
+    }
+    else
+    {
+      multiplier = 0.5f;
+    }
+  }
+
+  current = Quaternion( Radian( multiplier * Math::PI ), Vector3::ZAXIS );
+}
+
+void OvershootOverlayPositionConstraint( Vector3& current, const PropertyInputContainer& inputs )
+{
+  const Vector3& parentSize = inputs[0]->GetVector3();
+  const Vector2& parentScrollDirection = inputs[1]->GetVector2();
+  const Toolkit::ControlOrientation::Type& layoutOrientation = static_cast<Toolkit::ControlOrientation::Type>(inputs[2]->GetInteger());
+  const float parentOvershoot = inputs[3]->GetFloat();
+
+  Vector3 relativeOffset;
+
+  if(Toolkit::IsVertical(layoutOrientation))
+  {
+    if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
+    {
+      if( (layoutOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
+          || (layoutOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
+      {
+        relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
+      }
+      else
+      {
+        relativeOffset =Vector3(0.0f, 1.0f, 0.0f);
+      }
+    }
+    else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
+          || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
+    {
+      relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
+    }
+    else
+    {
+      relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
+    }
+  }
+  else
+  {
+    if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
+    {
+      if( (layoutOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0)
+          || (layoutOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) )
+      {
+        relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
+      }
+      else
+      {
+        relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
+      }
+    }
+    else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
+          || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
+    {
+      relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
+    }
+    else
+    {
+      relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
+    }
+  }
+
+  current = relativeOffset * parentSize;
+}
+
+void OvershootOverlayVisibilityConstraint( bool& current, const PropertyInputContainer& inputs )
+{
+  current = inputs[0]->GetBoolean();
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+//Type registration
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL)
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeSpeed",          FLOAT,     MINIMUM_SWIPE_SPEED          )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeDistance",       FLOAT,     MINIMUM_SWIPE_DISTANCE       )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "wheelScrollDistanceStep",    FLOAT,     WHEEL_SCROLL_DISTANCE_STEP   )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "snapToItemEnabled",          BOOLEAN,   SNAP_TO_ITEM_ENABLED         )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "refreshInterval",            FLOAT,     REFRESH_INTERVAL             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout",                     ARRAY,     LAYOUT                       )
+
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition",      FLOAT,    LAYOUT_POSITION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed",         FLOAT,    SCROLL_SPEED)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "overshoot",           FLOAT,    OVERSHOOT)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollDirection",     VECTOR2,  SCROLL_DIRECTION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutOrientation",   INTEGER,  LAYOUT_ORIENTATION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollContentSize",   FLOAT,    SCROLL_CONTENT_SIZE)
+
+DALI_SIGNAL_REGISTRATION(              Toolkit, ItemView, "layoutActivated",     LAYOUT_ACTIVATED_SIGNAL )
+
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "stopScrolling",       ACTION_STOP_SCROLLING   )
+
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "enableRefresh",       ACTION_ENABLE_REFRESH   )
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "disableRefresh",      ACTION_DISABLE_REFRESH  )
+
+DALI_TYPE_REGISTRATION_END()
+
+const ItemIter FindItemById( ItemContainer& items, ItemId id )
+{
+  for( ItemIter iter = items.begin(); items.end() != iter; ++iter )
+  {
+    if( iter->first == id )
+    {
+      return iter;
+    }
+  }
+
+  return items.end();
+}
+
+void InsertToItemContainer( ItemContainer& items, Item item )
+{
+  if( items.end() == FindItemById( items, item.first ) )
+  {
+    ItemIter iterToInsert = std::lower_bound( items.begin(), items.end(), item );
+    items.insert( iterToInsert, item );
+  }
+}
+
+
+/**
+  * Helper to apply size constraint to mOvershootOverlay
+  * @param[in] overshootOverlay The overshootOverlay actor
+  * @param[in] The required height
+  */
+void ApplyOvershootSizeConstraint( Actor overshootOverlay, float height )
+{
+  Constraint constraint = Constraint::New<Vector3>( overshootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint( height ) );
+  constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+  constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+  constraint.AddSource( ParentSource( Dali::Actor::Property::SIZE ) );
+  constraint.SetTag( OVERSHOOT_SIZE_CONSTRAINT_TAG );
+  constraint.Apply();
+}
+
+} // unnamed namespace
+
+Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
+{
+  // Create the implementation
+  ItemViewPtr itemView(new ItemView(factory));
+
+  // Pass ownership to CustomActor via derived handle
+  Dali::Toolkit::ItemView handle(*itemView);
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  itemView->Initialize();
+
+  return handle;
+}
+
+ItemView::ItemView(ItemFactory& factory)
+: Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS | REQUIRES_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
+  mItemFactory(factory),
+  mItemsParentOrigin(ParentOrigin::CENTER),
+  mItemsAnchorPoint(AnchorPoint::CENTER),
+  mTotalPanDisplacement(Vector2::ZERO),
+  mActiveLayout(NULL),
+  mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
+  mRefreshIntervalLayoutPositions(0.0f),
+  mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
+  mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
+  mWheelScrollDistanceStep(0.0f),
+  mScrollDistance(0.0f),
+  mScrollSpeed(0.0f),
+  mScrollOvershoot(0.0f),
+  mGestureState(Gesture::Clear),
+  mAnimatingOvershootOn(false),
+  mAnimateOvershootOff(false),
+  mAnchoringEnabled(false),
+  mRefreshOrderHint(true/*Refresh item 0 first*/),
+  mIsFlicking(false),
+  mAddingItems(false),
+  mRefreshEnabled(true),
+  mRefreshNotificationEnabled(true),
+  mInAnimation(false)
+{
+}
+
+void ItemView::OnInitialize()
+{
+  Actor self = Self();
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
+
+  self.TouchSignal().Connect( this, &ItemView::OnTouch );
+  EnableGestureDetection(Gesture::Type(Gesture::Pan));
+
+  mWheelEventFinishedTimer = Timer::New( WHEEL_EVENT_FINISHED_TIME_OUT );
+  mWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnWheelEventFinished );
+
+  SetRefreshInterval(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS);
+}
+
+ItemView::~ItemView()
+{
+}
+
+unsigned int ItemView::GetLayoutCount() const
+{
+  return mLayouts.size();
+}
+
+void ItemView::AddLayout(ItemLayout& layout)
+{
+  mLayouts.push_back(ItemLayoutPtr(&layout));
+}
+
+void ItemView::RemoveLayout(unsigned int layoutIndex)
+{
+  DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
+
+  if (mActiveLayout == mLayouts[layoutIndex].Get())
+  {
+    mActiveLayout = NULL;
+  }
+
+  mLayouts.erase(mLayouts.begin() + layoutIndex);
+}
+
+ItemLayoutPtr ItemView::GetLayout(unsigned int layoutIndex) const
+{
+  return mLayouts[layoutIndex];
+}
+
+ItemLayoutPtr ItemView::GetActiveLayout() const
+{
+  return ItemLayoutPtr(mActiveLayout);
+}
+
+float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
+{
+  return Self().GetCurrentProperty< float >( Toolkit::ItemView::Property::LAYOUT_POSITION ) + static_cast<float>( itemId );
+}
+
+void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
+{
+  DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
+
+  mRefreshEnabled = false;
+
+  Actor self = Self();
+
+  // The ItemView size should match the active layout size
+  self.SetSize(targetSize);
+  mActiveLayoutTargetSize = targetSize;
+
+  // Switch to the new layout
+  mActiveLayout = mLayouts[layoutIndex].Get();
+
+  // Move the items to the new layout positions...
+
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  {
+    unsigned int itemId = iter->first;
+    Actor actor = iter->second;
+
+    // Remove constraints from previous layout
+    actor.RemoveConstraints();
+
+    mActiveLayout->ApplyConstraints(actor, itemId, targetSize, Self() );
+
+    Vector3 size;
+    mActiveLayout->GetItemSize( itemId, targetSize, size );
+    actor.SetSize( size.GetVectorXY() );
+  }
+
+  // Refresh the new layout
+  ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), false/* don't reserve extra*/);
+  AddActorsWithinRange( range, targetSize );
+
+  // Scroll to an appropriate layout position
+
+  bool scrollAnimationNeeded(false);
+  float firstItemScrollPosition(0.0f);
+
+  float current = GetCurrentLayoutPosition(0);
+  float minimum = ClampFirstItemPosition(current, targetSize, *mActiveLayout);
+
+  if (current < minimum)
+  {
+    scrollAnimationNeeded = true;
+    firstItemScrollPosition = minimum;
+  }
+  else if (mAnchoringEnabled)
+  {
+    scrollAnimationNeeded = true;
+    firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(current);
+  }
+
+  if (scrollAnimationNeeded)
+  {
+    RemoveAnimation(mScrollAnimation);
+    mScrollAnimation = Animation::New(durationSeconds);
+    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, AlphaFunction::EASE_OUT );
+    mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished);
+    mScrollAnimation.Play();
+  }
+  else
+  {
+    // Emit the layout activated signal
+    mLayoutActivatedSignal.Emit();
+  }
+
+  AnimateScrollOvershoot(0.0f);
+  mScrollOvershoot = 0.0f;
+
+  Radian scrollDirection(mActiveLayout->GetScrollDirection());
+  self.SetProperty(Toolkit::ItemView::Property::SCROLL_DIRECTION, Vector2(sinf(scrollDirection), cosf(scrollDirection)));
+  self.SetProperty(Toolkit::ItemView::Property::LAYOUT_ORIENTATION, static_cast<int>(mActiveLayout->GetOrientation()));
+  self.SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
+
+  CalculateDomainSize(targetSize);
+}
+
+void ItemView::DeactivateCurrentLayout()
+{
+  if (mActiveLayout)
+  {
+    for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    {
+      Actor actor = iter->second;
+      actor.RemoveConstraints();
+    }
+
+    mActiveLayout = NULL;
+  }
+}
+
+void ItemView::OnRefreshNotification(PropertyNotification& source)
+{
+  if( mRefreshNotificationEnabled )
+  {
+    // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll.
+    if(!mRefreshEnabled && mScrollAnimation)
+    {
+      RemoveAnimation(mScrollAnimation);
+    }
+
+    // Only cache extra items when it is not a fast scroll
+    DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation);
+  }
+}
+
+void ItemView::Refresh()
+{
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
+  {
+    ReleaseActor( iter->first, iter->second );
+  }
+  mItemPool.clear();
+
+  DoRefresh(GetCurrentLayoutPosition(0), true);
+}
+
+void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra)
+{
+  if (mActiveLayout)
+  {
+    ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/);
+    RemoveActorsOutsideRange( range );
+    AddActorsWithinRange( range, Self().GetCurrentSize() );
+
+    mScrollUpdatedSignal.Emit( Vector2(0.0f, currentLayoutPosition) );
+  }
+}
+
+void ItemView::SetMinimumSwipeSpeed(float speed)
+{
+  mMinimumSwipeSpeed = speed;
+}
+
+float ItemView::GetMinimumSwipeSpeed() const
+{
+  return mMinimumSwipeSpeed;
+}
+
+void ItemView::SetMinimumSwipeDistance(float distance)
+{
+  mMinimumSwipeDistance = distance;
+}
+
+float ItemView::GetMinimumSwipeDistance() const
+{
+  return mMinimumSwipeDistance;
+}
+
+void ItemView::SetWheelScrollDistanceStep(float step)
+{
+  mWheelScrollDistanceStep = step;
+}
+
+float ItemView::GetWheelScrollDistanceStep() const
+{
+  return mWheelScrollDistanceStep;
+}
+
+void ItemView::SetAnchoring(bool enabled)
+{
+  mAnchoringEnabled = enabled;
+}
+
+bool ItemView::GetAnchoring() const
+{
+  return mAnchoringEnabled;
+}
+
+void ItemView::SetAnchoringDuration(float durationSeconds)
+{
+  mAnchoringDuration = durationSeconds;
+}
+
+float ItemView::GetAnchoringDuration() const
+{
+  return mAnchoringDuration;
+}
+
+void ItemView::SetRefreshInterval(float intervalLayoutPositions)
+{
+  if( !Equals(mRefreshIntervalLayoutPositions, intervalLayoutPositions) )
+  {
+    mRefreshIntervalLayoutPositions = intervalLayoutPositions;
+
+    Actor self = Self();
+    if(mRefreshNotification)
+    {
+      self.RemovePropertyNotification(mRefreshNotification);
+    }
+    mRefreshNotification = self.AddPropertyNotification( Toolkit::ItemView::Property::LAYOUT_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) );
+    mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification );
+  }
+}
+
+float ItemView::GetRefreshInterval() const
+{
+  return mRefreshIntervalLayoutPositions;
+}
+
+void ItemView::SetRefreshEnabled(bool enabled)
+{
+  mRefreshEnabled = enabled;
+}
+
+Actor ItemView::GetItem(unsigned int itemId) const
+{
+  Actor actor;
+
+  for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
+  {
+    if( iter->first == itemId )
+    {
+      actor = iter->second;
+      break;
+    }
+  }
+
+  return actor;
+}
+
+unsigned int ItemView::GetItemId( Actor actor ) const
+{
+  unsigned int itemId( 0 );
+
+  for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
+  {
+    if( iter->second == actor )
+    {
+      itemId = iter->first;
+      break;
+    }
+  }
+
+  return itemId;
+}
+
+void ItemView::InsertItem( Item newItem, float durationSeconds )
+{
+  mAddingItems = true;
+  Vector3 layoutSize = Self().GetCurrentSize();
+
+  Actor displacedActor;
+  ItemIter afterDisplacedIter = mItemPool.end();
+
+  ItemIter foundIter = FindItemById( mItemPool, newItem.first );
+  if( mItemPool.end() != foundIter )
+  {
+    SetupActor( newItem, layoutSize );
+    Self().Add( newItem.second );
+
+    displacedActor = foundIter->second;
+    foundIter->second = newItem.second;
+
+    afterDisplacedIter = ++foundIter;
+  }
+  else
+  {
+    // Inserting before the existing item range?
+    ItemIter iter = mItemPool.begin();
+    if( iter != mItemPool.end() &&
+        iter->first > newItem.first )
+    {
+      displacedActor = iter->second;
+      iter = mItemPool.erase( iter ); // iter is still valid after the erase
+
+      afterDisplacedIter = iter;
+    }
+  }
+
+  if( displacedActor )
+  {
+    // Move the existing actors to make room
+    for( ItemIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter )
+    {
+      Actor temp = iter->second;
+      iter->second = displacedActor;
+      displacedActor = temp;
+
+      iter->second.RemoveConstraints();
+      mActiveLayout->ApplyConstraints( iter->second, iter->first, layoutSize, Self() );
+    }
+
+    // Create last item
+    ItemContainer::reverse_iterator lastIter = mItemPool.rbegin();
+    if ( lastIter != mItemPool.rend() )
+    {
+      ItemId lastId = lastIter->first;
+      Item lastItem( lastId + 1, displacedActor );
+      InsertToItemContainer( mItemPool, lastItem );
+
+      lastItem.second.RemoveConstraints();
+      mActiveLayout->ApplyConstraints( lastItem.second, lastItem.first, layoutSize, Self() );
+    }
+  }
+
+  CalculateDomainSize( layoutSize );
+
+  mAddingItems = false;
+}
+
+void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds )
+{
+  mAddingItems = true;
+  Vector3 layoutSize = Self().GetCurrentSize();
+
+  // Insert from lowest id to highest
+  ItemContainer sortedItems(newItems);
+  std::sort( sortedItems.begin(), sortedItems.end() );
+
+  for( ItemIter iter = sortedItems.begin(); sortedItems.end() != iter; ++iter )
+  {
+    Self().Add( iter->second );
+
+    ItemIter foundIter = FindItemById( mItemPool, iter->first );
+    if( mItemPool.end() != foundIter )
+    {
+      Actor moveMe = foundIter->second;
+      foundIter->second = iter->second;
+
+      // Move the existing actors to make room
+      for( ItemIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
+      {
+        Actor temp = iter->second;
+        iter->second = moveMe;
+        moveMe = temp;
+      }
+
+      // Create last item
+      ItemId lastId = mItemPool.rbegin()->first;
+      Item lastItem( lastId + 1, moveMe );
+      InsertToItemContainer( mItemPool, lastItem );
+    }
+    else
+    {
+      InsertToItemContainer( mItemPool, *iter );
+    }
+  }
+
+  // Relayout everything
+  for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  {
+    // If newly inserted
+    if( std::binary_search( sortedItems.begin(), sortedItems.end(), *iter ) )
+    {
+      SetupActor( *iter, layoutSize );
+    }
+    else
+    {
+      iter->second.RemoveConstraints();
+      mActiveLayout->ApplyConstraints( iter->second, iter->first, layoutSize, Self() );
+    }
+  }
+
+  CalculateDomainSize( layoutSize );
+
+  mAddingItems = false;
+}
+
+void ItemView::RemoveItem( unsigned int itemId, float durationSeconds )
+{
+  bool actorsReordered = RemoveActor( itemId );
+  if( actorsReordered )
+  {
+    ReapplyAllConstraints();
+
+    OnItemsRemoved();
+  }
+}
+
+void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSeconds )
+{
+  bool actorsReordered( false );
+
+  // Remove from highest id to lowest
+  ItemIdContainer sortedItems(itemIds);
+  std::sort( sortedItems.begin(), sortedItems.end() );
+
+  for( ItemIdContainer::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter )
+  {
+    if( RemoveActor( *iter ) )
+    {
+      actorsReordered = true;
+    }
+  }
+
+  if( actorsReordered )
+  {
+    ReapplyAllConstraints();
+
+    OnItemsRemoved();
+  }
+}
+
+bool ItemView::RemoveActor(unsigned int itemId)
+{
+  bool reordered( false );
+
+  ItemIter removeIter = FindItemById( mItemPool, itemId );
+  if( removeIter != mItemPool.end() )
+  {
+    ReleaseActor(itemId, removeIter->second);
+  }
+  else
+  {
+    // Removing before the existing item range?
+    ItemIter iter = mItemPool.begin();
+    if( iter != mItemPool.end() &&
+        iter->first > itemId )
+    {
+      // In order to decrement the first visible item ID
+      InsertToItemContainer( mItemPool, Item(iter->first - 1, Actor()) );
+
+      removeIter = mItemPool.begin();
+    }
+  }
+
+  if( removeIter != mItemPool.end() )
+  {
+    reordered = true;
+
+    // Adjust the remaining item IDs, for example if item 2 is removed:
+    //   Initial actors:     After insert:
+    //     ID 1 - ActorA       ID 1 - ActorA
+    //     ID 2 - ActorB       ID 2 - ActorC (previously ID 3)
+    //     ID 3 - ActorC       ID 3 - ActorB (previously ID 4)
+    //     ID 4 - ActorD
+    for (ItemIter iter = removeIter; iter != mItemPool.end(); ++iter)
+    {
+      if( iter->first < mItemPool.rbegin()->first )
+      {
+        iter->second = ( iter + 1 )->second;
+      }
+      else
+      {
+        mItemPool.erase( iter );
+        break;
+      }
+    }
+  }
+
+  return reordered;
+}
+
+void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
+{
+  mAddingItems = true;
+  Vector3 layoutSize = Self().GetCurrentSize();
+
+  SetupActor( replacementItem, layoutSize );
+  Self().Add( replacementItem.second );
+
+  const ItemIter iter = FindItemById( mItemPool, replacementItem.first );
+  if( mItemPool.end() != iter )
+  {
+    ReleaseActor(iter->first, iter->second);
+    iter->second = replacementItem.second;
+  }
+  else
+  {
+    InsertToItemContainer( mItemPool, replacementItem );
+  }
+
+  CalculateDomainSize( layoutSize );
+
+  mAddingItems = false;
+}
+
+void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durationSeconds )
+{
+  for( ConstItemIter iter = replacementItems.begin(); replacementItems.end() != iter; ++iter )
+  {
+    ReplaceItem( *iter, durationSeconds );
+  }
+}
+
+void ItemView::RemoveActorsOutsideRange( ItemRange range )
+{
+  // Remove unwanted actors from the ItemView & ItemPool
+  for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); )
+  {
+    unsigned int current = iter->first;
+
+    if( ! range.Within( current ) )
+    {
+      ReleaseActor(iter->first, iter->second);
+
+      iter = mItemPool.erase( iter ); // iter is still valid after the erase
+    }
+    else
+    {
+      ++iter;
+    }
+  }
+}
+
+void ItemView::AddActorsWithinRange( ItemRange range, const Vector3& layoutSize )
+{
+  range.end = std::min(mItemFactory.GetNumberOfItems(), range.end);
+
+  // The order of addition depends on the scroll direction.
+  if (mRefreshOrderHint)
+  {
+    for (unsigned int itemId = range.begin; itemId < range.end; ++itemId)
+    {
+      AddNewActor( itemId, layoutSize );
+    }
+  }
+  else
+  {
+    for (unsigned int itemId = range.end; itemId > range.begin; --itemId)
+    {
+      AddNewActor( itemId-1, layoutSize );
+    }
+  }
+
+  // Total number of items may change dynamically.
+  // Always recalculate the domain size to reflect that.
+  CalculateDomainSize(Self().GetCurrentSize());
+}
+
+void ItemView::AddNewActor( unsigned int itemId, const Vector3& layoutSize )
+{
+  mAddingItems = true;
+
+  if( mItemPool.end() == FindItemById( mItemPool, itemId ) )
+  {
+    Actor actor = mItemFactory.NewItem( itemId );
+
+    if( actor )
+    {
+      Item newItem( itemId, actor );
+
+      InsertToItemContainer( mItemPool, newItem );
+
+      SetupActor( newItem, layoutSize );
+      Self().Add( actor );
+    }
+  }
+
+  mAddingItems = false;
+}
+
+void ItemView::SetupActor( Item item, const Vector3& layoutSize )
+{
+  item.second.SetParentOrigin( mItemsParentOrigin );
+  item.second.SetAnchorPoint( mItemsAnchorPoint );
+
+  if( mActiveLayout )
+  {
+    Vector3 size;
+    mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size );
+    item.second.SetSize( size.GetVectorXY() );
+
+    mActiveLayout->ApplyConstraints( item.second, item.first, layoutSize, Self() );
+  }
+}
+
+void ItemView::ReleaseActor( ItemId item, Actor actor )
+{
+  Self().Remove( actor );
+  mItemFactory.ItemReleased(item, actor);
+}
+
+ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra)
+{
+  unsigned int itemCount = mItemFactory.GetNumberOfItems();
+
+  ItemRange available(0u, itemCount);
+
+  ItemRange range = layout.GetItemsWithinArea( layoutPosition, layoutSize );
+
+  if (reserveExtra)
+  {
+    // Add the reserve items for scrolling
+    unsigned int extra = layout.GetReserveItemCount(layoutSize);
+    range.begin = (range.begin >= extra) ? (range.begin - extra) : 0u;
+    range.end += extra;
+  }
+
+  return range.Intersection(available);
+}
+
+void ItemView::OnChildAdd(Actor& child)
+{
+  if(!mAddingItems)
+  {
+    // We don't want to do this downcast check for any item added by ItemView itself.
+    Dali::Toolkit::ScrollBar scrollBar = Dali::Toolkit::ScrollBar::DownCast(child);
+    if(scrollBar)
+    {
+      scrollBar.SetScrollPropertySource(Self(),
+                                        Toolkit::ItemView::Property::LAYOUT_POSITION,
+                                        Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y,
+                                        Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y,
+                                        Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE);
+    }
+  }
+
+  Scrollable::OnChildAdd( child );
+}
+
+bool ItemView::OnWheelEvent(const WheelEvent& event)
+{
+  // Respond the wheel event to scroll
+  if (mActiveLayout)
+  {
+    Actor self = Self();
+    const Vector3 layoutSize = Self().GetCurrentSize();
+    float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
+    float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
+
+    self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
+
+    mScrollStartedSignal.Emit(GetCurrentScrollPosition());
+    mRefreshEnabled = true;
+  }
+
+  if (mWheelEventFinishedTimer.IsRunning())
+  {
+    mWheelEventFinishedTimer.Stop();
+  }
+
+  mWheelEventFinishedTimer.Start();
+
+  return true;
+}
+
+bool ItemView::OnWheelEventFinished()
+{
+  if (mActiveLayout)
+  {
+    RemoveAnimation(mScrollAnimation);
+
+    // No more wheel events coming. Do the anchoring if enabled.
+    mScrollAnimation = DoAnchoring();
+    if (mScrollAnimation)
+    {
+      mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
+      mScrollAnimation.Play();
+    }
+    else
+    {
+      mScrollOvershoot = 0.0f;
+      AnimateScrollOvershoot(0.0f);
+
+      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+    }
+  }
+
+  return false;
+}
+
+void ItemView::ReapplyAllConstraints()
+{
+  Vector3 layoutSize = Self().GetCurrentSize();
+
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  {
+    unsigned int id = iter->first;
+    Actor actor = iter->second;
+
+    actor.RemoveConstraints();
+    mActiveLayout->ApplyConstraints(actor, id, layoutSize, Self());
+  }
+}
+
+void ItemView::OnItemsRemoved()
+{
+  CalculateDomainSize(Self().GetCurrentSize());
+
+  // Adjust scroll-position after an item is removed
+  if( mActiveLayout )
+  {
+    float firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize(), *mActiveLayout);
+    Self().SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
+  }
+}
+
+float ItemView::ClampFirstItemPosition( float targetPosition, const Vector3& targetSize, ItemLayout& layout, bool updateOvershoot )
+{
+  Actor self = Self();
+  float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
+  float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, targetPosition));
+  self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
+
+  if( updateOvershoot )
+  {
+    mScrollOvershoot = targetPosition - clamppedPosition;
+  }
+
+  return clamppedPosition;
+}
+
+bool ItemView::OnTouch( Actor actor, const TouchData& touch )
+{
+  // Ignore events with multiple-touch points
+  if (touch.GetPointCount() != 1)
+  {
+    return false;
+  }
+
+  if ( touch.GetState( 0 ) == PointState::DOWN )
+  {
+    // Cancel ongoing scrolling etc.
+    mGestureState = Gesture::Clear;
+
+    mScrollDistance = 0.0f;
+    mScrollSpeed = 0.0f;
+    Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
+
+    mScrollOvershoot = 0.0f;
+    AnimateScrollOvershoot(0.0f);
+
+    if(mScrollAnimation)
+    {
+      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+    }
+
+    RemoveAnimation(mScrollAnimation);
+  }
+
+  return true; // consume since we're potentially scrolling
+}
+
+void ItemView::OnPan( const PanGesture& gesture )
+{
+  Actor self = Self();
+  const Vector3 layoutSize = Self().GetCurrentSize();
+
+  RemoveAnimation(mScrollAnimation);
+
+  // Short-circuit if there is no active layout
+  if (!mActiveLayout)
+  {
+    mGestureState = Gesture::Clear;
+    return;
+  }
+
+  mGestureState = gesture.state;
+
+  switch (mGestureState)
+  {
+    case Gesture::Finished:
+    {
+      // Swipe Detection
+      if (fabsf(mScrollDistance) > mMinimumSwipeDistance &&
+          mScrollSpeed > mMinimumSwipeSpeed)
+      {
+        float direction = (mScrollDistance < 0.0f) ? -1.0f : 1.0f;
+
+        mRefreshOrderHint = true;
+
+        float currentLayoutPosition = GetCurrentLayoutPosition(0);
+        float firstItemScrollPosition = ClampFirstItemPosition(currentLayoutPosition + mScrollSpeed * direction,
+                                                               layoutSize,
+                                                               *mActiveLayout);
+
+        if (mAnchoringEnabled)
+        {
+          firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(firstItemScrollPosition);
+        }
+
+        RemoveAnimation(mScrollAnimation);
+
+        float flickAnimationDuration = Clamp( mActiveLayout->GetItemFlickAnimationDuration() * std::max(1.0f, fabsf(firstItemScrollPosition - GetCurrentLayoutPosition(0)))
+                                       , DEFAULT_MINIMUM_SWIPE_DURATION, DEFAULT_MAXIMUM_SWIPE_DURATION);
+
+        mScrollAnimation = Animation::New(flickAnimationDuration);
+        mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION ), firstItemScrollPosition, AlphaFunction::EASE_OUT );
+        mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::SCROLL_SPEED), 0.0f, AlphaFunction::EASE_OUT );
+
+        mIsFlicking = true;
+
+        // Check whether it has already scrolled to the end
+        if( fabs(currentLayoutPosition - firstItemScrollPosition) < Math::MACHINE_EPSILON_0 )
+        {
+          AnimateScrollOvershoot( 0.0f );
+          RemoveAnimation( mScrollAnimation );
+        }
+      }
+
+      // Anchoring may be triggered when there was no swipe
+      if (!mScrollAnimation)
+      {
+        mScrollAnimation = DoAnchoring();
+      }
+
+      // Reset the overshoot if no scroll animation.
+      if (!mScrollAnimation)
+      {
+        mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+
+        AnimateScrollOvershoot(0.0f, false);
+      }
+    }
+    break;
+
+    case Gesture::Started: // Fall through
+    {
+      mTotalPanDisplacement = Vector2::ZERO;
+      mScrollStartedSignal.Emit(GetCurrentScrollPosition());
+      mRefreshEnabled = true;
+    }
+
+    case Gesture::Continuing:
+    {
+      mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout);
+      mScrollSpeed = Clamp((gesture.GetSpeed() * gesture.GetSpeed() * mActiveLayout->GetFlickSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed());
+
+      // Refresh order depends on the direction of the scroll; negative is towards the last item.
+      mRefreshOrderHint = mScrollDistance < 0.0f;
+
+      float layoutPositionDelta = GetCurrentLayoutPosition(0) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor());
+
+      float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
+
+      float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT );
+
+      self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
+
+      if( ( firstItemScrollPosition >= 0.0f &&
+            currentOvershoot < 1.0f ) ||
+          ( firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) &&
+            currentOvershoot > -1.0f ) )
+      {
+        mTotalPanDisplacement += gesture.displacement;
+      }
+
+      mScrollOvershoot = CalculateScrollOvershoot();
+
+      // If the view is moved in a direction against the overshoot indicator, then the indicator should be animated off.
+      // First make sure we are not in an animation, otherwise a previously started
+      // off-animation will be overwritten as the user continues scrolling.
+      if( !mInAnimation )
+      {
+        // Check if the movement is against the current overshoot amount (if we are currently displaying the indicator).
+        if( ( ( mScrollOvershoot > Math::MACHINE_EPSILON_0 ) && ( mScrollDistance < -Math::MACHINE_EPSILON_0 ) ) ||
+          ( ( mScrollOvershoot < Math::MACHINE_EPSILON_0 ) && ( mScrollDistance > Math::MACHINE_EPSILON_0 ) ) )
+        {
+          // The user has moved against the indicator direction.
+          // First, we reset the total displacement. This means the overshoot amount will become zero the next frame,
+          // and if the user starts dragging in the overshoot direction again, the indicator will appear once more.
+          mTotalPanDisplacement = Vector2::ZERO;
+          // Animate the overshoot indicator off.
+          AnimateScrollOvershoot( 0.0f, false );
+        }
+        else
+        {
+          // Only set the property directly if we are not animating the overshoot away,
+          // as otherwise this will overwrite the animation generated value.
+          self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, mScrollOvershoot );
+        }
+      }
+    }
+    break;
+
+    case Gesture::Cancelled:
+    {
+      mScrollAnimation = DoAnchoring();
+    }
+    break;
+
+    default:
+      break;
+  }
+
+  if (mScrollAnimation)
+  {
+    mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
+    mScrollAnimation.Play();
+  }
+}
+
+bool ItemView::OnAccessibilityPan(PanGesture gesture)
+{
+  OnPan(gesture);
+  return true;
+}
+
+Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  Actor nextFocusActor;
+  if(mActiveLayout)
+  {
+    int nextItemID = 0;
+    if(!actor || actor == this->Self())
+    {
+      nextFocusActor = GetItem(nextItemID);
+    }
+    else if(actor && actor.GetParent() == this->Self())
+    {
+      int itemID = GetItemId(actor);
+      nextItemID = mActiveLayout->GetNextFocusItemID(itemID, mItemFactory.GetNumberOfItems(), direction, loopEnabled);
+      nextFocusActor = GetItem(nextItemID);
+      if(nextFocusActor == actor)
+      {
+        // need to pass NULL actor back to focus manager
+        nextFocusActor.Reset();
+        return nextFocusActor;
+      }
+    }
+    float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
+    Vector3 layoutSize = Self().GetCurrentSize();
+    if(!nextFocusActor)
+    {
+      // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
+      ItemRange viewableItems = mActiveLayout->GetItemsWithinArea(layoutPosition, layoutSize);
+      nextItemID = viewableItems.begin;
+      nextFocusActor = GetItem(nextItemID);
+    }
+  }
+  return nextFocusActor;
+}
+
+void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
+{
+  // only in this function if our chosen focus actor was actually used
+  if(commitedFocusableActor)
+  {
+    int nextItemID = GetItemId(commitedFocusableActor);
+    float layoutPosition = GetCurrentLayoutPosition(0);
+    Vector3 layoutSize = Self().GetCurrentSize();
+
+    float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
+    ScrollTo(Vector2(0.0f, scrollTo), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
+  }
+}
+
+Animation ItemView::DoAnchoring()
+{
+  Animation anchoringAnimation;
+  Actor self = Self();
+
+  if (mActiveLayout && mAnchoringEnabled)
+  {
+    float anchorPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
+
+    anchoringAnimation = Animation::New(mAnchoringDuration);
+    anchoringAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), anchorPosition, AlphaFunction::EASE_OUT );
+    anchoringAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::SCROLL_SPEED), 0.0f, AlphaFunction::EASE_OUT );
+    if(!mIsFlicking)
+    {
+      AnimateScrollOvershoot(0.0f);
+    }
+  }
+
+  return anchoringAnimation;
+}
+
+void ItemView::OnScrollFinished(Animation& source)
+{
+  Actor self = Self();
+
+  RemoveAnimation(mScrollAnimation); // mScrollAnimation is used to query whether we're scrolling
+
+  mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+
+  if(mIsFlicking && fabsf(mScrollOvershoot) > Math::MACHINE_EPSILON_1)
+  {
+    AnimateScrollOvershoot( mScrollOvershoot > 0.0f ? 1.0f : -1.0f, true);
+  }
+  else
+  {
+    // Reset the overshoot
+    AnimateScrollOvershoot( 0.0f );
+  }
+  mIsFlicking = false;
+
+  mScrollOvershoot = 0.0f;
+}
+
+void ItemView::OnLayoutActivationScrollFinished(Animation& source)
+{
+  RemoveAnimation(mScrollAnimation);
+  mRefreshEnabled = true;
+  DoRefresh(GetCurrentLayoutPosition(0), true);
+
+  // Emit the layout activated signal
+  mLayoutActivatedSignal.Emit();
+}
+
+void ItemView::OnOvershootOnFinished(Animation& animation)
+{
+  mAnimatingOvershootOn = false;
+  mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ItemView::OnOvershootOnFinished);
+  RemoveAnimation(mScrollOvershootAnimation);
+  if(mAnimateOvershootOff)
+  {
+    AnimateScrollOvershoot(0.0f);
+  }
+  mInAnimation = false;
+}
+
+void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
+{
+  Actor self = Self();
+  const Vector3 layoutSize = Self().GetCurrentSize();
+  float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
+
+  if(durationSeconds > 0.0f)
+  {
+    RemoveAnimation(mScrollAnimation);
+    mScrollAnimation = Animation::New(durationSeconds);
+    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction );
+    mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
+    mScrollAnimation.Play();
+  }
+  else
+  {
+    self.SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
+    AnimateScrollOvershoot(0.0f);
+  }
+
+  mScrollStartedSignal.Emit(GetCurrentScrollPosition());
+  mRefreshEnabled = true;
+}
+
+void ItemView::RemoveAnimation(Animation& animation)
+{
+  if(animation)
+  {
+    // Cease animating, and reset handle.
+    animation.Clear();
+    animation.Reset();
+  }
+}
+
+void ItemView::CalculateDomainSize(const Vector3& layoutSize)
+{
+  Actor self = Self();
+
+  Vector3 firstItemPosition(Vector3::ZERO);
+  Vector3 lastItemPosition(Vector3::ZERO);
+
+  if(mActiveLayout)
+  {
+    firstItemPosition = mActiveLayout->GetItemPosition( 0,0,layoutSize );
+
+    float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
+    lastItemPosition = mActiveLayout->GetItemPosition( fabs(minLayoutPosition),fabs(minLayoutPosition),layoutSize );
+
+    float domainSize;
+
+    if(IsHorizontal(mActiveLayout->GetOrientation()))
+    {
+      domainSize = fabs(firstItemPosition.x - lastItemPosition.x);
+    }
+    else
+    {
+      domainSize = fabs(firstItemPosition.y - lastItemPosition.y);
+    }
+
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector2::ZERO);
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
+
+    self.SetProperty(Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE, domainSize);
+
+    bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, isLayoutScrollable);
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, false);
+  }
+}
+
+bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
+{
+  Actor self = Self();
+
+  float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout, false );
+  float forwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition + 1.0, layoutSize, *mActiveLayout, false );
+  float backwardClampedPosition = ClampFirstItemPosition( currentLayoutPosition - 1.0, layoutSize, *mActiveLayout, false );
+
+  return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
+}
+
+float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const
+{
+  Vector3 firstItemPosition( mActiveLayout->GetItemPosition(0, layoutPosition, layoutSize ) );
+  return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y;
+}
+
+Vector2 ItemView::GetCurrentScrollPosition() const
+{
+  return Vector2(0.0f, GetScrollPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize()));
+}
+
+void ItemView::AddOverlay(Actor actor)
+{
+  actor.SetDrawMode( DrawMode::OVERLAY_2D );
+  Self().Add(actor);
+}
+
+void ItemView::RemoveOverlay(Actor actor)
+{
+  Self().Remove(actor);
+}
+
+void ItemView::ScrollTo(const Vector2& position, float duration)
+{
+  Actor self = Self();
+  const Vector3 layoutSize = Self().GetCurrentSize();
+
+  float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
+
+  if(duration > 0.0f)
+  {
+    RemoveAnimation(mScrollAnimation);
+    mScrollAnimation = Animation::New(duration);
+    mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::LAYOUT_POSITION), firstItemScrollPosition, mScrollToAlphaFunction );
+    mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
+    mScrollAnimation.Play();
+  }
+  else
+  {
+    self.SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
+    AnimateScrollOvershoot(0.0f);
+  }
+
+  mScrollStartedSignal.Emit(GetCurrentScrollPosition());
+  mRefreshEnabled = true;
+}
+
+void ItemView::SetOvershootSize( const Vector2& size )
+{
+  mOvershootSize = size;
+
+  if( mOvershootOverlay )
+  {
+    // Remove old & add new size constraint
+    mOvershootOverlay.RemoveConstraints( OVERSHOOT_SIZE_CONSTRAINT_TAG );
+    ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height );
+  }
+}
+
+void ItemView::SetOvershootEffectColor( const Vector4& color )
+{
+  mOvershootEffectColor = color;
+  if( mOvershootOverlay )
+  {
+    mOvershootOverlay.SetColor( color );
+  }
+}
+
+void ItemView::EnableScrollOvershoot( bool enable )
+{
+  Actor self = Self();
+  if( enable )
+  {
+    if( !mOvershootOverlay )
+    {
+      Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
+      mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
+      mOvershootOverlay.SetColor(mOvershootEffectColor);
+      mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
+      mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+      mOvershootOverlay.SetDrawMode( DrawMode::OVERLAY_2D );
+      self.Add(mOvershootOverlay);
+
+      ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height );
+
+      Constraint constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint );
+      constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<bool>( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint );
+      constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) );
+      constraint.Apply();
+
+      constraint = Constraint::New<float>( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() );
+      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
+      constraint.Apply();
+    }
+  }
+  else
+  {
+    if( mOvershootOverlay )
+    {
+      self.Remove(mOvershootOverlay);
+      mOvershootOverlay.Reset();
+    }
+  }
+}
+
+float ItemView::CalculateScrollOvershoot()
+{
+  float overshoot = 0.0f;
+
+  if(mActiveLayout)
+  {
+    // The overshoot must be calculated from the accumulated pan gesture displacement
+    // since the pan gesture starts.
+    Actor self = Self();
+    float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
+    float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance;
+    float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
+    float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, positionDelta));
+    overshoot = positionDelta - clamppedPosition;
+  }
+
+  return overshoot > 0.0f ? std::min(overshoot, 1.0f) : std::max(overshoot, -1.0f);
+}
+
+void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
+{
+  bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
+
+  // make sure we animate back if needed
+  mAnimateOvershootOff = animateBack || (!animatingOn && mAnimatingOvershootOn);
+
+  if( mAnimatingOvershootOn )
+  {
+    // animating on, do not allow animate off
+    return;
+  }
+
+  Actor self = Self();
+
+  if(mOvershootAnimationSpeed > Math::MACHINE_EPSILON_0)
+  {
+    float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT );
+    float duration = 0.0f;
+
+    if (mOvershootOverlay)
+    {
+      duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed;
+    }
+
+    // Mark the animation as in progress to prevent manual property sets overwriting it.
+    mInAnimation = true;
+    mAnimatingOvershootOn = animatingOn;
+    RemoveAnimation(mScrollOvershootAnimation);
+    mScrollOvershootAnimation = Animation::New(duration);
+    mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
+    mScrollOvershootAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
+    mScrollOvershootAnimation.Play();
+  }
+  else
+  {
+    self.SetProperty( Toolkit::ItemView::Property::OVERSHOOT, overshootAmount );
+  }
+}
+
+void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
+{
+  if( parentOrigin != mItemsParentOrigin )
+  {
+    mItemsParentOrigin = parentOrigin;
+    for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    {
+      iter->second.SetParentOrigin(parentOrigin);
+    }
+  }
+}
+
+Vector3 ItemView::GetItemsParentOrigin() const
+{
+  return mItemsParentOrigin;
+}
+
+void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
+{
+  if( anchorPoint != mItemsAnchorPoint )
+  {
+    mItemsAnchorPoint = anchorPoint;
+    for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    {
+      iter->second.SetAnchorPoint(anchorPoint);
+    }
+  }
+}
+
+Vector3 ItemView::GetItemsAnchorPoint() const
+{
+  return mItemsAnchorPoint;
+}
+
+void ItemView::GetItemsRange(ItemRange& range)
+{
+  if( !mItemPool.empty() )
+  {
+    range.begin = mItemPool.begin()->first;
+    range.end = mItemPool.rbegin()->first + 1;
+  }
+  else
+  {
+    range.begin = 0;
+    range.end = 0;
+  }
+}
+
+bool ItemView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), LAYOUT_ACTIVATED_SIGNAL ) )
+  {
+    itemView.LayoutActivatedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void ItemView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) );
+
+  if( itemView )
+  {
+    ItemView& itemViewImpl( GetImpl( itemView ) );
+    switch( index )
+    {
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED:
+      {
+        itemViewImpl.SetMinimumSwipeSpeed( value.Get<float>() );
+        break;
+      }
+
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
+      {
+        itemViewImpl.SetMinimumSwipeDistance( value.Get<float>() );
+        break;
+      }
+
+      case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        itemViewImpl.SetWheelScrollDistanceStep( value.Get<float>() );
+        break;
+      }
+
+      case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
+      {
+        itemViewImpl.SetAnchoring( value.Get<bool>() );
+        break;
+      }
+
+      case Toolkit::ItemView::Property::REFRESH_INTERVAL:
+      {
+        itemViewImpl.SetRefreshInterval( value.Get<float>() );
+        break;
+      }
+
+      case Toolkit::ItemView::Property::LAYOUT:
+      {
+        // Get a Property::Array from the property if possible.
+        Property::Array layoutArray;
+        if( value.Get( layoutArray ) )
+        {
+          itemViewImpl.SetLayoutArray( layoutArray );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Array ItemView::GetLayoutArray()
+{
+  return mlayoutArray;
+}
+
+void ItemView::SetLayoutArray( const Property::Array& layouts )
+{
+  mlayoutArray = layouts;
+  const int layoutCount = GetLayoutCount();
+  if( layoutCount > 0 )
+  {
+    for(int index = layoutCount - 1; index >= 0; --index)
+    {
+      RemoveLayout(index);
+      if(index == 0) break;
+    }
+  }
+
+  for( unsigned int arrayIdx = 0, arrayCount = layouts.Count(); arrayIdx < arrayCount; ++arrayIdx )
+  {
+    const Property::Value& element = layouts.GetElementAt( arrayIdx );
+
+    Property::Map* layout = element.GetMap();
+    if( layout != NULL )
+    {
+      for( unsigned int mapIdx = 0, mapCount = (*layout).Count(); mapIdx < mapCount; ++mapIdx )
+      {
+        KeyValuePair propertyPair( (*layout).GetKeyValue( mapIdx ) );
+
+        if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+        {
+          int layoutType = propertyPair.second.Get<int>();
+          if(layoutType <= DefaultItemLayout::SPIRAL && layoutType >= DefaultItemLayout::DEPTH)
+          {
+            //DEPTH, GRID, LIST, SPIRAL
+            switch(DefaultItemLayout::Type(layoutType))
+            {
+              case DefaultItemLayout::DEPTH:
+              {
+                Internal::DepthLayoutPtr depthLayout = Internal::DepthLayout::New();
+                (*depthLayout).SetLayoutProperties(*layout);
+                (*depthLayout).SetDepthLayoutProperties(*layout);
+                AddLayout(*depthLayout);
+                break;
+              }
+              case DefaultItemLayout::GRID:
+              {
+                Internal::GridLayoutPtr gridLayout = Internal::GridLayout::New();
+                (*gridLayout).SetLayoutProperties(*layout);
+                (*gridLayout).SetGridLayoutProperties(*layout);
+                AddLayout(*gridLayout);
+                break;
+              }
+              case DefaultItemLayout::LIST:
+              {
+                Internal::GridLayoutPtr listLayout = Internal::GridLayout::New();
+                listLayout->SetNumberOfColumns( 1 );
+                (*listLayout).SetLayoutProperties(*layout);
+                (*listLayout).SetGridLayoutProperties(*layout);
+                AddLayout(*listLayout);
+                break;
+              }
+              case DefaultItemLayout::SPIRAL:
+              {
+                Internal::SpiralLayoutPtr spiralLayout = Internal::SpiralLayout::New();
+                (*spiralLayout).SetLayoutProperties(*layout);
+                (*spiralLayout).SetSpiralLayoutProperties(*layout);
+                AddLayout(*spiralLayout);
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) );
+
+  if( itemView )
+  {
+    ItemView& itemViewImpl( GetImpl( itemView ) );
+    switch( index )
+    {
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED:
+      {
+        value = itemViewImpl.GetMinimumSwipeSpeed();
+        break;
+      }
+
+      case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
+      {
+        value = itemViewImpl.GetMinimumSwipeDistance();
+        break;
+      }
+
+      case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        value = itemViewImpl.GetWheelScrollDistanceStep();
+        break;
+      }
+
+      case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
+      {
+        value = itemViewImpl.GetAnchoring();
+        break;
+      }
+
+      case Toolkit::ItemView::Property::REFRESH_INTERVAL:
+      {
+        value = itemViewImpl.GetRefreshInterval();
+        break;
+      }
+
+      case Toolkit::ItemView::Property::LAYOUT:
+      {
+        Property::Array layouts= itemViewImpl.GetLayoutArray();
+        value = layouts;
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+bool ItemView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  Dali::BaseHandle handle( object );
+
+  Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
+
+  DALI_ASSERT_ALWAYS( itemView );
+
+  if( 0 == strcmp( actionName.c_str(), ACTION_STOP_SCROLLING ) )
+  {
+    GetImpl( itemView ).DoStopScrolling();
+  }
+  else if ( 0 == strcmp( actionName.c_str(), ACTION_ENABLE_REFRESH ) )
+  {
+    GetImpl( itemView ).SetRefreshNotificationEnabled( true );
+  }
+  else if ( 0 == strcmp( actionName.c_str(), ACTION_DISABLE_REFRESH ) )
+  {
+    GetImpl( itemView ).SetRefreshNotificationEnabled( false );
+  }
+
+  return true;
+}
+
+void ItemView::DoStopScrolling()
+{
+  if( mScrollAnimation )
+  {
+    mScrollAnimation.Stop();
+    mScrollAnimation.Reset();
+  }
+}
+
+void ItemView::SetRefreshNotificationEnabled( bool enabled )
+{
+  mRefreshNotificationEnabled = enabled;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h
new file mode 100755 (executable)
index 0000000..9cb2df6
--- /dev/null
@@ -0,0 +1,675 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ITEM_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_ITEM_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/property-array.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ItemView;
+
+typedef IntrusivePtr<ItemView> ItemViewPtr;
+
+/**
+ * ItemView is a scrollable layout container.
+ * Multiple ItemLayouts may be provided, to determine the logical position of each item a layout.
+ * Actor-ID pairs are provided from a shared ItemFactory, to display the currently visible items.
+ */
+class ItemView : public Scrollable
+{
+public:
+
+  // Signals
+  typedef Toolkit::ItemView::LayoutActivatedSignalType LayoutActivatedSignalType;
+
+public:
+
+  /**
+   * Create a new ItemView.
+   * @param[in] factory The factory which provides ItemView with items.
+   * @return A public handle to the newly allocated ItemView.
+   */
+  static Dali::Toolkit::ItemView New(ItemFactory& factory);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetLayoutCount
+   */
+  unsigned int GetLayoutCount() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::AddLayout
+   */
+  void AddLayout(ItemLayout& layout);
+
+  /**
+   * @copydoc Toolkit::ItemView::RemoveLayout
+   */
+  void RemoveLayout(unsigned int layoutIndex);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetLayout
+   */
+  ItemLayoutPtr GetLayout(unsigned int layoutIndex) const;
+
+  /**
+   * @copydoc Toolkit::ItemView::GetActiveLayout
+   */
+  ItemLayoutPtr GetActiveLayout() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::GetCurrentLayoutPosition
+   */
+  float GetCurrentLayoutPosition(unsigned int itemId) const;
+
+  /**
+   * @copydoc Toolkit::ItemView::ActivateLayout
+   */
+  void ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::DeactivateCurrentLayout
+   */
+  void DeactivateCurrentLayout();
+
+  /**
+   * @copydoc Toolkit::ItemView::SetMinimumSwipeSpeed
+   */
+  void SetMinimumSwipeSpeed(float speed);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetMinimumSwipeSpeed
+   */
+  float GetMinimumSwipeSpeed() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::SetMinimumSwipeDistance
+   */
+  void SetMinimumSwipeDistance(float distance);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetMinimumSwipeDistance
+   */
+  float GetMinimumSwipeDistance() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::SetWheelScrollDistanceStep
+   */
+  void SetWheelScrollDistanceStep(float step);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetWheelScrollDistanceStep
+   */
+  float GetWheelScrollDistanceStep() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::SetAnchoring
+   */
+  void SetAnchoring(bool enabled);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetAnchoring
+   */
+  bool GetAnchoring() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::SetAnchoringDuration
+   */
+  void SetAnchoringDuration(float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetAnchoringDuration
+   */
+  float GetAnchoringDuration() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::ScrollToItem
+   */
+  void ScrollToItem(unsigned int itemId, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::SetRefreshInterval
+   */
+  void SetRefreshInterval(float intervalLayoutPositions);
+
+  /**
+   * @copydoc Toolkit::ItemView::GetRefreshInterval
+   */
+  float GetRefreshInterval() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::Refresh
+   */
+  void Refresh();
+
+  /**
+   * @copydoc Toolkit::ItemView::GetItem
+   */
+  Actor GetItem(unsigned int itemId) const;
+
+  /**
+   * @copydoc Toolkit::ItemView::GetItemId
+   */
+  unsigned int GetItemId(Actor actor) const;
+
+  /**
+   * @copydoc Toolkit::ItemView::InsertItem
+   */
+  void InsertItem(Item newItem, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::InsertItem
+   */
+  void InsertItems(const ItemContainer& newItems, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::RemoveItem
+   */
+  void RemoveItem(ItemId itemId, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::InsertItem
+   */
+  void RemoveItems(const ItemIdContainer& itemIds, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::InsertItem
+   */
+  void ReplaceItem(Item replacementItem, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::ItemView::InsertItem
+   */
+  void ReplaceItems(const ItemContainer& replacementItems, float durationSeconds);
+
+  /**
+   * @copydoc Toolkit::Scrollable::GetCurrentScrollPosition
+   */
+  Vector2 GetCurrentScrollPosition() const;
+
+  /**
+   * @copydoc Toolkit::Scrollable::AddOverlay()
+   */
+  void AddOverlay(Actor actor);
+
+  /**
+   * @copydoc Toolkit::Scrollable::RemoveOverlay()
+   */
+  void RemoveOverlay(Actor actor);
+
+  /**
+   * @copydoc Toolkit::Scrollable::ScrollTo(const Vector2& position, float duration)
+   */
+  void ScrollTo(const Vector2& position, float duration);
+
+  /**
+   * @copydoc Toolkit::Internal::Scrollable::SetOvershootSize
+   */
+  void SetOvershootSize( const Vector2& size );
+
+  /**
+   * @copydoc Toolkit::Internal::Scrollable::SetOvershootEffectColor
+   */
+  void SetOvershootEffectColor( const Vector4& color );
+
+  /**
+   * @brief Set whether to enable automatic refresh or not. When refresh is disabled,
+   * ItemView will not automatically refresh the cache in the given interval when the
+   * layout position is changed. This is useful in some cases, for example, automatic
+   * refresh is not needed during fast scrolling, otherwise it will cache unneeded
+   * items when the layout position changes quickly.
+   *
+   * @param[in] enabled True to enable automatic refresh or false to disable it.
+   */
+  void SetRefreshEnabled(bool enabled);
+
+  /**
+   * @brief Helper to perform the refresh.
+   *
+   * @param[in] currentLayoutPosition The current layout position.
+   * @param[in] cacheExtra Whether to cache extra items during refresh.
+   */
+  void DoRefresh(float currentLayoutPosition, bool cacheExtra);
+
+  /**
+   * @copydoc Toolkit::ItemView::SetItemsParentOrigin
+   */
+  void SetItemsParentOrigin( const Vector3& parentOrigin );
+
+  /**
+   * @copydoc Toolkit::ItemView::GetItemsParentOrigin
+   */
+  Vector3 GetItemsParentOrigin() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::SetItemsAnchorPoint
+   */
+  void SetItemsAnchorPoint( const Vector3& anchorPoint );
+
+  /**
+   * @copydoc Toolkit::ItemView::GetItemsAnchorPoint
+   */
+  Vector3 GetItemsAnchorPoint() const;
+
+  /**
+   * @copydoc Toolkit::ItemView::GetItemsRange
+   */
+  void GetItemsRange(ItemRange& range);
+
+  /**
+   * @copydoc Toolkit::ItemView::LayoutActivatedSignal()
+   */
+  LayoutActivatedSignalType& LayoutActivatedSignal()
+  {
+    return mLayoutActivatedSignal;
+  }
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  //properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * Performs actions as requested using the action name.
+   * @param[in] object The object on which to perform the action.
+   * @param[in] actionName The action to perform.
+   * @param[in] attributes The attributes with which to perfrom this action.
+   * @return true if action has been accepted by this control
+   */
+  static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes );
+
+  /**
+   * Helper for DoAction( ACTION_STOP_SCROLLING ).
+   */
+  void DoStopScrolling();
+
+  /**
+   * Helper for DoAction( ACTION_ENABLE/DISABLE_REFRESH_NOTIFICATIONS ).
+   * @param[in] enabled Whether to disable refresh notifications or not.
+   */
+  void SetRefreshNotificationEnabled( bool enabled );
+
+private:
+
+  /**
+   * Get all the layouts used in the ItemView.
+   * @return The layout array
+   */
+  Property::Array GetLayoutArray();
+
+  /**
+   * Set all the layouts. that will be used in the ItemView.
+   * @param[in] layouts The layouts used in the itemView.
+   */
+  void SetLayoutArray( const Property::Array& layouts );
+
+  /**
+   * Remove an Actor if found in the ItemPool.
+   * @param[in] itemId The item to remove.
+   * @return True if the remaining actors were reordered.
+   */
+  bool RemoveActor( unsigned int itemId );
+
+  /**
+   * Remove any Actors outside a given range.
+   * @param[in] @param[in] range The range of required items.
+   */
+  void RemoveActorsOutsideRange( ItemRange range );
+
+  /**
+   * Add a range of Actors, if they are not already in the ItemPool.
+   * @param[in] range The range of Item IDs to associate with the new actors.
+   * @param[in] layoutSize The layout-size.
+   */
+  void AddActorsWithinRange( ItemRange range, const Vector3& layoutSize );
+
+  /**
+   * Add a new Actor, if not already in the ItemPool.
+   * @param[in] item The ID for the new item.
+   * @param[in] layoutSize The layout-size.
+   */
+  void AddNewActor( ItemId item, const Vector3& layoutSize );
+
+  /**
+   * Apply the constraints etc. that are required for ItemView children.
+   * @param[in] item The item to setup.
+   * @param[in] layoutSize The layout-size.
+   */
+  void SetupActor( Item item, const Vector3& layoutSize );
+
+  /**
+   * Remove the Actor from the ItemPool and notify the ItemFactory the actor has been released by ItemView.
+   * @param[in] item The ID for the item to be released.
+   * @param[in] actor The actor to be removed from ItemView.
+   */
+  void ReleaseActor( ItemId item, Actor actor );
+
+private: // From CustomActorImpl
+
+  /**
+   * From CustomActorImpl; called after a child has been added to the owning actor.
+   * @param[in] child The child which has been added.
+   */
+  virtual void OnChildAdd(Actor& child);
+
+  /**
+   * From CustomActorImpl; called after a wheel-event is received by the owning actor.
+   * @param[in] event The wheel event.
+   * @return True if the event should be consumed.
+   */
+  virtual bool OnWheelEvent(const WheelEvent& event);
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::OnAccessibilityPan()
+   */
+  virtual bool OnAccessibilityPan(PanGesture gesture);
+
+  /**
+   * @copydoc Toolkit::Control::GetNextKeyboardFocusableActor()
+   */
+  virtual Actor GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled);
+
+  /**
+   * @copydoc Toolkit::Control::OnKeyboardFocusChangeCommitted()
+   */
+  virtual void OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor);
+
+protected:
+
+  /**
+   * Construct a new ItemView.
+   * @param[in] factory The factory which provides ItemView with items.
+   */
+  ItemView(ItemFactory& factory);
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ItemView();
+
+private:
+
+  // Undefined
+  ItemView(const ItemView&);
+
+  // Undefined
+  ItemView& operator=(const ItemView& rhs);
+
+  /**
+   * Helper to re-apply all the constraints after items have been inserted, removed etc.
+   * @param[in] durationSeconds The time taken to fully constrain the actors.
+   */
+  void ReapplyAllConstraints();
+
+  /**
+   * Helper to relayout after item(s) are removed.
+   */
+  void OnItemsRemoved();
+
+  /**
+   * Helper to remove items outside a given range.
+   * @param[in] range The range of required items.
+   */
+  void RemoveItems(ItemRange range);
+
+  /**
+   * Helper to add a range of items, if not already in the ItemPool.
+   * @param[in] layout The layout used to position the new items.
+   * @param[in] layoutSize The current size of the layout.
+   * @param[in] range The range of required items.
+   */
+  void AddItems(ItemLayout& layout, const Vector3& layoutSize, ItemRange range);
+
+  /**
+   * Helper to find the range of items to populate with.
+   * @param[in] layout The current layout.
+   * @param[in] range The range of items.
+   * @param[in] reserveExtra True if reserve items should be included.
+   */
+  ItemRange GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra);
+
+  // Input Handling
+
+  /**
+   * Helper to clamp the first-item position when dragging/swiping.
+   * @param[in] targetPosition The target position of the drag etc.
+   * @param[in] targetSize The target ItemView & layout size.
+   * @param[in] layout The current layout.
+   * @param[in] updateOvershoot False stops the current overshoot value from being clamped also.
+   * @return The clamped first-item position.
+   */
+  float ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout, bool updateOvershoot = true);
+
+  /**
+   * Called after a touch-signal is received by the owning actor.
+   * @param[in] actor The touched actor.
+   * @param[in] touch The touch information.
+   * @return True if the event should be consumed.
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Called upon pan gesture event.
+   *
+   * @param[in] gesture The gesture event.
+   */
+  void OnPan( const PanGesture& pan );
+
+  /**
+   * Helper to handle anchoring animations.
+   * @return The animation, or an uninitialized handle if not necessary.
+   */
+  Animation DoAnchoring();
+
+  /**
+   * Callback from scroll animations
+   * @param[in] animation The scroll-animation which has finished.
+   */
+  void OnScrollFinished(Animation& animation);
+
+  /**
+   * Callback from layout activation scroll animations
+   * @param[in] animation The scroll-animation which has finished.
+   */
+  void OnLayoutActivationScrollFinished(Animation& animation);
+
+  /**
+   * Called by animation system when overshoot has finished animating to maximum (either -1.0f or 1.0f)
+   *
+   * @param[in] animation the animation that has finished
+   */
+  void OnOvershootOnFinished(Animation& animation);
+
+  /**
+   * This is called after a timeout when no new wheel event is received for a certain period of time.
+   * @return will return false; one-shot timer.
+   */
+  bool OnWheelEventFinished();
+
+  /**
+   * Stops and removes animation if exists.
+   * @param[in,out] animation The animation handle to be removed.
+   */
+  void RemoveAnimation(Animation& animation);
+
+  /**
+   * @copydoc Toolkit::Internal::Scrollable::EnableScrollOvershoot
+   */
+  virtual void EnableScrollOvershoot( bool enable );
+
+  /**
+   * Helper to calculate the scroll overshoot according to the pan gesture displacement.
+   * @return The scroll overshoot.
+   */
+  float CalculateScrollOvershoot();
+
+  /**
+   * Helper to calculate the scroll overshoot according to the pan gesture displacement.
+   *
+   * @param[in] overshootAmount amount to animate to
+   * @param[in] animateBack whether to animate back to zero immediately after
+   * @return The scroll overshoot.
+   */
+  void AnimateScrollOvershoot(float overshootAmount, bool animateBack = false);
+
+  /**
+   * Gets the scroll position in pixels according to the logical layout position.
+   * @param[in] layoutSize The current size of the layout.
+   */
+  float GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const;
+
+  /**
+   * Calculates the minimum and maximum positions for each axis to scroll to.
+   * @param[in] layoutSize The current size of the layout.
+   */
+  void CalculateDomainSize(const Vector3& layoutSize);
+
+  /**
+   * Calculates whether we want to allow current item view to scroll.
+   * @param[in] layoutSize The current size of the layout.
+   * @return    true if itemview is scrollable
+   */
+  bool IsLayoutScrollable(const Vector3& layoutSize);
+
+  /**
+   * Callback when the current layout position of ItemView changes in both positive
+   * and negative directions by the specified amount. Refresh the ItemView to create
+   * newly visible items.
+   * @param[in] source the property notification that triggered this callback
+   */
+  void OnRefreshNotification(PropertyNotification& source);
+
+private:
+
+  Property::Array mlayoutArray;
+
+  ItemContainer mItemPool;
+  ItemFactory& mItemFactory;
+  std::vector< ItemLayoutPtr > mLayouts;            ///< Container of Dali::Toolkit::ItemLayout objects
+  Actor mOvershootOverlay;                          ///< The overlay actor for overshoot effect
+  Animation mResizeAnimation;
+  Animation mScrollAnimation;
+  Animation mScrollOvershootAnimation;
+  Timer mWheelEventFinishedTimer;                   ///< The timer to determine whether there is no wheel event received for a certain period of time.
+  PropertyNotification mRefreshNotification;        ///< Stores the property notification used for item view refresh
+  LayoutActivatedSignalType mLayoutActivatedSignal;
+  Vector3 mActiveLayoutTargetSize;
+  Vector3 mItemsParentOrigin;
+  Vector3 mItemsAnchorPoint;
+  Vector2 mTotalPanDisplacement;
+  ItemLayout* mActiveLayout;
+
+  float mAnchoringDuration;
+  float mRefreshIntervalLayoutPositions;            ///< Refresh item view when the layout position changes by this interval in both positive and negative directions.
+  float mMinimumSwipeSpeed;
+  float mMinimumSwipeDistance;
+  float mWheelScrollDistanceStep;                   ///< The step of scroll distance in actor coordinates for each wheel event received.
+  float mScrollDistance;
+  float mScrollSpeed;
+  float mScrollOvershoot;
+
+  Dali::Gesture::State mGestureState    : 4;
+  bool mAnimatingOvershootOn            : 1;        ///< Whether we are currently animating overshoot to 1.0f/-1.0f (on) or to 0.0f (off)
+  bool mAnimateOvershootOff             : 1;        ///< Whether we are currently animating overshoot to 1.0f/-1.0f (on) or to 0.0f (off)
+  bool mAnchoringEnabled                : 1;
+  bool mRefreshOrderHint                : 1;        ///< True if scrolling towards the last item
+  bool mIsFlicking                      : 1;
+  bool mAddingItems                     : 1;
+  bool mRefreshEnabled                  : 1;        ///< Whether to refresh the cache automatically
+  bool mRefreshNotificationEnabled      : 1;        ///< Whether to disable refresh notifications or not.
+  bool mInAnimation                     : 1;        ///< Keeps track of whether an animation is controlling the overshoot property.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ItemView& GetImpl(Toolkit::ItemView& itemView)
+{
+  DALI_ASSERT_ALWAYS(itemView);
+
+  Dali::RefObject& handle = itemView.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ItemView&>(handle);
+}
+
+inline const Toolkit::Internal::ItemView& GetImpl(const Toolkit::ItemView& itemView)
+{
+  DALI_ASSERT_ALWAYS(itemView);
+
+  const Dali::RefObject& handle = itemView.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ItemView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_ITEM_VIEW_H
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.cpp b/dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.cpp
new file mode 100755 (executable)
index 0000000..94bf0d6
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/constraint.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace // unnamed namespace
+{
+
+const float DEFAULT_ITEMS_PER_SPIRAL_TURN = 9.5f;
+const float DEFAULT_ITEM_SPACING_RADIANS = Math::PI*2.0f/DEFAULT_ITEMS_PER_SPIRAL_TURN;
+
+const float DEFAULT_REVOLUTION_DISTANCE = 190.0f;
+const float DEFAULT_ITEM_DESCENT = DEFAULT_REVOLUTION_DISTANCE / DEFAULT_ITEMS_PER_SPIRAL_TURN;
+
+const float DEFAULT_TOP_ITEM_ALIGNMENT = -0.125f;
+
+const float DEFAULT_SCROLL_SPEED_FACTOR = 0.01f;
+const float DEFAULT_MAXIMUM_SWIPE_SPEED = 30.0f;
+const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.1f;
+
+float GetDefaultSpiralRadiusFunction(const Vector3& layoutSize)
+{
+  return layoutSize.width*0.4f;
+}
+
+struct SpiralPositionConstraint
+{
+  SpiralPositionConstraint( unsigned int itemId, float spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment )
+  : mItemId( itemId ),
+    mSpiralRadius( spiralRadius ),
+    mItemSpacingRadians( itemSpacingRadians ),
+    mItemDescent( itemDescent ),
+    mTopItemAlignment( topItemAlignment )
+  {
+  }
+
+  inline void OrientationUp( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float angle = -Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
+
+    current.x = -mSpiralRadius * cosf( angle );
+    current.y = ( mItemDescent * layoutPosition ) + layoutSize.height * mTopItemAlignment;
+    current.z = -mSpiralRadius * sinf( angle );
+  }
+
+  inline void OrientationLeft( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float angle = Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
+
+    current.x = ( mItemDescent * layoutPosition ) + layoutSize.width * mTopItemAlignment;
+    current.y = -mSpiralRadius * cosf( angle );
+    current.z = mSpiralRadius * sinf( angle );
+  }
+
+  inline void OrientationDown( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float angle = Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
+
+    current.x = -mSpiralRadius * cosf( angle );
+    current.y = ( -mItemDescent * layoutPosition ) - layoutSize.height * mTopItemAlignment;
+    current.z = mSpiralRadius * sinf(angle);
+  }
+
+  inline void OrientationRight( Vector3& current, float layoutPosition, const Vector3& layoutSize )
+  {
+    float angle = -Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
+
+    current.x = (-mItemDescent * layoutPosition) - layoutSize.width * mTopItemAlignment;
+    current.y = -mSpiralRadius * cosf( angle );
+    current.z = -mSpiralRadius * sinf( angle );
+  }
+
+  void OrientationUp( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    OrientationUp( current, layoutPosition, layoutSize );
+  }
+
+  void OrientationLeft( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    OrientationLeft( current, layoutPosition, layoutSize );
+  }
+
+  void OrientationDown( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    OrientationDown( current, layoutPosition, layoutSize );
+  }
+
+  void OrientationRight( Vector3& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    OrientationRight( current, layoutPosition, layoutSize );
+  }
+
+  unsigned int mItemId;
+  float mSpiralRadius;
+  float mItemSpacingRadians;
+  float mItemDescent;
+  float mTopItemAlignment;
+};
+
+struct SpiralRotationConstraint
+{
+  SpiralRotationConstraint( unsigned int itemId, float itemSpacingRadians )
+  : mItemId( itemId ),
+    mItemSpacingRadians( itemSpacingRadians )
+  {
+  }
+
+  void OrientationUp( Quaternion& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float angle = -mItemSpacingRadians * layoutPosition;
+
+    current = Quaternion( Radian( angle ), Vector3::YAXIS);
+  }
+
+  void OrientationLeft( Quaternion& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float angle = -mItemSpacingRadians * layoutPosition;
+
+    current = Quaternion( Radian( -Math::PI * 0.5f ), Vector3::ZAXIS ) * Quaternion( Radian( angle ), Vector3::YAXIS );
+  }
+
+  void OrientationDown( Quaternion& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float angle = -mItemSpacingRadians * layoutPosition;
+
+    current = Quaternion( Radian( -Math::PI ), Vector3::ZAXIS) * Quaternion( Radian( angle ), Vector3::YAXIS );
+  }
+
+  void OrientationRight( Quaternion& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    float angle = -mItemSpacingRadians * layoutPosition;
+
+    current = Quaternion( Radian( -Math::PI * 1.5f ), Vector3::ZAXIS) * Quaternion( Radian( angle ), Vector3::YAXIS );
+  }
+
+  unsigned int mItemId;
+  float mItemSpacingRadians;
+};
+
+struct SpiralColorConstraint
+{
+  SpiralColorConstraint( unsigned int itemId, float itemSpacingRadians )
+  : mItemId( itemId ),
+    mItemSpacingRadians( itemSpacingRadians )
+  {
+  }
+
+  void operator()( Vector4& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    Radian angle( mItemSpacingRadians * fabsf( layoutPosition ) / Dali::ANGLE_360 );
+
+    float progress = angle - floorf( angle ); // take fractional bit only to get between 0.0 - 1.0
+    progress = (progress > 0.5f) ? 2.0f*(1.0f - progress) : progress*2.0f;
+
+    float darkness(1.0f);
+    {
+      const float startMarker = 0.10f; // The progress at which darkening starts
+      const float endMarker   = 0.35f; // The progress at which darkening ends
+      const float minDarkness = 0.15f; // The darkness at end marker
+
+      if (progress > endMarker)
+      {
+        darkness = minDarkness;
+      }
+      else if (progress > startMarker)
+      {
+        darkness = 1.0f - ( (1.0f - minDarkness) * ((progress-startMarker) / (endMarker-startMarker)) );
+      }
+    }
+
+    current.r = current.g = current.b = darkness;
+  }
+
+  unsigned int mItemId;
+  float mItemSpacingRadians;
+};
+
+struct SpiralVisibilityConstraint
+{
+  SpiralVisibilityConstraint( unsigned int itemId, float itemSpacingRadians, float itemDescent, float topItemAlignment )
+  : mItemId( itemId ),
+    mItemSpacingRadians( itemSpacingRadians ),
+    mItemDescent( itemDescent ),
+    mTopItemAlignment( topItemAlignment )
+  {
+  }
+
+  void Portrait( bool& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    float itemsCachedBeforeTopItem = layoutSize.height*(mTopItemAlignment+0.5f) / mItemDescent;
+    current = ( layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= ( layoutSize.height / mItemDescent ) + 1.0f );
+  }
+
+  void Landscape( bool& current, const PropertyInputContainer& inputs )
+  {
+    float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
+    const Vector3& layoutSize = inputs[1]->GetVector3();
+    float itemsCachedBeforeTopItem = layoutSize.width*(mTopItemAlignment+0.5f) / mItemDescent;
+    current = ( layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= ( layoutSize.width / mItemDescent ) + 1.0f );
+  }
+
+  unsigned int mItemId;
+  float mItemSpacingRadians;
+  float mItemDescent;
+  float mTopItemAlignment;
+};
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+struct SpiralLayout::Impl
+{
+  Impl()
+  : mItemSpacingRadians(DEFAULT_ITEM_SPACING_RADIANS),
+    mRevolutionDistance(DEFAULT_REVOLUTION_DISTANCE),
+    mItemDescent(DEFAULT_ITEM_DESCENT),
+    mTopItemAlignment(DEFAULT_TOP_ITEM_ALIGNMENT),
+    mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
+    mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
+    mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
+  {
+  }
+
+  float mItemSpacingRadians;
+  float mRevolutionDistance;
+  float mItemDescent;
+  float mTopItemAlignment;
+  float mScrollSpeedFactor;
+  float mMaximumSwipeSpeed;
+  float mItemFlickAnimationDuration;
+};
+
+SpiralLayoutPtr SpiralLayout::New()
+{
+  return SpiralLayoutPtr(new SpiralLayout());
+}
+
+SpiralLayout::~SpiralLayout()
+{
+  delete mImpl;
+}
+
+void SpiralLayout::SetItemSpacing(Radian itemSpacing)
+{
+  mImpl->mItemSpacingRadians = itemSpacing;
+
+  float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
+  mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
+}
+
+Radian SpiralLayout::GetItemSpacing() const
+{
+  return Radian( mImpl->mItemSpacingRadians );
+}
+
+void SpiralLayout::SetRevolutionDistance(float distance)
+{
+  mImpl->mRevolutionDistance = distance;
+
+  float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
+  mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
+}
+
+float SpiralLayout::GetRevolutionDistance() const
+{
+  return mImpl->mRevolutionDistance;
+}
+
+void SpiralLayout::SetTopItemAlignment(float alignment)
+{
+  mImpl->mTopItemAlignment = alignment;
+}
+
+float SpiralLayout::GetTopItemAlignment() const
+{
+  return mImpl->mTopItemAlignment;
+}
+
+void SpiralLayout::SetScrollSpeedFactor(float scrollSpeed)
+{
+  mImpl->mScrollSpeedFactor = scrollSpeed;
+}
+
+void SpiralLayout::SetMaximumSwipeSpeed(float speed)
+{
+  mImpl->mMaximumSwipeSpeed = speed;
+}
+
+void SpiralLayout::SetItemFlickAnimationDuration(float durationSeconds)
+{
+  mImpl->mItemFlickAnimationDuration = durationSeconds;
+}
+
+float SpiralLayout::GetScrollSpeedFactor() const
+{
+  return mImpl->mScrollSpeedFactor;
+}
+
+float SpiralLayout::GetMaximumSwipeSpeed() const
+{
+  return mImpl->mMaximumSwipeSpeed;
+}
+
+float SpiralLayout::GetItemFlickAnimationDuration() const
+{
+  return mImpl->mItemFlickAnimationDuration;
+}
+
+float SpiralLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
+{
+  return 1.0f - static_cast<float>(numberOfItems);
+}
+
+float SpiralLayout::GetClosestAnchorPosition(float layoutPosition) const
+{
+  return round(layoutPosition);
+}
+
+float SpiralLayout::GetItemScrollToPosition(unsigned int itemId) const
+{
+  return -(static_cast<float>(itemId));
+}
+
+ItemRange SpiralLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
+{
+  float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
+  float itemsPerSpiral = layoutHeight / mImpl->mItemDescent;
+  float itemsCachedBeforeTopItem = layoutHeight * (mImpl->mTopItemAlignment + 0.5f) / mImpl->mItemDescent;
+  float itemsViewable = std::min(itemsPerSpiral, itemsPerSpiral - itemsCachedBeforeTopItem - firstItemPosition + 1.0f);
+
+  unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, -firstItemPosition - itemsCachedBeforeTopItem - 1.0f));
+  unsigned int lastItem  = static_cast<unsigned int>(std::max(0.0f, firstItem + itemsViewable));
+
+  return ItemRange(firstItem, lastItem+1);
+}
+
+unsigned int SpiralLayout::GetReserveItemCount(Vector3 layoutSize) const
+{
+  float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
+  return static_cast<unsigned int>(layoutHeight / mImpl->mItemDescent);
+}
+
+void SpiralLayout::GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
+{
+  itemSize.width = layoutSize.width * 0.25f;
+
+  // 4x3 aspect ratio
+  itemSize.height = itemSize.depth = ( itemSize.width / 4.0f ) * 3.0f;
+}
+
+Degree SpiralLayout::GetScrollDirection() const
+{
+  Degree scrollDirection(0);
+  const ControlOrientation::Type orientation = GetOrientation();
+
+  if ( orientation == ControlOrientation::Up )
+  {
+    scrollDirection = Degree( -45.0f ); // Allow swiping horizontally & vertically
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    scrollDirection = Degree( 45.0f );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    scrollDirection = Degree( 180.0f - 45.0f );
+  }
+  else // orientation == ControlOrientation::Right
+  {
+    scrollDirection = Degree( 270.0f - 45.0f );
+  }
+
+  return scrollDirection;
+}
+
+void SpiralLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
+{
+
+  // This just implements the default behaviour of constraint application.
+  // Custom layouts can override this function to apply their custom constraints.
+  Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
+  if( itemView )
+  {
+    const ControlOrientation::Type orientation = GetOrientation();
+
+    // Position constraint
+    SpiralPositionConstraint positionConstraint( itemId, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
+    Constraint constraint;
+    if ( orientation == ControlOrientation::Up )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationUp );
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationLeft );
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationDown );
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationRight );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.Apply();
+
+    // Rotation constraint
+    SpiralRotationConstraint rotationConstraint( itemId, mImpl->mItemSpacingRadians );
+    if ( orientation == ControlOrientation::Up )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationUp );
+    }
+    else if ( orientation == ControlOrientation::Left )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationLeft );
+    }
+    else if ( orientation == ControlOrientation::Down )
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationDown );
+    }
+    else // orientation == ControlOrientation::Right
+    {
+      constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationRight );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.Apply();
+
+    // Color constraint
+    constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, SpiralColorConstraint( itemId, mImpl->mItemSpacingRadians ) );
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.SetRemoveAction(Dali::Constraint::Discard);
+    constraint.Apply();
+
+    // Visibility constraint
+    SpiralVisibilityConstraint visibilityConstraint( itemId, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
+    if (IsVertical( orientation ) )
+    {
+      constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Portrait );
+    }
+    else // horizontal
+    {
+      constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Landscape );
+    }
+    constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
+    constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
+    constraint.SetRemoveAction(Dali::Constraint::Discard);
+    constraint.Apply();
+  }
+}
+
+void SpiralLayout::SetSpiralLayoutProperties(const Property::Map& properties)
+{
+  // Set any properties specified for SpiralLayout.
+  for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
+  {
+    KeyValuePair propertyPair = properties.GetKeyValue( idx );
+    switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
+    {
+      case DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING:
+      {
+        SetItemSpacing(Radian(propertyPair.second.Get<float>()));
+        break;
+      }
+      case DefaultItemLayoutProperty::SPIRAL_MAXIMUM_SWIPE_SPEED:
+      {
+        SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT:
+      {
+        SetTopItemAlignment(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::SPIRAL_SCROLL_SPEED_FACTOR:
+      {
+        SetScrollSpeedFactor(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::SPIRAL_REVOLUTION_DISTANCE:
+      {
+        SetRevolutionDistance(propertyPair.second.Get<float>());
+        break;
+      }
+      case DefaultItemLayoutProperty::SPIRAL_ITEM_FLICK_ANIMATION_DURATION:
+      {
+        SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+Vector3 SpiralLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
+{
+  Vector3 itemPosition = Vector3::ZERO;
+  const ControlOrientation::Type orientation = GetOrientation();
+
+  SpiralPositionConstraint positionConstraint( itemID, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
+
+  if ( orientation == ControlOrientation::Up )
+  {
+    positionConstraint.OrientationUp( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Left )
+  {
+    positionConstraint.OrientationLeft( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else if ( orientation == ControlOrientation::Down )
+  {
+    positionConstraint.OrientationDown( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+  else //orientation == ControlOrientation::Right
+  {
+    positionConstraint.OrientationRight( itemPosition, currentLayoutPosition + itemID, layoutSize );
+  }
+
+  return itemPosition;
+}
+
+SpiralLayout::SpiralLayout()
+: mImpl(NULL)
+{
+  mImpl = new Impl();
+}
+
+float SpiralLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
+{
+  return GetItemScrollToPosition(itemID);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h b/dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h
new file mode 100755 (executable)
index 0000000..4d65433
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef DALI_TOOLKIT_SPIRAL_LAYOUT_H
+#define DALI_TOOLKIT_SPIRAL_LAYOUT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class SpiralLayout;
+
+typedef IntrusivePtr<SpiralLayout> SpiralLayoutPtr;
+
+/**
+ * An ItemView layout which arranges items in a spiral.
+ */
+class SpiralLayout : public ItemLayout
+{
+public:
+
+  /**
+   * Create a new spiral layout
+   */
+  static SpiralLayoutPtr New();
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~SpiralLayout();
+
+  /**
+   * Apply spiral layout Properties.
+   * @param[in] properties The properties of the layout.
+   */
+  void SetSpiralLayoutProperties(const Property::Map& properties);
+
+  /**
+   * Set spacing angle between items.
+   * @param[in] itemSpacing The angle in radians.
+   */
+  void SetItemSpacing(Radian itemSpacing);
+
+  /**
+   * Get spacing angle between items.
+   * @return The angle in radians.
+   */
+  Radian GetItemSpacing() const;
+
+  /**
+   * Set the vertical distance for one revolution of the spiral.
+   * @param[in] distance The revolution distance.
+   */
+  void SetRevolutionDistance(float distance);
+
+  /**
+   * Get the vertical distance for one revolution of the spiral.
+   * @return The revolution distance.
+   */
+  float GetRevolutionDistance() const;
+
+  /**
+   * Set the alignment of the top-item, when at the beginning of the spiral (with a first-item layout-position of zero).
+   * A value of 0 indicates that the top-item is centered in the middle of the layout. A value of -0.5 or 0.5 indicates
+   * that the top-item is centred at the top or bottom of the layout respectively.
+   * @param[in] alignment The top-item alignment.
+   */
+  void SetTopItemAlignment(float alignment);
+
+  /**
+   * Get the alignment of the top-item, when at the beginning of the spiral
+   * @return The top-item alignment.
+   */
+  float GetTopItemAlignment() const;
+
+  /**
+   * Set the factor used to customise the scroll speed while dragging and swiping the layout.
+   * @param[in] scrollSpeed The scroll speed factor.
+   */
+  void SetScrollSpeedFactor(float scrollSpeed);
+
+  /**
+   * Set the maximum swipe speed in pixels per second.
+   * @param[in] speed The maximum swipe speed.
+   */
+  void SetMaximumSwipeSpeed(float speed);
+
+  /**
+   * Set the duration of the flick animation in second. This is the time taken to animate each
+   * item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered
+   * by a swipe gesture.
+   * @pre durationSeconds must be greater than zero.
+   * @param[in] durationSeconds The duration of flick animation in seconds.
+   */
+  void SetItemFlickAnimationDuration(float durationSeconds);
+
+  /**
+   * @copydoc ItemLayout::GetScrollSpeedFactor()
+   */
+  virtual float GetScrollSpeedFactor() const;
+
+  /**
+   * @copydoc ItemLayout::GetMaximumSwipeSpeed()
+   */
+  virtual float GetMaximumSwipeSpeed() const;
+
+  /**
+   * @copydoc ItemLayout::GetItemFlickAnimationDuration()
+   */
+  virtual float GetItemFlickAnimationDuration() const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestOnScreenLayoutPosition()
+   */
+  virtual float GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize);
+
+private:
+
+  /**
+   * @copydoc ItemLayout::GetMinimumLayoutPosition()
+   */
+  virtual float GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetClosestAnchorPosition()
+   */
+  virtual float GetClosestAnchorPosition(float layoutPosition) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemScrollToPosition()
+   */
+  virtual float GetItemScrollToPosition(unsigned int itemId) const;
+
+  /**
+   * @copydoc ItemLayout::GetItemsWithinArea()
+   */
+  virtual ItemRange GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetReserveItemCount()
+   */
+  virtual unsigned int GetReserveItemCount(Vector3 layoutSize) const;
+
+  /**
+   * @copydoc ItemLayout::GetDefaultItemSize()
+   */
+  virtual void GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const;
+
+  /**
+   * @copydoc ItemLayout::GetScrollDirection()
+   */
+  virtual Degree GetScrollDirection() const;
+
+  /**
+   * @copydoc ItemLayout::ApplyConstraints()
+   */
+  virtual void ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor );
+
+  /**
+   * @copydoc ItemLayout::GetItemPosition()
+   */
+  virtual Vector3 GetItemPosition( int itemID, float currentLayoutPosition, const Vector3& layoutSize ) const;
+
+protected:
+
+  /**
+   * Protected constructor; see also SpiralLayout::New()
+   */
+  SpiralLayout();
+
+private:
+
+  // Undefined
+  SpiralLayout( const SpiralLayout& spiralLayout );
+
+  // Undefined
+  SpiralLayout& operator=( const SpiralLayout& spiralLayout );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SPIRAL_LAYOUT_H
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp
new file mode 100644 (file)
index 0000000..ffc7570
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ScrollBase
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ScrollBase::ScrollBase()
+: Scrollable(),
+  mParent(NULL),
+  mDelay(0.0f)
+{
+}
+
+ScrollBase::ScrollBase( ControlBehaviour behaviourFlags )
+: Scrollable( behaviourFlags ),
+  mParent(NULL),
+  mDelay(0.0f)
+{
+}
+
+void ScrollBase::SetParent(ScrollBase *parent)
+{
+  mParent = parent;
+}
+
+void ScrollBase::BindActor(Actor child)
+{
+  FindAndUnbindActor(child);
+
+  ActorInfoPtr actorInfo(new ActorInfo(child));
+  mBoundActors.push_back(actorInfo);
+
+  // Apply all our constraints to this new child.
+  ConstraintStack::iterator i;
+
+  for(i = mConstraintStack.begin();i!=mConstraintStack.end();i++)
+  {
+    actorInfo->ApplyConstraint(*i);
+  }
+}
+
+void ScrollBase::UnbindActor(Actor child)
+{
+  // Find the child in mBoundActors, and unparent it
+  for (ActorInfoIter iter = mBoundActors.begin(); iter != mBoundActors.end(); ++iter)
+  {
+    ActorInfoPtr actorInfo = *iter;
+
+    if( actorInfo->mActor == child )
+    {
+      mBoundActors.erase(iter);
+      break;
+    }
+  }
+}
+
+void ScrollBase::FindAndUnbindActor(Actor child)
+{
+  // Since we don't know if and where child may have been bound
+  // (as we cannot store such information inside the Actor), we
+  // perform a search on all associated ScrollBases
+  // This is done by recursively calling the parent of this ScrollBase
+  // until reaching the top (at which point implementation may be
+  // different as this is virtual)
+
+  if(mParent) // continuously ascend until reaches root ScrollBase.
+  {
+    mParent->FindAndUnbindActor(child);
+  }
+}
+
+void ScrollBase::ApplyConstraintToBoundActors(Constraint constraint)
+{
+  mConstraintStack.push_back(constraint);
+
+  for(ActorInfoIter i = mBoundActors.begin();i != mBoundActors.end(); ++i)
+  {
+    (*i)->ApplyConstraint(constraint);
+  }
+}
+
+void ScrollBase::RemoveConstraintsFromBoundActors()
+{
+  mConstraintStack.clear();
+
+  for(ActorInfoIter i = mBoundActors.begin();i != mBoundActors.end(); ++i)
+  {
+    (*i)->RemoveConstraints();
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h
new file mode 100644 (file)
index 0000000..aa34f20
--- /dev/null
@@ -0,0 +1,219 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_BASE_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_BASE_H
+
+/*
+ * Copyright (c) 2019 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
+// TODO - Replace list with dali-vector.h
+#include <list>
+#include <dali/public-api/animation/constraint.h>
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ScrollBase;
+
+typedef IntrusivePtr<Actor>         ActorPtr;
+typedef std::list<Constraint>               ConstraintStack;
+
+/**
+ * ScrollBase represents a set of properties (time, position
+ * scale etc.) that constrain a set of actors.
+ */
+class ScrollBase : public Scrollable
+{
+public:
+
+  struct ActorInfo : public Dali::RefObject
+  {
+    /**
+     * ActorInfo constructor
+     * @param[in] actor The actor that this ActorInfo represents.
+     */
+    ActorInfo(Actor actor)
+    : mActor(actor)
+    {
+    }
+
+    /**
+     * ActorInfo destructor
+     * removes scrollview-related constraints only.
+     */
+    ~ActorInfo()
+    {
+      RemoveConstraints();
+    }
+
+    /**
+     * Apply a constraint to this actor
+     * The constraint will be applied to the actor,
+     * and the ActorInfo will keep track of this constraint.
+     * @param[in] constraint The constraint to apply to the actor
+     */
+    void ApplyConstraint(Constraint constraint)
+    {
+      Constraint clone = constraint.Clone( mActor );
+      clone.Apply();
+      mConstraints.push_back( clone );
+    }
+
+    /**
+     * Remove constraints from this actor.
+     * All of the constraints that have been applied to the
+     * actor via this ActorInfo will be removed.
+     */
+    void RemoveConstraints()
+    {
+      std::vector<Constraint>::iterator it = mConstraints.begin();
+      std::vector<Constraint>::iterator end = mConstraints.end();
+      for(;it!=end;++it)
+      {
+        it->Remove();
+      }
+      mConstraints.clear();
+    }
+
+    Actor mActor;                                     ///< The Actor that this ActorInfo represents.
+    std::vector<Constraint> mConstraints;       ///< A list keeping track of constraints applied to the actor via this delegate.
+  };
+
+  typedef IntrusivePtr<ActorInfo> ActorInfoPtr;
+  typedef std::vector<ActorInfoPtr> ActorInfoContainer;
+  typedef ActorInfoContainer::iterator ActorInfoIter;
+  typedef ActorInfoContainer::const_iterator ActorInfoConstIter;
+
+public:
+
+  /**
+   * Sets the delay in seconds.
+   * This delay affects the animation timing for all
+   * Bound Actors.
+   *
+   * @param[in] delay The delay in seconds.
+   */
+  void SetDelay(float delay)
+  {
+    mDelay = delay;
+  }
+
+  /**
+   * Gets the current delay in seconds.
+   *
+   * @return The delay in seconds.
+   */
+  float GetDelay() const
+  {
+    return mDelay;
+  }
+
+public:
+
+  /**
+   * Sets ScrollBase Parent
+   *
+   * @param[in] parent The parent that this ScrollBase belongs to.
+   */
+  void SetParent(ScrollBase *parent);
+
+  /**
+   * Bind Actor to this scroll view/group.
+   * Once Bound, this scroll view/group will affect the actor (child)
+   *
+   * @param[in] child The actor to be bound.
+   */
+  void BindActor(Actor child);
+
+  /**
+   * Unbind Actor from this scroll view/group
+   * Once Unbound, this scroll view/group will not affect the actor
+   *
+   * @note this does not remove the child from the ScrollView container
+   *
+   * @param[in] child The actor to be unbound
+   */
+  void UnbindActor(Actor child);
+
+  /**
+   * Searches associated ScrollBases for the Actor, and attempts to Unbind
+   * systematically this Actor from the ScrollView or Groups attached.
+   *
+   * @param[in] child The actor to be unbound.
+   */
+  virtual void FindAndUnbindActor(Actor child);
+
+  /**
+   * Applies constraint to the bound actors within this ScrollView/Group only.
+   *
+   * @param[in] constraint, the constraint to apply to these bound actors and future
+   * ones.
+   */
+  void ApplyConstraintToBoundActors(Constraint constraint);
+
+  /**
+   * Removes all constraints from the bound actors within this ScrollView/Group only.
+   */
+  void RemoveConstraintsFromBoundActors();
+
+protected:
+
+  static const char* const SCROLL_DOMAIN_OFFSET_PROPERTY_NAME;
+
+protected:
+
+  /**
+   * Construct a new ScrollBase.
+   */
+  ScrollBase();
+
+  /**
+   * @brief Construct a new ScrollBase.
+   *
+   * @param[in] behaviourFlags Flags to enable
+   */
+  ScrollBase( ControlBehaviour behaviourFlags );
+
+protected:
+
+  ScrollBase *mParent;                              ///< Pointer to ScrollBase parent, if exists.
+
+private:
+
+  float mDelay;                             ///< delay in seconds.
+  ConstraintStack mConstraintStack;         ///< The list of constraints to apply to any actors
+  ActorInfoContainer mBoundActors;          ///< The list of actors that have been bound to this ScrollBase.
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_BASE_H
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp
new file mode 100644 (file)
index 0000000..859805c
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
+#include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+
+using namespace Dali;
+
+namespace
+{
+
+const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
+
+// local helper function to resize the height of the bounce actor
+float GetBounceActorHeight( float width, float defaultHeight )
+{
+  return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? defaultHeight : defaultHeight * 0.5f;
+}
+
+const float MAX_OVERSHOOT_NOTIFY_AMOUNT = 0.99f;                     // maximum amount to set notification for increased overshoot, beyond this we just wait for it to reduce again
+const float MIN_OVERSHOOT_NOTIFY_AMOUNT = Math::MACHINE_EPSILON_0;  // minimum amount to set notification for reduced overshoot, beyond this we just wait for it to increase again
+const float OVERSHOOT_NOTIFY_STEP = 0.01f;                          // amount to set notifications beyond current overshoot value
+
+}
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+ScrollOvershootIndicator::ScrollOvershootIndicator() :
+  mEffectX(NULL),
+  mEffectY(NULL)
+{
+}
+
+ScrollOvershootIndicator::~ScrollOvershootIndicator()
+{
+
+}
+
+ScrollOvershootIndicator* ScrollOvershootIndicator::New()
+{
+  ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator();
+  return scrollOvershootPtr;
+}
+
+void ScrollOvershootIndicator::AttachToScrollable(Scrollable& scrollable)
+{
+  if(!mEffectX)
+  {
+    mEffectX = ScrollOvershootEffectRipple::New(false, scrollable);
+  }
+  mEffectX->Apply();
+  if(!mEffectY)
+  {
+    mEffectY = ScrollOvershootEffectRipple::New(true, scrollable);
+  }
+  mEffectY->Apply();
+}
+
+void ScrollOvershootIndicator::DetachFromScrollable(Scrollable& scrollable)
+{
+  if(mEffectX)
+  {
+    mEffectX->Remove(scrollable);
+  }
+  if(mEffectY)
+  {
+    mEffectY->Remove(scrollable);
+  }
+}
+
+void ScrollOvershootIndicator::Reset()
+{
+  mEffectX->Reset();
+  mEffectY->Reset();
+}
+
+void ScrollOvershootIndicator::SetOvershootEffectColor( const Vector4& color )
+{
+  if(mEffectX)
+  {
+    mEffectX->SetOvershootEffectColor(color);
+  }
+  if(mEffectY)
+  {
+    mEffectY->SetOvershootEffectColor(color);
+  }
+}
+
+ScrollOvershootEffect::ScrollOvershootEffect( bool vertical ) :
+    mVertical(vertical)
+{
+
+}
+
+bool ScrollOvershootEffect::IsVertical() const
+{
+  return mVertical;
+}
+
+ScrollOvershootEffectRipple::ScrollOvershootEffectRipple( bool vertical, Scrollable& scrollable ) :
+    ScrollOvershootEffect( vertical ),
+    mAttachedScrollView(scrollable),
+    mOvershootProperty(Property::INVALID_INDEX),
+    mEffectOvershootProperty(Property::INVALID_INDEX),
+    mOvershoot(0.0f),
+    mOvershootSize( scrollable.GetOvershootSize() ),
+    mAnimationStateFlags(0)
+{
+  mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty);
+  mOvershootOverlay.SetColor(mAttachedScrollView.GetOvershootEffectColor());
+  mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
+  mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
+  mOvershootOverlay.SetVisible(false);
+
+}
+
+void ScrollOvershootEffectRipple::Apply()
+{
+  Actor self = mAttachedScrollView.Self();
+  mOvershootProperty = IsVertical() ? Toolkit::ScrollView::Property::OVERSHOOT_Y : Toolkit::ScrollView::Property::OVERSHOOT_X;
+
+  // make sure height is set, since we only create a constraint for image width
+  mOvershootSize = mAttachedScrollView.GetOvershootSize();
+  mOvershootOverlay.SetSize( mOvershootSize );
+
+  mAttachedScrollView.AddOverlay(mOvershootOverlay);
+
+  UpdatePropertyNotifications();
+}
+
+void ScrollOvershootEffectRipple::Remove( Scrollable& scrollable )
+{
+  if(mOvershootOverlay)
+  {
+    if(mOvershootIncreaseNotification)
+    {
+      scrollable.Self().RemovePropertyNotification(mOvershootIncreaseNotification);
+      mOvershootIncreaseNotification.Reset();
+    }
+    if(mOvershootDecreaseNotification)
+    {
+      scrollable.Self().RemovePropertyNotification(mOvershootDecreaseNotification);
+      mOvershootDecreaseNotification.Reset();
+    }
+    scrollable.RemoveOverlay(mOvershootOverlay);
+  }
+}
+
+void ScrollOvershootEffectRipple::Reset()
+{
+  mOvershootOverlay.SetVisible(false);
+  mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f);
+}
+
+void ScrollOvershootEffectRipple::UpdatePropertyNotifications()
+{
+  float absOvershoot = fabsf(mOvershoot);
+
+  Actor self = mAttachedScrollView.Self();
+  // update overshoot increase notify
+  if( mOvershootIncreaseNotification )
+  {
+    self.RemovePropertyNotification( mOvershootIncreaseNotification );
+    mOvershootIncreaseNotification.Reset();
+  }
+  if( absOvershoot < MAX_OVERSHOOT_NOTIFY_AMOUNT )
+  {
+    float increaseStep = absOvershoot + OVERSHOOT_NOTIFY_STEP;
+    if( increaseStep > MAX_OVERSHOOT_NOTIFY_AMOUNT )
+    {
+      increaseStep = MAX_OVERSHOOT_NOTIFY_AMOUNT;
+    }
+    mOvershootIncreaseNotification = self.AddPropertyNotification( mOvershootProperty, OutsideCondition(-increaseStep, increaseStep) );
+    mOvershootIncreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
+    mOvershootIncreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
+  }
+
+  // update overshoot decrease notify
+  if( mOvershootDecreaseNotification )
+  {
+    self.RemovePropertyNotification( mOvershootDecreaseNotification );
+    mOvershootDecreaseNotification.Reset();
+  }
+  if( absOvershoot > MIN_OVERSHOOT_NOTIFY_AMOUNT )
+  {
+    float reduceStep = absOvershoot - OVERSHOOT_NOTIFY_STEP;
+    if( reduceStep < MIN_OVERSHOOT_NOTIFY_AMOUNT )
+    {
+      reduceStep = MIN_OVERSHOOT_NOTIFY_AMOUNT;
+    }
+    mOvershootDecreaseNotification = self.AddPropertyNotification( mOvershootProperty, InsideCondition(-reduceStep, reduceStep) );
+    mOvershootDecreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue);
+    mOvershootDecreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification);
+  }
+}
+
+void ScrollOvershootEffectRipple::SetOvershootEffectColor( const Vector4& color )
+{
+  if(mOvershootOverlay)
+  {
+    mOvershootOverlay.SetColor(color);
+  }
+}
+
+void ScrollOvershootEffectRipple::UpdateVisibility( bool visible )
+{
+  mOvershootOverlay.SetVisible(visible);
+  // make sure overshoot image is correctly placed
+  if( visible )
+  {
+    Actor self = mAttachedScrollView.Self();
+    if(mOvershoot > 0.0f)
+    {
+      // positive overshoot
+      const Vector3 size = mOvershootOverlay.GetCurrentSize();
+      Vector3 relativeOffset;
+      const Vector3 parentSize = self.GetCurrentSize();
+      if(IsVertical())
+      {
+        mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.0f ), Vector3::ZAXIS ) );
+        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width, mOvershootSize.height), size.depth);
+      }
+      else
+      {
+        mOvershootOverlay.SetOrientation( Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS ) );
+        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height, mOvershootSize.height), size.depth);
+        relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
+      }
+      mOvershootOverlay.SetPosition(relativeOffset * parentSize);
+    }
+    else
+    {
+      // negative overshoot
+      const Vector3 size = mOvershootOverlay.GetCurrentSize();
+      Vector3 relativeOffset;
+      const Vector3 parentSize = self.GetCurrentSize();
+      if(IsVertical())
+      {
+        mOvershootOverlay.SetOrientation( Quaternion( Radian( Math::PI ), Vector3::ZAXIS ) );
+        mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width, mOvershootSize.height), size.depth);
+        relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
+      }
+      else
+      {
+        mOvershootOverlay.SetOrientation( Quaternion( Radian( 0.5f * Math::PI ), Vector3::ZAXIS ) );
+        mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height, mOvershootSize.height), size.depth);
+        relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
+      }
+      mOvershootOverlay.SetPosition(relativeOffset * parentSize);
+    }
+  }
+}
+
+void ScrollOvershootEffectRipple::OnOvershootNotification(PropertyNotification& source)
+{
+  Actor self = mAttachedScrollView.Self();
+  mOvershoot = self.GetCurrentProperty< float >( mOvershootProperty );
+  SetOvershoot(mOvershoot, false);
+  UpdatePropertyNotifications();
+}
+
+void ScrollOvershootEffectRipple::SetOvershoot(float amount, bool animate)
+{
+  float absAmount = fabsf(amount);
+  bool animatingOn = absAmount > Math::MACHINE_EPSILON_0;
+  if( (animatingOn && (mAnimationStateFlags & AnimatingIn)) )
+  {
+    // trying to do what we are already doing
+    if( mAnimationStateFlags & AnimateBack )
+    {
+      mAnimationStateFlags &= ~AnimateBack;
+    }
+    return;
+  }
+  if( (!animatingOn && (mAnimationStateFlags & AnimatingOut)) )
+  {
+    // trying to do what we are already doing
+    return;
+  }
+  if( !animatingOn && (mAnimationStateFlags & AnimatingIn) )
+  {
+    // dont interrupt while animating on
+    mAnimationStateFlags |= AnimateBack;
+    return;
+  }
+
+  if( absAmount > Math::MACHINE_EPSILON_1 )
+  {
+    UpdateVisibility(true);
+  }
+
+  float overshootAnimationSpeed = mAttachedScrollView.Self().GetProperty<float>(Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED);
+
+  if( animate && overshootAnimationSpeed > Math::MACHINE_EPSILON_0 )
+  {
+    float currentOvershoot = fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get<float>() );
+    float duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot) / overshootAnimationSpeed;
+
+    if( duration > Math::MACHINE_EPSILON_0 )
+    {
+      if(mScrollOvershootAnimation)
+      {
+        mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
+        mScrollOvershootAnimation.Stop();
+        mScrollOvershootAnimation.Reset();
+      }
+      mScrollOvershootAnimation = Animation::New(duration);
+      mScrollOvershootAnimation.FinishedSignal().Connect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
+      mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) );
+      mScrollOvershootAnimation.Play();
+      mAnimationStateFlags = animatingOn ? AnimatingIn : AnimatingOut;
+    }
+  }
+  else
+  {
+    mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount);
+  }
+}
+
+void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation)
+{
+  bool animateOff = false;
+  if( mAnimationStateFlags & AnimatingOut )
+  {
+    // should now be offscreen
+    mOvershootOverlay.SetVisible(false);
+  }
+  if( (mAnimationStateFlags & AnimateBack) )
+  {
+    animateOff = true;
+  }
+  mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished );
+  mScrollOvershootAnimation.Stop();
+  mScrollOvershootAnimation.Reset();
+  mAnimationStateFlags = 0;
+  if( animateOff )
+  {
+    SetOvershoot(0.0f, true);
+  }
+}
+
+ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New( bool vertical, Scrollable& scrollable )
+{
+  return new ScrollOvershootEffectRipple(vertical, scrollable);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h
new file mode 100644 (file)
index 0000000..fd408ac
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_OVERSHOOT_INDICATOR_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_OVERSHOOT_INDICATOR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/object/ref-object.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class Scrollable;
+class ScrollOvershootEffect;
+class ScrollOvershootEffectGradient;
+class ScrollOvershootEffectRipple;
+typedef IntrusivePtr<ScrollOvershootEffect> ScrollOvershootEffectPtr;
+typedef IntrusivePtr<ScrollOvershootEffectGradient> ScrollOvershootEffectGradientPtr;
+typedef IntrusivePtr<ScrollOvershootEffectRipple> ScrollOvershootEffectRipplePtr;
+
+struct ScrollOvershootIndicator : public Dali::RefObject
+{
+public:
+
+  /**
+   * ScrollOvershootIndicator constructor.
+   */
+  ScrollOvershootIndicator();
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~ScrollOvershootIndicator();
+
+  /**
+   * Attaches the scroll indicator to a scrollable actor
+   *
+   * &param[in] scrollable The scrollable actor to attach to
+   */
+  void AttachToScrollable(Scrollable& scrollable);
+
+  /**
+   * Detaches the scroll indicator from a scrollable actor
+   *
+   * &param[in] scrollable The scrollable actor to detach from
+   */
+  void DetachFromScrollable(Scrollable& scrollable);
+
+  /**
+   * Resets the indicator
+   */
+  void Reset();
+
+  /**
+   * Create an initialized ScrollOvershootIndicator
+   *
+   * @return A pointer to the created ScrollOvershootIndicator.
+   */
+  static ScrollOvershootIndicator* New();
+
+  /**
+   * Set the color of the overshoot effect.
+   * @parm[in] color The color of the overshoot effect
+   */
+  void SetOvershootEffectColor( const Vector4& color );
+
+private:
+  ScrollOvershootEffectPtr mEffectX;                      ///< effect used for x-axis/horizontal display
+  ScrollOvershootEffectPtr mEffectY;                      ///< effect used for y-axis/vertical display
+};
+
+/**
+ * ScrollOvershootEffect is a derivable class, designed to allow the application programmer to create their own
+ * overshoot effect and apply it with minimal implementation required
+ */
+struct ScrollOvershootEffect : public Dali::RefObject
+{
+public:
+  /**
+   * Create a new overshoot effect, passing in whether it is vertical or horizontal
+   *
+   * @param[in] vertical whether this effect is a vertical or horizontal one
+   */
+  ScrollOvershootEffect( bool vertical );
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~ScrollOvershootEffect() {}
+
+  /**
+   * Returns if this is a vertical or horizontal overhoot effect
+   *
+   * @return true or false
+   */
+  bool IsVertical() const;
+
+  /**
+   * Applies the indicator effect, all derived effects must implement this function
+   *
+   * @param[in] scrollable the scrollable object to apply this effect to
+   */
+  virtual void Apply() = 0;
+
+  /**
+   * Removes the indicator effect, all derived effects must implement this function
+   *
+   * @param[in] scrollable the scrollable object to remove this effect from
+   */
+  virtual void Remove( Scrollable& scrollable ) = 0;
+
+  /**
+   * Resets this overshoot effect
+   */
+  virtual void Reset() = 0;
+
+  /**
+   * Sets up property notifications for overshoot values
+   */
+  virtual void UpdatePropertyNotifications() {}
+
+  /**
+   * @copydoc ScrollOvershootIndicator::SetOvershootEffectColor()
+   */
+  virtual void SetOvershootEffectColor( const Vector4& color ) = 0;
+
+  /**
+   * Sets shader overshoot value, either immediately of by animating over time
+   *
+   * @param[in] amount The amount to set overshoot to [-1.0f,1.0f]
+   * @param[in] animate Whether to animate or set immediately
+   */
+  virtual void SetOvershoot(float amount, bool animate = true) = 0;
+
+private:
+  bool mVertical;                      ///< whether this is a vertical/horizontal effect
+};
+
+/**
+ * ScrollOvershootEffectRipple creates an animated bounce effect at the end of the scrollable area if the user
+ * attempts to scroll past it
+ */
+struct ScrollOvershootEffectRipple : public ScrollOvershootEffect, public ConnectionTracker
+{
+  enum AnimationState
+  {
+    AnimatingIn  = 0x01,  ///< animating overshoot to 0
+    AnimatingOut = 0x02,  ///< animating overshoot to negative (overshoot image displays in +ve area of screen)
+    AnimateBack  = 0x04,  ///< indicates that we need to animate overshoot back to zero immediately after it has finished animating in
+  };
+
+public:
+
+  /**
+   * Create a new gradient overshoot effect, passing in whether it is vertical or horizontal
+   *
+   * @param[in] vertical Whether this indicator is vertical or horizontal
+   */
+  ScrollOvershootEffectRipple( bool vertical, Scrollable& scrollable );
+
+  /**
+   * @copydoc ScrollOvershootEffect::Apply
+   */
+  virtual void Apply();
+
+  /**
+   * @copydoc ScrollOvershootEffect::Remove
+   */
+  virtual void Remove( Scrollable& scrollable );
+
+  /**
+   * @copydoc ScrollOvershootEffect::Reset
+   */
+  virtual void Reset();
+
+  /**
+   * @copydoc ScrollOvershootEffect::UpdatePropertyNotifications
+   */
+  void UpdatePropertyNotifications();
+
+  /**
+   * @copydoc ScrollOvershootEffect::SetOvershootEffectColor()
+   */
+  void SetOvershootEffectColor( const Vector4& color );
+
+  /**
+   * Updates the vibility of the overshoot image as well as updating its size, position and rotation
+   * This function is called when animation starts and finishes
+   *
+   * @param[in] visible Whether to set the image visible or not
+   */
+  void UpdateVisibility( bool visible );
+
+  /**
+   * Informs overshoot effect to update image position and to animate effect overshoot value for a
+   * positive overshoot value from scrollview
+   *
+   * @param[in] source the property notification that triggered this callback
+   */
+  void OnOvershootNotification(PropertyNotification& source);
+
+  /**
+   * @copydoc ScrollOvershootEffect::SetOvershoot()
+   */
+  void SetOvershoot(float amount, bool animate = true);
+
+  /**
+   * Connects to the animation finished signal of our overshoot animation
+   *
+   * @param[in] animation the animation instance that has finished
+   */
+  void OnOvershootAnimFinished(Animation& animation);
+
+  /**
+   * Creates a new ScrollOvershootEffectGradient objects and returns a pointer to it
+   *
+   * @param[in] vertical whether to create a vertical(true) or horizontal effect
+   * @return a pointer to the new effect
+   */
+  static ScrollOvershootEffectRipplePtr New( bool vertical, Scrollable& scrollable );
+
+private:
+  Actor                 mOvershootOverlay;             ///< the actor which displays the overshoot effect
+  Scrollable&           mAttachedScrollView;           ///< the actor that this indicator has been attached to
+  Animation             mScrollOvershootAnimation;     ///< overshoot animation
+  PropertyNotification  mOvershootIncreaseNotification;///< notification used to inform as overshoot increases
+  PropertyNotification  mOvershootDecreaseNotification;///< notification used to inform as overshoot decreases
+  Property::Index       mOvershootProperty;            ///< index of the overshoot property in the scrollable actor
+  Property::Index       mEffectOvershootProperty;      ///< index of the effect's overshoot property
+  float                 mOvershoot;                    ///< last overshoot value as detected by notifications
+  Vector2               mOvershootSize;                ///< The size of the overshoot effect
+  unsigned short        mAnimationStateFlags;          ///< contains flags indicating the current state of the overshoot animation
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_OVERSHOOT_INDICATOR_H
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp
new file mode 100644 (file)
index 0000000..82bc58f
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+ScrollViewEffect::ScrollViewEffect()
+: mScrollViewImpl(NULL)
+{
+}
+
+ScrollViewEffect::~ScrollViewEffect()
+{
+}
+
+void ScrollViewEffect::Attach(Toolkit::ScrollView& scrollView)
+{
+  DALI_ASSERT_ALWAYS( (!mScrollViewImpl) && "Already attached to a ScrollView" );
+
+  mScrollViewImpl = &GetImpl(scrollView);
+
+  OnAttach(scrollView);
+}
+
+void ScrollViewEffect::Detach(Toolkit::ScrollView& scrollView)
+{
+  DALI_ASSERT_ALWAYS( (mScrollViewImpl) && "Already detached from ScrollView" );
+  DALI_ASSERT_ALWAYS( (&GetImpl(scrollView) == mScrollViewImpl) && "Effect attached to a different ScrollView");
+
+  OnDetach(scrollView);
+
+  mScrollViewImpl = NULL;
+}
+
+Toolkit::ScrollView ScrollViewEffect::GetScrollView()
+{
+  DALI_ASSERT_ALWAYS(mScrollViewImpl);
+
+  return DownCast<Toolkit::ScrollView>( mScrollViewImpl->Self() );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h
new file mode 100644 (file)
index 0000000..603d8b2
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
+
+namespace Dali
+{
+
+class Animation;
+
+namespace Toolkit
+{
+
+class ScrollView;
+
+namespace Internal
+{
+
+class ScrollViewEffect;
+
+/**
+ * @copydoc Toolkit::ScrollViewEffect
+ */
+class ScrollViewEffect : public Dali::BaseObject, public ConnectionTracker
+{
+
+public:
+
+  ScrollViewEffect();
+
+  /**
+   * Attaches this effect to scrollView.
+   * @pre must not be already attached to a scrollView
+   * @note internally the scrollView effect holds a weak reference
+   * to scrollView.
+   * @param[in] scrollView The scrollView instance to attach to.
+   */
+  void Attach(Toolkit::ScrollView& scrollView);
+
+  /**
+   * Attaches this effect to scrollView.
+   * @pre must not be already attached to a scrollView
+   * @param[in] scrollView The scrollView instance to attach to.
+   */
+  void Detach(Toolkit::ScrollView& scrollView);
+
+public:
+
+  /**
+   * Called upon Attaching of effect to a scrollView instance.
+   *
+   * This will be called once.
+   *
+   * @param[in] scrollView The attached scrollView instance.
+   */
+  virtual void OnAttach(Toolkit::ScrollView& scrollView) = 0;
+
+  /**
+   * Called upon Detaching of effect from a scrollView instance.
+   *
+   * This will be called once.
+   *
+   * @param[in] scrollView The attached scrollView instance.
+   */
+  virtual void OnDetach(Toolkit::ScrollView& scrollView) = 0;
+
+protected:
+
+  /**
+   * Returns the ScrollView handle that this effect is
+   * attached to.
+   * @note if it's not attached to any ScrollView then
+   * will return an uninitialized handle.
+   * @return The scrollView handle is returned.
+   */
+  Toolkit::ScrollView GetScrollView();
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ScrollViewEffect();
+
+private:
+
+  Toolkit::Internal::ScrollView *mScrollViewImpl; ///< Attached ScrollView instance (pointer to implementation)
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::ScrollViewEffect& GetImpl(Dali::Toolkit::ScrollViewEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::RefObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::ScrollViewEffect&>(handle);
+}
+
+inline const Internal::ScrollViewEffect& GetImpl(const Dali::Toolkit::ScrollViewEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::RefObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::ScrollViewEffect&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_EFFECT_H
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
new file mode 100755 (executable)
index 0000000..e395194
--- /dev/null
@@ -0,0 +1,3048 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+
+//#define ENABLED_SCROLL_STATE_LOGGING
+
+#ifdef ENABLED_SCROLL_STATE_LOGGING
+#define DALI_LOG_SCROLL_STATE(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, "%s:%d " format "\n", __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__)
+#else
+#define DALI_LOG_SCROLL_STATE(format, ...)
+#endif
+
+// TODO: Change to two class system:
+// 1. DraggableActor (is an actor which can be dragged anywhere, can be set to range using the ruler)
+// 2. ScrollView (contains a draggable actor that can a) be dragged in the negative X, and Y domain, b) has a hitArea for touches)
+// TODO: external components (page and status overlays).
+// TODO: Orientation.
+// TODO: upgrade Vector2/3 to support returning Unit vectors, normals, & cross product (dot product is already provided)
+
+using namespace Dali;
+
+namespace
+{
+const float DEFAULT_SLOW_SNAP_ANIMATION_DURATION(0.5f);             ///< Default Drag-Release animation time.
+const float DEFAULT_FAST_SNAP_ANIMATION_DURATION(0.25f);            ///< Default Drag-Flick animation time.
+const float DEFAULT_SNAP_OVERSHOOT_DURATION(0.5f);                  ///< Default Overshoot snapping animation time.
+const float DEFAULT_MAX_OVERSHOOT(100.0f);                          ///< Default maximum allowed overshoot in pixels
+
+const float DEFAULT_AXIS_AUTO_LOCK_GRADIENT(0.36f);                 ///< Default Axis-AutoLock gradient threshold. default is 0.36:1 (20 degrees)
+const float DEFAULT_FRICTION_COEFFICIENT(1.0f);                     ///< Default Friction Co-efficient. (in stage diagonals per second)
+const float DEFAULT_FLICK_SPEED_COEFFICIENT(1.0f);                  ///< Default Flick speed coefficient (multiples input touch velocity)
+const float DEFAULT_MAX_FLICK_SPEED(3.0f);                          ///< Default Maximum flick speed. (in stage diagonals per second)
+
+const Vector2 DEFAULT_MIN_FLICK_DISTANCE(30.0f, 30.0f);              ///< minimum distance for pan before flick allowed
+const float DEFAULT_MIN_FLICK_SPEED_THRESHOLD(500.0f);              ///< Minimum pan speed required for flick in pixels/s
+const float FREE_FLICK_SPEED_THRESHOLD = 200.0f;                    ///< Free-Flick threshold in pixels/ms
+const float AUTOLOCK_AXIS_MINIMUM_DISTANCE2 = 100.0f;               ///< Auto-lock axis after minimum distance squared.
+const float FLICK_ORTHO_ANGLE_RANGE = 75.0f;                        ///< degrees. (if >45, then supports diagonal flicking)
+const Vector2 DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = Vector2(0.17f, 0.1f); ///< The step of horizontal scroll distance in the proportion of stage size for each wheel event received.
+const unsigned long MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET( 150u );
+const float TOUCH_DOWN_TIMER_INTERVAL = 100.0f;
+const float DEFAULT_SCROLL_UPDATE_DISTANCE( 30.0f );                ///< Default distance to travel in pixels for scroll update signal
+
+const std::string INTERNAL_MAX_POSITION_PROPERTY_NAME( "internalMaxPosition" );
+
+// Helpers ////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Find the vector (distance) from (a) to (b)
+ * in domain (start) to (end)
+ * (\ / start)               (\ / end)
+ *   |-a                 b<----|
+ *
+ * @note assumes both (a) and (b) are already with the domain
+ * (start) to (end)
+ *
+ * @param[in] a the current point
+ * @param[in] b the target point
+ * @param[in] start the start of the domain
+ * @param[in] end the end of the domain
+ * @param[in] bias whether to only take the right direction or the left direction,
+ * or the shortest direction.
+ * @return the shortest direction and distance
+ */
+float VectorInDomain(float a, float b, float start, float end, Dali::Toolkit::DirectionBias bias)
+{
+  if(bias == Dali::Toolkit::DirectionBiasNone)
+  {
+    return ShortestDistanceInDomain( a, b, start, end );
+  }
+  //  (a-start + end-b)
+  float size = end-start;
+  float vect = b-a;
+
+  if(vect > 0)
+  {
+    // +ve vector
+    if(bias == Dali::Toolkit::DirectionBiasRight) // going right, take the vector.
+    {
+      return vect;
+    }
+    else
+    {
+      float aRight = a+size;
+      return b-aRight;
+    }
+  }
+  else
+  {
+    // -ve vector
+    if(bias == Dali::Toolkit::DirectionBiasLeft) // going left, take the vector.
+    {
+      return vect;
+    }
+    else
+    {
+      float aLeft = a-size;
+      return b-aLeft;
+    }
+  }
+}
+
+/**
+ * Returns the position of the anchor within actor
+ *
+ * @param actor The Actor
+ * @param anchor The Anchor point of interest.
+ * @return The position of the Anchor
+ */
+Vector3 GetPositionOfAnchor(Actor &actor, const Vector3 &anchor)
+{
+  Vector3 childPosition = actor.GetCurrentPosition();
+  Vector3 childAnchor = - actor.GetCurrentAnchorPoint() + anchor;
+  Vector3 childSize = actor.GetCurrentSize();
+
+  return childPosition + childAnchor * childSize;
+}
+
+// AlphaFunctions /////////////////////////////////////////////////////////////////////////////////
+
+float FinalDefaultAlphaFunction(float offset)
+{
+  return offset * 0.5f;
+}
+
+/**
+ * ConstantDecelerationAlphaFunction
+ * Newtoninan distance for constant deceleration
+ * v = 1 - t, s = t - 1/2 t^2
+ * when t = 0, s = 0.0 (min distance)
+ * when t = 1, s = 0.5 (max distance)
+ * progress = s / (max-min) = 2t - t^2
+ *
+ * @param[in] offset The input progress
+ * @return The output progress
+ */
+float ConstantDecelerationAlphaFunction(float progress)
+{
+  return progress * 2.0f - progress * progress;
+}
+
+// Internal Constraints ///////////////////////////////////////////////////////////////////////////
+
+/**
+ * Internal Relative position Constraint
+ * Generates the relative position value of the scroll view
+ * based on the absolute position, and it's relation to the
+ * scroll domain. This is a value from 0.0f to 1.0f in each
+ * scroll position axis.
+ */
+void InternalRelativePositionConstraint( Vector2& relativePosition, const PropertyInputContainer& inputs)
+{
+  Vector2 position = -inputs[0]->GetVector2();
+  const Vector2& min = inputs[1]->GetVector2();
+  const Vector2& max = inputs[2]->GetVector2();
+  const Vector3& size = inputs[3]->GetVector3();
+
+  position.x = WrapInDomain(position.x, min.x, max.x);
+  position.y = WrapInDomain(position.y, min.y, max.y);
+
+  Vector2 domainSize = (max - min) - size.GetVectorXY();
+
+  relativePosition.x = domainSize.x > Math::MACHINE_EPSILON_1 ? fabsf((position.x - min.x) / domainSize.x) : 0.0f;
+  relativePosition.y = domainSize.y > Math::MACHINE_EPSILON_1 ? fabsf((position.y - min.y) / domainSize.y) : 0.0f;
+}
+
+/**
+ * Internal scroll domain Constraint
+ * Generates the scroll domain of the scroll view.
+ */
+void InternalScrollDomainConstraint( Vector2& scrollDomain, const PropertyInputContainer& inputs)
+{
+  const Vector2& min = inputs[0]->GetVector2();
+  const Vector2& max = inputs[1]->GetVector2();
+  const Vector3& size = inputs[2]->GetVector3();
+
+  scrollDomain = (max - min) - size.GetVectorXY();
+}
+
+/**
+ * Internal maximum scroll position Constraint
+ * Generates the maximum scroll position of the scroll view.
+ */
+void InternalPrePositionMaxConstraint( Vector2& scrollMax, const PropertyInputContainer& inputs)
+{
+  const Vector2& max = inputs[0]->GetVector2();
+  const Vector3& size = inputs[1]->GetVector3();
+
+  scrollMax = max - size.GetVectorXY();
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::ScrollView::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ScrollView, Toolkit::Scrollable, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollView, "wrapEnabled",                BOOLEAN,   WRAP_ENABLED                )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollView, "panningEnabled",             BOOLEAN,   PANNING_ENABLED             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollView, "axisAutoLockEnabled",        BOOLEAN,   AXIS_AUTO_LOCK_ENABLED      )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollView, "wheelScrollDistanceStep",    VECTOR2,   WHEEL_SCROLL_DISTANCE_STEP  )
+DALI_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollMode",                 MAP,       SCROLL_MODE )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollPosition",  VECTOR2, SCROLL_POSITION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollPrePosition",   VECTOR2, SCROLL_PRE_POSITION)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollPrePositionX",    SCROLL_PRE_POSITION_X, SCROLL_PRE_POSITION, 0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollPrePositionY",    SCROLL_PRE_POSITION_Y, SCROLL_PRE_POSITION, 1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollPrePositionMax",    VECTOR2, SCROLL_PRE_POSITION_MAX)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollPrePositionMaxX",     SCROLL_PRE_POSITION_MAX_X, SCROLL_PRE_POSITION_MAX, 0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollPrePositionMaxY",     SCROLL_PRE_POSITION_MAX_Y, SCROLL_PRE_POSITION_MAX, 1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "overshootX",  FLOAT, OVERSHOOT_X)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "overshootY",  FLOAT, OVERSHOOT_Y)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollFinal",  VECTOR2, SCROLL_FINAL)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollFinalX",   SCROLL_FINAL_X, SCROLL_FINAL,0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollFinalY",   SCROLL_FINAL_Y, SCROLL_FINAL,1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "wrap", BOOLEAN, WRAP)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "panning", BOOLEAN, PANNING)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrolling", BOOLEAN, SCROLLING)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollDomainSize",   VECTOR2, SCROLL_DOMAIN_SIZE)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollDomainSizeX",    SCROLL_DOMAIN_SIZE_X, SCROLL_DOMAIN_SIZE, 0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, ScrollView, "scrollDomainSizeY",    SCROLL_DOMAIN_SIZE_Y, SCROLL_DOMAIN_SIZE, 1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollDomainOffset",   VECTOR2, SCROLL_DOMAIN_OFFSET)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "scrollPositionDelta",   VECTOR2, SCROLL_POSITION_DELTA)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ScrollView, "startPagePosition",   VECTOR3, START_PAGE_POSITION)
+
+DALI_SIGNAL_REGISTRATION( Toolkit, ScrollView, "valueChanged",  SIGNAL_SNAP_STARTED )
+
+DALI_TYPE_REGISTRATION_END()
+
+/**
+ * Returns whether to lock scrolling to a particular axis
+ *
+ * @param[in] panDelta Distance panned since gesture started
+ * @param[in] currentLockAxis The current lock axis value
+ * @param[in] lockGradient How quickly to lock to a particular axis
+ *
+ * @return The new axis lock state
+ */
+ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
+{
+  if(panDelta.LengthSquared() > AUTOLOCK_AXIS_MINIMUM_DISTANCE2 &&
+      currentLockAxis == ScrollView::LockPossible)
+  {
+    float dx = fabsf(panDelta.x);
+    float dy = fabsf(panDelta.y);
+    if(dx * lockGradient >= dy)
+    {
+      // 0.36:1 gradient to the horizontal (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockVertical;
+    }
+    else if(dy * lockGradient > dx)
+    {
+      // 0.36:1 gradient to the vertical (deviate < 20 degrees)
+      currentLockAxis = ScrollView::LockHorizontal;
+    }
+    else
+    {
+      currentLockAxis = ScrollView::LockNone;
+    }
+  }
+  return currentLockAxis;
+}
+
+/**
+ * Internal Pre-Position Property Constraint.
+ *
+ * Generates position property based on current position + gesture displacement.
+ * Or generates position property based on positionX/Y.
+ * Note: This is the position prior to any clamping at scroll boundaries.
+ */
+struct InternalPrePositionConstraint
+{
+  InternalPrePositionConstraint( const Vector2& initialPanPosition,
+                                 const Vector2& initialPanMask,
+                                 bool axisAutoLock,
+                                 float axisAutoLockGradient,
+                                 ScrollView::LockAxis initialLockAxis,
+                                 const Vector2& maxOvershoot,
+                                 const RulerPtr& rulerX, const RulerPtr& rulerY )
+  : mLocalStart( initialPanPosition ),
+    mInitialPanMask( initialPanMask ),
+    mMaxOvershoot( maxOvershoot ),
+    mAxisAutoLockGradient( axisAutoLockGradient ),
+    mLockAxis( initialLockAxis ),
+    mAxisAutoLock( axisAutoLock ),
+    mWasPanning( false )
+  {
+    const RulerDomain& rulerDomainX = rulerX->GetDomain();
+    const RulerDomain& rulerDomainY = rulerY->GetDomain();
+    mDomainMin = Vector2( rulerDomainX.min, -rulerDomainY.min );
+    mDomainMax = Vector2( -rulerDomainX.max, -rulerDomainY.max );
+    mClampX = rulerDomainX.enabled;
+    mClampY = rulerDomainY.enabled;
+    mFixedRulerX = rulerX->GetType() == Ruler::Fixed;
+    mFixedRulerY = rulerY->GetType() == Ruler::Fixed;
+  }
+
+  void operator()( Vector2& scrollPostPosition, const PropertyInputContainer& inputs )
+  {
+    const Vector2& panPosition = inputs[0]->GetVector2();
+    const bool& inGesture = inputs[1]->GetBoolean();
+
+    // First check if we are within a gesture.
+    // The ScrollView may have received a start gesture from ::OnPan()
+    // while the finish gesture is received now in this constraint.
+    // This gesture must then be rejected as the value will be "old".
+    // Typically the last value from the end of the last gesture.
+    // If we are rejecting the gesture, we simply don't modify the constraint target.
+    if( inGesture )
+    {
+      if( !mWasPanning )
+      {
+        mPrePosition = scrollPostPosition;
+        mStartPosition = mPrePosition;
+        mCurrentPanMask = mInitialPanMask;
+        mWasPanning = true;
+      }
+
+      // Calculate Deltas...
+      const Vector2& currentPosition = panPosition;
+      Vector2 panDelta( currentPosition - mLocalStart );
+
+      // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
+      // appears mostly horizontal or mostly vertical respectively...
+      if( mAxisAutoLock )
+      {
+        mLockAxis = GetLockAxis( panDelta, mLockAxis, mAxisAutoLockGradient );
+        if( mLockAxis == ScrollView::LockVertical )
+        {
+          mCurrentPanMask.y = 0.0f;
+        }
+        else if( mLockAxis == ScrollView::LockHorizontal )
+        {
+          mCurrentPanMask.x = 0.0f;
+        }
+      }
+
+      // Restrict deltas based on ruler enable/disable and axis-lock state...
+      panDelta *= mCurrentPanMask;
+
+      // Perform Position transform based on input deltas...
+      scrollPostPosition = mPrePosition;
+      scrollPostPosition += panDelta;
+
+      // if no wrapping then clamp preposition to maximum overshoot amount
+      const Vector3& size = inputs[2]->GetVector3();
+      if( mClampX )
+      {
+        float newXPosition = Clamp( scrollPostPosition.x, ( mDomainMax.x + size.x ) - mMaxOvershoot.x, mDomainMin.x + mMaxOvershoot.x );
+        if( (newXPosition < scrollPostPosition.x - Math::MACHINE_EPSILON_1)
+          || (newXPosition > scrollPostPosition.x + Math::MACHINE_EPSILON_1) )
+        {
+          mPrePosition.x = newXPosition;
+          mLocalStart.x = panPosition.x;
+        }
+        scrollPostPosition.x = newXPosition;
+      }
+      if( mClampY )
+      {
+        float newYPosition = Clamp( scrollPostPosition.y, ( mDomainMax.y + size.y ) - mMaxOvershoot.y, mDomainMin.y + mMaxOvershoot.y );
+        if( ( newYPosition < scrollPostPosition.y - Math::MACHINE_EPSILON_1 )
+          || ( newYPosition > scrollPostPosition.y + Math::MACHINE_EPSILON_1 ) )
+        {
+          mPrePosition.y = newYPosition;
+          mLocalStart.y = panPosition.y;
+        }
+        scrollPostPosition.y = newYPosition;
+      }
+
+      // If we are using a fixed ruler in a particular axis, limit the maximum pages scrolled on that axis.
+      if( mFixedRulerX || mFixedRulerY )
+      {
+        // Here we limit the maximum amount that can be moved from the starting position of the gesture to one page.
+        // We do this only if we have a fixed ruler (on that axis) and the mode is enabled.
+        // Note: 1.0f is subtracted to keep the value within one page size (otherwise we stray on to the page after).
+        // Note: A further 1.0f is subtracted to handle a compensation that happens later within the flick handling code in SnapWithVelocity().
+        //       When a flick is completed, an adjustment of 1.0f is sometimes made to allow for the scenario where:
+        //       A flick finishes before the update thread has advanced the scroll position past the previous snap point.
+        Vector2 viewPageSizeLimit( size.x - ( 1.0f + 1.0f ), size.y - ( 1.0f - 1.0f ) );
+        Vector2 minPosition( mStartPosition.x - viewPageSizeLimit.x, mStartPosition.y - viewPageSizeLimit.y );
+        Vector2 maxPosition( mStartPosition.x + viewPageSizeLimit.x, mStartPosition.y + viewPageSizeLimit.y );
+
+        if( mFixedRulerX )
+        {
+          scrollPostPosition.x = Clamp( scrollPostPosition.x, minPosition.x, maxPosition.x );
+        }
+        if( mFixedRulerY )
+        {
+          scrollPostPosition.y = Clamp( scrollPostPosition.y, minPosition.y, maxPosition.y );
+        }
+      }
+    }
+  }
+
+  Vector2 mPrePosition;
+  Vector2 mLocalStart;
+  Vector2 mStartPosition;               ///< The start position of the gesture - used to limit scroll amount (not modified by clamping).
+  Vector2 mInitialPanMask;              ///< Initial pan mask (based on ruler settings).
+  Vector2 mCurrentPanMask;              ///< Current pan mask that can be altered by axis lock mode.
+  Vector2 mDomainMin;
+  Vector2 mDomainMax;
+  Vector2 mMaxOvershoot;
+
+  float mAxisAutoLockGradient;          ///< Set by ScrollView
+  ScrollView::LockAxis mLockAxis;
+
+  bool mAxisAutoLock:1;                 ///< Set by ScrollView
+  bool mWasPanning:1;
+  bool mClampX:1;
+  bool mClampY:1;
+  bool mFixedRulerX:1;
+  bool mFixedRulerY:1;
+};
+
+/**
+ * Internal Position Property Constraint.
+ *
+ * Generates position property based on pre-position
+ * Note: This is the position after clamping.
+ * (uses result of InternalPrePositionConstraint)
+ */
+struct InternalPositionConstraint
+{
+  InternalPositionConstraint(const RulerDomain& domainX, const RulerDomain& domainY, bool wrap)
+  : mDomainMin( -domainX.min, -domainY.min ),
+    mDomainMax( -domainX.max, -domainY.max ),
+    mClampX( domainX.enabled ),
+    mClampY( domainY.enabled ),
+    mWrap( wrap )
+  {
+  }
+
+  void operator()( Vector2& position, const PropertyInputContainer& inputs )
+  {
+    position = inputs[0]->GetVector2();
+    const Vector2& size = inputs[3]->GetVector3().GetVectorXY();
+    const Vector2& min = inputs[1]->GetVector2();
+    const Vector2& max = inputs[2]->GetVector2();
+
+    if( mWrap )
+    {
+      position.x = -WrapInDomain(-position.x, min.x, max.x);
+      position.y = -WrapInDomain(-position.y, min.y, max.y);
+    }
+    else
+    {
+      // clamp post position to domain
+      position.x = mClampX ? Clamp(position.x, mDomainMax.x + size.x, mDomainMin.x ) : position.x;
+      position.y = mClampY ? Clamp(position.y, mDomainMax.y + size.y, mDomainMin.y ) : position.y;
+    }
+  }
+
+  Vector2 mDomainMin;
+  Vector2 mDomainMax;
+  bool mClampX;
+  bool mClampY;
+  bool mWrap;
+
+};
+
+/**
+ * This constraint updates the X overshoot property using the difference
+ * SCROLL_PRE_POSITION.x and SCROLL_POSITION.x, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootXConstraint
+{
+  OvershootXConstraint(float maxOvershoot) : mMaxOvershoot(maxOvershoot) {}
+
+  void operator()( float& current, const PropertyInputContainer& inputs )
+  {
+    if( inputs[2]->GetBoolean() )
+    {
+      const Vector2& scrollPrePosition = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float newOvershoot = scrollPrePosition.x - scrollPostPosition.x;
+      current = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * This constraint updates the Y overshoot property using the difference
+ * SCROLL_PRE_POSITION.y and SCROLL_POSITION.y, returning a relative value between 0.0f and 1.0f
+ */
+struct OvershootYConstraint
+{
+  OvershootYConstraint(float maxOvershoot) : mMaxOvershoot(maxOvershoot) {}
+
+  void operator()( float& current, const PropertyInputContainer& inputs )
+  {
+    if( inputs[2]->GetBoolean() )
+    {
+      const Vector2& scrollPrePosition = inputs[0]->GetVector2();
+      const Vector2& scrollPostPosition = inputs[1]->GetVector2();
+      float newOvershoot = scrollPrePosition.y - scrollPostPosition.y;
+      current = (newOvershoot > 0.0f ? std::min(newOvershoot, mMaxOvershoot) : std::max(newOvershoot, -mMaxOvershoot)) / mMaxOvershoot;
+    }
+    else
+    {
+      current = 0.0f;
+    }
+  }
+
+  float mMaxOvershoot;
+};
+
+/**
+ * Internal Position-Delta Property Constraint.
+ *
+ * Generates position-delta property based on scroll-position + scroll-offset properties.
+ */
+void InternalPositionDeltaConstraint( Vector2& current, const PropertyInputContainer& inputs )
+{
+  const Vector2& scrollPosition = inputs[0]->GetVector2();
+  const Vector2& scrollOffset = inputs[1]->GetVector2();
+
+  current = scrollPosition + scrollOffset;
+}
+
+/**
+ * Internal Final Position Constraint
+ * The position of content is:
+ * of scroll-position + f(scroll-overshoot)
+ * where f(...) function defines how overshoot
+ * should affect final-position.
+ */
+struct InternalFinalConstraint
+{
+  InternalFinalConstraint(AlphaFunctionPrototype functionX,
+                          AlphaFunctionPrototype functionY)
+  : mFunctionX(functionX),
+    mFunctionY(functionY)
+  {
+  }
+
+  void operator()( Vector2& current, const PropertyInputContainer& inputs )
+  {
+    const float& overshootx = inputs[1]->GetFloat();
+    const float& overshooty = inputs[2]->GetFloat();
+    Vector2 offset( mFunctionX(overshootx),
+                    mFunctionY(overshooty) );
+
+    current = inputs[0]->GetVector2() - offset;
+  }
+
+  AlphaFunctionPrototype mFunctionX;
+  AlphaFunctionPrototype mFunctionY;
+};
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ScrollView
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Dali::Toolkit::ScrollView ScrollView::New()
+{
+  // Create the implementation
+  ScrollViewPtr scrollView(new ScrollView());
+
+  // Pass ownership to CustomActor via derived handle
+  Dali::Toolkit::ScrollView handle(*scrollView);
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  scrollView->Initialize();
+
+  return handle;
+}
+
+ScrollView::ScrollView()
+: ScrollBase( ControlBehaviour( REQUIRES_WHEEL_EVENTS | DISABLE_STYLE_CHANGE_SIGNALS ) ),   // Enable size negotiation
+  mTouchDownTime(0u),
+  mGestureStackDepth(0),
+  mScrollStateFlags(0),
+  mLockAxis(LockPossible),
+  mScrollUpdateDistance(DEFAULT_SCROLL_UPDATE_DISTANCE),
+  mMaxOvershoot(DEFAULT_MAX_OVERSHOOT, DEFAULT_MAX_OVERSHOOT),
+  mUserMaxOvershoot(DEFAULT_MAX_OVERSHOOT, DEFAULT_MAX_OVERSHOOT),
+  mSnapOvershootDuration(DEFAULT_SNAP_OVERSHOOT_DURATION),
+  mSnapOvershootAlphaFunction(AlphaFunction::EASE_OUT),
+  mSnapDuration(DEFAULT_SLOW_SNAP_ANIMATION_DURATION),
+  mSnapAlphaFunction(AlphaFunction::EASE_OUT),
+  mMinFlickDistance(DEFAULT_MIN_FLICK_DISTANCE),
+  mFlickSpeedThreshold(DEFAULT_MIN_FLICK_SPEED_THRESHOLD),
+  mFlickDuration(DEFAULT_FAST_SNAP_ANIMATION_DURATION),
+  mFlickAlphaFunction(AlphaFunction::EASE_OUT),
+  mAxisAutoLockGradient(DEFAULT_AXIS_AUTO_LOCK_GRADIENT),
+  mFrictionCoefficient(DEFAULT_FRICTION_COEFFICIENT),
+  mFlickSpeedCoefficient(DEFAULT_FLICK_SPEED_COEFFICIENT),
+  mMaxFlickSpeed(DEFAULT_MAX_FLICK_SPEED),
+  mWheelScrollDistanceStep(Vector2::ZERO),
+  mInAccessibilityPan(false),
+  mScrolling(false),
+  mScrollInterrupted(false),
+  mPanning(false),
+  mSensitive(true),
+  mTouchDownTimeoutReached(false),
+  mActorAutoSnapEnabled(false),
+  mAutoResizeContainerEnabled(false),
+  mWrapMode(false),
+  mAxisAutoLock(false),
+  mAlterChild(false),
+  mDefaultMaxOvershoot(true),
+  mCanScrollHorizontal(true),
+  mCanScrollVertical(true),
+  mTransientScrollBar(true)
+{
+}
+
+void ScrollView::OnInitialize()
+{
+  Actor self = Self();
+
+  // Internal Actor, used to hide actors from enumerations.
+  // Also actors added to Internal actor appear as overlays e.g. ScrollBar components.
+  mInternalActor = Actor::New();
+  self.Add(mInternalActor);
+
+  mInternalActor.SetParentOrigin(ParentOrigin::CENTER);
+  mInternalActor.SetAnchorPoint(AnchorPoint::CENTER);
+  mInternalActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  mAlterChild = true;
+
+  mScrollPostPosition = mScrollPrePosition = Vector2::ZERO;
+
+  mWheelScrollDistanceStep = Stage::GetCurrent().GetSize() * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
+
+  mGestureStackDepth = 0;
+
+  self.TouchSignal().Connect( this, &ScrollView::OnTouch );
+  EnableGestureDetection( Gesture::Type( Gesture::Pan ) );
+
+  // By default we'll allow the user to freely drag the scroll view,
+  // while disabling the other rulers.
+  RulerPtr ruler = new DefaultRuler();
+  mRulerX = ruler;
+  mRulerY = ruler;
+
+  self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, mCanScrollVertical);
+  self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal);
+
+  UpdatePropertyDomain();
+  SetInternalConstraints();
+}
+
+void ScrollView::OnStageConnection( int depth )
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this);
+
+  if ( mSensitive )
+  {
+    SetScrollSensitive( false );
+    SetScrollSensitive( true );
+  }
+
+  if(IsOvershootEnabled())
+  {
+    // try and make sure property notifications are set
+    EnableScrollOvershoot(true);
+  }
+
+  ScrollBase::OnStageConnection( depth );
+}
+
+void ScrollView::OnStageDisconnection()
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this);
+
+  StopAnimation();
+
+  ScrollBase::OnStageDisconnection();
+}
+
+ScrollView::~ScrollView()
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this);
+}
+
+AlphaFunction ScrollView::GetScrollSnapAlphaFunction() const
+{
+  return mSnapAlphaFunction;
+}
+
+void ScrollView::SetScrollSnapAlphaFunction(AlphaFunction alpha)
+{
+  mSnapAlphaFunction = alpha;
+}
+
+AlphaFunction ScrollView::GetScrollFlickAlphaFunction() const
+{
+  return mFlickAlphaFunction;
+}
+
+void ScrollView::SetScrollFlickAlphaFunction(AlphaFunction alpha)
+{
+  mFlickAlphaFunction = alpha;
+}
+
+float ScrollView::GetScrollSnapDuration() const
+{
+  return mSnapDuration;
+}
+
+void ScrollView::SetScrollSnapDuration(float time)
+{
+  mSnapDuration = time;
+}
+
+float ScrollView::GetScrollFlickDuration() const
+{
+  return mFlickDuration;
+}
+
+void ScrollView::SetScrollFlickDuration(float time)
+{
+  mFlickDuration = time;
+}
+
+void ScrollView::ApplyEffect(Toolkit::ScrollViewEffect effect)
+{
+  Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
+
+  // Assertion check to ensure effect doesn't already exist in this scrollview
+  bool effectAlreadyExistsInScrollView(false);
+  for (ScrollViewEffectIter iter = mEffects.begin(); iter != mEffects.end(); ++iter)
+  {
+    if(*iter==effect)
+    {
+      effectAlreadyExistsInScrollView = true;
+      break;
+    }
+  }
+
+  DALI_ASSERT_ALWAYS(!effectAlreadyExistsInScrollView);
+
+  // add effect to effects list
+  mEffects.push_back(effect);
+
+  // invoke Attachment request to ScrollView first
+  GetImpl(effect).Attach(self);
+}
+
+void ScrollView::RemoveEffect(Toolkit::ScrollViewEffect effect)
+{
+  Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
+
+  // remove effect from effects list
+  bool effectExistedInScrollView(false);
+  for (ScrollViewEffectIter iter = mEffects.begin(); iter != mEffects.end(); ++iter)
+  {
+    if(*iter==effect)
+    {
+      mEffects.erase(iter);
+      effectExistedInScrollView = true;
+      break;
+    }
+  }
+
+  // Assertion check to ensure effect existed.
+  DALI_ASSERT_ALWAYS(effectExistedInScrollView);
+
+  // invoke Detachment request to ScrollView last
+  GetImpl(effect).Detach(self);
+}
+
+void ScrollView::RemoveAllEffects()
+{
+  Dali::Toolkit::ScrollView self = Dali::Toolkit::ScrollView::DownCast(Self());
+
+  for (ScrollViewEffectIter effectIter = mEffects.begin(); effectIter != mEffects.end(); ++effectIter)
+  {
+    Toolkit::ScrollViewEffect effect = *effectIter;
+
+    // invoke Detachment request to ScrollView last
+    GetImpl(effect).Detach(self);
+  }
+
+  mEffects.clear();
+}
+
+void ScrollView::ApplyConstraintToChildren(Constraint constraint)
+{
+  ApplyConstraintToBoundActors(constraint);
+}
+
+void ScrollView::RemoveConstraintsFromChildren()
+{
+  RemoveConstraintsFromBoundActors();
+}
+
+const RulerPtr ScrollView::GetRulerX() const
+{
+  return mRulerX;
+}
+
+const RulerPtr ScrollView::GetRulerY() const
+{
+  return mRulerY;
+}
+
+void ScrollView::SetRulerX(RulerPtr ruler)
+{
+  mRulerX = ruler;
+
+  UpdatePropertyDomain();
+  UpdateMainInternalConstraint();
+}
+
+void ScrollView::SetRulerY(RulerPtr ruler)
+{
+  mRulerY = ruler;
+
+  UpdatePropertyDomain();
+  UpdateMainInternalConstraint();
+}
+
+void ScrollView::UpdatePropertyDomain()
+{
+  Actor self = Self();
+  Vector3 size = self.GetTargetSize();
+  Vector2 min = mMinScroll;
+  Vector2 max = mMaxScroll;
+  bool scrollPositionChanged = false;
+  bool domainChanged = false;
+
+  bool canScrollVertical = false;
+  bool canScrollHorizontal = false;
+  UpdateLocalScrollProperties();
+  if(mRulerX->IsEnabled())
+  {
+    const Toolkit::RulerDomain& rulerDomain = mRulerX->GetDomain();
+    if( fabsf(min.x - rulerDomain.min) > Math::MACHINE_EPSILON_100
+        || fabsf(max.x - rulerDomain.max) > Math::MACHINE_EPSILON_100 )
+    {
+      domainChanged = true;
+      min.x = rulerDomain.min;
+      max.x = rulerDomain.max;
+
+      // make sure new scroll value is within new domain
+      if( mScrollPrePosition.x < min.x
+          || mScrollPrePosition.x > max.x )
+      {
+        scrollPositionChanged = true;
+        mScrollPrePosition.x = Clamp(mScrollPrePosition.x, -(max.x - size.x), -min.x);
+      }
+    }
+    if( (fabsf(rulerDomain.max - rulerDomain.min) - size.x) > Math::MACHINE_EPSILON_100 )
+    {
+      canScrollHorizontal = true;
+    }
+  }
+  else if( fabs(min.x) > Math::MACHINE_EPSILON_100
+           || fabs(max.x) > Math::MACHINE_EPSILON_100 )
+  {
+    // need to reset to 0
+    domainChanged = true;
+    min.x = 0.0f;
+    max.x = 0.0f;
+    canScrollHorizontal = false;
+  }
+
+  if(mRulerY->IsEnabled())
+  {
+    const Toolkit::RulerDomain& rulerDomain = mRulerY->GetDomain();
+    if( fabsf(min.y - rulerDomain.min) > Math::MACHINE_EPSILON_100
+        || fabsf(max.y - rulerDomain.max) > Math::MACHINE_EPSILON_100 )
+    {
+      domainChanged = true;
+      min.y = rulerDomain.min;
+      max.y = rulerDomain.max;
+
+      // make sure new scroll value is within new domain
+      if( mScrollPrePosition.y < min.y
+          || mScrollPrePosition.y > max.y )
+      {
+        scrollPositionChanged = true;
+        mScrollPrePosition.y = Clamp(mScrollPrePosition.y, -(max.y - size.y), -min.y);
+      }
+    }
+    if( (fabsf(rulerDomain.max - rulerDomain.min) - size.y) > Math::MACHINE_EPSILON_100 )
+    {
+      canScrollVertical = true;
+    }
+  }
+  else if( fabs(min.y) > Math::MACHINE_EPSILON_100
+           || fabs(max.y) > Math::MACHINE_EPSILON_100 )
+  {
+    // need to reset to 0
+    domainChanged = true;
+    min.y = 0.0f;
+    max.y = 0.0f;
+    canScrollVertical = false;
+  }
+
+  // avoid setting properties if possible, otherwise this will cause an entire update as well as triggering constraints using each property we update
+  if( mCanScrollVertical != canScrollVertical )
+  {
+    mCanScrollVertical = canScrollVertical;
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, canScrollVertical);
+  }
+  if( mCanScrollHorizontal != canScrollHorizontal )
+  {
+    mCanScrollHorizontal = canScrollHorizontal;
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, canScrollHorizontal);
+  }
+  if( scrollPositionChanged )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Domain Changed, setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y );
+    self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition);
+  }
+  if( domainChanged )
+  {
+    mMinScroll = min;
+    mMaxScroll = max;
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, mMinScroll );
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, mMaxScroll );
+  }
+}
+
+bool ScrollView::GetScrollSensitive()
+{
+  return mSensitive;
+}
+
+void ScrollView::SetScrollSensitive(bool sensitive)
+{
+  Actor self = Self();
+  PanGestureDetector panGesture( GetPanGestureDetector() );
+
+  DALI_LOG_SCROLL_STATE("[0x%X] sensitive: before:[%d] setting[%d]", this, int(mSensitive), int(sensitive));
+
+  if((!mSensitive) && (sensitive))
+  {
+    mSensitive = sensitive;
+    panGesture.Attach(self);
+  }
+  else if((mSensitive) && (!sensitive))
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] BEFORE: panning:[%d]", this, int(mPanning));
+
+    // while the scroll view is panning, the state needs to be reset.
+    if ( mPanning )
+    {
+      PanGesture cancelGesture( Gesture::Cancelled );
+      OnPan( cancelGesture );
+    }
+
+    panGesture.Detach(self);
+    mSensitive = sensitive;
+
+    mGestureStackDepth = 0;
+    DALI_LOG_SCROLL_STATE("[0x%X] AFTER: panning:[%d]", this, int(mPanning));
+  }
+}
+
+void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
+{
+  mMaxOvershoot.x = overshootX;
+  mMaxOvershoot.y = overshootY;
+  mUserMaxOvershoot = mMaxOvershoot;
+  mDefaultMaxOvershoot = false;
+  UpdateMainInternalConstraint();
+}
+
+void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
+{
+  mSnapOvershootAlphaFunction = alpha;
+}
+
+float ScrollView::GetSnapOvershootDuration()
+{
+  return mSnapOvershootDuration;
+}
+
+void ScrollView::SetSnapOvershootDuration(float duration)
+{
+  mSnapOvershootDuration = duration;
+}
+
+bool ScrollView::GetActorAutoSnap()
+{
+  return mActorAutoSnapEnabled;
+}
+
+void ScrollView::SetActorAutoSnap(bool enable)
+{
+  mActorAutoSnapEnabled = enable;
+}
+
+void ScrollView::SetAutoResize(bool enable)
+{
+  mAutoResizeContainerEnabled = enable;
+  // TODO: This needs a lot of issues to be addressed before working.
+}
+
+bool ScrollView::GetWrapMode() const
+{
+  return mWrapMode;
+}
+
+void ScrollView::SetWrapMode(bool enable)
+{
+  mWrapMode = enable;
+  Self().SetProperty(Toolkit::ScrollView::Property::WRAP, enable);
+}
+
+int ScrollView::GetScrollUpdateDistance() const
+{
+  return mScrollUpdateDistance;
+}
+
+void ScrollView::SetScrollUpdateDistance(int distance)
+{
+  mScrollUpdateDistance = distance;
+}
+
+bool ScrollView::GetAxisAutoLock() const
+{
+  return mAxisAutoLock;
+}
+
+void ScrollView::SetAxisAutoLock(bool enable)
+{
+  mAxisAutoLock = enable;
+  UpdateMainInternalConstraint();
+}
+
+float ScrollView::GetAxisAutoLockGradient() const
+{
+  return mAxisAutoLockGradient;
+}
+
+void ScrollView::SetAxisAutoLockGradient(float gradient)
+{
+  DALI_ASSERT_DEBUG( gradient >= 0.0f && gradient <= 1.0f );
+  mAxisAutoLockGradient = gradient;
+  UpdateMainInternalConstraint();
+}
+
+float ScrollView::GetFrictionCoefficient() const
+{
+  return mFrictionCoefficient;
+}
+
+void ScrollView::SetFrictionCoefficient(float friction)
+{
+  DALI_ASSERT_DEBUG( friction > 0.0f );
+  mFrictionCoefficient = friction;
+}
+
+float ScrollView::GetFlickSpeedCoefficient() const
+{
+  return mFlickSpeedCoefficient;
+}
+
+void ScrollView::SetFlickSpeedCoefficient(float speed)
+{
+  mFlickSpeedCoefficient = speed;
+}
+
+Vector2 ScrollView::GetMinimumDistanceForFlick() const
+{
+  return mMinFlickDistance;
+}
+
+void ScrollView::SetMinimumDistanceForFlick( const Vector2& distance )
+{
+  mMinFlickDistance = distance;
+}
+
+float ScrollView::GetMinimumSpeedForFlick() const
+{
+  return mFlickSpeedThreshold;
+}
+
+void ScrollView::SetMinimumSpeedForFlick( float speed )
+{
+  mFlickSpeedThreshold = speed;
+}
+
+float ScrollView::GetMaxFlickSpeed() const
+{
+  return mMaxFlickSpeed;
+}
+
+void ScrollView::SetMaxFlickSpeed(float speed)
+{
+  mMaxFlickSpeed = speed;
+}
+
+void ScrollView::SetWheelScrollDistanceStep(Vector2 step)
+{
+  mWheelScrollDistanceStep = step;
+}
+
+Vector2 ScrollView::GetWheelScrollDistanceStep() const
+{
+  return mWheelScrollDistanceStep;
+}
+
+unsigned int ScrollView::GetCurrentPage() const
+{
+  // in case animation is currently taking place.
+  Vector2 position = GetPropertyPosition();
+
+  Actor self = Self();
+  unsigned int page = 0;
+  unsigned int pagesPerVolume = 1;
+  unsigned int volume = 0;
+
+  // if rulerX is enabled, then get page count (columns)
+  page = mRulerX->GetPageFromPosition(-position.x, mWrapMode);
+  volume = mRulerY->GetPageFromPosition(-position.y, mWrapMode);
+  pagesPerVolume = mRulerX->GetTotalPages();
+
+  return volume * pagesPerVolume + page;
+}
+
+Vector2 ScrollView::GetCurrentScrollPosition() const
+{
+  return -GetPropertyPosition();
+}
+
+void ScrollView::TransformTo(const Vector2& position,
+                             DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  TransformTo(position, mSnapDuration, mSnapAlphaFunction, horizontalBias, verticalBias);
+}
+
+void ScrollView::TransformTo(const Vector2& position, float duration, AlphaFunction alpha,
+                             DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  // If this is called while the timer is running, then cancel it
+  StopTouchDownTimer();
+
+  Actor self( Self() );
+
+  // Guard against destruction during signal emission
+  // Note that Emit() methods are called indirectly e.g. from within ScrollView::AnimateTo()
+  Toolkit::ScrollView handle( GetOwner() );
+
+  DALI_LOG_SCROLL_STATE("[0x%X] pos[%.2f,%.2f], duration[%.2f] bias[%d, %d]",
+    this, position.x, position.y, duration, int(horizontalBias), int(verticalBias));
+
+  Vector2 currentScrollPosition = GetCurrentScrollPosition();
+  self.SetProperty( Toolkit::ScrollView::Property::START_PAGE_POSITION, Vector3(currentScrollPosition) );
+
+  if( mScrolling ) // are we interrupting a current scroll?
+  {
+    // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
+    mScrolling = false;
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 1 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollCompletedSignal.Emit( currentScrollPosition );
+  }
+
+  if( mPanning ) // are we interrupting a current pan?
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Interrupting Pan, set to false", this );
+    mPanning = false;
+    mGestureStackDepth = 0;
+    self.SetProperty( Toolkit::ScrollView::Property::PANNING, false );
+
+    if( mScrollMainInternalPrePositionConstraint )
+    {
+      mScrollMainInternalPrePositionConstraint.Remove();
+    }
+  }
+
+  self.SetProperty(Toolkit::ScrollView::Property::SCROLLING, true);
+  mScrolling = true;
+
+  DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignal 1 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+  mScrollStartedSignal.Emit( currentScrollPosition );
+  bool animating = AnimateTo(-position,
+                             Vector2::ONE * duration,
+                             alpha,
+                             true,
+                             horizontalBias,
+                             verticalBias,
+                             Snap);
+
+  if(!animating)
+  {
+    // if not animating, then this pan has completed right now.
+    self.SetProperty(Toolkit::ScrollView::Property::SCROLLING, false);
+    mScrolling = false;
+
+    // If we have no duration, then in the next update frame, we will be at the position specified as we just set.
+    // In this scenario, we cannot return the currentScrollPosition as this is out-of-date and should instead return the requested final position
+    Vector2 completedPosition( currentScrollPosition );
+    if( duration <= Math::MACHINE_EPSILON_10 )
+    {
+      completedPosition = position;
+    }
+
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 2 [%.2f, %.2f]", this, completedPosition.x, completedPosition.y);
+    SetScrollUpdateNotification(false);
+    mScrollCompletedSignal.Emit( completedPosition );
+  }
+}
+
+void ScrollView::ScrollTo(const Vector2& position)
+{
+  ScrollTo(position, mSnapDuration );
+}
+
+void ScrollView::ScrollTo(const Vector2& position, float duration)
+{
+  ScrollTo(position, duration, DirectionBiasNone, DirectionBiasNone);
+}
+
+void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha)
+{
+  ScrollTo(position, duration, alpha, DirectionBiasNone, DirectionBiasNone);
+}
+
+void ScrollView::ScrollTo(const Vector2& position, float duration,
+                          DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  ScrollTo(position, duration, mSnapAlphaFunction, horizontalBias, verticalBias);
+}
+
+void ScrollView::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha,
+                DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  DALI_LOG_SCROLL_STATE("[0x%X] position[%.2f, %.2f] duration[%.2f], bias[%d, %d]", this, position.x, position.y, duration, int(horizontalBias), int(verticalBias));
+  TransformTo(position, duration, alpha, horizontalBias, verticalBias);
+}
+
+void ScrollView::ScrollTo(unsigned int page)
+{
+  ScrollTo(page, mSnapDuration);
+}
+
+void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
+{
+  Vector2 position;
+  unsigned int volume;
+  unsigned int libraries;
+
+  // The position to scroll to is continuous and linear
+  // unless a domain has been enabled on the X axis.
+  // or if WrapMode has been enabled.
+  bool carryX = mRulerX->GetDomain().enabled | mWrapMode;
+  bool carryY = mRulerY->GetDomain().enabled | mWrapMode;
+
+  position.x = mRulerX->GetPositionFromPage(page, volume, carryX);
+  position.y = mRulerY->GetPositionFromPage(volume, libraries, carryY);
+
+  ScrollTo(position, duration, bias, bias);
+}
+
+void ScrollView::ScrollTo(Actor &actor)
+{
+  ScrollTo(actor, mSnapDuration);
+}
+
+void ScrollView::ScrollTo(Actor &actor, float duration)
+{
+  DALI_ASSERT_ALWAYS(actor.GetParent() == Self());
+
+  Actor self = Self();
+  Vector3 size = self.GetCurrentSize();
+  Vector3 position = actor.GetCurrentPosition();
+  Vector2 prePosition = GetPropertyPrePosition();
+  position.GetVectorXY() -= prePosition;
+
+  ScrollTo(Vector2(position.x - size.width * 0.5f, position.y - size.height * 0.5f), duration);
+}
+
+Actor ScrollView::FindClosestActor()
+{
+  Actor self = Self();
+  Vector3 size = self.GetCurrentSize();
+
+  return FindClosestActorToPosition(Vector3(size.width * 0.5f,size.height * 0.5f,0.0f));
+}
+
+Actor ScrollView::FindClosestActorToPosition(const Vector3& position, FindDirection dirX, FindDirection dirY, FindDirection dirZ)
+{
+  Actor closestChild;
+  float closestDistance2 = 0.0f;
+  Vector3 actualPosition = position;
+
+  unsigned int numChildren = Self().GetChildCount();
+
+  for(unsigned int i = 0; i < numChildren; ++i)
+  {
+    Actor child = Self().GetChildAt(i);
+
+    if(mInternalActor == child) // ignore internal actor.
+    {
+      continue;
+    }
+
+    Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
+
+    Vector3 delta = childPosition - actualPosition;
+
+    // X-axis checking (only find Actors to the [dirX] of actualPosition)
+    if(dirX > All) // != All,None
+    {
+      FindDirection deltaH = delta.x > 0 ? Right : Left;
+      if(dirX != deltaH)
+      {
+        continue;
+      }
+    }
+
+    // Y-axis checking (only find Actors to the [dirY] of actualPosition)
+    if(dirY > All) // != All,None
+    {
+      FindDirection deltaV = delta.y > 0 ? Down : Up;
+      if(dirY  != deltaV)
+      {
+        continue;
+      }
+    }
+
+    // Z-axis checking (only find Actors to the [dirZ] of actualPosition)
+    if(dirZ > All) // != All,None
+    {
+      FindDirection deltaV = delta.y > 0 ? In : Out;
+      if(dirZ  != deltaV)
+      {
+        continue;
+      }
+    }
+
+    // compare child to closest child in terms of distance.
+    float distance2 = 0.0f;
+
+    // distance2 = the Square of the relevant dimensions of delta
+    if(dirX != None)
+    {
+      distance2 += delta.x * delta.x;
+    }
+
+    if(dirY != None)
+    {
+      distance2 += delta.y * delta.y;
+    }
+
+    if(dirZ != None)
+    {
+      distance2 += delta.z * delta.z;
+    }
+
+    if(closestChild) // Next time.
+    {
+      if(distance2 < closestDistance2)
+      {
+        closestChild = child;
+        closestDistance2 = distance2;
+      }
+    }
+    else // First time.
+    {
+      closestChild = child;
+      closestDistance2 = distance2;
+    }
+  }
+
+  return closestChild;
+}
+
+bool ScrollView::ScrollToSnapPoint()
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this );
+  Vector2 stationaryVelocity = Vector2(0.0f, 0.0f);
+  return SnapWithVelocity( stationaryVelocity );
+}
+
+// TODO: In situations where axes are different (X snap, Y free)
+// Each axis should really have their own independent animation (time and equation)
+// Consider, X axis snapping to nearest grid point (EaseOut over fixed time)
+// Consider, Y axis simulating physics to arrive at a point (Physics equation over variable time)
+// Currently, the axes have been split however, they both use the same EaseOut equation.
+bool ScrollView::SnapWithVelocity(Vector2 velocity)
+{
+  // Animator takes over now, touches are assumed not to interfere.
+  // And if touches do interfere, then we'll stop animation, update PrePosition
+  // to current mScroll's properties, and then resume.
+  // Note: For Flicking this may work a bit different...
+
+  float angle = atan2(velocity.y, velocity.x);
+  float speed2 = velocity.LengthSquared();
+  AlphaFunction alphaFunction = mSnapAlphaFunction;
+  Vector2 positionDuration = Vector2::ONE * mSnapDuration;
+  float biasX = 0.5f;
+  float biasY = 0.5f;
+  FindDirection horizontal = None;
+  FindDirection vertical = None;
+
+  // orthoAngleRange = Angle tolerance within the Exact N,E,S,W direction
+  // that will be accepted as a general N,E,S,W flick direction.
+
+  const float orthoAngleRange = FLICK_ORTHO_ANGLE_RANGE * M_PI / 180.0f;
+  const float flickSpeedThreshold2 = mFlickSpeedThreshold * mFlickSpeedThreshold;
+
+  Vector2 positionSnap = mScrollPrePosition;
+
+  // Flick logic X Axis
+
+  if(mRulerX->IsEnabled() && mLockAxis != LockHorizontal)
+  {
+    horizontal = All;
+
+    if( speed2 > flickSpeedThreshold2 || // exceeds flick threshold
+        mInAccessibilityPan ) // With AccessibilityPan its easier to move between snap positions
+    {
+      if((angle >= -orthoAngleRange) && (angle < orthoAngleRange)) // Swiping East
+      {
+        biasX = 0.0f, horizontal = Left;
+
+        // This guards against an error where no movement occurs, due to the flick finishing
+        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
+        positionSnap.x += 1.0f;
+      }
+      else if((angle >= M_PI-orthoAngleRange) || (angle < -M_PI+orthoAngleRange)) // Swiping West
+      {
+        biasX = 1.0f, horizontal = Right;
+
+        // This guards against an error where no movement occurs, due to the flick finishing
+        // before the update-thread has advanced mScrollPostPosition past the the previous snap point.
+        positionSnap.x -= 1.0f;
+      }
+    }
+  }
+
+  // Flick logic Y Axis
+
+  if(mRulerY->IsEnabled() && mLockAxis != LockVertical)
+  {
+    vertical = All;
+
+    if( speed2 > flickSpeedThreshold2 || // exceeds flick threshold
+        mInAccessibilityPan ) // With AccessibilityPan its easier to move between snap positions
+    {
+      if((angle >= M_PI_2-orthoAngleRange) && (angle < M_PI_2+orthoAngleRange)) // Swiping South
+      {
+        biasY = 0.0f, vertical = Up;
+      }
+      else if((angle >= -M_PI_2-orthoAngleRange) && (angle < -M_PI_2+orthoAngleRange)) // Swiping North
+      {
+        biasY = 1.0f, vertical = Down;
+      }
+    }
+  }
+
+  // isFlick: Whether this gesture is a flick or not.
+  bool isFlick = (horizontal != All || vertical != All);
+  // isFreeFlick: Whether this gesture is a flick under free panning criteria.
+  bool isFreeFlick = velocity.LengthSquared() > (FREE_FLICK_SPEED_THRESHOLD*FREE_FLICK_SPEED_THRESHOLD);
+
+  if(isFlick || isFreeFlick)
+  {
+    positionDuration = Vector2::ONE * mFlickDuration;
+    alphaFunction = mFlickAlphaFunction;
+  }
+
+  // Calculate next positionSnap ////////////////////////////////////////////////////////////
+
+  if(mActorAutoSnapEnabled)
+  {
+    Vector3 size = Self().GetCurrentSize();
+
+    Actor child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f), horizontal, vertical );
+
+    if(!child && isFlick )
+    {
+      // If we conducted a direction limited search and found no actor, then just snap to the closest actor.
+      child = FindClosestActorToPosition( Vector3(size.width * 0.5f,size.height * 0.5f,0.0f) );
+    }
+
+    if(child)
+    {
+      Vector2 position = Self().GetCurrentProperty<Vector2>( Toolkit::ScrollView::Property::SCROLL_POSITION );
+
+      // Get center-point of the Actor.
+      Vector3 childPosition = GetPositionOfAnchor(child, AnchorPoint::CENTER);
+
+      if(mRulerX->IsEnabled())
+      {
+        positionSnap.x = position.x - childPosition.x + size.width * 0.5f;
+      }
+      if(mRulerY->IsEnabled())
+      {
+        positionSnap.y = position.y - childPosition.y + size.height * 0.5f;
+      }
+    }
+  }
+
+  Vector2 startPosition = positionSnap;
+  positionSnap.x = -mRulerX->Snap(-positionSnap.x, biasX);  // NOTE: X & Y rulers think in -ve coordinate system.
+  positionSnap.y = -mRulerY->Snap(-positionSnap.y, biasY);  // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
+
+  Vector2 clampDelta(Vector2::ZERO);
+  ClampPosition(positionSnap);
+
+  if( (mRulerX->GetType() == Ruler::Free || mRulerY->GetType() == Ruler::Free)
+      && isFreeFlick && !mActorAutoSnapEnabled)
+  {
+    // Calculate target position based on velocity of flick.
+
+    // a = Deceleration (Set to diagonal stage length * friction coefficient)
+    // u = Initial Velocity (Flick velocity)
+    // v = 0 (Final Velocity)
+    // t = Time (Velocity / Deceleration)
+    Vector2 stageSize = Stage::GetCurrent().GetSize();
+    float stageLength = Vector3(stageSize.x, stageSize.y, 0.0f).Length();
+    float a = (stageLength * mFrictionCoefficient);
+    Vector3 u = Vector3(velocity.x, velocity.y, 0.0f) * mFlickSpeedCoefficient;
+    float speed = u.Length();
+    u/= speed;
+
+    // TODO: Change this to a decay function. (faster you flick, the slower it should be)
+    speed = std::min(speed, stageLength * mMaxFlickSpeed );
+    u*= speed;
+    alphaFunction = ConstantDecelerationAlphaFunction;
+
+    float t = speed / a;
+
+    if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
+    {
+      positionSnap.x += t*u.x*0.5f;
+    }
+
+    if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
+    {
+      positionSnap.y += t*u.y*0.5f;
+    }
+
+    clampDelta = positionSnap;
+    ClampPosition(positionSnap);
+    if((positionSnap - startPosition).LengthSquared() > Math::MACHINE_EPSILON_0)
+    {
+      clampDelta -= positionSnap;
+      clampDelta.x = clampDelta.x > 0.0f ? std::min(clampDelta.x, mMaxOvershoot.x) : std::max(clampDelta.x, -mMaxOvershoot.x);
+      clampDelta.y = clampDelta.y > 0.0f ? std::min(clampDelta.y, mMaxOvershoot.y) : std::max(clampDelta.y, -mMaxOvershoot.y);
+    }
+    else
+    {
+      clampDelta = Vector2::ZERO;
+    }
+
+    // If Axis is Free and has velocity, then calculate time taken
+    // to reach target based on velocity in axis.
+    if(mRulerX->IsEnabled() && mRulerX->GetType() == Ruler::Free)
+    {
+      float deltaX = fabsf(startPosition.x - positionSnap.x);
+
+      if(fabsf(u.x) > Math::MACHINE_EPSILON_1)
+      {
+        positionDuration.x = fabsf(deltaX / u.x);
+      }
+      else
+      {
+        positionDuration.x = 0;
+      }
+    }
+
+    if(mRulerY->IsEnabled() && mRulerY->GetType() == Ruler::Free)
+    {
+      float deltaY = fabsf(startPosition.y - positionSnap.y);
+
+      if(fabsf(u.y) > Math::MACHINE_EPSILON_1)
+      {
+        positionDuration.y = fabsf(deltaY / u.y);
+      }
+      else
+      {
+        positionDuration.y = 0;
+      }
+    }
+  }
+
+  if(IsOvershootEnabled())
+  {
+    // Scroll to the end of the overshoot only when overshoot is enabled.
+    positionSnap += clampDelta;
+  }
+
+  bool animating = AnimateTo(positionSnap, positionDuration,
+                             alphaFunction, false,
+                             DirectionBiasNone, DirectionBiasNone,
+                             isFlick || isFreeFlick ? Flick : Snap);
+
+  return animating;
+}
+
+void ScrollView::StopAnimation(void)
+{
+  // Clear Snap animation if exists.
+  StopAnimation(mInternalXAnimation);
+  StopAnimation(mInternalYAnimation);
+  mScrollStateFlags = 0;
+  // remove scroll animation flags
+  HandleStoppedAnimation();
+}
+
+void ScrollView::StopAnimation(Animation& animation)
+{
+  if(animation)
+  {
+    animation.Stop();
+    animation.Reset();
+  }
+}
+
+bool ScrollView::AnimateTo(const Vector2& position, const Vector2& positionDuration,
+                           AlphaFunction alpha, bool findShortcuts,
+                           DirectionBias horizontalBias, DirectionBias verticalBias,
+                           SnapType snapType)
+{
+  // Here we perform an animation on a number of properties (depending on which have changed)
+  // The animation is applied to all ScrollBases
+  Actor self = Self();
+  mScrollTargetPosition = position;
+  float totalDuration = 0.0f;
+
+  bool positionChanged = (mScrollTargetPosition != mScrollPostPosition);
+
+  if(positionChanged)
+  {
+    totalDuration = std::max(totalDuration, positionDuration.x);
+    totalDuration = std::max(totalDuration, positionDuration.y);
+  }
+  else
+  {
+    // try to animate for a frame, on some occasions update will be changing scroll value while event side thinks it hasnt changed
+    totalDuration = 0.01f;
+    positionChanged = true;
+  }
+
+  StopAnimation();
+
+  // Position Delta ///////////////////////////////////////////////////////
+  if(positionChanged)
+  {
+    UpdateMainInternalConstraint();
+    if(mWrapMode && findShortcuts)
+    {
+      // In Wrap Mode, the shortest distance is a little less intuitive...
+      const RulerDomain rulerDomainX = mRulerX->GetDomain();
+      const RulerDomain rulerDomainY = mRulerY->GetDomain();
+
+      if(mRulerX->IsEnabled())
+      {
+        float dir = VectorInDomain(-mScrollPrePosition.x, -mScrollTargetPosition.x, rulerDomainX.min, rulerDomainX.max, horizontalBias);
+        mScrollTargetPosition.x = mScrollPrePosition.x + -dir;
+      }
+
+      if(mRulerY->IsEnabled())
+      {
+        float dir = VectorInDomain(-mScrollPrePosition.y, -mScrollTargetPosition.y, rulerDomainY.min, rulerDomainY.max, verticalBias);
+        mScrollTargetPosition.y = mScrollPrePosition.y + -dir;
+      }
+    }
+
+    // note we have two separate animations for X & Y, this deals with sliding diagonally and hitting
+    // a horizonal/vertical wall.delay
+    AnimateInternalXTo(mScrollTargetPosition.x, positionDuration.x, alpha);
+    AnimateInternalYTo(mScrollTargetPosition.y, positionDuration.y, alpha);
+
+    if( !(mScrollStateFlags & SCROLL_ANIMATION_FLAGS) )
+    {
+      DALI_LOG_SCROLL_STATE("[0x%X] Setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollTargetPosition.x, mScrollTargetPosition.y );
+      self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollTargetPosition);
+      mScrollPrePosition = mScrollTargetPosition;
+      mScrollPostPosition = mScrollTargetPosition;
+      WrapPosition(mScrollPostPosition);
+    }
+
+    DALI_LOG_SCROLL_STATE("[0x%X] position-changed, mScrollTargetPosition[%.2f, %.2f], mScrollPrePosition[%.2f, %.2f], mScrollPostPosition[%.2f, %.2f]", this, mScrollTargetPosition.x, mScrollTargetPosition.y, mScrollPrePosition.x, mScrollPrePosition.y, mScrollPostPosition.x, mScrollPostPosition.y );
+    DALI_LOG_SCROLL_STATE("[0x%X] SCROLL_PRE_POSITION[%.2f, %.2f], SCROLL_POSITION[%.2f, %.2f]", this, self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ).Get<Vector2>().x, self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ).Get<Vector2>().y, self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_POSITION ).Get<Vector2>().x, self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_POSITION ).Get<Vector2>().y );
+  }
+
+  SetScrollUpdateNotification(true);
+
+  // Always send a snap event when AnimateTo is called.
+  Toolkit::ScrollView::SnapEvent snapEvent;
+  snapEvent.type = snapType;
+  snapEvent.position = -mScrollTargetPosition;
+  snapEvent.duration = totalDuration;
+
+  DALI_LOG_SCROLL_STATE("[0x%X] mSnapStartedSignal [%.2f, %.2f]", this, snapEvent.position.x, snapEvent.position.y);
+  mSnapStartedSignal.Emit( snapEvent );
+
+  return (mScrollStateFlags & SCROLL_ANIMATION_FLAGS) != 0;
+}
+
+void ScrollView::EnableScrollOvershoot(bool enable)
+{
+  if (enable)
+  {
+    if (!mOvershootIndicator)
+    {
+      mOvershootIndicator = ScrollOvershootIndicator::New();
+    }
+
+    mOvershootIndicator->AttachToScrollable(*this);
+  }
+  else
+  {
+    mMaxOvershoot = mUserMaxOvershoot;
+
+    if (mOvershootIndicator)
+    {
+      mOvershootIndicator->DetachFromScrollable(*this);
+    }
+  }
+
+  UpdateMainInternalConstraint();
+}
+
+void ScrollView::AddOverlay(Actor actor)
+{
+  actor.SetDrawMode( DrawMode::OVERLAY_2D );
+  mInternalActor.Add( actor );
+}
+
+void ScrollView::RemoveOverlay(Actor actor)
+{
+  mInternalActor.Remove( actor );
+}
+
+void ScrollView::SetOvershootSize( const Vector2& size )
+{
+  mOvershootSize = size;
+  if( IsOvershootEnabled() && mOvershootIndicator )
+  {
+    mOvershootIndicator->AttachToScrollable(*this);
+  }
+}
+
+void ScrollView::SetOvershootEffectColor( const Vector4& color )
+{
+  mOvershootEffectColor = color;
+  if( mOvershootIndicator )
+  {
+    mOvershootIndicator->SetOvershootEffectColor( color );
+  }
+}
+
+void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
+{
+  PanGestureDetector panGesture( GetPanGestureDetector() );
+
+  // First remove just in case we have some set, then add.
+  panGesture.RemoveDirection( direction );
+  panGesture.AddDirection( direction, threshold );
+}
+
+void ScrollView::RemoveScrollingDirection( Radian direction )
+{
+  PanGestureDetector panGesture( GetPanGestureDetector() );
+  panGesture.RemoveDirection( direction );
+}
+
+Toolkit::ScrollView::SnapStartedSignalType& ScrollView::SnapStartedSignal()
+{
+  return mSnapStartedSignal;
+}
+
+void ScrollView::FindAndUnbindActor(Actor child)
+{
+  UnbindActor(child);
+}
+
+Vector2 ScrollView::GetPropertyPrePosition() const
+{
+  Vector2 position = Self().GetCurrentProperty< Vector2 >( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION );
+  WrapPosition(position);
+  return position;
+}
+
+Vector2 ScrollView::GetPropertyPosition() const
+{
+  Vector2 position = Self().GetCurrentProperty< Vector2 >( Toolkit::ScrollView::Property::SCROLL_POSITION );
+  WrapPosition(position);
+
+  return position;
+}
+
+void ScrollView::HandleStoppedAnimation()
+{
+  SetScrollUpdateNotification(false);
+}
+
+void ScrollView::HandleSnapAnimationFinished()
+{
+  // Emit Signal that scrolling has completed.
+  mScrolling = false;
+  Actor self = Self();
+  self.SetProperty(Toolkit::ScrollView::Property::SCROLLING, false);
+
+  Vector2 deltaPosition(mScrollPrePosition);
+
+  UpdateLocalScrollProperties();
+  WrapPosition(mScrollPrePosition);
+  DALI_LOG_SCROLL_STATE("[0x%X] Setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y );
+  self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition);
+
+  Vector2 currentScrollPosition = GetCurrentScrollPosition();
+  DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 3 current[%.2f, %.2f], mScrollTargetPosition[%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y, -mScrollTargetPosition.x, -mScrollTargetPosition.y );
+  mScrollCompletedSignal.Emit( currentScrollPosition );
+
+  mDomainOffset += deltaPosition - mScrollPostPosition;
+  self.SetProperty(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET, mDomainOffset);
+  HandleStoppedAnimation();
+}
+
+void ScrollView::SetScrollUpdateNotification( bool enabled )
+{
+  Actor self = Self();
+  if( mScrollXUpdateNotification )
+  {
+    // disconnect now to avoid a notification before removed from update thread
+    mScrollXUpdateNotification.NotifySignal().Disconnect(this, &ScrollView::OnScrollUpdateNotification);
+    self.RemovePropertyNotification(mScrollXUpdateNotification);
+    mScrollXUpdateNotification.Reset();
+  }
+  if( enabled && !mScrollUpdatedSignal.Empty())
+  {
+    // Only set up the notification when the application has connected to the updated signal
+    mScrollXUpdateNotification = self.AddPropertyNotification(Toolkit::ScrollView::Property::SCROLL_POSITION, 0, StepCondition(mScrollUpdateDistance, 0.0f));
+    mScrollXUpdateNotification.NotifySignal().Connect( this, &ScrollView::OnScrollUpdateNotification );
+  }
+  if( mScrollYUpdateNotification )
+  {
+    // disconnect now to avoid a notification before removed from update thread
+    mScrollYUpdateNotification.NotifySignal().Disconnect(this, &ScrollView::OnScrollUpdateNotification);
+    self.RemovePropertyNotification(mScrollYUpdateNotification);
+    mScrollYUpdateNotification.Reset();
+  }
+  if( enabled && !mScrollUpdatedSignal.Empty())
+  {
+    // Only set up the notification when the application has connected to the updated signal
+    mScrollYUpdateNotification = self.AddPropertyNotification(Toolkit::ScrollView::Property::SCROLL_POSITION, 1, StepCondition(mScrollUpdateDistance, 0.0f));
+    mScrollYUpdateNotification.NotifySignal().Connect( this, &ScrollView::OnScrollUpdateNotification );
+  }
+}
+
+void ScrollView::OnScrollUpdateNotification(Dali::PropertyNotification& source)
+{
+  // Guard against destruction during signal emission
+  Toolkit::ScrollView handle( GetOwner() );
+
+  Vector2 currentScrollPosition = GetCurrentScrollPosition();
+  mScrollUpdatedSignal.Emit( currentScrollPosition );
+}
+
+bool ScrollView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::ScrollView view = Toolkit::ScrollView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_SNAP_STARTED ) )
+  {
+    view.SnapStartedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
+{
+  // need to update domain properties for new size
+  UpdatePropertyDomain();
+}
+
+void ScrollView::OnSizeSet( const Vector3& size )
+{
+  // need to update domain properties for new size
+  if( mDefaultMaxOvershoot )
+  {
+    mUserMaxOvershoot.x = size.x * 0.5f;
+    mUserMaxOvershoot.y = size.y * 0.5f;
+    if( !IsOvershootEnabled() )
+    {
+      mMaxOvershoot = mUserMaxOvershoot;
+    }
+  }
+  UpdatePropertyDomain();
+  UpdateMainInternalConstraint();
+  if( IsOvershootEnabled() )
+  {
+    mOvershootIndicator->Reset();
+  }
+
+  ScrollBase::OnSizeSet( size );
+}
+
+void ScrollView::OnChildAdd(Actor& child)
+{
+  ScrollBase::OnChildAdd( child );
+
+  Dali::Toolkit::ScrollBar scrollBar = Dali::Toolkit::ScrollBar::DownCast(child);
+  if( scrollBar )
+  {
+    mScrollBar = scrollBar;
+    scrollBar.SetName("ScrollBar");
+
+    mInternalActor.Add( scrollBar );
+    if( scrollBar.GetScrollDirection() == Toolkit::ScrollBar::Horizontal )
+    {
+      scrollBar.SetScrollPropertySource( Self(),
+                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_X,
+                                         Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_X,
+                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX_X,
+                                         Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE_X );
+    }
+    else
+    {
+      scrollBar.SetScrollPropertySource( Self(),
+                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_Y,
+                                         Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y,
+                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX_Y,
+                                         Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE_Y );
+    }
+
+    if( mTransientScrollBar )
+    {
+      // Show the scroll-indicator for a brief period
+      Property::Map emptyMap;
+      scrollBar.DoAction( "ShowTransientIndicator", emptyMap );
+    }
+  }
+  else if(mAlterChild)
+  {
+    BindActor(child);
+  }
+}
+
+void ScrollView::OnChildRemove(Actor& child)
+{
+  // TODO: Actor needs a RemoveConstraint method to take out an individual constraint.
+  UnbindActor(child);
+
+  ScrollBase::OnChildRemove( child );
+}
+
+void ScrollView::StartTouchDownTimer()
+{
+  if ( !mTouchDownTimer )
+  {
+    mTouchDownTimer = Timer::New( TOUCH_DOWN_TIMER_INTERVAL );
+    mTouchDownTimer.TickSignal().Connect( this, &ScrollView::OnTouchDownTimeout );
+  }
+
+  mTouchDownTimer.Start();
+}
+
+void ScrollView::StopTouchDownTimer()
+{
+  if ( mTouchDownTimer )
+  {
+    mTouchDownTimer.Stop();
+  }
+}
+
+bool ScrollView::OnTouchDownTimeout()
+{
+  DALI_LOG_SCROLL_STATE("[0x%X]", this);
+
+  mTouchDownTimeoutReached = true;
+
+  unsigned int currentScrollStateFlags( mScrollStateFlags ); // Cleared in StopAnimation so keep local copy for comparison
+  if( currentScrollStateFlags & (SCROLL_ANIMATION_FLAGS | SNAP_ANIMATION_FLAGS) )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Scrolling Or snapping flags set, stopping animation", this);
+
+    StopAnimation();
+    if( currentScrollStateFlags & SCROLL_ANIMATION_FLAGS )
+    {
+      DALI_LOG_SCROLL_STATE("[0x%X] Scrolling flags set, emitting signal", this);
+
+      mScrollInterrupted = true;
+      // reset domain offset as scrolling from original plane.
+      mDomainOffset = Vector2::ZERO;
+      Self().SetProperty(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET, Vector2::ZERO);
+
+      UpdateLocalScrollProperties();
+      Vector2 currentScrollPosition = GetCurrentScrollPosition();
+      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 4 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+      mScrollCompletedSignal.Emit( currentScrollPosition );
+    }
+  }
+
+  return false;
+}
+
+bool ScrollView::OnTouch( Actor actor, const TouchData& touch )
+{
+  if(!mSensitive)
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X], Not Sensitive, ignoring", this);
+
+    // Ignore this touch event, if scrollview is insensitive.
+    return false;
+  }
+
+  // Ignore events with multiple-touch points
+  if (touch.GetPointCount() != 1)
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X], multiple touch, ignoring", this);
+
+    return false;
+  }
+
+  const PointState::Type pointState = touch.GetState( 0 );
+  if( pointState == PointState::DOWN )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Down", this);
+
+    if(mGestureStackDepth==0)
+    {
+      mTouchDownTime = touch.GetTime();
+
+      // This allows time for a pan-gesture to start, to avoid breaking snap-animation behavior with fast flicks.
+      // If touch-down does not become a pan (after timeout interval), then snap-animation can be interrupted.
+      mTouchDownTimeoutReached = false;
+      mScrollInterrupted = false;
+      StartTouchDownTimer();
+    }
+  }
+  else if( ( pointState == PointState::UP ) ||
+           ( ( pointState == PointState::INTERRUPTED ) && ( touch.GetHitActor( 0 )== Self() ) ) )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] %s", this, ( ( pointState == TouchPoint::Up ) ? "Up" : "Interrupted" ) );
+
+    StopTouchDownTimer();
+
+    // if the user touches and releases without enough movement to go
+    // into a gesture state, then we should snap to nearest point.
+    // otherwise our scroll could be stopped (interrupted) half way through an animation.
+    if(mGestureStackDepth==0 && mTouchDownTimeoutReached)
+    {
+      if( ( pointState == PointState::INTERRUPTED ) ||
+          ( ( touch.GetTime() - mTouchDownTime ) >= MINIMUM_TIME_BETWEEN_DOWN_AND_UP_FOR_RESET ) )
+      {
+        // Reset the velocity only if down was received a while ago
+        mLastVelocity = Vector2( 0.0f, 0.0f );
+      }
+
+      UpdateLocalScrollProperties();
+      // Only finish the transform if scrolling was interrupted on down or if we are scrolling
+      if ( mScrollInterrupted || mScrolling )
+      {
+        DALI_LOG_SCROLL_STATE("[0x%X] Calling FinishTransform", this);
+
+        FinishTransform();
+      }
+    }
+    mTouchDownTimeoutReached = false;
+    mScrollInterrupted = false;
+  }
+
+  return true;
+}
+
+bool ScrollView::OnWheelEvent(const WheelEvent& event)
+{
+  if(!mSensitive)
+  {
+    // Ignore this wheel event, if scrollview is insensitive.
+    return false;
+  }
+
+  Vector2 targetScrollPosition = GetPropertyPosition();
+
+  if(mRulerX->IsEnabled() && !mRulerY->IsEnabled())
+  {
+    // If only the ruler in the X axis is enabled, scroll in the X axis.
+    if(mRulerX->GetType() == Ruler::Free)
+    {
+      // Free panning mode
+      targetScrollPosition.x += event.z * mWheelScrollDistanceStep.x;
+      ClampPosition(targetScrollPosition);
+      ScrollTo(-targetScrollPosition);
+    }
+    else if(!mScrolling)
+    {
+      // Snap mode, only respond to the event when the previous snap animation is finished.
+      ScrollTo(GetCurrentPage() - event.z);
+    }
+  }
+  else
+  {
+    // If the ruler in the Y axis is enabled, scroll in the Y axis.
+    if(mRulerY->GetType() == Ruler::Free)
+    {
+      // Free panning mode
+      targetScrollPosition.y += event.z * mWheelScrollDistanceStep.y;
+      ClampPosition(targetScrollPosition);
+      ScrollTo(-targetScrollPosition);
+    }
+    else if(!mScrolling)
+    {
+      // Snap mode, only respond to the event when the previous snap animation is finished.
+      ScrollTo(GetCurrentPage() - event.z * mRulerX->GetTotalPages());
+    }
+  }
+
+  return true;
+}
+
+void ScrollView::ResetScrolling()
+{
+  Actor self = Self();
+  self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_POSITION ).Get( mScrollPostPosition );
+  mScrollPrePosition = mScrollPostPosition;
+  DALI_LOG_SCROLL_STATE("[0x%X] Setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPostPosition.x, mScrollPostPosition.y );
+  self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPostPosition);
+}
+
+void ScrollView::UpdateLocalScrollProperties()
+{
+  Actor self = Self();
+  self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ).Get( mScrollPrePosition );
+  self.GetCurrentProperty( Toolkit::ScrollView::Property::SCROLL_POSITION ).Get( mScrollPostPosition );
+}
+
+// private functions
+
+void ScrollView::PreAnimatedScrollSetup()
+{
+  // SCROLL_PRE_POSITION is our unclamped property with wrapping
+  // SCROLL_POSITION is our final scroll position after clamping
+
+  Actor self = Self();
+
+  Vector2 deltaPosition(mScrollPostPosition);
+  WrapPosition(mScrollPostPosition);
+  mDomainOffset += deltaPosition - mScrollPostPosition;
+  Self().SetProperty(Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET, mDomainOffset);
+
+  if( mScrollStateFlags & SCROLL_X_STATE_MASK )
+  {
+    // already performing animation on internal x position
+    StopAnimation(mInternalXAnimation);
+  }
+
+  if( mScrollStateFlags & SCROLL_Y_STATE_MASK )
+  {
+    // already performing animation on internal y position
+    StopAnimation(mInternalYAnimation);
+  }
+
+  mScrollStateFlags = 0;
+
+  // Update Actor position with this wrapped value.
+}
+
+void ScrollView::FinaliseAnimatedScroll()
+{
+  // TODO - common animation finishing code in here
+}
+
+void ScrollView::AnimateInternalXTo( float position, float duration, AlphaFunction alpha )
+{
+  StopAnimation(mInternalXAnimation);
+
+  if( duration > Math::MACHINE_EPSILON_10 )
+  {
+    Actor self = Self();
+    DALI_LOG_SCROLL_STATE("[0x%X], Animating from[%.2f] to[%.2f]", this, self.GetCurrentProperty(  Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ).Get< Vector2 >().x, position );
+    mInternalXAnimation = Animation::New(duration);
+    DALI_LOG_SCROLL_STATE("[0x%X], mInternalXAnimation[0x%X]", this, mInternalXAnimation.GetObjectPtr() );
+    mInternalXAnimation.FinishedSignal().Connect(this, &ScrollView::OnScrollAnimationFinished);
+    mInternalXAnimation.AnimateTo( Property(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, 0), position, alpha, TimePeriod(duration));
+    mInternalXAnimation.Play();
+
+    // erase current state flags
+    mScrollStateFlags &= ~SCROLL_X_STATE_MASK;
+    // add internal animation state flag
+    mScrollStateFlags |= AnimatingInternalX;
+  }
+}
+
+void ScrollView::AnimateInternalYTo( float position, float duration, AlphaFunction alpha )
+{
+  StopAnimation(mInternalYAnimation);
+
+  if( duration > Math::MACHINE_EPSILON_10 )
+  {
+    Actor self = Self();
+    DALI_LOG_SCROLL_STATE("[0x%X], Animating from[%.2f] to[%.2f]", this, self.GetCurrentProperty(  Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ).Get< Vector2 >().y, position );
+    mInternalYAnimation = Animation::New(duration);
+    DALI_LOG_SCROLL_STATE("[0x%X], mInternalYAnimation[0x%X]", this, mInternalYAnimation.GetObjectPtr() );
+    mInternalYAnimation.FinishedSignal().Connect(this, &ScrollView::OnScrollAnimationFinished);
+    mInternalYAnimation.AnimateTo( Property(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, 1), position, alpha, TimePeriod(duration));
+    mInternalYAnimation.Play();
+
+    // erase current state flags
+    mScrollStateFlags &= ~SCROLL_Y_STATE_MASK;
+    // add internal animation state flag
+    mScrollStateFlags |= AnimatingInternalY;
+  }
+}
+
+void ScrollView::OnScrollAnimationFinished( Animation& source )
+{
+  // Guard against destruction during signal emission
+  // Note that ScrollCompletedSignal is emitted from HandleSnapAnimationFinished()
+  Toolkit::ScrollView handle( GetOwner() );
+
+  bool scrollingFinished = false;
+
+  // update our local scroll positions
+  UpdateLocalScrollProperties();
+
+  if( source == mInternalXAnimation )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] mInternalXAnimation[0x%X], expected[%.2f], actual[%.2f], post[%.2f]", this, mInternalXAnimation.GetObjectPtr(), mScrollTargetPosition.x, Self().GetCurrentProperty( SCROLL_PRE_POSITION ).Get< Vector2 >().x, mScrollPostPosition.x );
+
+    if( !(mScrollStateFlags & AnimatingInternalY) )
+    {
+      scrollingFinished = true;
+    }
+    mInternalXAnimation.Reset();
+    // wrap pre scroll x position and set it
+    if( mWrapMode )
+    {
+      const RulerDomain rulerDomain = mRulerX->GetDomain();
+      mScrollPrePosition.x = -WrapInDomain(-mScrollPrePosition.x, rulerDomain.min, rulerDomain.max);
+      DALI_LOG_SCROLL_STATE("[0x%X] Setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y );
+      handle.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition);
+    }
+    SnapInternalXTo(mScrollPostPosition.x);
+  }
+
+  if( source == mInternalYAnimation )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] mInternalYAnimation[0x%X], expected[%.2f], actual[%.2f], post[%.2f]", this, mInternalYAnimation.GetObjectPtr(), mScrollTargetPosition.y, DevelHandle::GetProperty( Self(), SCROLL_PRE_POSITION ).Get< Vector2 >().y, mScrollPostPosition.y );
+
+    if( !(mScrollStateFlags & AnimatingInternalX) )
+    {
+      scrollingFinished = true;
+    }
+    mInternalYAnimation.Reset();
+    if( mWrapMode )
+    {
+      // wrap pre scroll y position and set it
+      const RulerDomain rulerDomain = mRulerY->GetDomain();
+      mScrollPrePosition.y = -WrapInDomain(-mScrollPrePosition.y, rulerDomain.min, rulerDomain.max);
+      DALI_LOG_SCROLL_STATE("[0x%X] Setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y );
+      handle.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition);
+    }
+    SnapInternalYTo(mScrollPostPosition.y);
+  }
+
+  DALI_LOG_SCROLL_STATE("[0x%X] scrollingFinished[%d] Animation[0x%X]", this, scrollingFinished, source.GetObjectPtr());
+
+  if(scrollingFinished)
+  {
+    HandleSnapAnimationFinished();
+  }
+}
+
+void ScrollView::OnSnapInternalPositionFinished( Animation& source )
+{
+  Actor self = Self();
+  UpdateLocalScrollProperties();
+  if( source == mInternalXAnimation )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Finished X PostPosition Animation", this );
+
+    // clear internal x animation flags
+    mScrollStateFlags &= ~SCROLL_X_STATE_MASK;
+    mInternalXAnimation.Reset();
+    WrapPosition(mScrollPrePosition);
+  }
+  if( source == mInternalYAnimation )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Finished Y PostPosition Animation", this );
+
+    mScrollStateFlags &= ~SCROLL_Y_STATE_MASK;
+    mInternalYAnimation.Reset();
+    WrapPosition(mScrollPrePosition);
+  }
+}
+
+void ScrollView::SnapInternalXTo(float position)
+{
+  Actor self = Self();
+
+  StopAnimation(mInternalXAnimation);
+
+  // erase current state flags
+  mScrollStateFlags &= ~SCROLL_X_STATE_MASK;
+
+  // if internal x not equal to inputed parameter, animate it
+  float duration = std::min(fabsf((position - mScrollPrePosition.x) / mMaxOvershoot.x) * mSnapOvershootDuration, mSnapOvershootDuration);
+  DALI_LOG_SCROLL_STATE("[0x%X] duration[%.2f]", this, duration );
+  if( duration > Math::MACHINE_EPSILON_1 )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Starting X Snap Animation to[%.2f]", this, position );
+
+    mInternalXAnimation = Animation::New(duration);
+    mInternalXAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapInternalPositionFinished);
+    mInternalXAnimation.AnimateTo(Property(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, 0), position);
+    mInternalXAnimation.Play();
+
+    // add internal animation state flag
+    mScrollStateFlags |= SnappingInternalX;
+  }
+}
+
+void ScrollView::SnapInternalYTo(float position)
+{
+  Actor self = Self();
+
+  StopAnimation(mInternalYAnimation);
+
+  // erase current state flags
+  mScrollStateFlags &= ~SCROLL_Y_STATE_MASK;
+
+  // if internal y not equal to inputed parameter, animate it
+  float duration = std::min(fabsf((position - mScrollPrePosition.y) / mMaxOvershoot.y) * mSnapOvershootDuration, mSnapOvershootDuration);
+  DALI_LOG_SCROLL_STATE("[0x%X] duration[%.2f]", this, duration );
+  if( duration > Math::MACHINE_EPSILON_1 )
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Starting Y Snap Animation to[%.2f]", this, position );
+
+    mInternalYAnimation = Animation::New(duration);
+    mInternalYAnimation.FinishedSignal().Connect(this, &ScrollView::OnSnapInternalPositionFinished);
+    mInternalYAnimation.AnimateTo(Property(self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, 1), position);
+    mInternalYAnimation.Play();
+
+    // add internal animation state flag
+    mScrollStateFlags |= SnappingInternalY;
+  }
+}
+
+void ScrollView::GestureStarted()
+{
+  // we handle the first gesture.
+  // if we're currently doing a gesture and receive another
+  // we continue and combine the effects of the gesture instead of reseting.
+  if(mGestureStackDepth++==0)
+  {
+    Actor self = Self();
+    StopTouchDownTimer();
+    StopAnimation();
+    mPanDelta = Vector2::ZERO;
+    mLastVelocity = Vector2::ZERO;
+    if( !mScrolling )
+    {
+      mLockAxis = LockPossible;
+    }
+
+    if( mScrollStateFlags & SCROLL_X_STATE_MASK )
+    {
+      StopAnimation(mInternalXAnimation);
+    }
+    if( mScrollStateFlags & SCROLL_Y_STATE_MASK )
+    {
+      StopAnimation(mInternalYAnimation);
+    }
+    mScrollStateFlags = 0;
+
+    if(mScrolling) // are we interrupting a current scroll?
+    {
+      // set mScrolling to false, in case user has code that interrogates mScrolling Getter() in complete.
+      mScrolling = false;
+      // send negative scroll position since scroll internal scroll position works as an offset for actors,
+      // give applications the position within the domain from the scroll view's anchor position
+      DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 5 [%.2f, %.2f]", this, -mScrollPostPosition.x, -mScrollPostPosition.y);
+      mScrollCompletedSignal.Emit( -mScrollPostPosition );
+    }
+  }
+}
+
+void ScrollView::GestureContinuing(const Vector2& panDelta)
+{
+  mPanDelta.x+= panDelta.x;
+  mPanDelta.y+= panDelta.y;
+
+  // Save the velocity, there is a bug in PanGesture
+  // Whereby the Gesture::Finished's velocity is either:
+  // NaN (due to time delta of zero between the last two events)
+  // or 0 (due to position being the same between the last two events)
+
+  // Axis Auto Lock - locks the panning to the horizontal or vertical axis if the pan
+  // appears mostly horizontal or mostly vertical respectively.
+  if(mAxisAutoLock)
+  {
+    mLockAxis = GetLockAxis(mPanDelta, mLockAxis, mAxisAutoLockGradient);
+  } // end if mAxisAutoLock
+}
+
+// TODO: Upgrade to use a more powerful gesture detector (one that supports multiple touches on pan - so works as pan and flick gesture)
+// BUG: Gesture::Finished doesn't always return velocity on release (due to
+// timeDelta between last two events being 0 sometimes, or posiiton being the same)
+void ScrollView::OnPan( const PanGesture& gesture )
+{
+  // Guard against destruction during signal emission
+  // Note that Emit() methods are called indirectly e.g. from within ScrollView::OnGestureEx()
+  Actor self( Self() );
+
+  if(!mSensitive)
+  {
+    DALI_LOG_SCROLL_STATE("[0x%X] Pan Ignored, Insensitive", this);
+
+    // If another callback on the same original signal disables sensitivity,
+    // this callback will still be called, so we must suppress it.
+    return;
+  }
+
+  // translate Gesture input to get useful data...
+  switch(gesture.state)
+  {
+    case Gesture::Started:
+    {
+      DALI_LOG_SCROLL_STATE("[0x%X] Pan Started", this);
+      mPanStartPosition = gesture.position - gesture.displacement;
+      UpdateLocalScrollProperties();
+      GestureStarted();
+      mPanning = true;
+      self.SetProperty( Toolkit::ScrollView::Property::PANNING, true );
+      self.SetProperty( Toolkit::ScrollView::Property::START_PAGE_POSITION, Vector3(gesture.position.x, gesture.position.y, 0.0f) );
+
+      UpdateMainInternalConstraint();
+      Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
+      if( scrollBar && mTransientScrollBar )
+      {
+        Vector3 size = Self().GetCurrentSize();
+        const Toolkit::RulerDomain& rulerDomainX = mRulerX->GetDomain();
+        const Toolkit::RulerDomain& rulerDomainY = mRulerY->GetDomain();
+
+        if( ( rulerDomainX.max > size.width ) || ( rulerDomainY.max > size.height ) )
+        {
+          scrollBar.ShowIndicator();
+        }
+      }
+      break;
+    }
+
+    case Gesture::Continuing:
+    {
+      if ( mPanning )
+      {
+        DALI_LOG_SCROLL_STATE("[0x%X] Pan Continuing", this);
+        GestureContinuing(gesture.screenDisplacement);
+      }
+      else
+      {
+        // If we do not think we are panning, then we should not do anything here
+        return;
+      }
+      break;
+    }
+
+    case Gesture::Finished:
+    case Gesture::Cancelled:
+    {
+      if ( mPanning )
+      {
+        DALI_LOG_SCROLL_STATE("[0x%X] Pan %s", this, ( ( gesture.state == Gesture::Finished ) ? "Finished" : "Cancelled" ) );
+
+        UpdateLocalScrollProperties();
+        mLastVelocity = gesture.velocity;
+        mPanning = false;
+        self.SetProperty( Toolkit::ScrollView::Property::PANNING, false );
+
+        if( mScrollMainInternalPrePositionConstraint )
+        {
+          mScrollMainInternalPrePositionConstraint.Remove();
+        }
+
+        Toolkit::ScrollBar scrollBar = mScrollBar.GetHandle();
+        if( scrollBar && mTransientScrollBar )
+        {
+          scrollBar.HideIndicator();
+        }
+      }
+      else
+      {
+        // If we do not think we are panning, then we should not do anything here
+        return;
+      }
+      break;
+    }
+
+    case Gesture::Possible:
+    case Gesture::Clear:
+    {
+      // Nothing to do, not needed.
+      break;
+    }
+
+  } // end switch(gesture.state)
+
+  OnGestureEx(gesture.state);
+}
+
+void ScrollView::OnGestureEx(Gesture::State state)
+{
+  // call necessary signals for application developer
+
+  if(state == Gesture::Started)
+  {
+    Vector2 currentScrollPosition = GetCurrentScrollPosition();
+    Self().SetProperty(Toolkit::ScrollView::Property::SCROLLING, true);
+    mScrolling = true;
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollStartedSignal 2 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollStartedSignal.Emit( currentScrollPosition );
+  }
+  else if( (state == Gesture::Finished) ||
+           (state == Gesture::Cancelled) ) // Finished/default
+  {
+    // when all the gestures have finished, we finish the transform.
+    // so if a user decides to pan (1 gesture), and then pan+zoom (2 gestures)
+    // then stop panning (back to 1 gesture), and then stop zooming (0 gestures).
+    // this is the point we end, and perform necessary snapping.
+    mGestureStackDepth--;
+    if(mGestureStackDepth==0)
+    {
+      // no flick if we have not exceeded min flick distance
+      if( (fabsf(mPanDelta.x) < mMinFlickDistance.x)
+          && (fabsf(mPanDelta.y) < mMinFlickDistance.y) )
+      {
+        // reset flick velocity
+        mLastVelocity = Vector2::ZERO;
+      }
+      FinishTransform();
+    }
+    else
+    {
+      DALI_LOG_SCROLL_STATE("[0x%X] mGestureStackDepth[%d]", this, mGestureStackDepth);
+    }
+  }
+}
+
+void ScrollView::FinishTransform()
+{
+  // at this stage internal x and x scroll position should have followed prescroll position exactly
+  Actor self = Self();
+
+  PreAnimatedScrollSetup();
+
+  // convert pixels/millisecond to pixels per second
+  bool animating = SnapWithVelocity(mLastVelocity * 1000.0f);
+
+  if(!animating)
+  {
+    // if not animating, then this pan has completed right now.
+    SetScrollUpdateNotification(false);
+    mScrolling = false;
+    Self().SetProperty(Toolkit::ScrollView::Property::SCROLLING, false);
+
+    if( fabs(mScrollPrePosition.x - mScrollTargetPosition.x) > Math::MACHINE_EPSILON_10 )
+    {
+      SnapInternalXTo(mScrollTargetPosition.x);
+    }
+    if( fabs(mScrollPrePosition.y - mScrollTargetPosition.y) > Math::MACHINE_EPSILON_10 )
+    {
+      SnapInternalYTo(mScrollTargetPosition.y);
+    }
+    Vector2 currentScrollPosition = GetCurrentScrollPosition();
+    DALI_LOG_SCROLL_STATE("[0x%X] mScrollCompletedSignal 6 [%.2f, %.2f]", this, currentScrollPosition.x, currentScrollPosition.y);
+    mScrollCompletedSignal.Emit( currentScrollPosition );
+  }
+}
+
+Vector2 ScrollView::GetOvershoot(Vector2& position) const
+{
+  Vector3 size = Self().GetCurrentSize();
+  Vector2 overshoot;
+
+  const RulerDomain rulerDomainX = mRulerX->GetDomain();
+  const RulerDomain rulerDomainY = mRulerY->GetDomain();
+
+  if(mRulerX->IsEnabled() && rulerDomainX.enabled)
+  {
+    const float left = rulerDomainX.min - position.x;
+    const float right = size.width - rulerDomainX.max - position.x;
+    if(left<0)
+    {
+      overshoot.x = left;
+    }
+    else if(right>0)
+    {
+      overshoot.x = right;
+    }
+  }
+
+  if(mRulerY->IsEnabled() && rulerDomainY.enabled)
+  {
+    const float top = rulerDomainY.min - position.y;
+    const float bottom = size.height - rulerDomainY.max - position.y;
+    if(top<0)
+    {
+      overshoot.y = top;
+    }
+    else if(bottom>0)
+    {
+      overshoot.y = bottom;
+    }
+  }
+
+  return overshoot;
+}
+
+bool ScrollView::OnAccessibilityPan(PanGesture gesture)
+{
+  // Keep track of whether this is an AccessibilityPan
+  mInAccessibilityPan = true;
+  OnPan(gesture);
+  mInAccessibilityPan = false;
+
+  return true;
+}
+
+void ScrollView::ClampPosition(Vector2& position) const
+{
+  ClampState2D clamped;
+  ClampPosition(position, clamped);
+}
+
+void ScrollView::ClampPosition(Vector2& position, ClampState2D &clamped) const
+{
+  Vector3 size = Self().GetCurrentSize();
+
+  position.x = -mRulerX->Clamp(-position.x, size.width, 1.0f, clamped.x);    // NOTE: X & Y rulers think in -ve coordinate system.
+  position.y = -mRulerY->Clamp(-position.y, size.height, 1.0f, clamped.y);   // That is scrolling RIGHT (e.g. 100.0, 0.0) means moving LEFT.
+}
+
+void ScrollView::WrapPosition(Vector2& position) const
+{
+  if(mWrapMode)
+  {
+    const RulerDomain rulerDomainX = mRulerX->GetDomain();
+    const RulerDomain rulerDomainY = mRulerY->GetDomain();
+
+    if(mRulerX->IsEnabled())
+    {
+      position.x = -WrapInDomain(-position.x, rulerDomainX.min, rulerDomainX.max);
+    }
+
+    if(mRulerY->IsEnabled())
+    {
+      position.y = -WrapInDomain(-position.y, rulerDomainY.min, rulerDomainY.max);
+    }
+  }
+}
+
+void ScrollView::UpdateMainInternalConstraint()
+{
+  // TODO: Only update the constraints which have changed, rather than remove all and add all again.
+  // Requires a dali-core ApplyConstraintAt, or a ReplaceConstraint. The former is probably more flexible.
+  Actor self = Self();
+  PanGestureDetector detector( GetPanGestureDetector() );
+
+  if(mScrollMainInternalPositionConstraint)
+  {
+    mScrollMainInternalPositionConstraint.Remove();
+    mScrollMainInternalDeltaConstraint.Remove();
+    mScrollMainInternalFinalConstraint.Remove();
+    mScrollMainInternalRelativeConstraint.Remove();
+    mScrollMainInternalDomainConstraint.Remove();
+    mScrollMainInternalPrePositionMaxConstraint.Remove();
+  }
+  if( mScrollMainInternalPrePositionConstraint )
+  {
+    mScrollMainInternalPrePositionConstraint.Remove();
+  }
+
+  // TODO: It's probably better to use a local displacement value as this will give a displacement when scrolling just commences
+  // but we need to make sure than the gesture system gives displacement since last frame (60Hz), not displacement since last touch event (90Hz).
+
+  // 1. First calculate the pre-position (this is the scroll position if no clamping has taken place)
+  Vector2 initialPanMask = Vector2(mRulerX->IsEnabled() ? 1.0f : 0.0f, mRulerY->IsEnabled() ? 1.0f : 0.0f);
+
+  if( mLockAxis == LockVertical )
+  {
+    initialPanMask.y = 0.0f;
+  }
+  else if( mLockAxis == LockHorizontal )
+  {
+    initialPanMask.x = 0.0f;
+  }
+
+  if( mPanning )
+  {
+    mScrollMainInternalPrePositionConstraint = Constraint::New<Vector2>( self,
+                                                                         Toolkit::ScrollView::Property::SCROLL_PRE_POSITION,
+                                                                         InternalPrePositionConstraint( mPanStartPosition,
+                                                                                                        initialPanMask,
+                                                                                                        mAxisAutoLock,
+                                                                                                        mAxisAutoLockGradient,
+                                                                                                        mLockAxis,
+                                                                                                        mMaxOvershoot,
+                                                                                                        mRulerX,
+                                                                                                        mRulerY ) );
+    mScrollMainInternalPrePositionConstraint.AddSource( Source( detector, PanGestureDetector::Property::LOCAL_POSITION ) );
+    mScrollMainInternalPrePositionConstraint.AddSource( Source( detector, PanGestureDetector::Property::PANNING ) );
+    mScrollMainInternalPrePositionConstraint.AddSource( Source( self, Actor::Property::SIZE ) );
+    mScrollMainInternalPrePositionConstraint.Apply();
+  }
+
+  // 2. Second calculate the clamped position (actual position)
+  mScrollMainInternalPositionConstraint = Constraint::New<Vector2>( self,
+                                                                    Toolkit::ScrollView::Property::SCROLL_POSITION,
+                                                                    InternalPositionConstraint( mRulerX->GetDomain(),
+                                                                                                mRulerY->GetDomain(),
+                                                                                                mWrapMode ) );
+  mScrollMainInternalPositionConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ) );
+  mScrollMainInternalPositionConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
+  mScrollMainInternalPositionConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  mScrollMainInternalPositionConstraint.AddSource( Source( self, Actor::Property::SIZE ) );
+  mScrollMainInternalPositionConstraint.Apply();
+
+  mScrollMainInternalDeltaConstraint = Constraint::New<Vector2>( self, Toolkit::ScrollView::Property::SCROLL_POSITION_DELTA, InternalPositionDeltaConstraint );
+  mScrollMainInternalDeltaConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+  mScrollMainInternalDeltaConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_DOMAIN_OFFSET ) );
+  mScrollMainInternalDeltaConstraint.Apply();
+
+  mScrollMainInternalFinalConstraint = Constraint::New<Vector2>( self, Toolkit::ScrollView::Property::SCROLL_FINAL,
+                                                                 InternalFinalConstraint( FinalDefaultAlphaFunction,
+                                                                                          FinalDefaultAlphaFunction ) );
+  mScrollMainInternalFinalConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+  mScrollMainInternalFinalConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::OVERSHOOT_X ) );
+  mScrollMainInternalFinalConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::OVERSHOOT_Y ) );
+  mScrollMainInternalFinalConstraint.Apply();
+
+  mScrollMainInternalRelativeConstraint = Constraint::New<Vector2>( self, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, InternalRelativePositionConstraint );
+  mScrollMainInternalRelativeConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+  mScrollMainInternalRelativeConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
+  mScrollMainInternalRelativeConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  mScrollMainInternalRelativeConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+  mScrollMainInternalRelativeConstraint.Apply();
+
+  mScrollMainInternalDomainConstraint = Constraint::New<Vector2>( self, Toolkit::ScrollView::Property::SCROLL_DOMAIN_SIZE, InternalScrollDomainConstraint );
+  mScrollMainInternalDomainConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
+  mScrollMainInternalDomainConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  mScrollMainInternalDomainConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+  mScrollMainInternalDomainConstraint.Apply();
+
+  mScrollMainInternalPrePositionMaxConstraint = Constraint::New<Vector2>( self, Toolkit::ScrollView::Property::SCROLL_PRE_POSITION_MAX, InternalPrePositionMaxConstraint );
+  mScrollMainInternalPrePositionMaxConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  mScrollMainInternalPrePositionMaxConstraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+  mScrollMainInternalPrePositionMaxConstraint.Apply();
+
+  // When panning we want to make sure overshoot values are affected by pre position and post position
+  SetOvershootConstraintsEnabled(!mWrapMode);
+}
+
+void ScrollView::SetOvershootConstraintsEnabled(bool enabled)
+{
+  Actor self( Self() );
+  // remove and reset, it may now be in wrong order with the main internal constraints
+  if( mScrollMainInternalOvershootXConstraint )
+  {
+    mScrollMainInternalOvershootXConstraint.Remove();
+    mScrollMainInternalOvershootXConstraint.Reset();
+    mScrollMainInternalOvershootYConstraint.Remove();
+    mScrollMainInternalOvershootYConstraint.Reset();
+  }
+  if( enabled )
+  {
+    mScrollMainInternalOvershootXConstraint= Constraint::New<float>( self, Toolkit::ScrollView::Property::OVERSHOOT_X, OvershootXConstraint(mMaxOvershoot.x) );
+    mScrollMainInternalOvershootXConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ) );
+    mScrollMainInternalOvershootXConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+    mScrollMainInternalOvershootXConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL ) );
+    mScrollMainInternalOvershootXConstraint.Apply();
+
+    mScrollMainInternalOvershootYConstraint = Constraint::New<float>( self, Toolkit::ScrollView::Property::OVERSHOOT_Y, OvershootYConstraint(mMaxOvershoot.y) );
+    mScrollMainInternalOvershootYConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_PRE_POSITION ) );
+    mScrollMainInternalOvershootYConstraint.AddSource( LocalSource( Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+    mScrollMainInternalOvershootYConstraint.AddSource( LocalSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) );
+    mScrollMainInternalOvershootYConstraint.Apply();
+  }
+  else
+  {
+    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_X, 0.0f);
+    self.SetProperty(Toolkit::ScrollView::Property::OVERSHOOT_Y, 0.0f);
+  }
+}
+
+void ScrollView::SetInternalConstraints()
+{
+  // Internal constraints (applied to target ScrollBase Actor itself) /////////
+  UpdateMainInternalConstraint();
+
+  // User definable constraints to apply to all child actors //////////////////
+  Actor self = Self();
+
+  // Apply some default constraints to ScrollView & its bound actors
+  // Movement + Wrap function
+
+  Constraint constraint;
+
+  // MoveActor (scrolling)
+  constraint = Constraint::New<Vector3>( self, Actor::Property::POSITION, MoveActorConstraint );
+  constraint.AddSource( Source( self, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  ApplyConstraintToBoundActors(constraint);
+
+  // WrapActor (wrap functionality)
+  constraint = Constraint::New<Vector3>( self, Actor::Property::POSITION, WrapActorConstraint );
+  constraint.AddSource( LocalSource( Actor::Property::SCALE ) );
+  constraint.AddSource( LocalSource( Actor::Property::ANCHOR_POINT ) );
+  constraint.AddSource( LocalSource( Actor::Property::SIZE ) );
+  constraint.AddSource( Source( self, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
+  constraint.AddSource( Source( self, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
+  constraint.AddSource( Source( self, Toolkit::ScrollView::Property::WRAP ) );
+  constraint.SetRemoveAction(Constraint::Discard);
+  ApplyConstraintToBoundActors(constraint);
+}
+
+void ScrollView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollView )
+  {
+    ScrollView& scrollViewImpl( GetImpl( scrollView ) );
+    switch( index )
+    {
+      case Toolkit::ScrollView::Property::WRAP_ENABLED:
+      {
+        scrollViewImpl.SetWrapMode( value.Get<bool>() );
+        break;
+      }
+      case Toolkit::ScrollView::Property::PANNING_ENABLED:
+      {
+        scrollViewImpl.SetScrollSensitive( value.Get<bool>() );
+        break;
+      }
+      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
+      {
+        scrollViewImpl.SetAxisAutoLock( value.Get<bool>() );
+        break;
+      }
+      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        scrollViewImpl.SetWheelScrollDistanceStep( value.Get<Vector2>() );
+        break;
+      }
+      case Toolkit::ScrollView::Property::SCROLL_MODE:
+      {
+        Property::Map* map = value.GetMap();
+        if( map )
+        {
+          scrollViewImpl.SetScrollMode( *map );
+        }
+      }
+    }
+  }
+}
+
+Property::Value ScrollView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollView )
+  {
+    ScrollView& scrollViewImpl( GetImpl( scrollView ) );
+    switch( index )
+    {
+      case Toolkit::ScrollView::Property::WRAP_ENABLED:
+      {
+        value = scrollViewImpl.GetWrapMode();
+        break;
+      }
+      case Toolkit::ScrollView::Property::PANNING_ENABLED:
+      {
+        value = scrollViewImpl.GetScrollSensitive();
+        break;
+      }
+      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
+      {
+        value = scrollViewImpl.GetAxisAutoLock();
+        break;
+      }
+      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        value = scrollViewImpl.GetWheelScrollDistanceStep();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void ScrollView::SetScrollMode( const Property::Map& scrollModeMap )
+{
+  Toolkit::RulerPtr rulerX, rulerY;
+
+  // Check the scroll mode in the X axis
+  bool xAxisScrollEnabled = true;
+  Property::Value* valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::X_AXIS_SCROLL_ENABLED, "xAxisScrollEnabled" );
+  if( valuePtr && valuePtr->GetType() == Property::BOOLEAN )
+  {
+    valuePtr->Get( xAxisScrollEnabled );
+  }
+
+  if( !xAxisScrollEnabled )
+  {
+    // Default ruler and disabled
+    rulerX = new Toolkit::DefaultRuler();
+    rulerX->Disable();
+  }
+  else
+  {
+    valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::X_AXIS_SNAP_TO_INTERVAL, "xAxisSnapToInterval" );
+    float xAxisSnapToInterval = 0.0f;
+    if( valuePtr && valuePtr->Get( xAxisSnapToInterval ) )
+    {
+      // Fixed ruler and enabled
+      rulerX = new Toolkit::FixedRuler( xAxisSnapToInterval );
+    }
+    else
+    {
+      // Default ruler and enabled
+      rulerX = new Toolkit::DefaultRuler();
+    }
+
+    valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::X_AXIS_SCROLL_BOUNDARY, "xAxisScrollBoundary" );
+    float xAxisScrollBoundary = 0.0f;
+    if( valuePtr && valuePtr->Get( xAxisScrollBoundary ) )
+    {
+      // By default ruler domain is disabled unless set
+      rulerX->SetDomain( Toolkit::RulerDomain( 0, xAxisScrollBoundary, true ) );
+    }
+  }
+
+  // Check the scroll mode in the Y axis
+  bool yAxisScrollEnabled = true;
+  valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::Y_AXIS_SCROLL_ENABLED, "yAxisScrollEnabled" );
+  if( valuePtr && valuePtr->GetType() == Property::BOOLEAN )
+  {
+    valuePtr->Get( yAxisScrollEnabled );
+  }
+
+  if( !yAxisScrollEnabled )
+  {
+    // Default ruler and disabled
+    rulerY = new Toolkit::DefaultRuler();
+    rulerY->Disable();
+  }
+  else
+  {
+    valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, "yAxisSnapToInterval" );
+    float yAxisSnapToInterval = 0.0f;
+    if( valuePtr && valuePtr->Get( yAxisSnapToInterval ) )
+    {
+      // Fixed ruler and enabled
+      rulerY = new Toolkit::FixedRuler(yAxisSnapToInterval);
+    }
+    else
+    {
+      // Default ruler and enabled
+      rulerY = new Toolkit::DefaultRuler();
+    }
+
+    valuePtr = scrollModeMap.Find( Toolkit::ScrollMode::Y_AXIS_SCROLL_BOUNDARY, "yAxisScrollBoundary" );
+    float yAxisScrollBoundary = 0.0f;
+    if( valuePtr && valuePtr->Get( yAxisScrollBoundary ) )
+    {
+      // By default ruler domain is disabled unless set
+      rulerY->SetDomain( Toolkit::RulerDomain( 0, yAxisScrollBoundary, true ) );
+    }
+  }
+
+  SetRulerX(rulerX);
+  SetRulerY(rulerY);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
new file mode 100644 (file)
index 0000000..2c2829a
--- /dev/null
@@ -0,0 +1,996 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ScrollView;
+typedef IntrusivePtr<ScrollView>    ScrollViewPtr;
+
+class ScrollInternalConstraints;
+typedef IntrusivePtr<ScrollInternalConstraints>    ScrollInternalConstraintsPtr;
+
+class ScrollOvershootIndicator;
+typedef IntrusivePtr<ScrollOvershootIndicator> ScrollOvershootIndicatorPtr;
+
+/**
+ * @copydoc Toolkit::ScrollView
+ */
+class ScrollView : public ScrollBase
+{
+public:
+
+  /**
+   * FindDirection specifies how searching is conducted within the Find... routines.
+   */
+  enum FindDirection
+  {
+    None = -3,        ///< Includes none within the search query.
+    All = -2,         ///< Includes all within the search query.
+    Left = -1,        ///< Includes only those not right !(>)
+    Right = 1,        ///< Includes only those right (>)
+    Up = -1,          ///< Includes only those not below  !(>)
+    Down = 1,         ///< Includes only those below (>)
+    Out = -1,         ///< Includes only those not infront  !(>)
+    In = 1            ///< Includes only those infront (>)
+  };
+
+  enum LockAxis
+  {
+    LockPossible = 0, ///< Locking is possible, but not set in stone yet.
+    LockHorizontal,   ///< Locking is set to horizontal. (can pan vertically)
+    LockVertical,     ///< Locking is set to vertical. (can pan horizontally)
+    LockNone          ///< Locking is set to none (free panning).
+  };
+
+  enum ScrollStateFlag
+  {
+    AnimatingInternalX = 0x01, ///< animating mPropertyX due to externally requested ScrollTo or internal snapping operation
+    AnimatingInternalY = 0x02, ///< animating mPropertyY due to externally requested ScrollTo or internal snapping operation
+    SnappingInternalX  = 0x04, ///< snapping mPropertyX back to mPropertyPreScroll x value to remove x overshoot over time
+    SnappingInternalY  = 0x08, ///< snapping mPropertyY back to mPropertyPreScroll y value to remove y overshoot over time
+  };
+
+  static const unsigned int SCROLL_X_STATE_MASK = AnimatingInternalX | SnappingInternalX;
+  static const unsigned int SCROLL_Y_STATE_MASK = AnimatingInternalY | SnappingInternalY;
+  static const unsigned int SCROLL_ANIMATION_FLAGS = AnimatingInternalX | AnimatingInternalY;
+  static const unsigned int SNAP_ANIMATION_FLAGS = SnappingInternalX | SnappingInternalY;
+
+private:
+
+  typedef std::vector<Dali::Toolkit::ScrollViewEffect> ScrollViewEffectContainer; ///< Container of Dali::Toolkit::ScrollViewEffect
+  typedef ScrollViewEffectContainer::iterator ScrollViewEffectIter; ///< Iterator for Dali::Toolkit::ScrollViewEffectContainer
+
+public:
+
+  /**
+   * Create a new ScrollView.
+   * @return A public handle to the newly allocated ScrollView.
+   */
+  static Dali::Toolkit::ScrollView New();
+
+public:
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetScrollSnapAlphaFunction
+   */
+  AlphaFunction GetScrollSnapAlphaFunction() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollSnapAlphaFunction
+   */
+  void SetScrollSnapAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetScrollFlickAlphaFunction
+   */
+  AlphaFunction GetScrollFlickAlphaFunction() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollFlickAlphaFunction
+   */
+  void SetScrollFlickAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetScrollSnapDuration
+   */
+  float GetScrollSnapDuration() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollSnapDuration
+   */
+  void SetScrollSnapDuration(float time);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetScrollFlickDuration
+   */
+  float GetScrollFlickDuration() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollFlickDuration
+   */
+  void SetScrollFlickDuration(float time);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ApplyEffect
+   */
+  void ApplyEffect(Toolkit::ScrollViewEffect effect);
+
+  /**
+   * @copydoc Toolkit::ScrollView::RemoveEffect
+   */
+  void RemoveEffect(Toolkit::ScrollViewEffect effect);
+
+  /**
+   * @copydoc Toolkit::ScrollView::RemoveAllEffects
+   */
+  void RemoveAllEffects();
+
+  /**
+   * @copydoc Toolkit::ScrollView::ApplyConstraintToChildren
+   */
+  void ApplyConstraintToChildren(Constraint constraint);
+
+  /**
+   * @copydoc Toolkit::ScrollView::RemoveConstraintsFromChildren
+   */
+  void RemoveConstraintsFromChildren();
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetRulerX
+   */
+  const RulerPtr GetRulerX() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetRulerY
+   */
+  const RulerPtr GetRulerY() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetRulerX
+   */
+  void SetRulerX(RulerPtr ruler);
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetRulerY
+   */
+  void SetRulerY(RulerPtr ruler);
+
+  /**
+   * Retrieve the touch sensitivity.
+   *
+   * @return whether the touch sensitivity is true or false.
+   */
+  bool GetScrollSensitive();
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollSensitive
+   */
+  void SetScrollSensitive(bool sensitive);
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetMaxOvershoot
+   */
+  void SetMaxOvershoot(float overshootX, float overshootY);
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetSnapOvershootAlphaFunction
+   */
+  void SetSnapOvershootAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * Retrieve the duartion of Snap Overshoot animation
+   *
+   * @return the duration.
+   */
+  float GetSnapOvershootDuration();
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetSnapOvershootDuration
+   */
+  void SetSnapOvershootDuration(float duration);
+
+  /**
+   * Retrieve whether Actor Auto-Snap mode is enabled or not.
+   *
+   * @return Actor Auto-Snap mode Enabled flag.
+   */
+  bool GetActorAutoSnap();
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetActorAutoSnap
+   */
+  void SetActorAutoSnap(bool enable);
+
+  /**
+   * Enables or Disables Auto Resizing mode for ScrollView contents.
+   *
+   * When enabled, the ScrollView's X/Y Domains are restricted to the
+   * dimensions of the content's bounds, which may change as Actors are
+   * Added/Removed, and repositioned.
+   *
+   * @note This has been disabled for now, as this requires some fundamental
+   * changes to the way Actors positions and bounds are retrieved.
+   * (currently only constraints have these initial state knowledge)
+   *
+   * @param[in] enable Enables (true), or disables (false) Auto Resize.
+   */
+  void SetAutoResize(bool enable);
+
+  /**
+   * Returns whether the wrap mode has been enabled (true) or not (false).
+   *
+   * @return Wrap Mode Enabled flag.
+   */
+  bool GetWrapMode() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetWrapMode
+   */
+  void SetWrapMode(bool enable);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetScrollupdateDistance
+   */
+  int GetScrollUpdateDistance() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollUpdateDistance
+   */
+  void SetScrollUpdateDistance(int distance);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetAxisAutoLock
+   */
+  bool GetAxisAutoLock() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetAxisAutoLock
+   */
+  void SetAxisAutoLock(bool enable);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetAxisAutoLockGradient
+   */
+  float GetAxisAutoLockGradient() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetAxisAutoLockGradient
+   */
+  void SetAxisAutoLockGradient(float gradient);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetFrictionCoefficient
+   */
+  float GetFrictionCoefficient() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetFrictionCoefficient
+   */
+  void SetFrictionCoefficient(float friction);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetFlickSpeedCoefficient
+   */
+  float GetFlickSpeedCoefficient() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetFlickSpeedCoefficient
+   */
+  void SetFlickSpeedCoefficient(float speed);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetMinimumDistanceForFlick
+   */
+  Vector2 GetMinimumDistanceForFlick() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetMinimumDistanceForFlick
+   */
+  void SetMinimumDistanceForFlick( const Vector2& distance );
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetMinimumSpeedForFlick
+   */
+  float GetMinimumSpeedForFlick() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetMinimumSpeedForFlick
+   */
+  void SetMinimumSpeedForFlick( float speed );
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetMaxFlickSpeed
+   */
+  float GetMaxFlickSpeed() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetMaxFlickSpeed
+   */
+  void SetMaxFlickSpeed(float speed);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetWheelScrollDistanceStep
+   */
+  Vector2 GetWheelScrollDistanceStep() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetWheelScrollDistanceStep
+   */
+  void SetWheelScrollDistanceStep(Vector2 step);
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetCurrentPage
+   */
+  unsigned int GetCurrentPage() const;
+
+  /**
+   * @copydoc Toolkit::ScrollView::GetCurrentScrollPosition
+   */
+  Vector2 GetCurrentScrollPosition() const;
+
+  /**
+   * @copydoc ScrollTo(const Vector2&)
+   */
+  void TransformTo(const Vector2& position,
+                   DirectionBias horizontalBias = DirectionBiasNone, DirectionBias verticalBias = DirectionBiasNone);
+
+  /**
+   * @copydoc ScrollTo(const Vector2&, float, AlhpaFunction, DirectionBias, DirectionBias)
+   */
+  void TransformTo(const Vector2& position, float duration, AlphaFunction alpha,
+                   DirectionBias horizontalBias = DirectionBiasNone, DirectionBias verticalBias = DirectionBiasNone);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(const Vector2 &position)
+   */
+  void ScrollTo(const Vector2 &position);
+
+  /**
+   * @copydoc Toolkit::Scrollable::ScrollTo(const Vector2& position, float duration)
+   */
+  void ScrollTo(const Vector2& position, float duration);
+
+  /**
+   * @copydoc Toolkit::Scrollable::ScrollTo(const Vector2& position, float duration, AlphaFunction alpha)
+   */
+  void ScrollTo(const Vector2& position, float duration, AlphaFunction alpha);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(const Vector2 &position, float duration, DirectionBias horizontalBias, DirectionBias verticalBias)
+   */
+  void ScrollTo(const Vector2& position, float duration,
+                DirectionBias horizontalBias, DirectionBias verticalBias);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(const Vector2 &position, float duration, AlphaFunction alpha, DirectionBias horizontalBias, DirectionBias verticalBias)
+   */
+  void ScrollTo(const Vector2& position, float duration, AlphaFunction alpha,
+                DirectionBias horizontalBias, DirectionBias verticalBias);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(unsigned int page)
+   */
+  void ScrollTo(unsigned int page);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
+   */
+  void ScrollTo(unsigned int page, float duration, DirectionBias bias = DirectionBiasNone);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(Actor& actor)
+   */
+  void ScrollTo(Actor &actor);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollTo(Actor& actor, float duration)
+   */
+  void ScrollTo(Actor &actor, float duration);
+
+  /**
+   * @copydoc Toolkit::ScrollView::SetScrollingDirection()
+   */
+  void SetScrollingDirection( Radian direction, Radian threshold );
+
+  /**
+   * @copydoc Toolkit::ScrollView::RemoveScrollingDirection()
+   */
+  void RemoveScrollingDirection( Radian angle );
+
+  /**
+    * Finds the closest Actor to the current center of the ScrollView.
+    *
+    * @return A handle to the actor if found, or an empty handle if not.
+    */
+   Actor FindClosestActor();
+
+  /**
+   * Finds the closest Actor to position in ScrollView
+   *
+   * @param[in] position position within ScrollView.
+   * @param[in] dirX Whether to search only those elements that are Left,Right, or All
+   * @param[in] dirY Whether to search only those elements that are Up,Down, or All
+   * @param[in] dirZ Whether to search only those elements that are Out,In, or All
+   * @return A handle to the actor if found, or an empty handle if not.
+   */
+  Actor FindClosestActorToPosition(const Vector3& position, FindDirection dirX = All, FindDirection dirY = All, FindDirection dirZ = All);
+
+  /**
+   * @copydoc Toolkit::ScrollView::ScrollToSnapPoint
+  */
+  bool ScrollToSnapPoint();
+
+  /**
+   * Stops animation
+   */
+  void StopAnimation(void);
+
+  /**
+   * Stops the input animation
+   *
+   * @param[in] the animation to stop
+   */
+  void StopAnimation(Animation& animation);
+
+  /**
+   * Animates to position transform.
+   *
+   * @param[in] position The position to animate to
+   * @param[in] positionDuration The number of seconds this animation should run for in each axis.
+   * @param[in] alpha The easing alpha function to use.
+   * @param[in] findShortcuts (optional) Whether to find the shortest route (in Wrap mode)
+   * @param[in] horizontalBias (optional) Whether to bias animation to left or right (or no biasing)
+   * @param[in] verticalBias (optional) Whether to bias animation to top or bottom (or no biasing)
+   * @return True if animation necessary and taking place to reach desired transform.
+   */
+  bool AnimateTo(const Vector2& position, const Vector2& positionDuration,
+                             AlphaFunction alpha, bool findShortcuts = true,
+                             DirectionBias horizontalBias = DirectionBiasNone, DirectionBias verticalBias = DirectionBiasNone,
+                             SnapType snapType = Snap);
+
+  /**
+   * @copydoc Toolkit::Scrollable::AddOverlay()
+   */
+  void AddOverlay(Actor actor);
+
+  /**
+   * @copydoc Toolkit::Scrollable::RemoveOverlay()
+   */
+  void RemoveOverlay(Actor actor);
+
+  /**
+   * @copydoc Toolkit::Internal::Scrollable::SetOvershootSize
+   */
+  void SetOvershootSize( const Vector2& size );
+
+  /**
+   * @copydoc Toolkit::Internal::Scrollable::SetOvershootEffectColor
+   */
+  void SetOvershootEffectColor( const Vector4& color );
+
+  //properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+public: //Signals
+
+  /**
+   * @copydoc Dali::Toolkit::ScrollView::SnapStartedSignal()
+   */
+  Toolkit::ScrollView::SnapStartedSignalType& SnapStartedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private: // private overridden functions from CustomActorImpl and Controls
+
+  /**
+   * @copydoc Dali::CustomActorImpl::OnSizeAnimation(Animation&, const Vector3&)
+   */
+  virtual void OnSizeAnimation(Animation& animation, const Vector3& targetSize);
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet(const Vector3&)
+   */
+  virtual void OnSizeSet( const Vector3& size );
+
+  /**
+   * From CustomActorImpl; called after a child has been added to the owning actor.
+   * @param[in] child The child which has been added.
+   */
+  virtual void OnChildAdd(Actor& child);
+
+  /**
+   * From CustomActorImpl; called shortly before a child is removed from the owning actor.
+   * @param[in] child The child being removed.
+   */
+  virtual void OnChildRemove(Actor& child);
+
+  /**
+   * From CustomActorImpl; called after a wheelEvent is received by the owning actor.
+   * @param[in] event The wheel event.
+   * @return True if the event should be consumed.
+   */
+  virtual bool OnWheelEvent(const WheelEvent& event);
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc Toolkit::Control::OnAccessibilityPan()
+   */
+  virtual bool OnAccessibilityPan(PanGesture gesture);
+
+  /**
+   * @copydoc Toolkit::Scrollable::EnableScrollOvershoot()
+   */
+  virtual void EnableScrollOvershoot(bool enable);
+
+private:
+
+  /**
+   * Called after a touchSignal is received by the owning actor.
+   *
+   * We don't consume these events as content within the container may consume events.
+   *
+   * @param[in] actor The touched actor.
+   * @param[in] touch The touch information.
+   * @return True if the event should be consumed.
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Start a timer which calls OnTouchDownTimeout()
+   */
+  void StartTouchDownTimer();
+
+  /**
+   * Stop a timer which calls OnTouchDownTimeout()
+   */
+  void StopTouchDownTimer();
+
+  /**
+   * Helper to detect when touch-point has been down (outside of pan gesture)
+   */
+  bool OnTouchDownTimeout();
+
+  /**
+   * Called whenever a snap animation has completed
+   * @param[in] source the Animation instance that has completed.
+   * Resets all scrolling animations and states, leaving current scroll position at SCROLL_POSITION
+   */
+  void ResetScrolling();
+
+  /**
+   * Updates mScrollInternalPosition, mScrollPrePosition and mScrollPostPosition from their property counterparts
+   */
+  void UpdateLocalScrollProperties();
+
+  /**
+   * Makes sure scroll values are ready for animated scrolling
+   */
+  void PreAnimatedScrollSetup();
+
+  /**
+   * Finish an animated scroll, ensuring all scroll properties are updated
+   * and synchronised
+   */
+  void FinaliseAnimatedScroll();
+
+  /**
+   * Animates the internal x property to the given value
+   *
+   * @param[in] position The X position to animate to
+   * @param[in] duration The time in seconds for animation
+   * @param[in] alpha The alpha function to use for animating
+   */
+  void AnimateInternalXTo( float position, float duration, AlphaFunction alpha );
+
+  /**
+   * Animates the internal y property to the given value
+   *
+   * @param[in] position The Y position to animate to
+   * @param[in] duration The time in seconds for animation
+   * @param[in] alpha The alpha function to use for animating
+   */
+  void AnimateInternalYTo( float position, float duration, AlphaFunction alpha );
+
+  /**
+   * Called whenever a snap animation on the x-axis has completed
+   * @param[in] source the Animation instance that has completed.
+   */
+  void OnScrollAnimationFinished( Animation& source );
+
+  /**
+   * Called when either the X or Y internal scroll positions have finished snapping back to SCROLL_PRE_POSITION
+   *
+   * @param[in] source the Animation instance that has completed.
+   */
+  void OnSnapInternalPositionFinished( Animation& source );
+
+  /**
+   * Called whenever a snap animation on the x-axis has completed and we need to snap pre scroll
+   * position to our clamped position
+   * @param[in] position The x position to snap pre scroll property to
+   */
+  void SnapInternalXTo( float position );
+
+  /**
+   * Called whenever a snap animation on the y-axis has completed and we need to snap pre scroll
+   * position to our clamped position
+   * @param[in] position The y position to snap pre scroll property to
+   */
+  void SnapInternalYTo( float position );
+
+  /**
+   * This is called internally whenever the Scroll Rulers are
+   * modified. This will update the properties: 'scrollPositionMin'
+   * and 'scrollPositionMax' to reflect the changes.
+   */
+  void UpdatePropertyDomain();
+
+  /**
+   * Called when the gesture starts.
+   */
+  void GestureStarted();
+
+  /**
+   * Amalgamated Gesture Continuing event
+   *
+   * @param[in] panDelta average panning delta from base position (0)
+   */
+  void GestureContinuing(const Vector2& panDelta);
+
+  /**
+   * Called upon pan gesture event.
+   *
+   * @param[in] gesture The gesture event.
+   */
+  void OnPan( const PanGesture& pan);
+
+  /**
+   * Extension of the above gestures.
+   *
+   * @param[in] gesture The gesture event.
+   */
+  void OnGestureEx(Gesture::State state);
+
+  /**
+   * Performs snapping while taking into account Velocity of gesture
+   * (velocity in pixels/sec)
+   *
+   * @param[in] velocity velocity in pixels/sec
+   */
+  bool SnapWithVelocity(Vector2 velocity);
+
+  /**
+   * Finishes Container Transform
+   * (occurs upon finishing gesture i.e. releasing)
+   */
+  void FinishTransform();
+
+  /**
+   * Returns overshoot vector based on current position
+   *
+   * Overshoot vector is defined as how far outside of bounds
+   * the viewport is trying to view (prior to being clamped).
+   *
+   * an overshoot of (100,50), means user is in bottom right corner,
+   * trying to pan +100 to the right, and +50 below. This can be used
+   * to determine an effect, such as stretching.
+   *
+   * @param[in] position The position for which you wish to obtain overshoot vector
+   */
+  Vector2 GetOvershoot(Vector2& position) const;
+
+  /**
+   * Clamps position within the domain set up by X/Y Rulers
+   *
+   * @param[in,out] position The position you wish to clamp
+   */
+  void ClampPosition(Vector2& position) const;
+
+  /**
+   * Clamps position within the domain set up by X/Y Rulers
+   *
+   * @param[in,out] position The position you wish to clamp
+   * @param[out] clamped The results of the clamping.
+   */
+  void ClampPosition(Vector2& position, ClampState2D &clamped) const;
+
+  /**
+   * Wraps position within the domain set up by X/Y Rulers
+   *
+   * @note Only wraps if mWrapMode is enabled, and respective domains
+   * are enabled.
+   *
+   * @param[in,out] position The position you wish to wrap
+   */
+  void WrapPosition(Vector2& position) const;
+
+  /**
+   * Updates the main internal scroll constraints with new ruler and domain
+   * values
+   */
+  void UpdateMainInternalConstraint();
+
+  /**
+   * Enables/disables the overshoot constraints
+   *
+   * @param[in] enabled whether to enable or disable the overshoot constraints
+   */
+  void SetOvershootConstraintsEnabled(bool enabled);
+
+  /**
+   * Sets internal constraints for this ScrollView.
+   * Many of these internal constraints are based on properties within
+   * ScrollView.
+   */
+  void SetInternalConstraints();
+
+protected:
+
+  /**
+   * Construct a new ScrollView.
+   */
+  ScrollView();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ScrollView();
+
+private:
+
+  /**
+   * Searches this ScrollView, and attempts to Unbind
+   * systematically this Actor from the ScrollView attached.
+   *
+   * @param[in] child The actor to be unbound.
+   */
+  virtual void FindAndUnbindActor(Actor child);
+
+  /**
+   * Gets position property.
+   *
+   * @return The current position
+   */
+  Vector2 GetPropertyPrePosition() const;
+
+  /**
+   * Gets position property.
+   *
+   * @return The current position
+   */
+  Vector2 GetPropertyPosition() const;
+
+  /**
+   * Handles a Stopped animation. Its position properties need to be saved, and the animation flag
+   * switched off.
+   */
+  void HandleStoppedAnimation();
+
+  /**
+   * Handles a Stopped animation (whether the animation completed, or was
+   * manually stopped). Its position properties need to be saved, and the
+   * animation flag switched off.
+   */
+  void HandleSnapAnimationFinished();
+
+  /**
+   * Checks if the property notifications are active and adds them if not
+   */
+  void SetScrollUpdateNotification( bool enabled );
+
+  /**
+   * Refresh the ScrollView (used when animating to update application developer of changes)
+   * @return True if the refresh timer should be kept running.
+   */
+  void OnScrollUpdateNotification(Dali::PropertyNotification& source);
+
+  /**
+   * Set up default rulers using a property map
+   * @param[in] scrollModeMap A map defining the characteristics of X and Y scrolling
+   * using either FixedRuler or DefaultRuler.
+   */
+  void SetScrollMode( const Property::Map& scrollModeMap );
+
+private:
+
+  // Undefined
+  ScrollView(const ScrollView&);
+
+  // Undefined
+  ScrollView& operator=(const ScrollView& rhs);
+
+private:
+
+  unsigned long mTouchDownTime;         ///< The touch down time
+
+  int mGestureStackDepth;               ///< How many gestures are currently occuring.
+  Vector2 mPanStartPosition;            ///< Where the pan gesture's touch down occured
+  Vector2 mPanDelta;                    ///< Amount currently panned.
+
+  unsigned int mScrollStateFlags;       ///< flags indicating current state of scrolling
+  // Scroll delegate pre and post position properties...
+  Vector2 mScrollPrePosition;           ///< Wrapped scroll position, but not clamped
+  Vector2 mScrollPostPosition;          ///< Wrapped and clamped, this is the final scroll position used
+  Vector2 mScrollTargetPosition;        ///< Final target position for an animated scroll
+  Vector2 mDomainOffset;                ///< Domain offset (this keeps track of the domain boundaries that scroll positions traverses)
+
+  // Rulers for each axes...
+  RulerPtr mRulerX;
+  RulerPtr mRulerY;
+
+  // Last property values set to ScrollView
+  Vector2 mMinScroll;
+  Vector2 mMaxScroll;
+
+  Animation mInternalXAnimation;        ///< Animates mPropertyX to a snap position or application requested scroll position
+  Animation mInternalYAnimation;        ///< Animates mPropertyY to a snap position or application requested scroll position
+
+
+  Vector2 mLastVelocity;                ///< Record the last velocity from PanGesture (Finish event doesn't have correct velocity)
+  LockAxis mLockAxis;
+
+  Timer mTouchDownTimer;                ///< Used to interrupt snap-animation. This cannot be done in OnTouch without breaking fast flick behavior.
+
+  float mScrollUpdateDistance;          ///< Distance for scrolling to travel for the scroll update notifications
+  Dali::PropertyNotification mScrollXUpdateNotification; ///< scroll x position update notification
+  Dali::PropertyNotification mScrollYUpdateNotification; ///< scroll y position update notification
+
+  Actor mInternalActor;                 ///< Internal actor (we keep internal actors in here e.g. scrollbars, so we can ignore it in searches)
+
+  ScrollViewEffectContainer mEffects;   ///< Container keeping track of all the applied effects.
+
+  Vector2   mMaxOvershoot;                      ///< Number of scrollable pixels that will take overshoot from 0.0f to 1.0f
+  Vector2   mUserMaxOvershoot;                  ///< Set by user, allows overriding of default max overshoot for the scroll indicator
+  float     mSnapOvershootDuration;             ///< Duration for overshoot snapping back to Vector2::ZERO
+  AlphaFunction mSnapOvershootAlphaFunction;    ///< AlphaFunction to be used for this overshoot.
+
+  float mSnapDuration;                          ///< Time for the snap animation to take (in seconds).
+  AlphaFunction mSnapAlphaFunction;             ///< AlphaFunction to be used for the Snap Animation.
+
+  Vector2 mMinFlickDistance;                      ///< Minimum pan distance required for a flick
+  float mFlickSpeedThreshold;                   ///< Minimum pan speed required for a flick in pixels/ms
+  float mFlickDuration;                         ///< Time for the flick animation to take (in seconds).
+  AlphaFunction mFlickAlphaFunction;            ///< AlphaFunction to be used for the Flick Animation.
+
+  float mAxisAutoLockGradient;                  ///< Axis Auto-lock gradient threshold. Above this gradient and it will lock scrolling to closest axis.
+  float mFrictionCoefficient;                   ///< Friction coefficient. Amount of friction to apply to free panning flick animation. in stage.lengths/sec
+  float mFlickSpeedCoefficient;                 ///< Flick velocity coefficient. Input touch velocity is multiplied by this.
+  float mMaxFlickSpeed;                         ///< Maximum flick speed. Maximum speed of flick in stage.lengths/sec.
+
+  Vector2 mWheelScrollDistanceStep;        ///< The step of scroll distance in actor coordinates in X and Y axes for each wheel event received.
+
+  //ScrollInternalConstraintsPtr mScrollInternalConstraints;
+  Constraint mScrollMainInternalPrePositionConstraint;
+  Constraint mScrollMainInternalPositionConstraint;
+  Constraint mScrollMainInternalOvershootXConstraint;
+  Constraint mScrollMainInternalOvershootYConstraint;
+  Constraint mScrollMainInternalDeltaConstraint;
+  Constraint mScrollMainInternalFinalConstraint;
+  Constraint mScrollMainInternalRelativeConstraint;
+  Constraint mScrollMainInternalDomainConstraint;
+  Constraint mScrollMainInternalPrePositionMaxConstraint;
+
+  ScrollOvershootIndicatorPtr mOvershootIndicator;
+  WeakHandle<Toolkit::ScrollBar> mScrollBar;
+
+  Toolkit::ScrollView::SnapStartedSignalType mSnapStartedSignal;
+
+  bool mInAccessibilityPan:1;             ///< With AccessibilityPan its easier to move between snap positions
+  bool mScrolling:1;                      ///< Flag indicating whether the scroll view is being scrolled (by user or animation)
+  bool mScrollInterrupted:1;              ///< Flag set for when a down event interrupts a scroll
+  bool mPanning:1;                        ///< Whether scroll view is currently panning or not
+  bool mSensitive:1;                      ///< Scroll Sensitivity Flag.
+  bool mTouchDownTimeoutReached:1;        ///< Indicates when down event timeout occured without corresponding up event (touch still down)
+  bool mActorAutoSnapEnabled:1;           ///< Whether to automatically snap to closest actor.
+  bool mAutoResizeContainerEnabled:1;     ///< Whether to automatically resize container (affects RulerDomain's on X/Y axes)
+  bool mWrapMode:1;                       ///< Whether to wrap contents based on container size.
+  bool mAxisAutoLock:1;                   ///< Whether to automatically lock axis when panning.
+  bool mAlterChild:1;                     ///< Internal flag to control behavior of OnChildAdd/OnChildRemove when Adding internal Actors.
+  bool mDefaultMaxOvershoot:1;            ///< Whether to use default max overshoot or application defined one
+  bool mCanScrollHorizontal:1;            ///< Local value of our property to check against
+  bool mCanScrollVertical:1;              ///< Local value of our property to check against
+  bool mTransientScrollBar:1;             ///< True if scroll-bar should be automatically show/hidden during/after panning
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ScrollView& GetImpl(Toolkit::ScrollView& scrollView)
+{
+  DALI_ASSERT_ALWAYS(scrollView);
+
+  Dali::RefObject& handle = scrollView.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ScrollView&>(handle);
+}
+
+inline const Toolkit::Internal::ScrollView& GetImpl(const Toolkit::ScrollView& scrollView)
+{
+  DALI_ASSERT_ALWAYS(scrollView);
+
+  const Dali::RefObject& handle = scrollView.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ScrollView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_H
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
new file mode 100644 (file)
index 0000000..5d2c91b
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+ScrollViewPagePathEffect::ScrollViewPagePathEffect(Path path, const Vector3& forward, Dali::Property::Index inputPropertyIndex, const Vector3& viewPageSize, unsigned int pageCount)
+:mPageSize(viewPageSize),
+ mInputPropertyIndex(inputPropertyIndex),
+ mPageCount(pageCount)
+{
+  //Create path constrainer
+  mPathConstrainer = Dali::PathConstrainer::New();
+  mPathConstrainer.SetProperty( PathConstrainer::Property::FORWARD, forward );
+
+  Dali::Property::Value pointsProperty = path.GetProperty(Path::Property::POINTS);
+  mPathConstrainer.SetProperty( PathConstrainer::Property::POINTS, pointsProperty );
+
+  pointsProperty = path.GetProperty(Path::Property::CONTROL_POINTS);
+  mPathConstrainer.SetProperty( PathConstrainer::Property::CONTROL_POINTS, pointsProperty );
+
+  //Create linear constrainer
+  pointsProperty = Property::Value(Property::ARRAY);
+  Property::Array* array = pointsProperty.GetArray();
+
+  if( array )
+  {
+    array->PushBack(0.0f);
+    array->PushBack(1.0f);
+    array->PushBack(0.0f);
+  }
+  mLinearConstrainer = Dali::LinearConstrainer::New();
+  mLinearConstrainer.SetProperty( LinearConstrainer::Property::VALUE, pointsProperty );
+}
+
+ScrollViewPagePathEffect::~ScrollViewPagePathEffect()
+{
+}
+
+void ScrollViewPagePathEffect::ApplyToPage( Actor page, unsigned int pageOrder )
+{
+  float pageHalfSize = mPageSize.x * 0.5f;
+  Vector2 range = Vector2( pageHalfSize - (pageHalfSize*pageOrder),  -pageHalfSize - (pageHalfSize*pageOrder) );
+  Vector2 wrap  = Vector2( range.x, -pageHalfSize*(mPageCount-2) + range.y);
+
+  Toolkit::ScrollView scrollView = GetScrollView();
+
+  //Position
+  mPathConstrainer.Apply( Dali::Property( page, Dali::Actor::Property::POSITION ),
+                          Dali::Property( scrollView, mInputPropertyIndex),
+                          range, wrap
+                        );
+
+  //Rotation
+  mPathConstrainer.Apply( Dali::Property( page, Dali::Actor::Property::ORIENTATION ),
+                          Dali::Property( scrollView, mInputPropertyIndex ),
+                          range, wrap
+                        );
+
+  //Alpha
+  mLinearConstrainer.Apply( Dali::Property( page, Dali::Actor::Property::COLOR_ALPHA ),
+                            Dali::Property( scrollView, mInputPropertyIndex ),
+                            range, wrap
+                          );
+
+}
+
+void ScrollViewPagePathEffect::OnAttach(Toolkit::ScrollView& scrollView)
+{
+}
+
+void ScrollViewPagePathEffect::OnDetach(Toolkit::ScrollView& scrollView)
+{
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h
new file mode 100644 (file)
index 0000000..d6fcccd
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_PAGE_PATH_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_PAGE_PATH_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/linear-constrainer.h>
+#include <dali/devel-api/animation/path-constrainer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @copydoc Toolkit::ScrollViewPagePathEffect
+ */
+class ScrollViewPagePathEffect : public ScrollViewEffect
+{
+
+public:
+
+  /**
+   * Constructor
+   * @param[in] path Pages will follow this path
+   * @param[in] forward Vector in page local space which will be aligned with tangent of the path
+   * @param[in] inputPropertyIndex index of the property in the scrollview used to drivce the path
+   * @param[in] viewPageSize size of a page in the scrollview
+   * @param[in] pageCount total number of pages in the scrollview
+   */
+  ScrollViewPagePathEffect(Path path, const Vector3& forward, Dali::Property::Index inputPropertyIndex, const Vector3& viewPageSize, unsigned int pageCount );
+
+public:
+
+  /**
+   * @copydoc ScrollViewEffect::ApplyToActor
+   */
+  void ApplyToPage( Actor child, unsigned int pageOrder );
+
+public:
+
+  /**
+   * @copydoc ScrollViewEffect::OnAttach
+   */
+  virtual void OnAttach( Toolkit::ScrollView& scrollView );
+
+  /**
+   * @copydoc ScrollViewEffect::OnDetach
+   */
+  virtual void OnDetach( Toolkit::ScrollView& scrollView );
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ScrollViewPagePathEffect();
+
+private:
+
+  Vector3               mPageSize;            ///< The logical page size for the 3D effect.
+  PathConstrainer       mPathConstrainer;     ///< PathConstrainer used to constraint position and orientation
+  LinearConstrainer     mLinearConstrainer;   ///< LinearConstrainer used to constraint opacity
+  Dali::Property::Index mInputPropertyIndex;  ///< Index of the property in the scrollview used as the parameter for the path
+  unsigned int          mPageCount;           ///< Total number of pages (Needed for wrapping)
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::ScrollViewPagePathEffect& GetImpl(Dali::Toolkit::ScrollViewPagePathEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::RefObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::ScrollViewPagePathEffect&>(handle);
+}
+
+inline const Internal::ScrollViewPagePathEffect& GetImpl(const Dali::Toolkit::ScrollViewPagePathEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::RefObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::ScrollViewPagePathEffect&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_PAGE_PATH_EFFECT_H
diff --git a/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp b/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp
new file mode 100644 (file)
index 0000000..6cd2e67
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * 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 <cstring> // for strcmp
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  // empty handle as we cannot create Scrollable (but type registered for scroll signal)
+  return BaseHandle();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Scrollable, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootEffectColor",      VECTOR4, OVERSHOOT_EFFECT_COLOR    )
+DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootAnimationSpeed",   FLOAT,   OVERSHOOT_ANIMATION_SPEED )
+DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootEnabled",          BOOLEAN, OVERSHOOT_ENABLED )
+DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "overshootSize",             VECTOR2, OVERSHOOT_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scrollToAlphaFunction",     INTEGER, SCROLL_TO_ALPHA_FUNCTION )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scrollRelativePosition",   VECTOR2, SCROLL_RELATIVE_POSITION)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scrollPositionMin",        VECTOR2, SCROLL_POSITION_MIN)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, Scrollable, "scrollPositionMinX",    SCROLL_POSITION_MIN_X, SCROLL_POSITION_MIN, 0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, Scrollable, "scrollPositionMinY",    SCROLL_POSITION_MIN_Y, SCROLL_POSITION_MIN, 1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "scrollPositionMax",        VECTOR2, SCROLL_POSITION_MAX)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, Scrollable, "scrollPositionMaxX",    SCROLL_POSITION_MAX_X, SCROLL_POSITION_MAX, 0)
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, Scrollable, "scrollPositionMaxY",    SCROLL_POSITION_MAX_Y, SCROLL_POSITION_MAX, 1)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "canScrollVertical",        BOOLEAN, CAN_SCROLL_VERTICAL)
+DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, Scrollable, "canScrollHorizontal",      BOOLEAN, CAN_SCROLL_HORIZONTAL)
+
+DALI_SIGNAL_REGISTRATION(              Toolkit, Scrollable, "scrollStarted",                     SIGNAL_SCROLL_STARTED    )
+DALI_SIGNAL_REGISTRATION(              Toolkit, Scrollable, "scrollCompleted",                   SIGNAL_SCROLL_COMPLETED  )
+DALI_SIGNAL_REGISTRATION(              Toolkit, Scrollable, "scrollUpdated",                     SIGNAL_SCROLL_UPDATED    )
+
+DALI_TYPE_REGISTRATION_END()
+
+const Vector4 DEFAULT_OVERSHOOT_COLOUR(0.0f, 0.64f, 0.85f, 0.25f);
+const float DEFAULT_OVERSHOOT_ANIMATION_SPEED(120.0f); // 120 pixels per second
+const Vector2 OVERSHOOT_DEFAULT_SIZE( 720.0f, 42.0f );
+
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Scrollable
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Scrollable controls are not layout containers so they dont need size negotiation..
+// we dont want size negotiation while scrolling if we can avoid it
+Scrollable::Scrollable()
+: Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION ) ),
+  mOvershootEffectColor(  DEFAULT_OVERSHOOT_COLOUR ),
+  mOvershootAnimationSpeed ( DEFAULT_OVERSHOOT_ANIMATION_SPEED ),
+  mOvershootSize( OVERSHOOT_DEFAULT_SIZE ),
+  mScrollToAlphaFunction( AlphaFunction::EASE_OUT ),
+  mScrollStartedSignal(),
+  mScrollUpdatedSignal(),
+  mScrollCompletedSignal(),
+  mOvershootEnabled(true)
+{
+}
+
+Scrollable::Scrollable( ControlBehaviour behaviourFlags )
+: Control( ControlBehaviour( behaviourFlags ) ),
+  mOvershootEffectColor(  DEFAULT_OVERSHOOT_COLOUR ),
+  mOvershootAnimationSpeed ( DEFAULT_OVERSHOOT_ANIMATION_SPEED ),
+  mOvershootSize( OVERSHOOT_DEFAULT_SIZE ),
+  mScrollToAlphaFunction( AlphaFunction::EASE_OUT ),
+  mScrollStartedSignal(),
+  mScrollUpdatedSignal(),
+  mScrollCompletedSignal(),
+  mOvershootEnabled(true)
+{
+}
+
+Scrollable::~Scrollable()
+{
+}
+
+bool Scrollable::IsOvershootEnabled() const
+{
+  return mOvershootEnabled;
+}
+
+void Scrollable::SetOvershootEnabled(bool enable)
+{
+  EnableScrollOvershoot(enable);
+  mOvershootEnabled = enable;
+}
+
+Vector4 Scrollable::GetOvershootEffectColor() const
+{
+  return mOvershootEffectColor;
+};
+
+void Scrollable::SetOvershootAnimationSpeed( float pixelsPerSecond )
+{
+  mOvershootAnimationSpeed = pixelsPerSecond;
+}
+
+float Scrollable::GetOvershootAnimationSpeed() const
+{
+  return mOvershootAnimationSpeed;
+};
+
+const Vector2& Scrollable::GetOvershootSize() const
+{
+  return mOvershootSize;
+}
+
+Toolkit::Scrollable::ScrollStartedSignalType& Scrollable::ScrollStartedSignal()
+{
+  return mScrollStartedSignal;
+}
+
+Toolkit::Scrollable::ScrollUpdatedSignalType& Scrollable::ScrollUpdatedSignal()
+{
+  return mScrollUpdatedSignal;
+}
+
+Toolkit::Scrollable::ScrollCompletedSignalType& Scrollable::ScrollCompletedSignal()
+{
+  return mScrollCompletedSignal;
+}
+
+bool Scrollable::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::Scrollable scrollable = Toolkit::Scrollable::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_SCROLL_STARTED ) )
+  {
+    scrollable.ScrollStartedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_SCROLL_UPDATED ) )
+  {
+    scrollable.ScrollUpdatedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_SCROLL_COMPLETED ) )
+  {
+    scrollable.ScrollCompletedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void Scrollable::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::Scrollable scrollable = Toolkit::Scrollable::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollable )
+  {
+    Scrollable& scrollableImpl( GetImpl( scrollable ) );
+    switch( index )
+    {
+      case Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR:
+      {
+        scrollableImpl.SetOvershootEffectColor( value.Get<Vector4>() );
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED:
+      {
+        scrollableImpl.SetOvershootAnimationSpeed( value.Get<float>() );
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_ENABLED:
+      {
+        scrollableImpl.SetOvershootEnabled( value.Get<bool>() );
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_SIZE:
+      {
+        scrollableImpl.SetOvershootSize( value.Get<Vector2>() );
+        break;
+      }
+      case Toolkit::Scrollable::Property::SCROLL_TO_ALPHA_FUNCTION:
+      {
+        int alphaFunction = value.Get<int>();
+
+        if( alphaFunction >= AlphaFunction::DEFAULT &&
+            alphaFunction <  AlphaFunction::COUNT )
+        {
+          scrollableImpl.mScrollToAlphaFunction = static_cast< AlphaFunction::BuiltinFunction >( alphaFunction );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Scrollable::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::Scrollable scrollable = Toolkit::Scrollable::DownCast( Dali::BaseHandle( object ) );
+
+  if( scrollable )
+  {
+    Scrollable& scrollableImpl( GetImpl( scrollable ) );
+    switch( index )
+    {
+      case Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR:
+      {
+        value = scrollableImpl.GetOvershootEffectColor();
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_ANIMATION_SPEED:
+      {
+        value = scrollableImpl.GetOvershootAnimationSpeed();
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_ENABLED:
+      {
+        value = scrollableImpl.IsOvershootEnabled();
+        break;
+      }
+      case Toolkit::Scrollable::Property::OVERSHOOT_SIZE:
+      {
+        value = scrollableImpl.mOvershootSize;
+        break;
+      }
+      case Toolkit::Scrollable::Property::SCROLL_TO_ALPHA_FUNCTION:
+      {
+        value = static_cast<int>( scrollableImpl.mScrollToAlphaFunction );
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/scrollable/scrollable-impl.h b/dali-toolkit/internal/controls/scrollable/scrollable-impl.h
new file mode 100644 (file)
index 0000000..9ffdc8e
--- /dev/null
@@ -0,0 +1,255 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLLABLE_H
+#define DALI_TOOLKIT_INTERNAL_SCROLLABLE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/alpha-function.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Scrollable;
+typedef IntrusivePtr<Scrollable> ScrollablePtr;
+
+/**
+ * @copydoc Toolkit::Scrollable
+ */
+class Scrollable : public Control
+{
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::IsOvershootEnabled
+   */
+  bool IsOvershootEnabled() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::SetOvershootEnabled
+   */
+  void SetOvershootEnabled(bool enable);
+
+  /**
+   * Adds actor as an Overlay to Scrollable
+   * This method is called by Add-on UI components
+   * such as scroll bars, page indicators.
+   * @param[in] actor Actor to add as an overlay.
+   */
+  virtual void AddOverlay(Actor actor) = 0;
+
+  /**
+   * Removes overlay actor from Scrollable
+   * This method is called by Add-on UI components
+   * such as scroll bars, page indicators.
+   * @param[in] actor Actor overlay to remove.
+   */
+  virtual void RemoveOverlay(Actor actor) = 0;
+
+  /**
+   * Retrieves current scroll position.
+   * @returns The current scroll position.
+   */
+  virtual Vector2 GetCurrentScrollPosition() const = 0;
+
+  /**
+   * Scrolls Scrollable to position specified (contents will scroll to this position)
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * @param[in] position The position to scroll to.
+   * @param[in] duration The duration of the animation in seconds
+   */
+  virtual void ScrollTo(const Vector2 &position, float duration) = 0;
+
+  /**
+   * Set the color of the overshoot effect.
+   * @parm[in] color The color of the overshoot effect
+   */
+  virtual void SetOvershootEffectColor( const Vector4& color ) = 0;
+
+  /**
+   * Retrieve the color of the overshoot effect.
+   * @return The color of the overshoot effect.
+   */
+  Vector4 GetOvershootEffectColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::SetOvershootAnimationSpeed(float pixelsPerSecond)
+   */
+  void SetOvershootAnimationSpeed( float pixelsPerSecond );
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::GetOvershootAnimationSpeed()
+   */
+  float GetOvershootAnimationSpeed() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::GetOvershootSize()
+   */
+  const Vector2& GetOvershootSize() const;
+
+  /**
+   * Set the size of the overshoot effect.
+   * @parm[in] size The size of the overshoot effect
+   */
+  virtual void SetOvershootSize( const Vector2& size ) = 0;
+
+private:
+
+  /**
+   * Temporary function to override EnableScrollOvershoot functionality for overshoot
+   * Only ScrollView needs to override this as HQ has not requested disable functionality in ItemView
+   * @param[in] enable true to enable, false to disable overshoot indicator
+   */
+  virtual void EnableScrollOvershoot(bool enable) {}
+
+public: //Signals
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::ScrollStartedSignal()
+   */
+  Toolkit::Scrollable::ScrollStartedSignalType& ScrollStartedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::ScrollUpdatedSignal()
+   */
+  Toolkit::Scrollable::ScrollUpdatedSignalType& ScrollUpdatedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Scrollable::ScrollCompletedSignal()
+   */
+  Toolkit::Scrollable::ScrollCompletedSignalType& ScrollCompletedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  //properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+protected:
+
+  /**
+   * Construct a new Scrollable.
+   */
+  Scrollable();
+
+  /**
+   * @brief Construct a new Scrollable.
+   *
+   * @param[in] behaviourFlags Flags to enable
+   */
+  Scrollable( ControlBehaviour behaviourFlags );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Scrollable();
+
+private:
+
+  /**
+   * Gets position property.
+   *
+   * @return The current position
+   */
+  Vector2 GetPropertyPosition() const;
+
+private:
+
+  // Undefined
+  Scrollable(const Scrollable&);
+
+  // Undefined
+  Scrollable& operator=(const Scrollable& rhs);
+
+protected:
+
+  Vector4         mOvershootEffectColor;    ///<The color of the overshoot bouncing effect
+  float           mOvershootAnimationSpeed; ///<The speed of the overshoot animation (pixels per second)
+  Vector2         mOvershootSize;           ///<The size of the overshoot effect
+
+  Dali::AlphaFunction::BuiltinFunction mScrollToAlphaFunction; ///< The ScrollTo() animations use this
+
+  Toolkit::Scrollable::ScrollStartedSignalType mScrollStartedSignal;
+  Toolkit::Scrollable::ScrollUpdatedSignalType mScrollUpdatedSignal;
+  Toolkit::Scrollable::ScrollCompletedSignalType mScrollCompletedSignal;
+
+private:
+
+  bool mOvershootEnabled:1;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Scrollable& GetImpl(Toolkit::Scrollable& scrollable)
+{
+  DALI_ASSERT_ALWAYS(scrollable);
+
+  Dali::RefObject& handle = scrollable.GetImplementation();
+
+  return static_cast<Toolkit::Internal::Scrollable&>(handle);
+}
+
+inline const Toolkit::Internal::Scrollable& GetImpl(const Toolkit::Scrollable& scrollable)
+{
+  DALI_ASSERT_ALWAYS(scrollable);
+
+  const Dali::RefObject& handle = scrollable.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::Scrollable&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLLABLE_H
diff --git a/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp b/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp
new file mode 100644 (file)
index 0000000..0233991
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2017 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 "shadow-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+#include <dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h>
+#include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
+
+// TODO:
+// pixel format / size - set from JSON
+// aspect ratio property needs to be able to be constrained also for cameras. (now do-able)
+// default near clip value
+
+
+/////////////////////////////////////////////////////////
+// IMPLEMENTATION NOTES
+
+// As the ShadowView actor changes size, the amount of pixels we need to blur changes. Therefore we need some way of doing this. However:-
+// OnSetSize() does not get called when ShadowView object size is modified using a Constraint.
+// OnSizeAnimation() only gets called once per AnimateTo/By() and if an Animation has N such calls then only the final one will end up being used. Therefore we can't use
+// OnSizeAnimation() to alter render target sizes.
+// To get around the above problems, we use fixed sized render targets, from the last SetSize() call (which calls OnSetSize()), then we adjust the internal cameras / actors
+// to take account of the changed ShadowView object size, projecting to the unchanged render target sizes. This is done relative to the fixed render target / actor sizes
+// by using constraints relative to the ShadowView actor size.
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+using namespace Dali;
+
+BaseHandle Create()
+{
+  return Toolkit::ShadowView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ShadowView, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+const float BLUR_STRENGTH_DEFAULT = 1.0f;
+
+const Vector3 DEFAULT_LIGHT_POSITION(300.0f, 250.0f, 600.0f);
+const float DEFAULT_FIELD_OF_VIEW_RADIANS = Math::PI / 4.0f; // 45 degrees
+
+const Vector4 DEFAULT_SHADOW_COLOR = Vector4(0.2f, 0.2f, 0.2f, 0.8f);
+
+const char* const SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME = "uLightCameraProjectionMatrix";
+const char* const SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME = "uLightCameraViewMatrix";
+const char* const SHADER_SHADOW_COLOR_PROPERTY_NAME = "uShadowColor";
+const char* const BLUR_STRENGTH_PROPERTY_NAME = "BlurStrengthProperty";
+const char* const SHADOW_COLOR_PROPERTY_NAME = "ShadowColorProperty";
+
+const char* const RENDER_SHADOW_VERTEX_SOURCE =
+
+  " attribute mediump vec2 aPosition;\n"
+  " uniform mediump mat4 uMvpMatrix;\n"
+  " uniform mediump mat4 uModelMatrix;\n"
+  " uniform vec3 uSize;\n"
+  " varying vec2 vTexCoord;\n"
+
+  " uniform mediump mat4 uLightCameraProjectionMatrix;\n"
+  " uniform mediump mat4 uLightCameraViewMatrix;\n"
+  "\n"
+  "void main()\n"
+  "{\n"
+    "  mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n"
+    "  vertexPosition.xyz *= uSize;\n"
+    "  gl_Position = uMvpMatrix * vertexPosition;\n"
+    "  vec4 textureCoords = uLightCameraProjectionMatrix * uLightCameraViewMatrix * uModelMatrix  * vertexPosition;\n"
+    "  vTexCoord = 0.5 + 0.5 * (textureCoords.xy/textureCoords.w);\n"
+  "}\n";
+
+const char* const RENDER_SHADOW_FRAGMENT_SOURCE =
+  "varying mediump vec2 vTexCoord;\n"
+  "uniform lowp vec4 uShadowColor;\n"
+  "uniform sampler2D sTexture;\n"
+
+  "void main()\n"
+  "{\n"
+  "  lowp float alpha;\n"
+  "  alpha = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y)).a;\n"
+  "  gl_FragColor = vec4(uShadowColor.rgb, uShadowColor.a * alpha);\n"
+  "}\n";
+
+} // namespace
+
+ShadowView::ShadowView( float downsampleWidthScale, float downsampleHeightScale )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mChildrenRoot(Actor::New()),
+  mCachedShadowColor(DEFAULT_SHADOW_COLOR),
+  mCachedBackgroundColor(DEFAULT_SHADOW_COLOR.r, DEFAULT_SHADOW_COLOR.g, DEFAULT_SHADOW_COLOR.b, 0.0f),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mShadowColorPropertyIndex(Property::INVALID_INDEX),
+  mDownsampleWidthScale(downsampleWidthScale),
+  mDownsampleHeightScale(downsampleHeightScale)
+{
+}
+
+ShadowView::~ShadowView()
+{
+}
+
+Toolkit::ShadowView ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
+{
+  ShadowView* impl = new ShadowView(downsampleWidthScale, downsampleHeightScale);
+
+  Dali::Toolkit::ShadowView handle = Dali::Toolkit::ShadowView( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
+{
+  mShadowPlaneBg = shadowPlaneBackground;
+
+  mShadowPlane = Actor::New();
+  mShadowPlane.SetName( "SHADOW_PLANE" );
+  mShadowPlane.SetParentOrigin( ParentOrigin::CENTER );
+  mShadowPlane.SetAnchorPoint( AnchorPoint::CENTER );
+  Renderer shadowRenderer = CreateRenderer( RENDER_SHADOW_VERTEX_SOURCE, RENDER_SHADOW_FRAGMENT_SOURCE, Shader::Hint::OUTPUT_IS_TRANSPARENT, Uint16Pair(20,20) );
+  TextureSet textureSet = shadowRenderer.GetTextures();
+  textureSet.SetTexture( 0u, mOutputFrameBuffer.GetColorTexture() );
+  mShadowPlane.AddRenderer( shadowRenderer );
+
+  SetShaderConstants();
+
+  // Rather than parent the shadow plane drawable and have constraints to move it to the same
+  // position, instead parent the shadow plane drawable on the shadow plane passed in.
+  mShadowPlaneBg.Add( mShadowPlane );
+  mShadowPlane.SetParentOrigin( ParentOrigin::CENTER );
+  mShadowPlane.SetZ( 1.0f );
+
+  ConstrainCamera();
+
+  mShadowPlane.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  mBlurRootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+}
+
+void ShadowView::SetPointLight(Actor pointLight)
+{
+  mPointLight = pointLight;
+
+  ConstrainCamera();
+}
+
+void ShadowView::SetPointLightFieldOfView(float fieldOfView)
+{
+  mCameraActor.SetFieldOfView(fieldOfView);
+}
+
+void ShadowView::SetShadowColor(Vector4 color)
+{
+  mCachedShadowColor = color;
+  mCachedBackgroundColor.r = color.r;
+  mCachedBackgroundColor.g = color.g;
+  mCachedBackgroundColor.b = color.b;
+
+  if( mShadowPlane )
+  {
+    mShadowPlane.SetProperty( mShadowColorPropertyIndex, mCachedShadowColor );
+  }
+  if(mRenderSceneTask)
+  {
+    mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
+  }
+}
+
+void ShadowView::Activate()
+{
+  DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Activate()\n" );
+
+  // make sure resources are allocated and start the render tasks processing
+  CreateRenderTasks();
+}
+
+void ShadowView::Deactivate()
+{
+  DALI_ASSERT_ALWAYS( Self().OnStage() && "ShadowView should be on stage before calling Deactivate()\n" )
+
+  // stop render tasks processing
+  // Note: render target resources are automatically freed since we set the Image::Unused flag
+  RemoveRenderTasks();
+}
+
+///////////////////////////////////////////////////////////
+//
+// Private methods
+//
+
+void ShadowView::OnInitialize()
+{
+  // root actor to parent all user added actors. Used as source actor for shadow render task.
+  mChildrenRoot.SetParentOrigin( ParentOrigin::CENTER );
+  mChildrenRoot.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  Vector2 stageSize = Stage::GetCurrent().GetSize();
+  mCameraActor = CameraActor::New(stageSize);
+
+  mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
+
+  // Target is constrained to point at the shadow plane origin
+  mCameraActor.SetNearClippingPlane( 1.0f );
+  mCameraActor.SetType( Dali::Camera::FREE_LOOK ); // Camera orientation constrained to point at shadow plane world position
+  mCameraActor.SetOrientation(Radian(Degree(180)), Vector3::YAXIS);
+  mCameraActor.SetPosition(DEFAULT_LIGHT_POSITION);
+
+  // Create render targets needed for rendering from light's point of view
+  mSceneFromLightRenderTarget = FrameBuffer::New( stageSize.width, stageSize.height, FrameBuffer::Attachment::NONE );
+  Texture textureFromLight = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width), unsigned(stageSize.height) );
+  mSceneFromLightRenderTarget.AttachColorTexture( textureFromLight );
+
+  mOutputFrameBuffer = FrameBuffer::New( stageSize.width * 0.5f, stageSize.height * 0.5f, FrameBuffer::Attachment::NONE );
+  Texture outputTexture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(stageSize.width * 0.5f), unsigned(stageSize.height * 0.5f) );
+  mOutputFrameBuffer.AttachColorTexture( outputTexture );
+
+  //////////////////////////////////////////////////////
+  // Connect to actor tree
+
+  Self().Add( mChildrenRoot );
+  Stage::GetCurrent().Add( mCameraActor );
+
+  mBlurFilter.SetRefreshOnDemand( false );
+  mBlurFilter.SetInputTexture( mSceneFromLightRenderTarget.GetColorTexture() );
+  mBlurFilter.SetOutputFrameBuffer( mOutputFrameBuffer );
+  mBlurFilter.SetSize( stageSize * 0.5f );
+  mBlurFilter.SetPixelFormat( Pixel::RGBA8888 );
+
+  mBlurRootActor = Actor::New();
+  mBlurRootActor.SetName( "BLUR_ROOT_ACTOR" );
+
+  // 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 );
+
+  Self().Add( mBlurRootActor );
+
+  mBlurFilter.SetRootActor(mBlurRootActor);
+  mBlurFilter.SetBackgroundColor(Vector4::ZERO);
+
+  CustomActor self = Self();
+  // Register a property that the user can use to control the blur in the internal object
+  mBlurStrengthPropertyIndex = self.RegisterProperty(BLUR_STRENGTH_PROPERTY_NAME, BLUR_STRENGTH_DEFAULT);
+
+  Constraint blurStrengthConstraint = Constraint::New<float>( mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint() );
+  blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) );
+  blurStrengthConstraint.Apply();
+}
+
+void ShadowView::OnChildAdd( Actor& child )
+{
+  if( child != mChildrenRoot && child != mBlurRootActor)
+  {
+    mChildrenRoot.Add( child );
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void ShadowView::OnChildRemove( Actor& child )
+{
+  mChildrenRoot.Remove( child );
+
+  Control::OnChildRemove( child );
+}
+
+void ShadowView::ConstrainCamera()
+{
+  if( mPointLight && mShadowPlane )
+  {
+    // Constrain camera to look directly at center of shadow plane. (mPointLight position
+    // is under control of application, can't use transform inheritance)
+
+    Constraint cameraOrientationConstraint = Constraint::New<Quaternion> ( mCameraActor, Actor::Property::ORIENTATION, &LookAt );
+    cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_POSITION ) );
+    cameraOrientationConstraint.AddSource( Source( mPointLight,  Actor::Property::WORLD_POSITION ) );
+    cameraOrientationConstraint.AddSource( Source( mShadowPlane, Actor::Property::WORLD_ORIENTATION ) );
+    cameraOrientationConstraint.Apply();
+
+    Constraint pointLightPositionConstraint = Constraint::New<Vector3>( mCameraActor, Actor::Property::POSITION, EqualToConstraint() );
+    pointLightPositionConstraint.AddSource( Source( mPointLight, Actor::Property::WORLD_POSITION ) );
+    pointLightPositionConstraint.Apply();
+  }
+}
+
+void ShadowView::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // We want the first task to render the scene from the light
+  mRenderSceneTask = taskList.CreateTask();
+
+  mRenderSceneTask.SetCameraActor( mCameraActor );
+  mRenderSceneTask.SetSourceActor( mChildrenRoot );
+  mRenderSceneTask.SetFrameBuffer( mSceneFromLightRenderTarget );
+  mRenderSceneTask.SetInputEnabled( false );
+  mRenderSceneTask.SetClearEnabled( true );
+
+  // background color for render task should be the shadow color, but with alpha 0
+  // we don't want to blend the edges of the content with a BLACK at alpha 0, but
+  // the same shadow color at alpha 0.
+  mRenderSceneTask.SetClearColor( mCachedBackgroundColor );
+
+  mBlurFilter.Enable();
+}
+
+void ShadowView::RemoveRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  taskList.RemoveTask(mRenderSceneTask);
+  mRenderSceneTask.Reset();
+
+  mBlurFilter.Disable();
+}
+
+void ShadowView::SetShaderConstants()
+{
+  Property::Index lightCameraProjectionMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_PROJECTION_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
+  Constraint projectionMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraProjectionMatrixPropertyIndex, EqualToConstraint() );
+  projectionMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::PROJECTION_MATRIX ) );
+  projectionMatrixConstraint.Apply();
+
+  Property::Index lightCameraViewMatrixPropertyIndex = mShadowPlane.RegisterProperty( SHADER_LIGHT_CAMERA_VIEW_MATRIX_PROPERTY_NAME, Matrix::IDENTITY );
+  Constraint viewMatrixConstraint = Constraint::New<Dali::Matrix>( mShadowPlane, lightCameraViewMatrixPropertyIndex, EqualToConstraint() );
+  viewMatrixConstraint.AddSource( Source( mCameraActor, CameraActor::Property::VIEW_MATRIX ) );
+  viewMatrixConstraint.Apply();
+
+  mShadowColorPropertyIndex = mShadowPlane.RegisterProperty( SHADER_SHADOW_COLOR_PROPERTY_NAME, mCachedShadowColor );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h b/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.h
new file mode 100644 (file)
index 0000000..1cc97ca
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SHADOW_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_SHADOW_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <sstream>
+#include <cmath>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/shadow-view/shadow-view.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/filters/blur-two-pass-filter.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class ShadowView;
+
+namespace Internal
+{
+
+/**
+ * ShadowView implementation class
+ */
+class ShadowView : public Control
+{
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::ShadowView
+   */
+  ShadowView();
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::ShadowView
+   */
+  ShadowView(float downsampleWidthScale, float downsampleHeightScale);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::~ShadowView
+   */
+  virtual ~ShadowView();
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::New(float downsampleWidthScale, float downsampleHeightScale)
+   */
+  static Dali::Toolkit::ShadowView New(float downsampleWidthScale, float downsampleHeightScale);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::SetShadowPlaneBackground(Actor shadowPlaneBackground)
+   */
+  void SetShadowPlaneBackground(Actor shadowPlaneBackground);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::SetPointLight(Actor pointLight)
+   */
+  void SetPointLight(Actor pointLight);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::SetPointLightFieldOfView(float fieldOfView)
+   */
+  void SetPointLightFieldOfView(float fieldOfView);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::SetShadowColor(Vector4 color)
+   */
+  void SetShadowColor(Vector4 color);
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::Activate()
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::Deactivate()
+   */
+  void Deactivate();
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::GetBlurStrengthPropertyIndex()
+   */
+  Property::Index GetBlurStrengthPropertyIndex() const {return mBlurStrengthPropertyIndex;}
+
+  /**
+   * @copydoc Dali::Toolkit::ShadowView::GetShadowColorPropertyIndex()
+   */
+  Property::Index GetShadowColorPropertyIndex() const {return mShadowColorPropertyIndex;}
+
+  void SetShaderConstants();
+
+private:
+
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Control::OnChildAdd()
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnChildRemove()
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  /**
+   * Constrain the camera actor to the position of the point light, pointing
+   * at the center of the shadow plane.
+   */
+  void ConstrainCamera();
+
+  void CreateRenderTasks();
+  void RemoveRenderTasks();
+  void CreateBlurFilter();
+
+private:
+  Actor mShadowPlane; // Shadow renders into this actor
+  Actor mShadowPlaneBg; // mShadowPlane renders directly in front of this actor
+  Actor mPointLight;  // Shadow is cast from this point light
+
+  /////////////////////////////////////////////////////////////
+  FrameBuffer mSceneFromLightRenderTarget;  // for rendering normal scene seen from light to texture instead of the screen
+
+  FrameBuffer mOutputFrameBuffer;
+
+  Actor mChildrenRoot; // Subtree for all user added child actors that should be rendered normally
+  Actor mBlurRootActor; // Root actor for blur filter processing
+  RenderTask mRenderSceneTask;
+
+  CameraActor mCameraActor; // Constrained to same position as mPointLight and pointing at mShadowPlane
+
+  Property::Map mShadowVisualMap;
+  BlurTwoPassFilter mBlurFilter;
+
+  Vector4 mCachedShadowColor;                               ///< Cached Shadow color.
+  Vector4 mCachedBackgroundColor;                           ///< Cached Shadow background color (same as shadow color but with alpha at 0.0)
+
+  /////////////////////////////////////////////////////////////
+  // Properties that can be animated
+  Property::Index mBlurStrengthPropertyIndex;
+  Property::Index mShadowColorPropertyIndex;
+  float mDownsampleWidthScale;
+  float mDownsampleHeightScale;
+
+private:
+
+  // Undefined copy constructor.
+  ShadowView( const ShadowView& );
+
+  // Undefined assignment operator.
+  ShadowView& operator=( const ShadowView& );
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::ShadowView& GetImpl( Toolkit::ShadowView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::ShadowView&>(handle);
+}
+
+inline const Toolkit::Internal::ShadowView& GetImpl( const Toolkit::ShadowView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::ShadowView&>(handle);
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SHADOW_VIEW_H
diff --git a/dali-toolkit/internal/controls/slider/slider-impl.cpp b/dali-toolkit/internal/controls/slider/slider-impl.cpp
new file mode 100755 (executable)
index 0000000..419d222
--- /dev/null
@@ -0,0 +1,1416 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/slider/slider-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <sstream>
+#include <limits>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // Unnamed namespace
+{
+
+BaseHandle Create()
+{
+  return Dali::Toolkit::Slider::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Slider, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "lowerBound",             FLOAT,    LOWER_BOUND            )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "upperBound",             FLOAT,    UPPER_BOUND            )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "value",                  FLOAT,    VALUE                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "trackVisual",            MAP,      TRACK_VISUAL           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "handleVisual",           MAP,      HANDLE_VISUAL          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "progressVisual",         MAP,      PROGRESS_VISUAL        )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popupVisual",            MAP,      POPUP_VISUAL           )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "popupArrowVisual",       MAP,      POPUP_ARROW_VISUAL     )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "disabledColor",          VECTOR4,  DISABLED_COLOR         )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "valuePrecision",         INTEGER,  VALUE_PRECISION        )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "showPopup",              BOOLEAN,  SHOW_POPUP             )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "showValue",              BOOLEAN,  SHOW_VALUE             )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "marks",                  ARRAY,    MARKS                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "snapToMarks",            BOOLEAN,  SNAP_TO_MARKS          )
+DALI_PROPERTY_REGISTRATION( Toolkit, Slider, "markTolerance",          FLOAT,    MARK_TOLERANCE         )
+
+DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "valueChanged",                     SIGNAL_VALUE_CHANGED   )
+DALI_SIGNAL_REGISTRATION(   Toolkit, Slider, "mark",                             SIGNAL_MARK            )
+
+DALI_TYPE_REGISTRATION_END()
+
+const float MARK_SNAP_TOLERANCE = 0.05f; // 5% of slider width
+
+const int VALUE_VIEW_SHOW_DURATION = 1000;  // millisec
+const int VALUE_VIEW_SHOW_DURATION_LONG = 2000;  // millisec
+
+const float VALUE_VERTICAL_OFFSET = 48.0f;
+
+const float DEFAULT_WIDTH = 0.0f;
+const float DEFAULT_HEIGHT = 27.0f;
+const float DEFAULT_HIT_HEIGHT = 72.0f;
+const float DEFAULT_HANDLE_HEIGHT = DEFAULT_HIT_HEIGHT;
+const float POPUP_TEXT_PADDING = 10.0f;
+
+const char* SKINNED_TRACK_VISUAL_FILE_NAME = "slider-skin.9.png";
+const char* SKINNED_HANDLE_VISUAL_FILE_NAME = "slider-skin-handle.png";
+const char* SKINNED_PROGRESS_VISUAL_FILE_NAME = "slider-skin-progress.9.png";
+const char* SKINNED_POPUP_VISUAL_FILE_NAME = "slider-popup.9.png";
+const char* SKINNED_POPUP_ARROW_VISUAL_FILE_NAME = "slider-popup-arrow.png";
+
+const Vector2 DEFAULT_HIT_REGION( DEFAULT_WIDTH, DEFAULT_HIT_HEIGHT );
+const Vector2 DEFAULT_TRACK_REGION( DEFAULT_WIDTH, DEFAULT_HEIGHT );
+const Vector2 DEFAULT_HANDLE_SIZE( DEFAULT_HANDLE_HEIGHT, DEFAULT_HANDLE_HEIGHT );
+
+const Vector4 DEFAULT_DISABLED_COLOR( 0.5f, 0.5f, 0.5f, 1.0f );
+
+const float VALUE_POPUP_MARGIN = 10.0f;
+const float VALUE_POPUP_HEIGHT = 81.0f;
+const float VALUE_POPUP_MIN_WIDTH = 54.0f;
+
+const float DEFAULT_LOWER_BOUND = 0.0f;
+const float DEFAULT_UPPER_BOUND = 1.0f;
+const float DEFAULT_VALUE = 0.0f;
+const int DEFAULT_VALUE_PRECISION = 0;
+const bool DEFAULT_SHOW_POPUP = false;
+const bool DEFAULT_SHOW_VALUE = true;
+const bool DEFAULT_ENABLED = true;
+const bool DEFAULT_SNAP_TO_MARKS = false;
+
+} // Unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Slider
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Dali::Toolkit::Slider Slider::New()
+{
+  // Create the implementation
+  SliderPtr slider( new Slider() );
+
+  // Pass ownership to CustomActor via derived handle
+  Dali::Toolkit::Slider handle( *slider );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  slider->Initialize();
+
+  return handle;
+}
+
+Slider::Slider()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mState( NORMAL ),
+  mPopupVisual(""),
+  mPopupArrowVisual(""),
+  mTrackVisual(""),
+  mHandleVisual(""),
+  mProgressVisual(""),
+  mPopupMap(),
+  mTrackMap(),
+  mHandleMap(),
+  mPopupArrowMap(),
+  mDisabledColor( 0.0f, 0.0f, 0.0f, 0.0f ),
+  mHitRegion( 0.0f, 0.0f ),
+  mTrackRegion( 0.0f, 0.0f ),
+  mHandleSize( 0.0f, 0.0f ),
+  mLowerBound( 0.0f ),
+  mUpperBound( 0.0f ),
+  mValue( 0.0f ),
+  mMarkTolerance( 0.0f ),
+  mValuePrecision( 0 ),
+  mShowPopup( false ),
+  mShowValue( false ),
+  mSnapToMarks( false )
+{
+}
+
+Slider::~Slider()
+{
+}
+
+void Slider::OnInitialize()
+{
+  // Setup
+  CreateChildren();
+
+  // Properties
+  Actor self = Self();
+
+  SetHitRegion(     DEFAULT_HIT_REGION     );
+  SetTrackRegion(   DEFAULT_TRACK_REGION   );
+  SetHandleSize(    DEFAULT_HANDLE_SIZE    );
+
+  const std::string imageDirPath = AssetManager::GetDaliImagePath();
+  SetTrackVisual(            imageDirPath + SKINNED_TRACK_VISUAL_FILE_NAME             );
+  SetHandleVisual(           imageDirPath + SKINNED_HANDLE_VISUAL_FILE_NAME            );
+  SetProgressVisual(         imageDirPath + SKINNED_PROGRESS_VISUAL_FILE_NAME          );
+  SetPopupVisual(            imageDirPath + SKINNED_POPUP_VISUAL_FILE_NAME             );
+  SetPopupArrowVisual(       imageDirPath + SKINNED_POPUP_ARROW_VISUAL_FILE_NAME       );
+
+  SetShowPopup( DEFAULT_SHOW_POPUP );
+  SetShowValue( DEFAULT_SHOW_VALUE );
+
+  SetEnabled( DEFAULT_ENABLED );
+  SetDisabledColor( DEFAULT_DISABLED_COLOR );
+
+  SetSnapToMarks( DEFAULT_SNAP_TO_MARKS );
+  SetMarkTolerance( MARK_SNAP_TOLERANCE );
+
+  SetLowerBound( DEFAULT_LOWER_BOUND );
+  SetUpperBound( DEFAULT_UPPER_BOUND );
+  UpdateSkin();
+  SetValuePrecision( DEFAULT_VALUE_PRECISION );
+  mValue = DEFAULT_VALUE;
+  DisplayValue( mValue, false );       // Run this last to display the correct value
+
+  // Size the Slider actor to a default
+  self.SetSize( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y );
+
+  // Connect to the touch signal
+  self.TouchSignal().Connect( this, &Slider::OnTouch );
+}
+
+void Slider::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  SetHitRegion( Vector2( size.x, GetHitRegion().y ) );
+  // Factor in handle overshoot into size of backing
+  SetTrackRegion( Vector2( size.x - GetHandleSize().x, GetTrackRegion().y ) );
+  Control::OnRelayout( size, container );
+}
+
+bool Slider::OnTouch(Actor actor, const TouchData& touch)
+{
+  if( mState != DISABLED )
+  {
+    const PointState::Type touchState = touch.GetState(0);
+
+    if( touchState == PointState::DOWN )
+    {
+      mState = PRESSED;
+
+      float percentage = MapPercentage( touch.GetLocalPosition( 0 ) );
+      float value = MapBounds( ( GetSnapToMarks() ) ? SnapToMark( percentage ) : MarkFilter( percentage ), GetLowerBound(), GetUpperBound() );
+      SetValue( value );
+      DisplayPopup( value );
+    }
+    else if( touchState == PointState::UP )
+    {
+      if( mState == PRESSED )
+      {
+        mState = NORMAL;
+        mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
+      }
+    }
+  }
+
+  return true;
+}
+
+void Slider::OnPan( Actor actor, const PanGesture& gesture )
+{
+  // gesture.position is in local actor coordinates
+  if( mState != DISABLED )
+  {
+    switch( gesture.state )
+    {
+      case Gesture::Continuing:
+      {
+        if( mState == PRESSED )
+        {
+          float value = MapBounds( MarkFilter ( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
+          SetValue( value );
+          DisplayPopup( value );
+        }
+        break;
+      }
+      case Gesture::Finished:
+      {
+        if( mState == PRESSED  )
+        {
+          if( GetSnapToMarks() )
+          {
+            float value = MapBounds( SnapToMark( MapPercentage( gesture.position ) ), GetLowerBound(), GetUpperBound() );
+            SetValue( value );
+            DisplayPopup( value );
+          }
+          mSlidingFinishedSignal.Emit( Toolkit::Slider::DownCast( Self() ), GetValue() );
+        }
+
+        mState = NORMAL;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+float Slider::HitSpaceToDomain( float x )
+{
+  float halfRegionWidth = GetHitRegion().x * 0.5f;
+  float halfDomainWidth = ( mDomain.to.x - mDomain.from.x ) * 0.5f;
+  float endDiff = halfRegionWidth - halfDomainWidth;
+
+  return x - endDiff;
+}
+
+float Slider::MapPercentage( const Vector2& point )
+{
+  return Clamp( ( HitSpaceToDomain( point.x ) - mDomain.from.x ) / ( mDomain.to.x - mDomain.from.x ), 0.0f, 1.0f );
+}
+
+float Slider::MapValuePercentage( float value )
+{
+  return ( value - GetLowerBound() ) / ( GetUpperBound() - GetLowerBound() );
+}
+
+float Slider::MapBounds( float percent, float lowerBound, float upperBound )
+{
+  return lowerBound + percent * ( upperBound - lowerBound );
+}
+
+Slider::Domain Slider::CalcDomain( const Vector2& currentSize )
+{
+   return Domain( Vector2( 0.0f, 0.0f ), currentSize );
+}
+
+void Slider::DisplayValue( float value, bool raiseSignals )
+{
+  float clampedValue = Clamp( value, GetLowerBound(), GetUpperBound() );
+
+  float percent = MapValuePercentage( clampedValue );
+
+  float x = mDomain.from.x + percent * ( mDomain.to.x - mDomain.from.x );
+
+  mHandle.SetX( x );
+
+  // Progress bar
+  if( mProgress )
+  {
+    mProgress.SetSize( x, GetTrackRegion().y );
+  }
+
+  // Signals
+  if( raiseSignals )
+  {
+    Toolkit::Slider self = Toolkit::Slider::DownCast( Self() );
+    mValueChangedSignal.Emit( self, clampedValue );
+
+    int markIndex;
+    if( MarkReached( percent, markIndex ) )
+    {
+      mMarkReachedSignal.Emit( self, markIndex );
+    }
+  }
+
+  if( mHandleValueTextLabel )
+  {
+    std::stringstream ss;
+    ss.precision( GetValuePrecision() );
+    ss << std::fixed << clampedValue;
+
+    std::string label = mHandleValueTextLabel.GetProperty<std::string>( Toolkit::TextLabel::Property::TEXT );
+    if( label.compare(ss.str()) )
+    {
+      mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
+    }
+  }
+}
+
+void Slider::SetMarks( const MarkList& marks )
+{
+  mMarks = marks;
+}
+
+const Slider::MarkList& Slider::GetMarks() const
+{
+  return mMarks;
+}
+
+void Slider::SetSnapToMarks( bool snap )
+{
+  mSnapToMarks = snap;
+}
+
+bool Slider::GetSnapToMarks() const
+{
+  return mSnapToMarks;
+}
+
+Actor Slider::CreateHitRegion()
+{
+  Actor hitRegion = Actor::New();
+  hitRegion.SetParentOrigin( ParentOrigin::CENTER );
+  hitRegion.SetAnchorPoint( AnchorPoint::CENTER );
+  hitRegion.TouchSignal().Connect( this, &Slider::OnTouch );
+
+  return hitRegion;
+}
+
+Toolkit::ImageView Slider::CreateTrack()
+{
+  Toolkit::ImageView track = Toolkit::ImageView::New();
+  track.SetName("SliderTrack");
+  track.SetParentOrigin( ParentOrigin::CENTER );
+  track.SetAnchorPoint( AnchorPoint::CENTER );
+  return track;
+}
+
+void Slider::SetTrackVisual( const std::string& filename )
+{
+  if( mHandle && ( filename.size() > 0 ) )
+  {
+    mTrack.SetImage( filename );
+    mTrackVisual = filename;
+  }
+}
+
+void Slider::SetTrackVisual( Property::Map map )
+{
+  Property::Value* imageValue = map.Find( "url" );
+  if( imageValue )
+  {
+    mTrackVisual.clear();
+    std::string filename;
+    if( imageValue->Get( filename ) )
+    {
+      if( mTrack && ( filename.size() > 0 ) )
+      {
+        mTrack.SetImage( filename );
+        mTrackMap = map;
+      }
+    }
+  }
+
+  Property::Value* sizeValue = map.Find( "size" );
+  if( sizeValue )
+  {
+    Vector2 size;
+    if( sizeValue->Get( size ) )
+    {
+      mTrackRegion = size;
+      if( mTrack )
+      {
+        mTrack.SetSize( mTrackRegion );
+      }
+
+    ResizeProgressRegion( Vector2( 0.0f, mTrackRegion.y ) );
+
+    mDomain = CalcDomain( mTrackRegion );
+
+    // Set the progress bar to correct width
+    DisplayValue( GetValue(), false );
+    }
+  }
+}
+
+std::string Slider::GetTrackVisual()
+{
+  return mTrackVisual;
+}
+
+Toolkit::ImageView Slider::CreateProgress()
+{
+  Toolkit::ImageView progress = Toolkit::ImageView::New();
+  progress.SetName("SliderProgress");
+  progress.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  progress.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+
+  return progress;
+}
+
+void Slider::SetProgressVisual( const std::string& filename )
+{
+  if( mProgress && ( filename.size() > 0 ) )
+  {
+    mProgress.SetImage( filename );
+    mProgressVisual = filename;
+  }
+}
+
+void Slider::SetProgressVisual( Property::Map map )
+{
+  Property::Value* imageValue = map.Find( "url" );
+  if( imageValue )
+  {
+    mProgressVisual.clear();
+    std::string filename;
+    if( imageValue->Get( filename ) )
+    {
+      if( mProgress && ( filename.size() > 0 ) )
+      {
+        mProgress.SetImage( filename );
+        mProgressMap = map;
+      }
+    }
+  }
+}
+
+std::string Slider::GetProgressVisual()
+{
+  return mProgressVisual;
+}
+
+void Slider::SetPopupVisual( const std::string& filename )
+{
+  mPopupVisual = filename;
+}
+
+void Slider::SetPopupVisual( Property::Map map )
+{
+  Property::Value* imageValue = map.Find( "url" );
+  if( imageValue )
+  {
+    mPopupVisual.clear();
+    std::string filename;
+    if( imageValue->Get( filename ) )
+    {
+      if( mPopup && ( filename.size() > 0 ) )
+      {
+        mPopup.SetImage( filename );
+        mPopupMap = map;
+      }
+    }
+  }
+}
+
+std::string Slider::GetPopupVisual()
+{
+  return mPopupVisual;
+}
+
+void Slider::CreatePopupImage( const std::string& filename )
+{
+  if( mPopup && ( filename.size() > 0 ) )
+  {
+    Property::Map map;
+    map[Toolkit::ImageVisual::Property::URL] = filename;
+    mPopup.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
+  }
+}
+
+void Slider::SetPopupArrowVisual( const std::string& filename )
+{
+  mPopupArrowVisual = filename;
+}
+
+void Slider::SetPopupArrowVisual( Property::Map map )
+{
+  Property::Value* imageValue = map.Find( "url" );
+  if( imageValue )
+  {
+    mPopupArrowVisual.clear();
+    std::string filename;
+    if( imageValue->Get( filename ) )
+    {
+      if( mPopupArrow && ( filename.size() > 0 ) )
+      {
+        mPopupArrow.SetImage( filename );
+        mPopupArrowMap = map;
+      }
+    }
+  }
+}
+
+std::string Slider::GetPopupArrowVisual()
+{
+  return mPopupArrowVisual;
+}
+
+void Slider::CreatePopupArrowImage( const std::string& filename )
+{
+  if( mPopupArrow && ( filename.size() > 0 ) )
+  {
+    Property::Map map;
+    map[Toolkit::ImageVisual::Property::URL] = filename;
+    mPopupArrow.SetProperty( Toolkit::ImageView::Property::IMAGE, map );
+  }
+}
+
+void Slider::ResizeProgressRegion( const Vector2& region )
+{
+  if( mProgress )
+  {
+    mProgress.SetSize( region );
+  }
+}
+
+Toolkit::ImageView Slider::CreateHandle()
+{
+  Toolkit::ImageView handle = Toolkit::ImageView::New();
+  handle.SetName("SliderHandle");
+  handle.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  handle.SetAnchorPoint( AnchorPoint::CENTER );
+
+  return handle;
+}
+
+Toolkit::ImageView Slider::CreatePopupArrow()
+{
+  Toolkit::ImageView arrow = Toolkit::ImageView::New();
+  arrow.SetStyleName("SliderPopupArrow");
+  arrow.SetName("SliderPopupArrow");
+  arrow.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+  arrow.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+
+  return arrow;
+}
+
+Toolkit::TextLabel Slider::CreatePopupText()
+{
+  Toolkit::TextLabel textLabel = Toolkit::TextLabel::New();
+  textLabel.SetName( "SliderPopupTextLabel" );
+  textLabel.SetStyleName( "SliderPopupTextLabel" );
+  textLabel.SetParentOrigin( ParentOrigin::CENTER );
+  textLabel.SetAnchorPoint( AnchorPoint::CENTER );
+  textLabel.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+  textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+  textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+  textLabel.SetPadding( Padding( POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f ) );
+  return textLabel;
+}
+
+Toolkit::ImageView Slider::CreatePopup()
+{
+  Toolkit::ImageView popup = Toolkit::ImageView::New();
+  popup.SetName( "SliderPopup" );
+  popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+  popup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH );
+
+  mValueTextLabel = CreatePopupText();
+  popup.Add( mValueTextLabel );
+
+  return popup;
+}
+
+void Slider::SetHandleVisual( const std::string& filename )
+{
+  if( mHandle && ( filename.size() > 0 ) )
+  {
+    mHandle.SetImage( filename );
+    mHandleVisual = filename;
+  }
+}
+
+void Slider::SetHandleVisual( Property::Map map )
+{
+  Property::Value* imageValue = map.Find( "url" );
+  if( imageValue )
+  {
+    mHandleVisual.clear();
+    std::string filename;
+    if( imageValue->Get( filename ) )
+    {
+      if( mHandle && ( filename.size() > 0 ) )
+      {
+        mHandle.SetImage( filename );
+        mHandleMap = map;
+      }
+    }
+  }
+
+  Property::Value* sizeValue = map.Find( "size" );
+  if( sizeValue )
+  {
+    Vector2 size;
+    if( sizeValue->Get( size ) )
+    {
+      mHandleSize = size;
+      ResizeHandleSize( mHandleSize );
+
+      Vector2 hitRegion = GetHitRegion();
+      hitRegion.x += mHandleSize.x;
+      SetHitRegion( hitRegion );
+    }
+  }
+}
+
+std::string Slider::GetHandleVisual()
+{
+  return mHandleVisual;
+}
+
+void Slider::ResizeHandleSize( const Vector2& size )
+{
+  if( mHandle )
+  {
+    mHandle.SetSize( size );
+  }
+}
+
+void Slider::CreateHandleValueDisplay()
+{
+  if( mHandle && !mHandleValueTextLabel )
+  {
+    mHandleValueTextLabel = Toolkit::TextLabel::New();
+    mHandleValueTextLabel.SetName("SliderHandleTextLabel");
+    mHandleValueTextLabel.SetStyleName("SliderHandleTextLabel");
+    mHandleValueTextLabel.SetParentOrigin( ParentOrigin::CENTER );
+    mHandleValueTextLabel.SetAnchorPoint( AnchorPoint::CENTER );
+    mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+    mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+    mHandle.Add( mHandleValueTextLabel );
+  }
+}
+
+void Slider::DestroyHandleValueDisplay()
+{
+  UnparentAndReset(mHandleValueTextLabel);
+}
+
+Actor Slider::CreateValueDisplay()
+{
+  Actor popup = Actor::New();
+  popup.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  popup.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+
+  mPopupArrow = CreatePopupArrow();
+  popup.Add( mPopupArrow );
+
+  mPopup = CreatePopup();
+  mPopup.SetSize( 0.0f, VALUE_POPUP_HEIGHT );
+  mPopupArrow.Add( mPopup );
+
+  return popup;
+}
+
+Toolkit::Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
+{
+  return mValueChangedSignal;
+}
+
+Toolkit::Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
+{
+  return mSlidingFinishedSignal;
+}
+
+Toolkit::Slider::MarkReachedSignalType& Slider::MarkReachedSignal()
+{
+  return mMarkReachedSignal;
+}
+
+void Slider::UpdateSkin()
+{
+  switch( mState )
+  {
+    case NORMAL:
+    {
+      mTrack.SetColor( Color::WHITE );
+      mHandle.SetColor( Color::WHITE );
+      mProgress.SetColor( Color::WHITE );
+      break;
+    }
+    case DISABLED:
+    {
+      Vector4 disabledColor = GetDisabledColor();
+      mTrack.SetColor( disabledColor );
+      mHandle.SetColor( disabledColor );
+      mProgress.SetColor( disabledColor );
+      break;
+    }
+    case PRESSED:
+    {
+      break;
+    }
+    case FOCUSED:
+    {
+      break;
+    }
+  }
+}
+
+void Slider::CreateChildren()
+{
+  Actor self = Self();
+
+  // Hit region
+  mHitArea = CreateHitRegion();
+  mPanDetector = PanGestureDetector::New();
+  mPanDetector.Attach( mHitArea );
+  mPanDetector.DetectedSignal().Connect( this, &Slider::OnPan );
+  self.Add( mHitArea );
+
+  // Track
+  mTrack = CreateTrack();
+  self.Add( mTrack );
+
+  // Progress bar
+  mProgress = CreateProgress();
+  mTrack.Add( mProgress );
+
+  // Handle
+  mHandle = CreateHandle();
+  mProgress.Add( mHandle );
+}
+
+void Slider::SetHitRegion( const Vector2& size )
+{
+  mHitRegion = size;
+
+  if( mHitArea )
+  {
+    mHitArea.SetSize( mHitRegion );
+  }
+}
+
+const Vector2& Slider::GetHitRegion() const
+{
+  return mHitRegion;
+}
+
+void Slider::AddPopup()
+{
+  if( !mValueDisplay )
+  {
+    mValueDisplay = CreateValueDisplay();
+    mValueDisplay.SetVisible( false );
+    mHandle.Add( mValueDisplay );
+
+    CreatePopupImage( GetPopupVisual() );
+    CreatePopupArrowImage( GetPopupArrowVisual() );
+
+    mValueTimer = Timer::New( VALUE_VIEW_SHOW_DURATION );
+    mValueTimer.TickSignal().Connect( this, &Slider::HideValueView );
+  }
+}
+
+void Slider::RemovePopup()
+{
+  if( mValueDisplay )
+  {
+    mPopup.Unparent();
+    mPopup.Reset();
+
+    mPopupArrow.Unparent();
+    mPopupArrow.Reset();
+
+    mValueDisplay.Unparent();
+    mValueDisplay.Reset();
+
+    mValueTimer.TickSignal().Disconnect( this, &Slider::HideValueView );
+    mValueTimer.Reset();
+  }
+}
+
+
+float Slider::MarkFilter( float value )
+{
+  const float MARK_TOLERANCE = GetMarkTolerance();
+
+  float mark;
+  for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i)
+  {
+    const Property::Value& propertyValue = mMarks[i];
+    propertyValue.Get( mark );
+    mark = MapValuePercentage( mark );
+
+    // If close to a mark, return the mark
+    if( fabsf( mark - value ) < MARK_TOLERANCE )
+    {
+      return mark;
+    }
+  }
+
+  return value;
+}
+
+float Slider::SnapToMark( float value )
+{
+  float closestMark = value;
+  float closestDist = std::numeric_limits<float>::max();
+
+  float mark;
+  for( MarkList::SizeType  i = 0; i < mMarks.Count(); ++i)
+  {
+    const Property::Value& propertyValue = mMarks[i];
+    propertyValue.Get( mark );
+    mark = MapValuePercentage( mark );
+
+    float dist = fabsf( mark - value );
+    if( dist < closestDist )
+    {
+      closestDist = dist;
+      closestMark = mark;
+    }
+  }
+
+  return closestMark;
+}
+
+bool Slider::MarkReached( float value, int& outIndex )
+{
+  const float MARK_TOLERANCE = GetMarkTolerance();
+
+  // Binary search
+  int head = 0,
+      tail = mMarks.Size() - 1;
+  int current;
+  float mark;
+
+  while( head <= tail )
+  {
+    current = head + ( tail - head ) / 2;
+
+    const Property::Value& propertyValue = mMarks[ current ];
+    propertyValue.Get( mark );
+    mark = MapValuePercentage( mark );
+
+    if( fabsf( mark - value ) < MARK_TOLERANCE )
+    {
+      outIndex = current;
+      return true;
+    }
+
+    if( value < mark )
+    {
+      tail = current - 1;
+    }
+    else
+    {
+      head = current + 1;
+    }
+  }
+
+  return false;
+}
+
+bool Slider::HideValueView()
+{
+  if( mValueDisplay )
+  {
+    mValueDisplay.SetVisible( false );
+  }
+
+  return false;
+}
+
+void Slider::SetLowerBound( float bound )
+{
+  mLowerBound = bound;
+  DisplayValue( GetValue(), false );
+}
+
+float Slider::GetLowerBound() const
+{
+  return mLowerBound;
+}
+
+void Slider::SetUpperBound( float bound )
+{
+  mUpperBound = bound;
+  DisplayValue( GetValue(), false );
+}
+
+float Slider::GetUpperBound() const
+{
+  return mUpperBound;
+}
+
+void Slider::SetValue( float value )
+{
+  mValue = value;
+  DisplayValue( mValue, true );
+}
+
+float Slider::GetValue() const
+{
+  return mValue;
+}
+
+void Slider::SetTrackRegion( const Vector2& region )
+{
+  mTrackRegion = region;
+
+  if( mTrack )
+  {
+    mTrack.SetSize( mTrackRegion );
+  }
+
+  ResizeProgressRegion( Vector2( 0.0f, mTrackRegion.y ) );
+
+  mDomain = CalcDomain( mTrackRegion );
+
+  DisplayValue( GetValue(), false );  // Set the progress bar to correct width
+}
+
+const Vector2& Slider::GetTrackRegion() const
+{
+  return mTrackRegion;
+}
+
+void Slider::SetHandleSize( const Vector2& size )
+{
+  mHandleSize = size;
+
+  ResizeHandleSize( mHandleSize );
+
+  Vector2 hitRegion = GetHitRegion();
+  hitRegion.x += mHandleSize.x;
+  SetHitRegion( hitRegion );
+}
+
+const Vector2& Slider::GetHandleSize() const
+{
+  return mHandleSize;
+}
+
+void Slider::SetDisabledColor( const Vector4& color )
+{
+  mDisabledColor = color;
+
+  UpdateSkin();
+}
+
+Vector4 Slider::GetDisabledColor() const
+{
+  return mDisabledColor;
+}
+
+void Slider::SetValuePrecision( int precision )
+{
+  mValuePrecision = precision;
+}
+
+int Slider::GetValuePrecision() const
+{
+  return mValuePrecision;
+}
+
+void Slider::SetShowPopup( bool showPopup )
+{
+  mShowPopup = showPopup;
+
+  // Value display
+  if( mShowPopup )
+  {
+    AddPopup();
+  }
+  else
+  {
+    RemovePopup();
+  }
+}
+
+bool Slider::GetShowPopup() const
+{
+  return mShowPopup;
+}
+
+void Slider::SetShowValue( bool showValue )
+{
+  mShowValue = showValue;
+
+  if( mShowValue )
+  {
+    CreateHandleValueDisplay();
+  }
+  else
+  {
+    DestroyHandleValueDisplay();
+  }
+}
+
+bool Slider::GetShowValue() const
+{
+  return mShowValue;
+}
+
+void Slider::SetEnabled( bool enabled )
+{
+  if( enabled )
+  {
+    mState = NORMAL;
+  }
+  else
+  {
+    mState = DISABLED;
+  }
+
+  UpdateSkin();
+}
+
+bool Slider::IsEnabled() const
+{
+  return mState != DISABLED;
+}
+
+void Slider::SetMarkTolerance( float tolerance )
+{
+  mMarkTolerance = tolerance;
+}
+
+float Slider::GetMarkTolerance() const
+{
+  return mMarkTolerance;
+}
+
+// Static class method to support script connecting signals
+bool Slider::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected = true;
+  Toolkit::Slider slider = Toolkit::Slider::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_VALUE_CHANGED ) )
+  {
+    slider.ValueChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_MARK ) )
+  {
+    slider.MarkReachedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void Slider::DisplayPopup( float value )
+{
+  // Value displayDoConnectSignal
+  if( mValueTextLabel )
+  {
+    std::stringstream ss;
+    ss.precision( GetValuePrecision() );
+    ss << std::fixed << value;
+    mValueTextLabel.SetProperty( Toolkit::TextLabel::Property::TEXT, ss.str() );
+
+    if( mValueDisplay )
+    {
+      mValueDisplay.SetVisible( true );
+
+      mValueTimer.SetInterval( VALUE_VIEW_SHOW_DURATION );
+    }
+  }
+}
+
+void Slider::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
+
+  if ( slider )
+  {
+    Slider& sliderImpl( GetImpl( slider ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::Slider::Property::LOWER_BOUND:
+      {
+        sliderImpl.SetLowerBound( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::UPPER_BOUND:
+      {
+        sliderImpl.SetUpperBound( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::VALUE:
+      {
+        sliderImpl.SetValue( value.Get< float >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::TRACK_VISUAL:
+      {
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          sliderImpl.SetTrackVisual( map );
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::HANDLE_VISUAL:
+      {
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          sliderImpl.SetHandleVisual( map );
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::PROGRESS_VISUAL:
+      {
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          sliderImpl.SetProgressVisual( map );
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::POPUP_VISUAL:
+      {
+        std::string imageUrl;
+        if( value.Get( imageUrl ) )
+        {
+          sliderImpl.SetPopupVisual( imageUrl );
+        }
+
+        // If it is not a string, then get a Property::Map from the property if possible.
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          sliderImpl.SetPopupVisual( map );
+        }
+
+        break;
+      }
+
+      case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
+      {
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          sliderImpl.SetPopupArrowVisual( map );
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::DISABLED_COLOR:
+      {
+        sliderImpl.SetDisabledColor( value.Get< Vector4 >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::VALUE_PRECISION:
+      {
+        sliderImpl.SetValuePrecision( value.Get< int >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::SHOW_POPUP:
+      {
+        sliderImpl.SetShowPopup( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::SHOW_VALUE:
+      {
+        sliderImpl.SetShowValue( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::MARKS:
+      {
+        sliderImpl.SetMarks( value.Get< Property::Array >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::SNAP_TO_MARKS:
+      {
+        sliderImpl.SetSnapToMarks( value.Get< bool >() );
+        break;
+      }
+
+      case Toolkit::Slider::Property::MARK_TOLERANCE:
+      {
+        sliderImpl.SetMarkTolerance( value.Get< float >() );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value Slider::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::Slider slider = Toolkit::Slider::DownCast( Dali::BaseHandle( object ) );
+
+  if ( slider )
+  {
+    Slider& sliderImpl( GetImpl( slider ) );
+
+    switch ( propertyIndex )
+    {
+      case Toolkit::Slider::Property::LOWER_BOUND:
+      {
+        value = sliderImpl.GetLowerBound();
+        break;
+      }
+
+      case Toolkit::Slider::Property::UPPER_BOUND:
+      {
+        value = sliderImpl.GetUpperBound();
+        break;
+      }
+
+      case Toolkit::Slider::Property::VALUE:
+      {
+        value = sliderImpl.GetValue();
+        break;
+      }
+
+      case Toolkit::Slider::Property::TRACK_VISUAL:
+      {
+        if( !sliderImpl.mTrackVisual.empty() )
+        {
+          value = sliderImpl.GetTrackVisual();
+        }
+        else if( !sliderImpl.mTrackMap.Empty() )
+        {
+          value = sliderImpl.mTrackMap;
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::HANDLE_VISUAL:
+      {
+        if( !sliderImpl.mHandleVisual.empty() )
+        {
+          value = sliderImpl.GetHandleVisual();
+        }
+        else if( !sliderImpl.mHandleMap.Empty() )
+        {
+          value = sliderImpl.mHandleMap;
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::PROGRESS_VISUAL:
+      {
+        if( !sliderImpl.mProgressVisual.empty() )
+        {
+          value = sliderImpl.GetProgressVisual();
+        }
+        else if( !sliderImpl.mProgressMap.Empty() )
+        {
+          value = sliderImpl.mProgressMap;
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::POPUP_VISUAL:
+      {
+        if( !sliderImpl.mPopupVisual.empty() )
+        {
+          value = sliderImpl.GetPopupVisual();
+        }
+        else if( !sliderImpl.mPopupMap.Empty() )
+        {
+          value = sliderImpl.mPopupMap;
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::POPUP_ARROW_VISUAL:
+      {
+        if( !sliderImpl.mPopupArrowVisual.empty() )
+        {
+          value = sliderImpl.GetPopupArrowVisual();
+        }
+        else if( !sliderImpl.mPopupArrowMap.Empty() )
+        {
+          value = sliderImpl.mPopupArrowMap;
+        }
+        break;
+      }
+
+      case Toolkit::Slider::Property::DISABLED_COLOR:
+      {
+        value = sliderImpl.GetDisabledColor();
+        break;
+      }
+
+      case Toolkit::Slider::Property::VALUE_PRECISION:
+      {
+        value = sliderImpl.GetValuePrecision();
+        break;
+      }
+
+      case Toolkit::Slider::Property::SHOW_POPUP:
+      {
+        value = sliderImpl.GetShowPopup();
+        break;
+      }
+
+      case Toolkit::Slider::Property::SHOW_VALUE:
+      {
+        value = sliderImpl.GetShowValue();
+        break;
+      }
+
+      case Toolkit::Slider::Property::MARKS:
+      {
+        Property::Value value1( Property::ARRAY );
+        Property::Array* markArray = value1.GetArray();
+
+        if( markArray )
+        {
+          *markArray = sliderImpl.GetMarks();
+        }
+
+        value = value1;
+        break;
+      }
+
+      case Toolkit::Slider::Property::SNAP_TO_MARKS:
+      {
+        value = sliderImpl.GetSnapToMarks();
+        break;
+      }
+
+      case Toolkit::Slider::Property::MARK_TOLERANCE:
+      {
+        value = sliderImpl.GetMarkTolerance();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/slider/slider-impl.h b/dali-toolkit/internal/controls/slider/slider-impl.h
new file mode 100755 (executable)
index 0000000..bbae4d5
--- /dev/null
@@ -0,0 +1,786 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SLIDER_H
+#define DALI_TOOLKIT_INTERNAL_SLIDER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/slider/slider.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class Button;
+
+namespace Internal
+{
+
+class Slider;
+
+typedef Dali::IntrusivePtr< Slider > SliderPtr;
+
+/**
+ * @copydoc Toolkit::Slider
+ */
+class Slider : public Control
+{
+public:
+
+  typedef Property::Array MarkList;
+
+  /**
+   * Create a new Slider.
+   *
+   * @return A public handle to the newly allocated Slider.
+   */
+  static Dali::Toolkit::Slider New();
+
+public:
+
+  // Properties
+
+  /**
+   * Set marks from a list
+   *
+   * @param[in] marks The list of marks to set
+   */
+  void SetMarks( const MarkList& marks );
+
+  /**
+   * Get the list of marks
+   *
+   * @return The marks list
+   */
+  const MarkList& GetMarks() const;
+
+  /**
+   * Set if should snap to marks or not
+   *
+   * @param[in] snap Flag to snap to marks or not
+   */
+  void SetSnapToMarks( bool snap );
+
+  /**
+   * Return if snap to marks is set or not
+   *
+   * @return If snap to marks is set
+   */
+  bool GetSnapToMarks() const;
+
+  /**
+   * Set the value of the slider
+   *
+   * @param[in] value The value to set. Will be clamped to [lowerBound .. upperBound]
+   */
+  void SetValue( float value );
+
+  /**
+   * Get the value of the slider
+   *
+   * @return The current value of the slider
+   */
+  float GetValue() const;
+
+  /**
+   * Set hit region
+   *
+   * @param[in] region The hit region
+   */
+  void SetHitRegion( const Vector2& region );
+
+  /**
+   * Get hit region
+   *
+   * @return The hit region
+   */
+  const Vector2& GetHitRegion() const;
+
+  /**
+   * Set the track region
+   *
+   * @param[in] region The track region
+   */
+  void SetTrackRegion( const Vector2& region );
+
+  /**
+   * Get the track region
+   *
+   * @return The track region
+   */
+  const Vector2& GetTrackRegion() const;
+
+  /**
+   * @brief Set the disabled color.
+   *
+   * @param[in] color The disabled color.
+   */
+  void SetDisabledColor( const Vector4& color );
+
+  /**
+   * @brief Get disabled color
+   *
+   * @return The disabled color
+   */
+  Vector4 GetDisabledColor() const;
+
+  /**
+   * Set the value precision to be used for numbers in the slider
+   *
+   * @param[in] precision The number of decimal places to use for printing numbers
+   */
+  void SetValuePrecision( int precision );
+
+  /**
+   * Get value precision
+   *
+   * @return The value precision
+   */
+  int GetValuePrecision() const;
+
+  /**
+   * Show the popup
+   *
+   * @param[in] showPopup The show popup flag
+   */
+  void SetShowPopup( bool showPopup );
+
+  /**
+   * Get show value in popup
+   *
+   * @return The show value flag
+   */
+  bool GetShowPopup() const;
+
+  /**
+   * Set show value on handle
+   *
+   * @param[in] showValue The show value flag
+   */
+  void SetShowValue( bool showValue );
+
+  /**
+   * Get show value on handle
+   *
+   * @return The show value flag
+   */
+  bool GetShowValue() const;
+
+  /**
+   * Set enabled
+   *
+   * param[in] enabled Set the enabled flag
+   */
+  void SetEnabled( bool enabled );
+
+  /**
+   * Return if enabled or not
+   *
+   * @return If enabled
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @brief Set the mark tolerance
+   *
+   * The tolerance is the percentage of the slider width for which snapping to
+   * marks occurs
+   *
+   * @param[in] tolerance The percentage of width for which to snap
+   */
+  void SetMarkTolerance( float tolerance );
+
+  /**
+   * Return the mark tolerance
+   *
+   * @return The tolerance set for snapping to marks
+   */
+  float GetMarkTolerance() const;
+
+public:
+  //Signals
+
+  /**
+   * @copydoc Toolkit::Slider::ValueChangedSignal()
+   */
+  Toolkit::Slider::ValueChangedSignalType& ValueChangedSignal();
+
+  /**
+   * copydoc Toolkit::Slider::SlidingFinishedSignal()
+   */
+  Toolkit::Slider::ValueChangedSignalType& SlidingFinishedSignal();
+
+  /**
+   * @copydoc Toolkit::Slider::MarkReachedSignal()
+   */
+  Toolkit::Slider::MarkReachedSignalType& MarkReachedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName,
+                               FunctorDelegate* functor );
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+protected:
+
+  /**
+   * Construct a new Slider.
+   */
+  Slider();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Slider();
+
+  /**
+   * @copydoc CustomActorImpl::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+
+private:
+
+  /**
+   * Domain is a from/to pair
+   */
+  struct Domain
+  {
+    Vector2 from;
+    Vector2 to;
+
+    Domain()
+    {
+    }
+    Domain( Vector2 fromVal, Vector2 toVal )
+        : from( fromVal ), to( toVal )
+    {
+    }
+  };
+
+  /**
+   * Slider states
+   */
+  enum SliderState
+  {
+    NORMAL,
+    DISABLED,
+    PRESSED,
+    FOCUSED
+  };
+
+private:
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * Hit region touch
+   *
+   * @param[in] actor The actor the event is raised for
+   * @param[in] touch The touch info
+   * @return If touch is handled or not
+   */
+  bool OnTouch( Actor actor, const TouchData& touch );
+
+  /**
+   * Pan gesture event
+   *
+   * @param[in] actor The actor the event is raised for
+   * @param[in] gesture The pan event info
+   */
+  void OnPan( Actor actor, const PanGesture& gesture );
+
+  /**
+   * Map a position onto a domain and return the result as a percentage
+   *
+   * @param[in] point The point to map onto the domain
+   * @return The result as a percentage [0..1]
+   */
+  float MapPercentage( const Vector2& point );
+
+  /**
+   * Map a value in the range to a percentage
+   *
+   * @param[in] point The value in range [lowerBound..upperBound]
+   * @return The result as a percentage [0..1]
+   */
+  float MapValuePercentage( float value );
+
+  /**
+   * Convert a point in local hit space into domain space
+   *
+   * @param[in] x The x position to convert
+   * @return The x position in domain space
+   */
+  float HitSpaceToDomain( float x );
+
+  /**
+   * Map a percentage onto the slider's bounds
+   *
+   * @param[in] percent The current value of slider in percent
+   * @param[in] lowerBound The lower bound to map onto
+   * @param[in] upperBound The upper bound to map onto
+   * @return The value of percent mapped from lowerBound to upperBound
+   */
+  float MapBounds( float percent, float lowerBound, float upperBound );
+
+  /**
+   * Get the range of the valid values the slider handle can move between
+   *
+   * @param[in] currentSize The current size of the slider
+   * @return The range as a domain pair
+   */
+  Domain CalcDomain( const Vector2& currentSize );
+
+  /**
+   * Create the hit region
+   *
+   * @return The hit region actor
+   */
+  Actor CreateHitRegion();
+
+  /**
+   * Create the track for the slider
+   *
+   * @return The track actor
+   */
+  Toolkit::ImageView CreateTrack();
+
+  /**
+   * Create the progress track for the slider
+   *
+   * @return The track actor
+   */
+  Toolkit::ImageView CreateProgress();
+
+  /**
+   * Create the handle for the slider
+   *
+   * @return The created image handle
+   */
+  Toolkit::ImageView CreateHandle();
+
+  /**
+   * Create the popup arrow
+   *
+   * @return The created image handle
+   */
+  Toolkit::ImageView CreatePopupArrow();
+
+  /**
+   * Create the popup
+   *
+   * @return The created image handle
+   */
+  Toolkit::ImageView CreatePopup();
+
+  /**
+   * Create the textview for the popup
+   *
+   * @return The textview created for the popup
+   */
+  Toolkit::TextLabel CreatePopupText();
+
+  /**
+   * Create the value display for the slider
+   *
+   * @return The created root actor of the display
+   */
+  Actor CreateValueDisplay();
+
+  /**
+   * Set the skin based on the current state
+   */
+  void UpdateSkin();
+
+  /**
+   * Create all the children
+   */
+  void CreateChildren();
+
+  /**
+   * Create value popup
+   */
+  void AddPopup();
+
+  /**
+   * Remove value popup
+   */
+  void RemovePopup();
+
+  /**
+   * Display the popup for a set duration with the given value
+   *
+   * @param[in] value The value to display in the popup
+   */
+  void DisplayPopup( float value );
+
+  /**
+   * If there are marks present, filter the incoming percent based on snapping to any nearby marks
+   *
+   * @param[in] value The incoming value on the slider to filter
+   * @return The filtered percentage snapped to any nearby marks
+   */
+  float MarkFilter( float value );
+
+  /**
+   * If there are marks present, snap the incoming percent to the nearest mark
+   *
+   * @param[in] value The incoming value on the slider to snap
+   * @return The filtered percentage snapped to the nearest mark
+   */
+  float SnapToMark( float value );
+
+  /**
+   * Search for if a mark has been reached
+   *
+   * @param[in] value The value to search against
+   * @param[out] outIndex The index of the mark if found
+   * @return If a mark has been found to match percent
+   */
+  bool MarkReached( float value, int& outIndex );
+
+  /**
+   * Handler for when the value view needs to be hidden
+   *
+   * @return If handled or not
+   */
+  bool HideValueView();
+
+  /**
+   * Set value choosing whether to fire signals or not
+   *
+   * @paramp[in] value The value to set
+   * @param[in] raiseSignals Configure signals to be raised or not.
+   */
+  void DisplayValue( float value, bool raiseSignals );
+
+  /**
+   * Create the image for the track
+   *
+   * @param[in] filename The track image
+   */
+  void SetTrackVisual( const std::string& filename );
+
+  /**
+   * @brief Set the track visual from an Dali::Property::Map
+   *
+   * @param[in] map The Dali::Property::Map to use for to display
+   */
+  void SetTrackVisual( Dali::Property::Map map );
+
+  /**
+   * @brief Return the track image.
+   *
+   * @return The track image.
+   */
+  std::string GetTrackVisual();
+
+  /**
+   * Create the image for the progress bar
+   *
+   * @param[in] filename The progress bar image
+   */
+  void SetProgressVisual( const std::string& filename );
+
+  /**
+   * @brief Set the progress visual from an Dali::Property::Map
+   *
+   * @param[in] map The Dali::Property::Map to use for to display
+   */
+  void SetProgressVisual( Dali::Property::Map map );
+
+  /**
+   * @brief Return the progress bar image.
+   *
+   * @return The progress bar image if it exists.
+   */
+  std::string GetProgressVisual();
+
+  /**
+   * @brief Create the image for the popup
+   *
+   * @param[in] filename The popup image
+   */
+  void CreatePopupImage( const std::string& filename );
+
+  /**
+   * @brief Set the popup image
+   *
+   * @param[in] filename The popup image to set
+   */
+  void SetPopupVisual( const std::string& filename );
+
+  /**
+   * @brief Set the popup from an Dali::Property::Map
+   *
+   * @param[in] map The Dali::Property::Map to use for to display
+   */
+  void SetPopupVisual( Dali::Property::Map map );
+
+  /**
+   * @brief Return the popup image.
+   *
+   * @return The popup image if it exists.
+   */
+  std::string GetPopupVisual();
+
+  /**
+   * @brief Set the popup arrow image
+   *
+   * @param[in] filename The popup arrow image to set
+   */
+  void SetPopupArrowVisual( const std::string& filename );
+
+  /**
+   * @brief Set the popup arrow from an Dali::Property::Map
+   *
+   * @param[in] map The Dali::Property::Map to use for to display
+   */
+  void SetPopupArrowVisual( Dali::Property::Map map );
+
+  /**
+   * @brief Return the popup arrow image.
+   *
+   * @return The popup arrow image if it exists.
+   */
+  std::string GetPopupArrowVisual();
+
+  /**
+   * Create the image for the popup arrow
+   *
+   * @param[in] filename The popup arrow image to load and set
+   */
+  void CreatePopupArrowImage( const std::string& filename );
+
+  /**
+   * Set the size of the progress bar region
+   *
+   * @param[in] region The size of the region to set
+   */
+  void ResizeProgressRegion( const Vector2& region );
+
+  /**
+   * Create the image for the handle
+   *
+   * @param[in] filename The handle image
+   */
+  void SetHandleVisual( const std::string& filename );
+
+  /**
+   * @brief Set the handle visual from an Dali::Property::Map
+   *
+   * @param[in] map The Dali::Property::Map to use for to display
+   */
+  void SetHandleVisual( Property::Map map );
+
+  /**
+   * @brief Return the handle image.
+   *
+   * @return The handle image if it exists.
+   */
+  std::string GetHandleVisual();
+
+  /**
+   * Reset the size of the handle
+   *
+   * @param[in] size The size of the handle to set
+   */
+  void ResizeHandleSize( const Vector2& size );
+
+  /**
+   * Create and display the value on the handle
+   */
+  void CreateHandleValueDisplay();
+
+  /**
+   * Remove and destroy the handle value display
+   */
+  void DestroyHandleValueDisplay();
+
+  /**
+   * Set the size of the handle
+   *
+   * @param[in] size The handle size
+   */
+  void SetHandleSize( const Vector2& size );
+
+  /**
+   * Get the size of the handle
+   *
+   * @return The handle size
+   */
+  const Vector2& GetHandleSize() const;
+
+  /**
+   * Set the lower bound of the slider's value
+   *
+   * @param[in] bound The value to set for the lower bound
+   */
+  void SetLowerBound( float bound );
+
+  /**
+   * Get the lower bound of the slider's value
+   *
+   * @return The lower bound value
+   */
+  float GetLowerBound() const;
+
+  /**
+   * Set the upper bound of the slider's value
+   *
+   * @param[in] bound The value to set for the upper bound
+   */
+  void SetUpperBound( float bound );
+
+  /**
+   * Get the upper bound of the slider's value
+   *
+   * @return The upper bound value
+   */
+  float GetUpperBound() const;
+
+private:
+
+  // Undefined
+  Slider( const Slider& );
+
+  // Undefined
+  Slider& operator=( const Slider& rhs );
+
+private:
+
+  Domain mDomain;                           ///< Current domain of the handle
+
+  Actor mHitArea;                           ///< The input handler
+  Actor mValueDisplay;                      ///< Display of the value
+  Toolkit::ImageView mTrack;                ///< Track image
+  Toolkit::ImageView mHandle;               ///< Slider handle
+  Toolkit::ImageView mProgress;             ///< Progress bar
+  Toolkit::ImageView mPopup;                ///< Popup backing
+  Toolkit::ImageView mPopupArrow;           ///< Popup arrow backing
+
+  Toolkit::TextLabel mValueTextLabel;       //< The text value in popup
+  Toolkit::TextLabel mHandleValueTextLabel; ///< The text value on handle
+  Vector2 mHandleLastTouchPoint;            ///< The last touch point for the handle
+  Timer mValueTimer;                        ///< Timer used to hide value view
+
+  Toolkit::Slider::ValueChangedSignalType mValueChangedSignal;       ///< Signal emitted when the value is changed
+  Toolkit::Slider::ValueChangedSignalType mSlidingFinishedSignal;    ///< Signal emitted when a sliding is finished
+  Toolkit::Slider::MarkReachedSignalType mMarkReachedSignal;         ///< Signal emitted when a mark is reached
+
+  SliderState mState;                 ///< The state of the slider
+
+  PanGestureDetector mPanDetector;    ///< Hit region pan detector
+
+  MarkList mMarks;                    ///< List of discreet marks
+
+  std::string mPopupVisual;           ///< Image for popup image
+  std::string mPopupArrowVisual;      ///< Image for popup arrow image
+  std::string mTrackVisual;           ///< Image for track image
+  std::string mHandleVisual;          ///< Image for handle image
+  std::string mProgressVisual;        ///< Image for progress bar image
+
+  Property::Map mPopupMap;         ///< the Property::Map if the image came from a Property::Map, empty otherwise
+  Property::Map mTrackMap;         ///< the Property::Map if the image came from a Property::Map, empty otherwise
+  Property::Map mHandleMap;        ///< the Property::Map if the image came from a Property::Map, empty otherwise
+  Property::Map mProgressMap;      ///< the Property::Map if the image came from a Property::Map, empty otherwise
+  Property::Map mPopupArrowMap;    ///< the Property::Map if the image came from a Property::Map, empty otherwise
+
+  Vector4 mDisabledColor;    ///< The color to tint the slider when disabled
+
+  Vector2 mHitRegion;     ///< Size of hit region
+  Vector2 mTrackRegion;   ///< Size of track region
+  Vector2 mHandleSize;    ///< Size of the handle
+
+  float mLowerBound;        ///< Lower bound on value
+  float mUpperBound;        ///< Upper bound on value
+  float mValue;             ///< Current value of slider
+
+  float mMarkTolerance;     ///< Tolerance in percentage of slider width for which to snap to marks
+
+  int mValuePrecision;      ///< The precision to use for outputting the value
+
+  bool mShowPopup   : 1,      ///< Show the popup or not
+       mShowValue   : 1,      ///< Whether to display the value number or not on the handle
+       mSnapToMarks : 1;      ///< Turn on or off snapping to marks
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::Slider& GetImpl( Toolkit::Slider& pub )
+{
+  DALI_ASSERT_ALWAYS( pub );
+
+  Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast< Toolkit::Internal::Slider& >( handle );
+}
+
+inline const Toolkit::Internal::Slider& GetImpl( const Toolkit::Slider& pub )
+{
+  DALI_ASSERT_ALWAYS( pub );
+
+  const Dali::RefObject& handle = pub.GetImplementation();
+
+  return static_cast< const Toolkit::Internal::Slider& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SLIDER_H
diff --git a/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp b/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp
new file mode 100644 (file)
index 0000000..70bd49d
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2017 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 "super-blur-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL_INCLUDES
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+namespace //Unnamed namespace
+{
+
+using namespace Dali;
+
+//Todo: make these properties instead of constants
+const unsigned int GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES = 11;
+const unsigned int GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION = 10;
+const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH = 4.5f;
+const float GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION = 5.f;
+const Pixel::Format GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT = Pixel::RGBA8888;
+const float GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE = 0.5f;
+const float GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE = 0.5f;
+
+const char* ALPHA_UNIFORM_NAME( "uAlpha" );
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp float uAlpha;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+    gl_FragColor.a *= uAlpha;
+  }\n
+);
+
+/**
+ * The constraint is used to blend the group of blurred images continuously with a unified blur strength property value which ranges from zero to one.
+ */
+struct ActorOpacityConstraint
+{
+  ActorOpacityConstraint(int totalImageNum, int currentImageIdx)
+  {
+    float rangeLength = 1.f / static_cast<float>( totalImageNum );
+    float index = static_cast<float>( currentImageIdx );
+    mRange = Vector2( index*rangeLength, (index+1.f)*rangeLength );
+  }
+
+  void operator()( float& current, const PropertyInputContainer& inputs )
+  {
+    float blurStrength = inputs[0]->GetFloat();
+    if(blurStrength < mRange.x)
+    {
+      current = 0.f;
+    }
+    else if(blurStrength > mRange.y)
+    {
+      current = 1.f;
+    }
+    else
+    {
+      current = ( blurStrength - mRange.x) / ( mRange.y - mRange.x );
+    }
+  }
+
+  Vector2 mRange;
+};
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const unsigned int DEFAULT_BLUR_LEVEL(5u); ///< The default blur level when creating SuperBlurView from the type registry
+
+BaseHandle Create()
+{
+  return Toolkit::SuperBlurView::New( DEFAULT_BLUR_LEVEL );
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::SuperBlurView, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, SuperBlurView, "imageUrl", STRING, IMAGE_URL )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // unnamed namespace
+
+SuperBlurView::SuperBlurView( unsigned int blurLevels )
+: Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mTargetSize( Vector2::ZERO ),
+  mBlurStrengthPropertyIndex(Property::INVALID_INDEX),
+  mBlurLevels( blurLevels ),
+  mResourcesCleared( true )
+{
+  DALI_ASSERT_ALWAYS( mBlurLevels > 0 && " Minimal blur level is one, otherwise no blur is needed" );
+  mGaussianBlurView.assign( blurLevels, Toolkit::GaussianBlurView() );
+  mBlurredImage.assign( blurLevels, FrameBuffer() );
+  mRenderers.assign( blurLevels+1, Dali::Renderer() );
+}
+
+SuperBlurView::~SuperBlurView()
+{
+}
+
+Toolkit::SuperBlurView SuperBlurView::New( unsigned int blurLevels )
+{
+  //Create the implementation
+  IntrusivePtr<SuperBlurView> superBlurView( new SuperBlurView( blurLevels ) );
+
+  //Pass ownership to CustomActor via derived handle
+  Toolkit::SuperBlurView handle( *superBlurView );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  superBlurView->Initialize();
+
+  return handle;
+}
+
+void SuperBlurView::OnInitialize()
+{
+  Actor self( Self() );
+
+  mBlurStrengthPropertyIndex = self.RegisterProperty( "blurStrength", 0.f );
+}
+
+void SuperBlurView::SetTexture( Texture texture )
+{
+  mInputTexture = texture;
+
+  if( mTargetSize == Vector2::ZERO )
+  {
+    return;
+  }
+
+  ClearBlurResource();
+
+  Actor self( Self() );
+
+  BlurTexture( 0, mInputTexture );
+  SetRendererTexture( mRenderers[0], texture );
+
+  unsigned int i = 1;
+  for(; i<mBlurLevels; i++)
+  {
+    BlurTexture( i, mBlurredImage[i-1].GetColorTexture() );
+    SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
+  }
+
+  SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
+
+  mResourcesCleared = false;
+}
+
+Property::Index SuperBlurView::GetBlurStrengthPropertyIndex() const
+{
+  return mBlurStrengthPropertyIndex;
+}
+
+void SuperBlurView::SetBlurStrength( float blurStrength )
+{
+  Self().SetProperty(mBlurStrengthPropertyIndex, blurStrength);
+}
+
+float SuperBlurView::GetCurrentBlurStrength() const
+{
+  float blurStrength;
+  (Self().GetProperty( mBlurStrengthPropertyIndex )).Get(blurStrength);
+
+  return blurStrength;
+}
+
+Toolkit::SuperBlurView::SuperBlurViewSignal& SuperBlurView::BlurFinishedSignal()
+{
+  return mBlurFinishedSignal;
+}
+
+Texture SuperBlurView::GetBlurredTexture( unsigned int level )
+{
+  DALI_ASSERT_ALWAYS( level>0 && level<=mBlurLevels );
+
+  FrameBuffer frameBuffer = mBlurredImage[level-1];
+
+  return frameBuffer.GetColorTexture();
+}
+
+void SuperBlurView::BlurTexture( unsigned int idx, Texture texture )
+{
+  DALI_ASSERT_ALWAYS( mGaussianBlurView.size()>idx );
+  mGaussianBlurView[idx] = Toolkit::GaussianBlurView::New( GAUSSIAN_BLUR_DEFAULT_NUM_SAMPLES+GAUSSIAN_BLUR_NUM_SAMPLES_INCREMENTATION*idx,
+                                                           GAUSSIAN_BLUR_BELL_CURVE_WIDTH + GAUSSIAN_BLUR_BELL_CURVE_WIDTH_INCREMENTATION*static_cast<float>(idx),
+                                                           GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT,
+                                                           GAUSSIAN_BLUR_DOWNSAMPLE_WIDTH_SCALE, GAUSSIAN_BLUR_DOWNSAMPLE_HEIGHT_SCALE, true );
+  mGaussianBlurView[idx].SetParentOrigin(ParentOrigin::CENTER);
+  mGaussianBlurView[idx].SetSize(mTargetSize);
+  Stage::GetCurrent().Add( mGaussianBlurView[idx] );
+
+  mGaussianBlurView[idx].SetUserImageAndOutputRenderTarget( texture, mBlurredImage[idx] );
+
+  mGaussianBlurView[idx].ActivateOnce();
+  if( idx == mBlurLevels-1 )
+  {
+    mGaussianBlurView[idx].FinishedSignal().Connect( this, &SuperBlurView::OnBlurViewFinished );
+  }
+}
+
+void SuperBlurView::OnBlurViewFinished( Toolkit::GaussianBlurView blurView )
+{
+  ClearBlurResource();
+  Toolkit::SuperBlurView handle( GetOwner() );
+  mBlurFinishedSignal.Emit( handle );
+}
+
+void SuperBlurView::ClearBlurResource()
+{
+  if( !mResourcesCleared )
+  {
+    DALI_ASSERT_ALWAYS( mGaussianBlurView.size() == mBlurLevels && "must synchronize the GaussianBlurView group if blur levels got changed " );
+    for(unsigned int i=0; i<mBlurLevels;i++)
+    {
+      Stage::GetCurrent().Remove( mGaussianBlurView[i] );
+      mGaussianBlurView[i].Deactivate();
+    }
+    mResourcesCleared = true;
+  }
+}
+
+void SuperBlurView::OnSizeSet( const Vector3& targetSize )
+{
+  if( mTargetSize != Vector2(targetSize) )
+  {
+    mTargetSize = Vector2(targetSize);
+
+    Actor self = Self();
+    for( unsigned int i = 1; i <= mBlurLevels; i++ )
+    {
+      float exponent = static_cast<float>(i);
+
+      unsigned int width = mTargetSize.width/std::pow(2.f,exponent);
+      unsigned int height = mTargetSize.height/std::pow(2.f,exponent);
+
+      mBlurredImage[i-1] = FrameBuffer::New( width, height, FrameBuffer::Attachment::NONE );
+      Texture texture = Texture::New( TextureType::TEXTURE_2D, GAUSSIAN_BLUR_RENDER_TARGET_PIXEL_FORMAT, unsigned(width), unsigned(height) );
+      mBlurredImage[i-1].AttachColorTexture( texture );
+    }
+
+    if( mInputTexture )
+    {
+      SetTexture( mInputTexture );
+    }
+  }
+
+  Control::OnSizeSet( targetSize );
+}
+
+void SuperBlurView::OnStageConnection( int depth )
+{
+  if( mTargetSize == Vector2::ZERO )
+  {
+    return;
+  }
+
+  // Exception to the rule, chaining up first ensures visuals have SetOnStage called to create their renderers
+  Control::OnStageConnection( depth );
+
+  Actor self = Self();
+
+  for(unsigned int i=0; i<mBlurLevels+1;i++)
+  {
+    mRenderers[i] = CreateRenderer( BASIC_VERTEX_SOURCE, FRAGMENT_SHADER );
+    mRenderers[i].SetProperty( Dali::Renderer::Property::DEPTH_INDEX, (int)i );
+    self.AddRenderer( mRenderers[i] );
+
+    if( i > 0 )
+    {
+      Renderer renderer = mRenderers[i];
+      Property::Index index = renderer.RegisterProperty( ALPHA_UNIFORM_NAME, 0.f );
+      Constraint constraint = Constraint::New<float>( renderer, index, ActorOpacityConstraint(mBlurLevels, i-1) );
+      constraint.AddSource( Source( self, mBlurStrengthPropertyIndex ) );
+      constraint.Apply();
+    }
+  }
+
+  if( mInputTexture )
+  {
+    SetRendererTexture( mRenderers[0], mInputTexture );
+    unsigned int i = 1;
+    for(; i<mBlurLevels; i++)
+    {
+      SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
+    }
+    SetRendererTexture( mRenderers[i], mBlurredImage[i-1] );
+  }
+}
+
+void SuperBlurView::OnStageDisconnection()
+{
+  for(unsigned int i=0; i<mBlurLevels+1;i++)
+  {
+    Self().RemoveRenderer( mRenderers[i] );
+    mRenderers[i].Reset();
+  }
+
+  Control::OnStageDisconnection();
+}
+
+Vector3 SuperBlurView::GetNaturalSize()
+{
+  if( mInputTexture )
+  {
+    return Vector3( mInputTexture.GetWidth(), mInputTexture.GetHeight(), 0.f );
+  }
+  return Vector3::ZERO;
+}
+
+void SuperBlurView::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value )
+{
+  Toolkit::SuperBlurView superBlurView = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
+
+  if( superBlurView )
+  {
+    SuperBlurView& superBlurViewImpl( GetImpl( superBlurView ) );
+
+    if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL )
+    {
+      value.Get( superBlurViewImpl.mUrl );
+
+      PixelData pixels = SyncImageLoader::Load( superBlurViewImpl.mUrl );
+
+      if ( pixels )
+      {
+        Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
+        texture.Upload( pixels, 0, 0, 0, 0, pixels.GetWidth(), pixels.GetHeight() );
+
+        superBlurViewImpl.SetTexture( texture );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Cannot create image from property value\n" );
+      }
+    }
+  }
+}
+
+Property::Value SuperBlurView::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::SuperBlurView blurView = Toolkit::SuperBlurView::DownCast( Dali::BaseHandle( object ) );
+
+  if( blurView )
+  {
+    SuperBlurView& superBlurViewImpl( GetImpl( blurView ) );
+
+    if( propertyIndex == Toolkit::SuperBlurView::Property::IMAGE_URL )
+    {
+      value = superBlurViewImpl.mUrl;
+    }
+  }
+
+  return value;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.h b/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.h
new file mode 100644 (file)
index 0000000..585703a
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SUPER_BLUR_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_SUPER_BLUR_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/super-blur-view/super-blur-view.h>
+#include <dali-toolkit/devel-api/controls/gaussian-blur-view/gaussian-blur-view.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class SuperBlurView;
+
+namespace Internal
+{
+
+/**
+ * SuperBlurView implementation class
+ */
+class SuperBlurView : public Control
+{
+
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::New
+   */
+  static Toolkit::SuperBlurView New( unsigned int blurLevels );
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::SetImage
+   */
+  void SetTexture( Texture texture );
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::GetBlurStrengthPropertyIndex
+   */
+  Property::Index GetBlurStrengthPropertyIndex() const;
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::SetBlurStrength
+   */
+  void SetBlurStrength( float blurStrength );
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::GetCurrentBlurStrength
+   */
+  float GetCurrentBlurStrength() const;
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::BlurFinishedSignal
+   */
+  Dali::Toolkit::SuperBlurView::SuperBlurViewSignal& BlurFinishedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::SuperBlurView::GetBlurredTexture
+   */
+  Texture GetBlurredTexture( unsigned int level );
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+protected:
+
+  /**
+   * Constructor. It initializes the SuperBlurView members
+   */
+  SuperBlurView( unsigned int blurLevels );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~SuperBlurView();
+
+private: // from Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet()
+   */
+  virtual void OnSizeSet(const Vector3& targetSize);
+
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc CustomActorImpl::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+private:
+
+  /**
+   * Carry out the idx-th pass of blurring
+   * @param[in] idx The blur pass index
+   * @param[in] texture The input texture for the current blurring, it is either the original image or the blurred texture from the previous pass
+   */
+  void BlurTexture( unsigned int idx, Texture texture );
+
+  /**
+   * Signal handler to tell when the last blur view completes
+   * @param[in] blurView The blur view that just completed
+   */
+  void OnBlurViewFinished( Toolkit::GaussianBlurView blurView );
+
+  /**
+   * Clear the resources used to create the blurred image
+   */
+  void ClearBlurResource();
+
+private:
+  std::vector<Toolkit::GaussianBlurView> mGaussianBlurView;
+  std::vector<FrameBuffer>               mBlurredImage;
+  std::vector<Renderer>                  mRenderers;
+  Texture                                mInputTexture;
+  Vector2                                mTargetSize;
+
+  Toolkit::SuperBlurView::SuperBlurViewSignal mBlurFinishedSignal; ///< Signal emitted when blur has completed.
+
+  std::string                            mUrl;
+  Property::Index                        mBlurStrengthPropertyIndex;
+  unsigned int                           mBlurLevels;
+  bool                                   mResourcesCleared;
+};
+
+}
+
+// Helpers for public-api forwarding methods
+inline Toolkit::Internal::SuperBlurView& GetImpl( Toolkit::SuperBlurView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<Toolkit::Internal::SuperBlurView&>(handle);
+}
+
+inline const Toolkit::Internal::SuperBlurView& GetImpl( const Toolkit::SuperBlurView& obj )
+{
+  DALI_ASSERT_ALWAYS(obj);
+  const Dali::RefObject& handle = obj.GetImplementation();
+  return static_cast<const Toolkit::Internal::SuperBlurView&>(handle);
+}
+
+}
+
+}
+
+#endif // DALI_TOOLKIT_INTERNAL_SUPER_BLUR_VIEW_H
diff --git a/dali-toolkit/internal/controls/table-view/array-2d.h b/dali-toolkit/internal/controls/table-view/array-2d.h
new file mode 100644 (file)
index 0000000..31339c9
--- /dev/null
@@ -0,0 +1,275 @@
+#pragma once
+#ifndef DALI_ARRAY2D_H
+#define DALI_ARRAY2D_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+
+/**
+ * Helper wrapper for two dimensional array using std::vector
+ * Usage:
+ * <code>
+ *   Array2d< int > intArray( 3, 3 );
+ *   intArray[ 0 ][ 0 ] = 10;
+ *   intArray.Resize( 4, 4 );
+ * </code>
+ */
+template< typename T >
+class Array2d
+{
+public:
+
+  /**
+   * Default constructor. Creates a 0x0 array
+   */
+  Array2d()
+  : mArray( 0, std::vector< T >( 0 ) )
+  { }
+
+  /**
+   * Constructs an array with given dimensions
+   * @param [in] rows for array
+   * @param [in] columns for array
+   */
+  Array2d( unsigned int rows, unsigned int columns )
+  : mArray( rows, std::vector< T >( columns ) )
+  { }
+
+  /**
+   * Destructor
+   */
+  ~Array2d()
+  { } // Nothing to do, vector cleans up itself
+
+  /**
+   * Copy constructor
+   * @param array to copy from
+   */
+  Array2d( const Array2d& array )
+  {
+    if( this != &array )
+    {
+      mArray = array.mArray;
+    }
+  }
+
+  /**
+   * Assignment operator
+   * @param array to copy from
+   * @return reference to self for chaining
+   */
+  Array2d& operator=( const Array2d& array )
+  {
+    if( this != &array )
+    {
+      mArray = array.mArray;
+    }
+  return *this;
+  }
+
+  /**
+   * @return the number of rows in the array
+   */
+  unsigned int GetRows()
+  {
+    return mArray.size();
+  }
+
+  /**
+   * @return the number of columns in the array
+   */
+  unsigned int GetColumns()
+  {
+    if( mArray.size() > 0 )
+    {
+      // all columns are equal length
+      return mArray[ 0 ].size();
+    }
+    return 0;
+  }
+
+  /**
+   * @param [in] index of the row
+   * @return reference to the row vector for given index
+   */
+  std::vector< T >& operator[]( unsigned int index )
+  {
+    return mArray[ index ];
+  }
+
+  /**
+   * @param [in] index of the row
+   * @return const reference to the row vector for given index
+   */
+  const std::vector< T >& operator[]( unsigned int index ) const
+  {
+    return mArray[ index ];
+  }
+
+  /**
+   * Insert a new row to given index
+   * @param [in] rowIndex of the new row
+   */
+  void InsertRow( unsigned int rowIndex )
+  {
+    // insert default initialized row of elements
+    mArray.insert( mArray.begin() + rowIndex, std::vector< T >( GetColumns() ) );
+  }
+
+  /**
+   * Delete a row from given index
+   * Removed elements are deleted
+   * @param [in] rowIndex of the row to delete
+   */
+  void DeleteRow( unsigned int rowIndex )
+  {
+    // erase the row
+    mArray.erase( mArray.begin() + rowIndex );
+  }
+
+  /**
+   * Delete a row from given index
+   * @param [in] rowIndex of the row to delete
+   * @param [out] removed elements
+   */
+  void DeleteRow( unsigned int rowIndex, std::vector< T >& removed )
+  {
+    // copy the row elements
+    removed.insert( removed.end(), mArray[ rowIndex ].begin(), mArray[ rowIndex ].end() );
+    // erase the row
+    mArray.erase( mArray.begin() + rowIndex );
+  }
+
+  /**
+   * Insert a new column to given index
+   * @param [in] columnIndex of the new column
+   */
+  void InsertColumn( unsigned int columnIndex )
+  {
+    // go through all rows
+    const unsigned int rows = GetRows();
+    for( unsigned int i = 0; i < rows; ++i )
+    {
+      // insert default initialized element
+      mArray[ i ].insert( mArray[ i ].begin() + columnIndex, T() );
+    }
+  }
+
+  /**
+   * Delete a column from given index.
+   * Removed elements are deleted
+   * @param [in] columnIndex of the column to delete
+   */
+  void DeleteColumn( unsigned int columnIndex )
+  {
+    // go through all rows
+    const unsigned int rows = GetRows();
+    for( unsigned int i = 0; i < rows; ++i )
+    {
+      // erase the column
+      mArray[ i ].erase( mArray[ i ].begin() + columnIndex );
+    }
+  }
+
+  /**
+   * Delete a column from given index
+   * @param [in] columnIndex of the column to delete
+   * @param [out] removed elements
+   */
+  void DeleteColumn( unsigned int columnIndex, std::vector< T >& removed )
+  {
+    // go through all rows
+    const unsigned int rows = GetRows();
+    for( unsigned int i = 0; i < rows; ++i )
+    {
+      // copy the column element of this row
+      removed.push_back( mArray[ i ][ columnIndex ] );
+      // erase the column
+      mArray[ i ].erase( mArray[ i ].begin() + columnIndex );
+    }
+  }
+
+  /**
+   * Resizes the array to given dimensions
+   * If new size is smaller in either dimension, items that wont fit will be deleted
+   * @param [in] rows for array
+   * @param [in] columns for array
+   */
+  void Resize( unsigned int rows, unsigned int columns )
+  {
+    // resize rows first, may increase or decrease size
+    mArray.resize( rows );
+    for( unsigned int i = 0; i < rows; ++i )
+    {
+      // resize each column, may increase or decrease size
+      mArray[ i ].resize( columns );
+    }
+  }
+
+  /**
+   * Resizes the array to given dimensions
+   * If new size is smaller, items that wont fit will be returned to caller
+   * @param [in] rows for array
+   * @param [in] columns for array
+   * @param [out] removed elements in case array is smaller in either dimension
+   */
+  void Resize( unsigned int rows, unsigned int columns, std::vector< T >& removed )
+  {
+    // remember old counts
+    const unsigned int oldRows = GetRows();
+    const unsigned int oldColumns = GetColumns();
+    // are rows being removed ?
+    if( rows < oldRows )
+    {
+      // gather the elements of removed rows
+      for( unsigned int i = rows; i < oldRows; ++i )
+      {
+        // copy the row elements, the whole row is gone
+        removed.insert( removed.end(), mArray[ i ].begin(), mArray[ i ].end() );
+      }
+    }
+    // resize the rows, may increase or decrease size
+    mArray.resize( rows );
+    // process columns, need to do all rows as also columns for new row need resizing
+    for( unsigned int i = 0; i < rows; ++i )
+    {
+      // if this is an old row and columns are being removed
+      if( ( i < oldRows )&&( columns < oldColumns ) )
+      {
+        // copy the columns, the end of row from columns is gone
+        removed.insert( removed.end(), mArray[ i ].begin() + columns, mArray[ i ].end() );
+      }
+      // resize the column, may increase of decrease size
+      mArray[ i ].resize( columns );
+    }
+  }
+
+private:
+
+  std::vector< std::vector< T > > mArray;
+
+};
+
+} // namespace Dali
+
+#endif // DALI_ARRAY2D_H
diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp
new file mode 100755 (executable)
index 0000000..b4e81c7
--- /dev/null
@@ -0,0 +1,1716 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/table-view/table-view-impl.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/integration-api/debug.h>
+
+using namespace Dali;
+
+namespace
+{
+/**
+ * @brief Should the tableview fit around the given actor
+ *
+ * @param[in] actor The child actor to test against
+ * @param[dimension] The dimension to test against
+ */
+bool FitToChild( Actor actor, Dimension::Type dimension )
+{
+  return actor.GetResizePolicy( dimension ) != ResizePolicy::FILL_TO_PARENT && actor.GetRelayoutSize( dimension ) > 0.0f;
+}
+
+#if defined(DEBUG_ENABLED)
+// debugging support, very useful when new features are added or bugs are hunted down
+// currently not called from code so compiler will optimize these away, kept here for future debugging
+
+#define TABLEVIEW_TAG "DALI Toolkit::TableView "
+#define TV_LOG(fmt, args,...) Debug::LogMessage(Debug::DebugInfo, TABLEVIEW_TAG fmt, ## args)
+//#define TABLEVIEW_DEBUG 1
+
+#if defined(TABLEVIEW_DEBUG)
+void PrintArray( Array2d<Dali::Toolkit::Internal::TableView::CellData>& array )
+{
+  TV_LOG( "Array2d<CellData> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
+  // print values
+  for( unsigned int i = 0; i < array.GetRows(); ++i )
+  {
+    for( unsigned int j = 0; j < array.GetColumns(); ++j )
+    {
+      Dali::Toolkit::Internal::TableView::CellData data = array[i][j];
+      char actor = ' ';
+      std::string actorName;
+      if( data.actor )
+      {
+        actor = 'A';
+        actorName = data.actor.GetName();
+      }
+      TV_LOG("Array[%d,%d]=%c %s %d,%d,%d,%d  ", i, j, actor, actorName.c_str(),
+          data.position.rowIndex, data.position.columnIndex,
+          data.position.rowSpan, data.position.columnSpan );
+    }
+    TV_LOG( "\n" );
+  }
+}
+
+// debugging support, very useful when new features are added or bugs are hunted down
+// currently not called from code so compiler will optimize these away, kept here for future debugging
+void PrintArray( Array2d<Size>& array )
+{
+  TV_LOG( "Array2d<Size> size [%d,%d] \n", array.GetRows(), array.GetColumns() );
+  // print values
+  for( unsigned int i = 0; i < array.GetRows(); ++i )
+  {
+    for( unsigned int j = 0; j < array.GetColumns(); ++j )
+    {
+      TV_LOG( "Array[%d,%d]=%.2f,%.2f ", i, j, array[i][j].width, array[i][j].height );
+    }
+    TV_LOG( "\n" );
+  }
+}
+// debugging support, very useful when new features are added or bugs are hunted down
+// currently not called from code so compiler will optimize these away, kept here for future debugging
+void PrintVector( std::vector<float>& array )
+{
+  TV_LOG( "vector, size [%d]\n", array.size() );
+  // print values
+  for( unsigned int i = 0; i < array.size(); ++i )
+  {
+    TV_LOG( "vector[%d]=%.2f ", i, array[i] );
+  }
+  TV_LOG( "\n" );
+}
+#endif // defined(TABLEVIEW_DEBUG)
+#endif // defined(DEBUG_ENABLED)
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::TableView::New( 0, 0 );
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TableView, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "rows",           INTEGER, ROWS           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "columns",        INTEGER, COLUMNS        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "cellPadding",    VECTOR2, CELL_PADDING   )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutRows",     MAP,     LAYOUT_ROWS    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TableView, "layoutColumns",  MAP,     LAYOUT_COLUMNS )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellIndex",                VECTOR2, CELL_INDEX                )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "rowSpan",                  INTEGER, ROW_SPAN                  )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "columnSpan",               INTEGER, COLUMN_SPAN               )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellHorizontalAlignment",  STRING,  CELL_HORIZONTAL_ALIGNMENT )
+DALI_CHILD_PROPERTY_REGISTRATION( Toolkit, TableView, "cellVerticalAlignment",    STRING,  CELL_VERTICAL_ALIGNMENT   )
+
+DALI_TYPE_REGISTRATION_END()
+
+const Scripting::StringEnum LAYOUT_POLICY_STRING_TABLE[] =
+{
+ { "fixed",    Toolkit::TableView::FIXED    },
+ { "relative", Toolkit::TableView::RELATIVE },
+ { "fill",     Toolkit::TableView::FILL     },
+ { "fit",      Toolkit::TableView::FIT      }
+};
+const unsigned int LAYOUT_POLICY_STRING_TABLE_COUNT = sizeof(LAYOUT_POLICY_STRING_TABLE) / sizeof( LAYOUT_POLICY_STRING_TABLE[0] );
+
+const Scripting::StringEnum HORIZONTAL_ALIGNMENT_STRING_TABLE[] =
+{
+  {"left",   HorizontalAlignment::LEFT},
+  {"center", HorizontalAlignment::CENTER},
+  {"right",  HorizontalAlignment::RIGHT}
+};
+const unsigned int HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(HORIZONTAL_ALIGNMENT_STRING_TABLE) / sizeof( HORIZONTAL_ALIGNMENT_STRING_TABLE[0] );
+
+const Scripting::StringEnum VERTICAL_ALIGNMENT_STRING_TABLE[] =
+{
+  {"top",    VerticalAlignment::TOP},
+  {"center", VerticalAlignment::CENTER},
+  {"bottom", VerticalAlignment::BOTTOM}
+};
+const unsigned int VERTICAL_ALIGNMENT_STRING_TABLE_COUNT = sizeof(VERTICAL_ALIGNMENT_STRING_TABLE) / sizeof( VERTICAL_ALIGNMENT_STRING_TABLE[0] );
+
+} // Unnamed namespace
+
+Toolkit::TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TableView > impl = new TableView( initialRows, initialColumns );
+
+  // Pass ownership to CustomActor handle
+  Toolkit::TableView handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+bool TableView::AddChild( Actor& child, const Toolkit::TableView::CellPosition& position )
+{
+  // check that the child is valid
+  DALI_ASSERT_ALWAYS( child );
+
+  // if child is already parented, we adopt it
+  child.Unparent();
+
+  // check if we need to expand our data array
+  if( position.rowIndex >= mCellData.GetRows() )
+  {
+    // only adding new rows
+    ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
+  }
+
+  if( position.columnIndex >= mCellData.GetColumns() )
+  {
+    // only adding new columns
+    ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
+  }
+
+  // check if there already is something in this cell
+  if( mCellData[ position.rowIndex ][ position.columnIndex ].actor )
+  {
+    return false; // cannot share a cell, it would complicate all logic and not bring much benefit
+  }
+
+  RelayoutingLock lock( *this );
+  // adopt the child
+  Self().Add( child );
+
+  // if child spans multiple rows of columns
+  if( ( position.rowSpan > 1 ) && ( position.rowIndex + position.rowSpan > mCellData.GetRows() ) )
+  {
+    // increase table size for the full span, only increasing rows
+    ResizeContainers( position.rowIndex + position.rowSpan, mCellData.GetColumns() );
+  }
+
+  if( ( position.columnSpan > 1 ) && ( position.columnIndex + position.columnSpan > mCellData.GetColumns() ) )
+  {
+    // increase table size for the full span, only increasing columns
+    ResizeContainers( mCellData.GetRows(), position.columnIndex + position.columnSpan );
+  }
+
+  // Fill in all cells that need the data
+  CellData data;
+  data.actor = child;
+  data.position = position;
+
+  for( unsigned int row = position.rowIndex; row < ( position.rowIndex + position.rowSpan ); ++row )
+  {
+    // store same information to all cells, this way we can identify
+    // if a cell is the prime location of an actor or a spanned one
+    for( unsigned int column = position.columnIndex; column < ( position.columnIndex + position.columnSpan ); ++column )
+    {
+      // store same information to all cells, this way we can identify
+      // if a cell is the prime location of an actor or a spanned one
+      mCellData[ row ][ column ] = data;
+    }
+  }
+
+  // Relayout the whole table
+  if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT && position.rowSpan == 1 )
+  {
+    mRowDirty = true;
+  }
+  if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT && position.columnSpan == 1 )
+  {
+    mColumnDirty = true;
+  }
+
+  RelayoutRequest();
+
+  return true;    // Addition successful
+}
+
+Actor TableView::GetChildAt( const Toolkit::TableView::CellPosition& position )
+{
+  if( ( position.rowIndex < mCellData.GetRows() ) && ( position.columnIndex < mCellData.GetColumns() ) )
+  {
+    return mCellData[ position.rowIndex ][ position.columnIndex ].actor;
+  }
+
+  // Return an empty handle
+  return Actor();
+}
+
+Actor TableView::RemoveChildAt( const Toolkit::TableView::CellPosition& position )
+{
+  // get the child handle
+  Actor child = GetChildAt( position );
+  // if no real actor there, nothing else to be done
+  if( child )
+  {
+    RelayoutingLock lock( *this );
+    // Remove the child, this will trigger a call to OnChildRemove
+    Self().Remove( child );
+
+    // relayout the table only if instances were found
+    if( RemoveAllInstances( child ) )
+    {
+      if( mRowData[position.rowIndex].sizePolicy == Toolkit::TableView::FIT )
+      {
+        mRowDirty = true;
+      }
+      if( mColumnData[position.columnIndex].sizePolicy == Toolkit::TableView::FIT )
+      {
+        mColumnDirty = true;
+      }
+      RelayoutRequest();
+    }
+  }
+  // return the child back to caller
+  return child;
+}
+
+bool TableView::FindChildPosition( const Actor& child, Toolkit::TableView::CellPosition& positionOut )
+{
+  // Only find valid child actors
+  if( child )
+  {
+    // Walk through the layout data
+    const unsigned int rowCount = mCellData.GetRows();
+    const unsigned int columnCount = mCellData.GetColumns();
+
+    for( unsigned int row = 0; row < rowCount; ++row )
+    {
+      for( unsigned int column = 0; column < columnCount; ++column )
+      {
+        if( mCellData[ row ][ column ].actor == child )
+        {
+          positionOut = mCellData[ row ][ column ].position;
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
+void TableView::InsertRow( unsigned int rowIndex )
+{
+  RelayoutingLock lock( *this );
+
+  mCellData.InsertRow( rowIndex );
+
+  // Need to update the cell infos for the items that moved
+  const unsigned int rowCount = mCellData.GetRows();
+  const unsigned int columnCount = mCellData.GetColumns();
+
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
+    for( unsigned int column = 0; column < columnCount; ++column )
+    {
+      Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
+
+      // If cell is spanning and above and spans to inserted row
+      if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
+          ( position.rowIndex + position.rowSpan > rowIndex ) )
+      {
+        // Increment span
+        position.rowSpan++;
+
+        // Copy cell to occupy the new column
+        mCellData[ rowIndex ][ column ] = mCellData[ row ][ column ];
+      }
+      else if( row > rowIndex )   // If below of inserted row, increase row index
+      {
+        // Increment index
+        position.rowIndex++;
+      }
+    }
+  }
+
+  // Expand row data array
+  mRowData.Insert( mRowData.Begin() + rowIndex, RowColumnData() );
+
+  // Sizes may have changed, so relayout
+  mRowDirty = true;
+  RelayoutRequest();
+}
+
+void TableView::DeleteRow( unsigned int rowIndex )
+{
+  std::vector< Actor > ignored;
+  DeleteRow( rowIndex, ignored );
+}
+
+void TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
+{
+  RelayoutingLock lock( *this );
+
+  // Delete the row
+  std::vector< CellData > lost;
+  mCellData.DeleteRow( rowIndex, lost );
+
+  // Need to update the cell infos for the items that moved
+  const unsigned int rowCount = mCellData.GetRows();
+  const unsigned int columnCount = mCellData.GetColumns();
+
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
+    for( unsigned int column = 0; column < columnCount; ++column )
+    {
+      Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
+
+      // If cell is spanning and above and spans to deleted row
+      if( ( position.rowSpan > 1 ) && ( position.rowIndex <= rowIndex ) &&
+          ( position.rowIndex + position.rowSpan > rowIndex ) )
+      {
+        // Decrement span
+        if( position.rowSpan > 1 )
+        {
+          position.rowSpan--;
+        }
+      }
+      else if( row >= rowIndex )    // If below of or at the inserted row, decrease row index
+      {
+        // Decrement index
+        if( position.rowIndex > 0 )
+        {
+          position.rowIndex--;
+        }
+      }
+    }
+  }
+
+  // 1 row removed, 0 columns
+  RemoveAndGetLostActors( lost, removed, 1u, 0u );
+
+  // Contract row data array
+  mRowData.Erase( mRowData.Begin() + rowIndex );
+
+  // Sizes may have changed, so relayout
+  mRowDirty = true;
+  // it is possible that the deletion of row leads to remove of child which might further lead to the change of FIT column
+  mColumnDirty = true;
+
+  RelayoutRequest();
+}
+
+void TableView::InsertColumn( unsigned int columnIndex )
+{
+  RelayoutingLock lock( *this );
+
+  // Insert the new column
+  mCellData.InsertColumn( columnIndex );
+
+  // Need to update the cell infos for the items that moved
+  const unsigned int rowCount = mCellData.GetRows();
+  const unsigned int columnCount = mCellData.GetColumns();
+
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
+    for( unsigned int column = 0; column < columnCount; ++column )
+    {
+      Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
+
+      // If cell is spanning and left side and spans to inserted column
+      if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
+          ( position.columnIndex + position.columnSpan > columnIndex ) )
+      {
+        // Increment span
+        position.columnSpan++;
+
+        // Copy cell to occupy the new column
+        mCellData[ row ][ columnIndex ] = mCellData[ row ][ column ];
+      }
+      else if( column > columnIndex )   // If on the right side of inserted column, increase column index
+      {
+        // Increment index
+        position.columnIndex++;
+      }
+    }
+  }
+
+  // Expand column data array
+  mColumnData.Insert( mColumnData.Begin() + columnIndex, RowColumnData() );
+
+  // Sizes may have changed so relayout
+  mColumnDirty = true;
+  RelayoutRequest();
+}
+
+void TableView::DeleteColumn( unsigned int columnIndex )
+{
+  std::vector< Actor > ignored;
+  DeleteColumn( columnIndex, ignored );
+}
+
+void TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
+{
+  RelayoutingLock lock( *this );
+
+  // Remove the column
+  std::vector< CellData > lost;
+  mCellData.DeleteColumn( columnIndex, lost );
+
+  // Need to update the cell infos for the items that moved
+  const unsigned int rowCount = mCellData.GetRows();
+  const unsigned int columnCount = mCellData.GetColumns();
+
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
+    for( unsigned int column = 0; column < columnCount; ++column )
+    {
+      Toolkit::TableView::CellPosition& position = mCellData[ row ][ column ].position;
+
+      // If cell is spanning and left side and spans to inserted column
+      if( ( position.columnSpan > 1 ) && ( position.columnIndex <= columnIndex ) &&
+          ( position.columnIndex + position.columnSpan > columnIndex ) )
+      {
+        // Decrement span
+        if( position.columnSpan > 1 )
+        {
+          position.columnSpan--;
+        }
+      }
+      else if( column >= columnIndex )    // If on the right side of or at the inserted column, decrease column index
+      {
+        // Decrement index
+        if( position.columnIndex > 0 )
+        {
+          position.columnIndex--;
+        }
+      }
+    }
+  }
+
+  // 0 rows, 1 column removed
+  RemoveAndGetLostActors( lost, removed, 0u, 1u );
+
+  // Contract column data array
+  mColumnData.Erase( mColumnData.Begin() + columnIndex );
+
+  // Size may have changed so relayout
+  mColumnDirty = true;
+  // it is possible that the deletion of column leads to remove of child which might further lead to the change of FIT row
+  mRowDirty = true;
+
+  RelayoutRequest();
+}
+
+void TableView::Resize( unsigned int rows, unsigned int columns )
+{
+  std::vector< Actor > ignored;
+  Resize( rows, columns, ignored );
+}
+
+void TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
+{
+  RelayoutingLock lock( *this );
+
+  unsigned int oldRows = GetRows();
+  unsigned int oldColumns = GetColumns();
+
+  // Resize data array
+  std::vector< CellData > lost;
+  ResizeContainers( rows, columns, lost );
+
+  // Calculate if we lost rows
+  unsigned int rowsRemoved = 0;
+  unsigned int newRows = GetRows();
+
+  if( oldRows < newRows )
+  {
+    rowsRemoved = newRows - oldRows;
+  }
+
+  // Calculate if we lost columns
+  unsigned int columnsRemoved = 0;
+  unsigned int newColumns = GetColumns();
+  if( oldColumns < newColumns )
+  {
+    rowsRemoved = newColumns - oldColumns;
+  }
+
+  RemoveAndGetLostActors( lost, removed, rowsRemoved, columnsRemoved );
+
+  // Sizes may have changed so request a relayout
+  mRowDirty = true;
+  mColumnDirty = true;
+  RelayoutRequest();
+}
+
+void TableView::SetCellPadding( Size padding )
+{
+  // If padding really changed
+  if( padding != mPadding )
+  {
+    mPadding = padding;
+
+    RelayoutRequest();
+  }
+}
+
+Size TableView::GetCellPadding()
+{
+  return mPadding;
+}
+
+void TableView::SetFitHeight( unsigned int rowIndex )
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  if( mRowData[ rowIndex ].sizePolicy != Toolkit::TableView::FIT )
+  {
+    mRowData[ rowIndex ].sizePolicy = Toolkit::TableView::FIT;
+
+    mRowDirty = true;
+    RelayoutRequest();
+  }
+}
+
+bool TableView::IsFitHeight( unsigned int rowIndex ) const
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  return mRowData[ rowIndex ].sizePolicy == Toolkit::TableView::FIT;
+}
+
+void TableView::SetFitWidth( unsigned int columnIndex )
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  if( mColumnData[ columnIndex ].sizePolicy != Toolkit::TableView::FIT )
+  {
+    mColumnData[ columnIndex ].sizePolicy = Toolkit::TableView::FIT;
+
+    mColumnDirty = true;
+    RelayoutRequest();
+  }
+}
+
+bool TableView::IsFitWidth( unsigned int columnIndex ) const
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  return mColumnData[ columnIndex ].sizePolicy == Toolkit::TableView::FIT;
+}
+
+void TableView::SetFixedHeight( unsigned int rowIndex, float height )
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  RowColumnData& data = mRowData[ rowIndex ];
+  data.size = height;
+  data.sizePolicy = Toolkit::TableView::FIXED;
+
+  mRowDirty = true;
+  RelayoutRequest();
+}
+
+float TableView::GetFixedHeight( unsigned int rowIndex ) const
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  return mRowData[ rowIndex ].size;
+}
+
+void TableView::SetFixedWidth( unsigned int columnIndex, float width )
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  RowColumnData& data = mColumnData[ columnIndex ];
+  data.size = width;
+  data.sizePolicy = Toolkit::TableView::FIXED;
+
+  mColumnDirty = true;
+  RelayoutRequest();
+}
+
+float TableView::GetFixedWidth( unsigned int columnIndex ) const
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  return mColumnData[ columnIndex ].size;
+}
+
+void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  RowColumnData& data = mRowData[ rowIndex ];
+  data.fillRatio = heightPercentage;
+  data.sizePolicy = Toolkit::TableView::RELATIVE;
+
+  mRowDirty = true;
+  RelayoutRequest();
+}
+
+float TableView::GetRelativeHeight( unsigned int rowIndex ) const
+{
+  DALI_ASSERT_ALWAYS( rowIndex < mRowData.Size() );
+
+  return mRowData[ rowIndex ].fillRatio;
+}
+
+void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  RowColumnData& data = mColumnData[ columnIndex ];
+  data.fillRatio = widthPercentage;
+  data.sizePolicy = Toolkit::TableView::RELATIVE;
+
+  mColumnDirty = true;
+  RelayoutRequest();
+}
+
+float TableView::GetRelativeWidth( unsigned int columnIndex ) const
+{
+  DALI_ASSERT_ALWAYS( columnIndex < mColumnData.Size() );
+
+  return mColumnData[ columnIndex ].fillRatio;
+}
+
+void TableView::OnCalculateRelayoutSize( Dimension::Type dimension )
+{
+  if( (dimension & Dimension::WIDTH) && mColumnDirty )
+  {
+    /*
+     * FIXED and FIT have size in pixel
+     * Nothing to do with FIXED, as its value is assigned by user and will not get changed
+     *
+     * Need to update the size for FIT column here
+     */
+    CalculateFitSizes( mColumnData, Dimension::WIDTH );
+
+    /* RELATIVE and FILL have size in ratio
+     * Their size in pixel is not available until we get the negotiated size for the whole table
+     * Nothing to do with RELATIVE, as its ratio is assigned by user and will not get changed
+     *
+     * Need to update the ratio for FILL column here
+     */
+    CalculateFillSizes( mColumnData );
+
+    mFixedTotals.width = CalculateTotalFixedSize( mColumnData );
+  }
+
+  if( (dimension & Dimension::HEIGHT) && mRowDirty )
+  {
+    // refer to the comment above
+    CalculateFitSizes( mRowData, Dimension::HEIGHT );
+
+    // refer to the comment above
+    CalculateFillSizes( mRowData );
+
+    mFixedTotals.height = CalculateTotalFixedSize( mRowData );
+  }
+}
+
+void TableView::OnLayoutNegotiated( float size, Dimension::Type dimension )
+{
+  // Update the column sizes
+  if( (dimension & Dimension::WIDTH) && mColumnDirty )
+  {
+    float remainingSize = size - mFixedTotals.width;
+    if( remainingSize < 0.0f )
+    {
+      remainingSize = 0.0f;
+    }
+
+    // update every column position in ColumnData array
+    float cumulatedWidth = 0.0f;
+    for( auto&& element : mColumnData )
+    {
+      if( element.sizePolicy == Toolkit::TableView::FILL || element.sizePolicy == Toolkit::TableView::RELATIVE )
+      {
+        element.size = element.fillRatio * remainingSize;
+      }
+
+      cumulatedWidth += element.size;
+      element.position = cumulatedWidth;
+    }
+
+    mColumnDirty = false;
+  }
+
+  // Update the row sizes
+  if( (dimension & Dimension::HEIGHT) && mRowDirty )
+  {
+    float remainingSize = size - mFixedTotals.height;
+    if( remainingSize < 0.0f )
+    {
+      remainingSize = 0.0f;
+    }
+
+    // update every row position in RowData array
+    float cumulatedHeight = 0.0f;
+    for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
+    {
+      if( mRowData[ row ].sizePolicy == Toolkit::TableView::FILL ||  mRowData[ row ].sizePolicy == Toolkit::TableView::RELATIVE)
+      {
+        mRowData[ row ].size = mRowData[ row ].fillRatio * remainingSize;
+      }
+
+      cumulatedHeight += mRowData[ row ].size;
+      mRowData[row].position = cumulatedHeight;
+    }
+
+    mRowDirty = false;
+  }
+}
+
+void TableView::OnSizeSet( const Vector3& size )
+{
+  // If this table view is size negotiated by another actor or control, then the
+  // rows and columns must be recalculated or the new size will not take effect.
+  mRowDirty = mColumnDirty = true;
+  RelayoutRequest();
+
+  Control::OnSizeSet( size );
+}
+
+void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  // Go through the layout data
+  float totalWidth = 0.0;
+
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>() );
+
+  if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+  {
+    for (auto&& element : mColumnData)
+    {
+      totalWidth += element.size;
+    }
+  }
+
+  for( unsigned int row = 0, rowCount = mCellData.GetRows(); row < rowCount; ++row )
+  {
+    for( unsigned int column = 0, columnCount = mCellData.GetColumns(); column < columnCount; ++column )
+    {
+      CellData& cellData= mCellData[ row ][ column ];
+      Actor& actor = cellData.actor;
+      const Toolkit::TableView::CellPosition position = cellData.position;
+
+      // If there is an actor and this is the main cell of the actor.
+      // An actor can be in multiple cells if its row or column span is more than 1.
+      // We however must lay out each actor only once.
+      if( actor &&  position.rowIndex == row && position.columnIndex == column )
+      {
+        // Anchor actor to top left of the cell
+        if( actor.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >() )
+        {
+          actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+        }
+        actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+
+        Padding padding;
+        actor.GetPadding( padding );
+
+        float left = (column > 0) ? mColumnData[column - 1].position : 0.f;
+        float right;
+
+        if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+        {
+          right = totalWidth - left;
+          left = right - mColumnData[column].size;
+        }
+        else
+        {
+          right = left + mColumnData[column].size;
+        }
+
+        float top = row > 0 ? mRowData[row-1].position : 0.f;
+        float bottom = mRowData[row+position.rowSpan-1].position;
+
+        if( cellData.horizontalAlignment == HorizontalAlignment::LEFT )
+        {
+          actor.SetX( left + mPadding.width + padding.left );
+        }
+        else if( cellData.horizontalAlignment ==  HorizontalAlignment::RIGHT )
+        {
+          actor.SetX( right - mPadding.width - padding.right - actor.GetRelayoutSize( Dimension::WIDTH ) );
+        }
+        else //if( cellData.horizontalAlignment ==  HorizontalAlignment::CENTER )
+        {
+          actor.SetX( (left + right + padding.left - padding.right - actor.GetRelayoutSize( Dimension::WIDTH )) * 0.5f );
+        }
+
+        if( cellData.verticalAlignment == VerticalAlignment::TOP )
+        {
+          actor.SetY( top + mPadding.height + padding.top );
+        }
+        else if( cellData.verticalAlignment == VerticalAlignment::BOTTOM )
+        {
+          actor.SetY( bottom - mPadding.height - padding.bottom -  actor.GetRelayoutSize( Dimension::HEIGHT ) );
+        }
+        else //if( cellData.verticalAlignment = VerticalAlignment::CENTER )
+        {
+          actor.SetY( (top + bottom + padding.top - padding.bottom - actor.GetRelayoutSize( Dimension::HEIGHT )) * 0.5f );
+        }
+      }
+    }
+  }
+}
+
+unsigned int TableView::GetRows()
+{
+  return mCellData.GetRows();
+}
+
+unsigned int TableView::GetColumns()
+{
+  return mCellData.GetColumns();
+}
+
+void TableView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
+
+  if( tableView )
+  {
+    TableView& tableViewImpl( GetImpl( tableView ) );
+    switch( index )
+    {
+      case Toolkit::TableView::Property::ROWS:
+      {
+        int rows = 0;
+        if( value.Get( rows ) && rows >= 0 )
+        {
+          if( static_cast<unsigned int>(rows) != tableViewImpl.GetRows() )
+          {
+            tableViewImpl.Resize( rows, tableViewImpl.GetColumns() );
+          }
+        }
+        break;
+      }
+      case Toolkit::TableView::Property::COLUMNS:
+      {
+        int columns = 0;
+        if( value.Get( columns ) && columns >= 0 )
+        {
+          if( static_cast<unsigned int>( columns ) != tableViewImpl.GetColumns() )
+          {
+            tableViewImpl.Resize( tableViewImpl.GetRows(), value.Get<int>() );
+          }
+        }
+        break;
+      }
+      case Toolkit::TableView::Property::CELL_PADDING:
+      {
+        tableViewImpl.SetCellPadding( value.Get<Vector2>() );
+        break;
+      }
+      case Toolkit::TableView::Property::LAYOUT_ROWS:
+      {
+        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedHeight, &TableView::SetRelativeHeight, &TableView::SetFitHeight, value );
+        break;
+      }
+      case Toolkit::TableView::Property::LAYOUT_COLUMNS:
+      {
+        SetHeightOrWidthProperty( tableViewImpl, &TableView::SetFixedWidth, &TableView::SetRelativeWidth, &TableView::SetFitWidth, value );
+        break;
+      }
+    }
+  }
+}
+
+Property::Value TableView::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TableView tableView = Toolkit::TableView::DownCast( Dali::BaseHandle( object ) );
+
+  if( tableView )
+  {
+    TableView& tableViewImpl( GetImpl( tableView ) );
+    switch( index )
+    {
+      case Toolkit::TableView::Property::ROWS:
+      {
+        value = static_cast<int>( tableViewImpl.GetRows() );
+        break;
+      }
+      case Toolkit::TableView::Property::COLUMNS:
+      {
+        value = static_cast<int>( tableViewImpl.GetColumns() );
+        break;
+      }
+      case Toolkit::TableView::Property::CELL_PADDING:
+      {
+        value = tableViewImpl.GetCellPadding();
+        break;
+      }
+      case Toolkit::TableView::Property::LAYOUT_ROWS:
+      {
+        value = tableViewImpl.GetRowHeightsPropertyValue();
+        break;
+      }
+      case Toolkit::TableView::Property::LAYOUT_COLUMNS:
+      {
+        value = tableViewImpl.GetColumnWidthsPropertyValue();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void TableView::OnChildAdd( Actor& child )
+{
+  if( ! mLayoutingChild )
+  {
+    // Ensure we're not in the middle of laying out children
+
+    // Check child properties on actor to decide its position inside the table
+    HorizontalAlignment::Type horizontalAlignment = HorizontalAlignment::LEFT;
+    VerticalAlignment::Type verticalAlignment = VerticalAlignment::TOP;
+
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ) != Property::NONE )
+    {
+      std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_HORIZONTAL_ALIGNMENT ).Get<std::string >();
+      Scripting::GetEnumeration< HorizontalAlignment::Type >( value.c_str(),
+                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE,
+                                                              HORIZONTAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                              horizontalAlignment );
+    }
+
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ) != Property::NONE )
+    {
+      std::string value = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_VERTICAL_ALIGNMENT ).Get<std::string >();
+      Scripting::GetEnumeration< VerticalAlignment::Type >( value.c_str(),
+                                                            VERTICAL_ALIGNMENT_STRING_TABLE,
+                                                            VERTICAL_ALIGNMENT_STRING_TABLE_COUNT,
+                                                            verticalAlignment );
+    }
+
+    Toolkit::TableView::CellPosition cellPosition;
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::ROW_SPAN ) != Property::NONE )
+    {
+      cellPosition.rowSpan = child.GetProperty( Toolkit::TableView::ChildProperty::ROW_SPAN ).Get< int >();
+    }
+
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::COLUMN_SPAN ) != Property::NONE )
+    {
+      cellPosition.columnSpan = child.GetProperty( Toolkit::TableView::ChildProperty::COLUMN_SPAN ).Get< int >();
+    }
+
+    if( child.GetPropertyType( Toolkit::TableView::ChildProperty::CELL_INDEX ) != Property::NONE )
+    {
+      Vector2 indices = child.GetProperty( Toolkit::TableView::ChildProperty::CELL_INDEX ).Get<Vector2 >();
+      cellPosition.rowIndex = static_cast<unsigned int>( indices.x );
+      cellPosition.columnIndex = static_cast<unsigned int>( indices.y );
+
+      AddChild( child, cellPosition );
+      SetCellAlignment(cellPosition, horizontalAlignment, verticalAlignment);
+    }
+    else
+    {
+      bool availableCellFound = false;
+
+      // Find the first available cell to store the actor in
+      const unsigned int rowCount = mCellData.GetRows();
+      const unsigned int columnCount = mCellData.GetColumns();
+      for( unsigned int row = 0; row < rowCount && !availableCellFound; ++row )
+      {
+        for( unsigned int column = 0; column < columnCount && !availableCellFound; ++column )
+        {
+          if( !(mCellData[ row ][ column ].actor) )
+          {
+            // Put the actor in the cell
+            CellData data;
+            data.actor = child;
+            data.position.columnIndex = column;
+            data.position.rowIndex = row;
+            data.horizontalAlignment = horizontalAlignment;
+            data.verticalAlignment = verticalAlignment;
+            mCellData[ row ][ column ] = data;
+
+            availableCellFound = true;
+            break;
+          }
+        }
+      }
+
+      if( ! availableCellFound )
+      {
+        // No empty cells, so increase size of the table
+        unsigned int newColumnCount = ( columnCount > 0 ) ? columnCount : 1;
+        ResizeContainers( rowCount + 1, newColumnCount );
+
+        // Put the actor in the first cell of the new row
+        CellData data;
+        data.actor = child;
+        data.position.rowIndex = rowCount;
+        data.position.columnIndex = 0;
+        data.horizontalAlignment = horizontalAlignment;
+        data.verticalAlignment = verticalAlignment;
+        mCellData[ rowCount ][ 0 ] = data;
+      }
+
+      RelayoutRequest();
+    }
+  }
+
+  Control::OnChildAdd( child );
+}
+
+void TableView::OnChildRemove( Actor& child )
+{
+  // dont process if we're in the middle of bigger operation like delete row, column or resize
+  if( !mLayoutingChild )
+  {
+    // relayout the table only if instances were found
+    if( RemoveAllInstances( child ) )
+    {
+      RelayoutRequest();
+    }
+  }
+
+  Control::OnChildRemove( child );
+}
+
+TableView::TableView( unsigned int initialRows, unsigned int initialColumns )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mCellData( initialRows, initialColumns ),
+  mPreviousFocusedActor(),
+  mLayoutingChild( false ),
+  mRowDirty( true ),     // Force recalculation first time
+  mColumnDirty( true )
+{
+  SetKeyboardNavigationSupport( true );
+  ResizeContainers( initialRows, initialColumns );
+}
+
+void TableView::OnInitialize()
+{
+  // Make self as keyboard focusable and focus group
+  Actor self = Self();
+  self.SetKeyboardFocusable(true);
+  SetAsKeyboardFocusGroup(true);
+}
+
+void TableView::ResizeContainers( unsigned int rows, unsigned int columns )
+{
+  std::vector<CellData> ignored;
+  ResizeContainers( rows, columns, ignored );
+}
+
+void TableView::ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed )
+{
+  // Resize cell data
+  mCellData.Resize( rows, columns, removed );
+
+  // We don't care if these go smaller, data will be regenerated or is not needed anymore
+  mRowData.Resize( rows );
+  mColumnData.Resize( columns );
+}
+
+void TableView::RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
+                                        unsigned int rowsRemoved, unsigned int columnsRemoved )
+{
+  // iterate through all lost cells
+  std::vector< CellData >::const_iterator iter = lost.begin();
+  for( ; iter != lost.end(); ++iter )
+  {
+    // if it is a valid actor
+    if( (*iter).actor )
+    {
+      // is this actor still somewhere else in the table
+      Toolkit::TableView::CellPosition position;
+      if( FindChildPosition( (*iter).actor, position ) )
+      {
+        // it must be spanning multiple cells, position contains the top left most one
+        // check if position is left of the removed location
+        if( position.columnIndex < (*iter).position.columnIndex )
+        {
+          // if column span is greater than 1
+          if( mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan > 1 )
+          {
+            // decrease column span
+            mCellData[ position.rowIndex ][ position.columnIndex ].position.columnSpan -= columnsRemoved;
+          }
+        }
+        // check if position is left of the removed location
+        if( position.rowIndex < (*iter).position.rowIndex )
+        {
+          // if row span is greater than 1
+          if( mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan > 1 )
+          {
+            // decrease row span
+            mCellData[ position.rowIndex ][ position.columnIndex ].position.rowSpan -= rowsRemoved;
+          }
+        }
+      }
+      else
+      {
+        // this actor is gone for good
+        // add actor to removed container
+        removed.push_back( (*iter).actor );
+        // we dont want the child actor anymore
+        Self().Remove( (*iter).actor );
+      }
+    }
+  }
+}
+
+bool TableView::RemoveAllInstances( const Actor& child )
+{
+  bool found = false;
+  // walk through the layout data
+  const unsigned int rowCount = mCellData.GetRows();
+  const unsigned int columnCount = mCellData.GetColumns();
+  for( unsigned int row = 0; row < rowCount; ++row )
+  {
+    for( unsigned int column = 0; column < columnCount; ++column )
+    {
+      if( mCellData[ row ][ column ].actor == child )
+      {
+        // clear the cell, NOTE that the cell might be spanning multiple cells
+        mCellData[ row ][ column ] = CellData();
+        found = true;
+      }
+    }
+  }
+  return found;
+}
+
+void TableView::SetHeightOrWidthProperty(TableView& tableViewImpl,
+                                         void(TableView::*funcFixed)(unsigned int, float),
+                                         void(TableView::*funcRelative)(unsigned int, float),
+                                         void(TableView::*funcFit)(unsigned int),
+                                         const Property::Value& value )
+{
+  Property::Map* map = value.GetMap();
+  if( map )
+  {
+    unsigned int index(0);
+    for ( unsigned int i = 0, count = map->Count(); i < count; ++i )
+    {
+      Property::Value& item = map->GetValue(i);
+      Property::Map* childMap = item.GetMap();
+
+      std::istringstream( map->GetKey(i) ) >> index;
+      if( childMap )
+      {
+        Property::Value* policy = childMap->Find( "policy" );
+        Property::Value* childMapValue = childMap->Find( "value" );
+        if( policy && childMapValue )
+        {
+          std::string policyValue;
+          policy->Get( policyValue );
+          Toolkit::TableView::LayoutPolicy policy;
+          if( Scripting::GetEnumeration< Toolkit::TableView::LayoutPolicy >( policyValue.c_str(),
+                                                                             LAYOUT_POLICY_STRING_TABLE,
+                                                                             LAYOUT_POLICY_STRING_TABLE_COUNT,
+                                                                             policy ) )
+          {
+            if( policy == Toolkit::TableView::FIXED  )
+            {
+              (tableViewImpl.*funcFixed)( index, childMapValue->Get<float>() );
+            }
+            else if( policy == Toolkit::TableView::RELATIVE )
+            {
+              (tableViewImpl.*funcRelative)( index, childMapValue->Get<float>() );
+            }
+            else if( policy == Toolkit::TableView::FIT )
+            {
+              (tableViewImpl.*funcFit)( index );
+            }
+            // do nothing for FILL policy
+          }
+        }
+      }
+    }
+  }
+}
+
+Property::Value TableView::GetRowHeightsPropertyValue()
+{
+  Property::Map map;
+  GetMapPropertyValue( mRowData, map);
+  return Property::Value(map);
+}
+
+Property::Value TableView::GetColumnWidthsPropertyValue()
+{
+  Property::Map map;
+  GetMapPropertyValue( mColumnData, map);
+  return Property::Value(map);
+}
+
+void TableView::GetMapPropertyValue( const RowColumnArray& data, Property::Map& map )
+{
+  const char* fixedPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIXED,
+                                                                                               LAYOUT_POLICY_STRING_TABLE,
+                                                                                               LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* relativePolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::RELATIVE,
+                                                                                                  LAYOUT_POLICY_STRING_TABLE,
+                                                                                                  LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* fillPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FILL,
+                                                                                              LAYOUT_POLICY_STRING_TABLE,
+                                                                                              LAYOUT_POLICY_STRING_TABLE_COUNT );
+  const char* fitPolicy = Scripting::GetEnumerationName< Toolkit::TableView::LayoutPolicy >( Toolkit::TableView::FIT,
+                                                                                             LAYOUT_POLICY_STRING_TABLE,
+                                                                                             LAYOUT_POLICY_STRING_TABLE_COUNT );
+
+  const RowColumnArray::SizeType count = data.Size();
+  for( RowColumnArray::SizeType i = 0; i < count; i++ )
+  {
+    const RowColumnData& dataInstance = data[ i ];
+
+    Property::Map item;
+    switch( dataInstance.sizePolicy )
+    {
+      case Toolkit::TableView::FIXED:
+      {
+        item[ "policy" ] = fixedPolicy;
+        item[ "value" ] = dataInstance.size;
+        break;
+      }
+      case Toolkit::TableView::RELATIVE:
+      {
+        item[ "policy" ] = relativePolicy;
+        item[ "value" ] = dataInstance.fillRatio;
+        break;
+      }
+      case Toolkit::TableView::FIT:
+      {
+        item[ "policy" ] = fitPolicy;
+        item[ "value" ] = 0.f;
+        break;
+      }
+      case Toolkit::TableView::FILL:
+      default:
+      {
+        item[ "policy" ] = fillPolicy;
+        item[ "value" ] = 0.f;
+        break;
+      }
+    }
+    std::ostringstream ss;
+    ss << i;
+    map[ ss.str() ] = item;
+  }
+}
+
+TableView::~TableView()
+{
+  // nothing to do
+}
+
+Actor TableView::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  Actor nextFocusableActor;
+
+  if ( !currentFocusedActor )
+  {
+    // Nothing is currently focused, so the child in the first cell should be focused.
+    nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
+  }
+  else
+  {
+    Toolkit::TableView::CellPosition position;
+    if( FindChildPosition( currentFocusedActor, position ) )
+    {
+      // The current focused actor is a child of TableView
+      bool focusLost = false;
+      int currentRow = position.rowIndex;
+      int currentColumn = position.columnIndex;
+      int numberOfColumns = GetColumns();
+      int numberOfRows = GetRows();
+
+      bool lastCell = false;
+      Actor nextValidActor;
+
+      switch ( direction )
+      {
+        case Toolkit::Control::KeyboardFocus::LEFT:
+        {
+          do
+          {
+            if(--currentColumn < 0)
+            {
+              currentColumn = numberOfColumns - 1;
+              if(--currentRow < 0)
+              {
+                lastCell = true;
+                currentRow = loopEnabled ? numberOfRows - 1 : 0;
+                focusLost = (currentRow == 0);
+              }
+            }
+            nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+          } while ( !nextValidActor && !lastCell );
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::RIGHT:
+        {
+          do
+          {
+            if(++currentColumn > numberOfColumns - 1)
+            {
+              currentColumn = 0;
+              if(++currentRow > numberOfRows - 1)
+              {
+                lastCell = true;
+                currentRow = loopEnabled ? 0 : numberOfRows - 1;
+                focusLost = (currentRow == numberOfRows - 1);
+              }
+            }
+            nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+          } while ( !nextValidActor && !lastCell );
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::UP:
+        {
+          do
+          {
+            if(--currentRow < 0)
+            {
+              lastCell = true;
+              currentRow = loopEnabled ? numberOfRows - 1 : 0;
+              focusLost = (currentRow == 0);
+            }
+            nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+          } while ( !nextValidActor && !lastCell );
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::DOWN:
+
+        {
+          do
+          {
+            if(++currentRow > numberOfRows - 1)
+            {
+              lastCell = true;
+              currentRow = loopEnabled ? 0 : numberOfRows - 1;
+              focusLost = (currentRow == numberOfRows - 1);
+            }
+            nextValidActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+          } while ( !nextValidActor && !lastCell );
+          break;
+        }
+        default:
+        {
+          break;
+        }
+      }
+
+      // Move the focus if we haven't lost it.
+      if(!focusLost)
+      {
+        nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(currentRow, currentColumn));
+
+        // Save the focused actor in the TableView.
+        mPreviousFocusedActor = nextFocusableActor;
+      }
+    }
+    else
+    {
+      // The current focused actor is not within this TableView.
+
+      unsigned int numberOfColumns = GetColumns();
+      unsigned int numberOfRows = GetRows();
+
+      // Check whether the previous focused actor is a focus group (i.e. a layout container)
+      bool wasFocusedOnLayoutContainer = false;
+      Actor previousFocusedActor = mPreviousFocusedActor.GetHandle();
+      if( previousFocusedActor )
+      {
+        Toolkit::Control control = Toolkit::Control::DownCast( previousFocusedActor );
+        if( control )
+        {
+          Internal::Control& controlImpl = static_cast<Internal::Control&>(control.GetImplementation());
+          wasFocusedOnLayoutContainer = controlImpl.IsKeyboardFocusGroup();
+        }
+      }
+
+      // Check whether the previous focused actor is a layout container and also a child of this TableView
+      Toolkit::TableView::CellPosition position;
+      if( wasFocusedOnLayoutContainer && FindChildPosition( previousFocusedActor, position ) )
+      {
+        nextFocusableActor = GetNextKeyboardFocusableActor(previousFocusedActor, direction, loopEnabled);
+      }
+      else
+      {
+        // Otherwise, move the focus to either the first or the last cell according to the given direction.
+        if(direction == Toolkit::Control::KeyboardFocus::LEFT || direction == Toolkit::Control::KeyboardFocus::UP)
+        {
+          nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(numberOfRows - 1, numberOfColumns - 1));
+        }
+        else
+        {
+          nextFocusableActor = GetChildAt(Toolkit::TableView::CellPosition(0, 0));
+        }
+      }
+    }
+  }
+
+  return nextFocusableActor;
+}
+
+Vector3 TableView::GetNaturalSize()
+{
+  // Natural size is the size of all fixed cell widths or heights. This ignores cells with relative heights.
+  return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
+}
+
+float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
+{
+  Toolkit::TableView::CellPosition position;
+  if( FindChildPosition( child, position) )
+  {
+    switch( dimension )
+    {
+      case Dimension::WIDTH:
+      {
+        float cellSize = 0.0f;
+        cellSize = mColumnData[position.columnIndex+position.columnSpan-1].position
+                 - (position.columnIndex > 0 ? mColumnData[position.columnIndex-1].position : 0.f)
+                 - mPadding.width * 2.0f;
+
+        if( cellSize < 0.0f )
+        {
+          cellSize = 0.0f;
+        }
+
+        return cellSize;
+      }
+
+      case Dimension::HEIGHT:
+      {
+        float cellSize = 0.0f;
+
+        cellSize = mRowData[position.rowIndex+position.rowSpan-1].position
+                 - (position.rowIndex > 0 ? mRowData[position.rowIndex-1].position : 0.f)
+                 - mPadding.height * 2.0f;
+
+        if( cellSize < 0.0f )
+        {
+          cellSize = 0.0f;
+        }
+
+        return cellSize;
+      }
+      default:
+      {
+        return 0.0f;
+      }
+    }
+  }
+
+  return 0.0f;    // Child not found
+}
+
+bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
+{
+  if ( Control::RelayoutDependentOnChildren( dimension ) )
+  {
+    return true;
+  }
+
+  return FindFit( mRowData ) || FindFit( mColumnData );
+}
+
+void TableView::SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
+{
+  // Check if we need to expand our data array
+  if( position.rowIndex >= mCellData.GetRows() )
+  {
+    // Only adding new rows
+    ResizeContainers( position.rowIndex + 1, mCellData.GetColumns() );
+  }
+
+  if( position.columnIndex >= mCellData.GetColumns() )
+  {
+    // Only adding new columns
+    ResizeContainers( mCellData.GetRows(), position.columnIndex + 1 );
+  }
+
+  // Set the alignment of the cell
+  CellData& data = mCellData[ position.rowIndex ][ position.columnIndex ];
+  data.horizontalAlignment = horizontal;
+  data.verticalAlignment = vertical;
+}
+
+void TableView::CalculateFillSizes( RowColumnArray& data )
+{
+  // First pass: Count number of fill entries and calculate used relative space
+  Dali::Vector< RowColumnData* > fillData;
+  float relativeTotal = 0.0f;
+
+  const unsigned int dataCount = data.Size();
+
+  for( unsigned int i = 0; i < dataCount; ++i )
+  {
+    RowColumnData& dataInstance = data[ i ];
+
+    if( dataInstance.sizePolicy == Toolkit::TableView::RELATIVE )
+    {
+      relativeTotal += dataInstance.fillRatio;
+    }
+    else if(dataInstance.sizePolicy == Toolkit::TableView::FILL)
+    {
+      fillData.PushBack( &dataInstance );
+    }
+  }
+
+  // Second pass: Distribute remaining relative space
+  const unsigned int fillCount = fillData.Size();
+  if( fillCount > 0 )
+  {
+    if( relativeTotal > 1.0f )
+    {
+      relativeTotal = 1.0f;
+    }
+
+    const float evenFillRatio = (1.0f - relativeTotal ) / fillCount;
+
+    for( unsigned int i = 0; i < fillCount; ++i )
+    {
+      fillData[ i ]->fillRatio = evenFillRatio;
+    }
+  }
+}
+
+float TableView::CalculateTotalFixedSize( const RowColumnArray& data )
+{
+  float totalSize = 0.0f;
+
+  const unsigned int dataCount = data.Size();
+
+  for( unsigned int i = 0; i < dataCount; ++i )
+  {
+    const RowColumnData& dataInstance = data[ i ];
+
+    switch( dataInstance.sizePolicy )
+    {
+      // we have absolute size to FIXED and FIT column/row and relative size for RELATIVE and FILL column/row
+      case Toolkit::TableView::FIXED:
+      case Toolkit::TableView::FIT:
+      {
+        totalSize += dataInstance.size;
+        break;
+      }
+
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  return totalSize;
+}
+
+Vector2 TableView::GetCellPadding( Dimension::Type dimension )
+{
+  switch( dimension )
+  {
+    case Dimension::WIDTH:
+    {
+      return Vector2( mPadding.x, mPadding.x );
+    }
+    case Dimension::HEIGHT:
+    {
+      return Vector2( mPadding.y, mPadding.y );
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return Vector2();
+}
+
+void TableView::CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension )
+{
+  Vector2 cellPadding = GetCellPadding( dimension );
+
+  const unsigned int dataCount = data.Size();
+
+  for( unsigned int i = 0; i < dataCount; ++i )
+  {
+    RowColumnData& dataInstance = data[ i ];
+
+    if( dataInstance.sizePolicy == Toolkit::TableView::FIT )
+    {
+      // Find the size of the biggest actor in the row or column
+      float maxActorHeight = 0.0f;
+
+      unsigned int fitCount = ( dimension == Dimension::WIDTH ) ? mCellData.GetRows() : mCellData.GetColumns();
+
+      for( unsigned int j = 0; j < fitCount; ++j )
+      {
+        unsigned int row = ( dimension == Dimension::WIDTH ) ? j : i;
+        unsigned int column = ( dimension == Dimension::WIDTH ) ? i : j;
+        DALI_ASSERT_DEBUG( row < mCellData.GetRows() );
+        DALI_ASSERT_DEBUG( column < mCellData.GetColumns() );
+
+        const CellData& cellData = mCellData[ row ][ column ];
+        const Actor& actor = cellData.actor;
+        if( actor )
+        {
+          if( FitToChild( actor, dimension ) && ( dimension == Dimension::WIDTH ) ? ( cellData.position.columnSpan == 1 ) : ( cellData.position.rowSpan == 1 )  )
+          {
+            maxActorHeight = std::max( maxActorHeight, actor.GetRelayoutSize( dimension ) + cellPadding.x + cellPadding.y );
+          }
+        }
+      }
+
+      dataInstance.size = maxActorHeight;
+    }
+  }
+}
+
+bool TableView::FindFit( const RowColumnArray& data )
+{
+  for( unsigned int i = 0, count = data.Size(); i < count; ++i )
+  {
+    if( data[ i ].sizePolicy == Toolkit::TableView::FIT )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.h b/dali-toolkit/internal/controls/table-view/table-view-impl.h
new file mode 100755 (executable)
index 0000000..901461f
--- /dev/null
@@ -0,0 +1,536 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TABLE_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_TABLE_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include "array-2d.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * TableView is a custom control for laying out actors in a table layout
+ * @see Dali::Toolkit:TableView for more details
+ */
+class TableView : public Control
+{
+public:
+
+  /**
+   * Create a new TableView.
+   * @return A smart-pointer to the newly allocated TableView.
+   */
+  static Toolkit::TableView New( unsigned int initialRows, unsigned int initialColumns );
+
+  /**
+   * @copydoc Toolkit::TableView::AddChild
+   */
+  bool AddChild( Actor& child, const Toolkit::TableView::CellPosition& position );
+
+  /**
+   * @copydoc Toolkit::TableView::GetChildAt
+   */
+  Actor GetChildAt( const Toolkit::TableView::CellPosition& position );
+
+  /**
+   * @copydoc Toolkit::TableView::RemoveChildAt
+   */
+  Actor RemoveChildAt( const Toolkit::TableView::CellPosition& position );
+
+  /**
+   * @copydoc Toolkit::TableView::FindChildPosition
+   */
+  bool FindChildPosition( const Actor& child, Toolkit::TableView::CellPosition& positionOut );
+
+  /**
+   * @copydoc Toolkit::TableView::InsertRow
+   */
+  void InsertRow( unsigned int rowIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::DeleteRow( unsigned int rowIndex )
+   */
+  void DeleteRow( unsigned int rowIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed )
+   */
+  void DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed );
+
+  /**
+   * @copydoc Toolkit::TableView::InsertColumn
+   */
+  void InsertColumn( unsigned int columnIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::DeleteColumn( unsigned int columnIndex )
+   */
+  void DeleteColumn( unsigned int columnIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed )
+   */
+  void DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed );
+
+  /**
+   * @copydoc Toolkit::TableView::Resize( unsigned int rows, unsigned int columns )
+   */
+  void Resize( unsigned int rows, unsigned int columns );
+
+  /**
+   * @copydoc Toolkit::TableView::Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed )
+   */
+  void Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed );
+
+  /**
+   * @copydoc Toolkit::TableView::SetCellPadding
+   */
+  void SetCellPadding( Size padding );
+
+  /**
+   * @copydoc Toolkit::TableView::GetCellPadding
+   */
+  Size GetCellPadding();
+
+  /**
+   * @copydoc Toolkit::TableView::SetFitHeight
+   */
+  void SetFitHeight( unsigned int rowIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::IsFitHeight
+   */
+  bool IsFitHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::SetFitWidth
+   */
+  void SetFitWidth( unsigned int columnIndex );
+
+  /**
+   * @copydoc Toolkit::TableView::IsFitWidth
+   */
+  bool IsFitWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::SetFixedWidth
+   */
+  void SetFixedWidth( unsigned int columnIndex, float width );
+
+  /**
+   * @copydoc Toolkit::TableView::GetFixedWidth
+   */
+  float GetFixedWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::SetFixedHeight
+   */
+  void SetFixedHeight( unsigned int rowIndex, float height );
+
+  /**
+   * @copydoc Toolkit::TableView::GetFixedHeight
+   */
+  float GetFixedHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::SetRelativeHeight
+   */
+  void SetRelativeHeight( unsigned int rowIndex, float heightPercentage );
+
+  /**
+   * @copydoc Toolkit::TableView::GetRelativeHeight
+   */
+  float GetRelativeHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::SetRelativeWidth
+   */
+  void SetRelativeWidth( unsigned int columnIndex, float widthPercentage );
+
+  /**
+   * @copydoc Toolkit::TableView::GetRelativeWidth
+   */
+  float GetRelativeWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @copydoc Toolkit::TableView::GetRows
+   */
+  unsigned int GetRows();
+
+  /**
+   * @copydoc Toolkit::TableView::GetColumns
+   */
+  unsigned int GetColumns();
+
+  /**
+   * @copydoc Toolkit::TableView::SetCellAlignment
+   */
+  void SetCellAlignment( Toolkit::TableView::CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical );
+
+  // Properties
+
+  /**
+   * Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * Called to retrieve a property of an object of this type.
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnChildAdd(Actor& child)
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc Control::OnChildRemove(Actor& child)
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  /**
+   * @copydoc Control::OnRelayout
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc Control::CalculateChildSize
+   */
+  virtual float CalculateChildSize( const Actor& child, Dimension::Type dimension );
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Control::GetNextKeyboardFocusableActor
+   */
+  virtual Actor GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled );
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Control::RelayoutDependentOnChildren()
+   */
+  virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS );
+
+  /**
+   * @copydoc Control::OnCalculateRelayoutSize
+   */
+  virtual void OnCalculateRelayoutSize( Dimension::Type dimension );
+
+  /**
+   * @copydoc Control::OnLayoutNegotiated
+   */
+  virtual void OnLayoutNegotiated( float size, Dimension::Type dimension );
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet( const Vector3& size )
+   */
+  virtual void OnSizeSet( const Vector3& size );
+
+private: // Implementation
+
+  /**
+   * Struct to hold data for rows and columns
+   *
+   * If sizePolicy is FIXED then size is the absolute size to use.
+   * If sizePolicy is FIT, RELATIVE or FILL then size is the calculated value of size.
+   */
+  struct RowColumnData
+  {
+    /**
+     * Default constructor
+     */
+    RowColumnData()
+    : size( 0.0f ),
+      fillRatio( 0.0f ),
+      position( 0.0f ),
+      sizePolicy( Toolkit::TableView::FILL )
+    {
+    }
+
+    /**
+     * Constructor
+     *
+     * @param[in] newSize The size to set for this data
+     * @param[in] newSizePolicy The policy used to interpret the size value
+     */
+    RowColumnData( float newSize, float newFillRatio, Toolkit::TableView::LayoutPolicy newSizePolicy )
+    : size( newSize ),
+      fillRatio( newFillRatio ),
+      position( 0.0f ),
+      sizePolicy( newSizePolicy )
+    {
+    }
+
+    float size;                                  ///< Set or calculated size
+    float fillRatio;                             ///< Ratio to fill remaining space, only valid with RELATIVE or FILL policy
+    float position;                              ///< Position of the row/column, this value is updated during every Relayout round
+    Toolkit::TableView::LayoutPolicy sizePolicy; ///< The size policy used to interpret the size value
+  };
+
+  typedef Dali::Vector<RowColumnData> RowColumnArray;
+
+public:
+
+  /**
+   * Structure for the layout data
+   */
+  struct CellData
+  {
+    CellData()
+    : horizontalAlignment( HorizontalAlignment::LEFT ),
+      verticalAlignment( VerticalAlignment::TOP )
+    {
+    }
+
+    // data members
+    Dali::Actor actor;
+    Toolkit::TableView::CellPosition position;
+    HorizontalAlignment::Type horizontalAlignment;
+    VerticalAlignment::Type verticalAlignment;
+  };
+
+private:
+
+  /**
+   * Construct a new TableView.
+   */
+  TableView( unsigned int initialRows, unsigned int initialColumns );
+
+  /**
+   * Resizes the data containers to match the new size
+   * @param [in] rows in the table
+   * @param [in] columns in the table
+   */
+  void ResizeContainers( unsigned int rows, unsigned int columns );
+
+  /**
+   * Resizes the data containers to match the new size
+   * @param [in] rows in the table
+   * @param [in] columns in the table
+   * @param [out] removed celldata
+   */
+  void ResizeContainers( unsigned int rows, unsigned int columns, std::vector<CellData>& removed );
+
+  /**
+   * Helper to get the list of lost actors in the case when table looses cells.
+   * Also handles the case when actors span multiple cells
+   * @param lost cells
+   * @param removed actors
+   * @param rowsRemoved from table
+   * @param columnsRemoved from table
+   */
+  void RemoveAndGetLostActors( const std::vector<CellData>& lost, std::vector<Actor>& removed,
+      unsigned int rowsRemoved, unsigned int columnsRemoved );
+
+  /**
+   * Helper to remove all instances of the actor
+   * @param child actor to remove
+   * @return true if the actor was found
+   */
+  bool RemoveAllInstances( const Actor& child );
+
+  /**
+   * @brief Calculate the ratio of FILL rows/columns
+   *
+   * @param[in] data The RowColumn data to compute the relative sizes for
+   */
+  void CalculateFillSizes( RowColumnArray& data );
+
+  /**
+   * @brief Calculate the total fixed sizes for a row or column
+   *
+   * @param[in] data The row or column data to process
+   */
+  float CalculateTotalFixedSize( const RowColumnArray& data );
+
+  /**
+   * @brief Calculate the sizes of FIT rows/columns
+   *
+   * @param[in] data The row or column data to process
+   * @param[in] dimension The dimension being calculated: row == Dimension::HEIGHT, column == Dimension::WIDTH
+   */
+  void CalculateFitSizes( RowColumnArray& data, Dimension::Type dimension );
+
+  /**
+   * @brief Search for a FIT cell in the array
+   *
+   * @param[in] data The row or column data to process
+   * @return Return if a FIT cell was found or not
+   */
+  bool FindFit( const RowColumnArray& data );
+
+  /**
+   * @brief Return the cell padding for a given dimension
+   *
+   * @param[in] dimension The dimension to return the padding for
+   * @return Return the padding (x = low, y = high)
+   */
+  Vector2 GetCellPadding( Dimension::Type dimension );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TableView();
+
+private: // scripting support
+
+  /**
+   * Called to set the heights/widths property.
+   * @param[in] tableViewImpl The object whose property is set.
+   * @param[in] funcFixed The set function to call, it can be SetFixedHeight or SetFixedWidth.
+   * @param[in] funcRelative The set function to call, it can be SetRelativeHeight or SetRelativeWidth.
+   * @param[in] funcFit The set function to call, it can be SetFitHeight or SetFiltWidth.
+   * @param[in] value The new property value.
+   */
+  static void SetHeightOrWidthProperty( TableView& tableViewImpl,
+                                        void(TableView::*funcFixed)(unsigned int, float),
+                                        void(TableView::*funcRelative)(unsigned int, float),
+                                        void(TableView::*funcFit)(unsigned int),
+                                        const Property::Value& map );
+
+  /**
+   * Called to retrieve the property value of row heights.
+   * @return The property value of row heights.
+   */
+  Property::Value GetRowHeightsPropertyValue();
+
+  /**
+   * Called to retrieve the property value of column widths.
+   * @return The fixed-widths property value.
+   */
+  Property::Value GetColumnWidthsPropertyValue();
+
+  /**
+   * Generate the map type property value from the size vectors.
+   * @param[in] data The array of row or column data
+   * @param[out] map The property value.
+   */
+  void GetMapPropertyValue( const RowColumnArray& data, Property::Map& map );
+
+
+  /**
+   * Helper class to prevent child adds and removes from causing relayout
+   * when we're already anyways going to do one in the end
+   */
+  class RelayoutingLock
+  {
+  public: // API
+
+    /**
+     * Constructor, sets the lock boolean
+     */
+    RelayoutingLock( TableView& parent )
+    : mLock( parent.mLayoutingChild )
+    {
+      mLock = true;
+    }
+
+    /**
+     * Destructor, releases lock boolean
+     */
+    ~RelayoutingLock()
+    {
+      mLock = false;
+      // Note, we could also call Relayout here. This would save one line of code
+      // from each method that uses this lock but destructors are not meant to do
+      // big processing so better to not do it here. This destructor would also
+      // be called in case of an exception and we don't definitely want to do Relayout
+      // in that situation
+    }
+
+  private:
+    bool& mLock;
+  };
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  TableView(const TableView&);
+  TableView& operator=(const TableView& rhs);
+
+private: // Data
+
+  Array2d<CellData> mCellData;   ///< Data for each cell: Actor, alignment settings etc
+
+  RowColumnArray mRowData;       ///< Data for each row
+  RowColumnArray mColumnData;    ///< Data for each column
+  Size mFixedTotals;             ///< Accumulated totals for fixed width and height
+
+  Size mPadding;                 ///< Padding to apply to each cell
+
+  WeakHandle<Actor> mPreviousFocusedActor; ///< Perviously focused actor
+  bool mLayoutingChild;          ///< Can't be a bitfield due to Relayouting lock
+  bool mRowDirty : 1;            ///< Flag to indicate the row data is dirty
+  bool mColumnDirty : 1;         ///< Flag to indicate the column data is dirty
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TableView& GetImpl( Toolkit::TableView& tableView )
+{
+  DALI_ASSERT_ALWAYS(tableView);
+
+  Dali::RefObject& handle = tableView.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TableView&>(handle);
+}
+
+inline const Toolkit::Internal::TableView& GetImpl( const Toolkit::TableView& tableView )
+{
+  DALI_ASSERT_ALWAYS(tableView);
+
+  const Dali::RefObject& handle = tableView.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TableView&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TABLE_VIEW_H
diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
new file mode 100755 (executable)
index 0000000..3444c39
--- /dev/null
@@ -0,0 +1,1889 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <limits>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/rendering/text-backend.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+
+using namespace Dali::Toolkit::Text;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+const float DEFAULT_SCROLL_SPEED = 1200.f; ///< The default scroll speed for the text editor in pixels/second.
+} // unnamed namespace
+
+namespace
+{
+const char* const SCROLL_BAR_POSITION("sourcePosition");
+const char* const SCROLL_BAR_POSITION_MIN("sourcePositionMin");
+const char* const SCROLL_BAR_POSITION_MAX("sourcePositionMax");
+const char* const SCROLL_BAR_CONTENT_SIZE("sourceContentSize");
+
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::TextEditor::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextEditor, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "renderingBackend",                     INTEGER,   RENDERING_BACKEND                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "text",                                 STRING,    TEXT                                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "textColor",                            VECTOR4,   TEXT_COLOR                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "fontFamily",                           STRING,    FONT_FAMILY                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "fontStyle",                            MAP,       FONT_STYLE                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "pointSize",                            FLOAT,     POINT_SIZE                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "horizontalAlignment",                  STRING,    HORIZONTAL_ALIGNMENT                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollThreshold",                      FLOAT,     SCROLL_THRESHOLD                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollSpeed",                          FLOAT,     SCROLL_SPEED                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "primaryCursorColor",                   VECTOR4,   PRIMARY_CURSOR_COLOR                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "secondaryCursorColor",                 VECTOR4,   SECONDARY_CURSOR_COLOR               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableCursorBlink",                    BOOLEAN,   ENABLE_CURSOR_BLINK                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorBlinkInterval",                  FLOAT,     CURSOR_BLINK_INTERVAL                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorBlinkDuration",                  FLOAT,     CURSOR_BLINK_DURATION                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "cursorWidth",                          INTEGER,   CURSOR_WIDTH                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "grabHandleImage",                      STRING,    GRAB_HANDLE_IMAGE                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "grabHandlePressedImage",               STRING,    GRAB_HANDLE_PRESSED_IMAGE            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleImageLeft",             MAP,       SELECTION_HANDLE_IMAGE_LEFT          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleImageRight",            MAP,       SELECTION_HANDLE_IMAGE_RIGHT         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandlePressedImageLeft",      MAP,       SELECTION_HANDLE_PRESSED_IMAGE_LEFT  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandlePressedImageRight",     MAP,       SELECTION_HANDLE_PRESSED_IMAGE_RIGHT )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleMarkerImageLeft",       MAP,       SELECTION_HANDLE_MARKER_IMAGE_LEFT   )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHandleMarkerImageRight",      MAP,       SELECTION_HANDLE_MARKER_IMAGE_RIGHT  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "selectionHighlightColor",              VECTOR4,   SELECTION_HIGHLIGHT_COLOR            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "decorationBoundingBox",                RECTANGLE, DECORATION_BOUNDING_BOX              )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableMarkup",                         BOOLEAN,   ENABLE_MARKUP                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputColor",                           VECTOR4,   INPUT_COLOR                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputFontFamily",                      STRING,    INPUT_FONT_FAMILY                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputFontStyle",                       MAP,       INPUT_FONT_STYLE                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputPointSize",                       FLOAT,     INPUT_POINT_SIZE                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "lineSpacing",                          FLOAT,     LINE_SPACING                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputLineSpacing",                     FLOAT,     INPUT_LINE_SPACING                   )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "underline",                            MAP,       UNDERLINE                            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputUnderline",                       MAP,       INPUT_UNDERLINE                      )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "shadow",                               MAP,       SHADOW                               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputShadow",                          MAP,       INPUT_SHADOW                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "emboss",                               MAP,       EMBOSS                               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputEmboss",                          MAP,       INPUT_EMBOSS                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "outline",                              MAP,       OUTLINE                              )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "inputOutline",                         MAP,       INPUT_OUTLINE                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "smoothScroll",                         BOOLEAN,   SMOOTH_SCROLL                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "smoothScrollDuration",                 FLOAT,     SMOOTH_SCROLL_DURATION               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableScrollBar",                      BOOLEAN,   ENABLE_SCROLL_BAR                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollBarShowDuration",                FLOAT,     SCROLL_BAR_SHOW_DURATION             )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "scrollBarFadeDuration",                FLOAT,     SCROLL_BAR_FADE_DURATION             )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "pixelSize",                            FLOAT,     PIXEL_SIZE                           )
+DALI_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextEditor, "lineCount",                  INTEGER,   LINE_COUNT                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableSelection",                      BOOLEAN,   ENABLE_SELECTION                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "placeholder",                          MAP,       PLACEHOLDER                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextEditor, "lineWrapMode",                         INTEGER,   LINE_WRAP_MODE                       )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "placeholderText",                STRING,    PLACEHOLDER_TEXT                     )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "placeholderTextColor",           VECTOR4,   PLACEHOLDER_TEXT_COLOR               )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableShiftSelection",           BOOLEAN,   ENABLE_SHIFT_SELECTION               )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "enableGrabHandle",               BOOLEAN,   ENABLE_GRAB_HANDLE                   )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextEditor, "matchSystemLanguageDirection",   BOOLEAN,   MATCH_SYSTEM_LANGUAGE_DIRECTION      )
+
+DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "textChanged",        SIGNAL_TEXT_CHANGED )
+DALI_SIGNAL_REGISTRATION( Toolkit, TextEditor, "inputStyleChanged",  SIGNAL_INPUT_STYLE_CHANGED )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Toolkit::TextEditor TextEditor::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextEditor > impl = new TextEditor();
+
+  // Pass ownership to CustomActor handle
+  Toolkit::TextEditor handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextEditor::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast( Dali::BaseHandle( object ) );
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor SetProperty\n");
+
+
+  if( textEditor )
+  {
+    TextEditor& impl( GetImpl( textEditor ) );
+
+    switch( index )
+    {
+      case Toolkit::TextEditor::Property::RENDERING_BACKEND:
+      {
+        int backend = value.Get< int >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend );
+
+        if( impl.mRenderingBackend != backend )
+        {
+          impl.mRenderingBackend = backend;
+          impl.mRenderer.Reset();
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          const std::string& text = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p TEXT %s\n", impl.mController.Get(), text.c_str() );
+
+          impl.mController->SetText( text );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::TEXT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4& textColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
+
+          if( impl.mController->GetDefaultColor() != textColor )
+          {
+            impl.mController->SetDefaultColor( textColor );
+            impl.mController->SetInputColor( textColor );
+            impl.mRenderer.Reset();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          const std::string& fontFamily = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
+          impl.mController->SetDefaultFontFamily( fontFamily );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::FONT_STYLE:
+      {
+        SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pointSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p POINT_SIZE %f\n", impl.mController.Get(), pointSize );
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( Text::GetHorizontalAlignmentEnumeration( value, alignment ) )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment );
+            impl.mController->SetHorizontalAlignment( alignment );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
+      {
+        const float threshold = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetScrollThreshold( threshold );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_SPEED:
+      {
+        const float speed = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p SCROLL_SPEED %f\n", impl.mController.Get(), speed );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetScrollSpeed( speed );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          const Vector4& color = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+          impl.mDecorator->SetCursorColor( PRIMARY_CURSOR, color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          const Vector4& color = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+          impl.mDecorator->SetCursorColor( SECONDARY_CURSOR, color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
+      {
+        if( impl.mController )
+        {
+          const bool enable = value.Get< bool >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable );
+
+          impl.mController->SetEnableCursorBlink( enable );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
+      {
+        if( impl.mDecorator )
+        {
+          const float interval = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval );
+
+          impl.mDecorator->SetCursorBlinkInterval( interval );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
+      {
+        if( impl.mDecorator )
+        {
+          const float duration = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration );
+
+          impl.mDecorator->SetCursorBlinkDuration( duration );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_WIDTH:
+      {
+        if( impl.mDecorator )
+        {
+          const int width = value.Get< int >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p CURSOR_WIDTH %d\n", impl.mController.Get(), width );
+
+          impl.mDecorator->SetCursorWidth( width );
+          impl.mController->GetLayoutEngine().SetCursorWidth( width );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
+      {
+        const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
+      {
+        const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
+      {
+        const Vector4 color = value.Get< Vector4 >();
+        DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHighlightColor( color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
+      {
+        if( impl.mDecorator )
+        {
+          const Rect<int>& box = value.Get< Rect<int> >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height );
+
+          impl.mDecorator->SetBoundingBox( box );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          const bool enableMarkup = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup );
+
+          impl.mController->SetMarkupProcessorEnabled( enableMarkup );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4& inputColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a );
+
+          impl.mController->SetInputColor( inputColor );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          const std::string& fontFamily = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
+          impl.mController->SetInputFontFamily( fontFamily );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
+      {
+        SetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pointSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize );
+          impl.mController->SetInputFontPointSize( pointSize );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+
+          // The line spacing isn't supported by the TextEditor. Since it's supported
+          // by the TextLabel for now it must be ignored. The property is being shadowed
+          // locally so its value isn't affected.
+          const float lineSpacing = value.Get<float>();
+          impl.mLineSpacing = lineSpacing;
+          // set it to 0.0 due to missing implementation
+          impl.mController->SetDefaultLineSpacing( 0.0f );
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+          const float lineSpacing = value.Get<float>();
+          impl.mController->SetInputLineSpacing( lineSpacing );
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::UNDERLINE:
+      {
+        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
+      {
+        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SHADOW:
+      {
+        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_SHADOW:
+      {
+        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::EMBOSS:
+      {
+        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_EMBOSS:
+      {
+        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::OUTLINE:
+      {
+        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_OUTLINE:
+      {
+        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
+      {
+        const bool enable = value.Get< bool >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor SMOOTH_SCROLL %d\n", enable );
+
+        impl.mScrollAnimationEnabled = enable;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
+      {
+        const float duration = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor SMOOTH_SCROLL_DURATION %f\n", duration );
+
+        impl.mScrollAnimationDuration = duration;
+        if ( impl.mTextVerticalScroller )
+        {
+          impl.mTextVerticalScroller->SetDuration( duration );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
+      {
+        const bool enable = value.Get< bool >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor SHOW_SCROLL_BAR %d\n", enable );
+
+        impl.mScrollBarEnabled = enable;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
+      {
+        const float duration = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor SCROLL_BAR_SHOW_DURATION %f\n", duration );
+
+        impl.mAnimationPeriod.delaySeconds = duration;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
+      {
+        const float duration = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor SCROLL_BAR_FADE_DURATION %f\n", duration );
+
+        impl.mAnimationPeriod.durationSeconds = duration;
+        break;
+      }
+      case Toolkit::TextEditor::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pixelSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
+      {
+        if( impl.mController )
+        {
+          const std::string& text = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor::OnPropertySet %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str() );
+
+          impl.mController->SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4& textColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
+
+          if( impl.mController->GetPlaceholderTextColor() != textColor )
+          {
+            impl.mController->SetPlaceholderTextColor( textColor );
+            impl.mRenderer.Reset();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_SELECTION:
+      {
+        if( impl.mController )
+        {
+          const bool enableSelection = value.Get< bool >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection );
+          impl.mController->SetSelectionEnabled( enableSelection );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::PLACEHOLDER:
+      {
+        const Property::Map* map = value.GetMap();
+        if( map )
+        {
+          impl.mController->SetPlaceholderProperty( *map );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
+      {
+        if( impl.mController )
+        {
+          Text::LineWrap::Mode lineWrapMode( static_cast< Text::LineWrap::Mode >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( GetLineWrapModeEnumeration( value, lineWrapMode ) )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode );
+            impl.mController->SetLineWrapMode( lineWrapMode );
+          }
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
+      {
+        if( impl.mController )
+        {
+          const bool shiftSelection = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection );
+
+          impl.mController->SetShiftSelectionEnabled( shiftSelection );
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
+      {
+        if( impl.mController )
+        {
+          const bool grabHandleEnabled = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled );
+
+          impl.mController->SetGrabHandleEnabled( grabHandleEnabled );
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        if( impl.mController )
+        {
+          impl.mController->SetMatchSystemLanguageDirection(value.Get< bool >());
+        }
+        break;
+      }
+    } // switch
+  } // texteditor
+}
+
+Property::Value TextEditor::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextEditor textEditor = Toolkit::TextEditor::DownCast( Dali::BaseHandle( object ) );
+
+  if( textEditor )
+  {
+    TextEditor& impl( GetImpl( textEditor ) );
+
+    switch( index )
+    {
+      case Toolkit::TextEditor::Property::RENDERING_BACKEND:
+      {
+        value = impl.mRenderingBackend;
+        break;
+      }
+      case Toolkit::TextEditor::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetText( text );
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor %p returning text: %s\n", impl.mController.Get(), text.c_str() );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::TEXT_COLOR:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->GetDefaultColor();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontFamily();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::FONT_STYLE:
+      {
+        GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          const char* name = GetHorizontalAlignmentString( impl.mController->GetHorizontalAlignment() );
+          if( name )
+          {
+            value = std::string( name );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_THRESHOLD:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetScrollThreshold();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_SPEED:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetScrollSpeed();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::PRIMARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetColor( PRIMARY_CURSOR );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SECONDARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetColor( SECONDARY_CURSOR );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_CURSOR_BLINK:
+      {
+        value = impl.mController->GetEnableCursorBlink();
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_BLINK_INTERVAL:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorBlinkInterval();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_BLINK_DURATION:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorBlinkDuration();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::CURSOR_WIDTH:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorWidth();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::GRAB_HANDLE_IMAGE:
+      {
+        if( impl.mDecorator )
+        {
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) );
+          if( image )
+          {
+            value = image.GetUrl();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::GRAB_HANDLE_PRESSED_IMAGE:
+      {
+        if( impl.mDecorator )
+        {
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) );
+          if( image )
+          {
+            value = image.GetUrl();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) ;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SELECTION_HIGHLIGHT_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetHighlightColor();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::DECORATION_BOUNDING_BOX:
+      {
+        if( impl.mDecorator )
+        {
+          Rect<int> boundingBox;
+          impl.mDecorator->GetBoundingBox( boundingBox );
+          value = boundingBox;
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMarkupProcessorEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputColor();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputFontFamily();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_FONT_STYLE:
+      {
+        GetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputFontPointSize();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+          // LINE_SPACING isn't implemented for the TextEditor. Returning
+          // only shadowed value, not the real one.
+          value = impl.mLineSpacing;
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputLineSpacing();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::UNDERLINE:
+      {
+        GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_UNDERLINE:
+      {
+        GetUnderlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SHADOW:
+      {
+        GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_SHADOW:
+      {
+        GetShadowProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::EMBOSS:
+      {
+        GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_EMBOSS:
+      {
+        GetEmbossProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::OUTLINE:
+      {
+        GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::INPUT_OUTLINE:
+      {
+        GetOutlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextEditor::Property::SMOOTH_SCROLL:
+      {
+        value = impl.mScrollAnimationEnabled;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SMOOTH_SCROLL_DURATION:
+      {
+        value = impl.mScrollAnimationDuration;
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_SCROLL_BAR:
+      {
+        value = impl.mScrollBarEnabled;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_BAR_SHOW_DURATION:
+      {
+        value = impl.mAnimationPeriod.delaySeconds;
+        break;
+      }
+      case Toolkit::TextEditor::Property::SCROLL_BAR_FADE_DURATION:
+      {
+        value = impl.mAnimationPeriod.durationSeconds;
+        break;
+      }
+      case Toolkit::TextEditor::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::LINE_COUNT:
+      {
+        if( impl.mController )
+        {
+          float width = textEditor.GetProperty( Actor::Property::SIZE_WIDTH ).Get<float>();
+          value = impl.mController->GetLineCount( width );
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::PLACEHOLDER_TEXT_COLOR:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetPlaceholderTextColor();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::ENABLE_SELECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsSelectionEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextEditor::Property::PLACEHOLDER:
+      {
+        Property::Map map;
+        impl.mController->GetPlaceholderProperty( map );
+        value = map;
+        break;
+      }
+      case Toolkit::TextEditor::Property::LINE_WRAP_MODE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetLineWrapMode();
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ENABLE_SHIFT_SELECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsShiftSelectionEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::ENABLE_GRAB_HANDLE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsGrabHandleEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextEditor::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMatchSystemLanguageDirection();
+        }
+        break;
+      }
+    } //switch
+  }
+
+  return value;
+}
+
+InputMethodContext TextEditor::GetInputMethodContext()
+{
+  return mInputMethodContext;
+}
+
+bool TextEditor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::TextEditor editor = Toolkit::TextEditor::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_CHANGED ) )
+  {
+    editor.TextChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_INPUT_STYLE_CHANGED ) )
+  {
+    editor.InputStyleChangedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+Toolkit::TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal()
+{
+  return mTextChangedSignal;
+}
+
+Toolkit::TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedSignal()
+{
+  return mInputStyleChangedSignal;
+}
+
+Toolkit::TextEditor::ScrollStateChangedSignalType& TextEditor::ScrollStateChangedSignal()
+{
+  return mScrollStateChangedSignal;
+}
+
+void TextEditor::OnInitialize()
+{
+  Actor self = Self();
+
+  mController = Text::Controller::New( this, this );
+
+  mDecorator = Text::Decorator::New( *mController,
+                                     *mController );
+
+  mInputMethodContext = InputMethodContext::New( self );
+
+  mController->GetLayoutEngine().SetLayout( Layout::Engine::MULTI_LINE_BOX );
+
+  // Enables the text input.
+  mController->EnableTextInput( mDecorator, mInputMethodContext );
+
+  // Enables the vertical scrolling after the text input has been enabled.
+  mController->SetVerticalScrollEnabled( true );
+
+  // Disables the horizontal scrolling.
+  mController->SetHorizontalScrollEnabled( false );
+
+  // Sets the maximum number of characters.
+  mController->SetMaximumNumberOfCharacters( std::numeric_limits<Length>::max() );
+
+  // Enable the smooth handle panning.
+  mController->SetSmoothHandlePanEnabled( true );
+
+  mController->SetNoTextDoubleTapAction( Controller::NoTextTap::HIGHLIGHT );
+  mController->SetNoTextLongPressAction( Controller::NoTextTap::HIGHLIGHT );
+
+  // Sets layoutDirection value
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( stage.GetRootLayer().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+  mController->SetLayoutDirection( layoutDirection );
+
+  // Forward input events to controller
+  EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
+  GetTapGestureDetector().SetMaximumTapsRequired( 2 );
+
+  self.TouchSignal().Connect( this, &TextEditor::OnTouched );
+
+  // Set BoundingBox to stage size if not already set.
+  Rect<int> boundingBox;
+  mDecorator->GetBoundingBox( boundingBox );
+
+  if( boundingBox.IsEmpty() )
+  {
+    Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
+    mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
+  }
+
+  // Whether to flip the selection handles as soon as they cross.
+  mDecorator->FlipSelectionHandlesOnCrossEnabled( true );
+
+  // Set the default scroll speed.
+  mDecorator->SetScrollSpeed( DEFAULT_SCROLL_SPEED );
+
+  // Fill-parent area by default
+  self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+  self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
+  self.OnStageSignal().Connect( this, &TextEditor::OnStageConnect );
+
+  DevelControl::SetInputMethodContext( *this, mInputMethodContext );
+
+  // Creates an extra control to be used as stencil buffer.
+  mStencil = Control::New();
+  mStencil.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  mStencil.SetParentOrigin( ParentOrigin::TOP_LEFT );
+
+  // Creates a background visual. Even if the color is transparent it updates the stencil.
+  mStencil.SetProperty( Toolkit::Control::Property::BACKGROUND,
+                        Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR ).
+                        Add( ColorVisual::Property::MIX_COLOR, Color::TRANSPARENT ) );
+
+  // Enable the clipping property.
+  mStencil.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX );
+  mStencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+  self.Add( mStencil );
+}
+
+void TextEditor::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+{
+  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");
+      const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
+      // Property system did not set the font so should update it.
+      mController->UpdateAfterFontChange( newFont );
+      RelayoutRequest();
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+      RelayoutRequest();
+      break;
+    }
+    case StyleChange::THEME_CHANGE:
+    {
+      // Nothing to do, let control base class handle this
+      break;
+    }
+  }
+
+  // Up call to Control
+  Control::OnStyleChange( styleManager, change );
+}
+
+Vector3 TextEditor::GetNaturalSize()
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector3 naturalSize = mController->GetNaturalSize();
+  naturalSize.width += ( padding.start + padding.end );
+  naturalSize.height += ( padding.top + padding.bottom );
+
+  return naturalSize;
+}
+
+float TextEditor::GetHeightForWidth( float width )
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
+}
+
+void TextEditor::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor OnRelayout\n");
+
+  Actor self = Self();
+
+  Extents padding;
+  padding = self.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) );
+
+  // Support Right-To-Left of padding
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( self.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+  if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+  {
+    std::swap( padding.start, padding.end );
+  }
+
+  if( mStencil )
+  {
+    mStencil.SetPosition( padding.start, padding.top );
+  }
+  if( mActiveLayer )
+  {
+    mActiveLayer.SetPosition( padding.start, padding.top );
+  }
+
+  const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize, layoutDirection );
+
+  if( ( Text::Controller::NONE_UPDATED != updateTextType ) ||
+      !mRenderer )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnRelayout %p Displaying new contents\n", mController.Get() );
+
+    if( mDecorator &&
+        ( Text::Controller::NONE_UPDATED != ( Text::Controller::DECORATOR_UPDATED & updateTextType ) ) )
+    {
+      mDecorator->Relayout( size );
+    }
+
+    if( !mRenderer )
+    {
+      mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
+    }
+
+    RenderText( updateTextType );
+
+  }
+
+  // The text-editor emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-editor adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  if( !mController->IsInputStyleChangedSignalsQueueEmpty() )
+  {
+    if( Adaptor::IsAvailable() )
+    {
+      Adaptor& adaptor = Adaptor::Get();
+
+      if( NULL == mIdleCallback )
+      {
+        // @note: The callback manager takes the ownership of the callback object.
+        mIdleCallback = MakeCallback( this, &TextEditor::OnIdleSignal );
+        adaptor.AddIdle( mIdleCallback, false );
+      }
+    }
+  }
+}
+
+void TextEditor::RenderText( Text::Controller::UpdateTextType updateTextType )
+{
+  Actor renderableActor;
+
+  if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
+  {
+    if( mRenderer )
+    {
+      Dali::Toolkit::TextEditor handle = Dali::Toolkit::TextEditor( GetOwner() );
+
+      renderableActor = mRenderer->Render( mController->GetView(),
+                                           handle,
+                                           Property::INVALID_INDEX, // Animatable property not supported
+                                           mAlignmentOffset,
+                                           DepthIndex::CONTENT );
+    }
+
+    if( renderableActor != mRenderableActor )
+    {
+      UnparentAndReset( mRenderableActor );
+      mRenderableActor = renderableActor;
+    }
+  }
+
+  if( mRenderableActor )
+  {
+    // Make sure the actors are parented correctly with/without clipping
+    Actor self = mStencil ? mStencil : Self();
+
+    for( std::vector<Actor>::iterator it = mClippingDecorationActors.begin(),
+           endIt = mClippingDecorationActors.end();
+         it != endIt;
+         ++it )
+    {
+      self.Add( *it );
+      it->LowerToBottom();
+    }
+    mClippingDecorationActors.clear();
+
+    self.Add( mRenderableActor );
+
+    ApplyScrollPosition();
+  }
+  UpdateScrollBar();
+}
+
+void TextEditor::OnKeyInputFocusGained()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnKeyInputFocusGained %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.StatusChangedSignal().Connect( this, &TextEditor::KeyboardStatusChanged );
+
+    mInputMethodContext.EventReceivedSignal().Connect( this, &TextEditor::OnInputMethodContextEvent );
+
+    // Notify that the text editing start.
+    mInputMethodContext.Activate();
+
+    // When window gain lost focus, the InputMethodContext is deactivated. Thus when window gain focus again, the InputMethodContext must be activated.
+    mInputMethodContext.SetRestoreAfterFocusLost( true );
+  }
+  ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
+
+  if ( notifier )
+  {
+    notifier.ContentSelectedSignal().Connect( this, &TextEditor::OnClipboardTextSelected );
+  }
+
+  mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+
+  EmitKeyInputFocusSignal( true ); // Calls back into the Control hence done last.
+}
+
+void TextEditor::OnKeyInputFocusLost()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor:OnKeyInputFocusLost %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.StatusChangedSignal().Disconnect( this, &TextEditor::KeyboardStatusChanged );
+
+    // The text editing is finished. Therefore the InputMethodContext don't have restore activation.
+    mInputMethodContext.SetRestoreAfterFocusLost( false );
+
+    // Notify that the text editing finish.
+    mInputMethodContext.Deactivate();
+
+    mInputMethodContext.EventReceivedSignal().Disconnect( this, &TextEditor::OnInputMethodContextEvent );
+  }
+  ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
+
+  if ( notifier )
+  {
+    notifier.ContentSelectedSignal().Disconnect( this, &TextEditor::OnClipboardTextSelected );
+  }
+
+  mController->KeyboardFocusLostEvent();
+
+  EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last.
+}
+
+void TextEditor::OnTap( const TapGesture& gesture )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.Activate();
+  }
+  // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x - padding.start, gesture.localPoint.y - padding.top );
+
+  SetKeyInputFocus();
+}
+
+void TextEditor::OnPan( const PanGesture& gesture )
+{
+  mController->PanEvent( gesture.state, gesture.displacement );
+}
+
+void TextEditor::OnLongPress( const LongPressGesture& gesture )
+{
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.Activate();
+  }
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  mController->LongPressEvent( gesture.state, gesture.localPoint.x - padding.start, gesture.localPoint.y - padding.top );
+
+  SetKeyInputFocus();
+}
+
+bool TextEditor::OnKeyEvent( const KeyEvent& event )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode );
+
+  if( Dali::DALI_KEY_ESCAPE == event.keyCode && mController->ShouldClearFocusOnEscape() )
+  {
+    // Make sure ClearKeyInputFocus when only key is up
+    if( event.state == KeyEvent::Up )
+    {
+      ClearKeyInputFocus();
+    }
+
+    return true;
+  }
+
+  return mController->KeyEvent( event );
+}
+
+void TextEditor::RequestTextRelayout()
+{
+  RelayoutRequest();
+}
+
+void TextEditor::TextChanged()
+{
+  Dali::Toolkit::TextEditor handle( GetOwner() );
+  mTextChangedSignal.Emit( handle );
+}
+
+void TextEditor::MaxLengthReached()
+{
+  // Nothing to do as TextEditor doesn't emit a max length reached signal.
+}
+
+void TextEditor::InputStyleChanged( Text::InputStyle::Mask inputStyleMask )
+{
+  Dali::Toolkit::TextEditor handle( GetOwner() );
+
+  Toolkit::TextEditor::InputStyle::Mask editorInputStyleMask = Toolkit::TextEditor::InputStyle::NONE;
+
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_COLOR ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::COLOR );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_FAMILY ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_FAMILY );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_POINT_SIZE ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::POINT_SIZE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_WEIGHT ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_WIDTH ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_SLANT ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_LINE_SPACING ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::LINE_SPACING );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_UNDERLINE ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::UNDERLINE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_SHADOW ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::SHADOW );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_EMBOSS ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::EMBOSS );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_OUTLINE ) )
+  {
+    editorInputStyleMask = static_cast<Toolkit::TextEditor::InputStyle::Mask>( editorInputStyleMask | Toolkit::TextEditor::InputStyle::OUTLINE );
+  }
+
+  mInputStyleChangedSignal.Emit( handle, editorInputStyleMask );
+}
+
+void TextEditor::AddDecoration( Actor& actor, bool needsClipping )
+{
+  if( actor )
+  {
+    if( needsClipping )
+    {
+      mClippingDecorationActors.push_back( actor );
+    }
+    else
+    {
+      actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      Self().Add( actor );
+      mActiveLayer = actor;
+    }
+  }
+}
+
+void TextEditor::UpdateScrollBar()
+{
+  using namespace Dali;
+
+  float scrollPosition;
+  float controlSize;
+  float layoutSize;
+  bool latestScrolled;
+
+  if ( !mScrollBarEnabled )
+  {
+    return;
+  }
+  latestScrolled = mController->GetTextScrollInfo( scrollPosition, controlSize, layoutSize );
+  if ( !latestScrolled || controlSize > layoutSize)
+  {
+    return;
+  }
+
+  CustomActor self = Self();
+  if( !mScrollBar )
+  {
+    mScrollBar = Toolkit::ScrollBar::New( Toolkit::ScrollBar::Vertical );
+    mScrollBar.SetIndicatorHeightPolicy( Toolkit::ScrollBar::Variable );
+    mScrollBar.SetParentOrigin( ParentOrigin::TOP_RIGHT );
+    mScrollBar.SetAnchorPoint( AnchorPoint::TOP_RIGHT );
+    mScrollBar.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
+    mScrollBar.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::WIDTH );
+
+    // Register the scroll position property
+    Property::Index propertyScrollPosition = self.RegisterProperty( SCROLL_BAR_POSITION, scrollPosition );
+    // Register the minimum scroll position property
+    Property::Index propertyMinScrollPosition = self.RegisterProperty( SCROLL_BAR_POSITION_MIN, 0.0f );
+    // Register the maximum scroll position property
+    Property::Index propertyMaxScrollPosition = self.RegisterProperty( SCROLL_BAR_POSITION_MAX, (layoutSize - controlSize) );
+    // Register the scroll content size property
+    Property::Index propertyScrollContentSize = self.RegisterProperty( SCROLL_BAR_CONTENT_SIZE, layoutSize );
+
+    mScrollBar.SetScrollPropertySource(self, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+
+    // Set style name of ScrollBar for styling
+    mScrollBar.SetStyleName("TextEditorScrollBar");
+    Toolkit::Control scrollIndicator = Toolkit::Control::DownCast( mScrollBar.GetScrollIndicator() );
+    if( scrollIndicator )
+    {
+      // Set style name of ScrollBarIndicator for styling
+      scrollIndicator.SetStyleName("TextEditorScrollBarIndicator");
+    }
+
+    self.Add( mScrollBar );
+  }
+  else
+  {
+    Property::Index propertyScrollPosition = self.GetPropertyIndex( SCROLL_BAR_POSITION );
+    Property::Index propertyMaxScrollPosition = self.GetPropertyIndex( SCROLL_BAR_POSITION_MAX );
+    Property::Index propertyScrollContentSize = self.GetPropertyIndex( SCROLL_BAR_CONTENT_SIZE );
+
+    self.SetProperty( propertyScrollPosition, scrollPosition );
+    self.SetProperty( propertyMaxScrollPosition, (layoutSize - controlSize) );
+    self.SetProperty( propertyScrollContentSize, layoutSize );
+  }
+
+  // If scrolling is not started, start scrolling and emit ScrollStateChangedSignal
+  if( !mScrollStarted )
+  {
+    mScrollStarted = true;
+    Dali::Toolkit::TextEditor handle( GetOwner() );
+    mScrollStateChangedSignal.Emit( handle, Toolkit::TextEditor::Scroll::STARTED );
+  }
+
+  Actor indicator = mScrollBar.GetScrollIndicator();
+  if( mAnimation )
+  {
+    mAnimation.Stop(); // Cancel any animation
+  }
+  else
+  {
+    mAnimation = Animation::New( mAnimationPeriod.durationSeconds );
+  }
+  indicator.SetOpacity(1.0f);
+  mAnimation.AnimateTo( Property( indicator, Actor::Property::COLOR_ALPHA ), 0.0f, AlphaFunction::EASE_IN, mAnimationPeriod );
+  mAnimation.Play();
+  mAnimation.FinishedSignal().Connect( this, &TextEditor::OnScrollIndicatorAnimationFinished );
+}
+
+void TextEditor::OnScrollIndicatorAnimationFinished( Animation& animation )
+{
+  // If animation is successfully ended, then emit ScrollStateChangedSignal
+  if( animation.GetCurrentProgress() == 0.0f )
+  {
+    mScrollStarted = false;
+    Dali::Toolkit::TextEditor handle( GetOwner() );
+    mScrollStateChangedSignal.Emit( handle, Toolkit::TextEditor::Scroll::FINISHED );
+  }
+}
+
+void TextEditor::OnStageConnect( Dali::Actor actor )
+{
+  if ( mHasBeenStaged )
+  {
+    RenderText( static_cast<Text::Controller::UpdateTextType>( Text::Controller::MODEL_UPDATED | Text::Controller::DECORATOR_UPDATED ) );
+  }
+  else
+  {
+    mHasBeenStaged = true;
+  }
+}
+
+InputMethodContext::CallbackData TextEditor::OnInputMethodContextEvent( Dali::InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName );
+  return mController->OnInputMethodContextEvent( inputMethodContext, inputMethodContextEvent );
+}
+
+void TextEditor::GetHandleImagePropertyValue(  Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType )
+{
+  if( mDecorator )
+  {
+    ResourceImage image = ResourceImage::DownCast( mDecorator->GetHandleImage( handleType, handleImageType ) );
+
+    if ( image )
+    {
+      Property::Map map;
+      Scripting::CreatePropertyMap( image, map );
+      value = map;
+    }
+  }
+}
+
+void TextEditor::OnClipboardTextSelected( ClipboardEventNotifier& clipboard )
+{
+  mController->PasteClipboardItemEvent();
+}
+
+void TextEditor::KeyboardStatusChanged(bool keyboardShown)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown );
+
+  // Just hide the grab handle when keyboard is hidden.
+  if (!keyboardShown )
+  {
+    mController->KeyboardFocusLostEvent();
+  }
+  else
+  {
+    mController->KeyboardFocusGainEvent(); // Initially called by OnKeyInputFocusGained
+  }
+}
+
+void TextEditor::OnStageConnection( int depth )
+{
+  // Sets the depth to the visuals inside the text's decorator.
+  mDecorator->SetTextDepth( depth );
+
+  // The depth of the text renderer is set in the RenderText() called from OnRelayout().
+
+  // Call the Control::OnStageConnection() to set the depth of the background.
+  Control::OnStageConnection( depth );
+}
+
+bool TextEditor::OnTouched( Actor actor, const TouchData& touch )
+{
+  return true;
+}
+
+void TextEditor::OnIdleSignal()
+{
+  // Emits the change of input style signals.
+  mController->ProcessInputStyleChangedSignals();
+
+  // Set the pointer to null as the callback manager deletes the callback after execute it.
+  mIdleCallback = NULL;
+}
+
+void TextEditor::ApplyScrollPosition()
+{
+  const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
+  float scrollAmount = 0.0f;
+
+  if ( mScrollAnimationEnabled )
+  {
+    scrollAmount = mController->GetScrollAmountByUserInput();
+  }
+  if ( mTextVerticalScroller )
+  {
+    mTextVerticalScroller->CheckStartAnimation( mRenderableActor, scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount, scrollAmount );
+  }
+  else if ( Equals( scrollAmount, 0.0f, Math::MACHINE_EPSILON_1 ))
+  {
+    mRenderableActor.SetPosition( scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount );
+  }
+  else
+  {
+    mTextVerticalScroller = Text::TextVerticalScroller::New();
+    if ( !Equals( mScrollAnimationDuration, 0.0f, Math::MACHINE_EPSILON_1 ))
+    {
+      mTextVerticalScroller->SetDuration( mScrollAnimationDuration );
+    }
+    mTextVerticalScroller->CheckStartAnimation( mRenderableActor, scrollOffset.x + mAlignmentOffset, scrollOffset.y - scrollAmount, scrollAmount );
+  }
+}
+
+TextEditor::TextEditor()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mAnimationPeriod( 0.0f, 0.0f ),
+  mIdleCallback( NULL ),
+  mAlignmentOffset( 0.f ),
+  mScrollAnimationDuration( 0.f ),
+  mLineSpacing( 0.f ),
+  mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
+  mHasBeenStaged( false ),
+  mScrollAnimationEnabled( false ),
+  mScrollBarEnabled( false ),
+  mScrollStarted( false )
+{
+}
+
+TextEditor::~TextEditor()
+{
+  UnparentAndReset( mStencil );
+
+  if( ( NULL != mIdleCallback ) && Adaptor::IsAvailable() )
+  {
+    // Removes the callback from the callback manager in case the text-editor is destroyed before the callback is executed.
+    Adaptor::Get().RemoveIdle( mIdleCallback );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h
new file mode 100755 (executable)
index 0000000..5595e18
--- /dev/null
@@ -0,0 +1,342 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H
+
+/*
+ * Copyright (c) 2017 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 <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/animation/animation.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-vertical-scroller.h>
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+/**
+ * @brief A control which renders a long text string with styles.
+ */
+class TextEditor : public Control, public Text::ControlInterface, public Text::EditableControlInterface
+{
+public:
+
+  /**
+   * @copydoc Dali::Toollkit::TextEditor::New()
+   */
+  static Toolkit::TextEditor New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   *
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @copydoc Dali::Toollkit::TextEditor::GetInputMethodContext()
+   */
+  InputMethodContext GetInputMethodContext();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  /**
+   * @copydoc TextEditor::TextChangedSignal()
+   */
+  Toolkit::TextEditor::TextChangedSignalType&  TextChangedSignal();
+
+  /**
+   * @copydoc TextEditor::TextChangedSignal()
+   */
+  Toolkit::TextEditor::InputStyleChangedSignalType& InputStyleChangedSignal();
+
+  /**
+   * @copydoc TextEditor::ScrollStateChangedSignal()
+   */
+  Toolkit::TextEditor::ScrollStateChangedSignalType& ScrollStateChangedSignal();
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Control::OnStyleChange()
+   */
+  virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change );
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc Control::OnKeyInputFocusGained()
+   */
+  virtual void OnKeyInputFocusGained();
+
+  /**
+   * @copydoc Control::OnKeyInputFocusLost()
+   */
+  virtual void OnKeyInputFocusLost();
+
+  /**
+   * @copydoc Control::OnTap()
+   */
+  virtual void OnTap( const TapGesture& tap );
+
+  /**
+   * @copydoc Control::OnPan()
+   */
+  virtual void OnPan( const PanGesture& gesture );
+
+  /**
+   * @copydoc Control::OnLongPress()
+   */
+  virtual void OnLongPress( const LongPressGesture& gesture );
+
+  /**
+   * @copydoc Control::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Dali::CustomActorImpl::OnKeyEvent(const KeyEvent&)
+   */
+  virtual bool OnKeyEvent(const KeyEvent& event);
+
+// From ControlInterface
+
+  /**
+   * @copydoc Text::ControlInterface::RequestTextRelayout()
+   */
+  virtual void RequestTextRelayout();
+
+// From EditableControlInterface
+
+  /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
+   * @copydoc Text::ControlInterface::MaxLengthReached()
+   */
+  virtual void MaxLengthReached();
+
+  /**
+   * @copydoc Text::ControlInterface::InputStyleChanged()
+   */
+  virtual void InputStyleChanged( Text::InputStyle::Mask inputStyleMask );
+
+  /**
+   * @copydoc Text::ControlInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
+
+private: // Implementation
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
+   */
+  InputMethodContext::CallbackData OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent );
+
+  /**
+   * @brief Callback when Clipboard signals an item should be pasted
+   * @param[in] clipboard handle to Clipboard Event Notifier
+   */
+  void OnClipboardTextSelected( ClipboardEventNotifier& clipboard );
+
+  /**
+   * @brief Get a Property Map for the image used for the required Handle Image
+   * @param[out] value the returned image property
+   * @param[in] handleType the type of handle
+   * @param[in] handleImageType the type of image for the given handleType
+   */
+  void GetHandleImagePropertyValue(  Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType );
+
+  /**
+   * @brief Callback when keyboard is shown/hidden.
+   *
+   * @param[in] keyboardShown True if keyboard is shown.
+   */
+  void KeyboardStatusChanged( bool keyboardShown );
+
+  /**
+   * @brief update scroll bar position
+   *
+   * If text scroll is occurred, create or update scroll bar position
+   */
+  void UpdateScrollBar();
+
+  /**
+   * @brief Callback when TextEditor is touched
+   *
+   * @param[in] actor TextEditor touched
+   * @param[in] touch Touch information
+   */
+  bool OnTouched( Actor actor, const TouchData& touch );
+
+  /**
+   * @brief Callbacks called on idle.
+   *
+   * If there are notifications of change of input style on the queue, Toolkit::TextEditor::InputStyleChangedSignal() are emitted.
+   */
+  void OnIdleSignal();
+
+  /**
+   * @brief set RenderActor's position with new scrollPosition
+   *
+   * Apply updated scroll position or start scroll animation if VerticalScrollAnimation is enabled
+   */
+  void ApplyScrollPosition();
+
+  /**
+   * @brief Callback function for ScrollBar indicator animation finished signal
+   *
+   * Emit ScrollBarStateChanged Signal and toggle mScrollStarted flag to false
+   */
+  void OnScrollIndicatorAnimationFinished( Animation& animation );
+
+  /**
+   * Construct a new TextEditor.
+   */
+  TextEditor();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextEditor();
+
+  // Undefined copy constructor and assignment operators
+  TextEditor(const TextEditor&);
+  TextEditor& operator=(const TextEditor& rhs);
+
+  /**
+   * @brief Render view, create and attach actor(s) to this text editor.
+   */
+  void RenderText( Text::Controller::UpdateTextType updateTextType );
+
+  // Connection needed to re-render text, when a text editor returns to the stage.
+  void OnStageConnect( Dali::Actor actor );
+
+private: // Data
+  // Signals
+  Toolkit::TextEditor::TextChangedSignalType mTextChangedSignal;
+  Toolkit::TextEditor::InputStyleChangedSignalType mInputStyleChangedSignal;
+  Toolkit::TextEditor::ScrollStateChangedSignalType mScrollStateChangedSignal;
+
+  InputMethodContext mInputMethodContext;
+  Text::ControllerPtr mController;
+  Text::RendererPtr mRenderer;
+  Text::DecoratorPtr mDecorator;
+  Text::TextVerticalScrollerPtr mTextVerticalScroller;
+  Toolkit::Control mStencil;
+  Toolkit::ScrollBar mScrollBar;
+  Dali::Animation mAnimation;                                              ///< Scroll indicator Show/Hide Animation.
+  Dali::TimePeriod mAnimationPeriod;
+  std::vector<Actor> mClippingDecorationActors;   ///< Decoration actors which need clipping.
+
+  Actor mRenderableActor;
+  Actor mActiveLayer;
+  CallbackBase* mIdleCallback;
+
+  float mAlignmentOffset;
+  float mScrollAnimationDuration;
+  float mLineSpacing;
+  int mRenderingBackend;
+  bool mHasBeenStaged:1;
+  bool mScrollAnimationEnabled:1;
+  bool mScrollBarEnabled:1;
+  bool mScrollStarted:1;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextEditor& GetImpl( Toolkit::TextEditor& textEditor )
+{
+  DALI_ASSERT_ALWAYS(textEditor);
+
+  Dali::RefObject& handle = textEditor.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextEditor&>(handle);
+}
+
+inline const Toolkit::Internal::TextEditor& GetImpl( const Toolkit::TextEditor& textEditor )
+{
+  DALI_ASSERT_ALWAYS(textEditor);
+
+  const Dali::RefObject& handle = textEditor.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextEditor&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H
diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
new file mode 100755 (executable)
index 0000000..e9d1fe4
--- /dev/null
@@ -0,0 +1,1887 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-field-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/internal/text/rendering/text-backend.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+using namespace Dali::Toolkit::Text;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
+#endif
+
+  const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+} // unnamed namespace
+
+namespace
+{
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::TextField::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextField, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "renderingBackend",                     INTEGER,   RENDERING_BACKEND                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "text",                                 STRING,    TEXT                                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholderText",                      STRING,    PLACEHOLDER_TEXT                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholderTextFocused",               STRING,    PLACEHOLDER_TEXT_FOCUSED             )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "fontFamily",                           STRING,    FONT_FAMILY                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "fontStyle",                            MAP,       FONT_STYLE                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "pointSize",                            FLOAT,     POINT_SIZE                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "maxLength",                            INTEGER,   MAX_LENGTH                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "exceedPolicy",                         INTEGER,   EXCEED_POLICY                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "horizontalAlignment",                  STRING,    HORIZONTAL_ALIGNMENT                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "verticalAlignment",                    STRING,    VERTICAL_ALIGNMENT                   )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "textColor",                            VECTOR4,   TEXT_COLOR                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholderTextColor",                 VECTOR4,   PLACEHOLDER_TEXT_COLOR               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "reservedProperty01",                   STRING,    RESERVED_PROPERTY_01                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "reservedProperty02",                   STRING,    RESERVED_PROPERTY_02                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "primaryCursorColor",                   VECTOR4,   PRIMARY_CURSOR_COLOR                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "secondaryCursorColor",                 VECTOR4,   SECONDARY_CURSOR_COLOR               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "enableCursorBlink",                    BOOLEAN,   ENABLE_CURSOR_BLINK                  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "cursorBlinkInterval",                  FLOAT,     CURSOR_BLINK_INTERVAL                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "cursorBlinkDuration",                  FLOAT,     CURSOR_BLINK_DURATION                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "cursorWidth",                          INTEGER,   CURSOR_WIDTH                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "grabHandleImage",                      STRING,    GRAB_HANDLE_IMAGE                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "grabHandlePressedImage",               STRING,    GRAB_HANDLE_PRESSED_IMAGE            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "scrollThreshold",                      FLOAT,     SCROLL_THRESHOLD                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "scrollSpeed",                          FLOAT,     SCROLL_SPEED                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandleImageLeft",             MAP,       SELECTION_HANDLE_IMAGE_LEFT          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandleImageRight",            MAP,       SELECTION_HANDLE_IMAGE_RIGHT         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandlePressedImageLeft",      MAP,       SELECTION_HANDLE_PRESSED_IMAGE_LEFT  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandlePressedImageRight",     MAP,       SELECTION_HANDLE_PRESSED_IMAGE_RIGHT )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandleMarkerImageLeft",       MAP,       SELECTION_HANDLE_MARKER_IMAGE_LEFT   )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHandleMarkerImageRight",      MAP,       SELECTION_HANDLE_MARKER_IMAGE_RIGHT  )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selectionHighlightColor",              VECTOR4,   SELECTION_HIGHLIGHT_COLOR            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "decorationBoundingBox",                RECTANGLE, DECORATION_BOUNDING_BOX              )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputMethodSettings",                  MAP,       INPUT_METHOD_SETTINGS                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputColor",                           VECTOR4,   INPUT_COLOR                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "enableMarkup",                         BOOLEAN,   ENABLE_MARKUP                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputFontFamily",                      STRING,    INPUT_FONT_FAMILY                    )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputFontStyle",                       MAP,       INPUT_FONT_STYLE                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputPointSize",                       FLOAT,     INPUT_POINT_SIZE                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "underline",                            MAP,       UNDERLINE                            )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputUnderline",                       MAP,       INPUT_UNDERLINE                      )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadow",                               MAP,       SHADOW                               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputShadow",                          MAP,       INPUT_SHADOW                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "emboss",                               MAP,       EMBOSS                               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputEmboss",                          MAP,       INPUT_EMBOSS                         )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "outline",                              MAP,       OUTLINE                              )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputOutline",                         MAP,       INPUT_OUTLINE                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "hiddenInputSettings",                  MAP,       HIDDEN_INPUT_SETTINGS                )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "pixelSize",                            FLOAT,     PIXEL_SIZE                           )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "enableSelection",                      BOOLEAN,   ENABLE_SELECTION                     )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholder",                          MAP,       PLACEHOLDER                          )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "ellipsis",                             BOOLEAN,   ELLIPSIS                             )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "enableShiftSelection",           BOOLEAN,   ENABLE_SHIFT_SELECTION               )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "enableGrabHandle",               BOOLEAN,   ENABLE_GRAB_HANDLE                   )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "matchSystemLanguageDirection",   BOOLEAN,   MATCH_SYSTEM_LANGUAGE_DIRECTION      )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "enableGrabHandlePopup",          BOOLEAN,   ENABLE_GRAB_HANDLE_POPUP             )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextField, "textBackground",                 VECTOR4,   BACKGROUND                           )
+
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "textChanged",        SIGNAL_TEXT_CHANGED )
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "maxLengthReached",   SIGNAL_MAX_LENGTH_REACHED )
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "inputStyleChanged",  SIGNAL_INPUT_STYLE_CHANGED )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Toolkit::TextField TextField::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextField > impl = new TextField();
+
+  // Pass ownership to CustomActor handle
+  Toolkit::TextField handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextField::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField SetProperty\n");
+
+
+  if( textField )
+  {
+    TextField& impl( GetImpl( textField ) );
+
+    switch( index )
+    {
+      case Toolkit::TextField::Property::RENDERING_BACKEND:
+      {
+        int backend = value.Get< int >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p RENDERING_BACKEND %d\n", impl.mController.Get(), backend );
+
+#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
+        if( Text::RENDERING_VECTOR_BASED == backend )
+        {
+          backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
+        }
+#endif
+        if( impl.mRenderingBackend != backend )
+        {
+          impl.mRenderingBackend = backend;
+          impl.mRenderer.Reset();
+
+          if( impl.mController )
+          {
+            // When using the vector-based rendering, the size of the GLyphs are different
+            TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+            impl.mController->SetGlyphType( glyphType );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          const std::string& text = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p TEXT %s\n", impl.mController.Get(), text.c_str() );
+
+          impl.mController->SetText( text );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
+      {
+        if( impl.mController )
+        {
+          const std::string& text = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT %s\n", impl.mController.Get(), text.c_str() );
+
+          impl.mController->SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
+      {
+        if( impl.mController )
+        {
+          const std::string& text = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_FOCUSED %s\n", impl.mController.Get(), text.c_str() );
+
+          impl.mController->SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          const std::string& fontFamily = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
+          impl.mController->SetDefaultFontFamily( fontFamily );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::FONT_STYLE:
+      {
+        SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pointSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p POINT_SIZE %f\n", impl.mController.Get(), pointSize );
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::MAX_LENGTH:
+      {
+        if( impl.mController )
+        {
+          const int max = value.Get< int >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p MAX_LENGTH %d\n", impl.mController.Get(), max );
+
+          impl.mController->SetMaximumNumberOfCharacters( max );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::EXCEED_POLICY:
+      {
+        impl.mExceedPolicy = value.Get<int>();
+
+        if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == impl.mExceedPolicy )
+        {
+          impl.EnableClipping();
+        }
+        else
+        {
+          UnparentAndReset( impl.mStencil );
+        }
+        impl.RequestTextRelayout();
+        break;
+      }
+      case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( GetHorizontalAlignmentEnumeration( value, alignment ) )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p HORIZONTAL_ALIGNMENT %d\n", impl.mController.Get(), alignment );
+            impl.mController->SetHorizontalAlignment( alignment );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( GetVerticalAlignmentEnumeration( value, alignment ) )
+          {
+            impl.mController->SetVerticalAlignment( alignment );
+            DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p VERTICAL_ALIGNMENT %d\n", impl.mController.Get(), alignment );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::TEXT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4& textColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
+
+          if( impl.mController->GetDefaultColor() != textColor )
+          {
+            impl.mController->SetDefaultColor( textColor );
+            impl.mController->SetInputColor( textColor );
+            impl.mRenderer.Reset();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4& textColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PLACEHOLDER_TEXT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), textColor.r, textColor.g, textColor.b, textColor.a );
+
+          if( impl.mController->GetPlaceholderTextColor() != textColor )
+          {
+            impl.mController->SetPlaceholderTextColor( textColor );
+            impl.mRenderer.Reset();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          const Vector4& color = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PRIMARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+          impl.mDecorator->SetCursorColor( PRIMARY_CURSOR, color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          const Vector4& color = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SECONDARY_CURSOR_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+          impl.mDecorator->SetCursorColor( SECONDARY_CURSOR, color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
+      {
+        if( impl.mController )
+        {
+          const bool enable = value.Get< bool >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p ENABLE_CURSOR_BLINK %d\n", impl.mController.Get(), enable );
+
+          impl.mController->SetEnableCursorBlink( enable );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
+      {
+        if( impl.mDecorator )
+        {
+          const float interval = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_INTERVAL %f\n", impl.mController.Get(), interval );
+
+          impl.mDecorator->SetCursorBlinkInterval( interval );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
+      {
+        if( impl.mDecorator )
+        {
+          const float duration = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_BLINK_DURATION %f\n", impl.mController.Get(), duration );
+
+          impl.mDecorator->SetCursorBlinkDuration( duration );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_WIDTH:
+      {
+        if( impl.mDecorator )
+        {
+          const int width = value.Get< int >();
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p CURSOR_WIDTH %d\n", impl.mController.Get(), width );
+
+          impl.mDecorator->SetCursorWidth( width );
+          impl.mController->GetLayoutEngine().SetCursorWidth( width );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
+      {
+        const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
+      {
+        const ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p GRAB_HANDLE_PRESSED_IMAGE %s\n", impl.mController.Get(), image.GetUrl().c_str() );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SCROLL_THRESHOLD:
+      {
+        const float threshold = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_THRESHOLD %f\n", impl.mController.Get(), threshold );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetScrollThreshold( threshold );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SCROLL_SPEED:
+      {
+        const float speed = value.Get< float >();
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField %p SCROLL_SPEED %f\n", impl.mController.Get(), speed );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetScrollSpeed( speed );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+      {
+        const Image image = Scripting::NewImage( value );
+
+        if( impl.mDecorator && image )
+        {
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED, image );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
+      {
+        const Vector4 color = value.Get< Vector4 >();
+        DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p SELECTION_HIGHLIGHT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), color.r, color.g, color.b, color.a );
+
+        if( impl.mDecorator )
+        {
+          impl.mDecorator->SetHighlightColor( color );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
+      {
+        if( impl.mDecorator )
+        {
+          const Rect<int> box = value.Get< Rect<int> >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p DECORATION_BOUNDING_BOX %d,%d %dx%d\n", impl.mController.Get(), box.x, box.y, box.width, box.height );
+
+          impl.mDecorator->SetBoundingBox( box );
+          impl.RequestTextRelayout();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
+      {
+        const Property::Map* map = value.GetMap();
+        if (map)
+        {
+          impl.mInputMethodOptions.ApplyProperty( *map );
+        }
+        impl.mController->SetInputModePassword( impl.mInputMethodOptions.IsPassword() );
+
+        Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+        if (control == textField)
+        {
+          impl.mInputMethodContext.ApplyOptions( impl.mInputMethodOptions );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4 inputColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a );
+
+          impl.mController->SetInputColor( inputColor );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          const bool enableMarkup = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ENABLE_MARKUP %d\n", impl.mController.Get(), enableMarkup );
+
+          impl.mController->SetMarkupProcessorEnabled( enableMarkup );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          const std::string& fontFamily = value.Get< std::string >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p INPUT_FONT_FAMILY %s\n", impl.mController.Get(), fontFamily.c_str() );
+          impl.mController->SetInputFontFamily( fontFamily );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_FONT_STYLE:
+      {
+        SetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pointSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p INPUT_POINT_SIZE %f\n", impl.mController.Get(), pointSize );
+          impl.mController->SetInputFontPointSize( pointSize );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::UNDERLINE:
+      {
+        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_UNDERLINE:
+      {
+        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SHADOW:
+      {
+        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_SHADOW:
+      {
+        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::EMBOSS:
+      {
+        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_EMBOSS:
+      {
+        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::OUTLINE:
+      {
+        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_OUTLINE:
+      {
+        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        if( update )
+        {
+          impl.mRenderer.Reset();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
+      {
+        const Property::Map* map = value.GetMap();
+        if (map)
+        {
+          impl.mController->SetHiddenInputOption(*map);
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pixelSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_SELECTION:
+      {
+        if( impl.mController )
+        {
+          const bool enableSelection = value.Get< bool >();
+           DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ENABLE_SELECTION %d\n", impl.mController.Get(), enableSelection );
+          impl.mController->SetSelectionEnabled( enableSelection );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER:
+      {
+        const Property::Map* map = value.GetMap();
+        if( map )
+        {
+          impl.mController->SetPlaceholderProperty( *map );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ELLIPSIS:
+      {
+        if( impl.mController )
+        {
+          const bool ellipsis = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
+
+          impl.mController->SetTextElideEnabled( ellipsis );
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
+      {
+        if( impl.mController )
+        {
+          const bool shiftSelection = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ENABLE_SHIFT_SELECTION %d\n", impl.mController.Get(), shiftSelection );
+
+          impl.mController->SetShiftSelectionEnabled( shiftSelection );
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
+      {
+        if( impl.mController )
+        {
+          const bool grabHandleEnabled = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE %d\n", impl.mController.Get(), grabHandleEnabled );
+
+          impl.mController->SetGrabHandleEnabled( grabHandleEnabled );
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        if( impl.mController )
+        {
+          impl.mController->SetMatchSystemLanguageDirection(value.Get< bool >());
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
+      {
+        if( impl.mController )
+        {
+          const bool grabHandlePopupEnabled = value.Get<bool>();
+          DALI_LOG_INFO(gLogFilter, Debug::General, "TextField %p ENABLE_GRAB_HANDLE_POPUP %d\n", impl.mController.Get(), grabHandlePopupEnabled);
+
+          impl.mController->SetGrabHandlePopupEnabled(grabHandlePopupEnabled);
+          break;
+        }
+      }
+      case Toolkit::DevelTextField::Property::BACKGROUND:
+      {
+        if( impl.mController )
+        {
+          const Vector4 backgroundColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p BACKGROUND %f,%f,%f,%f\n", impl.mController.Get(), backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a );
+
+          impl.mController->SetBackgroundEnabled( true );
+          impl.mController->SetBackgroundColor( backgroundColor );
+        }
+        break;
+      }
+    } // switch
+  } // textfield
+}
+
+Property::Value TextField::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextField textField = Toolkit::TextField::DownCast( Dali::BaseHandle( object ) );
+
+  if( textField )
+  {
+    TextField& impl( GetImpl( textField ) );
+
+    switch( index )
+    {
+      case Toolkit::TextField::Property::RENDERING_BACKEND:
+      {
+        value = impl.mRenderingBackend;
+        break;
+      }
+      case Toolkit::TextField::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetText( text );
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p returning text: %s\n", impl.mController.Get(), text.c_str() );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_FOCUSED:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontFamily();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::FONT_STYLE:
+      {
+        GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::MAX_LENGTH:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetMaximumNumberOfCharacters();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::EXCEED_POLICY:
+      {
+        value = impl.mExceedPolicy;
+        break;
+      }
+      case Toolkit::TextField::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          const char* name = Text::GetHorizontalAlignmentString( impl.mController->GetHorizontalAlignment() );
+
+          if ( name )
+          {
+            value = std::string( name );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::VERTICAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          const char* name = Text::GetVerticalAlignmentString( impl.mController->GetVerticalAlignment() );
+
+          if( name )
+          {
+            value = std::string( name );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::TEXT_COLOR:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->GetDefaultColor();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER_TEXT_COLOR:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->GetPlaceholderTextColor();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PRIMARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetColor( PRIMARY_CURSOR );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SECONDARY_CURSOR_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetColor( SECONDARY_CURSOR );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_CURSOR_BLINK:
+      {
+        value = impl.mController->GetEnableCursorBlink();
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_BLINK_INTERVAL:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorBlinkInterval();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_BLINK_DURATION:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorBlinkDuration();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::CURSOR_WIDTH:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetCursorWidth();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::GRAB_HANDLE_IMAGE:
+      {
+        if( impl.mDecorator )
+        {
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) );
+          if( image )
+          {
+            value = image.GetUrl();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::GRAB_HANDLE_PRESSED_IMAGE:
+      {
+        if( impl.mDecorator )
+        {
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) );
+          if( image )
+          {
+            value = image.GetUrl();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SCROLL_THRESHOLD:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetScrollThreshold();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SCROLL_SPEED:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetScrollSpeed();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) ;
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED );
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_PRESSED_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED );
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_LEFT:
+      {
+        impl.GetHandleImagePropertyValue( value, LEFT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HANDLE_MARKER_IMAGE_RIGHT:
+      {
+        impl.GetHandleImagePropertyValue( value, RIGHT_SELECTION_HANDLE_MARKER, HANDLE_IMAGE_RELEASED );
+        break;
+      }
+      case Toolkit::TextField::Property::SELECTION_HIGHLIGHT_COLOR:
+      {
+        if( impl.mDecorator )
+        {
+          value = impl.mDecorator->GetHighlightColor();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::DECORATION_BOUNDING_BOX:
+      {
+        if( impl.mDecorator )
+        {
+          Rect<int> boundingBox;
+          impl.mDecorator->GetBoundingBox( boundingBox );
+          value = boundingBox;
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_METHOD_SETTINGS:
+      {
+        Property::Map map;
+        impl.mInputMethodOptions.RetrieveProperty( map );
+        value = map;
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputColor();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMarkupProcessorEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputFontFamily();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_FONT_STYLE:
+      {
+        GetFontStyleProperty( impl.mController, value, Text::FontStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputFontPointSize();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::UNDERLINE:
+      {
+        GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_UNDERLINE:
+      {
+        GetUnderlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::SHADOW:
+      {
+        GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_SHADOW:
+      {
+        GetShadowProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::EMBOSS:
+      {
+        GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_EMBOSS:
+      {
+        GetEmbossProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::OUTLINE:
+      {
+        GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextField::Property::INPUT_OUTLINE:
+      {
+        GetOutlineProperties( impl.mController, value, Text::EffectStyle::INPUT );
+        break;
+      }
+      case Toolkit::TextField::Property::HIDDEN_INPUT_SETTINGS:
+      {
+        Property::Map map;
+        impl.mController->GetHiddenInputOption(map);
+        value = map;
+        break;
+      }
+      case Toolkit::TextField::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::ENABLE_SELECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsSelectionEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextField::Property::PLACEHOLDER:
+      {
+        Property::Map map;
+        impl.mController->GetPlaceholderProperty( map );
+        value = map;
+        break;
+      }
+      case Toolkit::TextField::Property::ELLIPSIS:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsTextElideEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_SHIFT_SELECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsShiftSelectionEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsGrabHandleEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMatchSystemLanguageDirection();
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::ENABLE_GRAB_HANDLE_POPUP:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsGrabHandlePopupEnabled();
+        }
+        break;
+      }
+      case Toolkit::DevelTextField::Property::BACKGROUND:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetBackgroundColor();
+        }
+        break;
+      }
+    } //switch
+  }
+
+  return value;
+}
+
+void TextField::SelectWholeText()
+{
+  if( mController && mController->IsShowingRealText() )
+  {
+    mController->SelectEvent( 0.f, 0.f, true );
+    SetKeyInputFocus();
+  }
+}
+
+InputMethodContext TextField::GetInputMethodContext()
+{
+  return mInputMethodContext;
+}
+
+bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_CHANGED ) )
+  {
+    field.TextChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
+  {
+    field.MaxLengthReachedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_INPUT_STYLE_CHANGED ) )
+  {
+    field.InputStyleChangedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+Toolkit::TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return mTextChangedSignal;
+}
+
+Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
+{
+  return mMaxLengthReachedSignal;
+}
+
+Toolkit::TextField::InputStyleChangedSignalType& TextField::InputStyleChangedSignal()
+{
+  return mInputStyleChangedSignal;
+}
+
+void TextField::OnInitialize()
+{
+  Actor self = Self();
+
+  mController = Text::Controller::New( this, this );
+
+  // When using the vector-based rendering, the size of the GLyphs are different
+  TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+  mController->SetGlyphType( glyphType );
+
+  mDecorator = Text::Decorator::New( *mController,
+                                     *mController );
+
+  mInputMethodContext = InputMethodContext::New( self );
+
+  mController->GetLayoutEngine().SetLayout( Layout::Engine::SINGLE_LINE_BOX );
+
+  // Enables the text input.
+  mController->EnableTextInput( mDecorator, mInputMethodContext );
+
+  // Enables the horizontal scrolling after the text input has been enabled.
+  mController->SetHorizontalScrollEnabled( true );
+
+  // Disables the vertical scrolling.
+  mController->SetVerticalScrollEnabled( false );
+
+  // Disable the smooth handle panning.
+  mController->SetSmoothHandlePanEnabled( false );
+
+  mController->SetNoTextDoubleTapAction( Controller::NoTextTap::HIGHLIGHT );
+  mController->SetNoTextLongPressAction( Controller::NoTextTap::HIGHLIGHT );
+
+  // Sets layoutDirection value
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( stage.GetRootLayer().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+  mController->SetLayoutDirection( layoutDirection );
+
+  // Forward input events to controller
+  EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
+  GetTapGestureDetector().SetMaximumTapsRequired( 2 );
+
+  self.TouchSignal().Connect( this, &TextField::OnTouched );
+
+  // Set BoundingBox to stage size if not already set.
+  Rect<int> boundingBox;
+  mDecorator->GetBoundingBox( boundingBox );
+
+  if( boundingBox.IsEmpty() )
+  {
+    Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
+    mDecorator->SetBoundingBox( Rect<int>( 0.0f, 0.0f, stageSize.width, stageSize.height ) );
+  }
+
+  // Flip vertically the 'left' selection handle
+  mDecorator->FlipHandleVertically( LEFT_SELECTION_HANDLE, true );
+
+  // Fill-parent area by default
+  self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+  self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
+  self.OnStageSignal().Connect( this, &TextField::OnStageConnect );
+
+  DevelControl::SetInputMethodContext( *this, mInputMethodContext );
+
+  if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy )
+  {
+    EnableClipping();
+  }
+}
+
+void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+{
+  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");
+      const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
+      // Property system did not set the font so should update it.
+      mController->UpdateAfterFontChange( newFont );
+      RelayoutRequest();
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+      RelayoutRequest();
+      break;
+    }
+    case StyleChange::THEME_CHANGE:
+    {
+      // Nothing to do, let control base class handle this
+      break;
+    }
+  }
+
+  // Up call to Control
+  Control::OnStyleChange( styleManager, change );
+}
+
+Vector3 TextField::GetNaturalSize()
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector3 naturalSize = mController->GetNaturalSize();
+  naturalSize.width += ( padding.start + padding.end );
+  naturalSize.height += ( padding.top + padding.bottom );
+
+  return naturalSize;
+}
+
+float TextField::GetHeightForWidth( float width )
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
+}
+
+void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField OnRelayout\n");
+
+  Actor self = Self();
+
+  Extents padding;
+  padding = self.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) );
+
+  // Support Right-To-Left of padding
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( self.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+  if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+  {
+    std::swap( padding.start, padding.end );
+  }
+
+  if( mStencil )
+  {
+    mStencil.SetPosition( padding.start, padding.top );
+  }
+  if( mActiveLayer )
+  {
+    mActiveLayer.SetPosition( padding.start, padding.top );
+  }
+
+  const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize, layoutDirection );
+
+  if( ( Text::Controller::NONE_UPDATED != updateTextType ) ||
+      !mRenderer )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnRelayout %p Displaying new contents\n", mController.Get() );
+
+    if( mDecorator &&
+        ( Text::Controller::NONE_UPDATED != ( Text::Controller::DECORATOR_UPDATED & updateTextType ) ) )
+    {
+      mDecorator->Relayout( size );
+    }
+
+    if( !mRenderer )
+    {
+      mRenderer = Backend::Get().NewRenderer( mRenderingBackend );
+    }
+
+    RenderText( updateTextType );
+
+  }
+
+  // The text-field emits signals when the input style changes. These changes of style are
+  // detected during the relayout process (size negotiation), i.e after the cursor has been moved. Signals
+  // can't be emitted during the size negotiation as the callbacks may update the UI.
+  // The text-field adds an idle callback to the adaptor to emit the signals after the size negotiation.
+  if( !mController->IsInputStyleChangedSignalsQueueEmpty() )
+  {
+    if( Adaptor::IsAvailable() )
+    {
+      Adaptor& adaptor = Adaptor::Get();
+
+      if( NULL == mIdleCallback )
+      {
+        // @note: The callback manager takes the ownership of the callback object.
+        mIdleCallback = MakeCallback( this, &TextField::OnIdleSignal );
+        adaptor.AddIdle( mIdleCallback, false );
+      }
+    }
+  }
+}
+
+void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
+{
+  Actor renderableActor;
+
+  if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
+  {
+    if( mRenderer )
+    {
+      Dali::Toolkit::TextField handle = Dali::Toolkit::TextField( GetOwner() );
+
+      renderableActor = mRenderer->Render( mController->GetView(),
+                                           handle,
+                                           Property::INVALID_INDEX, // Animatable property not supported
+                                           mAlignmentOffset,
+                                           DepthIndex::CONTENT );
+    }
+
+    if( renderableActor != mRenderableActor )
+    {
+      UnparentAndReset( mBackgroundActor );
+      UnparentAndReset( mRenderableActor );
+      mRenderableActor = renderableActor;
+
+      if ( mRenderableActor )
+      {
+        mBackgroundActor = mController->CreateBackgroundActor();
+      }
+    }
+  }
+
+  if( mRenderableActor )
+  {
+    const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
+
+    float renderableActorPositionX, renderableActorPositionY;
+
+    if( mStencil )
+    {
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset;
+      renderableActorPositionY = scrollOffset.y;
+    }
+    else
+    {
+      Extents padding;
+      padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+      // Support Right-To-Left of padding
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+      {
+        std::swap( padding.start, padding.end );
+      }
+
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset + padding.start;
+      renderableActorPositionY = scrollOffset.y + padding.top;
+    }
+
+    mRenderableActor.SetPosition( renderableActorPositionX, renderableActorPositionY );
+
+    // Make sure the actors are parented correctly with/without clipping
+    Actor self = mStencil ? mStencil : Self();
+
+    Actor highlightActor;
+
+    for( std::vector<Actor>::iterator it = mClippingDecorationActors.begin(),
+           endIt = mClippingDecorationActors.end();
+         it != endIt;
+         ++it )
+    {
+      self.Add( *it );
+      it->LowerToBottom();
+
+      if ( it->GetName() == "HighlightActor" )
+      {
+        highlightActor = *it;
+      }
+    }
+    mClippingDecorationActors.clear();
+
+    self.Add( mRenderableActor );
+
+    if ( mBackgroundActor )
+    {
+      if ( mDecorator && mDecorator->IsHighlightVisible() )
+      {
+        self.Add( mBackgroundActor );
+        mBackgroundActor.SetPosition( renderableActorPositionX, renderableActorPositionY); // In text field's coords.
+        mBackgroundActor.LowerBelow( highlightActor );
+      }
+      else
+      {
+        mRenderableActor.Add( mBackgroundActor );
+        mBackgroundActor.SetPosition( 0.0f, 0.0f ); // In renderable actor's coords.
+        mBackgroundActor.LowerToBottom();
+      }
+    }
+  }
+}
+
+void TextField::OnKeyInputFocusGained()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyInputFocusGained %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.ApplyOptions( mInputMethodOptions );
+
+    mInputMethodContext.StatusChangedSignal().Connect( this, &TextField::KeyboardStatusChanged );
+
+    mInputMethodContext.EventReceivedSignal().Connect( this, &TextField::OnInputMethodContextEvent );
+
+    // Notify that the text editing start.
+    mInputMethodContext.Activate();
+
+    // When window gain lost focus, the inputMethodContext is deactivated. Thus when window gain focus again, the inputMethodContext must be activated.
+    mInputMethodContext.SetRestoreAfterFocusLost( true );
+  }
+  ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
+
+  if ( notifier )
+  {
+    notifier.ContentSelectedSignal().Connect( this, &TextField::OnClipboardTextSelected );
+  }
+
+  mController->KeyboardFocusGainEvent(); // Called in the case of no virtual keyboard to trigger this event
+
+  EmitKeyInputFocusSignal( true ); // Calls back into the Control hence done last.
+}
+
+void TextField::OnKeyInputFocusLost()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField:OnKeyInputFocusLost %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.StatusChangedSignal().Disconnect( this, &TextField::KeyboardStatusChanged );
+    // The text editing is finished. Therefore the inputMethodContext don't have restore activation.
+    mInputMethodContext.SetRestoreAfterFocusLost( false );
+
+    // Notify that the text editing finish.
+    mInputMethodContext.Deactivate();
+
+    mInputMethodContext.EventReceivedSignal().Disconnect( this, &TextField::OnInputMethodContextEvent );
+  }
+  ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
+
+  if ( notifier )
+  {
+    notifier.ContentSelectedSignal().Disconnect( this, &TextField::OnClipboardTextSelected );
+  }
+
+  mController->KeyboardFocusLostEvent();
+
+  EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last.
+}
+
+void TextField::OnTap( const TapGesture& gesture )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get() );
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.Activate();
+  }
+  // Deliver the tap before the focus event to controller; this allows us to detect when focus is gained due to tap-gestures
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  mController->TapEvent( gesture.numberOfTaps, gesture.localPoint.x - padding.start, gesture.localPoint.y - padding.top );
+
+  SetKeyInputFocus();
+}
+
+void TextField::OnPan( const PanGesture& gesture )
+{
+  mController->PanEvent( gesture.state, gesture.displacement );
+}
+
+void TextField::OnLongPress( const LongPressGesture& gesture )
+{
+  if ( mInputMethodContext )
+  {
+    mInputMethodContext.Activate();
+  }
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+  mController->LongPressEvent( gesture.state, gesture.localPoint.x - padding.start, gesture.localPoint.y - padding.top );
+
+  SetKeyInputFocus();
+}
+
+bool TextField::OnKeyEvent( const KeyEvent& event )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnKeyEvent %p keyCode %d\n", mController.Get(), event.keyCode );
+
+  if( Dali::DALI_KEY_ESCAPE == event.keyCode && mController->ShouldClearFocusOnEscape() )
+  {
+    // Make sure ClearKeyInputFocus when only key is up
+    if( event.state == KeyEvent::Up )
+    {
+      ClearKeyInputFocus();
+    }
+
+    return true;
+  }
+  else if( Dali::DevelKey::DALI_KEY_RETURN == event.keyCode )
+  {
+    // Do nothing when enter is comming.
+    return false;
+  }
+
+  return mController->KeyEvent( event );
+}
+
+void TextField::RequestTextRelayout()
+{
+  RelayoutRequest();
+}
+
+void TextField::TextChanged()
+{
+  Dali::Toolkit::TextField handle( GetOwner() );
+  mTextChangedSignal.Emit( handle );
+}
+
+void TextField::MaxLengthReached()
+{
+  Dali::Toolkit::TextField handle( GetOwner() );
+  mMaxLengthReachedSignal.Emit( handle );
+}
+
+void TextField::InputStyleChanged( Text::InputStyle::Mask inputStyleMask )
+{
+  Dali::Toolkit::TextField handle( GetOwner() );
+
+  Toolkit::TextField::InputStyle::Mask fieldInputStyleMask = Toolkit::TextField::InputStyle::NONE;
+
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_COLOR ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::COLOR );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_FAMILY ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_FAMILY );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_POINT_SIZE ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::POINT_SIZE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_WEIGHT ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_WIDTH ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_FONT_SLANT ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::FONT_STYLE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_UNDERLINE ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::UNDERLINE );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_SHADOW ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::SHADOW );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_EMBOSS ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::EMBOSS );
+  }
+  if( InputStyle::NONE != static_cast<InputStyle::Mask>( inputStyleMask & InputStyle::INPUT_OUTLINE ) )
+  {
+    fieldInputStyleMask = static_cast<Toolkit::TextField::InputStyle::Mask>( fieldInputStyleMask | Toolkit::TextField::InputStyle::OUTLINE );
+  }
+
+  mInputStyleChangedSignal.Emit( handle, fieldInputStyleMask );
+}
+
+void TextField::AddDecoration( Actor& actor, bool needsClipping )
+{
+  if( actor )
+  {
+    if( needsClipping )
+    {
+      mClippingDecorationActors.push_back( actor );
+    }
+    else
+    {
+      actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      Self().Add( actor );
+      mActiveLayer = actor;
+    }
+  }
+}
+
+void TextField::OnStageConnect( Dali::Actor actor )
+{
+  if ( mHasBeenStaged )
+  {
+    RenderText( static_cast<Text::Controller::UpdateTextType>( Text::Controller::MODEL_UPDATED | Text::Controller::DECORATOR_UPDATED ) );
+  }
+  else
+  {
+    mHasBeenStaged = true;
+  }
+}
+
+InputMethodContext::CallbackData TextField::OnInputMethodContextEvent( Dali::InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnInputMethodContextEvent %p eventName %d\n", mController.Get(), inputMethodContextEvent.eventName );
+  return mController->OnInputMethodContextEvent( inputMethodContext, inputMethodContextEvent );
+}
+
+void TextField::GetHandleImagePropertyValue(  Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType )
+{
+  if( mDecorator )
+  {
+    ResourceImage image = ResourceImage::DownCast( mDecorator->GetHandleImage( handleType, handleImageType ) );
+
+    if ( image )
+    {
+      Property::Map map;
+      Scripting::CreatePropertyMap( image, map );
+      value = map;
+    }
+  }
+}
+
+void TextField::EnableClipping()
+{
+  if( !mStencil )
+  {
+    // Creates an extra control to be used as stencil buffer.
+    mStencil = Control::New();
+    mStencil.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    mStencil.SetParentOrigin( ParentOrigin::TOP_LEFT );
+
+    // Creates a background visual. Even if the color is transparent it updates the stencil.
+    mStencil.SetProperty( Toolkit::Control::Property::BACKGROUND,
+                          Property::Map().Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR ).
+                          Add( ColorVisual::Property::MIX_COLOR, Color::TRANSPARENT ) );
+
+    // Enable the clipping property.
+    mStencil.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX );
+    mStencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+    Self().Add( mStencil );
+  }
+}
+
+void TextField::OnClipboardTextSelected( ClipboardEventNotifier& clipboard )
+{
+  mController->PasteClipboardItemEvent();
+}
+
+void TextField::KeyboardStatusChanged(bool keyboardShown)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::KeyboardStatusChanged %p keyboardShown %d\n", mController.Get(), keyboardShown );
+
+  // Just hide the grab handle when keyboard is hidden.
+  if (!keyboardShown )
+  {
+    mController->KeyboardFocusLostEvent();
+  }
+  else
+  {
+    mController->KeyboardFocusGainEvent(); // Initially called by OnKeyInputFocusGained
+  }
+}
+
+void TextField::OnStageConnection( int depth )
+{
+  // Sets the depth to the visuals inside the text's decorator.
+  mDecorator->SetTextDepth( depth );
+
+  // The depth of the text renderer is set in the RenderText() called from OnRelayout().
+
+  // Call the Control::OnStageConnection() to set the depth of the background.
+  Control::OnStageConnection( depth );
+}
+
+bool TextField::OnTouched( Actor actor, const TouchData& touch )
+{
+  return true;
+}
+
+void TextField::OnIdleSignal()
+{
+  // Emits the change of input style signals.
+  mController->ProcessInputStyleChangedSignals();
+
+  // Set the pointer to null as the callback manager deletes the callback after execute it.
+  mIdleCallback = NULL;
+}
+
+TextField::TextField()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mIdleCallback( NULL ),
+  mAlignmentOffset( 0.f ),
+  mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
+  mExceedPolicy( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP ),
+  mHasBeenStaged( false )
+{
+}
+
+TextField::~TextField()
+{
+  UnparentAndReset( mStencil );
+
+  if( ( NULL != mIdleCallback ) && Adaptor::IsAvailable() )
+  {
+    Adaptor::Get().RemoveIdle( mIdleCallback );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.h b/dali-toolkit/internal/controls/text-controls/text-field-impl.h
new file mode 100755 (executable)
index 0000000..25bd4bd
--- /dev/null
@@ -0,0 +1,327 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_FIELD_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_FIELD_H
+
+/*
+ * Copyright (c) 2017 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 <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+/**
+ * @brief A control which renders a short text string.
+ */
+class TextField : public Control, public Text::ControlInterface, public Text::EditableControlInterface
+{
+public:
+
+  /**
+   * @copydoc Dali::Toollkit::TextField::New()
+   */
+  static Toolkit::TextField New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   *
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @copydoc Dali::Toollkit::TextField::GetInputMethodContext()
+   */
+  InputMethodContext GetInputMethodContext();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  /**
+   * @copydoc TextField::TextChangedSignal()
+   */
+  Toolkit::TextField::TextChangedSignalType&  TextChangedSignal();
+
+  /**
+   * @copydoc TextField::MaxLengthReachedSignal()
+   */
+  Toolkit::TextField::MaxLengthReachedSignalType&  MaxLengthReachedSignal();
+
+  /**
+   * @copydoc TextField::TextChangedSignal()
+   */
+  Toolkit::TextField::InputStyleChangedSignalType& InputStyleChangedSignal();
+
+  /**
+   * @brief Called to select the whole texts.
+   */
+  void SelectWholeText();
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Control::OnStyleChange()
+   */
+  virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change );
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc Control::OnKeyInputFocusGained()
+   */
+  virtual void OnKeyInputFocusGained();
+
+  /**
+   * @copydoc Control::OnKeyInputFocusLost()
+   */
+  virtual void OnKeyInputFocusLost();
+
+  /**
+   * @copydoc Control::OnTap()
+   */
+  virtual void OnTap( const TapGesture& tap );
+
+  /**
+   * @copydoc Control::OnPan()
+   */
+  virtual void OnPan( const PanGesture& gesture );
+
+  /**
+   * @copydoc Control::OnLongPress()
+   */
+  virtual void OnLongPress( const LongPressGesture& gesture );
+
+  /**
+   * @copydoc Control::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Dali::CustomActorImpl::OnKeyEvent(const KeyEvent&)
+   */
+  virtual bool OnKeyEvent(const KeyEvent& event);
+
+// From ControlInterface
+
+  /**
+   * @copydoc Text::ControlInterface::RequestTextRelayout()
+   */
+  virtual void RequestTextRelayout();
+
+// From EditableControlInterface
+
+  /**
+   * @copydoc Text::ControlInterface::TextChanged()
+   */
+  virtual void TextChanged();
+
+  /**
+   * @copydoc Text::ControlInterface::MaxLengthReached()
+   */
+  virtual void MaxLengthReached();
+
+  /**
+   * @copydoc Text::ControlInterface::InputStyleChanged()
+   */
+  virtual void InputStyleChanged( Text::InputStyle::Mask inputStyleMask );
+
+  /**
+   * @copydoc Text::ControlInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
+
+private: // Implementation
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Controller::(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
+   */
+  InputMethodContext::CallbackData OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent );
+
+  /**
+   * @brief Callback when Clipboard signals an item should be pasted
+   * @param[in] clipboard handle to Clipboard Event Notifier
+   */
+  void OnClipboardTextSelected( ClipboardEventNotifier& clipboard );
+
+  /**
+   * @brief Get a Property Map for the image used for the required Handle Image
+   * @param[out] value the returned image property
+   * @param[in] handleType the type of handle
+   * @param[in] handleImageType the type of image for the given handleType
+   */
+  void GetHandleImagePropertyValue(  Property::Value& value, Text::HandleType handleType, Text::HandleImageType handleImageType );
+
+  /**
+   * @brief Enable or disable clipping.
+   */
+  void EnableClipping();
+
+  /**
+   * @brief Callback when keyboard is shown/hidden.
+   *
+   * @param[in] keyboardShown True if keyboard is shown.
+   */
+  void KeyboardStatusChanged( bool keyboardShown );
+
+  /**
+   * @brief Callback when TextField is touched
+   *
+   * @param[in] actor TextField touched
+   * @param[in] touch Touch information
+   */
+  bool OnTouched( Actor actor, const TouchData& touch );
+
+  /**
+   * @brief Callbacks called on idle.
+   *
+   * If there are notifications of change of input style on the queue, Toolkit::TextField::InputStyleChangedSignal() are emitted.
+   */
+  void OnIdleSignal();
+
+  /**
+   * Construct a new TextField.
+   */
+  TextField();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextField();
+
+  // Undefined copy constructor and assignment operators
+  TextField(const TextField&);
+  TextField& operator=(const TextField& rhs);
+
+  /**
+   * @brief Render view, create and attach actor(s) to this Text Field.
+   */
+  void RenderText( Text::Controller::UpdateTextType updateTextType );
+
+  // Connection needed to re-render text, when a Text Field returns to the stage.
+  void OnStageConnect( Dali::Actor actor );
+
+public: // For UTC only
+
+  Text::ControllerPtr GetTextController() { return mController; }
+
+private: // Data
+
+  // Signals
+  Toolkit::TextField::TextChangedSignalType mTextChangedSignal;
+  Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal;
+  Toolkit::TextField::InputStyleChangedSignalType mInputStyleChangedSignal;
+
+  InputMethodContext mInputMethodContext;
+  Text::ControllerPtr mController;
+  Text::RendererPtr mRenderer;
+  Text::DecoratorPtr mDecorator;
+  Toolkit::Control mStencil; ///< For EXCEED_POLICY_CLIP
+  std::vector<Actor> mClippingDecorationActors;   ///< Decoration actors which need clipping.
+  Dali::InputMethodOptions mInputMethodOptions;
+
+  Actor mRenderableActor;
+  Actor mActiveLayer;
+  Actor mBackgroundActor;
+  CallbackBase* mIdleCallback;
+
+  float mAlignmentOffset;
+  int mRenderingBackend;
+  int mExceedPolicy;
+  bool mHasBeenStaged:1;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextField& GetImpl( Toolkit::TextField& textField )
+{
+  DALI_ASSERT_ALWAYS(textField);
+
+  Dali::RefObject& handle = textField.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextField&>(handle);
+}
+
+inline const Toolkit::Internal::TextField& GetImpl( const Toolkit::TextField& textField )
+{
+  DALI_ASSERT_ALWAYS(textField);
+
+  const Dali::RefObject& handle = textField.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextField&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_FIELD_H
diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
new file mode 100755 (executable)
index 0000000..c521817
--- /dev/null
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/object/property-helper-devel.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/text/property-string-parser.h>
+#include <dali-toolkit/internal/text/rendering/text-backend.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
+
+using namespace Dali::Toolkit::Text;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+  const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::Text::DEFAULT_RENDERING_BACKEND;
+
+  /**
+   * @brief How the text visual should be aligned vertically inside the control.
+   *
+   * 0.0f aligns the text to the top, 0.5f aligns the text to the center, 1.0f aligns the text to the bottom.
+   * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
+   */
+  const float VERTICAL_ALIGNMENT_TABLE[ Text::VerticalAlignment::BOTTOM + 1 ] =
+  {
+    0.0f,  // VerticalAlignment::TOP
+    0.5f,  // VerticalAlignment::CENTER
+    1.0f   // VerticalAlignment::BOTTOM
+  };
+
+  const std::string TEXT_FIT_ENABLE_KEY( "enable" );
+  const std::string TEXT_FIT_MIN_SIZE_KEY( "minSize" );
+  const std::string TEXT_FIT_MAX_SIZE_KEY( "maxSize" );
+  const std::string TEXT_FIT_STEP_SIZE_KEY( "stepSize" );
+  const std::string TEXT_FIT_FONT_SIZE_TYPE_KEY( "fontSizeType" );
+}
+
+namespace
+{
+
+#if defined ( DEBUG_ENABLED )
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
+{
+  { "IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE },
+  { "FINISH_LOOP",  Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP  },
+};
+const unsigned int AUTO_SCROLL_STOP_MODE_TABLE_COUNT = sizeof( AUTO_SCROLL_STOP_MODE_TABLE ) / sizeof( AUTO_SCROLL_STOP_MODE_TABLE[0] );
+
+// Type registration
+BaseHandle Create()
+{
+  return Toolkit::TextLabel::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextLabel, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "renderingBackend",          INTEGER, RENDERING_BACKEND          )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "text",                      STRING,  TEXT                       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "fontFamily",                STRING,  FONT_FAMILY                )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "fontStyle",                 MAP,     FONT_STYLE                 )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "pointSize",                 FLOAT,   POINT_SIZE                 )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "multiLine",                 BOOLEAN, MULTI_LINE                 )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "horizontalAlignment",       STRING,  HORIZONTAL_ALIGNMENT       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "verticalAlignment",         STRING,  VERTICAL_ALIGNMENT         )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "unusedPropertyTextColor",   VECTOR4, UNUSED_PROPERTY_TEXT_COLOR )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "reservedProperty01",        STRING,  RESERVED_PROPERTY_01       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "reservedProperty02",        STRING,  RESERVED_PROPERTY_02       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "reservedProperty03",        STRING,  RESERVED_PROPERTY_03       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "reservedProperty04",        STRING,  RESERVED_PROPERTY_04       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "reservedProperty05",        STRING,  RESERVED_PROPERTY_05       )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "enableMarkup",              BOOLEAN, ENABLE_MARKUP              )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "enableAutoScroll",          BOOLEAN, ENABLE_AUTO_SCROLL         )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollSpeed",           INTEGER, AUTO_SCROLL_SPEED          )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollLoopCount",       INTEGER, AUTO_SCROLL_LOOP_COUNT     )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollGap",             FLOAT,   AUTO_SCROLL_GAP            )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "lineSpacing",               FLOAT,   LINE_SPACING               )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "underline",                 MAP,     UNDERLINE                  )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "shadow",                    MAP,     SHADOW                     )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "emboss",                    MAP,     EMBOSS                     )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "outline",                   MAP,     OUTLINE                    )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "pixelSize",                 FLOAT,   PIXEL_SIZE                 )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "ellipsis",                  BOOLEAN, ELLIPSIS                   )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollLoopDelay",       FLOAT,   AUTO_SCROLL_LOOP_DELAY     )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "autoScrollStopMode",        STRING,  AUTO_SCROLL_STOP_MODE      )
+DALI_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "lineCount",                 INTEGER, LINE_COUNT                 )
+DALI_PROPERTY_REGISTRATION( Toolkit,           TextLabel, "lineWrapMode",              INTEGER, LINE_WRAP_MODE             )
+DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "textDirection",       INTEGER, TEXT_DIRECTION             )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "verticalLineAlignment",     INTEGER, VERTICAL_LINE_ALIGNMENT    )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "textBackground",            MAP,     BACKGROUND                 )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "ignoreSpacesAfterText",     BOOLEAN, IGNORE_SPACES_AFTER_TEXT   )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit,     TextLabel, "textFit",                   MAP,     TEXT_FIT                 )
+DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor",      Color::BLACK,     TEXT_COLOR     )
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorRed",   TEXT_COLOR_RED,   TEXT_COLOR, 0  )
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1  )
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorBlue",  TEXT_COLOR_BLUE,  TEXT_COLOR, 2  )
+DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit,    TextLabel, "textColorAlpha", TEXT_COLOR_ALPHA, TEXT_COLOR, 3  )
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Toolkit::TextLabel TextLabel::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextLabel > impl = new TextLabel();
+
+  // Pass ownership to CustomActor handle
+  Toolkit::TextLabel handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
+
+  if( label )
+  {
+    TextLabel& impl( GetImpl( label ) );
+    switch( index )
+    {
+      case Toolkit::TextLabel::Property::RENDERING_BACKEND:
+      {
+        DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
+
+        int backend = value.Get< int >();
+
+#ifndef ENABLE_VECTOR_BASED_TEXT_RENDERING
+        if( Text::RENDERING_VECTOR_BASED == backend )
+        {
+          backend = TextAbstraction::BITMAP_GLYPH; // Fallback to bitmap-based rendering
+        }
+#endif
+        if( impl.mRenderingBackend != backend )
+        {
+          impl.mRenderingBackend = backend;
+          impl.mTextUpdateNeeded = true;
+
+          if( impl.mController )
+          {
+            // When using the vector-based rendering, the size of the GLyphs are different
+            TextAbstraction::GlyphType glyphType = (Text::RENDERING_VECTOR_BASED == impl.mRenderingBackend) ? TextAbstraction::VECTOR_GLYPH : TextAbstraction::BITMAP_GLYPH;
+            impl.mController->SetGlyphType( glyphType );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          impl.mController->SetText( value.Get< std::string >() );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          const std::string& fontFamily = value.Get< std::string >();
+
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::SetProperty Property::FONT_FAMILY newFont(%s)\n", fontFamily.c_str() );
+          impl.mController->SetDefaultFontFamily( fontFamily );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::FONT_STYLE:
+      {
+        SetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pointSize = value.Get< float >();
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::MULTI_LINE:
+      {
+        if( impl.mController )
+        {
+          impl.mController->SetMultiLineEnabled( value.Get< bool >() );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( Text::GetHorizontalAlignmentEnumeration( value, alignment ) )
+          {
+            impl.mController->SetHorizontalAlignment( alignment );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( Text::GetVerticalAlignmentEnumeration( value, alignment ) )
+          {
+            impl.mController->SetVerticalAlignment( alignment );
+          }
+        }
+        break;
+      }
+
+      case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR:
+      {
+        label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, value );
+        impl.mTextUpdateNeeded = true;
+        break;
+      }
+      case Toolkit::TextLabel::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          const bool enableMarkup = value.Get<bool>();
+          impl.mController->SetMarkupProcessorEnabled( enableMarkup );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
+      {
+        if( impl.mController )
+        {
+          const bool enableAutoScroll = value.Get<bool>();
+          // If request to auto scroll is the same as current state then do nothing.
+          if ( enableAutoScroll != impl.mController->IsAutoScrollEnabled() )
+          {
+             // If request is disable (false) and auto scrolling is enabled then need to stop it
+             if ( enableAutoScroll == false )
+             {
+               if( impl.mTextScroller )
+               {
+                 impl.mTextScroller->StopScrolling();
+               }
+             }
+             // If request is enable (true) then start autoscroll as not already running
+             else
+             {
+               impl.mController->SetAutoScrollEnabled( enableAutoScroll );
+             }
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
+      {
+        if( !impl.mTextScroller )
+        {
+          impl.mTextScroller = Text::TextScroller::New( impl );
+        }
+        Toolkit::TextLabel::AutoScrollStopMode::Type stopMode = impl.mTextScroller->GetStopMode();
+        if( Scripting::GetEnumerationProperty< Toolkit::TextLabel::AutoScrollStopMode::Type >( value,
+                                                                                                    AUTO_SCROLL_STOP_MODE_TABLE,
+                                                                                                    AUTO_SCROLL_STOP_MODE_TABLE_COUNT,
+                                                                                                    stopMode ) )
+        {
+            impl.mTextScroller->SetStopMode( stopMode );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
+      {
+        if( !impl.mTextScroller )
+        {
+          impl.mTextScroller = Text::TextScroller::New( impl );
+        }
+        impl.mTextScroller->SetSpeed( value.Get<int>() );
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
+      {
+        if( !impl.mTextScroller )
+        {
+          impl.mTextScroller = Text::TextScroller::New( impl );
+        }
+        impl.mTextScroller->SetLoopCount( value.Get<int>() );
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
+      {
+         if( !impl.mTextScroller )
+        {
+          impl.mTextScroller = Text::TextScroller::New( impl );
+        }
+        impl.mTextScroller->SetLoopDelay( value.Get<float>() );
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
+      {
+        if( !impl.mTextScroller )
+        {
+          impl.mTextScroller = Text::TextScroller::New( impl );
+        }
+        impl.mTextScroller->SetGap( value.Get<float>() );
+        break;
+      }
+      case Toolkit::TextLabel::Property::LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+          const float lineSpacing = value.Get<float>();
+
+          // Don't trigger anything if the line spacing didn't change
+          if( impl.mController->SetDefaultLineSpacing( lineSpacing ) )
+          {
+            impl.mTextUpdateNeeded = true;
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::UNDERLINE:
+      {
+        const bool update = SetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mTextUpdateNeeded = true;
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::SHADOW:
+      {
+        const bool update = SetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mTextUpdateNeeded = true;
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::EMBOSS:
+      {
+        const bool update = SetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mTextUpdateNeeded = true;
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::OUTLINE:
+      {
+        const bool update = SetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mTextUpdateNeeded = true;
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          const float pixelSize = value.Get< float >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p PIXEL_SIZE %f\n", impl.mController.Get(), pixelSize );
+
+          if( !Equals( impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
+          {
+            impl.mController->SetDefaultFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::ELLIPSIS:
+      {
+        if( impl.mController )
+        {
+          const bool ellipsis = value.Get<bool>();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p ELLIPSIS %d\n", impl.mController.Get(), ellipsis );
+
+          impl.mController->SetTextElideEnabled( ellipsis );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
+      {
+        if( impl.mController )
+        {
+          Text::LineWrap::Mode lineWrapMode( static_cast< Text::LineWrap::Mode >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+          if( GetLineWrapModeEnumeration( value, lineWrapMode ) )
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel %p LineWrap::MODE %d\n", impl.mController.Get(), lineWrapMode );
+            impl.mController->SetLineWrapMode( lineWrapMode );
+          }
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
+      {
+        if( impl.mController && impl.mController->GetTextModel() )
+        {
+          DevelText::VerticalLineAlignment::Type alignment = static_cast<DevelText::VerticalLineAlignment::Type>( value.Get<int>() );
+
+          impl.mController->SetVerticalLineAlignment( alignment );
+
+          // Property doesn't affect the layout, only Visual must be updated
+          TextVisual::EnableRendererUpdate( impl.mVisual );
+
+          // No need to trigger full re-layout. Instead call UpdateRenderer() directly
+          TextVisual::UpdateRenderer( impl.mVisual );
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::BACKGROUND:
+      {
+        const bool update = SetBackgroundProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        if( update )
+        {
+          impl.mTextUpdateNeeded = true;
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
+      {
+        impl.mController->SetIgnoreSpacesAfterText(value.Get< bool >());
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        impl.mController->SetMatchSystemLanguageDirection(value.Get< bool >());
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::TEXT_FIT:
+      {
+        const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+        bool enabled = false;
+        float minSize = 0.f;
+        float maxSize = 0.f;
+        float stepSize = 0.f;
+        bool isMinSizeSet = false, isMaxSizeSet = false, isStepSizeSet = false;
+        Controller::FontSizeType type = Controller::FontSizeType::POINT_SIZE;
+
+        if ( !propertiesMap.Empty() )
+        {
+          const unsigned int numberOfItems = propertiesMap.Count();
+
+          // Parses and applies
+          for( unsigned int index = 0u; index < numberOfItems; ++index )
+          {
+            const KeyValuePair& valueGet = propertiesMap.GetKeyValue( index );
+
+            if( ( Controller::TextFitInfo::Property::TEXT_FIT_ENABLE == valueGet.first.indexKey ) || ( TEXT_FIT_ENABLE_KEY == valueGet.first.stringKey ) )
+            {
+              /// Enable key.
+              enabled = valueGet.second.Get< bool >();
+            }
+            else if( ( Controller::TextFitInfo::Property::TEXT_FIT_MIN_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_MIN_SIZE_KEY == valueGet.first.stringKey ) )
+            {
+              /// min size.
+              minSize = valueGet.second.Get< float >();
+              isMinSizeSet = true;
+            }
+            else if( ( Controller::TextFitInfo::Property::TEXT_FIT_MAX_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_MAX_SIZE_KEY == valueGet.first.stringKey ) )
+            {
+              /// max size.
+              maxSize = valueGet.second.Get< float >();
+              isMaxSizeSet = true;
+            }
+            else if( ( Controller::TextFitInfo::Property::TEXT_FIT_STEP_SIZE == valueGet.first.indexKey ) || ( TEXT_FIT_STEP_SIZE_KEY == valueGet.first.stringKey ) )
+            {
+              /// step size.
+              stepSize = valueGet.second.Get< float >();
+              isStepSizeSet = true;
+            }
+            else if( ( Controller::TextFitInfo::Property::TEXT_FIT_FONT_SIZE_TYPE == valueGet.first.indexKey ) || ( TEXT_FIT_FONT_SIZE_TYPE_KEY == valueGet.first.stringKey ) )
+            {
+              if( "pixelSize" == valueGet.second.Get< std::string >() )
+              {
+                type = Controller::FontSizeType::PIXEL_SIZE;
+              }
+            }
+          }
+
+          impl.mController->SetTextFitEnabled( enabled );
+          if( isMinSizeSet )
+          {
+            impl.mController->SetTextFitMinSize( minSize, type );
+          }
+          if( isMaxSizeSet )
+          {
+            impl.mController->SetTextFitMaxSize( maxSize, type );
+          }
+          if( isStepSizeSet )
+          {
+            impl.mController->SetTextFitStepSize( stepSize, type );
+          }
+        }
+        break;
+      }
+    }
+
+    // Request relayout when text update is needed. It's necessary to call it
+    // as changing the property not via UI interaction brings no effect if only
+    // the mTextUpdateNeeded is changed.
+    if( impl.mTextUpdateNeeded )
+    {
+      // need to request relayout as size of text may have changed
+      impl.RequestTextRelayout();
+    }
+  }
+}
+
+Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextLabel label = Toolkit::TextLabel::DownCast( Dali::BaseHandle( object ) );
+
+  if( label )
+  {
+    TextLabel& impl( GetImpl( label ) );
+    switch( index )
+    {
+      case Toolkit::TextLabel::Property::RENDERING_BACKEND:
+      {
+        DALI_LOG_WARNING("[%s] Using deprecated Property TextLabel::Property::RENDERING_BACKEND which is no longer supported and will be ignored\n", __FUNCTION__);
+
+        value = impl.mRenderingBackend;
+        break;
+      }
+      case Toolkit::TextLabel::Property::TEXT:
+      {
+        if( impl.mController )
+        {
+          std::string text;
+          impl.mController->GetText( text );
+          value = text;
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::FONT_FAMILY:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontFamily();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::FONT_STYLE:
+      {
+        GetFontStyleProperty( impl.mController, value, Text::FontStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::POINT_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::POINT_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::MULTI_LINE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMultiLineEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          const char* name = Text::GetHorizontalAlignmentString( impl.mController->GetHorizontalAlignment() );
+
+           if ( name )
+           {
+             value = std::string( name );
+           }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          const char* name = Text::GetVerticalAlignmentString( impl.mController->GetVerticalAlignment() );
+          if( name )
+          {
+            value = std::string( name );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::UNUSED_PROPERTY_TEXT_COLOR:
+      {
+        value = label.GetProperty( Toolkit::TextLabel::Property::TEXT_COLOR );
+        break;
+      }
+      case Toolkit::TextLabel::Property::ENABLE_MARKUP:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsMarkupProcessorEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::ENABLE_AUTO_SCROLL:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsAutoScrollEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_STOP_MODE:
+      {
+        if( impl.mTextScroller )
+        {
+          const char* mode = Scripting::GetEnumerationName< Toolkit::TextLabel::AutoScrollStopMode::Type >( impl.mTextScroller->GetStopMode(),
+                                                                                                                 AUTO_SCROLL_STOP_MODE_TABLE,
+                                                                                                                 AUTO_SCROLL_STOP_MODE_TABLE_COUNT );
+          if( mode )
+          {
+            value = std::string( mode );
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_SPEED:
+      {
+        TextLabel& impl( GetImpl( label ) );
+        if ( impl.mTextScroller )
+        {
+          value = impl.mTextScroller->GetSpeed();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_COUNT:
+      {
+        if( impl.mController )
+        {
+          TextLabel& impl( GetImpl( label ) );
+          if ( impl.mTextScroller )
+          {
+            value = impl.mTextScroller->GetLoopCount();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_LOOP_DELAY:
+      {
+        if( impl.mController )
+        {
+          TextLabel& impl( GetImpl( label ) );
+          if ( impl.mTextScroller )
+          {
+            value = impl.mTextScroller->GetLoopDelay();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::AUTO_SCROLL_GAP:
+      {
+        TextLabel& impl( GetImpl( label ) );
+        if ( impl.mTextScroller )
+        {
+          value = impl.mTextScroller->GetGap();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::LINE_SPACING:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultLineSpacing();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::UNDERLINE:
+      {
+        GetUnderlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::SHADOW:
+      {
+        GetShadowProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::EMBOSS:
+      {
+        GetEmbossProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::OUTLINE:
+      {
+        GetOutlineProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::TextLabel::Property::PIXEL_SIZE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetDefaultFontSize( Text::Controller::PIXEL_SIZE );
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::ELLIPSIS:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->IsTextElideEnabled();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::LINE_WRAP_MODE:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetLineWrapMode();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::LINE_COUNT:
+      {
+        if( impl.mController )
+        {
+          float width = label.GetProperty( Actor::Property::SIZE_WIDTH ).Get<float>();
+          value = impl.mController->GetLineCount( width );
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::TEXT_DIRECTION:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetTextDirection();
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::VERTICAL_LINE_ALIGNMENT:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetVerticalLineAlignment();
+        }
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::BACKGROUND:
+      {
+        GetBackgroundProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
+      {
+        value = impl.mController->IsIgnoreSpacesAfterText();
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION:
+      {
+        value = impl.mController->IsMatchSystemLanguageDirection();
+        break;
+      }
+      case Toolkit::DevelTextLabel::Property::TEXT_FIT:
+      {
+        const bool enabled = impl.mController->IsTextFitEnabled();
+        const float minSize = impl.mController->GetTextFitMinSize();
+        const float maxSize = impl.mController->GetTextFitMaxSize();
+        const float stepSize = impl.mController->GetTextFitStepSize();
+
+        Property::Map map;
+        map.Insert( TEXT_FIT_ENABLE_KEY, enabled );
+        map.Insert( TEXT_FIT_MIN_SIZE_KEY, minSize );
+        map.Insert( TEXT_FIT_MAX_SIZE_KEY, maxSize );
+        map.Insert( TEXT_FIT_STEP_SIZE_KEY, stepSize );
+        map.Insert( TEXT_FIT_FONT_SIZE_TYPE_KEY, "pointSize" );
+
+        value = map;
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void TextLabel::OnInitialize()
+{
+  Actor self = Self();
+
+  Property::Map propertyMap;
+  propertyMap.Add( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
+
+  mVisual =  Toolkit::VisualFactory::Get().CreateVisual( propertyMap );
+  DevelControl::RegisterVisual( *this, Toolkit::TextLabel::Property::TEXT, mVisual  );
+
+  TextVisual::SetAnimatableTextColorProperty( mVisual, Toolkit::TextLabel::Property::TEXT_COLOR );
+
+  mController = TextVisual::GetController(mVisual);
+  if( mController )
+  {
+    mController->SetControlInterface(this);
+  }
+
+  // Use height-for-width negotiation by default
+  self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+  self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+
+  // Enable the text ellipsis.
+  mController->SetTextElideEnabled( true );   // If false then text larger than control will overflow
+
+  // Sets layoutDirection value
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( stage.GetRootLayer().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+  mController->SetLayoutDirection( layoutDirection );
+
+  Layout::Engine& engine = mController->GetLayoutEngine();
+  engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
+}
+
+void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
+
+  switch ( change )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      // Property system did not set the font so should update it.
+      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 );
+      RelayoutRequest();
+      break;
+    }
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+      RelayoutRequest();
+      break;
+    }
+    case StyleChange::THEME_CHANGE:
+    {
+      // Nothing to do, let control base class handle this
+      break;
+    }
+  }
+
+  // Up call to Control
+  Control::OnStyleChange( styleManager, change );
+}
+
+Vector3 TextLabel::GetNaturalSize()
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector3 naturalSize = mController->GetNaturalSize();
+  naturalSize.width += ( padding.start + padding.end );
+  naturalSize.height += ( padding.top + padding.bottom );
+
+  return naturalSize;
+}
+
+float TextLabel::GetHeightForWidth( float width )
+{
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  return mController->GetHeightForWidth( width ) + padding.top + padding.bottom;
+}
+
+void TextLabel::OnPropertySet( Property::Index index, Property::Value propertyValue )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnPropertySet index[%d]\n", index );
+
+  switch ( index )
+  {
+    case Toolkit::TextLabel::Property::TEXT_COLOR:
+    {
+      const Vector4& textColor = propertyValue.Get< Vector4 >();
+      if( mController->GetDefaultColor() != textColor )
+      {
+         mController->SetDefaultColor( textColor );
+         mTextUpdateNeeded = true;
+      }
+      break;
+    }
+    default:
+    {
+      Control::OnPropertySet( index, propertyValue ); // up call to control for non-handled properties
+      break;
+    }
+  }
+}
+
+void TextLabel::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout\n" );
+
+  Extents padding;
+  padding = Self().GetProperty<Extents>( Toolkit::Control::Property::PADDING );
+
+  Vector2 contentSize( size.x - ( padding.start + padding.end ), size.y - ( padding.top + padding.bottom ) );
+
+  if( mController->IsTextFitEnabled() )
+  {
+    mController->FitPointSizeforLayout( contentSize );
+    mController->SetTextFitContentSize( contentSize );
+  }
+
+  // Support Right-To-Left
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( Self().GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+  const Text::Controller::UpdateTextType updateTextType = mController->Relayout( contentSize, layoutDirection );
+
+  if( ( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType ) )
+     || mTextUpdateNeeded )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnRelayout IsAutoScrollEnabled[%s] [%p]\n", ( mController->IsAutoScrollEnabled())?"true":"false", this );
+
+    // Update the visual
+    TextVisual::EnableRendererUpdate( mVisual );
+
+    // Support Right-To-Left of padding
+    if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+    {
+      std::swap( padding.start, padding.end );
+    }
+
+    // Calculate the size of the visual that can fit the text
+    Size layoutSize = mController->GetTextModel()->GetLayoutSize();
+    layoutSize.x = contentSize.x;
+
+    const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+    if ( shadowOffset.y > Math::MACHINE_EPSILON_1 )
+    {
+      layoutSize.y += shadowOffset.y;
+    }
+
+    float outlineWidth = mController->GetTextModel()->GetOutlineWidth();
+    layoutSize.y += outlineWidth * 2.0f;
+    layoutSize.y = std::min( layoutSize.y, contentSize.y );
+
+    // Calculate the offset for vertical alignment only, as the layout engine will do the horizontal alignment.
+    Vector2 alignmentOffset;
+    alignmentOffset.x = 0.0f;
+    alignmentOffset.y = ( contentSize.y - layoutSize.y ) * VERTICAL_ALIGNMENT_TABLE[mController->GetVerticalAlignment()];
+
+    Property::Map visualTransform;
+    visualTransform.Add( Toolkit::Visual::Transform::Property::SIZE, layoutSize )
+                   .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( padding.start, padding.top ) + alignmentOffset )
+                   .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE ) )
+                   .Add( Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN )
+                   .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN );
+    mVisual.SetTransformAndSize( visualTransform, size );
+
+    if ( mController->IsAutoScrollEnabled() )
+    {
+      SetUpAutoScrolling();
+    }
+
+    mTextUpdateNeeded = false;
+  }
+}
+
+void TextLabel::RequestTextRelayout()
+{
+  RelayoutRequest();
+  // Signal that a Relayout may be needed
+}
+
+void TextLabel::SetUpAutoScrolling()
+{
+  const Size& controlSize = mController->GetView().GetControlSize();
+  const Size textNaturalSize = GetNaturalSize().GetVectorXY(); // As relayout of text may not be done at this point natural size is used to get size. Single line scrolling only.
+  const Text::CharacterDirection direction = mController->GetAutoScrollDirection();
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling textNaturalSize[%f,%f] controlSize[%f,%f]\n",
+                 textNaturalSize.x,textNaturalSize.y , controlSize.x,controlSize.y );
+
+  if ( !mTextScroller )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::SetUpAutoScrolling Creating default TextScoller\n" );
+
+    // If speed, loopCount or gap not set via property system then will need to create a TextScroller with defaults
+    mTextScroller = Text::TextScroller::New( *this );
+  }
+
+  // Calculate the actual gap before scrolling wraps.
+  int textPadding = std::max( controlSize.x - textNaturalSize.x, 0.0f );
+  float wrapGap = std::max( mTextScroller->GetGap(), textPadding );
+  Vector2 textureSize = textNaturalSize + Vector2(wrapGap, 0.0f); // Add the gap as a part of the texture
+
+  // Create a texture of the text for scrolling
+  Size verifiedSize = textureSize;
+  const int maxTextureSize = Dali::GetMaxTextureSize();
+
+  //if the texture size width exceed maxTextureSize, modify the visual model size and enabled the ellipsis
+  if( verifiedSize.width > maxTextureSize )
+  {
+    verifiedSize.width = maxTextureSize;
+    if( textNaturalSize.width > maxTextureSize )
+    {
+      mController->SetTextElideEnabled( true );
+    }
+    GetHeightForWidth( maxTextureSize );
+    wrapGap = std::max( maxTextureSize - textNaturalSize.width, 0.0f );
+  }
+
+  Text::TypesetterPtr typesetter = Text::Typesetter::New( mController->GetTextModel() );
+
+  PixelData data = typesetter->Render( verifiedSize, mController->GetTextDirection(), Text::Typesetter::RENDER_TEXT_AND_STYLES, true, Pixel::RGBA8888 ); // ignore the horizontal alignment
+  Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                  data.GetPixelFormat(),
+                                  data.GetWidth(),
+                                  data.GetHeight() );
+  texture.Upload( data );
+
+  TextureSet textureSet = TextureSet::New();
+  textureSet.SetTexture( 0u, texture );
+
+  // Filter mode needs to be set to linear to produce better quality while scaling.
+  Sampler sampler = Sampler::New();
+  sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+  sampler.SetWrapMode( Dali::WrapMode::DEFAULT, Dali::WrapMode::REPEAT, Dali::WrapMode::DEFAULT ); // Wrap the texture in the x direction
+  textureSet.SetSampler( 0u, sampler );
+
+  // Set parameters for scrolling
+  Renderer renderer = static_cast<Internal::Visual::Base&>( GetImplementation( mVisual ) ).GetRenderer();
+  mTextScroller->SetParameters( Self(), renderer, textureSet, controlSize, verifiedSize, wrapGap, direction, mController->GetHorizontalAlignment(), mController->GetVerticalAlignment() );
+}
+
+void TextLabel::ScrollingFinished()
+{
+  // Pure Virtual from TextScroller Interface
+  DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::ScrollingFinished\n");
+  mController->SetAutoScrollEnabled( false );
+  mController->SetTextElideEnabled( true );
+  RequestTextRelayout();
+}
+
+TextLabel::TextLabel()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mRenderingBackend( DEFAULT_RENDERING_BACKEND ),
+  mTextUpdateNeeded( false )
+{
+}
+
+TextLabel::~TextLabel()
+{
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/dali-toolkit/internal/controls/text-controls/text-label-impl.h
new file mode 100644 (file)
index 0000000..85e94ab
--- /dev/null
@@ -0,0 +1,182 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_LABEL_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_LABEL_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-scroller-interface.h>
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+#include <dali-toolkit/internal/text/text-scroller.h>
+#include <dali-toolkit/internal/visuals/text/text-visual.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @brief A control which renders a short text string.
+ */
+class TextLabel : public Control, public Text::ControlInterface, public Text::ScrollerInterface
+{
+public:
+
+  /**
+   * @copydoc Dali::Toollkit::TextLabel::New()
+   */
+  static Toolkit::TextLabel New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   *
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize() override ;
+
+  /**
+   * @copydoc Control::OnStyleChange()
+   */
+  virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) override ;
+
+  /**
+   * @copydoc Control::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container ) override ;
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize() override ;
+
+  /**
+   * @copydoc Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width ) override ;
+
+  /**
+   * @copydoc Control::OnPropertySet()
+   */
+  virtual void OnPropertySet( Property::Index index, Property::Value propertyValue ) override ;
+
+  // From ControlInterface
+
+  /**
+   * @copydoc Text::ControlInterface::RequestTextRelayout()
+   */
+  virtual void RequestTextRelayout() override ;
+
+private: // from TextScroller
+
+  /**
+   * @copydoc Text::ScrollerInterface::ScrollingFinished()
+   */
+  virtual void ScrollingFinished();
+
+private: // Implementation
+
+  /**
+   * Construct a new TextLabel.
+   */
+  TextLabel();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextLabel();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  TextLabel(const TextLabel&);
+  TextLabel& operator=(const TextLabel& rhs);
+
+  /**
+   * @brief Set up Autoscrolling
+   */
+  void SetUpAutoScrolling();
+
+private: // Data
+
+  Text::ControllerPtr mController;
+  Text::TextScrollerPtr mTextScroller;
+
+  Toolkit::Visual::Base mVisual;
+
+  int mRenderingBackend;
+  bool mTextUpdateNeeded:1;
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextLabel& GetImpl( Toolkit::TextLabel& textLabel )
+{
+  DALI_ASSERT_ALWAYS(textLabel);
+
+  Dali::RefObject& handle = textLabel.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextLabel&>(handle);
+}
+
+inline const Toolkit::Internal::TextLabel& GetImpl( const Toolkit::TextLabel& textLabel )
+{
+  DALI_ASSERT_ALWAYS(textLabel);
+
+  const Dali::RefObject& handle = textLabel.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextLabel&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_LABEL_H
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp
new file mode 100644 (file)
index 0000000..10e7f78
--- /dev/null
@@ -0,0 +1,900 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h>
+
+// EXTERNAL INCLUDES
+#if defined(__GLIBC__)
+#include <libintl.h>
+#endif
+#include <string.h>
+#include <cfloat>
+#include <dali/public-api/animation/animation.h>
+#include <dali/devel-api/images/nine-patch-image.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/helpers/color-conversion.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+#if defined(__GLIBC__)
+#define GET_LOCALE_TEXT(string) dgettext("dali-toolkit", string)
+#endif
+
+const std::string TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME( "TextSelectionPopupButton" );
+const Dali::Vector4 DEFAULT_OPTION_PRESSED_COLOR( Dali::Vector4( 0.24f, 0.72f, 0.8f, 1.0f ) );
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+#ifdef DGETTEXT_ENABLED
+
+#define POPUP_CUT_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CUT")
+#define POPUP_COPY_STRING GET_LOCALE_TEXT("IDS_COM_BODY_COPY")
+#define POPUP_PASTE_STRING GET_LOCALE_TEXT("IDS_COM_BODY_PASTE")
+#define POPUP_SELECT_STRING GET_LOCALE_TEXT("IDS_COM_SK_SELECT")
+#define POPUP_SELECT_ALL_STRING GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL")
+#define POPUP_CLIPBOARD_STRING GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD")
+
+#else
+
+#define POPUP_CUT_STRING  "Cut"
+#define POPUP_COPY_STRING  "Copy"
+#define POPUP_PASTE_STRING  "Paste"
+#define POPUP_SELECT_STRING  "Select"
+#define POPUP_SELECT_ALL_STRING  "Select All"
+#define POPUP_CLIPBOARD_STRING  "Clipboard"
+
+#endif
+
+const char* const OPTION_SELECT_WORD = "option-select_word";                       // "Select Word" popup option.
+const char* const OPTION_SELECT_ALL("option-select_all");                          // "Select All" popup option.
+const char* const OPTION_CUT("optionCut");                                        // "Cut" popup option.
+const char* const OPTION_COPY("optionCopy");                                      // "Copy" popup option.
+const char* const OPTION_PASTE("optionPaste");                                    // "Paste" popup option.
+const char* const OPTION_CLIPBOARD("optionClipboard");                            // "Clipboard" popup option.
+
+const std::string IDS_LTR( "IDS_LTR" );
+const std::string RTL_DIRECTION( "RTL" );
+
+BaseHandle Create()
+{
+  return Toolkit::TextSelectionPopup::New( NULL );
+}
+
+// Setup properties, signals and actions using the type-registry.
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionPopup, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupMaxSize", VECTOR2,   POPUP_MAX_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupMinSize", VECTOR2,   POPUP_MIN_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "optionMaxSize", VECTOR2,   OPTION_MAX_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "optionMinSize", VECTOR2,   OPTION_MIN_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "optionDividerSize", VECTOR2,   OPTION_DIVIDER_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupClipboardButtonImage", STRING, POPUP_CLIPBOARD_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupCutButtonImage", STRING, POPUP_CUT_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupCopyButtonImage", STRING, POPUP_COPY_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupPasteButtonImage", STRING, POPUP_PASTE_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupSelectButtonImage", STRING, POPUP_SELECT_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupSelectAllButtonImage", STRING, POPUP_SELECT_ALL_BUTTON_ICON_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupDividerColor", VECTOR4, POPUP_DIVIDER_COLOR )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupIconColor", VECTOR4, POPUP_ICON_COLOR )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupPressedColor", VECTOR4, POPUP_PRESSED_COLOR )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupPressedImage", STRING, POPUP_PRESSED_IMAGE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupFadeInDuration", FLOAT, POPUP_FADE_IN_DURATION )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "popupFadeOutDuration", FLOAT, POPUP_FADE_OUT_DURATION )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionPopup, "backgroundBorder", MAP, BACKGROUND_BORDER )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+
+Dali::Toolkit::TextSelectionPopup TextSelectionPopup::New( TextSelectionPopupCallbackInterface* callbackInterface )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextSelectionPopup::New\n" );
+
+   // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextSelectionPopup > impl = new TextSelectionPopup( callbackInterface );
+
+  // Pass ownership to CustomActor handle
+  Dali::Toolkit::TextSelectionPopup handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextSelectionPopup::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionPopup& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
+      {
+       impl.SetDimensionToCustomise( POPUP_MAXIMUM_SIZE, value.Get< Vector2 >() );
+       break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_MAXIMUM_SIZE, value.Get< Vector2 >() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_MINIMUM_SIZE, value.Get< Vector2>() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+      {
+        impl.SetDimensionToCustomise( OPTION_DIVIDER_SIZE, value.Get< Vector2>() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::CUT, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::COPY, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::PASTE, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+        impl.SetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL, image );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_DIVIDER_COLOR:
+      {
+        impl.mDividerColor = value.Get< Vector4 >();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_ICON_COLOR:
+      {
+        impl.mIconColor = value.Get< Vector4 >();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_COLOR:
+      {
+        impl.mPressedColor = value.Get< Vector4 >();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
+      {
+        impl.SetPressedImage( value.Get< std::string >() );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
+      {
+        impl.mFadeInDuration = value.Get < float >();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
+      {
+        impl.mFadeOutDuration = value.Get < float >();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
+      {
+        Property::Map map = value.Get<Property::Map>();
+        impl.CreateBackgroundBorder( map );
+        break;
+      }
+    } // switch
+  } // TextSelectionPopup
+}
+
+Property::Value TextSelectionPopup::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextSelectionPopup selectionPopup = Toolkit::TextSelectionPopup::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionPopup& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionPopup::Property::POPUP_MAX_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( POPUP_MAXIMUM_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MAX_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( OPTION_MAXIMUM_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_MIN_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( OPTION_MINIMUM_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::OPTION_DIVIDER_SIZE:
+      {
+        value = impl.GetDimensionToCustomise( OPTION_DIVIDER_SIZE );
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_CLIPBOARD_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CLIPBOARD ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_CUT_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::CUT ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_COPY_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::COPY ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_PASTE_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::PASTE ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_SELECT_ALL_BUTTON_ICON_IMAGE:
+      {
+        ResourceImage image = ResourceImage::DownCast( impl.GetButtonImage( Toolkit::TextSelectionPopup::SELECT_ALL ) );
+        if( image )
+        {
+          value = image.GetUrl();
+        }
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_PRESSED_IMAGE:
+      {
+        value = impl.GetPressedImage();
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_FADE_IN_DURATION:
+      {
+        value = impl.mFadeInDuration;
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::POPUP_FADE_OUT_DURATION:
+      {
+        value = impl.mFadeOutDuration;
+        break;
+      }
+      case Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER:
+      {
+        Property::Map map;
+        Toolkit::Visual::Base visual = DevelControl::GetVisual( impl, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER );
+        if( visual )
+        {
+          visual.CreatePropertyMap( map );
+        }
+        value = map;
+        break;
+      }
+    } // switch
+  }
+  return value;
+}
+
+void TextSelectionPopup::EnableButtons( Toolkit::TextSelectionPopup::Buttons buttonsToEnable )
+{
+  mEnabledButtons = buttonsToEnable;
+  mButtonsChanged = true;
+}
+
+void TextSelectionPopup::RaiseAbove( Layer target )
+{
+  if( mToolbar )
+  {
+    mToolbar.RaiseAbove( target );
+  }
+}
+
+void TextSelectionPopup::ShowPopup()
+{
+  if( ( !mPopupShowing || mButtonsChanged ) &&
+      ( Toolkit::TextSelectionPopup::NONE != mEnabledButtons ) )
+  {
+    Actor self = Self();
+    AddPopupOptionsToToolbar( mShowIcons, mShowCaptions );
+
+    Animation animation = Animation::New( mFadeInDuration );
+    animation.AnimateTo( Property(self, Actor::Property::COLOR_ALPHA), 1.0f  );
+    animation.Play();
+    mPopupShowing = true;
+  }
+}
+
+void TextSelectionPopup::HidePopup()
+{
+  if ( mPopupShowing )
+  {
+    mPopupShowing = false;
+    Actor self = Self();
+    Animation animation = Animation::New( mFadeOutDuration );
+    animation.AnimateTo( Property(self, Actor::Property::COLOR_ALPHA), 0.0f  );
+    animation.FinishedSignal().Connect( this, &TextSelectionPopup::HideAnimationFinished );
+    animation.Play();
+  }
+}
+
+void TextSelectionPopup::OnInitialize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::OnInitialize\n" );
+  Actor self = Self();
+  self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  self.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f );
+}
+
+void TextSelectionPopup::HideAnimationFinished( Animation& animation )
+{
+  Actor self = Self();
+  if ( !mPopupShowing ) // During the Hide/Fade animation there could be a call to Show the Popup again, mPopupShowing will be true in this case.
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::HideAnimationFinished\n" );
+    UnparentAndReset( mToolbar );
+  }
+}
+
+bool TextSelectionPopup::OnCutButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnCopyButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::COPY );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnPasteButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::PASTE );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnSelectButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnSelectAllButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::SELECT_ALL );
+  }
+
+  return true;
+}
+
+bool TextSelectionPopup::OnClipboardButtonPressed( Toolkit::Button button )
+{
+  if( mCallbackInterface )
+  {
+    mCallbackInterface->TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::CLIPBOARD );
+  }
+
+  return true;
+}
+
+void TextSelectionPopup::SetDimensionToCustomise( const PopupCustomisations& settingToCustomise, const Size& dimension )
+{
+  switch( settingToCustomise )
+  {
+    case POPUP_MAXIMUM_SIZE :
+    {
+      mPopupMaxSize = dimension;
+      if ( mToolbar )
+      {
+        mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, dimension );
+      }
+      break;
+    }
+    case OPTION_MAXIMUM_SIZE :
+    {
+      mOptionMaxSize = dimension;
+      // Option max size not currently currently supported
+      break;
+    }
+    case OPTION_MINIMUM_SIZE :
+    {
+      mOptionMinSize = dimension;
+      // Option min size not currently currently supported
+      break;
+    }
+    case OPTION_DIVIDER_SIZE :
+    {
+      mOptionDividerSize = dimension;
+      if ( mToolbar )
+      {
+        // Resize Dividers not currently supported
+      }
+      break;
+    }
+  } // switch
+}
+
+Size TextSelectionPopup::GetDimensionToCustomise( const PopupCustomisations& settingToCustomise )
+{
+  switch( settingToCustomise )
+  {
+    case POPUP_MAXIMUM_SIZE :
+    {
+      if ( mToolbar )
+      {
+        return mToolbar.GetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE ).Get< Vector2 >();
+      }
+      else
+      {
+        return mPopupMaxSize;
+      }
+    }
+    case OPTION_MAXIMUM_SIZE :
+    {
+      return mOptionMaxSize;
+    }
+    case OPTION_MINIMUM_SIZE :
+    {
+      return mOptionMinSize;
+    }
+    case OPTION_DIVIDER_SIZE :
+    {
+      return mOptionDividerSize;
+    }
+  } // switch
+
+  return Size::ZERO;
+}
+
+void TextSelectionPopup::SetButtonImage( Toolkit::TextSelectionPopup::Buttons button, Dali::Image image )
+{
+   switch ( button )
+   {
+   break;
+   case Toolkit::TextSelectionPopup::CLIPBOARD:
+   {
+     mClipboardIconImage  = image;
+   }
+   break;
+   case Toolkit::TextSelectionPopup::CUT :
+   {
+     mCutIconImage = image;
+   }
+   break;
+   case Toolkit::TextSelectionPopup::COPY :
+   {
+     mCopyIconImage = image;
+   }
+   break;
+   case Toolkit::TextSelectionPopup::PASTE :
+   {
+     mPasteIconImage = image;
+   }
+   break;
+   case Toolkit::TextSelectionPopup::SELECT :
+   {
+     mSelectIconImage = image;
+   }
+   break;
+   case Toolkit::TextSelectionPopup::SELECT_ALL :
+   {
+     mSelectAllIconImage = image;
+   }
+   break;
+   default :
+   {
+     DALI_ASSERT_DEBUG( "TextSelectionPopup SetPopupImage Unknown Button" );
+   }
+   } // switch
+}
+
+Dali::Image TextSelectionPopup::GetButtonImage( Toolkit::TextSelectionPopup::Buttons button )
+{
+  switch ( button )
+  {
+  case Toolkit::TextSelectionPopup::CLIPBOARD :
+  {
+    return mClipboardIconImage;
+  }
+  break;
+  case Toolkit::TextSelectionPopup::CUT :
+  {
+    return mCutIconImage;
+  }
+  break;
+  case Toolkit::TextSelectionPopup::COPY :
+  {
+    return mCopyIconImage;
+  }
+  break;
+  case Toolkit::TextSelectionPopup::PASTE :
+  {
+    return mPasteIconImage;
+  }
+  break;
+  case Toolkit::TextSelectionPopup::SELECT :
+  {
+    return mSelectIconImage;
+  }
+  break;
+  case Toolkit::TextSelectionPopup::SELECT_ALL :
+  {
+    return mSelectAllIconImage;
+  }
+  break;
+  default :
+  {
+    DALI_ASSERT_DEBUG( "TextSelectionPopup GetPopupImage Unknown Button" );
+  }
+  } // switch
+
+  return Dali::Image();
+}
+
+void TextSelectionPopup::SetPressedImage( const std::string& filename )
+{
+  mPressedImage = filename;
+}
+
+std::string TextSelectionPopup::GetPressedImage() const
+{
+  return mPressedImage;
+}
+
+ void TextSelectionPopup::CreateOrderedListOfPopupOptions()
+ {
+   mOrderListOfButtons.clear();
+   mOrderListOfButtons.reserve( 8u );
+
+   // Create button for each possible option using Option priority
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CUT, mCutOptionPriority, OPTION_CUT, POPUP_CUT_STRING , mCutIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::CUT)  ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::COPY, mCopyOptionPriority, OPTION_COPY, POPUP_COPY_STRING, mCopyIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::COPY)  ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::PASTE, mPasteOptionPriority, OPTION_PASTE, POPUP_PASTE_STRING, mPasteIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::PASTE)  ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT, mSelectOptionPriority, OPTION_SELECT_WORD, POPUP_SELECT_STRING, mSelectIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT)  ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::SELECT_ALL, mSelectAllOptionPriority, OPTION_SELECT_ALL, POPUP_SELECT_ALL_STRING, mSelectAllIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::SELECT_ALL)  ) );
+   mOrderListOfButtons.push_back( ButtonRequirement( Toolkit::TextSelectionPopup::CLIPBOARD, mClipboardOptionPriority, OPTION_CLIPBOARD, POPUP_CLIPBOARD_STRING, mClipboardIconImage, 0 != ( mEnabledButtons & Toolkit::TextSelectionPopup::CLIPBOARD)  ) );
+
+   // Sort the buttons according their priorities.
+   std::sort( mOrderListOfButtons.begin(), mOrderListOfButtons.end(), TextSelectionPopup::ButtonPriorityCompare() );
+ }
+
+ void TextSelectionPopup::AddOption( const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption  )
+ {
+   // 1. Create a option.
+   DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::AddOption\n" );
+
+   Toolkit::PushButton option = Toolkit::PushButton::New();
+   option.SetName( button.name );
+   option.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+   switch( button.id )
+   {
+     case Toolkit::TextSelectionPopup::CUT:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCutButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::COPY:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnCopyButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::PASTE:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnPasteButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::SELECT:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::SELECT_ALL:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnSelectAllButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::CLIPBOARD:
+     {
+       option.ClickedSignal().Connect( this, &TextSelectionPopup::OnClipboardButtonPressed );
+       break;
+     }
+     case Toolkit::TextSelectionPopup::NONE:
+     {
+       // Nothing to do:
+       break;
+     }
+   }
+
+   // 2. Set the options contents.
+   if( showCaption )
+   {
+     // PushButton layout properties.
+     option.SetProperty( Toolkit::PushButton::Property::LABEL_PADDING, Vector4( 24.0f, 24.0f, 14.0f, 14.0f ) );
+
+     // Label properties.
+     Property::Map buttonLabelProperties;
+     buttonLabelProperties.Insert( Toolkit::TextVisual::Property::TEXT, button.caption );
+     option.SetProperty( Toolkit::Button::Property::LABEL, buttonLabelProperties );
+   }
+   if( showIcons )
+   {
+     option.SetProperty( Toolkit::PushButton::Property::ICON_PADDING, Vector4( 10.0f, 10.0f, 10.0f, 10.0f ) );
+     option.SetProperty( Toolkit::PushButton::Property::ICON_ALIGNMENT, "TOP" );
+
+     // TODO: This is temporarily disabled until the text-selection-popup image API is changed to strings.
+     //option.SetProperty( Toolkit::PushButton::Property::SELECTED_ICON, button.icon );
+     //option.SetProperty( Toolkit::PushButton::Property::UNSELECTED_ICON, button.icon );
+   }
+
+   // 3. Set the normal option image (blank / Transparent).
+   option.SetProperty( Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, "" );
+
+   // 4. Set the pressed option image.
+   Property::Value selectedBackgroundValue( mPressedImage );
+   if( mPressedImage.empty() )
+   {
+     // The image can be blank, the color can be used in that case.
+     selectedBackgroundValue = Property::Value{ { Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR  },
+                                                { Toolkit::ColorVisual::Property::MIX_COLOR, mPressedColor } };
+   }
+   option.SetProperty( Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, selectedBackgroundValue );
+   option.SetProperty( Toolkit::Control::Property::STYLE_NAME, TEXT_SELECTION_POPUP_BUTTON_STYLE_NAME );
+
+   // 5 Add option to tool bar
+   mToolbar.AddOption( option );
+
+   // 6. Add the divider
+   if( showDivider )
+   {
+     const Size size( mOptionDividerSize.width, 0.0f ); // Height FILL_TO_PARENT
+
+     Toolkit::Control divider = Toolkit::Control::New();
+#ifdef DECORATOR_DEBUG
+     divider.SetName("Text's popup divider");
+#endif
+     divider.SetSize( size );
+     divider.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT );
+     divider.SetBackgroundColor( mDividerColor  );
+     mToolbar.AddDivider( divider );
+   }
+ }
+
+ std::size_t TextSelectionPopup::GetNumberOfEnabledOptions()
+ {
+   std::size_t numberOfOptions = 0u;
+   for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
+   {
+     const ButtonRequirement& button( *it );
+     if( button.enabled )
+     {
+       ++numberOfOptions;
+     }
+   }
+
+   return numberOfOptions;
+ }
+
+ void TextSelectionPopup::AddPopupOptionsToToolbar( bool showIcons, bool showCaptions )
+ {
+   DALI_LOG_INFO( gLogFilter, Debug::General, "TextSelectionPopup::AddPopupOptionsToToolbar\n" );
+
+   CreateOrderedListOfPopupOptions();
+
+   mButtonsChanged = false;
+   UnparentAndReset( mToolbar);
+
+   if( !mToolbar )
+   {
+     Actor self = Self();
+     mToolbar = Toolkit::TextSelectionToolbar::New();
+     if ( mPopupMaxSize != Vector2::ZERO ) // If PopupMaxSize property set then apply to Toolbar. Toolbar currently is not retriving this from json
+     {
+       mToolbar.SetProperty( Toolkit::TextSelectionToolbar::Property::MAX_SIZE, mPopupMaxSize );
+     }
+     mToolbar.SetParentOrigin( ParentOrigin::CENTER );
+#ifdef DECORATOR_DEBUG
+     mToolbar.SetName("TextSelectionToolbar");
+#endif
+     self.Add( mToolbar );
+   }
+
+   // Whether to mirror the list of buttons (for right to left languages)
+   bool mirror = false;
+#if defined(__GLIBC__)
+   char* idsLtr = GET_LOCALE_TEXT( IDS_LTR.c_str() );
+   if( NULL != idsLtr )
+   {
+     mirror = ( 0 == strcmp( idsLtr, RTL_DIRECTION.c_str() ) );
+
+     if( mirror )
+     {
+       std::reverse( mOrderListOfButtons.begin(), mOrderListOfButtons.end() );
+     }
+   }
+#endif
+
+   // Iterate list of buttons and add active ones to Toolbar
+   std::size_t numberOfOptionsRequired =  GetNumberOfEnabledOptions();
+   std::size_t numberOfOptionsAdded = 0u;
+   for( std::vector<ButtonRequirement>::const_iterator it = mOrderListOfButtons.begin(), endIt = mOrderListOfButtons.end(); ( it != endIt ); ++it )
+   {
+     const ButtonRequirement& button( *it );
+     if ( button.enabled )
+     {
+       numberOfOptionsAdded++;
+       AddOption(  button, ( numberOfOptionsAdded < numberOfOptionsRequired ) , showIcons, showCaptions );
+     }
+   }
+
+   if( mirror )
+   {
+     mToolbar.ScrollTo( Vector2( mPopupMaxSize.x, 0.f ) );
+   }
+ }
+
+void TextSelectionPopup::CreateBackgroundBorder( Property::Map& propertyMap )
+{
+  // Removes previous image if necessary
+  DevelControl::UnregisterVisual( *this, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER );
+
+  if( ! propertyMap.Empty() )
+  {
+    Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( propertyMap );
+
+    if( visual )
+    {
+      DevelControl::RegisterVisual( *this, Toolkit::TextSelectionPopup::Property::BACKGROUND_BORDER, visual, DepthIndex::CONTENT );
+    }
+  }
+}
+
+TextSelectionPopup::TextSelectionPopup( TextSelectionPopupCallbackInterface* callbackInterface )
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mToolbar(),
+  mPopupMaxSize(),
+  mOptionMaxSize(),
+  mOptionMinSize(),
+  mOptionDividerSize(),
+  mEnabledButtons( Toolkit::TextSelectionPopup::NONE ),
+  mCallbackInterface( callbackInterface ),
+  mPressedColor( DEFAULT_OPTION_PRESSED_COLOR ),
+  mDividerColor( Color::WHITE ),
+  mIconColor( Color::WHITE ),
+  mSelectOptionPriority( 1 ),
+  mSelectAllOptionPriority ( 2 ),
+  mCutOptionPriority ( 4 ),
+  mCopyOptionPriority ( 3 ),
+  mPasteOptionPriority ( 5 ),
+  mClipboardOptionPriority( 6 ),
+  mFadeInDuration(0.0f),
+  mFadeOutDuration(0.0f),
+  mShowIcons( false ),
+  mShowCaptions( true ),
+  mPopupShowing( false ),
+  mButtonsChanged( false )
+{
+}
+
+TextSelectionPopup::~TextSelectionPopup()
+{
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h b/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.h
new file mode 100644 (file)
index 0000000..a79a925
--- /dev/null
@@ -0,0 +1,343 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/buttons/push-button.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/object/property-map.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+enum PopupCustomisations
+{
+  POPUP_MAXIMUM_SIZE,
+  OPTION_MAXIMUM_SIZE,
+  OPTION_MINIMUM_SIZE,
+  OPTION_DIVIDER_SIZE
+};
+
+class TextSelectionPopup : public Control
+{
+public:
+
+  struct ButtonRequirement
+  {
+    ButtonRequirement()
+    : id( Toolkit::TextSelectionPopup::NONE ),
+      priority( 0u ),
+      name(),
+      caption(),
+      icon(),
+      enabled( false )
+    {}
+
+    ButtonRequirement( Toolkit::TextSelectionPopup::Buttons buttonId,
+                       std::size_t buttonPriority,
+                       const std::string& buttonName,
+                       const std::string& buttonCaption,
+                       Dali::Image& buttonIcon,
+                       bool buttonEnabled )
+    : id( buttonId ),
+      priority( buttonPriority ),
+      name( buttonName ),
+      caption( buttonCaption ),
+      icon( buttonIcon ),
+      enabled( buttonEnabled )
+    {}
+
+    Toolkit::TextSelectionPopup::Buttons id;
+    std::size_t priority;
+    std::string name;
+    std::string caption;
+    Dali::Image icon;
+    bool enabled;
+  };
+
+  struct ButtonPriorityCompare
+  {
+      bool operator()( const ButtonRequirement& lhs, const ButtonRequirement& rhs ) const {
+        return lhs.priority < rhs.priority;
+      }
+  };
+
+  /**
+   * @brief New constructor with provided buttons to enable.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   * @return A handle to the TextSelectionPopup control.
+   */
+  static Toolkit::TextSelectionPopup New( TextSelectionPopupCallbackInterface* callbackInterface );
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   * @copydoc Toolkit::EnableButtons
+   */
+  void EnableButtons( Toolkit::TextSelectionPopup::Buttons buttonsToEnable );
+
+  /**
+   * @copydoc Toolkit::TextSelectionPopup::RaiseAbove()
+   */
+  void RaiseAbove( Layer target );
+
+  /**
+   * @copydoc Toolkit::TextSelectionPopup::ShowPopup()
+   */
+  void ShowPopup();
+
+  /**
+   * @copydoc Toolkiut::TextSelectionPopup::HidePopup()
+   */
+  void HidePopup();
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+private: // Implementation
+
+  void HideAnimationFinished( Animation& animation );
+
+  /**
+   * @brief When the cut button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnCutButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the copy button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnCopyButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the paste button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnPasteButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the select button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnSelectButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the select all button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnSelectAllButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief When the clipboard button is pressed.
+   * @param[in] button the button pressed
+   * @return @e true to consume the event.
+   */
+  bool OnClipboardButtonPressed( Toolkit::Button button );
+
+  /**
+   * @brief Method to set the dimension or dimension constraint on certain aspects of the Popup.
+   *
+   * @param[in] settingToCustomise The setting for the PopupCustomisations enum that can be customised
+   * @param[in] dimension The size to customise with
+   */
+  void SetDimensionToCustomise( const PopupCustomisations& settingToCustomise, const Size& dimension );
+
+  /**
+   * @brief Method to get the dimension or dimension constraint on certain aspects of the Popup that was previously customised
+   *
+   * @param[in] setting The setting from the PopupCustomisations enum
+   */
+  Size GetDimensionToCustomise( const PopupCustomisations& setting );
+
+  /**
+   * @brief Sets the image for the given button of the Popup.
+   *
+   * @param[in] button  The button the image should be used for from the Buttons Enum.
+   * @param[in] image The image to use.
+   */
+ void SetButtonImage( Toolkit::TextSelectionPopup::Buttons button, Dali::Image image );
+
+  /**
+   * @brief Retrieves the image of the given button used by the popup
+   *
+   * @param[in] button The button to get the image from
+   * @return The image used for that button.
+   */
+  Dali::Image GetButtonImage( Toolkit::TextSelectionPopup::Buttons button );
+
+  /**
+   * @brief Sets the image for the pressed state of a popup option.
+   *
+   * @param[in]  filename The image filename to use.
+   */
+  void SetPressedImage( const std::string& filename);
+
+  /**
+   * @brief Gets the image used for the pressed state of a popup option.
+   *
+   * @return     The image filename used.
+   */
+  std::string GetPressedImage() const;
+
+  void CreateOrderedListOfPopupOptions();
+
+  void AddOption( const ButtonRequirement& button, bool showDivider, bool showIcons, bool showCaption );
+
+  std::size_t GetNumberOfEnabledOptions();
+
+  void AddPopupOptionsToToolbar(  bool showIcons, bool showCaptions );
+
+  /**
+   * Creates the background-border image
+   *
+   * @param[in] propertyMap The properties describing the background-border
+   */
+  void CreateBackgroundBorder( Property::Map& propertyMap );
+
+  /**
+   * Construct a new TextField.
+   */
+  TextSelectionPopup( TextSelectionPopupCallbackInterface* callbackInterface );
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextSelectionPopup();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  TextSelectionPopup(const TextSelectionPopup&);
+  TextSelectionPopup& operator=(const TextSelectionPopup& rhs);
+
+private: // Data
+
+
+  Dali::Toolkit::TextSelectionToolbar mToolbar;
+
+  Dali::Toolkit::TableView mTableOfButtons;           // Actor which holds all the buttons, sensitivity can be set on buttons via this actor
+
+  // Images to be used by the Popup buttons
+  Image mCutIconImage;
+  Image mCopyIconImage;
+  Image mPasteIconImage;
+  Image mClipboardIconImage;
+  Image mSelectIconImage;
+  Image mSelectAllIconImage;
+
+  Size mPopupMaxSize;                   // Maximum size of the Popup
+  Size mOptionMaxSize;                  // Maximum size of an Option button
+  Size mOptionMinSize;                  // Minimum size of an Option button
+  Size mOptionDividerSize;              // Size of divider line
+
+  std::vector<ButtonRequirement> mOrderListOfButtons; // List of buttons in the order to be displayed and a flag to indicate if needed.
+
+  Toolkit::TextSelectionPopup::Buttons mEnabledButtons; // stores enabled buttons
+  Toolkit::TextSelectionPopupCallbackInterface* mCallbackInterface;
+
+  std::string mPressedImage;            // Image used for the popup option when pressed.
+  Vector4 mPressedColor;                // Color of the popup option when pressed.
+  Vector4 mDividerColor;                // Color of the divider between buttons
+  Vector4 mIconColor;                   // Color of the popup icon.
+
+  // Priority of Options/Buttons in the Cut and Paste pop-up, higher priority buttons are displayed first, left to right.
+  std::size_t mSelectOptionPriority;    // Position of Select Button
+  std::size_t mSelectAllOptionPriority; // Position of Select All button
+  std::size_t mCutOptionPriority;       // Position of Cut button
+  std::size_t mCopyOptionPriority;      // Position of Copy button
+  std::size_t mPasteOptionPriority;     // Position of Paste button
+  std::size_t mClipboardOptionPriority; // Position of Clipboard button
+  float mFadeInDuration;                // Duration of the animation to fade in the Popup
+  float mFadeOutDuration;               // Duration of the animation to fade out the Popup
+
+  bool mShowIcons:1; // Flag to show icons
+  bool mShowCaptions:1; // Flag to show text captions
+  bool mPopupShowing:1; // Flag to indicate Popup showing
+  bool mButtonsChanged:1; // Flag to indicate the Popup Buttons have changed
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextSelectionPopup& GetImpl( Toolkit::TextSelectionPopup& textSelectionPopup )
+{
+  DALI_ASSERT_ALWAYS( textSelectionPopup );
+
+  Dali::RefObject& handle = textSelectionPopup.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextSelectionPopup&>(handle);
+}
+
+inline const Toolkit::Internal::TextSelectionPopup& GetImpl( const Toolkit::TextSelectionPopup& textSelectionPopup )
+{
+  DALI_ASSERT_ALWAYS( textSelectionPopup );
+
+  const Dali::RefObject& handle = textSelectionPopup.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextSelectionPopup&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_POPUP_H
+
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp
new file mode 100644 (file)
index 0000000..358ace6
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cfloat>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/helpers/color-conversion.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const Dali::Vector2 DEFAULT_SCROLL_BAR_PADDING( 8.0f, 6.0f );
+
+BaseHandle Create()
+{
+  return Toolkit::TextSelectionToolbar::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::TextSelectionToolbar, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "maxSize",  VECTOR2, MAX_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "enableOvershoot",  BOOLEAN, ENABLE_OVERSHOOT )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "enableScrollBar", BOOLEAN, ENABLE_SCROLL_BAR )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "scrollBarPadding", VECTOR2, SCROLL_BAR_PADDING )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextSelectionToolbar, "scrollView",  MAP, SCROLL_VIEW )
+
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Dali::Toolkit::TextSelectionToolbar TextSelectionToolbar::New()
+{
+  // Create the implementation, temporarily owned by this handle on stack
+  IntrusivePtr< TextSelectionToolbar > impl = new TextSelectionToolbar();
+
+  // Pass ownership to CustomActor handle
+  Dali::Toolkit::TextSelectionToolbar handle( *impl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  impl->Initialize();
+
+  return handle;
+}
+
+void TextSelectionToolbar::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
+      {
+       impl.SetPopupMaxSize( value.Get< Vector2 >() );
+       break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
+      {
+        if( !impl.mScrollView )
+        {
+          impl.mScrollView  = Toolkit::ScrollView::New();
+        }
+        impl.mScrollView.SetOvershootEnabled( value.Get< bool >() );
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
+      {
+        impl.SetUpScrollBar( value.Get< bool >() );
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
+      {
+        impl.SetScrollBarPadding( value.Get< Vector2 >() );
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::SCROLL_VIEW:
+      {
+        // Get a Property::Map from the property if possible.
+        Property::Map setPropertyMap;
+        if( value.Get( setPropertyMap ) )
+        {
+          impl.ConfigureScrollview( setPropertyMap );
+        }
+        break;
+      }
+    } // switch
+  } // TextSelectionToolbar
+}
+
+Property::Value TextSelectionToolbar::GetProperty( BaseObject* object, Property::Index index )
+{
+  Property::Value value;
+
+  Toolkit::TextSelectionToolbar selectionPopup = Toolkit::TextSelectionToolbar::DownCast( Dali::BaseHandle( object ) );
+
+  if( selectionPopup )
+  {
+    TextSelectionToolbar& impl( GetImpl( selectionPopup ) );
+
+    switch( index )
+    {
+      case Toolkit::TextSelectionToolbar::Property::MAX_SIZE:
+      {
+        value = impl.GetPopupMaxSize();
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::ENABLE_OVERSHOOT:
+      {
+        value = impl.mScrollView.IsOvershootEnabled();
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::ENABLE_SCROLL_BAR:
+      {
+        value = impl.mScrollBar ? true : false;
+        break;
+      }
+      case Toolkit::TextSelectionToolbar::Property::SCROLL_BAR_PADDING:
+      {
+        value = impl.GetScrollBarPadding();
+        break;
+      }
+    } // switch
+  }
+  return value;
+}
+
+void TextSelectionToolbar::OnInitialize()
+{
+  SetUp();
+}
+
+void TextSelectionToolbar::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  float width = std::max ( mTableOfButtons.GetNaturalSize().width, size.width );
+  mRulerX->SetDomain( RulerDomain( 0.0, width, true ) );
+  mScrollView.SetRulerX( mRulerX );
+
+  if( mScrollBar )
+  {
+    float barWidth = std::min( mTableOfButtons.GetNaturalSize().width, size.width ) - 2.f * mScrollBarPadding.x;
+    mScrollBar.SetSize( Vector2( 0.0f, barWidth ) );
+  }
+}
+
+void TextSelectionToolbar::SetPopupMaxSize( const Size& maxSize )
+{
+  mMaxSize = maxSize;
+  if (mScrollView && mToolbarLayer )
+  {
+    mScrollView.SetMaximumSize( mMaxSize );
+    mToolbarLayer.SetMaximumSize( mMaxSize );
+  }
+}
+
+const Dali::Vector2& TextSelectionToolbar::GetPopupMaxSize() const
+{
+  return mMaxSize;
+}
+
+void TextSelectionToolbar::SetUpScrollView()
+{
+  mScrollView.SetName("TextSelectionScrollView");
+  mScrollView.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  mScrollView.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  mScrollView.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+
+  mScrollView.SetScrollingDirection( PanGestureDetector::DIRECTION_HORIZONTAL, Degree( 40.0f ) );
+  mScrollView.SetAxisAutoLock( true );
+  mScrollView.ScrollStartedSignal().Connect( this, &TextSelectionToolbar::OnScrollStarted );
+  mScrollView.ScrollCompletedSignal().Connect( this, &TextSelectionToolbar::OnScrollCompleted );
+  mScrollView.SetProperty( Actor::Property::CLIPPING_MODE, ClippingMode::CLIP_TO_BOUNDING_BOX ); // In a new layer, so clip to scroll-view's bounding box
+
+  mRulerX = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+
+  RulerPtr rulerY = new DefaultRuler();  // IntrusivePtr which is unreferenced when ScrollView is destroyed.
+  rulerY->Disable();
+  mScrollView.SetRulerY( rulerY );
+
+  mScrollView.SetOvershootEnabled( true );
+}
+
+void TextSelectionToolbar::SetUp()
+{
+  Actor self = Self();
+
+  self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+
+  // Create Layer to house the toolbar.
+  mToolbarLayer = Layer::New();
+  mToolbarLayer.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+  mToolbarLayer.SetAnchorPoint( AnchorPoint::CENTER );
+  mToolbarLayer.SetParentOrigin( ParentOrigin::CENTER );
+
+  if( !mScrollView )
+  {
+    mScrollView = Toolkit::ScrollView::New();
+  }
+  SetUpScrollView();
+
+  // Toolbar must start with at least one option, adding further options with increase it's size
+  mTableOfButtons = Dali::Toolkit::TableView::New( 1, 1 );
+  mTableOfButtons.SetFitHeight( 0 );
+  mTableOfButtons.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+  mTableOfButtons.SetAnchorPoint( AnchorPoint::CENTER_LEFT );
+
+  mScrollView.Add( mTableOfButtons );
+  mToolbarLayer.Add( mScrollView );
+
+  self.Add( mToolbarLayer );
+}
+
+void TextSelectionToolbar::SetUpScrollBar( bool enable )
+{
+  if( enable )
+  {
+    if( ! mScrollBar )
+    {
+      Toolkit::ImageView indicator = Toolkit::ImageView::New();
+      indicator.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      indicator.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      indicator.SetStyleName( "TextSelectionScrollIndicator" );
+
+      mScrollBar = Toolkit::ScrollBar::New( Toolkit::ScrollBar::Horizontal );
+      mScrollBar.SetName( "Text popup scroll bar" );
+      mScrollBar.SetStyleName( "TextSelectionScrollBar" );
+      mScrollBar.SetParentOrigin( ParentOrigin::BOTTOM_LEFT );
+      mScrollBar.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      mScrollBar.SetPosition( mScrollBarPadding.x, -mScrollBarPadding.y );
+      mScrollBar.SetResizePolicy( Dali::ResizePolicy::FIT_TO_CHILDREN, Dali::Dimension::WIDTH );
+      mScrollBar.SetOrientation( Quaternion( Radian( 1.5f * Math::PI ), Vector3::ZAXIS ) );
+      mScrollBar.SetScrollIndicator( indicator );
+      mScrollBar.GetPanGestureDetector().DetachAll();
+      mScrollView.Add( mScrollBar );
+    }
+  }
+  else
+  {
+    UnparentAndReset( mScrollBar );
+  }
+}
+
+void TextSelectionToolbar::OnScrollStarted( const Vector2& position )
+{
+  if( mFirstScrollEnd )
+  {
+    mScrollView.SetOvershootEnabled( true );
+  }
+  mTableOfButtons.SetSensitive( false );
+}
+
+void TextSelectionToolbar::OnScrollCompleted( const Vector2& position )
+{
+  mFirstScrollEnd = true;
+  mTableOfButtons.SetSensitive( true );
+}
+
+void TextSelectionToolbar::AddOption( Actor& option )
+{
+  mTableOfButtons.AddChild( option, Toolkit::TableView::CellPosition( 0, mIndexInTable )  );
+  mTableOfButtons.SetFitWidth( mIndexInTable );
+  mIndexInTable++;
+}
+
+void TextSelectionToolbar::AddDivider( Actor& divider )
+{
+  AddOption( divider );
+  mDividerIndexes.PushBack( mIndexInTable - 1u );
+}
+
+void TextSelectionToolbar::ResizeDividers( Size& size )
+{
+  for( unsigned int i = 0; i < mDividerIndexes.Count(); ++i )
+  {
+    Actor divider = mTableOfButtons.GetChildAt( Toolkit::TableView::CellPosition( 0, mDividerIndexes[ i ] ) );
+    divider.SetSize( size );
+  }
+  RelayoutRequest();
+}
+
+void TextSelectionToolbar::RaiseAbove( Layer target )
+{
+  mToolbarLayer.RaiseAbove( target );
+}
+
+void TextSelectionToolbar::SetScrollBarPadding( const Vector2& padding )
+{
+  mScrollBarPadding = padding;
+  if( mScrollBar )
+  {
+    mScrollBar.SetPosition( mScrollBarPadding.x, -mScrollBarPadding.y );
+  }
+
+  RelayoutRequest();
+}
+
+void TextSelectionToolbar::ScrollTo( const Vector2& position )
+{
+  mFirstScrollEnd = false;
+  mScrollView.SetOvershootEnabled( false );
+  mScrollView.ScrollTo( position, 0.f );
+}
+
+void TextSelectionToolbar::ConfigureScrollview( const Property::Map& properties )
+{
+  // Set any properties specified for the label by iterating through all property key-value pairs.
+  for( unsigned int i = 0, mapCount = properties.Count(); i < mapCount; ++i )
+  {
+    const StringValuePair& propertyPair( properties.GetPair( i ) );
+
+    // Convert the property string to a property index.
+    Property::Index setPropertyIndex = mScrollView.GetPropertyIndex( propertyPair.first );
+    if( setPropertyIndex != Property::INVALID_INDEX )
+    {
+      // Convert the string representation of a color into a Vector4
+      if( setPropertyIndex == Toolkit::Scrollable::Property::OVERSHOOT_EFFECT_COLOR )
+      {
+        Vector4 color;
+        if( ConvertPropertyToColor( propertyPair.second, color ) )
+        {
+          mScrollView.SetOvershootEffectColor( color );
+        }
+      }
+      else
+      {
+        // If the conversion worked, we have a valid property index,
+        // Set the property to the new value.
+        mScrollView.SetProperty( setPropertyIndex, propertyPair.second );
+      }
+    }
+  }
+
+  RelayoutRequest();
+}
+
+const Vector2& TextSelectionToolbar::GetScrollBarPadding() const
+{
+  return mScrollBarPadding;
+}
+
+TextSelectionToolbar::TextSelectionToolbar()
+: Control( ControlBehaviour( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ) ),
+  mMaxSize (),
+  mScrollBarPadding( DEFAULT_SCROLL_BAR_PADDING ),
+  mIndexInTable( 0 ),
+  mDividerIndexes(),
+  mFirstScrollEnd( false )
+{
+}
+
+TextSelectionToolbar::~TextSelectionToolbar()
+{
+  mRulerX.Reset();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.h
new file mode 100644 (file)
index 0000000..adaf3b6
--- /dev/null
@@ -0,0 +1,221 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-toolbar.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class TextSelectionToolbar : public Control
+{
+public:
+
+  /**
+   * @copydoc Dali::Toollkit::TextSelectionToolbar::New()
+   */
+  static Toolkit::TextSelectionToolbar New();
+
+  // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index index );
+
+  /**
+   *  @copydoc Toolkit::TextSelectionToolbar::AddOption()
+   */
+  void AddOption( Actor& option );
+
+  /**
+   *  @copydoc Toolkit::TextSelectionToolbar::AddDivider()
+   */
+  void AddDivider( Actor& divider );
+
+  /**
+   * @copydoc Toolkit::TextSelectionToolbar::ResizeDividers()
+   */
+  void ResizeDividers( Size& size );
+
+  /**
+   * @copydoc Toolkit::TextSelectionToolbar::RaiseAbove()
+   */
+  void RaiseAbove( Layer target );
+
+  /**
+   * Sets the scroll bar padding.
+   *
+   * @param[in] padding The padding value.
+   */
+  void SetScrollBarPadding( const Vector2& padding );
+
+  /**
+   * @return The padding value.
+   */
+  const Vector2& GetScrollBarPadding() const;
+
+  /**
+   * @copydoc Toolkit::TextSelectionToolbar::ScrollTo()
+   */
+  void ScrollTo( const Vector2& position );
+
+private: // From Control
+
+  /**
+   * @copydoc Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+  * @copydoc Control::OnRelayout()
+  */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @brief Set max size of Popup
+   * @param[in] maxSize Size (Vector2)
+   */
+  void SetPopupMaxSize( const Size& maxSize );
+
+  /**
+   * @brief Get Max size of Popup
+   * @return Vector2 the max size of the Popup
+   */
+  const Dali::Vector2& GetPopupMaxSize() const;
+
+private: // Implementation
+
+  /**
+   * @copydoc Toolkit::TextSelectionToolbar::ConfigureScrollview()
+   */
+  void ConfigureScrollview( const Property::Map& properties );
+
+  /**
+   * @brief Set up scrollview to scroll Toolbar horizontally
+   */
+  void SetUpScrollView();
+
+  /**
+   * @brief Set up the parts that make the Toolbar
+   */
+  void SetUp();
+
+  /**
+   * @brief Enable or disable the scroll-bar
+   *
+   * @param[in] enable True if the scroll-bar is required
+   */
+  void SetUpScrollBar( bool enable );
+
+  /**
+   * Toolbar has started to scroll
+   * @param[in] position current scroll view position
+   */
+  void OnScrollStarted( const Vector2& position );
+
+  /**
+   * Toolbar has stopped scrolling
+   * @param[in] position current scroll view position
+   */
+  void OnScrollCompleted( const Vector2& position );
+
+  /**
+   * Construct a new TextField.
+   */
+  TextSelectionToolbar();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~TextSelectionToolbar();
+
+private:
+
+  // Undefined copy constructor and assignment operators
+  TextSelectionToolbar(const TextSelectionToolbar&);
+  TextSelectionToolbar& operator=(const TextSelectionToolbar& rhs);
+
+private: // Data
+
+  Layer mToolbarLayer;                                ///< The layer used to house the toolbar.
+  Toolkit::TableView mTableOfButtons;                 ///< Actor which holds all the buttons, sensitivity can be set on buttons via this actor
+  Toolkit::ScrollView mScrollView;                    ///< Provides scrolling of Toolbar when content does not fit.
+  Toolkit::ScrollBar mScrollBar;                      ///< An horizontal scroll bar for the text's popup options.
+  RulerPtr mRulerX;                                   ///< Ruler to clamp horizontal scrolling. Updates on Relayout
+  Size mMaxSize;                                      ///< Max size of the Toolbar
+  Vector2 mScrollBarPadding;                          ///< The padding used to position the scroll indicator.
+  unsigned int mIndexInTable;                         ///< Index in table to add option
+  Dali::Vector< unsigned int > mDividerIndexes;       ///< Vector of indexes in the Toolbar that contain dividers.
+  bool mFirstScrollEnd;                               ///< Used for RTL mirroring. Avoids the overshoot to be shown the first time the popup is shown.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::TextSelectionToolbar& GetImpl( Toolkit::TextSelectionToolbar& textSelectionToolbar )
+{
+  DALI_ASSERT_ALWAYS( textSelectionToolbar );
+
+  Dali::RefObject& handle = textSelectionToolbar.GetImplementation();
+
+  return static_cast<Toolkit::Internal::TextSelectionToolbar&>(handle);
+}
+
+inline const Toolkit::Internal::TextSelectionToolbar& GetImpl( const Toolkit::TextSelectionToolbar& textSelectionToolbar )
+{
+  DALI_ASSERT_ALWAYS( textSelectionToolbar );
+
+  const Dali::RefObject& handle = textSelectionToolbar.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::TextSelectionToolbar&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_SELECTION_TOOLBAR_H
diff --git a/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp b/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp
new file mode 100644 (file)
index 0000000..441b640
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2017 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 "tool-bar-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/alignment/alignment.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::ToolBar::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ToolBar, Toolkit::Control, Create )
+DALI_TYPE_REGISTRATION_END()
+
+const float DEFAULT_RELATIVE_SIZE( 0.1f );
+const Toolkit::Alignment::Type DEFAULT_ALIGNMENT( Toolkit::Alignment::HorizontalLeft );
+} // namespace
+
+Toolkit::ToolBar ToolBar::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< ToolBar > internalToolBar = new ToolBar();
+
+  // Pass ownership to Toolkit::Toolbar
+  Toolkit::ToolBar toolBar( *internalToolBar );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  internalToolBar->Initialize();
+
+  return toolBar;
+}
+
+void ToolBar::AddControl( Actor control, float relativeSize, Toolkit::Alignment::Type alignment, const Toolkit::Alignment::Padding& padding )
+{
+  // Work out index and update bases and offsets for further insertions.
+  unsigned int index = 0;
+  switch( alignment )
+  {
+    case Toolkit::Alignment::HorizontalLeft:
+    {
+      index = mLeftOffset;
+      ++mLeftOffset;
+      ++mCenterBase;
+      ++mRightBase;
+      break;
+    }
+    case Toolkit::Alignment::HorizontalCenter:
+    {
+      index = mCenterBase + mCenterOffset;
+      ++mCenterOffset;
+      ++mRightBase;
+      break;
+    }
+    case Toolkit::Alignment::HorizontalRight:
+    {
+      index = mRightBase - mRightOffset;
+      ++mRightBase;
+      ++mRightOffset;
+      break;
+    }
+    default:
+    {
+      DALI_ASSERT_ALWAYS( false );
+    }
+  }
+
+  // Create a new column for the new control.
+  mLayout.InsertColumn( index );
+
+  // Create an alignment container where to place the control.
+  Toolkit::Alignment alignmentContainer = Toolkit::Alignment::New( alignment );
+  alignmentContainer.SetSizeScalePolicy( SizeScalePolicy::FIT_WITH_ASPECT_RATIO );
+  alignmentContainer.SetPadding( padding );
+  alignmentContainer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  alignmentContainer.Add( control );
+
+  // Insert the control in the table view.
+  mLayout.AddChild( alignmentContainer, Toolkit::TableView::CellPosition( 0, index ) );
+  mLayout.SetRelativeWidth( index, relativeSize );
+
+  // Relate control and alignmentContainer in order to allow removing controls.
+  mControls[control] = alignmentContainer;
+
+  // Update accumulated relative space.
+  mAccumulatedRelativeSpace += relativeSize;
+
+  // Update spaces between left, center and right groups of controls.
+  switch( alignment )
+  {
+    case Toolkit::Alignment::HorizontalLeft:
+    {
+      mLeftRelativeSpace -= relativeSize;
+      if ( mLeftRelativeSpace < 0.f )
+      {
+        mLeftRelativeSpace = 0.f;
+      }
+      break;
+    }
+    case Toolkit::Alignment::HorizontalCenter:
+    {
+      mLeftRelativeSpace -= 0.5f * relativeSize;
+      if ( mLeftRelativeSpace < 0.f )
+      {
+        mLeftRelativeSpace = 0.f;
+      }
+      mRightRelativeSpace -= 0.5f * relativeSize;
+      if ( mRightRelativeSpace < 0.f )
+      {
+        mRightRelativeSpace = 0.f;
+      }
+      break;
+    }
+    case Toolkit::Alignment::HorizontalRight:
+    {
+      mRightRelativeSpace -= relativeSize;
+      if ( mRightRelativeSpace < 0.f )
+      {
+        mRightRelativeSpace = 0.f;
+      }
+      break;
+    }
+    default:
+    {
+      DALI_ASSERT_ALWAYS( false );
+    }
+  }
+
+  mLayout.SetRelativeWidth( mLeftOffset, mLeftRelativeSpace );
+  mLayout.SetRelativeWidth( mCenterBase + mCenterOffset, mRightRelativeSpace );
+}
+
+void ToolBar::RemoveControl( Actor control )
+{
+  Toolkit::TableView::CellPosition position;
+
+  // Find the alignment where the control is placed.
+  std::map<Actor,Toolkit::Alignment>::iterator it = mControls.find( control );
+
+  if( ( it != mControls.end() ) && ( mLayout.FindChildPosition( it->second, position ) ) )
+  {
+    // Update accumulated relative space.
+    mAccumulatedRelativeSpace -= mLayout.GetRelativeWidth( position.columnIndex );
+
+    // Update spaces between left, center and right groups of controls.
+    if( 1.0 > mAccumulatedRelativeSpace )
+    {
+      Toolkit::Alignment::Type alignment = Toolkit::Alignment::HorizontalLeft;
+      if( position.columnIndex < mLeftOffset )
+      {
+        alignment = Toolkit::Alignment::HorizontalLeft;
+      }
+      else if( ( position.columnIndex > mLeftOffset ) && ( position.columnIndex < mCenterBase + mCenterOffset ) )
+      {
+        alignment = Toolkit::Alignment::HorizontalCenter;
+      }
+      else if( position.columnIndex > mCenterBase + mCenterOffset )
+      {
+        alignment = Toolkit::Alignment::HorizontalRight;
+      }
+      else
+      {
+        DALI_ASSERT_ALWAYS( false );
+      }
+
+      float relativeSize = mLayout.GetRelativeWidth( position.columnIndex );
+
+      switch( alignment )
+      {
+        case Toolkit::Alignment::HorizontalLeft:
+        {
+          mLeftRelativeSpace += relativeSize;
+          if ( mLeftRelativeSpace < 0.f )
+          {
+            mLeftRelativeSpace = 0.f;
+          }
+          break;
+        }
+        case Toolkit::Alignment::HorizontalCenter:
+        {
+          mLeftRelativeSpace += 0.5f * relativeSize;
+          if ( mLeftRelativeSpace < 0.f )
+          {
+            mLeftRelativeSpace = 0.f;
+          }
+          mRightRelativeSpace += 0.5f * relativeSize;
+          if ( mRightRelativeSpace < 0.f )
+          {
+            mRightRelativeSpace = 0.f;
+          }
+          break;
+        }
+        case Toolkit::Alignment::HorizontalRight:
+        {
+          mRightRelativeSpace += relativeSize;
+          if ( mRightRelativeSpace < 0.f )
+          {
+            mRightRelativeSpace = 0.f;
+          }
+          break;
+        }
+        default:
+        {
+          DALI_ASSERT_ALWAYS( false );
+        }
+      }
+      mLayout.SetRelativeWidth( mLeftOffset, mLeftRelativeSpace );
+      mLayout.SetRelativeWidth( mCenterBase + mCenterOffset, mRightRelativeSpace );
+    }
+
+    // Remove alignment as parent of control.
+    it->second.Remove( control );
+
+    // Remove the relationship between control and alignment.
+    mControls.erase( it );
+
+    // Remove column from tableview.
+    mLayout.DeleteColumn( position.columnIndex );
+
+    // Update bases and offsets.
+    if( position.columnIndex < mCenterBase )
+    {
+      // Control is on the left side. Decrease left offset and center and right bases.
+      --mLeftOffset;
+      --mCenterBase;
+      --mRightBase;
+    }
+    else if( position.columnIndex < mCenterBase + mCenterOffset )
+    {
+      // Control is on the center side. Decrease center offset and right base.
+      --mCenterOffset;
+      --mRightBase;
+    }
+    else
+    {
+      // Control is on the right side. Decrease right base and right offset.
+      --mRightBase;
+      --mRightOffset;
+    }
+  }
+}
+
+ToolBar::ToolBar()
+: Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) ),
+  mLayout(),
+  mLeftOffset( 0 ),
+  mCenterBase( 1 ),
+  mCenterOffset( 0 ),
+  mRightBase( 2 ),
+  mRightOffset( 0 ),
+  mLeftRelativeSpace( 0.5f ),
+  mRightRelativeSpace( 0.5f ),
+  mAccumulatedRelativeSpace( 0.f ),
+  mInitializing( false ),
+  mControls()
+{
+}
+
+ToolBar::~ToolBar()
+{
+}
+
+void ToolBar::OnInitialize()
+{
+  Lock lock( mInitializing );
+
+  // Layout
+  mLayout = Toolkit::TableView::New( 1, 1 );
+  mLayout.SetName( "TOOLBAR_LAYOUT" );
+  mLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  mLayout.SetParentOrigin( ParentOrigin::CENTER );
+
+  Self().Add( mLayout );
+
+  // Add two default actors to create spaces between controls grouped on the left, center and right.
+  Actor leftSpace = Actor::New();
+  Actor rightSpace = Actor::New();
+  mLayout.AddChild( leftSpace, Toolkit::TableView::CellPosition( 0, 0 ) );
+  mLayout.AddChild( rightSpace, Toolkit::TableView::CellPosition( 0, 1 ) );
+  mLayout.SetRelativeWidth( 0, mLeftRelativeSpace );
+  mLayout.SetRelativeWidth( 1, mRightRelativeSpace );
+}
+
+void ToolBar::OnChildAdd(Actor& child)
+{
+  if( !mInitializing )
+  {
+    // An actor is being added through the Actor's API.
+
+    // Remove child from tool bar actor and insert it in table view with some 'default' values
+    if ( child && child.GetParent() )
+    {
+      child.GetParent().Remove( child );
+    }
+
+    AddControl( child, DEFAULT_RELATIVE_SIZE, DEFAULT_ALIGNMENT, Toolkit::ToolBar::DEFAULT_PADDING );
+  }
+
+  // No OnChildRemove method required because Actors are added to the mLayout table view, so if an
+  // actor is removed using the Actor::RemoveChild method it will not remove anything because the
+  // actor is in mLayout not in Self().
+
+  Control::OnChildAdd( child );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.h b/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.h
new file mode 100644 (file)
index 0000000..2d6b981
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TOOL_BAR_H
+#define DALI_TOOLKIT_INTERNAL_TOOL_BAR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/common/map-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/devel-api/controls/tool-bar/tool-bar.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class ToolBar;
+
+namespace Internal
+{
+
+/**
+ * ToolBar is a control to create a tool bar.
+ * @see Dali::Toolkit::ToolBar for more details.
+ */
+class ToolBar : public Control
+{
+public:
+
+  /**
+   * Create an initialized ToolBar.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static Toolkit::ToolBar New();
+
+  /**
+   * @copydoc Dali::Toolkit::ToolBar::AddControl()
+   */
+  void AddControl( Dali::Actor control, float relativeSize, Toolkit::Alignment::Type alignment, const Toolkit::Alignment::Padding& padding );
+
+  /**
+   * @copydoc Dali::Toolkit::ToolBar::RemoveControl()
+   */
+  void RemoveControl( Dali::Actor control );
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * Adds a control using some default values (the control uses 10% of the tool bar space and is placed on the left group).
+   * @param child The control to be added.
+   *
+   * @see Control::OnChildAdd()
+   */
+  virtual void OnChildAdd(Actor& child);
+
+private:
+  /**
+   */
+  class Lock
+  {
+  public:
+    /**
+     * Constructor, sets the lock boolean
+     */
+    Lock( bool& lock )
+    : mLock( lock )
+    {
+      mLock = true;
+    }
+
+    /**
+     * Destructor, releases lock boolean
+     */
+    ~Lock()
+    {
+      mLock = false;
+    }
+  private:
+    bool& mLock;
+  };
+
+  /**
+   * Constructor.
+   * It initializes ToolBar members.
+   */
+  ToolBar();
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~ToolBar();
+
+private:
+  Toolkit::TableView mLayout;                   ///< TableView used to place controls.
+  unsigned int       mLeftOffset;               ///< Offset index where the next control is going to be added in the left group.
+  unsigned int       mCenterBase;               ///< Base index where the first control of the center group is placed.
+  unsigned int       mCenterOffset;             ///< Offset index where the next control is going to be added in the center group.
+  unsigned int       mRightBase;                ///< Base index where the first control of the right group is placed.
+  unsigned int       mRightOffset;              ///< Offset index where the next control is going to be added in the right group.
+  float              mLeftRelativeSpace;        ///< Relative space between left and center groups of controls.
+  float              mRightRelativeSpace;       ///< Relative space between center and right groups of controls.
+  float              mAccumulatedRelativeSpace; ///< Stores the total percentage space used by controls.
+  bool               mInitializing;             ///< Allows the use of Actor's API to add controls.
+
+  std::map<Actor/*control*/,Toolkit::Alignment> mControls; ///< Stores a relationship between controls and their alignments used to place them inside the table view.
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Toolkit::Internal::ToolBar& GetImpl( Toolkit::ToolBar& toolBar )
+{
+  DALI_ASSERT_ALWAYS( toolBar );
+
+  Dali::RefObject& handle = toolBar.GetImplementation();
+
+  return static_cast<Toolkit::Internal::ToolBar&>( handle );
+}
+
+inline const Toolkit::Internal::ToolBar& GetImpl( const Toolkit::ToolBar& toolBar )
+{
+  DALI_ASSERT_ALWAYS( toolBar );
+
+  const Dali::RefObject& handle = toolBar.GetImplementation();
+
+  return static_cast<const Toolkit::Internal::ToolBar&>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TOOL_BAR_H
diff --git a/dali-toolkit/internal/controls/tooltip/tooltip.cpp b/dali-toolkit/internal/controls/tooltip/tooltip.cpp
new file mode 100644 (file)
index 0000000..d9bb052
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/controls/tooltip/tooltip.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/hover-event.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/controls/popup/popup-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( TOOLTIP_POSITION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, ABOVE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, BELOW )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Tooltip::Position, HOVER_POINT )
+DALI_ENUM_TO_STRING_TABLE_END( TOOLTIP_POSITION )
+
+const float MILLISECONDS_PER_SECOND = 1000.0f;
+
+const char * const PROPERTY_CONTENT_NAME              = "content";
+const char * const PROPERTY_LAYOUT_NAME               = "layout";
+const char * const PROPERTY_WAIT_TIME_NAME            = "waitTime";
+const char * const PROPERTY_BACKGROUND_NAME           = "background";
+const char * const PROPERTY_TAIL_NAME                 = "tail";
+const char * const PROPERTY_POSITION_NAME             = "position";
+const char * const PROPERTY_HOVER_POINT_OFFSET_NAME   = "hoverPointOffset";
+const char * const PROPERTY_MOVEMENT_THRESHOLD        = "movementThreshold";
+const char * const PROPERTY_DISAPPEAR_ON_MOVEMENT     = "disappearOnMovement";
+
+const char * const PROPERTY_BACKGROUND_VISUAL         = "visual";
+const char * const PROPERTY_BACKGROUND_BORDER         = "border";
+
+const char * const PROPERTY_TAIL_VISIBILITY           = "visibility";
+const char * const PROPERTY_TAIL_ABOVE_VISUAL         = "aboveVisual";
+const char * const PROPERTY_TAIL_BELOW_VISUAL         = "belowVisual";
+
+} // unnamed namespace
+
+TooltipPtr Tooltip::New( Toolkit::Control control )
+{
+  return new Tooltip( control );
+}
+
+void Tooltip::SetProperties( const Property::Value& value )
+{
+  Toolkit::Control control = mControl.GetHandle();
+  if( control )
+  {
+    Property::Map* properties = value.GetMap();
+    if( properties )
+    {
+      const Property::Map::SizeType count = properties->Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = properties->GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        if( key == Toolkit::Tooltip::Property::CONTENT || key == PROPERTY_CONTENT_NAME )
+        {
+          SetContent( control, value );
+        }
+        else if( key == Toolkit::Tooltip::Property::LAYOUT || key == PROPERTY_LAYOUT_NAME )
+        {
+          value.Get( mLayout );
+        }
+        else if( key == Toolkit::Tooltip::Property::WAIT_TIME || key == PROPERTY_WAIT_TIME_NAME )
+        {
+          float waitTime = 0.0f;
+          if( value.Get( waitTime ) )
+          {
+            mWaitTime = waitTime * MILLISECONDS_PER_SECOND;
+          }
+        }
+        else if( key == Toolkit::Tooltip::Property::BACKGROUND || key == PROPERTY_BACKGROUND_NAME )
+        {
+          SetBackground( value );
+        }
+        else if( key == Toolkit::Tooltip::Property::TAIL || key == PROPERTY_TAIL_NAME )
+        {
+          SetTail( value );
+        }
+        else if( key == Toolkit::Tooltip::Property::POSITION || key == PROPERTY_POSITION_NAME )
+        {
+          Scripting::GetEnumerationProperty< Toolkit::Tooltip::Position::Type >( value, TOOLTIP_POSITION_TABLE, TOOLTIP_POSITION_TABLE_COUNT, mPositionType );
+        }
+        else if( key == Toolkit::Tooltip::Property::HOVER_POINT_OFFSET || key == PROPERTY_HOVER_POINT_OFFSET_NAME )
+        {
+          value.Get( mHoverPointOffset );
+        }
+        else if( key == Toolkit::Tooltip::Property::MOVEMENT_THRESHOLD || key == PROPERTY_MOVEMENT_THRESHOLD )
+        {
+          value.Get( mMovementThreshold );
+        }
+        else if( key == Toolkit::Tooltip::Property::DISAPPEAR_ON_MOVEMENT || key == PROPERTY_DISAPPEAR_ON_MOVEMENT )
+        {
+          value.Get( mDisappearOnMovement );
+        }
+      }
+    }
+    else
+    {
+      Property::Type type = value.GetType();
+      if( ( value.GetType() == Property::STRING ) || ( type == Property::ARRAY ) )
+      {
+        SetContent( control, value );
+      }
+    }
+  }
+}
+
+void Tooltip::CreatePropertyMap( Property::Map& map ) const
+{
+  if( ! mContentTextVisual.Empty() )
+  {
+    Property::Map content = mContentTextVisual; // Need this copy as there's no Value constructor which takes in a 'const Property::Map&'.
+    map.Insert( Toolkit::Tooltip::Property::CONTENT, content );
+  }
+  else if( ! mContentArray.Empty() )
+  {
+    Property::Array content = mContentArray; // Need this copy as there's no Value constructor which takes in a 'const Property::Array&'.
+    map.Insert( Toolkit::Tooltip::Property::CONTENT, content );
+  }
+
+  map.Insert( Toolkit::Tooltip::Property::LAYOUT, mLayout );
+  map.Insert( Toolkit::Tooltip::Property::WAIT_TIME, static_cast<float>( mWaitTime ) / MILLISECONDS_PER_SECOND );
+  map.Insert( Toolkit::Tooltip::Property::BACKGROUND,
+              Property::Map().Add( Toolkit::Tooltip::Background::Property::VISUAL, mBackgroundImage )
+                             .Add( Toolkit::Tooltip::Background::Property::BORDER, mBackgroundBorder ) );
+  map.Insert( Toolkit::Tooltip::Property::TAIL,
+              Property::Map().Add( Toolkit::Tooltip::Tail::Property::VISIBILITY, mTailVisibility )
+                             .Add( Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL, mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ])
+                             .Add( Toolkit::Tooltip::Tail::Property::BELOW_VISUAL, mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ]) );
+  map.Insert( Toolkit::Tooltip::Property::POSITION, mPositionType );
+  map.Insert( Toolkit::Tooltip::Property::HOVER_POINT_OFFSET, mHoverPointOffset );
+  map.Insert( Toolkit::Tooltip::Property::MOVEMENT_THRESHOLD, mMovementThreshold );
+  map.Insert( Toolkit::Tooltip::Property::DISAPPEAR_ON_MOVEMENT, mDisappearOnMovement );
+}
+
+Tooltip::Tooltip( Toolkit::Control control )
+: mPopup(),
+  mTooltipTimer(),
+  mControl( control ),
+  mContentTextVisual(),
+  mTailImages(),
+  mContentArray(),
+  mBackgroundBorder( 0, 0, 0, 0 ),
+  mLayout( 1, 1 ),
+  mHoverPoint(),
+  mHoverPointOffset( 10.0f, 10.0f ),
+  mBackgroundImage(),
+  mMovementThreshold( 5.0f ),
+  mWaitTime( 500 ),
+  mPositionType( Toolkit::Tooltip::Position::ABOVE ),
+  mTailVisibility( false ),
+  mDisappearOnMovement( false ),
+  mSignalsConnected( false )
+{
+  mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] = "";
+  mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] = "";
+}
+
+Tooltip::~Tooltip()
+{
+  if( mPopup )
+  {
+    mPopup.Unparent();
+    mPopup.Reset();
+  }
+}
+
+void Tooltip::SetContent( Toolkit::Control& control, const Property::Value& value )
+{
+  // Delete popup & timer
+
+  if( mTooltipTimer )
+  {
+    mTooltipTimer.Stop();
+    mTooltipTimer.Reset();
+  }
+
+  if( mPopup )
+  {
+    mPopup.Unparent();
+    mPopup.Reset();
+  }
+
+  bool connectSignals = false;
+
+  Property::Type type = value.GetType();
+  if( type == Property::MAP )
+  {
+    Property::Map* map = value.GetMap();
+    if( map )
+    {
+      mContentTextVisual.Merge( *map );
+
+      Property::Value* typeValue = map->Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
+      if( typeValue )
+      {
+        // Set to an invalid value so it definitely changes if set in Scripting::GetEnumerationProperty
+        Toolkit::Visual::Type visualType = static_cast< Toolkit::Visual::Type >( -1 );
+
+        if( Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, visualType ) )
+        {
+          if( visualType == Toolkit::Visual::TEXT )
+          {
+            // Visual Type is text, ensure we have a the TEXT property set before we connect to the signals.
+
+            if( map->Find( Toolkit::TextVisual::Property::TEXT, TEXT_PROPERTY ) )
+            {
+              mContentArray.Clear();
+              connectSignals = true;
+            }
+          }
+          else
+          {
+            // Visual Type is not text, so connect to the signals as we're displaying a non text visual.
+
+            mContentArray.Clear();
+            connectSignals = true;
+          }
+        }
+      }
+    }
+  }
+  else if( type == Property::ARRAY )
+  {
+    if( value.Get( mContentArray ) )
+    {
+      mContentTextVisual.Clear();
+      connectSignals = true;
+    }
+  }
+  else if( type == Property::STRING )
+  {
+    std::string text;
+    if( value.Get( text ) )
+    {
+      mContentTextVisual[ Toolkit::TextVisual::Property::TEXT ] = text;
+      mContentTextVisual[ Toolkit::Visual::Property::TYPE ] = Visual::TEXT;
+      mContentArray.Clear();
+      connectSignals = true;
+    }
+  }
+
+  if( connectSignals && ! mSignalsConnected )
+  {
+    control.HoveredSignal().Connect( this, &Tooltip::OnHovered );
+    control.SetLeaveRequired( true );
+    mSignalsConnected = true;
+  }
+}
+
+void Tooltip::SetBackground( const Property::Value& value )
+{
+  Property::Type type = value.GetType();
+
+  if( type == Property::STRING )
+  {
+    value.Get( mBackgroundImage );
+    mBackgroundBorder.Set( 0, 0, 0, 0 );
+  }
+  else if( type == Property::MAP )
+  {
+    Property::Map* map = value.GetMap();
+    if( map )
+    {
+      const Property::Map::SizeType count = map->Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = map->GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        if( key == Toolkit::Tooltip::Background::Property::VISUAL || key == PROPERTY_BACKGROUND_VISUAL )
+        {
+          value.Get( mBackgroundImage );
+        }
+        else if( key == Toolkit::Tooltip::Background::Property::BORDER || key == PROPERTY_BACKGROUND_BORDER )
+        {
+          if( ! value.Get( mBackgroundBorder ) )
+          {
+            // If not a Property::RECTANGLE, then check if it's a Vector4 and set it accordingly
+            Vector4 valueVector4;
+            if( value.Get( valueVector4 ) )
+            {
+              mBackgroundBorder.left   = valueVector4.x;
+              mBackgroundBorder.right  = valueVector4.y;
+              mBackgroundBorder.bottom = valueVector4.z;
+              mBackgroundBorder.top    = valueVector4.w;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void Tooltip::SetTail( const Property::Value& value )
+{
+  Property::Type type = value.GetType();
+
+  if( type == Property::BOOLEAN )
+  {
+    value.Get( mTailVisibility );
+  }
+  else if( type == Property::MAP )
+  {
+    Property::Map map;
+    if( value.Get( map ) )
+    {
+      const Property::Map::SizeType count = map.Count();
+      for( Property::Map::SizeType position = 0; position < count; ++position )
+      {
+        KeyValuePair keyValue = map.GetKeyValue( position );
+        Property::Key& key = keyValue.first;
+        Property::Value& value = keyValue.second;
+
+        // Set the values manually rather than merging so that we only have to deal with Property indices when creating the actual tooltip.
+
+        if( key == Toolkit::Tooltip::Tail::Property::VISIBILITY || key == PROPERTY_TAIL_VISIBILITY )
+        {
+          value.Get( mTailVisibility );
+        }
+        else if( key == Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL || key == PROPERTY_TAIL_ABOVE_VISUAL )
+        {
+          std::string path;
+          if( value.Get( path ) )
+          {
+            mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] = path;
+          }
+        }
+        else if( key == Toolkit::Tooltip::Tail::Property::BELOW_VISUAL || key == PROPERTY_TAIL_BELOW_VISUAL )
+        {
+          std::string path;
+          if( value.Get( path ) )
+          {
+            mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] = path;
+          }
+        }
+      }
+    }
+  }
+}
+
+bool Tooltip::OnHovered( Actor /* actor */, const HoverEvent& hover )
+{
+  const TouchPoint::State state = hover.points[0].state;
+  switch( state )
+  {
+    case TouchPoint::Started:
+    case TouchPoint::Motion:
+    {
+      if( ! mPopup )
+      {
+        if( ! mTooltipTimer )
+        {
+          mHoverPoint = hover.points[ 0 ].screen;
+          mTooltipTimer = Timer::New( mWaitTime );
+          mTooltipTimer.TickSignal().Connect( this, &Tooltip::OnTimeout );
+          mTooltipTimer.Start();
+        }
+        else
+        {
+          Vector2 movement = mHoverPoint - hover.points[ 0 ].screen;
+          if( std::abs( movement.Length() ) > mMovementThreshold )
+          {
+            mTooltipTimer.Stop();
+            mTooltipTimer.Reset();
+
+            mHoverPoint = hover.points[ 0 ].screen;
+            mTooltipTimer = Timer::New( mWaitTime );
+            mTooltipTimer.TickSignal().Connect( this, &Tooltip::OnTimeout );
+            mTooltipTimer.Start();
+          }
+        }
+      }
+      else if( mDisappearOnMovement )
+      {
+        // Popup is showing, and we're set to disappear on excessive movement so make sure we're still within the threshold.
+
+        Vector2 movement = mHoverPoint - hover.points[ 0 ].screen;
+        if( std::abs( movement.Length() ) > mMovementThreshold )
+        {
+          // Exceeding the threshold, hide the popup.
+
+          if( mTooltipTimer )
+          {
+            mTooltipTimer.Stop();
+            mTooltipTimer.Reset();
+          }
+          if( mPopup )
+          {
+            mPopup.Unparent();
+            mPopup.Reset();
+          }
+        }
+      }
+      break;
+    }
+    case TouchPoint::Finished:
+    case TouchPoint::Leave:
+    case TouchPoint::Interrupted:
+    {
+      if( mTooltipTimer )
+      {
+        mTooltipTimer.Stop();
+        mTooltipTimer.Reset();
+      }
+      if( mPopup )
+      {
+        mPopup.Unparent();
+        mPopup.Reset();
+      }
+      break;
+    }
+
+    case TouchPoint::Stationary:
+    case TouchPoint::Last:
+    {
+      break;
+    }
+  }
+
+  return true;
+}
+
+bool Tooltip::OnTimeout()
+{
+  Toolkit::Control control = mControl.GetHandle();
+  if( ! mPopup && control )
+  {
+    mPopup = Toolkit::Popup::New();
+
+    // General set up of popup
+    mPopup.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS );
+    mPopup.SetProperty( Toolkit::Popup::Property::CONTEXTUAL_MODE, "NON_CONTEXTUAL" );
+    mPopup.SetProperty( Toolkit::Popup::Property::ANIMATION_MODE, "NONE" );
+    mPopup.SetProperty( Toolkit::Popup::Property::BACKING_ENABLED, false ); // Disable the dimmed backing.
+    mPopup.SetProperty( Toolkit::Popup::Property::TOUCH_TRANSPARENT, true ); // Let events pass through the popup
+    mPopup.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    mPopup.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+    // Background
+    mPopup.SetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_IMAGE, mBackgroundImage );
+    mPopup.SetProperty( Toolkit::Popup::Property::POPUP_BACKGROUND_BORDER, mBackgroundBorder );
+
+    // Tail
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_VISIBILITY, mTailVisibility );
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_UP_IMAGE,   mTailImages[ Toolkit::Tooltip::Tail::Property::ABOVE_VISUAL ] );
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_DOWN_IMAGE, mTailImages[ Toolkit::Tooltip::Tail::Property::BELOW_VISUAL ] );
+
+    Vector3 tailPosition;
+    switch( mPositionType )
+    {
+      case Toolkit::Tooltip::Position::HOVER_POINT:
+      case Toolkit::Tooltip::Position::BELOW:
+      {
+        tailPosition = Vector3( 0.5f, 0.0f, 0.0 );
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::ABOVE:
+      {
+        tailPosition = Vector3( 0.5f, 1.0f, 0.0 );
+        break;
+      }
+    }
+    mPopup.SetProperty( Toolkit::Popup::Property::TAIL_POSITION, tailPosition );
+
+    // Content
+    Actor content;
+    if( ! mContentTextVisual.Empty() )
+    {
+      content = Toolkit::Control::New();
+      content.SetProperty( Toolkit::Control::Property::BACKGROUND, mContentTextVisual );
+    }
+    else if( ! mContentArray.Empty() )
+    {
+      const unsigned int visuals = mContentArray.Size();
+      unsigned int rows = mLayout.x;
+      unsigned int columns = mLayout.y;
+      if( Equals( mLayout.x, 1.0f, Math::MACHINE_EPSILON_1 ) &&
+          Equals( mLayout.y, 1.0f, Math::MACHINE_EPSILON_1 ) &&
+          visuals > 1 )
+      {
+        rows = mLayout.x;
+        columns = visuals;
+      }
+
+      Toolkit::TableView tableView = Toolkit::TableView::New( rows, columns );
+      tableView.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+
+      for( unsigned int currentContent = 0, currentRow = 0; currentRow < rows && currentContent < visuals; ++currentRow )
+      {
+        tableView.SetFitHeight( currentRow );
+        for( unsigned int currentColumn = 0; currentColumn < columns && currentContent < visuals; ++currentColumn )
+        {
+          Actor child = Toolkit::Control::New();
+          child.SetProperty( Toolkit::Control::Property::BACKGROUND, mContentArray[ currentContent ] );
+
+          Toolkit::TableView::CellPosition cellPosition( currentRow, currentColumn );
+          tableView.AddChild( child, cellPosition );
+          tableView.SetCellAlignment( cellPosition, HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
+          tableView.SetFitWidth( currentColumn );
+
+          ++currentContent;
+        }
+      }
+      content = tableView;
+    }
+    mPopup.SetContent( content );
+
+    // Connect to the relayout signal of the background of the popup as at that point we have the full size
+    Actor popupBackground = GetImpl( mPopup ).GetPopupBackgroundImage();
+    if( popupBackground )
+    {
+      popupBackground.OnRelayoutSignal().Connect( this, &Tooltip::OnRelayout );
+    }
+
+    mPopup.SetDisplayState( Toolkit::Popup::SHOWN );
+
+    Stage::GetCurrent().Add( mPopup );
+  }
+
+  return false;
+}
+
+void Tooltip::OnRelayout( Actor actor )
+{
+  if( mPopup && actor )
+  {
+    float popupWidth = actor.GetRelayoutSize( Dimension::WIDTH );
+    float popupHeight = actor.GetRelayoutSize( Dimension::HEIGHT );
+    float tailHeight = 0.0f;
+    Actor tail;
+
+    if( mTailVisibility )
+    {
+      // Popup's background has the tail, we want to know the tail size as well.
+      if( actor.GetChildCount() )
+      {
+        tail = actor.GetChildAt( 0 );
+        if( tail )
+        {
+          tailHeight = tail.GetRelayoutSize( Dimension::HEIGHT );
+        }
+      }
+    }
+
+    Vector2 stageSize = Stage::GetCurrent().GetSize();
+    Vector3 position;
+
+    switch( mPositionType )
+    {
+      case Toolkit::Tooltip::Position::HOVER_POINT:
+      {
+        position = mHoverPoint + mHoverPointOffset;
+        position.y += tailHeight;
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::ABOVE:
+      {
+        Toolkit::Control control = mControl.GetHandle();
+        if( control )
+        {
+          Vector3 worldPos = control.GetCurrentWorldPosition();
+          float height = control.GetRelayoutSize( Dimension::HEIGHT );
+
+          position.x = stageSize.width * 0.5f + worldPos.x - popupWidth * 0.5f;
+          position.y = stageSize.height * 0.5f + worldPos.y - height * 0.5f - popupHeight * 1.0f - tailHeight;
+        }
+        break;
+      }
+
+      case Toolkit::Tooltip::Position::BELOW:
+      {
+        Toolkit::Control control = mControl.GetHandle();
+        if( control )
+        {
+          Vector3 worldPos = control.GetCurrentWorldPosition();
+          float height = control.GetRelayoutSize( Dimension::HEIGHT );
+
+          position.x = stageSize.width * 0.5f + worldPos.x - popupWidth * 0.5f;
+          position.y = stageSize.height * 0.5f + worldPos.y + height * 0.5f + tailHeight;
+        }
+        break;
+      }
+    }
+
+    // Ensure the Popup is still on the screen
+
+    if( position.x < 0.0f )
+    {
+      position.x = 0.0f;
+    }
+    else if( ( position.x + popupWidth ) > stageSize.width )
+    {
+      position.x -= position.x + popupWidth - stageSize.width;
+    }
+
+    bool yPosChanged = false;
+    if( position.y < 0.0f )
+    {
+      yPosChanged = true;
+      position.y = 0.0f;
+    }
+    else if( ( position.y + popupHeight ) > stageSize.height )
+    {
+      yPosChanged = true;
+      position.y -= position.y + popupHeight - stageSize.height;
+    }
+
+    if( yPosChanged && tail )
+    {
+      // If we change the y position, then the tail may be shown pointing to the wrong control so just hide it.
+      tail.SetVisible( false );
+    }
+
+    mPopup.SetPosition( position );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/tooltip/tooltip.h b/dali-toolkit/internal/controls/tooltip/tooltip.h
new file mode 100644 (file)
index 0000000..bd44de4
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_INTERNAL_TOOLTIP_H
+#define DALI_INTERNAL_TOOLTIP_H
+
+/*
+ * Copyright (c) 2017 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/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/devel-api/controls/popup/popup.h>
+#include <dali-toolkit/devel-api/controls/tooltip/tooltip-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Tooltip;
+typedef IntrusivePtr< Tooltip > TooltipPtr;
+
+/**
+ * @brief Handles all the required tooltip related functionality for a control.
+ *
+ * Connects to the Hovered signal of the control.
+ * Styling is achieved by merging the properties set so that new properties override previous but existing properties are still kept.
+ */
+class Tooltip : public RefObject, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Creates an instance of the Tooltip class.
+   * @param[in]  control  The control the tooltip should be shown on.
+   */
+  static TooltipPtr New( Toolkit::Control control );
+
+  /**
+   * @brief Sets the properties of the Tooltip.
+   * @details The properties are merged over the currently stored properties.
+   *          If a Property::STRING is passed, then the style set previously by the stylesheet is used.
+   *          If a Property::MAP then the map is merged.
+   *          If a Property::ARRAY of Visuals then all are displayed in one row.
+   * @param[in]  value  This can either be a Property::STRING, Property::MAP or Property::ARRAY.
+   */
+  void SetProperties( const Property::Value& value );
+
+  /**
+   * @brief Creates a property map of the tooltip properties.
+   * @param[out]  map  Filled with all the properties of the tooltip.
+   * @note map should be empty.
+   */
+  void CreatePropertyMap( Property::Map& map ) const;
+
+private:
+
+  /**
+   * @brief Private constructor.
+   */
+  Tooltip( Toolkit::Control control );
+
+  /**
+   * @brief Private destructor.
+   */
+  ~Tooltip();
+
+  Tooltip( const Tooltip& ); ///< Undefined
+  Tooltip& operator=( const Tooltip& ); ///< ///< Undefined
+
+  /**
+   * @brief Sets the content of the tooltip.
+   * @details Connects to the signals if there is real content to display.
+   * @param[in]  control  Is used to connect to this control's signals.
+   * @param[in]  value    The content property value.
+   */
+  void SetContent( Toolkit::Control& control, const Property::Value& value );
+
+  /**
+   * @brief Sets the background properties of the tooltip.
+   * @param[in]  value  The background property value.
+   */
+  void SetBackground( const Property::Value& value );
+
+  /**
+   * @brief Sets the tail properties of the tooltip.
+   * @param[in]  value  The tail property value.
+   */
+  void SetTail( const Property::Value& value );
+
+  /**
+   * @brief Method used to connect to the control's Hovered signal.
+   * @param[in]  hover  The hover event.
+   */
+  bool OnHovered( Actor /* actor */, const HoverEvent& hover );
+
+  /**
+   * @brief Method used to connect to the internal timer used by Tooltip.
+   * @return Always return false as we're only interested in one timeout.
+   */
+  bool OnTimeout();
+
+  /**
+   * @brief Used to know when the we're laying out the actor used to display the tooltip.
+   * @details This is required so we can appropriately position it.
+   * @param[in]  actor  The actor being laid out.
+   */
+  void OnRelayout( Actor actor );
+
+  // Data
+
+  Toolkit::Popup mPopup; ///< The Popup class is used to display the actual tooltip.
+  Timer mTooltipTimer; ///< Timer used to wait a certain length of time before we display the tooltip.
+
+  WeakHandle< Toolkit::Control > mControl; ///< A weak handle to the control we are setting the tooltip on.
+
+  Property::Map mContentTextVisual; ///< If using just one visual, then this is set.
+  Property::Map mTailImages; ///< The different images used by the tail.
+  Property::Array mContentArray; ///< If using an array of visuals, then this is used.
+
+  Rect< int > mBackgroundBorder; ///< The size of the background border in the order: left, right, bottom, top. @see Toolkit::Tooltip::Border::Property::BORDER
+
+  Vector2 mLayout; ///< The layout of the content if using an array.
+  Vector2 mHoverPoint; ///< The first point where hover starts.
+  Vector2 mHoverPointOffset; ///< The tooltip is displayed with this offset from hover point if using Toolkit::Tooltip::Position::HOVER_POINT.
+
+  std::string mBackgroundImage; ///< The path to the background image used for the tooltip.
+
+  float mMovementThreshold; ///< This is the allowable movement of the hover before the tooltip processing is cancelled.
+
+  int mWaitTime; ///< Time in milliseconds to wait before we display the tooltip.
+
+  Toolkit::Tooltip::Position::Type mPositionType; ///< The position of the tooltip.
+  bool mTailVisibility; ///< Whether we are showing a tail or not.
+  bool mDisappearOnMovement; ///< Whether the tooltip is set to disappear on movement or when we go out of the bounds of mControl.
+  bool mSignalsConnected; ///< Whether any signals required for Tooltip functionality have been connected.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TOOLTIP_H
diff --git a/dali-toolkit/internal/controls/video-view/video-view-impl.cpp b/dali-toolkit/internal/controls/video-view/video-view-impl.cpp
new file mode 100755 (executable)
index 0000000..8c34ab5
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ * Copyright (c) 2019 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 "video-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/devel-api/actors/actor-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::VideoView::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::VideoView, Toolkit::Control, Create );
+
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "video", MAP, VIDEO )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "looping", BOOLEAN, LOOPING )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "muted", BOOLEAN, MUTED )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "volume", MAP, VOLUME )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "underlay", BOOLEAN, UNDERLAY )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "playPosition", INTEGER, PLAY_POSITION )
+DALI_PROPERTY_REGISTRATION( Toolkit, VideoView, "displayMode", INTEGER, DISPLAY_MODE )
+
+DALI_SIGNAL_REGISTRATION( Toolkit, VideoView, "finished", FINISHED_SIGNAL )
+
+DALI_ACTION_REGISTRATION( Toolkit, VideoView, "play", ACTION_VIDEOVIEW_PLAY )
+DALI_ACTION_REGISTRATION( Toolkit, VideoView, "pause", ACTION_VIDEOVIEW_PAUSE )
+DALI_ACTION_REGISTRATION( Toolkit, VideoView, "stop", ACTION_VIDEOVIEW_STOP )
+DALI_ACTION_REGISTRATION( Toolkit, VideoView, "forward", ACTION_VIDEOVIEW_FORWARD )
+DALI_ACTION_REGISTRATION( Toolkit, VideoView, "backward", ACTION_VIDEOVIEW_BACKWARD )
+
+DALI_TYPE_REGISTRATION_END()
+
+const char* const VOLUME_LEFT( "volumeLeft" );
+const char* const VOLUME_RIGHT( "volumeRight" );
+
+// 3.0 TC uses RENDERING_TARGET. It should be removed in next release
+const char* const RENDERING_TARGET( "renderingTarget" );
+const char* const WINDOW_SURFACE_TARGET( "windowSurfaceTarget" );
+const char* const NATIVE_IMAGE_TARGET( "nativeImageTarget" );
+
+const char* const CUSTOM_SHADER( "shader" );
+const char* const CUSTOM_VERTEX_SHADER( "vertexShader" );
+const char* const CUSTOM_FRAGMENT_SHADER( "fragmentShader" );
+const char* const DEFAULT_SAMPLER_TYPE_NAME( "sampler2D" );
+const char* const CUSTOM_SAMPLER_TYPE_NAME( "samplerExternalOES" );
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = vec4(0.0);\n
+  }\n
+);
+
+const char* VERTEX_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  varying mediump vec2 sTexCoordRect;\n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * vec4(aPosition * uSize.xy, 0.0, 1.0);\n
+    vTexCoord = aPosition + vec2(0.5);\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_TEXTURE = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform samplerExternalOES sTexture;\n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+  }\n
+);
+
+} // anonymous namepsace
+
+VideoView::VideoView()
+: Control( ControlBehaviour( ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mCurrentVideoPlayPosition( 0 ),
+  mIsPlay( false ),
+  mIsUnderlay( true )
+{
+  mVideoPlayer = Dali::VideoPlayer::New();
+}
+
+VideoView::~VideoView()
+{
+}
+
+Toolkit::VideoView VideoView::New()
+{
+  VideoView* impl = new VideoView();
+  Toolkit::VideoView handle = Toolkit::VideoView( *impl );
+
+  impl->Initialize();
+
+  return handle;
+}
+
+void VideoView::OnInitialize()
+{
+  mVideoPlayer.FinishedSignal().Connect( this, &VideoView::EmitSignalFinish );
+}
+
+void VideoView::SetUrl( const std::string& url )
+{
+    mUrl = url;
+    mPropertyMap.Clear();
+
+  mVideoPlayer.SetUrl( mUrl );
+}
+
+void VideoView::SetPropertyMap( Property::Map map )
+{
+  mPropertyMap = map;
+
+  Property::Value* target = map.Find( RENDERING_TARGET );
+  std::string targetType;
+
+  if( target && target->Get( targetType ) && targetType == WINDOW_SURFACE_TARGET )
+  {
+    mIsUnderlay = true;
+    SetWindowSurfaceTarget();
+  }
+  else if( target && target->Get( targetType ) && targetType == NATIVE_IMAGE_TARGET )
+  {
+    mIsUnderlay = false;
+    SetNativeImageTarget();
+  }
+
+  // Custom shader
+  Property::Value* shaderValue;
+  if( !map.Empty() )
+  {
+    shaderValue = map.Find( CUSTOM_SHADER );
+
+    if( shaderValue )
+    {
+      Property::Map* shaderMap = shaderValue->GetMap();
+      if( shaderMap )
+      {
+        mEffectPropertyMap = *shaderMap;
+      }
+    }
+  }
+
+  if( mTextureRenderer && !mEffectPropertyMap.Empty() )
+  {
+    Dali::Shader shader = CreateShader();
+    mTextureRenderer.SetShader( shader );
+  }
+
+  RelayoutRequest();
+}
+
+std::string VideoView::GetUrl()
+{
+  return mUrl;
+}
+
+void VideoView::SetLooping( bool looping )
+{
+  mVideoPlayer.SetLooping( looping );
+}
+
+bool VideoView::IsLooping()
+{
+  return mVideoPlayer.IsLooping();
+}
+
+void VideoView::Play()
+{
+  if( mOverlayRenderer )
+  {
+    Self().AddRenderer( mOverlayRenderer );
+  }
+
+  mVideoPlayer.Play();
+  mIsPlay = true;
+}
+
+void VideoView::Pause()
+{
+  mVideoPlayer.Pause();
+  mIsPlay = false;
+}
+
+void VideoView::Stop()
+{
+  mVideoPlayer.Stop();
+  mIsPlay = false;
+}
+
+void VideoView::Forward( int millisecond )
+{
+  int curPos = mVideoPlayer.GetPlayPosition();
+
+  int nextPos = curPos + millisecond;
+
+  mVideoPlayer.SetPlayPosition( nextPos );
+}
+
+void VideoView::Backward( int millisecond )
+{
+  int curPos = mVideoPlayer.GetPlayPosition();
+
+  int nextPos = curPos - millisecond;
+  nextPos = ( nextPos < 0 )? 0: nextPos;
+
+  mVideoPlayer.SetPlayPosition( nextPos );
+}
+
+void VideoView::SetMute( bool mute )
+{
+  mVideoPlayer.SetMute( mute );
+}
+
+bool VideoView::IsMuted()
+{
+  return mVideoPlayer.IsMuted();
+}
+
+void VideoView::SetVolume( float left, float right )
+{
+  mVideoPlayer.SetVolume( left, right );
+}
+
+void VideoView::GetVolume( float& left, float& right )
+{
+  mVideoPlayer.GetVolume( left, right );
+}
+
+Dali::Toolkit::VideoView::VideoViewSignalType& VideoView::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+void VideoView::EmitSignalFinish()
+{
+  if( mOverlayRenderer )
+  {
+    Self().RemoveRenderer( mOverlayRenderer );
+  }
+
+  if ( !mFinishedSignal.Empty() )
+  {
+    Dali::Toolkit::VideoView handle( GetOwner() );
+    mFinishedSignal.Emit( handle );
+  }
+}
+
+bool VideoView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
+{
+  bool ret = false;
+
+  Dali::BaseHandle handle( object );
+  Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
+
+  if( !videoView )
+  {
+    return ret;
+  }
+
+  VideoView& impl = GetImpl( videoView );
+
+  if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PLAY ) == 0 )
+  {
+    impl.Play();
+    ret = true;
+  }
+  else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_PAUSE ) == 0 )
+  {
+    impl.Pause();
+    ret = true;
+  }
+  else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_STOP ) == 0 )
+  {
+    impl.Stop();
+    ret = true;
+  }
+  else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_FORWARD ) == 0 )
+  {
+    int millisecond = 0;
+    if( attributes["videoForward"].Get( millisecond ) )
+    {
+      impl.Forward( millisecond );
+      ret = true;
+    }
+  }
+  else if( strcmp( actionName.c_str(), ACTION_VIDEOVIEW_BACKWARD ) == 0 )
+  {
+    int millisecond = 0;
+    if( attributes["videoBackward"].Get( millisecond ) )
+    {
+      impl.Backward( millisecond );
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+bool VideoView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), FINISHED_SIGNAL ) )
+  {
+    videoView.FinishedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void VideoView::SetPropertyInternal( Property::Index index, const Property::Value& value )
+{
+  switch( index )
+  {
+    case Toolkit::VideoView::Property::VIDEO:
+    {
+      std::string videoUrl;
+      Property::Map map;
+
+      if( value.Get( videoUrl ) )
+      {
+        SetUrl( videoUrl );
+      }
+      else if( value.Get( map ) )
+      {
+        SetPropertyMap( map );
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::LOOPING:
+    {
+      bool looping;
+      if( value.Get( looping ) )
+      {
+        SetLooping( looping );
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::MUTED:
+    {
+      bool mute;
+      if( value.Get( mute ) )
+      {
+        SetMute( mute );
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::VOLUME:
+    {
+      Property::Map map;
+      float left, right;
+      if( value.Get( map ) )
+      {
+        Property::Value* volumeLeft = map.Find( VOLUME_LEFT );
+        Property::Value* volumeRight = map.Find( VOLUME_RIGHT );
+        if( volumeLeft && volumeLeft->Get( left ) && volumeRight && volumeRight->Get( right ) )
+        {
+          SetVolume( left, right );
+        }
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::UNDERLAY:
+    {
+      bool underlay;
+      if( value.Get( underlay ) )
+      {
+        SetUnderlay( underlay );
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::PLAY_POSITION:
+    {
+      int pos;
+      if( value.Get( pos ) )
+      {
+        SetPlayPosition( pos );
+      }
+      break;
+    }
+    case Toolkit::VideoView::Property::DISPLAY_MODE:
+    {
+      int mode;
+      if( value.Get( mode ) )
+      {
+        SetDisplayMode( mode );
+      }
+      break;
+    }
+  }
+}
+
+void VideoView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
+
+  if( videoView )
+  {
+    VideoView& impl = GetImpl( videoView );
+
+    impl.SetPropertyInternal( index, value );
+
+    if( index != Toolkit::VideoView::Property::UNDERLAY )
+    {
+      // Backup values.
+      // These values will be used when underlay mode is changed.
+      impl.mPropertyBackup[index] = value;
+    }
+  }
+}
+
+Property::Value VideoView::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+  Toolkit::VideoView videoView = Toolkit::VideoView::DownCast( Dali::BaseHandle( object ) );
+
+  if( videoView )
+  {
+    VideoView& impl = GetImpl( videoView );
+
+    switch( propertyIndex )
+    {
+      case Toolkit::VideoView::Property::VIDEO:
+      {
+        if( !impl.mUrl.empty() )
+        {
+          value = impl.mUrl;
+        }
+        else if( !impl.mPropertyMap.Empty() )
+        {
+          value = impl.mPropertyMap;
+        }
+        break;
+      }
+      case Toolkit::VideoView::Property::LOOPING:
+      {
+        value = impl.IsLooping();
+        break;
+      }
+      case Toolkit::VideoView::Property::MUTED:
+      {
+        value = impl.IsMuted();
+        break;
+      }
+      case Toolkit::VideoView::Property::VOLUME:
+      {
+        Property::Map map;
+        float left, right;
+
+        impl.GetVolume( left, right );
+        map.Insert( VOLUME_LEFT, left );
+        map.Insert( VOLUME_RIGHT, right );
+        value = map;
+        break;
+      }
+      case Toolkit::VideoView::Property::UNDERLAY:
+      {
+        value = impl.IsUnderlay();
+        break;
+      }
+      case Toolkit::VideoView::Property::PLAY_POSITION:
+      {
+        value = impl.GetPlayPosition();
+        break;
+      }
+      case Toolkit::VideoView::Property::DISPLAY_MODE:
+      {
+        value = impl.GetDisplayMode();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void VideoView::SetDepthIndex( int depthIndex )
+{
+  if( mTextureRenderer )
+  {
+    mTextureRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, depthIndex );
+  }
+}
+
+void VideoView::OnStageConnection( int depth )
+{
+  Control::OnStageConnection( depth );
+
+  if( mIsUnderlay )
+  {
+    SetWindowSurfaceTarget();
+  }
+}
+
+void VideoView::OnStageDisconnection()
+{
+  Control::OnStageDisconnection();
+}
+
+Vector3 VideoView::GetNaturalSize()
+{
+  Vector3 size;
+  size.x = mVideoSize.GetWidth();
+  size.y = mVideoSize.GetHeight();
+
+  if( size.x > 0 && size.y > 0 )
+  {
+    size.z = std::min( size.x, size.y );
+    return size;
+  }
+  else
+  {
+    return Control::GetNaturalSize();
+  }
+}
+
+float VideoView::GetHeightForWidth( float width )
+{
+  if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
+  {
+    return GetHeightForWidthBase( width );
+  }
+  else
+  {
+    return Control::GetHeightForWidthBase( width );
+  }
+}
+
+float VideoView::GetWidthForHeight( float height )
+{
+  if( mVideoSize.GetWidth() > 0 && mVideoSize.GetHeight() > 0 )
+  {
+    return GetWidthForHeightBase( height );
+  }
+  else
+  {
+    return Control::GetWidthForHeightBase( height );
+  }
+}
+
+void VideoView::SetWindowSurfaceTarget()
+{
+  Actor self = Self();
+
+  if( !self.OnStage() )
+  {
+    // When the control is off the stage, it does not have Window.
+    return;
+  }
+
+  int curPos = mVideoPlayer.GetPlayPosition();
+
+  if( mIsPlay )
+  {
+    mVideoPlayer.Pause();
+  }
+
+  mPositionUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_POSITION, StepCondition( 1.0f, 1.0f ) );
+  mSizeUpdateNotification = self.AddPropertyNotification( Actor::Property::SIZE, StepCondition( 1.0f, 1.0f ) );
+  mScaleUpdateNotification = self.AddPropertyNotification( Actor::Property::WORLD_SCALE, StepCondition( 0.1f, 1.0f ) );
+  mPositionUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
+  mSizeUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
+  mScaleUpdateNotification.NotifySignal().Connect( this, &VideoView::UpdateDisplayArea );
+
+  if( mTextureRenderer )
+  {
+    self.RemoveRenderer( mTextureRenderer );
+  }
+
+  // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
+  mVideoPlayer.SetRenderingTarget( Dali::Adaptor::Get().GetNativeWindowHandle( self ) );
+
+  ApplyBackupProperties();
+
+  if( !mOverlayRenderer )
+  {
+    // For underlay rendering mode, video display area have to be transparent.
+    Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
+    Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    mOverlayRenderer = Renderer::New( geometry, shader );
+    mOverlayRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
+  }
+
+  if( mIsPlay )
+  {
+    Play();
+  }
+
+  if( curPos > 0 )
+  {
+    mVideoPlayer.SetPlayPosition( curPos );
+  }
+}
+
+void VideoView::SetNativeImageTarget()
+{
+  if( mVideoPlayer.IsVideoTextureSupported() == false )
+  {
+    DALI_LOG_ERROR( "Platform doesn't support decoded video frame images\n" );
+    mIsUnderlay = true;
+    return;
+  }
+
+  if( mIsPlay )
+  {
+    mVideoPlayer.Pause();
+  }
+
+  Actor self( Self() );
+
+  if( mOverlayRenderer )
+  {
+    self.RemoveRenderer( mOverlayRenderer );
+
+    mOverlayRenderer.Reset();
+  }
+
+  self.RemovePropertyNotification( mPositionUpdateNotification );
+  self.RemovePropertyNotification( mSizeUpdateNotification );
+  self.RemovePropertyNotification( mScaleUpdateNotification );
+
+  int curPos = mVideoPlayer.GetPlayPosition();
+
+  Any source;
+  Dali::NativeImageSourcePtr nativeImageSourcePtr = Dali::NativeImageSource::New( source );
+  mNativeTexture = Dali::Texture::New( *nativeImageSourcePtr );
+
+  if( !mTextureRenderer )
+  {
+    Dali::Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
+    Dali::Shader shader = CreateShader();
+    Dali::TextureSet textureSet = Dali::TextureSet::New();
+    textureSet.SetTexture( 0u, mNativeTexture );
+
+    mTextureRenderer = Renderer::New( geometry, shader );
+    mTextureRenderer.SetTextures( textureSet );
+  }
+  else
+  {
+    Dali::TextureSet textureSet = mTextureRenderer.GetTextures();
+    textureSet.SetTexture( 0u, mNativeTexture );
+  }
+  Self().AddRenderer( mTextureRenderer );
+
+  // Note VideoPlayer::SetRenderingTarget resets all the options. (e.g. url, mute, looping)
+  mVideoPlayer.SetRenderingTarget( nativeImageSourcePtr );
+
+  ApplyBackupProperties();
+
+  if( mIsPlay )
+  {
+    Play();
+  }
+
+  if( curPos > 0 )
+  {
+    mVideoPlayer.SetPlayPosition( curPos );
+  }
+}
+
+void VideoView::UpdateDisplayArea( Dali::PropertyNotification& source )
+{
+  if( !mIsUnderlay )
+  {
+    return;
+  }
+
+  Actor self( Self() );
+
+  bool positionUsesAnchorPoint = self.GetProperty( DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >();
+  Vector3 actorSize = self.GetCurrentSize() * self.GetCurrentScale();
+  Vector3 anchorPointOffSet = actorSize * ( positionUsesAnchorPoint ? self.GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT );
+
+  Vector2 screenPosition = self.GetProperty( DevelActor::Property::SCREEN_POSITION ).Get< Vector2 >();
+
+  mDisplayArea.x = screenPosition.x - anchorPointOffSet.x;
+  mDisplayArea.y = screenPosition.y - anchorPointOffSet.y;
+  mDisplayArea.width = actorSize.x;
+  mDisplayArea.height = actorSize.y;
+
+  mVideoPlayer.SetDisplayArea( mDisplayArea );
+}
+
+void VideoView::SetUnderlay( bool set )
+{
+  if( set != mIsUnderlay )
+  {
+    mIsUnderlay = set;
+
+    if( mIsUnderlay )
+    {
+      SetWindowSurfaceTarget();
+    }
+    else
+    {
+      SetNativeImageTarget();
+    }
+
+    RelayoutRequest();
+  }
+}
+
+bool VideoView::IsUnderlay()
+{
+  return mIsUnderlay;
+}
+
+void VideoView::SetSWCodec( bool on )
+{
+  // If setting SW or HW type is failed , video-view shows video by default codec type.
+  // The default codec type is selected by platform.
+  if( on )
+  {
+    mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::SW );
+  }
+  else
+  {
+    mVideoPlayer.SetCodecType( Dali::VideoPlayerPlugin::CodecType::HW );
+  }
+}
+
+int VideoView::GetPlayPosition()
+{
+  return mVideoPlayer.GetPlayPosition();
+}
+
+void VideoView::SetPlayPosition( int pos )
+{
+  mVideoPlayer.SetPlayPosition( pos );
+}
+
+void VideoView::SetDisplayMode( int mode )
+{
+  mVideoPlayer.SetDisplayMode( static_cast< Dali::VideoPlayerPlugin::DisplayMode::Type >( mode ) );
+}
+
+int VideoView::GetDisplayMode() const
+{
+  return static_cast< int >( mVideoPlayer.GetDisplayMode() );
+}
+
+Any VideoView::GetMediaPlayer()
+{
+  return mVideoPlayer.GetMediaPlayer();
+}
+
+Dali::Shader VideoView::CreateShader()
+{
+  std::string fragmentShader = "#extension GL_OES_EGL_image_external:require\n";
+  std::string vertexShader;
+  std::string customFragmentShader;
+  bool checkShader = false;
+
+  if( !mEffectPropertyMap.Empty() )
+  {
+    Property::Value* vertexShaderValue = mEffectPropertyMap.Find( CUSTOM_VERTEX_SHADER );
+    if( vertexShaderValue )
+    {
+      checkShader = GetStringFromProperty( *vertexShaderValue, vertexShader );
+    }
+
+    if( !vertexShaderValue || !checkShader )
+    {
+      vertexShader = VERTEX_SHADER_TEXTURE;
+    }
+
+    Property::Value* fragmentShaderValue = mEffectPropertyMap.Find( CUSTOM_FRAGMENT_SHADER );
+    if( fragmentShaderValue )
+    {
+      checkShader = GetStringFromProperty( *fragmentShaderValue, customFragmentShader );
+
+      if( checkShader )
+      {
+        fragmentShader = customFragmentShader;
+      }
+    }
+
+    if( !fragmentShaderValue || !checkShader )
+    {
+      fragmentShader += FRAGMENT_SHADER_TEXTURE;
+    }
+  }
+  else
+  {
+    vertexShader = VERTEX_SHADER_TEXTURE;
+    fragmentShader += FRAGMENT_SHADER_TEXTURE;
+  }
+
+  return Dali::Shader::New( vertexShader, fragmentShader );
+}
+
+bool VideoView::GetStringFromProperty( const Dali::Property::Value& value, std::string& output )
+{
+  bool extracted = false;
+  if( value.Get( output ) )
+  {
+    extracted = true;
+  }
+
+  return extracted;
+}
+
+void VideoView::ApplyBackupProperties()
+{
+  Property::Map::SizeType pos = 0;
+  Property::Map::SizeType count = mPropertyBackup.Count();
+
+  for( ; pos < count; pos++ )
+  {
+    KeyValuePair property = mPropertyBackup.GetKeyValue( pos );
+
+    SetPropertyInternal( property.first.indexKey, property.second );
+  }
+}
+
+} // namespace Internal
+
+} // namespace toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/video-view/video-view-impl.h b/dali-toolkit/internal/controls/video-view/video-view-impl.h
new file mode 100755 (executable)
index 0000000..3d345a3
--- /dev/null
@@ -0,0 +1,376 @@
+#ifndef DALI_TOOLKIT_INTERNAL_VIDEO_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_VIDEO_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-map.h>
+#include <dali/public-api/images/native-image.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/object/property-conditions.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/devel-api/adaptor-framework/video-player.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class VideoView;
+
+namespace Internal
+{
+
+class VideoView: public Control
+{
+protected:
+
+  VideoView();
+
+  virtual ~VideoView();
+
+public:
+
+  /**
+   * @copydoc Toolkit::VideoView::New()
+   */
+  static Toolkit::VideoView New();
+
+  /**
+   * @brief Sets a video url to play.
+   *
+   * @SINCE_1_1.38
+   * @param [in] url The url of the video resource to play
+   */
+  void SetUrl( const std::string& url );
+
+  /**
+   * @brief Returns a video url.
+   * @SINCE_1_1.38
+   * @return Url of string type
+   */
+  std::string GetUrl();
+
+  /**
+   * @brief Sets the player looping status.
+   *
+   * @SINCE_1_1.38
+   * @param [in] looping The new looping status: true or false
+   */
+  void SetLooping(bool looping);
+
+  /**
+   * @brief Returns the player looping status.
+   *
+   * @SINCE_1_1.38
+   * @return True if player is looping, false otherwise.
+   */
+  bool IsLooping();
+
+  /**
+   * @copydoc Toolkit::VideoView::Play()
+   */
+  void Play();
+
+  /**
+   * @copydoc Toolkit::VideoView::Pause()
+   */
+  void Pause();
+
+  /**
+   * @copydoc Toolkit::VideoView::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc Toolkit::VideoView::Forward()
+   */
+  void Forward( int millisecond );
+
+  /**
+   * @copydoc Toolkit::VideoView::Backward()
+   */
+  void Backward( int millisecond );
+
+  /**
+   * @brief Sets the player mute status.
+   * @SINCE_1_1.38
+   * @param[i] mute The new mute status, true is mute.
+   */
+  void SetMute( bool mute );
+
+  /**
+   * @brief Returns the player mute status.
+   * @SINCE_1_1.38
+   * @return True if player is mute.
+   */
+  bool IsMuted();
+
+  /**
+   * @brief Sets the player volume.
+   * @SINCE_1_1.38
+   * @param[in] left The left volume scalar
+   * @param[in] right The right volume scalar
+   */
+  void SetVolume( float left, float right );
+
+  /**
+   * @brief Returns current volume factor.
+   * @SINCE_1_1.38
+   * @param[out] left The current left volume scalar
+   * @param[out] right The current right volume scalar
+   */
+  void GetVolume( float& left, float& right );
+
+ /**
+   * @copydoc Dali::Toolkit::VideoView::FinishedSignal()
+   */
+  Dali::Toolkit::VideoView::VideoViewSignalType& FinishedSignal();
+
+  /**
+   * @brief Emit the finished signal
+   */
+  void EmitSignalFinish();
+
+  /**
+   * @brief Set property map
+   * @SINCE_1_1.38
+   * @param[in] map The Dali::Property::Map to use for to display.
+   */
+  void SetPropertyMap( Property::Map map );
+
+  // Properties
+  /**
+   * @brief Called when a property of an object of this type is set.
+   * @SINCE_1_1.38
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( BaseObject* object, Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   * @SINCE_1_1.38
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex );
+
+  /**
+   * @brief Set the depth index of this image renderer
+   *
+   * Renderer with higher depth indices are rendered in front of other visuals with smaller values
+   * @SINCE_1_1.38
+   * @param[in] depthIndex The depth index of this renderer
+   */
+  void SetDepthIndex( int depthIndex );
+
+  /**
+   * @brief Performs actions as requested using the action name.
+   * @SINCE_1_1.38
+   * @param[in] object The object on which to perform the action.
+   * @param[in] actionName The action to perform.
+   * @param[in] attributes The attributes with which to perfrom this action.
+   * @return True if action has been accepted by this control
+   */
+  static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes );
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the c
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  /**
+   * @brief Updates video display area for window rendering target
+   */
+  void UpdateDisplayArea( Dali::PropertyNotification& source );
+
+  /**
+   * @brief Sets underlay flag and initializes new rendering target by flag.
+   */
+  void SetUnderlay( bool set );
+
+  /**
+   * @brief Checks underlay flag.
+   */
+  bool IsUnderlay();
+
+  /**
+   * @brief Sets sw codec type.
+   */
+  void SetSWCodec( bool on );
+
+  /**
+   * @brief Gets play position.
+   */
+  int GetPlayPosition();
+
+  /**
+   * @brief Sets play position.
+   */
+  void SetPlayPosition( int pos );
+
+  /**
+   * @brief Sets Display mode.
+   */
+  void SetDisplayMode( int mode );
+
+  /**
+   * @brief Gets Display mode.
+   */
+  int GetDisplayMode() const;
+
+  /**
+   * @brief Gets internal media player.
+   */
+  Any GetMediaPlayer();
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::OnStageConnect()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc Toolkit::Control::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc Toolkit::Control::GetNaturalSize
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Toolkit::Control::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Toolkit::Control::GetWidthForHeight()
+   */
+  virtual float GetWidthForHeight( float height );
+
+private:
+
+  /**
+   * @brief Construct a new VideoView.
+   */
+  VideoView( const VideoView& videoView );
+
+  // Undefined assignment operator.
+  VideoView& operator=( const VideoView& videoView );
+
+  /**
+   * @brief SetWindowSurfaceTarget for underlay video playback.
+   */
+  void SetWindowSurfaceTarget();
+
+  /**
+   * @brief SetNativeImageTarget for native image video playback.
+   */
+  void SetNativeImageTarget();
+
+  /**
+   * @brief CreateShader for native image target
+   */
+  Dali::Shader CreateShader();
+
+  /**
+   * @brief Checks whether the property has a string value.
+   * @param Property value
+   * @param String output
+   * @return true if the output was found
+   */
+  bool GetStringFromProperty( const Dali::Property::Value& value, std::string& output );
+
+  /*
+   * @brief Internal version of SetProperty
+   */
+  void SetPropertyInternal( Property::Index index, const Property::Value& value );
+
+  /*
+   * @brief Apply properties after reset video player
+   */
+  void ApplyBackupProperties();
+
+private:
+
+  Dali::VideoPlayer mVideoPlayer;
+  Dali::ImageDimensions mVideoSize;
+  Dali::Property::Map mPropertyMap;
+  Dali::Property::Map mEffectPropertyMap;
+  Dali::Texture mNativeTexture;
+  Dali::Toolkit::VideoView::VideoViewSignalType mFinishedSignal;
+  std::string mUrl;
+  Dali::DisplayArea mDisplayArea;
+  Dali::Renderer mOverlayRenderer;
+  Dali::Renderer mTextureRenderer;
+  Dali::PropertyNotification mPositionUpdateNotification;
+  Dali::PropertyNotification mSizeUpdateNotification;
+  Dali::PropertyNotification mScaleUpdateNotification;
+  Dali::Property::Map mPropertyBackup;
+
+  int mCurrentVideoPlayPosition;
+  bool mIsPlay;
+  bool mIsUnderlay;
+};
+
+} // namespace Internal
+
+inline Toolkit::Internal::VideoView& GetImpl( Toolkit::VideoView& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast< Toolkit::Internal::VideoView& >( impl );
+}
+
+inline const Toolkit::Internal::VideoView& GetImpl( const Toolkit::VideoView& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  const Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast< const Toolkit::Internal::VideoView& >( impl );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VIDEO_VIEW_H
diff --git a/dali-toolkit/internal/controls/web-view/web-view-impl.cpp b/dali-toolkit/internal/controls/web-view/web-view-impl.cpp
new file mode 100644 (file)
index 0000000..b0d81de
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2018 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 "web-view-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/images/native-image.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return Toolkit::WebView::New();
+}
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( CacheModel )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CacheModel, DOCUMENT_VIEWER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CacheModel, DOCUMENT_BROWSER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CacheModel, PRIMARY_WEB_BROWSER )
+DALI_ENUM_TO_STRING_TABLE_END( CacheModel )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( CookieAcceptPolicy )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CookieAcceptPolicy, ALWAYS )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CookieAcceptPolicy, NEVER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::WebView::CookieAcceptPolicy, NO_THIRD_PARTY )
+DALI_ENUM_TO_STRING_TABLE_END( CookieAcceptPolicy )
+
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::WebView, Toolkit::Control, Create )
+
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "url",                     STRING,  URL                        )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "cacheModel",              STRING,  CACHE_MODEL                )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "cookieAcceptPolicy",      STRING,  COOKIE_ACCEPT_POLICY       )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "userAgent",               STRING,  USER_AGENT                 )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "enableJavaScript",        BOOLEAN, ENABLE_JAVASCRIPT          )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "loadImagesAutomatically", BOOLEAN, LOAD_IMAGES_AUTOMATICALLY  )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "defaultTextEncodingName", STRING,  DEFAULT_TEXT_ENCODING_NAME )
+DALI_PROPERTY_REGISTRATION( Toolkit, WebView, "defaultFontSize",         INTEGER, DEFAULT_FONT_SIZE          )
+
+DALI_SIGNAL_REGISTRATION(   Toolkit, WebView, "pageLoadStarted",         PAGE_LOAD_STARTED_SIGNAL            )
+DALI_SIGNAL_REGISTRATION(   Toolkit, WebView, "pageLoadFinished",        PAGE_LOAD_FINISHED_SIGNAL           )
+DALI_SIGNAL_REGISTRATION(   Toolkit, WebView, "pageLoadError",           PAGE_LOAD_ERROR_SIGNAL              )
+
+DALI_TYPE_REGISTRATION_END()
+
+const std::string kEmptyString;
+
+} // anonymous namepsace
+
+#define GET_ENUM_STRING( structName, inputExp ) \
+  Scripting::GetLinearEnumerationName< Toolkit::WebView::structName::Type >( static_cast< Toolkit::WebView::structName::Type >( inputExp ), structName##_TABLE, structName##_TABLE_COUNT )
+
+#define GET_ENUM_VALUE( structName, inputExp, outputExp ) \
+  Scripting::GetEnumerationProperty< Toolkit::WebView::structName::Type >( inputExp, structName##_TABLE, structName##_TABLE_COUNT, outputExp )
+
+WebView::WebView( const std::string& locale, const std::string& timezoneId )
+: Control( ControlBehaviour( ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mUrl(),
+  mVisual(),
+  mWebViewSize( Stage::GetCurrent().GetSize() ),
+  mWebEngine(),
+  mPageLoadStartedSignal(),
+  mPageLoadFinishedSignal(),
+  mPageLoadErrorSignal()
+{
+  mWebEngine = Dali::WebEngine::New();
+
+  // WebEngine is empty when it is not properly initialized.
+  if( mWebEngine )
+  {
+    mWebEngine.Create( mWebViewSize.width, mWebViewSize.height, locale, timezoneId );
+  }
+}
+
+WebView::WebView()
+: WebView( "", "" )
+{
+}
+
+WebView::~WebView()
+{
+}
+
+Toolkit::WebView WebView::New()
+{
+  WebView* impl = new WebView();
+  Toolkit::WebView handle = Toolkit::WebView( *impl );
+
+  impl->Initialize();
+  return handle;
+}
+
+Toolkit::WebView WebView::New( const std::string& locale, const std::string& timezoneId )
+{
+  WebView* impl = new WebView( locale, timezoneId );
+  Toolkit::WebView handle = Toolkit::WebView( *impl );
+
+  impl->Initialize();
+  return handle;
+}
+
+void WebView::OnInitialize()
+{
+  Self().SetKeyboardFocusable( true );
+  Self().TouchSignal().Connect( this, &WebView::OnTouchEvent );
+
+  if( mWebEngine )
+  {
+    mWebEngine.PageLoadStartedSignal().Connect( this, &WebView::OnPageLoadStarted );
+    mWebEngine.PageLoadFinishedSignal().Connect( this, &WebView::OnPageLoadFinished );
+    mWebEngine.PageLoadErrorSignal().Connect( this, &WebView::OnPageLoadError );
+  }
+}
+
+void WebView::LoadUrl( const std::string& url )
+{
+  mUrl = url;
+  if( mWebEngine )
+  {
+    Dali::Image image = Dali::NativeImage::New( *mWebEngine.GetNativeImageSource() );
+    mVisual = Toolkit::VisualFactory::Get().CreateVisual( image );
+
+    if( mVisual )
+    {
+      // Clean up previously registered visual and add new one.
+      DevelControl::RegisterVisual( *this, Toolkit::WebView::Property::URL, mVisual );
+      mWebEngine.LoadUrl( url );
+    }
+  }
+}
+
+void WebView::LoadHTMLString( const std::string& htmlString )
+{
+  if( mWebEngine )
+  {
+    Dali::Image image = Dali::NativeImage::New( *mWebEngine.GetNativeImageSource() );
+    mVisual = Toolkit::VisualFactory::Get().CreateVisual( image );
+
+    if( mVisual )
+    {
+      DevelControl::RegisterVisual( *this, Toolkit::WebView::Property::URL, mVisual );
+      mWebEngine.LoadHTMLString( htmlString );
+    }
+  }
+}
+
+void WebView::Reload()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.Reload();
+  }
+}
+
+void WebView::StopLoading()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.StopLoading();
+  }
+}
+
+void WebView::Suspend()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.Suspend();
+  }
+}
+
+void WebView::Resume()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.Resume();
+  }
+}
+
+bool WebView::CanGoForward()
+{
+  return mWebEngine ? mWebEngine.CanGoForward() : false;
+}
+
+void WebView::GoForward()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.GoForward();
+  }
+}
+
+bool WebView::CanGoBack()
+{
+  return mWebEngine ? mWebEngine.CanGoBack() : false;
+}
+
+void WebView::GoBack()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.GoBack();
+  }
+}
+
+void WebView::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.EvaluateJavaScript( script, resultHandler );
+  }
+}
+
+void WebView::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.AddJavaScriptMessageHandler( exposedObjectName, handler );
+  }
+}
+
+void WebView::ClearHistory()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.ClearHistory();
+  }
+}
+
+void WebView::ClearCache()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.ClearCache();
+  }
+}
+
+void WebView::ClearCookies()
+{
+  if( mWebEngine )
+  {
+    mWebEngine.ClearCookies();
+  }
+}
+
+Dali::Toolkit::WebView::WebViewPageLoadSignalType& WebView::PageLoadStartedSignal()
+{
+  return mPageLoadStartedSignal;
+}
+
+Dali::Toolkit::WebView::WebViewPageLoadSignalType& WebView::PageLoadFinishedSignal()
+{
+  return mPageLoadFinishedSignal;
+}
+
+Dali::Toolkit::WebView::WebViewPageLoadErrorSignalType& WebView::PageLoadErrorSignal()
+{
+  return mPageLoadErrorSignal;
+}
+
+void WebView::OnPageLoadStarted( const std::string& url )
+{
+  if( !mPageLoadStartedSignal.Empty() )
+  {
+    Dali::Toolkit::WebView handle( GetOwner() );
+    mPageLoadStartedSignal.Emit( handle, url );
+  }
+}
+
+void WebView::OnPageLoadFinished( const std::string& url )
+{
+  if( !mPageLoadFinishedSignal.Empty() )
+  {
+    Dali::Toolkit::WebView handle( GetOwner() );
+    mPageLoadFinishedSignal.Emit( handle, url );
+  }
+}
+
+void WebView::OnPageLoadError( const std::string& url, int errorCode )
+{
+  if( !mPageLoadErrorSignal.Empty() )
+  {
+    Dali::Toolkit::WebView handle( GetOwner() );
+    mPageLoadErrorSignal.Emit( handle, url, static_cast< Toolkit::WebView::LoadErrorCode >( errorCode ) );
+  }
+}
+
+bool WebView::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected = false;
+  Toolkit::WebView webView = Toolkit::WebView::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), PAGE_LOAD_STARTED_SIGNAL ) )
+  {
+    webView.PageLoadStartedSignal().Connect( tracker, functor );
+    connected = true;
+  }
+  else if( 0 == strcmp( signalName.c_str(), PAGE_LOAD_FINISHED_SIGNAL ) )
+  {
+    webView.PageLoadFinishedSignal().Connect( tracker, functor );
+    connected = true;
+  }
+  else if( 0 == strcmp( signalName.c_str(), PAGE_LOAD_ERROR_SIGNAL ) )
+  {
+    webView.PageLoadErrorSignal().Connect( tracker, functor );
+    connected = true;
+  }
+
+  return connected;
+}
+
+Vector3 WebView::GetNaturalSize()
+{
+  if( mVisual )
+  {
+    Vector2 rendererNaturalSize;
+    mVisual.GetNaturalSize( rendererNaturalSize );
+    return Vector3( rendererNaturalSize );
+  }
+
+  return Vector3( mWebViewSize );
+}
+
+void WebView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  Control::OnRelayout( size, container );
+
+  if( size.width > 0 && size.height > 0 && mWebViewSize != size )
+  {
+    mWebViewSize = size;
+
+    if( mWebEngine )
+    {
+      mWebEngine.SetSize( size.width, size.height );
+    }
+  }
+}
+
+void WebView::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  Toolkit::WebView webView = Toolkit::WebView::DownCast( Dali::BaseHandle( object ) );
+
+  if( webView )
+  {
+    WebView& impl = GetImpl( webView );
+    switch( index )
+    {
+      case Toolkit::WebView::Property::URL:
+      {
+        std::string url;
+        if( value.Get( url ) )
+        {
+          impl.LoadUrl( url );
+        }
+        break;
+      }
+      case Toolkit::WebView::Property::CACHE_MODEL:
+      {
+        Toolkit::WebView::CacheModel::Type output = impl.GetCacheModel();
+        GET_ENUM_VALUE( CacheModel, value, output );
+        impl.SetCacheModel( output );
+        break;
+      }
+      case Toolkit::WebView::Property::COOKIE_ACCEPT_POLICY:
+      {
+        Toolkit::WebView::CookieAcceptPolicy::Type output = impl.GetCookieAcceptPolicy();
+        GET_ENUM_VALUE( CookieAcceptPolicy, value, output );
+        impl.SetCookieAcceptPolicy( output );
+        break;
+      }
+      case Toolkit::WebView::Property::USER_AGENT:
+      {
+        std::string input;
+        if( value.Get( input ) )
+        {
+          impl.SetUserAgent( input );
+        }
+        break;
+      }
+      case Toolkit::WebView::Property::ENABLE_JAVASCRIPT:
+      {
+        bool input;
+        if( value.Get( input ) )
+        {
+          impl.EnableJavaScript( input );
+        }
+        break;
+      }
+      case Toolkit::WebView::Property::LOAD_IMAGES_AUTOMATICALLY:
+      {
+        bool input;
+        if( value.Get( input ) )
+        {
+          impl.LoadImagesAutomatically( input );
+        }
+        break;
+      }
+      case Toolkit::WebView::Property::DEFAULT_TEXT_ENCODING_NAME:
+      {
+        std::string input;
+        if( value.Get( input ) )
+        {
+          impl.SetDefaultTextEncodingName( input );
+        }
+        break;
+      }
+      case Toolkit::WebView::Property::DEFAULT_FONT_SIZE:
+      {
+        int input;
+        if( value.Get( input ) )
+        {
+          impl.SetDefaultFontSize( input );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Value WebView::GetProperty( BaseObject* object, Property::Index propertyIndex )
+{
+  Property::Value value;
+
+  Toolkit::WebView webView = Toolkit::WebView::DownCast( Dali::BaseHandle( object ) );
+
+  if( webView )
+  {
+    WebView& impl = GetImpl( webView );
+    switch( propertyIndex )
+    {
+      case Toolkit::WebView::Property::URL:
+      {
+        value = impl.mUrl;
+        break;
+      }
+      case Toolkit::WebView::Property::CACHE_MODEL:
+      {
+        value = GET_ENUM_STRING( CacheModel, impl.GetCacheModel() );
+        break;
+      }
+      case Toolkit::WebView::Property::COOKIE_ACCEPT_POLICY:
+      {
+        value = GET_ENUM_STRING( CookieAcceptPolicy, impl.GetCookieAcceptPolicy() );
+        break;
+      }
+      case Toolkit::WebView::Property::USER_AGENT:
+      {
+        value = impl.GetUserAgent();
+        break;
+      }
+      case Toolkit::WebView::Property::ENABLE_JAVASCRIPT:
+      {
+        value = impl.IsJavaScriptEnabled();
+        break;
+      }
+      case Toolkit::WebView::Property::LOAD_IMAGES_AUTOMATICALLY:
+      {
+        value = impl.AreImagesAutomaticallyLoaded();
+        break;
+      }
+      case Toolkit::WebView::Property::DEFAULT_TEXT_ENCODING_NAME:
+      {
+        value = impl.GetDefaultTextEncodingName();
+        break;
+      }
+      case Toolkit::WebView::Property::DEFAULT_FONT_SIZE:
+      {
+        value = impl.GetDefaultFontSize();
+        break;
+      }
+      default:
+         break;
+    }
+  }
+
+  return value;
+}
+
+bool WebView::OnTouchEvent( Actor actor, const Dali::TouchData& touch )
+{
+  bool result = false;
+
+  if( mWebEngine )
+  {
+    result = mWebEngine.SendTouchEvent( touch );
+  }
+  return result;
+}
+
+bool WebView::OnKeyEvent( const Dali::KeyEvent& event )
+{
+  bool result = false;
+
+  if( mWebEngine )
+  {
+    result = mWebEngine.SendKeyEvent( event );
+  }
+  return result;
+}
+
+Toolkit::WebView::CacheModel::Type WebView::GetCacheModel() const
+{
+  return mWebEngine ? static_cast< Toolkit::WebView::CacheModel::Type >( mWebEngine.GetCacheModel() ) : Toolkit::WebView::CacheModel::DOCUMENT_VIEWER;
+}
+
+void WebView::SetCacheModel( Toolkit::WebView::CacheModel::Type cacheModel )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.SetCacheModel( static_cast< WebEnginePlugin::CacheModel >( cacheModel ) );
+  }
+}
+
+Toolkit::WebView::CookieAcceptPolicy::Type WebView::GetCookieAcceptPolicy() const
+{
+  return mWebEngine ? static_cast< Toolkit::WebView::CookieAcceptPolicy::Type >( mWebEngine.GetCookieAcceptPolicy() ) : Toolkit::WebView::CookieAcceptPolicy::NO_THIRD_PARTY;
+}
+
+void WebView::SetCookieAcceptPolicy( Toolkit::WebView::CookieAcceptPolicy::Type policy )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.SetCookieAcceptPolicy( static_cast< WebEnginePlugin::CookieAcceptPolicy >( policy ) );
+  }
+}
+
+const std::string& WebView::GetUserAgent() const
+{
+  return mWebEngine ? mWebEngine.GetUserAgent() : kEmptyString;
+}
+
+void WebView::SetUserAgent( const std::string& userAgent )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.SetUserAgent( userAgent );
+  }
+}
+
+bool WebView::IsJavaScriptEnabled() const
+{
+  return mWebEngine ? mWebEngine.IsJavaScriptEnabled() : true;
+}
+
+void WebView::EnableJavaScript( bool enabled )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.EnableJavaScript( enabled );
+  }
+}
+
+bool WebView::AreImagesAutomaticallyLoaded() const
+{
+  return mWebEngine ? mWebEngine.AreImagesAutomaticallyLoaded() : true;
+}
+
+void WebView::LoadImagesAutomatically( bool automatic )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.LoadImagesAutomatically( automatic );
+  }
+}
+
+const std::string& WebView::GetDefaultTextEncodingName() const
+{
+  return mWebEngine ? mWebEngine.GetDefaultTextEncodingName() : kEmptyString;
+}
+
+void WebView::SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.SetDefaultTextEncodingName( defaultTextEncodingName );
+  }
+}
+
+int WebView::GetDefaultFontSize() const
+{
+  return mWebEngine ? mWebEngine.GetDefaultFontSize() : 0;
+}
+
+void WebView::SetDefaultFontSize( int defaultFontSize )
+{
+  if( mWebEngine )
+  {
+    mWebEngine.SetDefaultFontSize( defaultFontSize );
+  }
+}
+
+#undef GET_ENUM_STRING
+#undef GET_ENUM_VALUE
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/web-view/web-view-impl.h b/dali-toolkit/internal/controls/web-view/web-view-impl.h
new file mode 100644 (file)
index 0000000..bce288d
--- /dev/null
@@ -0,0 +1,368 @@
+#ifndef DALI_TOOLKIT_INTERNAL_WEB_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_WEB_VIEW_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/web-engine.h>
+#include <dali/public-api/images/image-operations.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/web-view/web-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class KeyEvent;
+class TouchData;
+class WebView;
+
+namespace Internal
+{
+
+class WebView : public Control
+{
+protected:
+
+  WebView();
+
+  WebView( const std::string& locale, const std::string& timezoneId );
+
+  virtual ~WebView();
+
+public:
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::New()
+   */
+  static Toolkit::WebView New();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::New( const std::string&, const std::string& )
+   */
+  static Toolkit::WebView New( const std::string& locale, const std::string& timezoneId );
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::LoadUrl()
+   */
+  void LoadUrl( const std::string& url );
+
+  /**
+   * @copydoc Dali::WebEngine::LoadHTMLString()
+   */
+  void LoadHTMLString( const std::string& htmlString );
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::Reload()
+   */
+  void Reload();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::StopLoading()
+   */
+  void StopLoading();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::StopLoading()
+   */
+  void Suspend();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::Resume()
+   */
+  void Resume();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::CanGoForward()
+   */
+  bool CanGoForward();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::GoForward()
+   */
+  void GoForward();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::CanGoBack()
+   */
+  bool CanGoBack();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::GoBack()
+   */
+  void GoBack();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::EvaluateJavaScript()
+   */
+  void EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler );
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::AddJavaScriptMessageHandler()
+   */
+  void AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler );
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::ClearHistory()
+   */
+  void ClearHistory();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::ClearCache()
+   */
+  void ClearCache();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::ClearCookies()
+   */
+  void ClearCookies();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::PageLoadStartedSignal()
+   */
+  Dali::Toolkit::WebView::WebViewPageLoadSignalType& PageLoadStartedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::PageLoadFinishedSignal()
+   */
+  Dali::Toolkit::WebView::WebViewPageLoadSignalType& PageLoadFinishedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::WebView::PageLoadErrorSignal()
+   */
+  Dali::Toolkit::WebView::WebViewPageLoadErrorSignalType& PageLoadErrorSignal();
+
+public: // Properties
+
+  /**
+   * @brief Called when a property of an object of this type is set.
+   *
+   * @param[in] object The object whose property is set.
+   * @param[in] index The property index.
+   * @param[in] value The new property value.
+   */
+  static void SetProperty( Dali::BaseObject* object, Dali::Property::Index index, const Dali::Property::Value& value );
+
+  /**
+   * @brief Called to retrieve a property of an object of this type.
+   *
+   * @param[in] object The object whose property is to be retrieved.
+   * @param[in] index The property index.
+   * @return The current value of the property.
+   */
+  static Dali::Property::Value GetProperty( Dali::BaseObject* object, Dali::Property::Index propertyIndex );
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the c
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private: // From Control
+
+  /**
+   * @copydoc Toolkit::Control::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Control::GetNaturalSize
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Toolkit::Control::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * Signal occurs when the Web View has been touched.
+   * @param[in] actor The Actor Touched
+   * @param[in] touch The Touch Data.
+   * @return Whether to consume event or not.
+   */
+  bool OnTouchEvent( Actor actor, const Dali::TouchData& touch );
+
+  /**
+   * @copydoc Toolkit::Control::OnKeyEvent()
+   */
+  virtual bool OnKeyEvent( const Dali::KeyEvent& event );
+
+private:
+
+  // Undefined
+  WebView( const WebView& webView );
+
+  WebView& operator=( const WebView& webView );
+
+  /**
+   * @brief Get cache model option. The default isToolkit::WebView::CacheModel::DOCUMENT_VIEWER.
+   * @see Toolkit::WebView::CacheModel::Type
+   */
+  Toolkit::WebView::CacheModel::Type GetCacheModel() const;
+
+  /**
+   * @brief Set cache model option. The default isToolkit::WebView::CacheModel::DOCUMENT_VIEWER.
+   * @param[in] cacheModel The cache model option
+   * @see Toolkit::WebView::CacheModel::Type
+   */
+  void SetCacheModel( Toolkit::WebView::CacheModel::Type cacheModel );
+
+  /**
+   * @brief Gets the cookie acceptance policy. The default is Toolkit::WebView::CookieAcceptPolicy::NO_THIRD_PARTY.
+   * @see Toolkit::WebView::CookieAcceptPolicy::Type
+   */
+  Toolkit::WebView::CookieAcceptPolicy::Type GetCookieAcceptPolicy() const;
+
+  /**
+   * @brief Sets the cookie acceptance policy. The default is Toolkit::WebView::CookieAcceptPolicy::NO_THIRD_PARTY.
+   * @param[in] policy The cookie acceptance policy
+   * @see Toolkit::WebView::CookieAcceptPolicy::Type
+   */
+  void SetCookieAcceptPolicy( Toolkit::WebView::CookieAcceptPolicy::Type policy );
+
+  /**
+   * @brief Get user agent string.
+   * @return The string value of user agent
+   */
+  const std::string& GetUserAgent() const;
+
+  /**
+   * @brief Set user agent string.
+   * @param[in] userAgent The string value of user agent
+   */
+  void SetUserAgent( const std::string& userAgent );
+
+  /**
+   * @brief Returns whether JavaScript can be executable. The default is true.
+   *
+   * @return true if JavaScript executing is enabled, false otherwise
+   */
+  bool IsJavaScriptEnabled() const;
+
+  /**
+   * @brief Enables/disables JavaScript executing. The default is enabled.
+   *
+   * @param[in] enabled True if JavaScript executing is enabled, false otherwise
+   */
+  void EnableJavaScript( bool enabled );
+
+  /**
+   * @brief Returns whether images can be loaded automatically. The default is true.
+   *
+   * @return true if images are loaded automatically, false otherwise
+   */
+  bool AreImagesAutomaticallyLoaded() const;
+
+  /**
+   * @brief Enables/disables auto loading of images. The default is enabled.
+   *
+   * @param[in] automatic True if images are loaded automatically, false otherwise
+   */
+  void LoadImagesAutomatically( bool automatic );
+
+  /**
+   * @brief Gets the default text encoding name (e.g. UTF-8).
+   *
+   * @return The default text encoding name
+   */
+  const std::string& GetDefaultTextEncodingName() const;
+
+  /**
+   * @brief Sets the default text encoding name (e.g. UTF-8).
+   *
+   * @param[in] defaultTextEncodingName The default text encoding name
+   */
+  void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName );
+
+  /**
+   * @brief Returns the default font size in pixel. The default value is 16.
+   *
+   * @return The default font size
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @brief Sets the default font size in pixel. The default value is 16.
+   *
+   * @param[in] defaultFontSize A new default font size to set
+   */
+  void SetDefaultFontSize( int defaultFontSize );
+
+  /**
+   * @brief Callback function to be called when page load started.
+   * @param[in] url The url currently being loaded
+   */
+  void OnPageLoadStarted( const std::string& url );
+
+  /**
+   * @brief Callback function to be called when page load finished.
+   * @param[in] url The url currently being loaded
+   */
+  void OnPageLoadFinished( const std::string& url );
+
+  /**
+   * @brief Callback function to be called when there is an error in page loading.
+   * @param[in] url The url currently being loaded
+   * @param[in] errorCode The error code
+   */
+  void OnPageLoadError( const std::string& url, int errorCode );
+
+private:
+
+  std::string                                            mUrl;
+  Dali::Toolkit::Visual::Base                            mVisual;
+  Dali::Size                                             mWebViewSize;
+  Dali::WebEngine                                        mWebEngine;
+
+  Dali::Toolkit::WebView::WebViewPageLoadSignalType      mPageLoadStartedSignal;
+  Dali::Toolkit::WebView::WebViewPageLoadSignalType      mPageLoadFinishedSignal;
+  Dali::Toolkit::WebView::WebViewPageLoadErrorSignalType mPageLoadErrorSignal;
+};
+
+} // namespace Internal
+
+inline Toolkit::Internal::WebView& GetImpl( Toolkit::WebView& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast< Toolkit::Internal::WebView& >( impl );
+}
+
+inline const Toolkit::Internal::WebView& GetImpl( const Toolkit::WebView& handle )
+{
+  DALI_ASSERT_ALWAYS( handle );
+  const Dali::RefObject& impl = handle.GetImplementation();
+  return static_cast< const Toolkit::Internal::WebView& >( impl );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_WEB_VIEW_H
diff --git a/dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.cpp b/dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.cpp
new file mode 100755 (executable)
index 0000000..dcb52fa
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h>
+
+#include <dali/public-api/events/point-state.h>
+#include <dali/public-api/events/touch-data.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+Dali::Toolkit::DragAndDropDetector DragAndDropDetector::New()
+{
+  Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector(new DragAndDropDetector());
+
+  return detector;
+}
+
+void DragAndDropDetector::Attach(Dali::Toolkit::Control& control)
+{
+  if(control)
+  {
+    if(!mControls.empty())
+    {
+      auto match = std::find(mControls.begin(), mControls.end(), control);
+      if(match != mControls.end())
+      {
+        return;
+      }
+    }
+    mControls.push_back(control);
+    control.TouchSignal().Connect(this, &DragAndDropDetector::OnDrag);
+    mFirstEnter.push_back(control.GetId());
+    mPanGestureDetector.Attach(control);
+    mPanGestureDetector.DetectedSignal().Connect(this, &DragAndDropDetector::OnPan);
+  }
+
+}
+
+void DragAndDropDetector::Detach(Dali::Toolkit::Control& control)
+{
+  if(!mControls.empty())
+  {
+    if(!control)
+    {
+      return;
+    }
+
+    auto match = std::find(mControls.begin(), mControls.end(), control);
+
+    if(match != mControls.end())
+    {
+      match->TouchSignal().Disconnect(this, &DragAndDropDetector::OnDrag);
+      mPanGestureDetector.Detach(*match);
+      mFirstEnter.erase(std::find(mFirstEnter.begin(), mFirstEnter.end(), control.GetId()));
+      mControls.erase(match);
+    }
+  }
+}
+
+void DragAndDropDetector::DetachAll()
+{
+  if(!mControls.empty())
+  {
+    auto iter = mControls.begin();
+    for(;iter != mControls.end();)
+    {
+      iter->TouchSignal().Disconnect(this, &DragAndDropDetector::OnDrag);
+      mPanGestureDetector.Detach(*iter);
+      iter = mControls.erase(iter);
+    }
+  }
+
+  if(!mFirstEnter.empty())
+  {
+    auto iter = mFirstEnter.begin();
+    for(;iter != mFirstEnter.end();)
+    {
+      iter = mFirstEnter.erase(iter);
+    }
+  }
+}
+
+uint32_t DragAndDropDetector::GetAttachedControlCount() const
+{
+  return mControls.size();
+}
+
+Dali::Toolkit::Control DragAndDropDetector::GetAttachedControl(uint32_t index) const
+{
+  Dali::Toolkit::Control control;
+
+  if(index < mControls.size())
+  {
+    control = mControls[index];
+  }
+
+  return control;
+}
+
+void DragAndDropDetector::OnPan(Dali::Actor actor, const PanGesture& gesture)
+{
+  Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+
+  if(gesture.state == Gesture::Started)
+  {
+    mDragLocalPosition = gesture.position;
+    mPointDown = true;
+    mDragControl = control;
+    mFirstEnter.clear();
+    for( auto&& control : mControls)
+    {
+      mFirstEnter.push_back(control.GetId());
+    }
+    float width = control.GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH);
+    float height = control.GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT);
+    Vector3 actorPos = control.GetProperty<Vector3>(Dali::Actor::Property::POSITION);
+
+    mShadowControl = Dali::Toolkit::Control::New();
+    mShadowControl.SetPosition(actorPos);
+    mShadowControl.SetSize(width, height);
+    mShadowControl.SetBackgroundColor(Vector4(0.3f, 0.3f, 0.3f, 0.7f));
+    mShadowControl.SetParentOrigin(control.GetCurrentParentOrigin());
+    mShadowControl.SetAnchorPoint(control.GetCurrentAnchorPoint());
+    control.GetParent().Add(mShadowControl);
+    SetPosition(gesture.screenPosition);
+    EmitStartedSignal(control);
+  }
+  if(gesture.state == Gesture::Continuing)
+  {
+      Vector2 screenPosition = gesture.screenPosition;
+      control.GetParent().ScreenToLocal(mLocalPosition.x, mLocalPosition.y, screenPosition.x, screenPosition.y);
+      mShadowControl.SetPosition(mLocalPosition.x - mDragLocalPosition.x, mLocalPosition.y - mDragLocalPosition.y);
+  }
+  if(gesture.state == Gesture::Finished)
+  {
+    mDragControl.GetParent().Remove(mShadowControl);
+    EmitEndedSignal(control);
+  }
+}
+
+bool DragAndDropDetector::OnDrag(Dali::Actor actor, const Dali::TouchData& data)
+{
+  Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
+  PointState::Type type = data.GetState(0);
+
+  if(type == PointState::MOTION)
+  {
+    if(mDragControl != control && mPointDown)
+    {
+      auto found = std::find(mFirstEnter.begin(), mFirstEnter.end(), control.GetId());
+      if(mFirstEnter.end() != found)
+      {
+        SetPosition(data.GetScreenPosition(0));
+        mFirstEnter.erase(found);
+        EmitEnteredSignal(control);
+      }
+      else
+      {
+        SetPosition(data.GetScreenPosition(0));
+        EmitMovedSignal(control);
+      }
+    }
+  }
+
+  if(type == PointState::LEAVE)
+  {
+    if(mDragControl != control && mPointDown)
+    {
+      mFirstEnter.push_back(control.GetId());
+      EmitExitedSignal(control);
+    }
+  }
+
+  if(type == PointState::UP)
+  {
+    if(mDragControl != control && mPointDown)
+    {
+      SetPosition(data.GetScreenPosition(0));
+      ClearContent();
+      SetContent(mDragControl.GetName());
+      EmitDroppedSignal(control);
+    }
+
+    if(mShadowControl)
+    {
+    control.GetParent().Remove(mShadowControl);
+    }
+    mPointDown = false;
+  }
+  return true;
+}
+
+const std::string& DragAndDropDetector::GetContent() const
+{
+  return mContent;
+}
+
+const Vector2& DragAndDropDetector::GetCurrentScreenPosition() const
+{
+  return mScreenPosition;
+}
+
+void DragAndDropDetector::SetContent( const std::string& content )
+{
+  mContent = content;
+}
+
+void DragAndDropDetector::ClearContent()
+{
+  mContent.clear();
+}
+
+void DragAndDropDetector::SetPosition( const Vector2& screenPosition )
+{
+  mScreenPosition = screenPosition;
+}
+
+void DragAndDropDetector::EmitStartedSignal(Dali::Toolkit::Control& control)
+{
+  if( !mStartedSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mStartedSignal.Emit( control, handle );
+  }
+}
+void DragAndDropDetector::EmitEnteredSignal(Dali::Toolkit::Control& control)
+{
+  if ( !mEnteredSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mEnteredSignal.Emit( control, handle );
+  }
+}
+
+void DragAndDropDetector::EmitExitedSignal(Dali::Toolkit::Control& control)
+{
+  if ( !mExitedSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mExitedSignal.Emit( control, handle );
+  }
+}
+
+void DragAndDropDetector::EmitMovedSignal(Dali::Toolkit::Control& control)
+{
+  if ( !mMovedSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mMovedSignal.Emit( control, handle );
+  }
+}
+
+void DragAndDropDetector::EmitDroppedSignal(Dali::Toolkit::Control& control)
+{
+  if ( !mDroppedSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mDroppedSignal.Emit( control, handle );
+  }
+}
+
+void DragAndDropDetector::EmitEndedSignal(Dali::Toolkit::Control& control)
+{
+  if( !mEndedSignal.Empty() )
+  {
+    Dali::Toolkit::DragAndDropDetector handle( this );
+    mEndedSignal.Emit( control, handle );
+  }
+}
+
+DragAndDropDetector::DragAndDropDetector()
+: mContent(),
+  mScreenPosition()
+{
+  mPanGestureDetector = Dali::PanGestureDetector::New();
+  mPointDown = false;
+}
+
+DragAndDropDetector::~DragAndDropDetector()
+{
+}
+
+} // namespace Internal
+
+} //namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h b/dali-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h
new file mode 100755 (executable)
index 0000000..b83ea13
--- /dev/null
@@ -0,0 +1,269 @@
+#ifndef DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H
+#define DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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 <vector>
+#include <algorithm>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/drag-drop-detector/drag-and-drop-detector.h>
+#include <dali/public-api/events/pan-gesture-detector.h>
+#include <dali/public-api/events/pan-gesture.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+using DragAndDropDetectorPtr = IntrusivePtr< DragAndDropDetector >;
+
+/**
+ * This class listens to Drag & Drop events.
+ */
+class DragAndDropDetector : public Dali::BaseObject, public ConnectionTracker
+{
+public:
+
+  using DragAndDropSignal = Dali::Toolkit::DragAndDropDetector::DragAndDropSignal;
+
+  // Creation
+
+  /**
+   * @copydoc Toolkit::DragAndDropDetector::New()
+   */
+  static Dali::Toolkit::DragAndDropDetector New();
+
+  // Public API
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::GetContent() const
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::GetCurrentScreenPosition() const
+   */
+  const Vector2& GetCurrentScreenPosition() const;
+
+  /**
+   * Attaches control to DragAndDropDetector.
+   * @param[in] control  control that will be attached to DragAndDropDetector.
+   */
+  void Attach(Dali::Toolkit::Control& control);
+
+  /**
+   * Detaches control to DragAndDropDetector.
+   * @param[in] control  control that will be Detached from DragAndDropDetector.
+   */
+  void Detach(Dali::Toolkit::Control& control);
+
+  /**
+   * Detaches all control attached to DragAndDropDetector.
+   */
+  void DetachAll();
+
+  /**
+   * Returns the number of controls attached to the DragAndDropDetector.
+   */
+  uint32_t GetAttachedControlCount() const;
+
+  /**
+   * Returns a control by index. An empty handle if the index is not valid.
+   */
+  Dali::Toolkit::Control GetAttachedControl(uint32_t index) const;
+
+  /**
+   * Sets the dragged content.
+   * @param[in] content  A string that represents the content that has been dropped.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * Sets the position the drop occurred.
+   */
+  void SetPosition( const Vector2& screenPosition );
+
+  /**
+   * Called when a draggable object start drag.
+   */
+  void EmitStartedSignal(Dali::Toolkit::Control& control);
+
+  /**
+   * Called when a draggable object enters other object.
+   */
+  void EmitEnteredSignal(Dali::Toolkit::Control& control);
+
+  /**
+   * Called when a draggable object leaves other object.
+   */
+  void EmitExitedSignal(Dali::Toolkit::Control& control);
+
+  /**
+   * Called when a draggable object leaves other object.
+   */
+  void EmitMovedSignal(Dali::Toolkit::Control& control);
+
+  /**
+   * Is called when a drop actually occurs.
+   */
+  void EmitDroppedSignal(Dali::Toolkit::Control& control);
+
+  /**
+   * Called when a draggable object drag ended.
+   */
+  void EmitEndedSignal(Dali::Toolkit::Control& control);
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::StartedSignal
+   */
+  DragAndDropSignal& StartedSignal()
+  {
+    return mStartedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::EnteredSignal
+   */
+  DragAndDropSignal& EnteredSignal()
+  {
+    return mEnteredSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::ExitedSignal
+   */
+  DragAndDropSignal& ExitedSignal()
+  {
+    return mExitedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::MovedSignal
+   */
+  DragAndDropSignal& MovedSignal()
+  {
+    return mMovedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::DroppedSignal
+   */
+  DragAndDropSignal& DroppedSignal()
+  {
+    return mDroppedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Toolkit::DragAndDropDetector::DroppedSignal
+   */
+  DragAndDropSignal& EndedSignal()
+  {
+    return mEndedSignal;
+  }
+
+public:
+  bool OnDrag(Dali::Actor actor, const Dali::TouchData& data);
+  void OnPan(Dali::Actor actor, const PanGesture& gesture);
+
+private:
+
+  // Construction & Destruction
+
+  /**
+   * Constructor.
+   */
+  DragAndDropDetector();
+
+  /**
+   * Destructor.
+   */
+  virtual ~DragAndDropDetector();
+
+  // Undefined
+  DragAndDropDetector( const DragAndDropDetector& ) = delete;
+  DragAndDropDetector& operator=( DragAndDropDetector& );
+
+private:
+
+  std::string mContent;    ///< The current Drag & drop content.
+
+  DragAndDropSignal mStartedSignal;
+  DragAndDropSignal mEnteredSignal;
+  DragAndDropSignal mExitedSignal;
+  DragAndDropSignal mMovedSignal;
+  DragAndDropSignal mDroppedSignal;
+  DragAndDropSignal mEndedSignal;
+
+  std::vector<Dali::Toolkit::Control> mControls;      //controls attached by Attach interface for drag&drop
+  Dali::Toolkit::Control mDragControl;                //the current drag control
+  Dali::Toolkit::Control mShadowControl;              //a shadow control for indicating where the control is, same size as the dragged control
+  std::vector<uint32_t> mFirstEnter;                  //control id indicating if the cursor is enter
+  Dali::PanGestureDetector mPanGestureDetector;       //pangesture for calculating the shadow actor position
+
+  Vector2 mLocalPosition;
+  Vector2 mDragLocalPosition;
+  Vector2 mScreenPosition; ///< The screen position of the drop location.
+
+  bool mPointDown; //bool flag to indicate if PointState::DOWN have been processed
+};
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Internal::DragAndDropDetector& GetImplementation(Dali::Toolkit::DragAndDropDetector& detector)
+{
+  DALI_ASSERT_ALWAYS( detector && "DragAndDropDetector handle is empty" );
+
+  BaseObject& handle = detector.GetBaseObject();
+
+  return static_cast<Internal::DragAndDropDetector&>(handle);
+}
+
+inline const Internal::DragAndDropDetector& GetImplementation(const Dali::Toolkit::DragAndDropDetector& detector)
+{
+  DALI_ASSERT_ALWAYS( detector && "DragAndDropDetector handle is empty" );
+
+  const BaseObject& handle = detector.GetBaseObject();
+
+  return static_cast<const Internal::DragAndDropDetector&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H
diff --git a/dali-toolkit/internal/feedback/feedback-ids.h b/dali-toolkit/internal/feedback/feedback-ids.h
new file mode 100644 (file)
index 0000000..7dd256e
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef DALI_FEEDBACK_IDS_H
+#define DALI_FEEDBACK_IDS_H
+
+/*
+ * Copyright (c) 2019 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
+{
+
+/**
+ *  Enumerations for the types of feedback
+ *  Note: These are based on feedback_type_e in libsvi
+ */
+enum FeedbackType
+{
+  FEEDBACK_TYPE_NONE,
+
+  FEEDBACK_TYPE_SOUND,
+  FEEDBACK_TYPE_VIBRATION,
+  FEEDBACK_TYPE_LED,
+
+  FEEDBACK_TYPE_END
+};
+
+/**
+ *  The pattern list for feedback effects.
+ *  Note: These are based on feedback_pattern_e in libsvi
+ */
+enum FeedbackPattern
+{
+  FEEDBACK_PATTERN_NONE = -1,
+
+  FEEDBACK_PATTERN_TAP = 0,           /**< feedback pattern when general touch */
+  FEEDBACK_PATTERN_SIP,               /**< feedback pattern when touch text key */
+  FEEDBACK_PATTERN_SIP_BACKSPACE,     /**< feedback pattern when touch backspace key */
+  FEEDBACK_PATTERN_MAX_CHARACTER,     /**< feedback pattern when max character */
+  FEEDBACK_PATTERN_KEY0,              /**< feedback pattern when touch numeric 0 key */
+  FEEDBACK_PATTERN_KEY1,              /**< feedback pattern when touch numeric 1 key */
+  FEEDBACK_PATTERN_KEY2,              /**< feedback pattern when touch numeric 2 key */
+  FEEDBACK_PATTERN_KEY3,              /**< feedback pattern when touch numeric 3 key */
+  FEEDBACK_PATTERN_KEY4,              /**< feedback pattern when touch numeric 4 key */
+  FEEDBACK_PATTERN_KEY5,              /**< feedback pattern when touch numeric 5 key */
+  FEEDBACK_PATTERN_KEY6,              /**< feedback pattern when touch numeric 6 key */
+  FEEDBACK_PATTERN_KEY7,              /**< feedback pattern when touch numeric 7 key */
+  FEEDBACK_PATTERN_KEY8,              /**< feedback pattern when touch numeric 8 key */
+  FEEDBACK_PATTERN_KEY9,              /**< feedback pattern when touch numeric 9 key */
+  FEEDBACK_PATTERN_KEY_STAR,          /**< feedback pattern when touch star key */
+  FEEDBACK_PATTERN_KEY_SHARP,         /**< feedback pattern when touch sharp key */
+  FEEDBACK_PATTERN_HOLD,              /**< feedback pattern when touch hold */
+  FEEDBACK_PATTERN_MULTI_TAP,         /**< feedback pattern when multi touch */
+  FEEDBACK_PATTERN_HW_TAP,            /**< feedback pattern when press hardware key */
+  FEEDBACK_PATTERN_HW_HOLD,           /**< feedback pattern when holding press hardware key */
+
+  FEEDBACK_PATTERN_MESSAGE,           /**< feedback pattern when incoming a message */
+  FEEDBACK_PATTERN_MESSAGE_ON_CALL,   /**< feedback pattern when incoming a message on call */
+  FEEDBACK_PATTERN_EMAIL,             /**< feedback pattern when incoming an email */
+  FEEDBACK_PATTERN_EMAIL_ON_CALL,     /**< feedback pattern when incoming an email on call */
+  FEEDBACK_PATTERN_WAKEUP,            /**< feedback pattern when alert wake up call */
+  FEEDBACK_PATTERN_WAKEUP_ON_CALL,    /**< feedback pattern when alert wake up call on call */
+  FEEDBACK_PATTERN_SCHEDULE,          /**< feedback pattern when alert schedule alarm */
+  FEEDBACK_PATTERN_SCHEDULE_ON_CALL,    /**< feedback pattern when alert schedule alarm on call */
+  FEEDBACK_PATTERN_TIMER,             /**< feedback pattern when alert timer */
+  FEEDBACK_PATTERN_TIMER_ON_CALL,     /**< feedback pattern when alert timer on call */
+  FEEDBACK_PATTERN_GENERAL,           /**< feedback pattern when alert general event */
+  FEEDBACK_PATTERN_GENERAL_ON_CALL,   /**< feedback pattern when alert general event on call */
+
+  FEEDBACK_PATTERN_POWER_ON,           /**< feedback pattern when power on */
+  FEEDBACK_PATTERN_POWER_OFF,           /**< feedback pattern when power off */
+  FEEDBACK_PATTERN_CHARGERCONN,         /**< feedback pattern when connecting charger */
+  FEEDBACK_PATTERN_CHARGERCONN_ON_CALL, /**< feedback pattern when connecting charger on call */
+  FEEDBACK_PATTERN_FULLCHARGED,         /**< feedback pattern when full charged */
+  FEEDBACK_PATTERN_FULLCHARGED_ON_CALL, /**< feedback pattern when full charged on call */
+  FEEDBACK_PATTERN_LOWBATT,             /**< feedback pattern when low battery */
+  FEEDBACK_PATTERN_LOWBATT_ON_CALL,     /**< feedback pattern when low battery on call */
+  FEEDBACK_PATTERN_LOCK,                /**< feedback pattern when lock */
+  FEEDBACK_PATTERN_UNLOCK,              /**< feedback pattern when unlock */
+  FEEDBACK_PATTERN_CALLCONNECT,         /**< feedback pattern when connecting call */
+  FEEDBACK_PATTERN_DISCALLCONNECT,      /**< feedback pattern when disconnecting call */
+  FEEDBACK_PATTERN_MINUTEMINDER,        /**< feedback pattern when minute minder */
+  FEEDBACK_PATTERN_VIBRATION,           /**< feedback pattern when vibration */
+  FEEDBACK_PATTERN_SHUTTER,             /**< feedback pattern when screen capture or camera shutter */
+  FEEDBACK_PATTERN_LIST_REORDER,        /**< feedback pattern when list reorder */
+  FEEDBACK_PATTERN_SLIDER_SWEEP,        /**< feedback pattern when slider sweep */
+
+  FEEDBACK_PATTERN_END,
+};
+
+
+}  // namespace Dali
+
+#endif // DALI_FEEDBACK_IDS_H
diff --git a/dali-toolkit/internal/feedback/feedback-style.cpp b/dali-toolkit/internal/feedback/feedback-style.cpp
new file mode 100644 (file)
index 0000000..08d5d46
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/feedback/feedback-style.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/object-registry.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+#include <dali-toolkit/internal/feedback/feedback-ids.h>
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::General, false, "LOG_FEEDBACK");
+#endif
+
+const char* DEFAULT_FEEDBACK_THEME_FILE_NAME = "default-feedback-theme.json";
+
+// Sets bool and string if the node has a child "name"
+void GetIfString(const Dali::Toolkit::TreeNode& node, const std::string& name, bool& exists, std::string& str)
+{
+  const Dali::Toolkit::TreeNode* child = node.GetChild(name);
+  if( child &&
+      Dali::Toolkit::TreeNode::STRING == child->GetType() )
+  {
+    exists = true;
+    str = child->GetString();
+  }
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+struct SignalFeedbackInfo
+{
+  /**
+   * Default constructor.
+   */
+  SignalFeedbackInfo()
+  :mHasHapticFeedbackInfo(false),
+   mHasSoundFeedbackInfo(false)
+  {
+  }
+
+  bool mHasHapticFeedbackInfo;
+  bool mHasSoundFeedbackInfo;
+  std::string mSignalName;
+  std::string mHapticFeedbackPattern;
+  std::string mSoundFeedbackPattern;
+  std::string mHapticFeedbackFile;
+  std::string mSoundFeedbackFile;
+};
+
+typedef std::vector<SignalFeedbackInfo> SignalFeedbackInfoContainer;
+typedef SignalFeedbackInfoContainer::const_iterator SignalFeedbackInfoConstIter;
+
+struct FeedbackStyleInfo
+{
+  /**
+   * Default constructor.
+   */
+  FeedbackStyleInfo()
+  {
+  }
+
+  std::string mTypeName;
+
+  SignalFeedbackInfoContainer mSignalFeedbackInfoList;
+};
+
+static const FeedbackStyleInfo DEFAULT_FEEDBACK_STYLE_INFO;
+
+FeedbackStyle::FeedbackStyle()
+{
+  mFeedback = Dali::FeedbackPlayer::Get();
+
+  const std::string styleDirPath = AssetManager::GetDaliStylePath();
+  const std::string defaultThemeFilePath = styleDirPath + DEFAULT_FEEDBACK_THEME_FILE_NAME;
+
+  std::string defaultTheme;
+
+  if( mFeedback && mFeedback.LoadFile( defaultThemeFilePath, defaultTheme ) )
+  {
+    LoadTheme( defaultTheme );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceLoader::LoadTheme(%s) - loaded %d bytes\n",
+                   defaultThemeFilePath.c_str(), defaultTheme.size() );
+  }
+  else
+  {
+    DALI_LOG_ERROR("ResourceLoader::LoadTheme(%s) - failed to load\n", defaultThemeFilePath.c_str());
+  }
+
+}
+
+FeedbackStyle::~FeedbackStyle()
+{
+}
+
+struct PlayFeedbackFromSignal
+{
+  PlayFeedbackFromSignal( FeedbackStyle& controller, const std::string& typeName, const std::string& signalName )
+  : mController( controller ),
+    mTypeName( typeName ),
+    mSignalName( signalName )
+  {
+  }
+
+  void operator()()
+  {
+    mController.PlayFeedback( mTypeName, mSignalName );
+  }
+
+  FeedbackStyle& mController;
+  std::string mTypeName;
+  std::string mSignalName;
+};
+
+
+void FeedbackStyle::ObjectCreated( BaseHandle handle )
+{
+  if( handle )
+  {
+    const std::string& type = handle.GetTypeName();
+
+    const FeedbackStyleInfo styleInfo = GetStyleInfo( type );
+
+    for( SignalFeedbackInfoConstIter iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter )
+    {
+      const SignalFeedbackInfo& info = *iter;
+
+      if( info.mHasHapticFeedbackInfo || info.mHasSoundFeedbackInfo )
+      {
+        if( !info.mHapticFeedbackPattern.empty() || !info.mHapticFeedbackFile.empty() ||
+            !info.mSoundFeedbackPattern.empty()  || !info.mSoundFeedbackFile.empty() )
+        {
+          handle.ConnectSignal( this,
+                                info.mSignalName,
+                                PlayFeedbackFromSignal( *this, type, info.mSignalName ) );
+
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::Set found Haptic pattern %s for Object type: %s, Signal Type: %s\n",
+                         info.mHapticFeedbackPattern.c_str(), type.c_str(), info.mSignalName.c_str() );
+        }
+        else
+        {
+          DALI_LOG_ERROR("FeedbackStyle::Set() Warning Inconsistent data in theme file!\n");
+        }
+      }
+    }
+  }
+}
+
+const FeedbackStyleInfo& FeedbackStyle::GetStyleInfo( const std::string& type ) const
+{
+  std::map<const std::string, FeedbackStyleInfo>::const_iterator iter( mStyleInfoLut.find( type ) );
+  if( iter != mStyleInfoLut.end() )
+  {
+    return iter->second;
+  }
+  else
+  {
+    return DEFAULT_FEEDBACK_STYLE_INFO;
+  }
+}
+
+void FeedbackStyle::StyleChanged( const std::string& userDefinedThemePath, Dali::StyleChange::Type styleChange )
+{
+  if( styleChange == StyleChange::THEME_CHANGE )
+  {
+    std::string userDefinedTheme;
+
+    if( mFeedback && mFeedback.LoadFile( userDefinedThemePath, userDefinedTheme ) )
+    {
+      if( !LoadTheme( userDefinedTheme ) )
+      {
+        DALI_LOG_ERROR("FeedbackStyle::StyleChanged() User defined theme failed to load! \n");
+
+        const std::string styleDirPath = AssetManager::GetDaliStylePath();
+        const std::string defaultThemeFilePath = styleDirPath + DEFAULT_FEEDBACK_THEME_FILE_NAME;
+
+        //If there is any problem is using the user defined theme, then fall back to default theme
+        if( !LoadTheme( defaultThemeFilePath ) )
+        {
+          //If the default theme fails, Then No luck!
+          DALI_LOG_ERROR("FeedbackStyle::StyleChanged() Default theme failed to load! \n");
+        }
+      }
+      else
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceLoader::LoadTheme(%s) - loaded %d bytes\n",
+                       userDefinedThemePath.c_str(), userDefinedTheme.size() );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR("ResourceLoader::LoadTheme(%s) - failed to load\n", userDefinedThemePath.c_str());
+    }
+  }
+}
+
+bool FeedbackStyle::LoadTheme( const std::string& data )
+{
+  bool result = false;
+
+  try
+  {
+    LoadFromString( data );
+
+    result = true;
+  }
+  catch(...)
+  {
+    //Problem in user set theme, So fallback to use default theme.
+    DALI_LOG_ERROR( "FeedbackStyle::LoadTheme() Failed to load theme\n" );
+  }
+
+  return result;
+}
+
+void FeedbackStyle::LoadFromString( const std::string& data )
+{
+  Toolkit::JsonParser parser = Toolkit::JsonParser::New();
+  const Toolkit::TreeNode* root = NULL;
+
+  if( !parser.Parse( data ) )
+  {
+    DALI_LOG_WARNING( "JSON Parse Error:'%s'\n", parser.GetErrorDescription().c_str() );
+    DALI_LOG_WARNING( "JSON Parse Line :'%d (%d)'\n",
+                      parser.GetErrorLineNumber(),
+                      parser.GetErrorColumn() );
+  }
+  else
+  {
+    root = parser.GetRoot();
+  }
+
+  if(root)
+  {
+    // Clear previously loaded style
+    mStyleInfoLut.clear();
+
+    // Parse style
+    if( const TreeNode* node = root->GetChild("style") )
+    {
+      Toolkit::TreeNode::ConstIterator iter = node->CBegin();
+      Toolkit::TreeNode::ConstIterator end = node->CEnd();
+      for( ; iter != end; ++iter )
+      {
+        const char* key = (*iter).first;
+        FeedbackStyleInfo themeInfo;
+        themeInfo.mTypeName = key;
+
+        if( const TreeNode* signals = (*iter).second.GetChild("signals") )
+        {
+          TreeNode::ConstIterator signalIter = signals->CBegin();
+          TreeNode::ConstIterator signalEnd = signals->CEnd();
+          for( ; signalIter != signalEnd; ++signalIter )
+          {
+            SignalFeedbackInfo signalFeedbackInfo;
+
+            const TreeNode* type = (*signalIter).second.GetChild("type");
+            DALI_ASSERT_ALWAYS(type && TreeNode::STRING == type->GetType() && "Signal must have a type");
+            signalFeedbackInfo.mSignalName = type->GetString();
+
+            GetIfString( (*signalIter).second, "hapticFeedbackPattern",
+                         signalFeedbackInfo.mHasHapticFeedbackInfo,
+                         signalFeedbackInfo.mHapticFeedbackPattern );
+
+            GetIfString( (*signalIter).second, "hapticFeedbackFile",
+                         signalFeedbackInfo.mHasHapticFeedbackInfo,
+                         signalFeedbackInfo.mHapticFeedbackFile );
+
+            GetIfString( (*signalIter).second, "soundFeedbackPattern",
+                         signalFeedbackInfo.mHasSoundFeedbackInfo,
+                         signalFeedbackInfo.mSoundFeedbackPattern );
+
+            GetIfString( (*signalIter).second, "hapticFeedbackFile",
+                         signalFeedbackInfo.mHasSoundFeedbackInfo,
+                         signalFeedbackInfo.mSoundFeedbackFile );
+
+            if( signalFeedbackInfo.mHasHapticFeedbackInfo || signalFeedbackInfo.mHasSoundFeedbackInfo )
+            {
+              AddSignalInfo( themeInfo, std::move( signalFeedbackInfo ) );
+            }
+          }
+        }
+
+        mStyleInfoLut[key] = themeInfo;
+
+      } // for styles
+    } // if(style)
+  } // if(root)
+
+} // LoadFromString()
+
+void FeedbackStyle::AddSignalInfo( FeedbackStyleInfo& styleInfo, SignalFeedbackInfo&& signalInfo )
+{
+  bool updated = false;
+  SignalFeedbackInfoContainer::iterator iter;
+
+  // If info exists for the signal then update it, else add new
+  for( iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter )
+  {
+    if( (*iter).mSignalName == signalInfo.mSignalName )
+    {
+      (*iter).mHasHapticFeedbackInfo = signalInfo.mHasHapticFeedbackInfo;
+      (*iter).mHapticFeedbackPattern = signalInfo.mHapticFeedbackPattern;
+      (*iter).mHapticFeedbackFile    = signalInfo.mHapticFeedbackFile;
+      (*iter).mHasSoundFeedbackInfo  = signalInfo.mHasSoundFeedbackInfo;
+      (*iter).mSoundFeedbackPattern  = signalInfo.mSoundFeedbackPattern;
+      (*iter).mSoundFeedbackFile     = signalInfo.mSoundFeedbackFile;
+
+      updated = true;
+      break;
+    }
+  }
+
+  if( !updated )
+  {
+    styleInfo.mSignalFeedbackInfoList.emplace_back( std::move( signalInfo ) );
+  }
+}
+
+void FeedbackStyle::PlayFeedback(const std::string& type, const std::string& signalName)
+{
+  const FeedbackStyleInfo styleInfo = GetStyleInfo(type);
+  SignalFeedbackInfoConstIter iter;
+
+  for(iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter)
+  {
+    const SignalFeedbackInfo& info = *iter;
+
+    if(info.mSignalName == signalName)
+    {
+      if(info.mHasHapticFeedbackInfo)
+      {
+        if(!info.mHapticFeedbackPattern.empty())
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::PlayFeedback Playing Haptic effect: Object type: %s, Signal type: %s, pattern type: %s\n",
+              type.c_str(), signalName.c_str(), info.mHapticFeedbackPattern.c_str());
+
+          mFeedback.PlayFeedbackPattern( FEEDBACK_TYPE_VIBRATION, GetFeedbackPattern(info.mHapticFeedbackPattern) );
+        }
+        else if(!info.mHapticFeedbackFile.empty())
+        {
+          mFeedback.PlayFile( info.mHapticFeedbackFile );
+        }
+      }
+
+      if(info.mHasSoundFeedbackInfo)
+      {
+        if(!info.mSoundFeedbackPattern.empty())
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::PlayFeedback Playing Sound effect: Object type: %s, Signal type: %s, pattern type: %s\n",
+              type.c_str(), signalName.c_str(), info.mHapticFeedbackPattern.c_str());
+
+          mFeedback.PlayFeedbackPattern( FEEDBACK_TYPE_SOUND, GetFeedbackPattern(info.mSoundFeedbackPattern) );
+        }
+        else if(!info.mSoundFeedbackFile.empty())
+        {
+          mFeedback.PlaySound( info.mSoundFeedbackFile );
+        }
+      }
+
+      break;
+    }
+  }
+}
+
+FeedbackPattern FeedbackStyle::GetFeedbackPattern( const std::string &pattern )
+{
+  if( 0 == mFeedbackPatternLut.size() )
+  {
+    mFeedbackPatternLut["FEEDBACK_PATTERN_NONE"]                = Dali::FEEDBACK_PATTERN_NONE;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_TAP"]                 = Dali::FEEDBACK_PATTERN_TAP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SIP"]                 = Dali::FEEDBACK_PATTERN_SIP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SIP_BACKSPACE"]       = Dali::FEEDBACK_PATTERN_SIP_BACKSPACE;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_MAX_CHARACTER"]       = Dali::FEEDBACK_PATTERN_MAX_CHARACTER;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY0"]                = Dali::FEEDBACK_PATTERN_KEY0;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY1"]                = Dali::FEEDBACK_PATTERN_KEY1;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY2"]                = Dali::FEEDBACK_PATTERN_KEY2;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY3"]                = Dali::FEEDBACK_PATTERN_KEY3;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY4"]                = Dali::FEEDBACK_PATTERN_KEY4;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY5"]                = Dali::FEEDBACK_PATTERN_KEY5;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY6"]                = Dali::FEEDBACK_PATTERN_KEY6;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY7"]                = Dali::FEEDBACK_PATTERN_KEY7;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY8"]                = Dali::FEEDBACK_PATTERN_KEY8;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY9"]                = Dali::FEEDBACK_PATTERN_KEY9;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY_STAR"]            = Dali::FEEDBACK_PATTERN_KEY_STAR;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_KEY_SHARP"]           = Dali::FEEDBACK_PATTERN_KEY_SHARP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_HOLD"]                = Dali::FEEDBACK_PATTERN_HOLD;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_MULTI_TAP"]           = Dali::FEEDBACK_PATTERN_MULTI_TAP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_HW_TAP"]              = Dali::FEEDBACK_PATTERN_HW_TAP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_HW_HOLD"]             = Dali::FEEDBACK_PATTERN_HW_HOLD;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_MESSAGE"]             = Dali::FEEDBACK_PATTERN_MESSAGE;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_MESSAGE_ON_CALL"]     = Dali::FEEDBACK_PATTERN_MESSAGE_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_EMAIL"]               = Dali::FEEDBACK_PATTERN_EMAIL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_EMAIL_ON_CALL"]       = Dali::FEEDBACK_PATTERN_EMAIL_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_WAKEUP"]              = Dali::FEEDBACK_PATTERN_WAKEUP;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_WAKEUP_ON_CALL"]      = Dali::FEEDBACK_PATTERN_WAKEUP_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SCHEDULE"]            = Dali::FEEDBACK_PATTERN_SCHEDULE;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SCHEDULE_ON_CALL"]    = Dali::FEEDBACK_PATTERN_SCHEDULE_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_TIMER"]               = Dali::FEEDBACK_PATTERN_TIMER;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_TIMER_ON_CALL"]       = Dali::FEEDBACK_PATTERN_TIMER_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_GENERAL"]             = Dali::FEEDBACK_PATTERN_GENERAL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_GENERAL_ON_CALL"]     = Dali::FEEDBACK_PATTERN_GENERAL_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_POWER_ON"]            = Dali::FEEDBACK_PATTERN_POWER_ON;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_POWER_OFF"]           = Dali::FEEDBACK_PATTERN_POWER_OFF;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_CHARGERCONN"]         = Dali::FEEDBACK_PATTERN_CHARGERCONN;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_CHARGERCONN_ON_CALL"] = Dali::FEEDBACK_PATTERN_CHARGERCONN_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_FULLCHARGED"]         = Dali::FEEDBACK_PATTERN_FULLCHARGED;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_FULLCHARGED_ON_CALL"] = Dali::FEEDBACK_PATTERN_FULLCHARGED_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_LOWBATT"]             = Dali::FEEDBACK_PATTERN_LOWBATT;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_LOWBATT_ON_CALL"]     = Dali::FEEDBACK_PATTERN_LOWBATT_ON_CALL;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_LOCK"]                = Dali::FEEDBACK_PATTERN_LOCK;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_UNLOCK"]              = Dali::FEEDBACK_PATTERN_UNLOCK;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_CALLCONNECT"]         = Dali::FEEDBACK_PATTERN_CALLCONNECT;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_DISCALLCONNECT"]      = Dali::FEEDBACK_PATTERN_DISCALLCONNECT;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_MINUTEMINDER"]        = Dali::FEEDBACK_PATTERN_MINUTEMINDER;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_VIBRATION"]           = Dali::FEEDBACK_PATTERN_VIBRATION;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SHUTTER"]             = Dali::FEEDBACK_PATTERN_SHUTTER;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_LIST_REORDER"]        = Dali::FEEDBACK_PATTERN_LIST_REORDER;
+    mFeedbackPatternLut["FEEDBACK_PATTERN_SLIDER_SWEEP"]        = Dali::FEEDBACK_PATTERN_SLIDER_SWEEP;
+  }
+
+  std::map<const std::string, FeedbackPattern>::const_iterator iter( mFeedbackPatternLut.find( pattern ) );
+
+  if( iter != mFeedbackPatternLut.end() )
+  {
+    return iter->second;
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Unknown feedback pattern type: %s, So Defaulting to FEEDBACK_PATTERN_NONE!\n" );
+    return Dali::FEEDBACK_PATTERN_NONE;
+  }
+}
+
+} // namespace Toolkit
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/feedback/feedback-style.h b/dali-toolkit/internal/feedback/feedback-style.h
new file mode 100644 (file)
index 0000000..2167ace
--- /dev/null
@@ -0,0 +1,160 @@
+#ifndef DALI_INTERNAL_FEEDBACK_STYLE_H
+#define DALI_INTERNAL_FEEDBACK_STYLE_H
+
+/*
+ * Copyright (c) 2019 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 <map>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/devel-api/adaptor-framework/feedback-player.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/public-api/adaptor-framework/style-change.h>
+#include <dali/public-api/signals/slot-delegate.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/feedback/feedback-ids.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+struct FeedbackStyleInfo;
+struct SignalFeedbackInfo;
+
+/**
+ * Plays feedback effects for Dali-Toolkit UI Controls.
+ *
+ * This functionality relies on an adaptor plugin.
+ * (And will have no effect if this is not loaded)
+ *
+ */
+class FeedbackStyle : public ConnectionTracker
+{
+public:
+
+  /**
+   * Constructor.
+   */
+  FeedbackStyle();
+
+  /**
+   * The destructor
+   */
+  ~FeedbackStyle();
+
+  /**
+   * Called to start playing feedback effects.
+   */
+  void Start();
+
+  /**
+   * Called to stop playing feedback effects.
+   */
+  void Stop();
+
+  /**
+   * Callback function to play a feedback effect when a signal is emitted for an object
+   * Plays feedback effect.
+   * @param [in] type The Object type
+   * @param [in] signalName The name of the signal
+   */
+  void PlayFeedback(const std::string& type, const std::string& signalName);
+
+  /**
+   * Connects feedback to signals for the newly created object
+   * @param [in] object Handle to the newly created object
+   */
+  void ObjectCreated( BaseHandle object );
+
+  /**
+   * Style changed so reload the theme file
+   * @param [in] userDefinedThemePath Theme filename path
+   * @param [in] styleChange The type of style change
+   */
+  void StyleChanged(const std::string& userDefinedThemePath, StyleChange::Type styleChange);
+
+private:
+
+  /**
+   * Helper to retrieve styleInfo from mStyleInfoLut
+   * @param type A string described a type of object
+   * @return The style information for the given object
+   */
+  const FeedbackStyleInfo& GetStyleInfo( const std::string& type) const;
+
+  /**
+   * Callback function for Dali::Toolkit::PushButton::SignalPressed signal
+   * Plays feedback effect.
+   * @param [in] effect The feedback effect to play
+   */
+  bool LoadTheme(const std::string& data);
+
+  /**
+   * Loads a string representation the theme.
+   * @param [in] data A string represenation of the theme.
+   * @param [in] format The string representation format ie JSON.
+   */
+  void LoadFromString( const std::string& data );
+
+  /**
+   * Helper to store signal information.
+   * @param [in] styleInfo The information will be stored here.
+   * @param [in] signalInfo The information to add.
+   */
+  void AddSignalInfo( FeedbackStyleInfo& styleInfo, SignalFeedbackInfo&& signalInfo );
+
+  /**
+   * Map a pattern string to feedback pattern ID.
+   * @param [in] pattern The pattern string.
+   * @return A feedback pattern ID.
+   */
+  FeedbackPattern GetFeedbackPattern( const std::string& pattern );
+
+  /**
+   * Plays a feedback effect
+   * @param [in] type The feedback type haptic or sound
+   * @param [in] effect The feedback effect to play
+   */
+  void PlayEffect(FeedbackType type, FeedbackPattern effect);
+
+  /**
+   * Plays a haptic or sound effect file
+   * @param [in] type The feedback type haptic or sound
+   * @param [in] file The path to the file containing the effect
+   */
+  void PlayFile(FeedbackType type, const std::string& file);
+
+private:
+  Dali::FeedbackPlayer mFeedback;
+
+  std::map<const std::string, FeedbackPattern>   mFeedbackPatternLut; ///< Used to convert feedback pattern strings into enumerated values
+  std::map<const std::string, FeedbackStyleInfo> mStyleInfoLut;       ///< Converts key strings into style information
+};
+
+} // namespace Toolkit
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FEEDBACK_STYLE_H
diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list
new file mode 100644 (file)
index 0000000..8f3b2f2
--- /dev/null
@@ -0,0 +1,177 @@
+# Set the source directory
+SET( toolkit_src_dir ${ROOT_SRC_DIR}/dali-toolkit/internal )
+
+# Add local source files here
+SET( toolkit_src_files
+   ${toolkit_src_dir}/builder/builder-animations.cpp
+   ${toolkit_src_dir}/builder/builder-impl.cpp
+   ${toolkit_src_dir}/builder/builder-impl-debug.cpp
+   ${toolkit_src_dir}/builder/builder-set-property.cpp
+   ${toolkit_src_dir}/builder/builder-signals.cpp
+   ${toolkit_src_dir}/builder/json-parser-state.cpp
+   ${toolkit_src_dir}/builder/json-parser-impl.cpp
+   ${toolkit_src_dir}/builder/style.cpp
+   ${toolkit_src_dir}/builder/tree-node-manipulator.cpp
+   ${toolkit_src_dir}/builder/replacement.cpp
+   ${toolkit_src_dir}/visuals/animated-image/animated-image-visual.cpp
+   ${toolkit_src_dir}/visuals/animated-image/image-cache.cpp
+   ${toolkit_src_dir}/visuals/animated-image/fixed-image-cache.cpp
+   ${toolkit_src_dir}/visuals/animated-image/rolling-image-cache.cpp
+   ${toolkit_src_dir}/visuals/animated-image/rolling-gif-image-cache.cpp
+   ${toolkit_src_dir}/visuals/animated-vector-image/animated-vector-image-visual.cpp
+   ${toolkit_src_dir}/visuals/animated-vector-image/vector-animation-task.cpp
+   ${toolkit_src_dir}/visuals/animated-vector-image/vector-animation-thread.cpp
+   ${toolkit_src_dir}/visuals/animated-vector-image/vector-rasterize-thread.cpp
+   ${toolkit_src_dir}/visuals/arc/arc-visual.cpp
+   ${toolkit_src_dir}/visuals/border/border-visual.cpp
+   ${toolkit_src_dir}/visuals/color/color-visual.cpp
+   ${toolkit_src_dir}/visuals/gradient/gradient-visual.cpp
+   ${toolkit_src_dir}/visuals/gradient/gradient.cpp
+   ${toolkit_src_dir}/visuals/gradient/linear-gradient.cpp
+   ${toolkit_src_dir}/visuals/gradient/radial-gradient.cpp
+   ${toolkit_src_dir}/visuals/animated-gradient/animated-gradient-visual.cpp
+   ${toolkit_src_dir}/visuals/image-atlas-manager.cpp
+   ${toolkit_src_dir}/visuals/image/image-visual.cpp
+   ${toolkit_src_dir}/visuals/mesh/mesh-visual.cpp
+   ${toolkit_src_dir}/visuals/npatch-loader.cpp
+   ${toolkit_src_dir}/visuals/npatch/npatch-visual.cpp
+   ${toolkit_src_dir}/visuals/primitive/primitive-visual.cpp
+   ${toolkit_src_dir}/visuals/svg/svg-rasterize-thread.cpp
+   ${toolkit_src_dir}/visuals/svg/svg-visual.cpp
+   ${toolkit_src_dir}/visuals/text/text-visual.cpp
+   ${toolkit_src_dir}/visuals/transition-data-impl.cpp
+   ${toolkit_src_dir}/visuals/texture-manager-impl.cpp
+   ${toolkit_src_dir}/visuals/texture-upload-observer.cpp
+   ${toolkit_src_dir}/visuals/image-visual-shader-factory.cpp
+   ${toolkit_src_dir}/visuals/visual-base-data-impl.cpp
+   ${toolkit_src_dir}/visuals/visual-base-impl.cpp
+   ${toolkit_src_dir}/visuals/visual-factory-cache.cpp
+   ${toolkit_src_dir}/visuals/visual-factory-impl.cpp
+   ${toolkit_src_dir}/visuals/visual-string-constants.cpp
+   ${toolkit_src_dir}/visuals/visual-url.cpp
+   ${toolkit_src_dir}/visuals/wireframe/wireframe-visual.cpp
+   ${toolkit_src_dir}/controls/alignment/alignment-impl.cpp
+   ${toolkit_src_dir}/controls/bloom-view/bloom-view-impl.cpp
+   ${toolkit_src_dir}/controls/bubble-effect/bubble-emitter-impl.cpp
+   ${toolkit_src_dir}/controls/bubble-effect/bubble-renderer.cpp
+   ${toolkit_src_dir}/controls/buttons/button-impl.cpp
+   ${toolkit_src_dir}/controls/buttons/check-box-button-impl.cpp
+   ${toolkit_src_dir}/controls/buttons/push-button-impl.cpp
+   ${toolkit_src_dir}/controls/buttons/radio-button-impl.cpp
+   ${toolkit_src_dir}/controls/buttons/toggle-button-impl.cpp
+   ${toolkit_src_dir}/controls/control/control-data-impl.cpp
+   ${toolkit_src_dir}/controls/control/control-debug.cpp
+   ${toolkit_src_dir}/controls/control/control-renderers.cpp
+   ${toolkit_src_dir}/controls/effects-view/effects-view-impl.cpp
+   ${toolkit_src_dir}/controls/flex-container/flex-container-impl.cpp
+   ${toolkit_src_dir}/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp
+   ${toolkit_src_dir}/controls/image-view/image-view-impl.cpp
+   ${toolkit_src_dir}/controls/magnifier/magnifier-impl.cpp
+   ${toolkit_src_dir}/controls/navigation-view/navigation-view-impl.cpp
+   ${toolkit_src_dir}/controls/popup/confirmation-popup-impl.cpp
+   ${toolkit_src_dir}/controls/model3d-view/model3d-view-impl.cpp
+   ${toolkit_src_dir}/controls/model3d-view/obj-loader.cpp
+   ${toolkit_src_dir}/controls/popup/popup-impl.cpp
+   ${toolkit_src_dir}/controls/page-turn-view/page-turn-portrait-view-impl.cpp
+   ${toolkit_src_dir}/controls/page-turn-view/page-turn-effect.cpp
+   ${toolkit_src_dir}/controls/page-turn-view/page-turn-landscape-view-impl.cpp
+   ${toolkit_src_dir}/controls/page-turn-view/page-turn-view-impl.cpp
+   ${toolkit_src_dir}/controls/progress-bar/progress-bar-impl.cpp
+   ${toolkit_src_dir}/controls/scroll-bar/scroll-bar-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/bouncing-effect-actor.cpp
+   ${toolkit_src_dir}/controls/scrollable/item-view/depth-layout.cpp
+   ${toolkit_src_dir}/controls/scrollable/item-view/grid-layout.cpp
+   ${toolkit_src_dir}/controls/scrollable/item-view/item-view-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/item-view/spiral-layout.cpp
+   ${toolkit_src_dir}/controls/scrollable/scrollable-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-base-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
+   ${toolkit_src_dir}/controls/scene3d-view/scene3d-view-impl.cpp
+   ${toolkit_src_dir}/controls/scene3d-view/gltf-loader.cpp
+   ${toolkit_src_dir}/controls/shadow-view/shadow-view-impl.cpp
+   ${toolkit_src_dir}/controls/slider/slider-impl.cpp
+   ${toolkit_src_dir}/controls/super-blur-view/super-blur-view-impl.cpp
+   ${toolkit_src_dir}/controls/table-view/table-view-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-editor-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-field-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-label-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-selection-popup-impl.cpp
+   ${toolkit_src_dir}/controls/text-controls/text-selection-toolbar-impl.cpp
+   ${toolkit_src_dir}/controls/tool-bar/tool-bar-impl.cpp
+   ${toolkit_src_dir}/controls/tooltip/tooltip.cpp
+   ${toolkit_src_dir}/controls/video-view/video-view-impl.cpp
+   ${toolkit_src_dir}/controls/web-view/web-view-impl.cpp
+   ${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp
+
+   ${toolkit_src_dir}/feedback/feedback-style.cpp
+
+   ${toolkit_src_dir}/focus-manager/keyboard-focus-manager-impl.cpp
+   ${toolkit_src_dir}/focus-manager/keyinput-focus-manager-impl.cpp
+   ${toolkit_src_dir}/helpers/color-conversion.cpp
+   ${toolkit_src_dir}/helpers/property-helper.cpp
+   ${toolkit_src_dir}/filters/blur-two-pass-filter.cpp
+   ${toolkit_src_dir}/filters/emboss-filter.cpp
+   ${toolkit_src_dir}/filters/image-filter.cpp
+   ${toolkit_src_dir}/filters/spread-filter.cpp
+   ${toolkit_src_dir}/image-loader/async-image-loader-impl.cpp
+   ${toolkit_src_dir}/image-loader/atlas-packer.cpp
+   ${toolkit_src_dir}/image-loader/image-atlas-impl.cpp
+   ${toolkit_src_dir}/image-loader/image-load-thread.cpp
+   ${toolkit_src_dir}/styling/style-manager-impl.cpp
+   ${toolkit_src_dir}/text/bidirectional-support.cpp
+   ${toolkit_src_dir}/text/character-set-conversion.cpp
+   ${toolkit_src_dir}/text/color-segmentation.cpp
+   ${toolkit_src_dir}/text/cursor-helper-functions.cpp
+   ${toolkit_src_dir}/text/glyph-metrics-helper.cpp
+   ${toolkit_src_dir}/text/logical-model-impl.cpp
+   ${toolkit_src_dir}/text/markup-processor.cpp
+   ${toolkit_src_dir}/text/markup-processor-color.cpp
+   ${toolkit_src_dir}/text/markup-processor-embedded-item.cpp
+   ${toolkit_src_dir}/text/markup-processor-font.cpp
+   ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
+   ${toolkit_src_dir}/text/multi-language-support.cpp
+   ${toolkit_src_dir}/text/hidden-text.cpp
+   ${toolkit_src_dir}/text/property-string-parser.cpp
+   ${toolkit_src_dir}/text/segmentation.cpp
+   ${toolkit_src_dir}/text/shaper.cpp
+   ${toolkit_src_dir}/text/text-enumerations-impl.cpp
+   ${toolkit_src_dir}/text/text-controller.cpp
+   ${toolkit_src_dir}/text/text-controller-impl.cpp
+   ${toolkit_src_dir}/text/text-effects-style.cpp
+   ${toolkit_src_dir}/text/text-font-style.cpp
+   ${toolkit_src_dir}/text/text-io.cpp
+   ${toolkit_src_dir}/text/text-model.cpp
+   ${toolkit_src_dir}/text/text-scroller.cpp
+   ${toolkit_src_dir}/text/text-vertical-scroller.cpp
+   ${toolkit_src_dir}/text/text-view.cpp
+   ${toolkit_src_dir}/text/text-view-interface.cpp
+   ${toolkit_src_dir}/text/visual-model-impl.cpp
+   ${toolkit_src_dir}/text/decorator/text-decorator.cpp
+   ${toolkit_src_dir}/text/layouts/layout-engine.cpp
+   ${toolkit_src_dir}/text/multi-language-helper-functions.cpp
+   ${toolkit_src_dir}/text/multi-language-support-impl.cpp
+   ${toolkit_src_dir}/text/rendering/text-backend.cpp
+   ${toolkit_src_dir}/text/rendering/text-renderer.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/text-atlas-renderer.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/atlas-glyph-manager.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/atlas-glyph-manager-impl.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/atlas-manager.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/atlas-manager-impl.cpp
+   ${toolkit_src_dir}/text/rendering/atlas/atlas-mesh-factory.cpp
+   ${toolkit_src_dir}/text/rendering/text-backend-impl.cpp
+   ${toolkit_src_dir}/text/rendering/text-typesetter.cpp
+   ${toolkit_src_dir}/text/rendering/view-model.cpp
+   ${toolkit_src_dir}/transition-effects/cube-transition-effect-impl.cpp
+   ${toolkit_src_dir}/transition-effects/cube-transition-cross-effect-impl.cpp
+   ${toolkit_src_dir}/transition-effects/cube-transition-fold-effect-impl.cpp
+   ${toolkit_src_dir}/transition-effects/cube-transition-wave-effect-impl.cpp
+   ${toolkit_src_dir}/text/xhtml-entities.cpp
+   ${toolkit_src_dir}/drag-drop-detector/drag-and-drop-detector-impl.cpp
+)
+
+SET( SOURCES ${SOURCES}
+  ${toolkit_src_files}
+)
diff --git a/dali-toolkit/internal/filters/blur-two-pass-filter.cpp b/dali-toolkit/internal/filters/blur-two-pass-filter.cpp
new file mode 100644 (file)
index 0000000..5dabfb7
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2017 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 "blur-two-pass-filter.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const float DEFAULT_KERNEL0[] = { 12.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f };
+
+const float DEFAULT_KERNEL1[] = { 8.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.25f/16.0f,
+                                  1.25f/16.0f };
+
+const float DEFAULT_KERNEL2[] = { 5.0f/16.0f, 2.75f/16.0f, 2.75f/16.0f, 1.75f/16.0f,
+                                  1.75f/16.0f, 1.5f/16.0f, 1.5f/16.0f };
+
+const float DEFAULT_KERNEL3[] = { 3.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f,
+                                  2.0f/16.0f, 2.0f/16.0f, 2.0f/16.0f, 0.5f/16.0f,
+                                  0.5f/16.0f };
+
+const float DEFAULT_KERNEL4[] = { 2.0f/16.0f, 1.5f/16.0f, 1.5f/16.0f, 1.5f/16.0f,
+                                  1.5f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f,
+                                  1.0f/16.0f, 1.0f/16.0f, 1.0f/16.0f, 0.5f/16.0f,
+                                  0.5f/16.0f, 0.5f/16.0f, 0.5f/16.0f };
+
+const char* BLUR_TWO_PASS_FRAGMENT_SOURCE =
+{
+ "precision highp float;\n"
+ "varying mediump vec2 vTexCoord;\n"
+ "uniform sampler2D sTexture;\n"
+ "uniform vec2 uSampleOffsets[NUM_SAMPLES];\n"
+ "uniform float uSampleWeights[NUM_SAMPLES];\n"
+ "void main()\n"
+ "{\n"
+ "  vec4 color = vec4(0.0);\n"
+ "  for( int i = 0; i < NUM_SAMPLES; ++i )\n"
+ "  {\n"
+ "    color += texture2D( sTexture, vTexCoord + uSampleOffsets[i] ) * uSampleWeights[i];\n"
+ "  }\n"
+ "  gl_FragColor = color;\n"
+ "}\n"
+};
+
+std::string GetOffsetUniformName( int index )
+{
+  std::ostringstream oss;
+  oss << "uSampleOffsets[" << index << "]";
+  return oss.str();
+}
+
+std::string GetWeightUniformName( int index )
+{
+  std::ostringstream oss;
+  oss << "uSampleWeights[" << index << "]";
+  return oss.str();
+}
+
+const char* BLEND_TWO_IMAGES_FRAGMENT_SOURCE =
+{
+ "precision highp float;\n"
+ "uniform float uBlurStrength;\n "
+ "uniform sampler2D sTexture;\n"
+ "uniform sampler2D sEffect;\n"
+ "varying mediump vec2 vTexCoord;\n"
+ "void main()\n"
+ "{\n"
+ "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uBlurStrength"
+ "               + texture2D( sEffect, vTexCoord )*(1.0-uBlurStrength); \n"
+ "}\n"
+};
+
+const char* const BLUR_STRENGTH_UNIFORM_NAME( "uBlurStrength"  );
+const char* const EFFECT_IMAGE_NAME( "sEffect" );
+
+} // namespace
+
+
+BlurTwoPassFilter::BlurTwoPassFilter()
+: ImageFilter()
+{
+  // create blending actor and register the property in constructor
+  // to make sure that GetBlurStrengthPropertyIndex() always returns a valid index
+  mActorForBlending = Actor::New();
+  mBlurStrengthPropertyIndex = mActorForBlending.RegisterProperty( BLUR_STRENGTH_UNIFORM_NAME, 1.f );
+}
+
+BlurTwoPassFilter::~BlurTwoPassFilter()
+{
+}
+
+void BlurTwoPassFilter::Enable()
+{
+  // create custom shader effect
+  if( !GetKernelSize() )
+  {
+    CreateKernel( DEFAULT_KERNEL4, sizeof(DEFAULT_KERNEL4)/sizeof(DEFAULT_KERNEL4[0]) );
+  }
+  int kernelSize( static_cast< int >(GetKernelSize()) );
+
+  // Set up blur-two-pass custom shader
+  std::ostringstream sstream;
+  sstream << "#define NUM_SAMPLES " << kernelSize << "\n";
+  sstream << BLUR_TWO_PASS_FRAGMENT_SOURCE;
+  std::string fragmentSource( sstream.str() );
+
+  // create actor to render input with applied emboss effect
+  mActorForInput = Actor::New();
+  mActorForInput.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForInput.SetSize( mTargetSize );
+  Renderer rendererForInput = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
+  SetRendererTexture( rendererForInput, mInputTexture );
+  mActorForInput.AddRenderer( rendererForInput );
+
+  // create internal offscreen for result of horizontal pass
+  mFrameBufferForHorz = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+  Texture textureForHorz = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+  mFrameBufferForHorz.AttachColorTexture( textureForHorz );
+
+  // create an actor to render mImageForHorz for vertical blur pass
+  mActorForHorz = Actor::New();
+  mActorForHorz.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForHorz.SetSize( mTargetSize );
+  Renderer rendererForHorz = CreateRenderer( BASIC_VERTEX_SOURCE, fragmentSource.c_str() );
+  SetRendererTexture( rendererForHorz, textureForHorz );
+  mActorForHorz.AddRenderer( rendererForHorz );
+
+  // create internal offscreen for result of the two pass blurred image
+  mBlurredFrameBuffer = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+  Texture blurredTexture = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+  mBlurredFrameBuffer.AttachColorTexture( blurredTexture );
+
+  // create an actor to blend the blurred image and the input image with the given blur strength
+  Renderer rendererForBlending = CreateRenderer( BASIC_VERTEX_SOURCE, BLEND_TWO_IMAGES_FRAGMENT_SOURCE );
+  TextureSet textureSetForBlending = rendererForBlending.GetTextures();
+  textureSetForBlending.SetTexture( 0u, blurredTexture );
+  textureSetForBlending.SetTexture( 1u, mInputTexture );
+  mActorForBlending.AddRenderer( rendererForBlending );
+  mActorForBlending.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForBlending.SetSize( mTargetSize );
+
+  for( int i = 0; i < kernelSize; ++i )
+  {
+    const std::string offsetUniform( GetOffsetUniformName( i ) );
+    const std::string weightUniform( GetWeightUniformName( i ) );
+
+    mActorForInput.RegisterProperty( offsetUniform, Vector2(mKernel[i]) * Vector2::XAXIS );
+    mActorForInput.RegisterProperty( weightUniform, mKernel[i].z );
+
+    mActorForHorz.RegisterProperty( offsetUniform, Vector2(mKernel[i]) * Vector2::YAXIS );
+    mActorForHorz.RegisterProperty( weightUniform, mKernel[i].z );
+  }
+
+  mRootActor.Add( mActorForInput );
+  mRootActor.Add( mActorForHorz );
+  mRootActor.Add( mActorForBlending );
+
+  SetupCamera();
+  CreateRenderTasks();
+}
+
+void BlurTwoPassFilter::Disable()
+{
+  if( mRootActor )
+  {
+    if( mCameraActor )
+    {
+      mRootActor.Remove( mCameraActor );
+      mCameraActor.Reset();
+    }
+
+    if( mActorForInput )
+    {
+      mRootActor.Remove( mActorForInput );
+      mActorForInput.Reset();
+    }
+
+    if( mActorForHorz )
+    {
+      mRootActor.Remove( mActorForHorz );
+      mActorForHorz.Reset();
+    }
+
+    RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+    if( mRenderTaskForHorz )
+    {
+      taskList.RemoveTask(mRenderTaskForHorz);
+    }
+    if( mRenderTaskForVert )
+    {
+      taskList.RemoveTask(mRenderTaskForVert);
+    }
+    if( mRenderTaskForBlending )
+    {
+      taskList.RemoveTask(mRenderTaskForBlending);
+    }
+
+    mRootActor.Reset();
+  }
+}
+
+void BlurTwoPassFilter::Refresh()
+{
+  if( mRenderTaskForHorz )
+  {
+    mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+
+  if( mRenderTaskForVert )
+  {
+    mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+
+  if( mRenderTaskForBlending )
+  {
+    mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+}
+
+void BlurTwoPassFilter::SetSize( const Vector2& size )
+{
+  mTargetSize = size;
+  if( mActorForInput )
+  {
+    mActorForInput.SetSize(mTargetSize);
+  }
+  if( mActorForHorz )
+  {
+    mActorForHorz.SetSize(mTargetSize);
+  }
+  if( mActorForBlending )
+  {
+    mActorForBlending.SetSize(mTargetSize);
+  }
+}
+
+Handle BlurTwoPassFilter::GetHandleForAnimateBlurStrength()
+{
+  return mActorForBlending;
+}
+
+void BlurTwoPassFilter::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // perform a horizontal blur targeting the internal buffer
+  mRenderTaskForHorz = taskList.CreateTask();
+  mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForHorz.SetSourceActor( mActorForInput );
+  mRenderTaskForHorz.SetExclusive(true);
+  mRenderTaskForHorz.SetInputEnabled( false );
+  mRenderTaskForHorz.SetClearEnabled( true );
+  mRenderTaskForHorz.SetClearColor( mBackgroundColor );
+  mRenderTaskForHorz.SetFrameBuffer( mFrameBufferForHorz );
+  mRenderTaskForHorz.SetCameraActor( mCameraActor );
+
+  // use the internal buffer and perform a horizontal blur targeting the output buffer
+  mRenderTaskForVert = taskList.CreateTask();
+  mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForVert.SetSourceActor( mActorForHorz );
+  mRenderTaskForVert.SetExclusive(true);
+  mRenderTaskForVert.SetInputEnabled( false );
+  mRenderTaskForVert.SetClearEnabled( true );
+  mRenderTaskForVert.SetClearColor( mBackgroundColor );
+  mRenderTaskForVert.SetFrameBuffer( mBlurredFrameBuffer );
+  mRenderTaskForVert.SetCameraActor( mCameraActor );
+
+  //Perform a blending between the blurred image and the input image
+  mRenderTaskForBlending = taskList.CreateTask();
+  mRenderTaskForBlending.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForBlending.SetSourceActor( mActorForBlending );
+  mRenderTaskForBlending.SetExclusive(true);
+  mRenderTaskForBlending.SetInputEnabled( false );
+  mRenderTaskForBlending.SetClearEnabled( true );
+  mRenderTaskForBlending.SetClearColor( mBackgroundColor );
+  mRenderTaskForBlending.SetFrameBuffer( mOutputFrameBuffer );
+  mRenderTaskForBlending.SetCameraActor( mCameraActor );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/filters/blur-two-pass-filter.h b/dali-toolkit/internal/filters/blur-two-pass-filter.h
new file mode 100644 (file)
index 0000000..9dd33af
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BLUR_TWO_PASS_FILTER_H
+#define DALI_TOOLKIT_INTERNAL_BLUR_TWO_PASS_FILTER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/render-tasks/render-task.h>
+
+// INTERNAL INCLUDES
+#include "image-filter.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * A two pass blur filter, pass one performs a horizontal blur and pass two performs a
+ * vertical blur on the result of pass one.
+ */
+class BlurTwoPassFilter : public ImageFilter
+{
+public:
+  /**
+   * Default constructor
+   */
+  BlurTwoPassFilter();
+
+  /**
+   * Destructor
+   */
+  virtual ~BlurTwoPassFilter();
+
+public: // From ImageFilter
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Enable
+  virtual void Enable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Disable
+  virtual void Disable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Refresh
+  virtual void Refresh();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::SetSize
+  virtual void SetSize( const Vector2& size );
+
+  /**
+   * Get the property index that controls the strength of the blur applied to the image. Useful for animating this property.
+   * This property represents a value in the range [0.0 - 1.0] where 0.0 is no blur and 1.0 is full blur.
+   */
+  Property::Index GetBlurStrengthPropertyIndex() const {return mBlurStrengthPropertyIndex;}
+
+  /**
+   * Retrieve the handle to the object in order to animate or constrain the blur strength property
+   * @return The hadnle to the object which blends the output image according to the blur strength
+   */
+  Handle GetHandleForAnimateBlurStrength();
+
+private:
+
+  /**
+   * Setup render tasks for blur
+   */
+  void CreateRenderTasks();
+
+private:
+  BlurTwoPassFilter( const BlurTwoPassFilter& );
+  BlurTwoPassFilter& operator=( const BlurTwoPassFilter& );
+
+private: // Attributes
+
+  // To perform horizontal blur from mInputTexture to mFrameBufferForHorz
+  RenderTask         mRenderTaskForHorz;
+  Actor              mActorForInput;
+  FrameBuffer        mFrameBufferForHorz;
+
+  // To perform vertical blur from mFrameBufferForHorz to mOutputFrameBuffer
+  RenderTask         mRenderTaskForVert;
+  Actor              mActorForHorz;
+  FrameBuffer        mBlurredFrameBuffer;
+
+  // To blend the blurred image and input image according to the blur strength
+  RenderTask         mRenderTaskForBlending;
+  Actor              mActorForBlending;
+  Actor              mRootActorForBlending;
+  Property::Index    mBlurStrengthPropertyIndex;
+
+}; // class BlurTwoPassFilter
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BLUR_TWO_PASS_FILTER_H
+
diff --git a/dali-toolkit/internal/filters/emboss-filter.cpp b/dali-toolkit/internal/filters/emboss-filter.cpp
new file mode 100644 (file)
index 0000000..d8349da
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017 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 "emboss-filter.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const char* EMBOSS_FRAGMENT_SOURCE =
+{
+ "precision highp float;\n"
+ "varying mediump vec2 vTexCoord;\n"
+ "uniform sampler2D sTexture;\n"
+ "uniform vec2 uTexScale;\n"
+ "uniform vec3 uCoefficient;\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ "  vec4 color  = uCoefficient.x * texture2D( sTexture, vTexCoord + vec2(0.0, -uTexScale.y) );\n"
+ "  color += uCoefficient.y * texture2D( sTexture, vTexCoord );\n"
+ "  color += uCoefficient.z * texture2D( sTexture, vTexCoord + vec2(0.0, uTexScale.y) );\n"
+ "  gl_FragColor = color;\n"
+ "}\n"
+};
+
+const char* const COMPOSITE_FRAGMENT_SOURCE =
+{
+  "varying mediump vec2 vTexCoord;\n"
+  "uniform sampler2D sTexture;\n"
+  "uniform lowp vec4 uEffectColor;\n"
+  "void main()\n"
+  "{\n"
+  "  gl_FragColor = uEffectColor;\n"
+  "  gl_FragColor.a *= texture2D( sTexture, vTexCoord).a;\n"
+  "}\n"
+};
+
+const char* const TEX_SCALE_UNIFORM_NAME( "uTexScale" );
+const char* const COEFFICIENT_UNIFORM_NAME( "uCoefficient" );
+const char* const COLOR_UNIFORM_NAME( "uEffectColor" );
+
+} // namespace
+
+EmbossFilter::EmbossFilter()
+: ImageFilter()
+{
+}
+
+EmbossFilter::~EmbossFilter()
+{
+}
+
+void EmbossFilter::Enable()
+{
+  mFrameBufferForEmboss1 = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+  Texture texture1 = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+  mFrameBufferForEmboss1.AttachColorTexture( texture1 );
+
+  mFrameBufferForEmboss2 = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+  Texture texture2 = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+  mFrameBufferForEmboss2.AttachColorTexture( texture2 );
+
+  // create actor to render input with applied emboss effect
+  mActorForInput1 = Actor::New();
+  mActorForInput1.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForInput1.SetSize(mTargetSize);
+  Vector2 textureScale( 1.5f/mTargetSize.width, 1.5f/mTargetSize.height);
+  mActorForInput1.RegisterProperty( TEX_SCALE_UNIFORM_NAME, textureScale );
+  mActorForInput1.RegisterProperty( COEFFICIENT_UNIFORM_NAME, Vector3( 2.f, -1.f, -1.f ) );
+  // set EMBOSS custom shader
+  Renderer renderer1 = CreateRenderer( BASIC_VERTEX_SOURCE, EMBOSS_FRAGMENT_SOURCE );
+  SetRendererTexture( renderer1, mInputTexture );
+  mActorForInput1.AddRenderer( renderer1 );
+  mRootActor.Add( mActorForInput1 );
+
+  mActorForInput2 = Actor::New();
+  mActorForInput2.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForInput2.SetSize(mTargetSize);
+  mActorForInput2.RegisterProperty( TEX_SCALE_UNIFORM_NAME, textureScale );
+  mActorForInput2.RegisterProperty( COEFFICIENT_UNIFORM_NAME, Vector3( -1.f, -1.f, 2.f ) );
+  // set EMBOSS custom shader
+  Renderer renderer2 = CreateRenderer( BASIC_VERTEX_SOURCE, EMBOSS_FRAGMENT_SOURCE );
+  SetRendererTexture( renderer2, mInputTexture );
+  mActorForInput2.AddRenderer( renderer2 );
+  mRootActor.Add( mActorForInput2 );
+
+  mActorForComposite = Actor::New();
+  mActorForComposite.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForComposite.SetSize(mTargetSize);
+  mActorForComposite.SetColor( Color::BLACK );
+
+  mRootActor.Add( mActorForComposite );
+
+  mRendererForEmboss1 = CreateRenderer( BASIC_VERTEX_SOURCE, COMPOSITE_FRAGMENT_SOURCE );
+  SetRendererTexture( mRendererForEmboss1, mFrameBufferForEmboss1 );
+  mRendererForEmboss1.RegisterProperty( COLOR_UNIFORM_NAME, Color::BLACK );
+  mActorForComposite.AddRenderer( mRendererForEmboss1 );
+
+  mRendererForEmboss2 = CreateRenderer( BASIC_VERTEX_SOURCE, COMPOSITE_FRAGMENT_SOURCE );
+  SetRendererTexture( mRendererForEmboss2, mFrameBufferForEmboss2 );
+  mRendererForEmboss2.RegisterProperty( COLOR_UNIFORM_NAME, Color::WHITE );
+  mActorForComposite.AddRenderer( mRendererForEmboss2 );
+
+  SetupCamera();
+  CreateRenderTasks();
+}
+
+void EmbossFilter::Disable()
+{
+  if( mRootActor )
+  {
+    if( mCameraActor )
+    {
+      mRootActor.Remove( mCameraActor );
+      mCameraActor.Reset();
+    }
+
+    if( mActorForInput1 )
+    {
+      mRootActor.Remove( mActorForInput1 );
+      mActorForInput1.Reset();
+    }
+
+    if( mActorForInput2 )
+    {
+      mRootActor.Remove( mActorForInput2 );
+      mActorForInput2.Reset();
+    }
+
+    if( mActorForComposite )
+    {
+      mActorForComposite.RemoveRenderer( mRendererForEmboss1 );
+      mRendererForEmboss1.Reset();
+
+      mActorForComposite.RemoveRenderer( mRendererForEmboss2 );
+      mRendererForEmboss2.Reset();
+
+      mRootActor.Remove( mActorForComposite );
+      mActorForComposite.Reset();
+    }
+
+    RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+    if( mRenderTaskForEmboss1 )
+    {
+      taskList.RemoveTask(mRenderTaskForEmboss1);
+    }
+
+    if( mRenderTaskForEmboss2 )
+    {
+      taskList.RemoveTask(mRenderTaskForEmboss2);
+    }
+
+    if( mRenderTaskForOutput )
+    {
+      taskList.RemoveTask( mRenderTaskForOutput );
+    }
+
+    mRootActor.Reset();
+  }
+}
+
+void EmbossFilter::Refresh()
+{
+  if( mRenderTaskForEmboss1 )
+  {
+    mRenderTaskForEmboss1.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+  if( mRenderTaskForEmboss2 )
+  {
+    mRenderTaskForEmboss2.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+}
+
+void EmbossFilter::SetSize( const Vector2& size )
+{
+  mTargetSize = size;
+  if( mActorForInput1 )
+  {
+    mActorForInput1.SetSize(mTargetSize);
+  }
+  if( mActorForInput2 )
+  {
+    mActorForInput2.SetSize(mTargetSize);
+  }
+  if( mActorForComposite )
+  {
+    mActorForComposite.SetSize(mTargetSize);
+  }
+}
+
+void EmbossFilter::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  mRenderTaskForEmboss1 = taskList.CreateTask();
+  mRenderTaskForEmboss1.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForEmboss1.SetSourceActor( mActorForInput1 );
+  mRenderTaskForEmboss1.SetExclusive(true);
+  mRenderTaskForEmboss1.SetInputEnabled( false );
+  mRenderTaskForEmboss1.SetClearColor( Vector4( 0.0f, 0.0f, 0.0f, 0.0f ) );
+  mRenderTaskForEmboss1.SetClearEnabled( true );
+  mRenderTaskForEmboss1.SetFrameBuffer( mFrameBufferForEmboss1 );
+  mRenderTaskForEmboss1.SetCameraActor( mCameraActor );
+
+  mRenderTaskForEmboss2 = taskList.CreateTask();
+  mRenderTaskForEmboss2.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForEmboss2.SetSourceActor( mActorForInput2 );
+  mRenderTaskForEmboss2.SetExclusive(true);
+  mRenderTaskForEmboss2.SetInputEnabled( false );
+  mRenderTaskForEmboss2.SetClearColor( Vector4( 1.0f, 1.0f, 1.0f, 0.0f ) );
+  mRenderTaskForEmboss2.SetClearEnabled( true );
+  mRenderTaskForEmboss2.SetFrameBuffer( mFrameBufferForEmboss2 );
+  mRenderTaskForEmboss2.SetCameraActor( mCameraActor );
+
+  mRenderTaskForOutput = taskList.CreateTask();
+  mRenderTaskForOutput.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForOutput.SetSourceActor( mActorForComposite );
+  mRenderTaskForOutput.SetExclusive(true);
+  mRenderTaskForOutput.SetInputEnabled( false );
+  mRenderTaskForOutput.SetClearColor( Vector4( 0.5f, 0.5f, 0.5f, 0.0f ) );
+  mRenderTaskForOutput.SetClearEnabled( true );
+  mRenderTaskForOutput.SetFrameBuffer( mOutputFrameBuffer );
+  mRenderTaskForOutput.SetCameraActor( mCameraActor );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/filters/emboss-filter.h b/dali-toolkit/internal/filters/emboss-filter.h
new file mode 100644 (file)
index 0000000..2d58538
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef DALI_TOOLKIT_INTERNAL_EMBOSS_FILTER_H
+#define DALI_TOOLKIT_INTERNAL_EMBOSS_FILTER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include "image-filter.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * An embossing image filter, implements Dali::Toolkit::Internal::ImageFilter
+ */
+class EmbossFilter : public ImageFilter
+{
+public:
+  /**
+   * Construct an empty filter
+   */
+  EmbossFilter();
+
+  /**
+   * Destructor
+   */
+  virtual ~EmbossFilter();
+
+public: // From ImageFilter
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Enable
+  virtual void Enable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Disable
+  virtual void Disable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Refresh
+  virtual void Refresh();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::SetSize
+  virtual void SetSize( const Vector2& size );
+
+private:
+  /**
+   * Setup render tasks for blur
+   */
+  void CreateRenderTasks();
+
+private:
+  EmbossFilter( const EmbossFilter& );
+  EmbossFilter& operator=( const EmbossFilter& );
+
+private: // Attributes
+
+  RenderTask            mRenderTaskForEmboss1;
+  RenderTask            mRenderTaskForEmboss2;
+  RenderTask            mRenderTaskForOutput;
+  FrameBuffer           mFrameBufferForEmboss1;
+  FrameBuffer           mFrameBufferForEmboss2;
+  Actor                 mActorForInput1;
+  Actor                 mActorForInput2;
+  Renderer              mRendererForEmboss1;
+  Renderer              mRendererForEmboss2;
+  Actor                 mActorForComposite;
+}; // class EmbossFilter
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_EMBOSS_FILTER_H
+
diff --git a/dali-toolkit/internal/filters/image-filter.cpp b/dali-toolkit/internal/filters/image-filter.cpp
new file mode 100644 (file)
index 0000000..e90e07e
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "image-filter.h"
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const float ARBITRARY_FIELD_OF_VIEW = Math::PI / 4.0f;
+} // namespace
+
+ImageFilter::ImageFilter()
+: mBackgroundColor( Vector4( 1.0f, 1.0f, 1.0f, 0.0f ) ),
+  mTargetSize( Vector2::ZERO ),
+  mPixelFormat( Pixel::RGBA8888 ),
+  mRefreshOnDemand( false )
+{
+}
+
+ImageFilter::~ImageFilter()
+{
+}
+
+void ImageFilter::SetRefreshOnDemand( bool onDemand )
+{
+  mRefreshOnDemand = onDemand;
+}
+
+void ImageFilter::SetInputTexture( Texture texture )
+{
+  mInputTexture = texture;
+}
+
+void ImageFilter::SetOutputFrameBuffer( FrameBuffer frameBuffer )
+{
+  mOutputFrameBuffer = frameBuffer;
+}
+
+void ImageFilter::SetSize( const Vector2& size )
+{
+  mTargetSize = size;
+}
+
+void ImageFilter::SetPixelFormat( Pixel::Format pixelFormat )
+{
+  mPixelFormat = pixelFormat;
+}
+
+void ImageFilter::SetKernel( const FilterKernel& kernel )
+{
+  mKernel = kernel;
+}
+
+const ImageFilter::FilterKernel& ImageFilter::GetKernel() const
+{
+  return mKernel;
+}
+
+size_t ImageFilter::GetKernelSize() const
+{
+  return mKernel.size();
+}
+
+void ImageFilter::CreateKernel( const float* weights, size_t count )
+{
+  if( (mTargetSize.width * mTargetSize.height ) > 0.0f )
+  {
+    Vector2 pixelsToUV( 1.0f / mTargetSize.width, 1.0f / mTargetSize.height );
+
+    mKernel.clear();
+
+    mKernel.push_back( Vector3( 0.0f, 0.0f, weights[0] ) );
+    for( size_t i = 0; i < count >> 1; ++i )
+    {
+      float offset = 1.5f + (i << 1);
+
+      mKernel.push_back( Vector3( pixelsToUV.x * offset, pixelsToUV.y * offset, weights[(i << 1) + 1] ) );
+      mKernel.push_back( Vector3( -pixelsToUV.x * offset, -pixelsToUV.y * offset, weights[(i << 1) + 2] ) );
+    }
+  }
+}
+
+void ImageFilter::SetRootActor( Actor rootActor )
+{
+  mRootActor = rootActor;
+}
+
+void ImageFilter::SetBackgroundColor( const Vector4& color )
+{
+  mBackgroundColor = color;
+}
+
+void ImageFilter::SetupCamera()
+{
+  if( !mCameraActor )
+  {
+    // create a camera for the render task, corresponding to its render target size
+    mCameraActor = CameraActor::New(mTargetSize);
+    mCameraActor.SetParentOrigin(ParentOrigin::CENTER);
+    mCameraActor.SetInvertYAxis( true );
+    mRootActor.Add( mCameraActor );
+  }
+  else
+  {
+    // place the camera for the render task, corresponding to its render target size
+    mCameraActor.SetFieldOfView(ARBITRARY_FIELD_OF_VIEW);
+    mCameraActor.SetNearClippingPlane(1.0f);
+    mCameraActor.SetAspectRatio(mTargetSize.width / mTargetSize.height);
+    mCameraActor.SetType(Dali::Camera::FREE_LOOK); // camera orientation based solely on actor
+    mCameraActor.SetPosition(0.0f, 0.0f, ((mTargetSize.height * 0.5f) / tanf(ARBITRARY_FIELD_OF_VIEW * 0.5f)));
+  }
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/filters/image-filter.h b/dali-toolkit/internal/filters/image-filter.h
new file mode 100644 (file)
index 0000000..d73f9e6
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef DALI_TOOLKIT_INTERNAL_IMAGE_FILTER_H
+#define DALI_TOOLKIT_INTERNAL_IMAGE_FILTER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/devel-api/controls/effects-view/effects-view.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * An interface class that provides a interface for image filters that perform
+ * a simple shader effect on an input texture, rendering the output to a FrameBuffer.
+ */
+class ImageFilter
+{
+public:
+  typedef std::vector< Vector3 > FilterKernel;
+
+public:
+
+  /**
+   * Default constructor
+   */
+  ImageFilter();
+
+  /**
+   * Destructor
+   */
+  virtual ~ImageFilter();
+
+  /**
+   * Enable effect, allocates any necessary resources
+   */
+  virtual void Enable() = 0;
+
+  /**
+   * Disable effect, releases any allocated resources
+   */
+  virtual void Disable() = 0;
+
+  /**
+   * Refresh the filter output
+   */
+  virtual void Refresh() = 0;
+
+  /**
+   * @copydoc Dali::Toolkit::EffectsView::SetRefreshOnDemand
+   */
+  void SetRefreshOnDemand( bool onDemand );
+
+  /**
+   * Set the input texture
+   * @param[in] The input/original texture.
+   */
+  void SetInputTexture( Texture texture );
+
+  /**
+   * Set the output frame buffer
+   * @return The output frame buffer.
+   */
+  void SetOutputFrameBuffer( FrameBuffer frameBuffer );
+
+  /**
+   * Set size of ImageFilter. Used to create internal offscreen buffers
+   * @param[in] size  THe size.
+   */
+  virtual void SetSize( const Vector2& size );
+
+  /**
+   * Set the pixel format for internal offscreen buffers
+   * @param[in] pixelFormat The pixel format.
+   */
+  void SetPixelFormat( Pixel::Format pixelFormat );
+
+  /**
+   * Set the filter kernel
+   * @param[in] The filter kernel
+   */
+  void SetKernel( const FilterKernel& kernel );
+
+  /**
+   * Get a const reference to the internal filter kernel
+   * @Return A a const reference to the internal filter kernel
+   */
+  const FilterKernel& GetKernel() const;
+
+  /**
+   * Get the number of steps/elements in the kernel
+   * @return The number of steps/elements in the kernel
+   */
+  size_t GetKernelSize() const;
+
+  /**
+   * Create a kernel from an array of weights
+   * @param[in] weights
+   * @param[in] count
+   */
+  void CreateKernel( const float* weights, size_t count);
+
+  /**
+   * Set the actor which acts as the root actor for all internal actors for connection to stage
+   * @param[in] rootActor   An actor which acts as the root actor for any internal actors that need
+   *                        to be created
+   */
+  void SetRootActor( Actor rootActor );
+
+  /**
+   * Set the background / clear color
+   * @param[in] color The background / clear color
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+protected:
+
+  /**
+   * Setup position and parameters for camera
+   */
+  void SetupCamera();
+
+protected:
+  Texture          mInputTexture;
+  FrameBuffer      mOutputFrameBuffer;
+  FilterKernel     mKernel;
+  Actor            mRootActor;
+  CameraActor      mCameraActor;
+  Vector4          mBackgroundColor;
+  Vector2          mTargetSize;
+  Pixel::Format    mPixelFormat;
+  bool             mRefreshOnDemand;
+
+}; // class Imagefilter
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_IMAGE_FILTER_H
+
diff --git a/dali-toolkit/internal/filters/spread-filter.cpp b/dali-toolkit/internal/filters/spread-filter.cpp
new file mode 100644 (file)
index 0000000..5100821
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017 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 "spread-filter.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/control/control-renderers.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const char* const SPREAD_FRAGMENT_SOURCE =
+{
+ "precision highp float;\n"
+ "varying mediump vec2 vTexCoord;\n"
+ "uniform sampler2D sTexture;\n"
+ "uniform int uSpread;\n"
+ "uniform vec2 uTexScale;\n"
+ "void main()\n"
+ "{\n"
+ "  vec4 color = texture2D( sTexture, vTexCoord);\n"
+ "  for( int i = 1; i <= uSpread; ++i )\n"
+ "  {\n"
+ "    vec2 offset = uTexScale * float(i);\n"
+ "    color = max( texture2D( sTexture, vTexCoord + offset), color );\n"
+ "    color = max( texture2D( sTexture, vTexCoord - offset), color );\n"
+ "  }\n"
+ "  gl_FragColor = color;\n"
+ "}\n"
+};
+
+const char* const SPREAD_UNIFORM_NAME( "uSpread" );
+const char* const TEX_SCALE_UNIFORM_NAME( "uTexScale" );
+
+} // namespace
+
+
+SpreadFilter::SpreadFilter()
+: ImageFilter(),
+  mSpread(2)
+{
+}
+
+SpreadFilter::~SpreadFilter()
+{
+}
+
+void SpreadFilter::SetSpread( float spread )
+{
+  mSpread = spread;
+}
+
+void SpreadFilter::Enable()
+{
+  // create actor to render input with applied emboss effect
+  mActorForInput = Actor::New();
+  mActorForInput.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForInput.SetSize(mTargetSize);
+  // register properties as shader uniforms
+  mActorForInput.RegisterProperty( SPREAD_UNIFORM_NAME, mSpread );
+  mActorForInput.RegisterProperty( TEX_SCALE_UNIFORM_NAME, Vector2( 1.0f / mTargetSize.width, 0.0f ) );
+
+  Renderer rendererForInput = CreateRenderer( BASIC_VERTEX_SOURCE, SPREAD_FRAGMENT_SOURCE );
+  SetRendererTexture( rendererForInput, mInputTexture );
+  mActorForInput.AddRenderer( rendererForInput );
+
+  // create internal offscreen for result of horizontal pass
+  mFrameBufferForHorz = FrameBuffer::New( mTargetSize.width, mTargetSize.height, FrameBuffer::Attachment::NONE );
+  Texture textureForHorz = Texture::New( TextureType::TEXTURE_2D, mPixelFormat, unsigned(mTargetSize.width), unsigned(mTargetSize.height) );
+  mFrameBufferForHorz.AttachColorTexture( textureForHorz );
+
+  // create an actor to render mImageForHorz for vertical blur pass
+  mActorForHorz = Actor::New();
+  mActorForHorz.SetParentOrigin( ParentOrigin::CENTER );
+  mActorForHorz.SetSize(mTargetSize);
+  // register properties as shader uniforms
+  mActorForHorz.RegisterProperty( SPREAD_UNIFORM_NAME, mSpread );
+  mActorForHorz.RegisterProperty( TEX_SCALE_UNIFORM_NAME, Vector2( 0.0f, 1.0f / mTargetSize.height ) );
+  Renderer rendererForHorz = CreateRenderer( BASIC_VERTEX_SOURCE, SPREAD_FRAGMENT_SOURCE );
+  SetRendererTexture( rendererForHorz, textureForHorz );
+  mActorForHorz.AddRenderer( rendererForHorz );
+
+  mRootActor.Add( mActorForInput );
+  mRootActor.Add( mActorForHorz );
+
+  SetupCamera();
+  CreateRenderTasks();
+}
+
+void SpreadFilter::Disable()
+{
+  if( mRootActor )
+  {
+    if( mCameraActor )
+    {
+      mRootActor.Remove( mCameraActor );
+      mCameraActor.Reset();
+    }
+
+    if( mActorForInput )
+    {
+      mRootActor.Remove( mActorForInput );
+      mActorForInput.Reset();
+    }
+
+    if( mActorForHorz )
+    {
+      mRootActor.Remove( mActorForHorz );
+      mActorForHorz.Reset();
+    }
+
+    RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+    if( mRenderTaskForHorz )
+    {
+      taskList.RemoveTask(mRenderTaskForHorz);
+    }
+    if( mRenderTaskForVert )
+    {
+      taskList.RemoveTask(mRenderTaskForVert);
+    }
+
+    mRootActor.Reset();
+  }
+}
+
+void SpreadFilter::Refresh()
+{
+  if( mRenderTaskForHorz )
+  {
+    mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+
+  if( mRenderTaskForVert )
+  {
+    mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  }
+}
+
+void SpreadFilter::SetSize( const Vector2& size )
+{
+  mTargetSize = size;
+  if( mActorForInput )
+  {
+    mActorForInput.SetSize(mTargetSize);
+  }
+  if( mActorForHorz )
+  {
+    mActorForHorz.SetSize(mTargetSize);
+  }
+}
+
+void SpreadFilter::CreateRenderTasks()
+{
+  RenderTaskList taskList = Stage::GetCurrent().GetRenderTaskList();
+
+  // perform a horizontal blur targeting the internal buffer
+  mRenderTaskForHorz = taskList.CreateTask();
+  mRenderTaskForHorz.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForHorz.SetSourceActor( mActorForInput );
+  mRenderTaskForHorz.SetExclusive(true);
+  mRenderTaskForHorz.SetInputEnabled( false );
+  mRenderTaskForHorz.SetClearEnabled( true );
+  mRenderTaskForHorz.SetClearColor( mBackgroundColor );
+  mRenderTaskForHorz.SetFrameBuffer( mFrameBufferForHorz );
+  mRenderTaskForHorz.SetCameraActor( mCameraActor );
+
+  // use the internal buffer and perform a horizontal blur targeting the output buffer
+  mRenderTaskForVert = taskList.CreateTask();
+  mRenderTaskForVert.SetRefreshRate( mRefreshOnDemand ? RenderTask::REFRESH_ONCE : RenderTask::REFRESH_ALWAYS );
+  mRenderTaskForVert.SetSourceActor( mActorForHorz );
+  mRenderTaskForVert.SetExclusive(true);
+  mRenderTaskForVert.SetInputEnabled( false );
+  mRenderTaskForVert.SetClearEnabled( true );
+  mRenderTaskForVert.SetClearColor( mBackgroundColor );
+  mRenderTaskForVert.SetFrameBuffer( mOutputFrameBuffer );
+  mRenderTaskForVert.SetCameraActor( mCameraActor );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/filters/spread-filter.h b/dali-toolkit/internal/filters/spread-filter.h
new file mode 100644 (file)
index 0000000..83809f1
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SPREAD_FILTER_H
+#define DALI_TOOLKIT_INTERNAL_SPREAD_FILTER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/render-tasks/render-task.h>
+
+// INTERNAL INCLUDES
+#include "image-filter.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * A spread/thicken filter. Expands an image into transparent areas.
+ */
+class SpreadFilter : public ImageFilter
+{
+public:
+  /**
+   * Default constructor
+   */
+  SpreadFilter();
+
+  /**
+   * Destructor
+   */
+  virtual ~SpreadFilter();
+
+  /**
+   * Set the amount of spread in pixels.
+   * @param[in] spread The amount of spread
+   */
+  void SetSpread( float spread );
+
+public: // From ImageFilter
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Enable
+  virtual void Enable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Disable
+  virtual void Disable();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::Refresh
+  virtual void Refresh();
+
+  /// @copydoc Dali::Toolkit::Internal::ImageFilter::SetSize
+  virtual void SetSize( const Vector2& size );
+
+private:
+
+  /**
+   * Setup render tasks for blur
+   */
+  void CreateRenderTasks();
+
+private:
+  SpreadFilter( const SpreadFilter& );
+  SpreadFilter& operator=( const SpreadFilter& );
+
+private: // Attributes
+
+  // To perform horizontal spread from mInputTexture to mFrameBufferForHorz
+  RenderTask         mRenderTaskForHorz;
+  Actor              mActorForInput;
+  FrameBuffer        mFrameBufferForHorz;
+
+  // To perform vertical spread from mFrameBufferForHorz to mOutputFrameBuffer
+  RenderTask         mRenderTaskForVert;
+  Actor              mActorForHorz;
+
+  int                mSpread;
+}; // class SpreadFilter
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_SPREAD_FILTER_H
+
diff --git a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
new file mode 100644 (file)
index 0000000..691f9ab
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * Copyright (c) 2019 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 "keyboard-focus-manager-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/actors/layer.h>
+#include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+#include <dali/public-api/animation/constraints.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace // Unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEYBOARD_FOCUS_MANAGER");
+#endif
+
+const char* const IS_FOCUS_GROUP_PROPERTY_NAME = "isKeyboardFocusGroup"; // This property will be replaced by a flag in Control.
+
+const char* const FOCUS_BORDER_IMAGE_FILE_NAME = "keyboard_focus.9.png";
+
+BaseHandle Create()
+{
+  BaseHandle handle = KeyboardFocusManager::Get();
+
+  if ( !handle )
+  {
+    SingletonService singletonService( SingletonService::Get() );
+    if ( singletonService )
+    {
+      Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager( new Internal::KeyboardFocusManager() );
+      singletonService.Register( typeid( manager ), manager );
+      handle = manager;
+    }
+  }
+
+  return handle;
+}
+
+DALI_TYPE_REGISTRATION_BEGIN_CREATE( Toolkit::KeyboardFocusManager, Dali::BaseHandle, Create, true )
+
+DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardPreFocusChange",           SIGNAL_PRE_FOCUS_CHANGE )
+DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusChanged",             SIGNAL_FOCUS_CHANGED )
+DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusGroupChanged",        SIGNAL_FOCUS_GROUP_CHANGED )
+DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusedActorEnterKey",     SIGNAL_FOCUSED_ACTOR_ENTER_KEY )
+
+DALI_TYPE_REGISTRATION_END()
+
+const unsigned int MAX_HISTORY_AMOUNT = 30; ///< Max length of focus history stack
+
+} // unnamed namespace
+
+Toolkit::KeyboardFocusManager KeyboardFocusManager::Get()
+{
+  Toolkit::KeyboardFocusManager manager;
+
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    // Check whether the keyboard focus manager is already created
+    Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::KeyboardFocusManager ) );
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to keyboard focus manager
+      manager = Toolkit::KeyboardFocusManager( dynamic_cast< KeyboardFocusManager* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return manager;
+}
+
+KeyboardFocusManager::KeyboardFocusManager()
+: mPreFocusChangeSignal(),
+  mFocusChangedSignal(),
+  mFocusGroupChangedSignal(),
+  mFocusedActorEnterKeySignal(),
+  mCurrentFocusActor(),
+  mFocusIndicatorActor(),
+  mFocusHistory(),
+  mSlotDelegate( this ),
+  mCustomAlgorithmInterface(NULL),
+  mCurrentFocusedWindow(),
+  mIsFocusIndicatorShown( UNKNOWN ),
+  mEnableFocusIndicator( ENABLE ),
+  mAlwaysShowIndicator( ALWAYS_SHOW ),
+  mFocusGroupLoopEnabled( false ),
+  mIsWaitingKeyboardFocusChangeCommit( false ),
+  mClearFocusOnTouch( true )
+{
+  // TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorShown.
+
+  LifecycleController::Get().InitSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnAdaptorInit );
+}
+
+void KeyboardFocusManager::OnAdaptorInit()
+{
+  if( Adaptor::IsAvailable() )
+  {
+    // Retrieve all the existing scene holders
+    Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
+    for( auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter )
+    {
+      ( *iter ).KeyEventSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnKeyEvent );
+      ( *iter ).TouchSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnTouch );
+      Dali::Window window = DevelWindow::DownCast( *iter );
+      if( window )
+      {
+        window.FocusChangeSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
+      }
+    }
+
+    // Get notified when any new scene holder is created afterwards
+    Adaptor::Get().WindowCreatedSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnSceneHolderCreated );
+  }
+}
+
+void KeyboardFocusManager::OnSceneHolderCreated( Dali::Integration::SceneHolder& sceneHolder )
+{
+  sceneHolder.KeyEventSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnKeyEvent );
+  sceneHolder.TouchSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnTouch );
+  Dali::Window window = DevelWindow::DownCast( sceneHolder );
+  if( window )
+  {
+    window.FocusChangeSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
+  }
+}
+
+KeyboardFocusManager::~KeyboardFocusManager()
+{
+}
+
+void KeyboardFocusManager::GetConfigurationFromStyleManger()
+{
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
+      mAlwaysShowIndicator = config["alwaysShowFocus"].Get<bool>() ? ALWAYS_SHOW : NONE;
+      mIsFocusIndicatorShown = ( mAlwaysShowIndicator == ALWAYS_SHOW )? SHOW : HIDE;
+      mClearFocusOnTouch = ( mIsFocusIndicatorShown == SHOW ) ? false : true;
+    }
+}
+
+bool KeyboardFocusManager::SetCurrentFocusActor( Actor actor )
+{
+  DALI_ASSERT_DEBUG( !mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?" );
+
+  if( mIsFocusIndicatorShown == UNKNOWN )
+  {
+    GetConfigurationFromStyleManger();
+  }
+
+  return DoSetCurrentFocusActor( actor );
+}
+
+bool KeyboardFocusManager::DoSetCurrentFocusActor( Actor actor )
+{
+  bool success = false;
+  if( actor && actor.IsKeyboardFocusable() && actor.OnStage() )
+  {
+    Integration::SceneHolder currentWindow = Integration::SceneHolder::Get( actor );
+
+    if( currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle())
+    {
+      Layer rootLayer = currentWindow.GetRootLayer();
+      mCurrentFocusedWindow = rootLayer;
+    }
+  }
+
+  Actor currentFocusedActor = GetCurrentFocusActor();
+
+  // If developer set focus on same actor, doing nothing
+  if( actor == currentFocusedActor )
+  {
+    if( !actor )
+    {
+      return false;
+    }
+    return true;
+  }
+
+  // Check whether the actor is in the stage and is keyboard focusable.
+  if( actor && actor.IsKeyboardFocusable() && actor.OnStage() )
+  {
+    if( ( mIsFocusIndicatorShown == SHOW ) && ( mEnableFocusIndicator == ENABLE ) )
+    {
+      actor.Add( GetFocusIndicatorActor() );
+    }
+
+    // Send notification for the change of focus actor
+    if( !mFocusChangedSignal.Empty() )
+    {
+      mFocusChangedSignal.Emit(currentFocusedActor, actor);
+    }
+
+    Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
+    if( currentlyFocusedControl )
+    {
+      // Do we need it to remember if it was previously DISABLED?
+      currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL );
+      currentlyFocusedControl.ClearKeyInputFocus();
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__);
+
+    // Save the current focused actor
+    mCurrentFocusActor = actor;
+
+    bool focusedWindowFound = false;
+    for( unsigned int i = 0; i < mCurrentFocusActors.size(); i++ )
+    {
+      if( mCurrentFocusActors[i].first == mCurrentFocusedWindow )
+      {
+        mCurrentFocusActors[i].second = actor;
+        focusedWindowFound = true;
+        break;
+      }
+    }
+    if( !focusedWindowFound)
+    {
+      // A new window gains the focus, so store the focused actor in that window.
+      mCurrentFocusActors.push_back( std::pair< WeakHandle< Layer>, WeakHandle< Actor > >( mCurrentFocusedWindow , actor ));
+    }
+
+    Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor);
+    if( newlyFocusedControl )
+    {
+      newlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::FOCUSED );
+      newlyFocusedControl.SetKeyInputFocus();
+    }
+
+    // Push Current Focused Actor to FocusHistory
+    mFocusHistory.push_back( actor );
+
+    // Delete first element before add new element when Stack is full.
+    if( mFocusHistory.size() > MAX_HISTORY_AMOUNT )
+    {
+       FocusStackIterator beginPos = mFocusHistory.begin();
+       mFocusHistory.erase( beginPos );
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
+    success = true;
+  }
+  else
+  {
+    DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
+  }
+
+  return success;
+}
+
+Actor KeyboardFocusManager::GetCurrentFocusActor()
+{
+  Actor actor = mCurrentFocusActor.GetHandle();
+
+  if( actor && ! actor.OnStage() )
+  {
+    // If the actor has been removed from the stage, then it should not be focused
+    actor.Reset();
+    mCurrentFocusActor.Reset();
+  }
+  return actor;
+}
+
+Actor KeyboardFocusManager::GetFocusActorFromCurrentWindow()
+{
+  Actor actor;
+  unsigned int index;
+  for( index = 0; index < mCurrentFocusActors.size(); index++ )
+  {
+    if( mCurrentFocusActors[index].first == mCurrentFocusedWindow )
+    {
+      actor = mCurrentFocusActors[index].second.GetHandle();
+      break;
+    }
+  }
+
+  if( actor && ! actor.OnStage() )
+  {
+    // If the actor has been removed from the window, then the window doesn't have any focused actor
+    actor.Reset();
+    mCurrentFocusActors.erase( mCurrentFocusActors.begin() + index );
+  }
+
+  return actor;
+}
+
+Actor KeyboardFocusManager::GetCurrentFocusGroup()
+{
+  return GetFocusGroup(GetCurrentFocusActor());
+}
+
+void KeyboardFocusManager::MoveFocusBackward()
+{
+  // Find Pre Focused Actor when the list size is more than 1
+  if( mFocusHistory.size() > 1 )
+  {
+    // Delete current focused actor in history
+    mFocusHistory.pop_back();
+
+    // If pre-focused actors are not on stage or deleted, remove them in stack
+    while( mFocusHistory.size() > 0 )
+    {
+      // Get pre focused actor
+      Actor target = mFocusHistory[ mFocusHistory.size() -1 ].GetHandle();
+
+      // Impl of Actor is not null
+      if( target && target.OnStage() )
+      {
+        // Delete pre focused actor in history because it will pushed again by SetCurrentFocusActor()
+        mFocusHistory.pop_back();
+        SetCurrentFocusActor( target );
+        break;
+      }
+      else
+      {
+        // Target is empty handle or off stage. Erase from queue
+        mFocusHistory.pop_back();
+      }
+    }
+
+    // if there is no actor which can get focus, then push current focus actor in stack again
+    if( mFocusHistory.size() == 0 )
+    {
+      Actor currentFocusedActor = GetCurrentFocusActor();
+      mFocusHistory.push_back( currentFocusedActor );
+    }
+  }
+}
+
+bool KeyboardFocusManager::IsLayoutControl(Actor actor) const
+{
+  Toolkit::Control control = Toolkit::Control::DownCast(actor);
+  return control && GetImplementation( control ).IsKeyboardNavigationSupported();
+}
+
+Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const
+{
+  // Get the actor's parent layout control that supports two dimensional keyboard navigation
+  Actor rootActor;
+  Actor parent;
+  if(actor)
+  {
+    Integration::SceneHolder window = Integration::SceneHolder::Get( actor );
+    if ( window )
+    {
+      rootActor = window.GetRootLayer();
+    }
+
+    parent = actor.GetParent();
+  }
+
+  while( parent && !IsLayoutControl(parent) && parent != rootActor )
+  {
+    parent = parent.GetParent();
+  }
+
+  return Toolkit::Control::DownCast(parent);
+}
+
+bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction)
+{
+  Actor currentFocusActor = GetCurrentFocusActor();
+
+  bool succeed = false;
+
+  // Go through the actor's hierarchy until we find a layout control that knows how to move the focus
+  Toolkit::Control parentLayoutControl = GetParentLayoutControl( currentFocusActor );
+  while( parentLayoutControl && !succeed )
+  {
+    succeed = DoMoveFocusWithinLayoutControl( parentLayoutControl, currentFocusActor, direction );
+    parentLayoutControl = GetParentLayoutControl( parentLayoutControl );
+  }
+
+  if( !succeed )
+  {
+    Actor nextFocusableActor;
+
+    Toolkit::Control currentFocusControl = Toolkit::Control::DownCast(currentFocusActor);
+
+    // If the current focused actor is a control, then find the next focusable actor via the focusable properties.
+    if( currentFocusControl )
+    {
+      int actorId = -1;
+      Property::Index index = Property::INVALID_INDEX;
+      Property::Value value;
+
+      // Find property index based upon focus direction
+      switch ( direction )
+      {
+        case Toolkit::Control::KeyboardFocus::LEFT:
+        {
+          index = Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID;
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::RIGHT:
+        {
+          index = Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID;
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::UP:
+        {
+          index = Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID;
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::DOWN:
+        {
+          index = Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID;
+          break;
+        }
+        default:
+          break;
+      }
+
+      // If the focusable property is set then determine next focusable actor
+      if( index != Property::INVALID_INDEX)
+      {
+        value = currentFocusActor.GetProperty( index );
+        actorId = value.Get<int>();
+
+        // If actor's id is valid then find actor form actor's id. The actor should be on the stage.
+        if( actorId != -1 )
+        {
+          if( currentFocusActor.GetParent() )
+          {
+            nextFocusableActor = currentFocusActor.GetParent().FindChildById( actorId );
+          }
+
+          if( !nextFocusableActor )
+          {
+            Integration::SceneHolder window = Integration::SceneHolder::Get( currentFocusActor );
+            if ( window )
+            {
+              nextFocusableActor = window.GetRootLayer().FindChildById( actorId );
+            }
+          }
+        }
+      }
+    }
+
+    if( !nextFocusableActor )
+    {
+      // If the implementation of CustomAlgorithmInterface is provided then the PreFocusChangeSignal is no longer emitted.
+      if( mCustomAlgorithmInterface )
+      {
+        mIsWaitingKeyboardFocusChangeCommit = true;
+        nextFocusableActor = mCustomAlgorithmInterface->GetNextFocusableActor( currentFocusActor, Actor(), direction );
+        mIsWaitingKeyboardFocusChangeCommit = false;
+      }
+      else if( !mPreFocusChangeSignal.Empty() )
+      {
+        // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to
+        mIsWaitingKeyboardFocusChangeCommit = true;
+        nextFocusableActor = mPreFocusChangeSignal.Emit( currentFocusActor, Actor(), direction );
+        mIsWaitingKeyboardFocusChangeCommit = false;
+      }
+    }
+
+    if( nextFocusableActor && nextFocusableActor.IsKeyboardFocusable() )
+    {
+      // Whether the next focusable actor is a layout control
+      if( IsLayoutControl( nextFocusableActor ) )
+      {
+        // If so, move the focus inside it.
+        Toolkit::Control layoutControl = Toolkit::Control::DownCast( nextFocusableActor) ;
+        succeed = DoMoveFocusWithinLayoutControl( layoutControl, currentFocusActor, direction );
+      }
+      else
+      {
+        // Otherwise, just set focus to the next focusable actor
+        succeed = SetCurrentFocusActor( nextFocusableActor );
+      }
+    }
+  }
+
+  return succeed;
+}
+
+bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocus::Direction direction)
+{
+  // Ask the control for the next actor to focus
+  Actor nextFocusableActor = GetImplementation( control ).GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled);
+  if(nextFocusableActor)
+  {
+    if(!nextFocusableActor.IsKeyboardFocusable())
+    {
+      // If the actor is not focusable, ask the same layout control for the next actor to focus
+      return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction);
+    }
+    else
+    {
+      Actor currentFocusActor = GetCurrentFocusActor();
+      Actor committedFocusActor = nextFocusableActor;
+
+      // We will try to move the focus to the actor. Emit a signal to notify the proposed actor to focus
+      // Signal handler can check the proposed actor and return a different actor if it wishes.
+      if( !mPreFocusChangeSignal.Empty() )
+      {
+        mIsWaitingKeyboardFocusChangeCommit = true;
+        committedFocusActor = mPreFocusChangeSignal.Emit(currentFocusActor, nextFocusableActor, direction);
+        mIsWaitingKeyboardFocusChangeCommit = false;
+      }
+
+      if (committedFocusActor && committedFocusActor.IsKeyboardFocusable())
+      {
+        // Whether the commited focusable actor is a layout control
+        if(IsLayoutControl(committedFocusActor))
+        {
+          // If so, move the focus inside it.
+          Toolkit::Control layoutControl = Toolkit::Control::DownCast(committedFocusActor);
+          return DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
+        }
+        else
+        {
+          // Otherwise, just set focus to the next focusable actor
+          if(committedFocusActor == nextFocusableActor)
+          {
+            // If the application hasn't changed our proposed actor, we informs the layout control we will
+            // move the focus to what the control returns. The control might wish to perform some actions
+            // before the focus is actually moved.
+            GetImplementation( control ).OnKeyboardFocusChangeCommitted( committedFocusActor );
+          }
+
+          return SetCurrentFocusActor(committedFocusActor);
+        }
+      }
+      else
+      {
+        return false;
+      }
+    }
+  }
+  else
+  {
+    // No more actor can be focused in the given direction within the same layout control.
+    return false;
+  }
+}
+
+bool KeyboardFocusManager::DoMoveFocusToNextFocusGroup(bool forward)
+{
+  bool succeed = false;
+
+  // Get the parent layout control of the current focus group
+  Toolkit::Control parentLayoutControl = GetParentLayoutControl(GetCurrentFocusGroup());
+
+  while(parentLayoutControl && !succeed)
+  {
+    // If the current focus group has a parent layout control, we can probably automatically
+    // move the focus to the next focus group in the forward or backward direction.
+    Toolkit::Control::KeyboardFocus::Direction direction = forward ? Toolkit::Control::KeyboardFocus::RIGHT : Toolkit::Control::KeyboardFocus::LEFT;
+    succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction);
+    parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
+  }
+
+  if(!mFocusGroupChangedSignal.Empty())
+  {
+    // Emit a focus group changed signal. The applicaton can move the focus to a new focus group
+    mFocusGroupChangedSignal.Emit(GetCurrentFocusActor(), forward);
+  }
+
+  return succeed;
+}
+
+void KeyboardFocusManager::DoKeyboardEnter(Actor actor)
+{
+  if( actor )
+  {
+    Toolkit::Control control = Toolkit::Control::DownCast( actor );
+    if( control )
+    {
+      // Notify the control that enter has been pressed on it.
+      GetImplementation( control ).KeyboardEnter();
+    }
+
+    // Send a notification for the actor.
+    if( !mFocusedActorEnterKeySignal.Empty() )
+    {
+      mFocusedActorEnterKeySignal.Emit( actor );
+    }
+  }
+}
+
+void KeyboardFocusManager::ClearFocus()
+{
+  Actor actor = GetCurrentFocusActor();
+  if( actor )
+  {
+    if( mFocusIndicatorActor )
+    {
+      actor.Remove( mFocusIndicatorActor );
+    }
+
+    // Send notification for the change of focus actor
+    if( !mFocusChangedSignal.Empty() )
+    {
+      mFocusChangedSignal.Emit( actor, Actor() );
+    }
+
+    Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast( actor );
+    if( currentlyFocusedControl )
+    {
+      currentlyFocusedControl.SetProperty( DevelControl::Property::STATE, DevelControl::NORMAL );
+      currentlyFocusedControl.ClearKeyInputFocus();
+    }
+  }
+
+  mCurrentFocusActor.Reset();
+  mIsFocusIndicatorShown = ( mAlwaysShowIndicator == ALWAYS_SHOW ) ? SHOW : HIDE;
+}
+
+void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
+{
+  mFocusGroupLoopEnabled = enabled;
+}
+
+bool KeyboardFocusManager::GetFocusGroupLoop() const
+{
+  return mFocusGroupLoopEnabled;
+}
+
+void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
+{
+  if(actor)
+  {
+    // Create/Set focus group property.
+    actor.RegisterProperty( IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE );
+  }
+}
+
+bool KeyboardFocusManager::IsFocusGroup(Actor actor) const
+{
+  // Check whether the actor is a focus group
+  bool isFocusGroup = false;
+
+  if(actor)
+  {
+    Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
+    if(propertyIsFocusGroup != Property::INVALID_INDEX)
+    {
+      isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
+    }
+  }
+
+  return isFocusGroup;
+}
+
+Actor KeyboardFocusManager::GetFocusGroup(Actor actor)
+{
+  // Go through the actor's hierarchy to check which focus group the actor belongs to
+  while (actor && !IsFocusGroup(actor))
+  {
+    actor = actor.GetParent();
+  }
+
+  return actor;
+}
+
+void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator)
+{
+  if(mFocusIndicatorActor != indicator)
+  {
+    Actor currentFocusActor = GetCurrentFocusActor();
+    if(currentFocusActor)
+    {
+      // The new focus indicator should be added to the current focused actor immediately
+      if(mFocusIndicatorActor)
+      {
+        currentFocusActor.Remove(mFocusIndicatorActor);
+      }
+
+      if(indicator)
+      {
+        currentFocusActor.Add(indicator);
+      }
+    }
+
+    mFocusIndicatorActor = indicator;
+  }
+}
+
+Actor KeyboardFocusManager::GetFocusIndicatorActor()
+{
+  if( ! mFocusIndicatorActor )
+  {
+    // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
+    const std::string imageDirPath = AssetManager::GetDaliImagePath();
+    mFocusIndicatorActor = Toolkit::ImageView::New( imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME );
+
+    // Apply size constraint to the focus indicator
+    mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+  }
+
+  mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
+  mFocusIndicatorActor.SetAnchorPoint( AnchorPoint::CENTER );
+  mFocusIndicatorActor.SetPosition(0.0f, 0.0f);
+
+  return mFocusIndicatorActor;
+}
+
+void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
+{
+  AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
+  bool isAccessibilityEnabled = accessibilityAdaptor.IsEnabled();
+
+  Toolkit::AccessibilityManager accessibilityManager = Toolkit::AccessibilityManager::Get();
+
+  std::string keyName = event.keyPressedName;
+
+  if( mIsFocusIndicatorShown == UNKNOWN )
+  {
+    GetConfigurationFromStyleManger();
+  }
+
+  bool isFocusStartableKey = false;
+
+  if(event.state == KeyEvent::Down)
+  {
+    if (keyName == "Left")
+    {
+      if(!isAccessibilityEnabled)
+      {
+        if(mIsFocusIndicatorShown == HIDE)
+        {
+          // Show focus indicator
+          mIsFocusIndicatorShown = SHOW;
+        }
+        else
+        {
+          // Move the focus towards left
+          MoveFocus(Toolkit::Control::KeyboardFocus::LEFT);
+        }
+
+        isFocusStartableKey = true;
+      }
+      else
+      {
+        // Move the accessibility focus backward
+        accessibilityManager.MoveFocusBackward();
+      }
+    }
+    else if (keyName == "Right")
+    {
+      if(!isAccessibilityEnabled)
+      {
+        if( mIsFocusIndicatorShown == HIDE )
+        {
+          // Show focus indicator
+          mIsFocusIndicatorShown = SHOW;
+        }
+        else
+        {
+          // Move the focus towards right
+          MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
+        }
+      }
+      else
+      {
+        // Move the accessibility focus forward
+        accessibilityManager.MoveFocusForward();
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Up" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // Move the focus towards up
+        MoveFocus(Toolkit::Control::KeyboardFocus::UP);
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Down" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // Move the focus towards down
+        MoveFocus(Toolkit::Control::KeyboardFocus::DOWN);
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Prior" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // Move the focus towards the previous page
+        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP);
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Next" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // Move the focus towards the next page
+        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN);
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Tab" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // "Tab" key changes the focus group in the forward direction and
+        // "Shift-Tab" key changes it in the backward direction.
+        DoMoveFocusToNextFocusGroup(!event.IsShiftModifier());
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "space" && !isAccessibilityEnabled)
+    {
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "" && !isAccessibilityEnabled)
+    {
+      // Check the fake key event for evas-plugin case
+      if( mIsFocusIndicatorShown == HIDE )
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+
+      isFocusStartableKey = true;
+    }
+    else if (keyName == "Backspace" && !isAccessibilityEnabled)
+    {
+      // Emit signal to go back to the previous view???
+    }
+    else if (keyName == "Escape" && !isAccessibilityEnabled)
+    {
+    }
+  }
+  else if(event.state == KeyEvent::Up)
+  {
+    if (keyName == "Return")
+    {
+      if((mIsFocusIndicatorShown == HIDE) && !isAccessibilityEnabled)
+      {
+        // Show focus indicator
+        mIsFocusIndicatorShown = SHOW;
+      }
+      else
+      {
+        // The focused actor has enter pressed on it
+        Actor actor;
+        if( !isAccessibilityEnabled )
+        {
+          actor = GetCurrentFocusActor();
+        }
+        else
+        {
+          actor = accessibilityManager.GetCurrentFocusActor();
+        }
+
+        if( actor )
+        {
+          DoKeyboardEnter( actor );
+        }
+      }
+
+      isFocusStartableKey = true;
+    }
+  }
+
+  if(isFocusStartableKey && ( mIsFocusIndicatorShown == SHOW ) && !isAccessibilityEnabled)
+  {
+    Actor actor = GetCurrentFocusActor();
+    if( actor )
+    {
+      if( mEnableFocusIndicator == ENABLE )
+      {
+        // Make sure the focused actor is highlighted
+        actor.Add( GetFocusIndicatorActor() );
+      }
+    }
+    else
+    {
+      // No actor is focused but keyboard focus is activated by the key press
+      // Let's try to move the initial focus
+      MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
+    }
+  }
+}
+
+void KeyboardFocusManager::OnTouch(const TouchData& touch)
+{
+  // if mIsFocusIndicatorShown is UNKNOWN, it means Configuration is not loaded.
+  // Try to load configuration.
+  if( mIsFocusIndicatorShown == UNKNOWN )
+  {
+    GetConfigurationFromStyleManger();
+  }
+
+  // Clear the focus when user touch the screen.
+  // We only do this on a Down event, otherwise the clear action may override a manually focused actor.
+  // If mClearFocusOnTouch is false, do not clear the focus even if user touch the screen.
+  if( (( touch.GetPointCount() < 1 ) || ( touch.GetState( 0 ) == PointState::DOWN )) && mClearFocusOnTouch )
+  {
+    ClearFocus();
+  }
+}
+
+void KeyboardFocusManager::OnWindowFocusChanged(Window window, bool focusIn )
+{
+  if( focusIn && mCurrentFocusedWindow.GetHandle() != window.GetRootLayer() )
+  {
+    // Change Current Focused Window
+    Layer rootLayer = window.GetRootLayer();
+    mCurrentFocusedWindow = rootLayer;
+
+    // Get Current Focused Actor from window
+    Actor currentFocusedActor = GetFocusActorFromCurrentWindow();
+    SetCurrentFocusActor( currentFocusedActor );
+
+    if( currentFocusedActor && ( mEnableFocusIndicator == ENABLE ) )
+    {
+      // Make sure the focused actor is highlighted
+      currentFocusedActor.Add( GetFocusIndicatorActor() );
+      mIsFocusIndicatorShown = SHOW;
+    }
+  }
+}
+
+Toolkit::KeyboardFocusManager::PreFocusChangeSignalType& KeyboardFocusManager::PreFocusChangeSignal()
+{
+  return mPreFocusChangeSignal;
+}
+
+Toolkit::KeyboardFocusManager::FocusChangedSignalType& KeyboardFocusManager::FocusChangedSignal()
+{
+  return mFocusChangedSignal;
+}
+
+Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType& KeyboardFocusManager::FocusGroupChangedSignal()
+{
+  return mFocusGroupChangedSignal;
+}
+
+Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType& KeyboardFocusManager::FocusedActorEnterKeySignal()
+{
+  return mFocusedActorEnterKeySignal;
+}
+
+bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  KeyboardFocusManager* manager = static_cast< KeyboardFocusManager* >( object ); // TypeRegistry guarantees that this is the correct type.
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_PRE_FOCUS_CHANGE ) )
+  {
+    manager->PreFocusChangeSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
+  {
+    manager->FocusChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED ) )
+  {
+    manager->FocusGroupChangedSignal().Connect( tracker, functor );
+  }
+  else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ENTER_KEY ) )
+  {
+    manager->FocusedActorEnterKeySignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+void KeyboardFocusManager::SetCustomAlgorithm(CustomAlgorithmInterface& interface)
+{
+  mCustomAlgorithmInterface = &interface;
+}
+
+void KeyboardFocusManager::EnableFocusIndicator(bool enable)
+{
+  if( !enable && mFocusIndicatorActor )
+  {
+    mFocusIndicatorActor.Unparent();
+  }
+
+  mEnableFocusIndicator = enable? ENABLE : DISABLE;
+
+}
+
+bool KeyboardFocusManager::IsFocusIndicatorEnabled() const
+{
+  return ( mEnableFocusIndicator == ENABLE );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h
new file mode 100644 (file)
index 0000000..176bfce
--- /dev/null
@@ -0,0 +1,371 @@
+#ifndef DALI_TOOLKIT_INTERNAL_KEYBOARD_FOCUS_MANAGER_H
+#define DALI_TOOLKIT_INTERNAL_KEYBOARD_FOCUS_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+#include <dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+class SceneHolder;
+
+} // namespace Integration
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @copydoc Toolkit::KeyboardFocusManager
+ */
+class KeyboardFocusManager : public Dali::BaseObject, public ConnectionTracker
+{
+public:
+
+  typedef Toolkit::DevelKeyboardFocusManager::CustomAlgorithmInterface CustomAlgorithmInterface;
+
+  enum FocusIndicatorState
+  {
+    UNKNOWN = -1,   ///< Unknown state
+    HIDE = 0,          ///< FocusIndicator is hidden
+    SHOW = 1,          ///< FocusIndicator is shown
+  };
+
+  enum EnableFocusedIndicatorState
+  {
+    DISABLE = 0,          ///< FocusIndicator is disable
+    ENABLE = 1,          ///< FocusIndicator is enable
+  };
+
+  enum FocusedIndicatorModeState
+  {
+    NONE = 0,          ///< Set nothing
+    ALWAYS_SHOW = 1,          ///< FocusIndicator is always shown
+  };
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::Get
+   */
+  static Toolkit::KeyboardFocusManager Get();
+
+  /**
+   * Construct a new KeyboardFocusManager.
+   */
+  KeyboardFocusManager();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::SetCurrentFocusActor
+   */
+  bool SetCurrentFocusActor(Actor actor);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::GetCurrentFocusActor
+   */
+  Actor GetCurrentFocusActor();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::MoveFocus
+   */
+  bool MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::ClearFocus
+   */
+  void ClearFocus();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::SetAsFocusGroup
+   */
+  void SetAsFocusGroup(Actor actor, bool isFocusGroup);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::IsFocusGroup
+   */
+  bool IsFocusGroup(Actor actor) const;
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::GetFocusGroup
+   */
+  Actor GetFocusGroup(Actor actor);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::SetFocusGroupLoop
+   */
+  void SetFocusGroupLoop(bool enabled);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::GetFocusGroupLoop
+   */
+  bool GetFocusGroupLoop() const;
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::SetFocusIndicatorActor
+   */
+  void SetFocusIndicatorActor(Actor indicator);
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::GetFocusIndicatorActor
+   */
+  Actor GetFocusIndicatorActor();
+
+  /**
+   * Move current focus to backward
+   */
+  void MoveFocusBackward();
+
+  /**
+   * @copydoc Toolkit::DevelKeyboardFocusManager::SetCustomAlgorithm
+   */
+  void SetCustomAlgorithm(CustomAlgorithmInterface& interface);
+
+  /**
+   * @copydoc Toolkit::DevelKeyboardFocusManager::UseFocusIndicator
+   */
+  void EnableFocusIndicator(bool enable);
+
+  /**
+   * @copydoc Toolkit::DevelKeyboardFocusManager::UseFocusIndicator
+   */
+  bool IsFocusIndicatorEnabled() const;
+
+public:
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::PreFocusChangeSignal()
+   */
+  Toolkit::KeyboardFocusManager::PreFocusChangeSignalType& PreFocusChangeSignal();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::FocusChangedSignal()
+   */
+  Toolkit::KeyboardFocusManager::FocusChangedSignalType& FocusChangedSignal();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::FocusGroupChangedSignal()
+   */
+  Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType& FocusGroupChangedSignal();
+
+  /**
+   * @copydoc Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignal()
+   */
+  Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType& FocusedActorEnterKeySignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+  /**
+   * Destructor
+   */
+  virtual ~KeyboardFocusManager();
+
+private:
+
+  typedef std::vector< WeakHandle< Actor > > FocusStack; ///< Define Dali::Vector< Dali::BaseObject* > as FocusStack to contain focus history
+  typedef FocusStack::iterator FocusStackIterator; ///< Define FocusStack::Iterator as FocusStackIterator to navigate FocusStack
+
+  /**
+   * This will be called when the adaptor is initialized
+   */
+  void OnAdaptorInit();
+
+  /**
+   * This will be called when a new scene holder is created
+   * @param sceneHolder The new scene holder
+   */
+  void OnSceneHolderCreated( Dali::Integration::SceneHolder& sceneHolder );
+
+  /**
+   * Get configuration from StyleManager.
+   */
+  void GetConfigurationFromStyleManger();
+
+  /**
+   * Get the focus group of current focused actor.
+   * @pre The FocusManager has been initialized.
+   * @return A handle to the parent of the current focused actor which is a focus group,
+   * or an empty handle if no actor is focused.
+   */
+  Actor GetCurrentFocusGroup();
+
+  /**
+   * Move the focus to the specified actor and send notification for the focus change.
+   * @param actor The actor to be queried
+   * @return Whether the focus is successful or not
+   */
+  bool DoSetCurrentFocusActor(Actor actor);
+
+  /**
+   * Move the focus to the next actor towards the specified direction within the layout control
+   * @param control The layout control to move the focus in
+   * @param actor The current focused actor
+   * @param direction The direction of focus movement
+   * @return Whether the focus is successful or not
+   */
+  bool DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocus::Direction direction);
+
+  /**
+   * Move the focus to the first focusable actor in the next focus group in the forward
+   * or backward direction. The "Tab" key changes the focus group in the forward direction
+   * and the "Shift-Tab" key changes it in the backward direction.
+   * @param forward Whether the direction of focus group change is forward or backward
+   * @return Whether the focus group change is successful or not
+   */
+  bool DoMoveFocusToNextFocusGroup(bool forward);
+
+  /**
+   * Enter has been pressed on the actor. If the actor is control, call the OnKeybaordEnter virtual function.
+   * This function will emit FocusedActorEnterKeySignal.
+   * @param actor The actor to notify
+   */
+  void DoKeyboardEnter( Actor actor );
+
+  /**
+   * Check whether the actor is a layout control that supports two dimensional keyboard navigation.
+   * The layout control needs to internally set the focus order for the child actor and be able to
+   * tell KeyboardFocusmanager the next focusable actor in the given direction.
+   * @pre The KeyboardFocusManager has been initialized.
+   * @pre The Actor has been initialized.
+   * @param actor The actor to be checked.
+   * @return Whether the actor is a layout control or not.
+   */
+  bool IsLayoutControl(Actor actor) const;
+
+  /**
+   * Returns the closest ancestor of the given actor that is a layout control.
+   * @param actor The actor to be checked for its parent layout control
+   * @return The parent layout control the given actor belongs to or an empty handle if the given actor doesn't belong to a layout control
+   */
+ Toolkit::Control GetParentLayoutControl(Actor actor) const;
+
+  /**
+   * Callback for the key event when no actor in the stage has gained the key input focus
+   * @param[in] event The KeyEvent event.
+   */
+  void OnKeyEvent( const KeyEvent& event );
+
+  /**
+   * Callback for the touch event when the screen is touched and when the touch ends
+   * (i.e. the down & up touch events only).
+   * @param[in] touch The touch information
+   */
+  void OnTouch( const TouchData& touch );
+
+  /**
+   * Called when the window focus is changed.
+   * @param[in] window The window whose focus is changed
+   * @param[in] focusIn Whether the focus is in/out
+   */
+  void OnWindowFocusChanged( Window window, bool focusIn );
+
+  /**
+   * Get the focus Actor from current window
+   */
+  Actor GetFocusActorFromCurrentWindow();
+
+private:
+
+  // Undefined
+  KeyboardFocusManager(const KeyboardFocusManager&);
+
+  KeyboardFocusManager& operator=(const KeyboardFocusManager& rhs);
+
+private:
+
+  Toolkit::KeyboardFocusManager::PreFocusChangeSignalType mPreFocusChangeSignal; ///< The signal to notify the focus will be changed
+  Toolkit::KeyboardFocusManager::FocusChangedSignalType mFocusChangedSignal; ///< The signal to notify the focus change
+  Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType mFocusGroupChangedSignal; ///< The signal to notify the focus group change
+  Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType mFocusedActorEnterKeySignal; ///< The signal to notify that enter has been pressed on the focused actor
+
+  WeakHandle< Actor > mCurrentFocusActor; ///< A weak handle to the current focused actor
+
+  Actor mFocusIndicatorActor; ///< The focus indicator actor shared by all the keyboard focusable actors for highlight
+
+  FocusStack mFocusHistory; ///< Stack to contain pre-focused actor's BaseObject*
+
+  SlotDelegate< KeyboardFocusManager > mSlotDelegate;
+
+  CustomAlgorithmInterface* mCustomAlgorithmInterface; ///< The user's (application / toolkit) implementation of CustomAlgorithmInterface
+
+  typedef std::vector< std::pair< WeakHandle< Layer >, WeakHandle< Actor > > > FocusActorContainer;
+
+  FocusActorContainer mCurrentFocusActors; ///< A container of focused actors
+
+  WeakHandle< Layer > mCurrentFocusedWindow; ///< A weak handle to the current focused window's root layer
+
+  FocusIndicatorState mIsFocusIndicatorShown; ///< Whether indicator should be shown / hidden when getting focus. It could be enabled when keyboard focus feature is enabled and navigation keys or 'Tab' key are pressed.
+
+  EnableFocusedIndicatorState mEnableFocusIndicator;  ///< Whether use focus indicator
+
+  FocusedIndicatorModeState mAlwaysShowIndicator; ///< Whether always show indicator. If true, the indicator would be directly shown when focused
+
+  bool mFocusGroupLoopEnabled:1; ///< Whether the focus movement is looped within the same focus group
+
+  bool mIsWaitingKeyboardFocusChangeCommit:1; /// A flag to indicate PreFocusChangeSignal emitted but the proposed focus actor is not commited by the application yet.
+
+  bool mClearFocusOnTouch:1; ///< Whether clear focus on touch.
+};
+
+} // namespace Internal
+
+inline Internal::KeyboardFocusManager& GetImpl(Dali::Toolkit::KeyboardFocusManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::KeyboardFocusManager&>(handle);
+}
+
+inline const Internal::KeyboardFocusManager& GetImpl(const Dali::Toolkit::KeyboardFocusManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::KeyboardFocusManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_KEYBOARD_FOCUS_MANAGER_H
diff --git a/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp b/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.cpp
new file mode 100644 (file)
index 0000000..6b95600
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2019 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 "keyinput-focus-manager-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/common/stage-devel.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Signals
+
+const char* const SIGNAL_KEY_INPUT_FOCUS_CHANGED = "keyInputFocusChanged";
+
+}
+
+KeyInputFocusManager::KeyInputFocusManager()
+: mSlotDelegate( this ),
+  mCurrentFocusControl()
+{
+  // Retrieve all the existing widnows
+  Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
+  for( auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter )
+  {
+    ( *iter ).KeyEventGeneratedSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnKeyEvent );
+  }
+
+  // Get notified when any new scene holder is created afterwards
+  Adaptor::Get().WindowCreatedSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnSceneHolderCreated );
+}
+
+KeyInputFocusManager::~KeyInputFocusManager()
+{
+}
+
+void KeyInputFocusManager::OnSceneHolderCreated( Dali::Integration::SceneHolder& sceneHolder )
+{
+  sceneHolder.KeyEventGeneratedSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnKeyEvent );
+}
+
+void KeyInputFocusManager::SetFocus( Toolkit::Control control )
+{
+  if( !control )
+  {
+    // No-op
+    return;
+  }
+
+  if( control == mCurrentFocusControl )
+  {
+    // Control already has focus
+    return;
+  }
+
+  control.OffStageSignal().Connect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
+
+  Dali::Toolkit::Control previousFocusControl = GetCurrentFocusControl();
+  if( previousFocusControl )
+  {
+    // Notify the control that it has lost key input focus
+    GetImplementation( previousFocusControl ).OnKeyInputFocusLost();
+  }
+
+  // Set control to currentFocusControl
+  mCurrentFocusControl = control;
+
+  // Tell the new actor that it has gained focus.
+  GetImplementation( control ).OnKeyInputFocusGained();
+
+  // Emit the signal to inform focus change to the application.
+  if ( !mKeyInputFocusChangedSignal.Empty() )
+  {
+    mKeyInputFocusChangedSignal.Emit( control, previousFocusControl );
+  }
+}
+
+void KeyInputFocusManager::RemoveFocus( Toolkit::Control control )
+{
+  if( control == mCurrentFocusControl )
+  {
+    control.OffStageSignal().Disconnect( mSlotDelegate, &KeyInputFocusManager::OnFocusControlStageDisconnection );
+
+    // Notify the control that it has lost key input focus
+    GetImplementation( control ).OnKeyInputFocusLost();
+
+    mCurrentFocusControl.Reset();
+  }
+}
+
+Toolkit::Control KeyInputFocusManager::GetCurrentFocusControl() const
+{
+  return mCurrentFocusControl;
+}
+
+Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusManager::KeyInputFocusChangedSignal()
+{
+  return mKeyInputFocusChangedSignal;
+}
+
+bool KeyInputFocusManager::OnKeyEvent( const KeyEvent& event )
+{
+  bool consumed = false;
+
+  Toolkit::Control control = GetCurrentFocusControl();
+  if( control )
+  {
+    // Notify the control about the key event
+    consumed = EmitKeyEventSignal( control, event );
+  }
+
+  return consumed;
+}
+
+bool KeyInputFocusManager::EmitKeyEventSignal( Toolkit::Control control, const KeyEvent& event )
+{
+  bool consumed = false;
+
+  if( control )
+  {
+    consumed = GetImplementation( control ).EmitKeyEventSignal( event );
+
+    // if control doesn't consume KeyEvent, give KeyEvent to its parent.
+    if( !consumed )
+    {
+      Toolkit::Control parent = Toolkit::Control::DownCast( control.GetParent() );
+
+      if( parent )
+      {
+        consumed = EmitKeyEventSignal( parent, event );
+      }
+    }
+  }
+
+  return consumed;
+}
+
+void KeyInputFocusManager::OnFocusControlStageDisconnection( Dali::Actor actor )
+{
+  RemoveFocus( Dali::Toolkit::Control::DownCast( actor ) );
+}
+
+
+bool KeyInputFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  KeyInputFocusManager* manager = dynamic_cast<KeyInputFocusManager*>( object );
+
+  if( manager )
+  {
+    if( 0 == strcmp( signalName.c_str(), SIGNAL_KEY_INPUT_FOCUS_CHANGED ) )
+    {
+      manager->KeyInputFocusChangedSignal().Connect( tracker, functor );
+    }
+    else
+    {
+      // signalName does not match any signal
+      connected = false;
+    }
+  }
+
+  return connected;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h b/dali-toolkit/internal/focus-manager/keyinput-focus-manager-impl.h
new file mode 100644 (file)
index 0000000..ab83e37
--- /dev/null
@@ -0,0 +1,167 @@
+#ifndef DALI_TOOLKIT_INTERNAL_KEYINPUT_FOCUS_MANAGER_H
+#define DALI_TOOLKIT_INTERNAL_KEYINPUT_FOCUS_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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/public-api/object/base-object.h>
+#include <dali/public-api/object/object-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+class SceneHolder;
+
+} // namespace Integration
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class KeyInputFocusManager;
+
+/**
+ * @copydoc Toolkit::KeyInputFocusManager
+ */
+class KeyInputFocusManager : public Dali::BaseObject, public Dali::ConnectionTracker
+{
+public:
+  /**
+   * Construct a new KeyInputFocusManager.
+   */
+  KeyInputFocusManager();
+
+  /**
+   * @copydoc Toolkit::SetFocus
+   */
+  void SetFocus(Toolkit::Control control);
+
+  /**
+   * @copydoc Toolkit::RemoveFocus
+   */
+  void RemoveFocus(Toolkit::Control control);
+
+  /**
+   * @copydoc Toolkit::GetCurrentFocusControl
+   */
+  Toolkit::Control GetCurrentFocusControl() const;
+
+public:
+
+  /**
+   * @copydoc Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignal()
+   */
+  Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType& KeyInputFocusChangedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+
+  /**
+   * Destructor
+   */
+  virtual ~KeyInputFocusManager();
+
+private:
+  /**
+   * This will be called when a new scene holder is created
+   * @param sceneHolder The new scene holder
+   */
+  void OnSceneHolderCreated( Dali::Integration::SceneHolder& sceneHolder );
+
+  /**
+   * Callback for the key event when no actor in the stage has gained the key input focus
+   * @param[in] event The KeyEvent event.
+   */
+  bool OnKeyEvent(const KeyEvent& event);
+
+  /**
+   * Signal handler called when a focused Control is removed from Stage.
+   * @param[in]  control  The control removed from stage.
+   */
+  void OnFocusControlStageDisconnection( Dali::Actor control );
+
+  /**
+    *  Recursively deliver events to the control and its parents, until the event is consumed or the stage is reached.
+   * @param[in]  control  The control got KeyEvent.
+   * @param[in]  event    The KeyEvent.
+   * @return True if KeyEvent is consumed.
+    */
+  bool EmitKeyEventSignal( Toolkit::Control control, const KeyEvent& event );
+
+private:
+
+  // Undefined
+  KeyInputFocusManager(const KeyInputFocusManager&);
+
+  KeyInputFocusManager& operator=(const KeyInputFocusManager& rhs);
+
+private:
+
+  // The key input focus change signal
+  Toolkit::KeyInputFocusManager::KeyInputFocusChangedSignalType mKeyInputFocusChangedSignal;
+
+  SlotDelegate< KeyInputFocusManager > mSlotDelegate;
+
+  Toolkit::Control mCurrentFocusControl; ///< The current focused control
+};
+
+} // namespace Internal
+
+inline Internal::KeyInputFocusManager& GetImpl(Dali::Toolkit::KeyInputFocusManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<Internal::KeyInputFocusManager&>(handle);
+}
+
+inline const Internal::KeyInputFocusManager& GetImpl(const Dali::Toolkit::KeyInputFocusManager& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast<const Internal::KeyInputFocusManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_KEYINPUT_FOCUS_MANAGER_H
diff --git a/dali-toolkit/internal/helpers/color-conversion.cpp b/dali-toolkit/internal/helpers/color-conversion.cpp
new file mode 100644 (file)
index 0000000..6789cee
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/helpers/color-conversion.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/public-api/math/vector4.h>
+#include <dali/devel-api/adaptor-framework/color-controller.h>
+
+using Dali::Vector4;
+
+namespace
+{
+
+/**
+ * Converts a HTML style 'color' hex string ("#FF0000" for bright red) to a Vector4.
+ * The Vector4 alpha component will be set to 1.0f
+ * @param hexString The HTML style hex string
+ * @return a Vector4 containing the new color value
+ */
+Vector4 HexStringToVector4( const char* s )
+{
+  unsigned int value(0u);
+  std::istringstream( s ) >> std::hex >> value;
+  return Vector4( ((value >> 16 ) & 0xff ) / 255.0f,
+                  ((value >> 8 ) & 0xff ) / 255.0f,
+                  (value & 0xff ) / 255.0f,
+                  1.0f );
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+bool ConvertStringToColor( const std::string& colorString, Vector4& outColor )
+{
+  bool success( false );
+
+  if( ( '#' == colorString[0] ) &&
+      (  7  == colorString.size() ) )
+  {
+    const char* cString = colorString.c_str();
+    outColor = HexStringToVector4( &cString[1] );
+    success = true;
+  }
+  else
+  {
+    Dali::ColorController controller = Dali::ColorController::Get();
+
+    if( controller )
+    {
+      success = controller.RetrieveColor( colorString, outColor );
+    }
+  }
+
+  return success;
+}
+
+bool ConvertPropertyToColor( const Property::Value& colorValue, Vector4& outColor )
+{
+  bool success( false );
+
+  if( Property::VECTOR4 == colorValue.GetType() )
+  {
+    success = colorValue.Get( outColor );
+  }
+  else if( Property::STRING == colorValue.GetType() )
+  {
+    std::string colorString;
+    if( colorValue.Get( colorString ) )
+    {
+      success = ConvertStringToColor( colorString, outColor );
+    }
+  }
+
+  return success;
+}
+
+} // Internal
+} // Toolkit
+} // Dali
diff --git a/dali-toolkit/internal/helpers/color-conversion.h b/dali-toolkit/internal/helpers/color-conversion.h
new file mode 100644 (file)
index 0000000..2838dc3
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_TOOLKIT_INTERNAL_COLOR_CONVERSION_H
+#define DALI_TOOLKIT_INTERNAL_COLOR_CONVERSION_H
+
+/*
+ * Copyright (c) 2019 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/public-api/object/property.h>
+
+namespace Dali
+{
+
+struct Vector4;
+
+namespace Toolkit
+{
+namespace Internal
+{
+
+/*
+ * @brief Convert the string representation of a color into a Vector4.
+ *
+ * The supported string formats are:
+ * 1) An HTML style 'color' hex string ("#FF0000" for bright red).
+ * 2) An ID referring to the color palette of the current theme e.g. "B018"
+ *
+ * @param[in] colorString The color in string format.
+ * @param[out] outColor The color if found.
+ * @return True if the conversion was successful.
+ */
+bool ConvertStringToColor( const std::string& colorString, Vector4& outColor );
+
+/*
+ * @brief Convert a variety of different color representations into a Vector4.
+ *
+ * @param[in] colorValue The color in Vector4 or string format.
+ * @param[out] outColor The color if found.
+ * @return True if the conversion was successful.
+ */
+bool ConvertPropertyToColor( const Property::Value& colorValue, Vector4& outColor );
+
+} // Internal
+} // Toolkit
+} // Dali
+
+
+#endif // DALI_TOOLKIT_INTERNAL_COLOR_CONVERSION_H
diff --git a/dali-toolkit/internal/helpers/property-helper.cpp b/dali-toolkit/internal/helpers/property-helper.cpp
new file mode 100644 (file)
index 0000000..94be023
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// HEADER
+#include <dali-toolkit/internal/helpers/property-helper.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+bool GetStringFromProperty( const Property::Value& value, std::string& output )
+{
+  bool extracted = false;
+  if( value.Get( output ) )
+  {
+    extracted = true;
+  }
+  else
+  {
+    Property::Array* array = value.GetArray();
+    if( array )
+    {
+      const unsigned int arraySize = array->Size();
+      for( unsigned int i = 0; i < arraySize; ++i )
+      {
+        std::string element;
+        if( array->GetElementAt( i ).Get( element ) )
+        {
+          extracted = true;
+          output += element + '\n';
+        }
+        else
+        {
+          // If property in array is anything other than a string, then it is invalid so break and clear output.
+          output.clear();
+          extracted = false;
+          break;
+        }
+      }
+    }
+  }
+
+  return extracted;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/helpers/property-helper.h b/dali-toolkit/internal/helpers/property-helper.h
new file mode 100644 (file)
index 0000000..e91062d
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PROPERTY_HELPER_H
+#define DALI_TOOLKIT_INTERNAL_PROPERTY_HELPER_H
+
+/*
+ * Copyright (c) 2017 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/public-api/object/property.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Parses a Property::Value to retrieve the string.
+ *
+ * If value is a Property::STRING, then it simply extracts the required string.
+ * If value is a Property::ARRAY, then it combines all the strings it contains into one adding a newline character to each line.
+ * The second option allows users to write long strings over several lines in a JSON file.
+ *
+ * @return True if a string was extracted successfully.
+ */
+bool GetStringFromProperty( const Property::Value& value, std::string& output );
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_INTERNAL_PROPERTY_HELPER_H
diff --git a/dali-toolkit/internal/helpers/round-robin-container-view.h b/dali-toolkit/internal/helpers/round-robin-container-view.h
new file mode 100644 (file)
index 0000000..c3619f9
--- /dev/null
@@ -0,0 +1,124 @@
+
+#ifndef DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
+#define DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
+
+/*
+ * Copyright (c) 2017 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 <cstddef>
+#include <vector>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * @brief RoundRobinContainerView is a view to a container that allows iterating through the elements cyclically.
+ */
+template<typename T>
+class RoundRobinContainerView
+{
+public:
+  using ContainerType = std::vector<T>;
+
+  /**
+   * @brief Constructs a new RoundRobinControlView with the given number elements using the provided factory.
+   * @param[in] numberOfElements The number of elements in the container
+   * @param[in] factory          Factory function of functor that will be used to create instances of the elements
+   */
+  template<typename FactoryType>
+  RoundRobinContainerView(size_t numberOfElements, const FactoryType& factory)
+  : mElements(),
+    mNextIndex{}
+  {
+    mElements.reserve(numberOfElements);
+    for(unsigned i = {}; i < numberOfElements; ++i)
+    {
+      mElements.push_back(factory());
+    }
+  }
+
+  /**
+   * @brief Reset the position of the iterator returned by GetNext() to the first element.
+   */
+  void Reset()
+  {
+    mNextIndex = 0u;
+  }
+
+  /**
+   * @brief Returns the next element on the container.
+   * @return Iterator for the next element
+   */
+  typename ContainerType::iterator GetNext()
+  {
+    SetValidNextIndex();
+
+    return mElements.begin() + mNextIndex++;
+  }
+
+  /**
+   * @brief Returns the iterator to the end of the container.
+   *
+   * Can be used to compare against GetNext() to check if the container is empty.
+   *
+   * @return The container end() element
+   */
+  typename ContainerType::const_iterator End() const
+  {
+    return mElements.cend();
+  }
+
+  // default members
+  ~RoundRobinContainerView() = default;
+
+  RoundRobinContainerView(const RoundRobinContainerView&)  = delete;
+  RoundRobinContainerView& operator=(const RoundRobinContainerView&)  = delete;
+  RoundRobinContainerView(RoundRobinContainerView&&) = default;
+  RoundRobinContainerView& operator=(RoundRobinContainerView&&) = default;
+
+private:
+  /**
+   * @brief Check the current index and reset if necessary.
+   */
+  void SetValidNextIndex()
+  {
+    if(mNextIndex >= mElements.size())
+    {
+      Reset();
+    }
+  }
+
+private:
+  ContainerType mElements; //< container of elements
+  size_t mNextIndex;       //< index to the next element to be viewed
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_INTERNAL_ROUND_ROBIN_CONTAINER_VIEW_H
diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp b/dali-toolkit/internal/image-loader/async-image-loader-impl.cpp
new file mode 100644 (file)
index 0000000..6fe8eba
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019 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 "async-image-loader-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+AsyncImageLoader::AsyncImageLoader()
+: mLoadedSignal(),
+  mLoadThread( new EventThreadCallback( MakeCallback( this, &AsyncImageLoader::ProcessLoadedImage ) ) ),
+  mLoadTaskId( 0u ),
+  mIsLoadThreadStarted( false )
+{
+}
+
+AsyncImageLoader::~AsyncImageLoader()
+{
+  mLoadThread.CancelAll();
+}
+
+IntrusivePtr<AsyncImageLoader> AsyncImageLoader::New()
+{
+  IntrusivePtr<AsyncImageLoader> internal = new AsyncImageLoader();
+  return internal;
+}
+
+uint32_t AsyncImageLoader::Load( const VisualUrl& url,
+                                 ImageDimensions dimensions,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection,
+                                 DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+{
+  if( !mIsLoadThreadStarted )
+  {
+    mLoadThread.Start();
+    mIsLoadThreadStarted = true;
+  }
+  mLoadThread.AddTask( new LoadingTask( ++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad ) );
+
+  return mLoadTaskId;
+}
+
+uint32_t AsyncImageLoader::ApplyMask( Devel::PixelBuffer pixelBuffer,
+                                      Devel::PixelBuffer maskPixelBuffer,
+                                      float contentScale,
+                                      bool cropToMask,
+                                      DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+{
+  if( !mIsLoadThreadStarted )
+  {
+    mLoadThread.Start();
+    mIsLoadThreadStarted = true;
+  }
+  mLoadThread.AddTask( new LoadingTask( ++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad ) );
+
+  return mLoadTaskId;
+}
+
+Toolkit::AsyncImageLoader::ImageLoadedSignalType& AsyncImageLoader::ImageLoadedSignal()
+{
+  return mLoadedSignal;
+}
+
+Toolkit::DevelAsyncImageLoader::PixelBufferLoadedSignalType& AsyncImageLoader::PixelBufferLoadedSignal()
+{
+  return mPixelBufferLoadedSignal;
+}
+
+bool AsyncImageLoader::Cancel( uint32_t loadingTaskId )
+{
+  return mLoadThread.CancelTask( loadingTaskId );
+}
+
+void AsyncImageLoader::CancelAll()
+{
+  mLoadThread.CancelAll();
+}
+
+void AsyncImageLoader::ProcessLoadedImage()
+{
+  while( LoadingTask *next = mLoadThread.NextCompletedTask() )
+  {
+    if( mPixelBufferLoadedSignal.GetConnectionCount() > 0 )
+    {
+      mPixelBufferLoadedSignal.Emit( next->id, next->pixelBuffer );
+    }
+    else if( mLoadedSignal.GetConnectionCount() > 0 )
+    {
+      PixelData pixelData;
+      if( next->pixelBuffer )
+      {
+        pixelData = Devel::PixelBuffer::Convert( next->pixelBuffer );
+      }
+      mLoadedSignal.Emit( next->id, pixelData );
+    }
+
+    delete next;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/async-image-loader-impl.h b/dali-toolkit/internal/image-loader/async-image-loader-impl.h
new file mode 100644 (file)
index 0000000..a97088d
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H
+#define DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/image-loader/image-load-thread.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AsyncImageLoader : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  AsyncImageLoader();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::New()
+   */
+  static IntrusivePtr<AsyncImageLoader> New();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::Load( const std::string&, ImageDimensions, FittingMode::Type, SamplingMode::Type, bool , DevelAsyncImageLoader::PreMultiplyOnLoad )
+   */
+  uint32_t Load( const VisualUrl& url,
+                 ImageDimensions dimensions,
+                 FittingMode::Type fittingMode,
+                 SamplingMode::Type samplingMode,
+                 bool orientationCorrection,
+                 DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
+
+  /**
+   * @brief Starts an mask applying task.
+   * @param[in] pixelBuffer of the to be masked image
+   * @param[in] maskPixelBuffer of the mask image
+   * @param[in] contentScale The factor to scale the content
+   * @param[in] cropToMask Whether to crop the content to the mask size
+   * @param[in] preMultiplyOnLoad ON if the image color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+   * @return The loading task id
+   */
+  uint32_t ApplyMask( Devel::PixelBuffer pixelBuffer,
+                      Devel::PixelBuffer maskPixelBuffer,
+                      float contentScale,
+                      bool cropToMask,
+                      DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::ImageLoadedSignal
+   */
+  Toolkit::AsyncImageLoader::ImageLoadedSignalType& ImageLoadedSignal();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::PixelBufferLoadedSignal
+   */
+  Toolkit::DevelAsyncImageLoader::PixelBufferLoadedSignalType& PixelBufferLoadedSignal();
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::Cancel
+   */
+  bool Cancel( uint32_t loadingTaskId );
+
+  /**
+   * @copydoc Toolkit::AsyncImageLoader::CancelAll
+   */
+  void CancelAll();
+
+  /**
+   * Process the completed loading task from the worker thread.
+   */
+  void ProcessLoadedImage();
+
+protected:
+
+  /**
+   * Destructor
+   */
+  ~AsyncImageLoader();
+
+private:
+  Toolkit::AsyncImageLoader::ImageLoadedSignalType mLoadedSignal;
+  Toolkit::DevelAsyncImageLoader::PixelBufferLoadedSignalType mPixelBufferLoadedSignal;
+
+  ImageLoadThread mLoadThread;
+  uint32_t        mLoadTaskId;
+  bool            mIsLoadThreadStarted;
+};
+
+} // namespace Internal
+
+inline const Internal::AsyncImageLoader& GetImplementation( const Toolkit::AsyncImageLoader& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "AsyncImageLoader handle is empty" );
+
+  const BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<const Internal::AsyncImageLoader&>( object );
+}
+
+inline Internal::AsyncImageLoader& GetImplementation( Toolkit::AsyncImageLoader& handle )
+{
+  DALI_ASSERT_ALWAYS( handle && "AsyncImageLoader handle is empty" );
+
+  BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<Internal::AsyncImageLoader&>( object );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ASYNC_IMAGE_LOADER_IMPL_H
diff --git a/dali-toolkit/internal/image-loader/atlas-packer.cpp b/dali-toolkit/internal/image-loader/atlas-packer.cpp
new file mode 100644 (file)
index 0000000..4becddf
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "atlas-packer.h"
+
+// EXTERNAL HEADER
+#include <cstdlib> // For abs()
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+bool ApproximatelyEqual( uint32_t a, uint32_t b  )
+{
+  return std::abs( static_cast<int32_t>( a - b ) ) <= 1;
+}
+
+uint16_t MaxDimension( const Uint16Pair& dimensions )
+{
+  return dimensions.GetWidth() >= dimensions.GetHeight() ? dimensions.GetWidth() : dimensions.GetHeight();
+}
+
+void Swap( Uint16Pair& first, Uint16Pair& second )
+{
+  Uint16Pair temp = first;
+  first = second;
+  second = temp;
+}
+
+}
+
+AtlasPacker::Node::Node( Node* parent, SizeType x, SizeType y, SizeType width, SizeType height  )
+: rectArea( x, y, width, height ),
+  parent(parent),
+  occupied( false )
+{
+  child[0] = NULL;
+  child[1] = NULL;
+}
+
+AtlasPacker:: AtlasPacker( SizeType atlasWidth, SizeType atlasHeight )
+: mAvailableArea( atlasWidth * atlasHeight )
+{
+  mRoot = new Node( NULL, 0u, 0u, atlasWidth, atlasHeight );
+}
+
+AtlasPacker::~AtlasPacker()
+{
+  DeleteNode( mRoot );
+}
+
+bool AtlasPacker::Pack( SizeType blockWidth, SizeType blockHeight,
+                        SizeType& packPositionX, SizeType& packPositionY)
+{
+  Node* firstFit = InsertNode( mRoot, blockWidth, blockHeight );
+  if( firstFit != NULL )
+  {
+    firstFit->occupied = true;
+    packPositionX = firstFit->rectArea.x;
+    packPositionY = firstFit->rectArea.y;
+    mAvailableArea -= blockWidth*blockHeight;
+    return true;
+  }
+  return false;
+}
+
+void AtlasPacker::DeleteBlock( SizeType packPositionX, SizeType packPositionY, SizeType blockWidth, SizeType blockHeight )
+{
+  Node* node =  SearchNode( mRoot, packPositionX, packPositionY, blockWidth, blockHeight  );
+  if( node != NULL )
+  {
+    mAvailableArea += blockWidth*blockHeight;
+    MergeToNonOccupied( node );
+  }
+}
+
+unsigned int AtlasPacker::GetAvailableArea() const
+{
+  return mAvailableArea;
+}
+
+AtlasPacker::Node* AtlasPacker::InsertNode( Node* root, SizeType blockWidth, SizeType blockHeight )
+{
+  if( root == NULL )
+  {
+    return NULL;
+  }
+
+  if( root->occupied )
+  {
+    // if not the leaf, then try insert into the first child.
+    Node* newNode = InsertNode(root->child[0], blockWidth, blockHeight);
+    if( newNode == NULL )// no room, try insert into the second child.
+    {
+      newNode = InsertNode(root->child[1], blockWidth, blockHeight);
+    }
+    return newNode;
+  }
+
+  // too small, return
+  if( root->rectArea.width < blockWidth || root->rectArea.height < blockHeight )
+  {
+    return NULL;
+  }
+
+  // right size, accept
+  if( root->rectArea.width == blockWidth && root->rectArea.height == blockHeight )
+  {
+    return root;
+  }
+
+  //too much room, need to split
+  SplitNode( root, blockWidth, blockHeight );
+  // insert into the first child created.
+  return InsertNode( root->child[0], blockWidth, blockHeight);
+}
+
+void AtlasPacker::SplitNode( Node* node, SizeType blockWidth, SizeType blockHeight )
+{
+  node->occupied = true;
+
+  // decide which way to split
+  SizeType remainingWidth = node->rectArea.width - blockWidth;
+  SizeType remainingHeight = node->rectArea.height - blockHeight;
+
+  if( remainingWidth > remainingHeight ) // split vertically
+  {
+    node->child[0] = new Node( node, node->rectArea.x, node->rectArea.y, blockWidth, node->rectArea.height  );
+    node->child[1] = new Node( node, node->rectArea.x+blockWidth, node->rectArea.y, node->rectArea.width-blockWidth, node->rectArea.height );
+  }
+  else // split horizontally
+  {
+    node->child[0] = new Node( node, node->rectArea.x, node->rectArea.y, node->rectArea.width, blockHeight  );
+    node->child[1] = new Node( node, node->rectArea.x, node->rectArea.y+blockHeight, node->rectArea.width, node->rectArea.height-blockHeight );
+  }
+}
+
+AtlasPacker::Node* AtlasPacker::SearchNode( Node* node, SizeType packPositionX, SizeType packPositionY, SizeType blockWidth, SizeType blockHeight  )
+{
+  if( node != NULL )
+  {
+    if( node->child[0] != NULL) //not a leaf
+    {
+      Node* newNode = SearchNode(node->child[0], packPositionX, packPositionY, blockWidth, blockHeight);
+      if( newNode == NULL )// try search from the second child.
+      {
+        newNode = SearchNode(node->child[1], packPositionX, packPositionY, blockWidth, blockHeight);
+      }
+      return newNode;
+    }
+    else if( ApproximatelyEqual(node->rectArea.x, packPositionX) && ApproximatelyEqual(node->rectArea.y, packPositionY )
+        && ApproximatelyEqual(node->rectArea.width, blockWidth) && ApproximatelyEqual( node->rectArea.height, blockHeight) )
+    {
+      return node;
+    }
+  }
+
+  return NULL;
+}
+
+void AtlasPacker::MergeToNonOccupied( Node* node )
+{
+  node->occupied = false;
+  Node* parent = node->parent;
+  // both child are not occupied, merge the space to parent
+  if( parent != NULL && parent->child[0]->occupied == false && parent->child[1]->occupied == false)
+  {
+    delete parent->child[0];
+    parent->child[0] = NULL;
+    delete parent->child[1];
+    parent->child[1] = NULL;
+
+    MergeToNonOccupied( parent );
+  }
+}
+
+void AtlasPacker::DeleteNode( Node *node )
+{
+  if( node != NULL )
+  {
+    DeleteNode( node->child[0] );
+    DeleteNode( node->child[1] );
+    delete node;
+  }
+}
+
+Uint16Pair AtlasPacker::GroupPack( const Dali::Vector<Uint16Pair>& blockSizes, Dali::Vector<Uint16Pair>& packPositions )
+{
+  uint16_t count = blockSizes.Count();
+  packPositions.Resize( count );
+
+  // Sort the blocks according to its maximum dimension. The bigger blocks are packed first.
+  Dali::Vector<Uint16Pair> packOrder;
+  packOrder.Resize( count );
+  for( uint16_t i = 0; i < count; i++ )
+  {
+    packOrder[i].SetX( MaxDimension( blockSizes[i] ) );
+    packOrder[i].SetY( i );
+  }
+  for( uint16_t i = 0; i < count-1; i++ )
+    for( uint16_t j = 0; j < count-i-1; j++ )
+    {
+      if( packOrder[j].GetX() < packOrder[j+1].GetX() )
+      {
+        Swap( packOrder[j], packOrder[j+1] );
+      }
+    }
+
+  int index = packOrder[0].GetY();
+  AtlasPacker packer( blockSizes[index].GetWidth(), blockSizes[index].GetHeight() );
+
+  SizeType packPositionX, packPositionY;
+  // pack the blocks one by one with descending size, grows as necessary to accommodate each subsequent block.
+  for( uint16_t i = 0; i < count; i++ )
+  {
+    index = packOrder[i].GetY();
+    packer.GrowPack( blockSizes[index].GetWidth(), blockSizes[index].GetHeight(),
+                     packPositionX, packPositionY );
+    packPositions[index].SetX( packPositionX );
+    packPositions[index].SetY( packPositionY );
+  }
+
+  return Uint16Pair( packer.mRoot->rectArea.width, packer.mRoot->rectArea.height );
+}
+
+void AtlasPacker::GrowPack( SizeType blockWidth, SizeType blockHeight,
+                            SizeType& packPositionX, SizeType& packPositionY )
+{
+  Node* firstFit = InsertNode( mRoot, blockWidth, blockHeight );
+  if( firstFit == NULL )
+  {
+    // Could fit in the current left space, grow the partition tree to get more space.
+    GrowNode( blockWidth, blockHeight );
+    firstFit = InsertNode( mRoot->child[1], blockWidth, blockHeight );
+  }
+
+  DALI_ASSERT_ALWAYS( firstFit != NULL && "It should never happen!")
+
+  firstFit->occupied = true;
+  packPositionX = firstFit->rectArea.x;
+  packPositionY = firstFit->rectArea.y;
+}
+
+void AtlasPacker::GrowNode( SizeType blockWidth, SizeType blockHeight )
+{
+  // Attempts to maintain a roughly square ratio when choosing the growing direction: right or down
+  bool canGrowRight = blockWidth <= mRoot->rectArea.width;
+  bool canGrowDown = blockHeight <= mRoot->rectArea.height;
+
+  bool shouldGrowRight = canGrowRight && mRoot->rectArea.height >= mRoot->rectArea.width+blockWidth;
+  bool shouldGrowDown = canGrowDown && mRoot->rectArea.width >= mRoot->rectArea.height+blockHeight;
+
+  if( canGrowRight && canGrowDown )
+  {
+    shouldGrowRight = mRoot->rectArea.width+blockWidth <= mRoot->rectArea.height+blockHeight;
+    shouldGrowDown = !shouldGrowRight;
+  }
+
+  if( shouldGrowRight || ( canGrowRight && !shouldGrowDown ) )
+  {
+    Node* newRoot = new Node( NULL, 0u, 0u, mRoot->rectArea.width+blockWidth, mRoot->rectArea.height );
+    newRoot->occupied = true;
+    newRoot->child[0] = mRoot;
+    newRoot->child[1] = new Node( newRoot, mRoot->rectArea.width, 0u, blockWidth, mRoot->rectArea.height );
+
+    mRoot = newRoot;
+  }
+  else if( shouldGrowDown || ( canGrowDown && !shouldGrowRight ) )
+  {
+    Node* newRoot = new Node( NULL, 0u, 0u, mRoot->rectArea.width, mRoot->rectArea.height+blockHeight );
+    newRoot->occupied = true;
+    newRoot->child[0] = mRoot;
+    newRoot->child[1] = new Node( newRoot, 0u, mRoot->rectArea.height, mRoot->rectArea.width, blockHeight );
+
+    mRoot = newRoot;
+  }
+  else
+  {
+    DALI_LOG_ERROR( " Atlas Packer failed to grow: make sure the packing order is sorted with the block size to avoid this happening");
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/atlas-packer.h b/dali-toolkit/internal/image-loader/atlas-packer.h
new file mode 100644 (file)
index 0000000..b356124
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef DALI_TOOLKIT_ATLAS_PACKER_H
+#define DALI_TOOLKIT_ATLAS_PACKER_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/math/uint-16-pair.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Binary space tree based bin packing algorithm.
+ * It is initialised with a fixed width and height and will fit each block into the first node where it fits
+ * and then split that node into 2 parts (down and right) to track the remaining empty space.
+ */
+class AtlasPacker
+{
+public:
+
+  /**
+   * rectangular area (x,y,width,height)
+   */
+  typedef uint32_t SizeType;
+  typedef Rect<SizeType> RectArea;
+
+  /**
+   * Tree node.
+   */
+  struct Node
+  {
+    Node( Node* parent, SizeType x, SizeType y, SizeType width, SizeType height );
+
+    RectArea rectArea;
+    Node* parent;
+    Node* child[2];
+    bool occupied;
+  };
+
+  /**
+   * Constructor.
+   *
+   * @param[in] atlasWidth The width of the atlas.
+   * @param[in] atlasHeight The height of the atlas.
+   */
+  AtlasPacker( SizeType atlasWidth, SizeType atlasHeight );
+
+  /**
+   * Destructor
+   */
+  ~AtlasPacker();
+
+  /**
+   * Pack a block into the atlas.
+   *
+   * @param[in] blockWidth The width of the block to pack.
+   * @param[in] blockHeight The height of the block to pack.
+   * @param[out] packPositionX The x coordinate of the position to pack the block.
+   * @param[out] packPositionY The y coordinate of the position to pack the block.
+   * @return True if there are room for this block, false otherwise.
+   */
+  bool Pack( SizeType blockWidth, SizeType blockHeight,
+             SizeType& packPositionX, SizeType& packPositionY);
+
+  /**
+   * Delete the block.
+   *
+   * @param[in] packPositionX The x coordinate of the pack position.
+   * @param[in] packPositionY The y coordinate of the pack position.
+   * @param[in] blockWidth The width of the block to delete.
+   * @param[in] blockHeight The height of the block to delete.
+   */
+  void DeleteBlock( SizeType packPositionX, SizeType packPositionY, SizeType blockWidth, SizeType blockHeight );
+
+  /**
+   * Query how much empty space left.
+   *
+   * @return The area available for packing.
+   */
+  unsigned int GetAvailableArea() const;
+
+  /**
+   * Pack a group of blocks with different sizes, calculate the required packing size and the position of each block.
+   * @param[in] blockSizes The size list of the blocks .
+   * @param[out] packPositions The packing position of each block.
+   * @return The required size to accommodate all the blocks.
+   */
+  static Uint16Pair GroupPack( const Dali::Vector<Uint16Pair>& blockSizes, Dali::Vector<Uint16Pair>& packPositions );
+
+private:
+
+  /*
+   * Search the node which can pack the block with given size.
+   *
+   * @param[in] root The root node of the subtree to be searched.
+   * @param[in] blockWidth The width of the block to pack.
+   * @param[in] blockHeight The height of the block to pack.
+   * @return The poniter pointing to node that can pack the block.
+   *          If it is NULL, there are no room in the subtree to pack the block.
+   */
+  Node* InsertNode( Node* root, SizeType blockWidth, SizeType blockHeight );
+
+  /**
+   * Split the node into two to fit the block width/size.
+   *
+   * @parm[in] node The node to split.
+   * @param[in] blockWidth The width of the block to pack.
+   * @param[in] blockHeight The height of the block to pack.
+   */
+  void SplitNode( Node* node, SizeType blockWidth, SizeType blockHeight );
+
+  /**
+   * Search the node at the given position and with the given size.
+
+   * @param[in] node The root node of the subtree to be searched.
+   * @param[in] packPositionX The x coordinate of the pack position.
+   * @param[in] packPositionY The y coordinate of the pack position.
+   * @param[in] blockWidth The width of the block.
+   * @param[in] blockHeight The height of the block.
+   */
+  Node* SearchNode( Node* node, SizeType packPositionX, SizeType packPositionY, SizeType blockWidth, SizeType blockHeight  );
+
+  /**
+   * Merge the rect of the node to non-occupied area.
+   *
+   * @param[in] node The node to me merged to the non-occupied area
+   */
+  void MergeToNonOccupied( Node* node );
+
+  /**
+   * Delete a node and its subtree.
+   *
+   * @parm[in] node The node to delete.
+   */
+  void DeleteNode( Node* node );
+
+  /**
+   * Pack a block into the atlas. If there is no enough room, grow the partition tree.
+   *
+   * @param[in] blockWidth The width of the block to pack.
+   * @param[in] blockHeight The height of the block to pack.
+   * @param[out] packPositionX The x coordinate of the position to pack the block.
+   * @param[out] packPositionY The y coordinate of the position to pack the block.
+   */
+  void GrowPack( SizeType blockWidth, SizeType blockHeight,
+                 SizeType& packPositionX, SizeType& packPositionY );
+
+  /**
+   * Add extra node into the partition tree to accommodate the given block.
+   *
+   * @param[in] blockWidth The width of the block to pack.
+   * @param[in] blockHeight The height of the block to pack.
+   */
+  void GrowNode( SizeType blockWidth, SizeType blockHeight );
+
+  // Undefined
+  AtlasPacker( const AtlasPacker& atlasPacker);
+
+  // Undefined
+  AtlasPacker& operator=( const AtlasPacker& atlasPacker );
+
+private:
+
+  Node* mRoot; ///< The root of the binary space tree
+  unsigned int mAvailableArea;
+
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_PACKER_H
diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.cpp b/dali-toolkit/internal/image-loader/image-atlas-impl.cpp
new file mode 100644 (file)
index 0000000..d167499
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "image-atlas-impl.h"
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <dali/public-api/signals/callback.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+typedef unsigned char PixelBuffer;
+
+Texture ImageAtlas::PackToAtlas( const std::vector<PixelData>& pixelData, Dali::Vector<Vector4>& textureRects  )
+{
+  // Record each block size
+  Dali::Vector<Uint16Pair> blockSizes;
+  SizeType count = pixelData.size();
+  for( SizeType index = 0; index < count; index++ )
+  {
+    blockSizes.PushBack( ImageDimensions( pixelData[index].GetWidth(), pixelData[index].GetHeight() ) );
+  }
+
+  // Ask atlasPacker for packing position of each block
+  Dali::Vector<Uint16Pair> packPositions;
+  ImageDimensions atlasSize = AtlasPacker::GroupPack( blockSizes, packPositions );
+
+  // Prepare for outout texture rect array
+  textureRects.Clear();
+  textureRects.Resize( count );
+
+  // create the texture for uploading the multiple pixel data
+  Texture atlasTexture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888, atlasSize.GetWidth(), atlasSize.GetHeight() );
+
+  float atlasWidth = static_cast<float>( atlasTexture.GetWidth() );
+  float atlasHeight = static_cast<float>( atlasTexture.GetHeight() );
+  int packPositionX, packPositionY;
+  // Upload the pixel data one by one to its packing position, and record the texture rects
+  for( SizeType index = 0; index < count; index++ )
+  {
+    packPositionX = packPositions[index].GetX();
+    packPositionY = packPositions[index].GetY();
+    atlasTexture.Upload( pixelData[index], 0u, 0u,
+                         packPositionX, packPositionY,
+                         pixelData[index].GetWidth(), pixelData[index].GetHeight() );
+
+    // Apply the half pixel correction to avoid the color bleeding between neighbour blocks
+    textureRects[index].x = ( static_cast<float>( packPositionX ) +0.5f ) / atlasWidth; // left
+    textureRects[index].y = ( static_cast<float>( packPositionY ) +0.5f ) / atlasHeight; // right
+    textureRects[index].z = ( static_cast<float>( packPositionX + pixelData[index].GetWidth() )-0.5f ) / atlasWidth; // right
+    textureRects[index].w = ( static_cast<float>( packPositionY + pixelData[index].GetHeight() )-0.5f ) / atlasHeight;// bottom
+  }
+
+  return atlasTexture;
+}
+
+ImageAtlas::ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat )
+: mAtlas( Texture::New( Dali::TextureType::TEXTURE_2D, pixelFormat, width, height ) ),
+  mPacker( width, height ),
+  mAsyncLoader( Toolkit::AsyncImageLoader::New() ),
+  mBrokenImageUrl(""),
+  mBrokenImageSize(),
+  mWidth( static_cast<float>(width) ),
+  mHeight( static_cast<float>( height ) ),
+  mPixelFormat( pixelFormat )
+{
+  mAsyncLoader.ImageLoadedSignal().Connect( this, &ImageAtlas::UploadToAtlas );
+}
+
+ImageAtlas::~ImageAtlas()
+{
+  const std::size_t count = mLoadingTaskInfoContainer.Count();
+  for( std::size_t i=0; i < count; ++i )
+  {
+    // Call unregister to every observer in the list.
+    // Note that, the Atlas can be registered to same observer multiple times, and the Unregister method only remove one item each time.
+    // In this way, the atlas is actually detached from a observer either every upload call invoked by this observer is completed or atlas is destroyed.
+    if( mLoadingTaskInfoContainer[i]->observer )
+    {
+      mLoadingTaskInfoContainer[i]->observer->Unregister( *this );
+    }
+  }
+
+  mLoadingTaskInfoContainer.Clear();
+}
+
+IntrusivePtr<ImageAtlas> ImageAtlas::New( SizeType width, SizeType height, Pixel::Format pixelFormat )
+{
+  IntrusivePtr<ImageAtlas> internal = new ImageAtlas( width, height, pixelFormat );
+
+  return internal;
+}
+
+Texture ImageAtlas::GetAtlas()
+{
+  return mAtlas;
+}
+
+float ImageAtlas::GetOccupancyRate() const
+{
+  return 1.f - static_cast<float>( mPacker.GetAvailableArea() ) / ( mWidth*mHeight );
+}
+
+void ImageAtlas::SetBrokenImage( const std::string& brokenImageUrl )
+{
+  mBrokenImageSize = Dali::GetClosestImageSize( brokenImageUrl );
+  if(mBrokenImageSize.GetWidth() > 0 && mBrokenImageSize.GetHeight() > 0 ) // check the url is valid
+  {
+    mBrokenImageUrl = brokenImageUrl;
+  }
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect,
+                         const std::string& url,
+                         ImageDimensions size,
+                         FittingMode::Type fittingMode,
+                         bool orientationCorrection,
+                         AtlasUploadObserver* atlasUploadObserver )
+{
+  ImageDimensions dimensions = size;
+  ImageDimensions zero;
+  if( size == zero ) // image size not provided
+  {
+    dimensions = Dali::GetClosestImageSize( url );
+    if( dimensions == zero ) // Fail to read the image & broken image file exists
+    {
+      if( !mBrokenImageUrl.empty() )
+      {
+        return Upload( textureRect, mBrokenImageUrl, mBrokenImageSize, FittingMode::DEFAULT, true, atlasUploadObserver );
+      }
+      else
+      {
+        textureRect = Vector4::ZERO;
+        return true;
+      }
+    }
+  }
+
+  unsigned int packPositionX = 0;
+  unsigned int packPositionY = 0;
+  if( mPacker.Pack( dimensions.GetWidth(), dimensions.GetHeight(), packPositionX, packPositionY ) )
+  {
+    unsigned short loadId = mAsyncLoader.Load( url, size, fittingMode, SamplingMode::BOX_THEN_LINEAR, orientationCorrection);
+    mLoadingTaskInfoContainer.PushBack( new LoadingTaskInfo( loadId, packPositionX, packPositionY, dimensions.GetWidth(), dimensions.GetHeight(), atlasUploadObserver ) );
+    // apply the half pixel correction
+    textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
+    textureRect.y = ( static_cast<float>( packPositionY ) +0.5f ) / mHeight; // right
+    textureRect.z = ( static_cast<float>( packPositionX + dimensions.GetX() )-0.5f ) / mWidth; // right
+    textureRect.w = ( static_cast<float>( packPositionY + dimensions.GetY() )-0.5f ) / mHeight;// bottom
+
+    if( atlasUploadObserver )
+    {
+      // register to the observer,
+      // Not that a matching unregister call should be invoked in UploadToAtlas if the observer is still alive by then.
+      atlasUploadObserver->Register( *this );
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+bool ImageAtlas::Upload( Vector4& textureRect, PixelData pixelData )
+{
+  unsigned int packPositionX = 0;
+  unsigned int packPositionY = 0;
+  if( mPacker.Pack( pixelData.GetWidth(), pixelData.GetHeight(), packPositionX, packPositionY ) )
+  {
+    mAtlas.Upload( pixelData, 0u, 0u, packPositionX, packPositionY, pixelData.GetWidth(), pixelData.GetHeight() );
+
+    // apply the half pixel correction
+    textureRect.x = ( static_cast<float>( packPositionX ) +0.5f ) / mWidth; // left
+    textureRect.y = ( static_cast<float>( packPositionY ) +0.5f ) / mHeight; // right
+    textureRect.z = ( static_cast<float>( packPositionX + pixelData.GetWidth() )-0.5f ) / mWidth; // right
+    textureRect.w = ( static_cast<float>( packPositionY + pixelData.GetHeight() )-0.5f ) / mHeight;// bottom
+
+    return true;
+  }
+
+  return false;
+}
+
+void ImageAtlas::Remove( const Vector4& textureRect )
+{
+  mPacker.DeleteBlock( static_cast<SizeType>(textureRect.x*mWidth),
+                       static_cast<SizeType>(textureRect.y*mHeight),
+                       static_cast<SizeType>((textureRect.z-textureRect.x)*mWidth+1.f),
+                       static_cast<SizeType>((textureRect.w-textureRect.y)*mHeight+1.f) );
+}
+
+void ImageAtlas::ObserverDestroyed( AtlasUploadObserver* observer )
+{
+  const std::size_t count = mLoadingTaskInfoContainer.Count();
+  for( std::size_t i=0; i < count; ++i )
+  {
+    if( mLoadingTaskInfoContainer[i]->observer == observer )
+    {
+      // the observer is destructing, so its member function should not be called anymore
+      mLoadingTaskInfoContainer[i]->observer = NULL;
+    }
+  }
+}
+
+void ImageAtlas::UploadToAtlas( uint32_t id, PixelData pixelData )
+{
+  if(  mLoadingTaskInfoContainer[0]->loadTaskId == id)
+  {
+    Rect<unsigned int> packRect( mLoadingTaskInfoContainer[0]->packRect  );
+    if( !pixelData || ( pixelData.GetWidth() ==0 && pixelData.GetHeight() == 0 ))
+    {
+      if(!mBrokenImageUrl.empty()) // replace with the broken image
+      {
+        UploadBrokenImage( packRect );
+      }
+    }
+    else
+    {
+      if( pixelData.GetWidth() < packRect.width || pixelData.GetHeight() < packRect.height  )
+      {
+        DALI_LOG_ERROR( "Can not upscale the image from actual loaded size [ %d, %d ] to specified size [ %d, %d ]\n",
+            pixelData.GetWidth(), pixelData.GetHeight(),
+            packRect.width, packRect.height );
+      }
+
+      mAtlas.Upload( pixelData, 0u, 0u, packRect.x, packRect.y, packRect.width, packRect.height );
+    }
+
+    if( mLoadingTaskInfoContainer[0]->observer )
+    {
+      mLoadingTaskInfoContainer[0]->observer->UploadCompleted();
+      mLoadingTaskInfoContainer[0]->observer->Unregister( *this );
+    }
+
+    mLoadingTaskInfoContainer.Erase( mLoadingTaskInfoContainer.Begin() );
+  }
+}
+
+void ImageAtlas::UploadBrokenImage( const Rect<unsigned int>& area )
+{
+  Devel::PixelBuffer brokenBuffer = LoadImageFromFile( mBrokenImageUrl, ImageDimensions( area.width, area.height ) );
+  SizeType loadedWidth = brokenBuffer.GetWidth();
+  SizeType loadedHeight = brokenBuffer.GetHeight();
+
+  bool needBackgroundClear = false;
+  SizeType packX = area.x;
+  SizeType packY = area.y;
+  // locate the broken image in the middle.
+  if( area.width > loadedWidth)
+  {
+    packX += (area.width - loadedWidth)/2;
+    needBackgroundClear = true;
+  }
+  if( area.height > loadedHeight)
+  {
+    packY += (area.height - loadedHeight)/2;
+    needBackgroundClear = true;
+  }
+
+  if( needBackgroundClear )
+  {
+    SizeType size = area.width * area.height * Pixel::GetBytesPerPixel( mPixelFormat );
+    Devel::PixelBuffer background = Devel::PixelBuffer::New( area.width, area.height, mPixelFormat );
+    unsigned char* buffer = background.GetBuffer();
+    for( SizeType idx = 0; idx < size; idx++ )
+    {
+      buffer[idx] = 0x00;
+    }
+    PixelData pixelData = Devel::PixelBuffer::Convert( background );
+    mAtlas.Upload( pixelData, 0u, 0u, area.x, area.y, area.width, area.height );
+  }
+
+  PixelData brokenPixelData = Devel::PixelBuffer::Convert( brokenBuffer );
+  mAtlas.Upload( brokenPixelData, 0u, 0u, packX, packY, loadedWidth, loadedHeight );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/image-atlas-impl.h b/dali-toolkit/internal/image-loader/image-atlas-impl.h
new file mode 100644 (file)
index 0000000..94601a2
--- /dev/null
@@ -0,0 +1,195 @@
+#ifndef DALI_TOOLKIT_IMAGE_ATLAS_IMPL_H
+#define DALI_TOOLKIT_IMAGE_ATLAS_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/common/owner-container.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/internal/image-loader/atlas-packer.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+
+namespace Dali
+{
+class EventThreadCallback;
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ImageAtlas : public BaseObject, public ConnectionTracker
+{
+public:
+
+  typedef Toolkit::ImageAtlas::SizeType SizeType;
+
+  /**
+   * @copydoc ImageAtlas::PackToAtlas( const std::vector<PixelData>&, Dali::Vector<Vector4>& )
+   */
+  static Texture PackToAtlas( const std::vector<PixelData>& pixelData, Dali::Vector<Vector4>& textureRects  );
+
+  /**
+   * Constructor
+   * @param [in] width          The atlas width in pixels.
+   * @param [in] height         The atlas height in pixels.
+   * @param [in] pixelFormat    The pixel format.
+   */
+  ImageAtlas( SizeType width, SizeType height, Pixel::Format pixelFormat );
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::New
+   */
+  static IntrusivePtr<ImageAtlas> New( SizeType width, SizeType height, Pixel::Format pixelFormat );
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::GetAtlas
+   */
+  Texture GetAtlas();
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::GetOccupancyRate
+   */
+  float GetOccupancyRate() const;
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::SetBrokenImage
+   */
+  void SetBrokenImage( const std::string& brokenImageUrl );
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::Upload( Vector4&, const std::string&, ImageDimensions,FittingMode::Type, bool )
+   */
+  bool Upload( Vector4& textureRect,
+               const std::string& url,
+               ImageDimensions size,
+               FittingMode::Type fittingMode,
+               bool orientationCorrection,
+               AtlasUploadObserver* atlasUploadObserver );
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::Upload( Vector4&, PixelData )
+   */
+  bool Upload( Vector4& textureRect, PixelData pixelData );
+
+  /**
+   * @copydoc Toolkit::ImageAtlas::Remove
+   */
+  void Remove( const Vector4& textureRect );
+
+  /**
+   * Resets the destroying observer pointer so that we know not to call methods of this object any more.
+   */
+  void ObserverDestroyed( AtlasUploadObserver* observer );
+
+protected:
+
+  /**
+   * Destructor
+   */
+  ~ImageAtlas();
+
+private:
+
+  /**
+   * @copydoc PixelDataRequester::ProcessPixels
+   */
+  void UploadToAtlas( uint32_t id, PixelData pixelData );
+
+  /**
+   * Upload broken image
+   *
+   * @param[in] area The pixel area for uploading.
+   */
+  void UploadBrokenImage( const Rect<unsigned int>& area );
+
+  // Undefined
+  ImageAtlas( const ImageAtlas& imageAtlas);
+
+  // Undefined
+  ImageAtlas& operator=( const ImageAtlas& imageAtlas );
+
+private:
+
+  /**
+   * Each loading task( identified with an ID ) is associated with a rect region for packing the loaded pixel data into the atlas,
+   * and an AtlasUploadObserver whose UploadCompleted method should get executed once the sub texture is ready.
+   */
+  struct LoadingTaskInfo
+  {
+    LoadingTaskInfo( unsigned short loadTaskId,
+                     unsigned int packPositionX,
+                     unsigned int packPositionY,
+                     unsigned int width,
+                     unsigned int height,
+                     AtlasUploadObserver* observer )
+    : loadTaskId( loadTaskId ),
+      packRect( packPositionX, packPositionY, width, height ),
+      observer( observer )
+    {}
+
+    unsigned short loadTaskId;
+    Rect<unsigned int> packRect;
+    AtlasUploadObserver* observer;
+  };
+
+  OwnerContainer<LoadingTaskInfo*> mLoadingTaskInfoContainer;
+
+  Texture                   mAtlas;
+  AtlasPacker               mPacker;
+  Toolkit::AsyncImageLoader mAsyncLoader;
+  std::string               mBrokenImageUrl;
+  ImageDimensions           mBrokenImageSize;
+  float                     mWidth;
+  float                     mHeight;
+  Pixel::Format             mPixelFormat;
+
+
+};
+
+} // namespace Internal
+
+inline const Internal::ImageAtlas& GetImplementation( const Toolkit::ImageAtlas& imageAtlas )
+{
+  DALI_ASSERT_ALWAYS( imageAtlas && "ImageAtlas handle is empty" );
+
+  const BaseObject& handle = imageAtlas.GetBaseObject();
+
+  return static_cast<const Internal::ImageAtlas&>(handle);
+}
+
+inline Internal::ImageAtlas& GetImplementation( Toolkit::ImageAtlas& imageAtlas )
+{
+  DALI_ASSERT_ALWAYS( imageAtlas && "ImageAtlas handle is empty" );
+
+  BaseObject& handle = imageAtlas.GetBaseObject();
+
+  return static_cast<Internal::ImageAtlas&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_ATLAS_IMPL_H
diff --git a/dali-toolkit/internal/image-loader/image-load-thread.cpp b/dali-toolkit/internal/image-loader/image-load-thread.cpp
new file mode 100644 (file)
index 0000000..179734a
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2019 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 "image-load-thread.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+LoadingTask::LoadingTask( uint32_t id, const VisualUrl& url, ImageDimensions dimensions,
+                          FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
+: pixelBuffer(),
+  url( url ),
+  id( id ),
+  dimensions( dimensions ),
+  fittingMode( fittingMode ),
+  samplingMode( samplingMode ),
+  orientationCorrection( orientationCorrection ),
+  preMultiplyOnLoad( preMultiplyOnLoad ),
+  isMaskTask( false ),
+  maskPixelBuffer(),
+  contentScale( 1.0f ),
+  cropToMask( false )
+{
+}
+
+LoadingTask::LoadingTask( uint32_t id, Devel::PixelBuffer pixelBuffer, Devel::PixelBuffer maskPixelBuffer, float contentScale, bool cropToMask,
+                          DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
+: pixelBuffer( pixelBuffer ),
+  url( "" ),
+  id( id ),
+  dimensions(),
+  fittingMode(),
+  samplingMode(),
+  orientationCorrection(),
+  preMultiplyOnLoad( preMultiplyOnLoad ),
+  isMaskTask( true ),
+  maskPixelBuffer( maskPixelBuffer ),
+  contentScale( contentScale ),
+  cropToMask( cropToMask )
+{
+}
+
+void LoadingTask::Load()
+{
+  if( url.IsLocalResource() )
+  {
+    pixelBuffer = Dali::LoadImageFromFile( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+  }
+  else
+  {
+    pixelBuffer = Dali::DownloadImageSynchronously ( url.GetUrl(), dimensions, fittingMode, samplingMode, orientationCorrection );
+  }
+
+  if( !pixelBuffer )
+  {
+    DALI_LOG_ERROR( "LoadingTask::Load: Loading is failed: %s\n", url.GetUrl().c_str() );
+  }
+}
+
+void LoadingTask::ApplyMask()
+{
+  pixelBuffer.ApplyMask( maskPixelBuffer, contentScale, cropToMask );
+}
+
+void LoadingTask::MultiplyAlpha()
+{
+  if( pixelBuffer && Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
+  {
+    if( preMultiplyOnLoad == DevelAsyncImageLoader::PreMultiplyOnLoad::ON )
+    {
+      pixelBuffer.MultiplyColorByAlpha();
+    }
+  }
+}
+
+ImageLoadThread::ImageLoadThread( EventThreadCallback* trigger )
+: mTrigger( trigger ),
+  mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
+{
+}
+
+ImageLoadThread::~ImageLoadThread()
+{
+  // add an empty task would stop the thread from conditional wait.
+  AddTask( NULL );
+  // stop the thread
+  Join();
+
+  delete mTrigger;
+}
+
+void ImageLoadThread::Run()
+{
+  SetThreadName( "ImageLoadThread" );
+  mLogFactory.InstallLogFunction();
+
+  while( LoadingTask* task = NextTaskToProcess() )
+  {
+    if( !task->isMaskTask )
+    {
+      task->Load();
+    }
+    else
+    {
+      task->ApplyMask();
+    }
+    task->MultiplyAlpha();
+
+    AddCompletedTask( task );
+  }
+}
+
+void ImageLoadThread::AddTask( LoadingTask* task )
+{
+  bool wasEmpty = false;
+
+  {
+    // Lock while adding task to the queue
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    wasEmpty = mLoadQueue.Empty();
+    mLoadQueue.PushBack( task );
+  }
+
+  if( wasEmpty )
+  {
+    // wake up the image loading thread
+    mConditionalWait.Notify();
+  }
+}
+
+LoadingTask* ImageLoadThread::NextCompletedTask()
+{
+  // Lock while popping task out from the queue
+  Mutex::ScopedLock lock( mMutex );
+
+  if( mCompleteQueue.Empty() )
+  {
+    return NULL;
+  }
+
+  Vector< LoadingTask* >::Iterator next = mCompleteQueue.Begin();
+  LoadingTask* nextTask = *next;
+  mCompleteQueue.Erase( next );
+
+  return nextTask;
+}
+
+bool ImageLoadThread::CancelTask( uint32_t loadingTaskId )
+{
+  // Lock while remove task from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
+  {
+    if( (*iter)->id == loadingTaskId )
+    {
+      delete (*iter);
+      mLoadQueue.Erase( iter );
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+void ImageLoadThread::CancelAll()
+{
+  // Lock while remove task from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  for( Vector< LoadingTask* >::Iterator iter = mLoadQueue.Begin(); iter != mLoadQueue.End(); ++iter )
+  {
+    delete ( *iter );
+  }
+  mLoadQueue.Clear();
+}
+
+LoadingTask* ImageLoadThread::NextTaskToProcess()
+{
+  // Lock while popping task out from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  while( mLoadQueue.Empty() )
+  {
+    mConditionalWait.Wait( lock );
+  }
+
+  Vector< LoadingTask* >::Iterator next = mLoadQueue.Begin();
+  LoadingTask* nextTask = *next;
+  mLoadQueue.Erase( next );
+
+  return nextTask;
+}
+
+void ImageLoadThread::AddCompletedTask( LoadingTask* task )
+{
+  // Lock while adding task to the queue
+  Mutex::ScopedLock lock( mMutex );
+  mCompleteQueue.PushBack( task );
+
+  // wake up the main thread
+  mTrigger->Trigger();
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/image-loader/image-load-thread.h b/dali-toolkit/internal/image-loader/image-load-thread.h
new file mode 100644 (file)
index 0000000..779541a
--- /dev/null
@@ -0,0 +1,217 @@
+#ifndef DALI_TOOLKIT_IMAGE_LOAD_THREAD_H
+#define DALI_TOOLKIT_IMAGE_LOAD_THREAD_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * The task of loading and packing an image into the atlas.
+ */
+struct LoadingTask
+{
+  /**
+   * Constructor.
+   * @param [in] id of the task
+   * @param [in] url The URL of the image file to load.
+   * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+   */
+  LoadingTask( uint32_t id,
+               const VisualUrl& url,
+               ImageDimensions dimensions,
+               FittingMode::Type fittingMode,
+               SamplingMode::Type samplingMode,
+               bool orientationCorrection,
+               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+
+  /**
+   * Constructor.
+   * @param [in] id of the task
+   * @param [in] pixelBuffer of the to be masked image
+   * @param [in] maskPixelBuffer of the mask image
+   * @param [in] contentScale The factor to scale the content
+   * @param [in] cropToMask Whether to crop the content to the mask size
+   * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+   */
+  LoadingTask( uint32_t id,
+              Devel::PixelBuffer pixelBuffer,
+              Devel::PixelBuffer maskPixelBuffer,
+              float contentScale,
+              bool cropToMask,
+              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+
+  /**
+   * Load the image
+   */
+  void Load();
+
+  /**
+   * Apply mask
+   */
+  void ApplyMask();
+
+  /**
+   * Multiply alpha
+   */
+  void MultiplyAlpha();
+
+private:
+
+  // Undefined
+  LoadingTask( const LoadingTask& queue );
+
+  // Undefined
+  LoadingTask& operator=( const LoadingTask& queue );
+
+public:
+
+  Devel::PixelBuffer pixelBuffer;   ///< pixelBuffer handle after successful load
+                                    ///< or pixelBuffer to be masked image in the mask task
+  VisualUrl          url;           ///< url of the image to load
+  uint32_t           id;            ///< The unique id associated with this task.
+  ImageDimensions    dimensions;    ///< dimensions to load
+  FittingMode::Type  fittingMode;   ///< fitting options
+  SamplingMode::Type samplingMode;  ///< sampling options
+  bool               orientationCorrection:1; ///< if orientation correction is needed
+  DevelAsyncImageLoader::PreMultiplyOnLoad            preMultiplyOnLoad; //< if the image's color should be multiplied by it's alpha
+
+  bool isMaskTask;                  ///< whether this task is for mask or not
+  Devel::PixelBuffer maskPixelBuffer; ///< pixelBuffer of mask image
+  float contentScale;               ///< The factor to scale the content
+  bool cropToMask;                  ///< Whether to crop the content to the mask size
+};
+
+
+/**
+ * The worker thread for image loading.
+ */
+class ImageLoadThread : public Thread
+{
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param[in] mTrigger The trigger to wake up the main thread.
+   */
+  ImageLoadThread( EventThreadCallback* mTrigger );
+
+  /**
+   * Destructor.
+   */
+  virtual ~ImageLoadThread();
+
+  /**
+   * Add a task in to the loading queue
+   *
+   * @param[in] task The task added to the queue.
+   *
+   * @note This class takes ownership of the task object
+   */
+  void AddTask( LoadingTask* task );
+
+  /**
+   * Pop the next task out from the completed queue.
+   *
+   * @return The next task to be processed.
+   */
+  LoadingTask* NextCompletedTask();
+
+  /**
+   * Remove the loading task from the waiting queue.
+   */
+  bool CancelTask( uint32_t loadingTaskId );
+
+  /**
+   * Remove all the loading tasks in the waiting queue.
+   */
+  void CancelAll();
+
+private:
+
+  /**
+   * Pop the next loading task out from the queue to process.
+   *
+   * @return The next task to be processed.
+   */
+  LoadingTask* NextTaskToProcess();
+
+  /**
+   * Add a task in to the loading queue
+   *
+   * @param[in] task The task added to the queue.
+   */
+  void AddCompletedTask( LoadingTask* task );
+
+protected:
+
+  /**
+   * The entry function of the worker thread.
+   * It fetches loading task from the loadQueue, loads the image and adds to the completeQueue.
+   */
+  virtual void Run();
+
+private:
+
+  // Undefined
+  ImageLoadThread( const ImageLoadThread& thread );
+
+  // Undefined
+  ImageLoadThread& operator=( const ImageLoadThread& thread );
+
+private:
+
+  Vector< LoadingTask* > mLoadQueue;     ///<The task queue with images for loading.
+  Vector< LoadingTask* > mCompleteQueue; ///<The task queue with images loaded.
+  EventThreadCallback*   mTrigger;
+  const Dali::LogFactoryInterface& mLogFactory; ///< The log factory
+
+  ConditionalWait        mConditionalWait;
+  Dali::Mutex            mMutex;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_LOAD_THREAD_H
diff --git a/dali-toolkit/internal/styling/style-manager-impl.cpp b/dali-toolkit/internal/styling/style-manager-impl.cpp
new file mode 100644 (file)
index 0000000..a5a02dd
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2018 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 "style-manager-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/adaptor-framework/application.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/internal/builder/builder-impl.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/internal/feedback/feedback-style.h>
+
+namespace
+{
+
+//const char* LANDSCAPE_QUALIFIER = "landscape";
+const char* PORTRAIT_QUALIFIER  = "portrait";
+const char* FONT_SIZE_QUALIFIER = "fontsize";
+
+const char* DEFAULT_THEME_FILE_NAME = "dali-toolkit-default-theme.json";
+
+const char* PACKAGE_PATH_KEY = "PACKAGE_PATH";
+const char* APPLICATION_RESOURCE_PATH_KEY = "APPLICATION_RESOURCE_PATH";
+
+const char* DEFAULT_TOOLKIT_PACKAGE_PATH = "/toolkit/";
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_STYLE");
+#endif
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  BaseHandle handle = StyleManager::Get();
+
+  if ( !handle )
+  {
+    SingletonService singletonService( SingletonService::Get() );
+    if ( singletonService )
+    {
+      Toolkit::StyleManager manager = Toolkit::StyleManager( new Internal::StyleManager() );
+      singletonService.Register( typeid( manager ), manager );
+      handle = manager;
+    }
+  }
+
+  return handle;
+}
+
+DALI_TYPE_REGISTRATION_BEGIN_CREATE( Toolkit::StyleManager, Dali::BaseHandle, Create, true )
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+Toolkit::StyleManager StyleManager::Get()
+{
+  Toolkit::StyleManager manager;
+
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    // Check whether the style manager is already created
+    Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::StyleManager ) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton
+      manager = Toolkit::StyleManager( dynamic_cast< StyleManager* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return manager;
+}
+
+StyleManager::StyleManager()
+: mDefaultFontSize( -1 ),
+  mDefaultFontFamily(""),
+  mDefaultThemeFilePath(),
+  mFeedbackStyle( nullptr )
+{
+  // Add theme builder constants
+  const std::string dataReadOnlyDir = AssetManager::GetDaliDataReadOnlyPath();
+  mThemeBuilderConstants[ PACKAGE_PATH_KEY ] = dataReadOnlyDir + DEFAULT_TOOLKIT_PACKAGE_PATH;
+  mThemeBuilderConstants[ APPLICATION_RESOURCE_PATH_KEY ] = Application::GetResourcePath();
+
+  mStyleMonitor = StyleMonitor::Get();
+  if( mStyleMonitor )
+  {
+    mStyleMonitor.StyleChangeSignal().Connect( this, &StyleManager::StyleMonitorChange );
+    mDefaultFontSize = mStyleMonitor.GetDefaultFontSize();
+  }
+
+  // Set the full path for the default style theme.
+  const std::string styleDirPath = AssetManager::GetDaliStylePath();
+  mDefaultThemeFilePath = styleDirPath + DEFAULT_THEME_FILE_NAME;
+
+  // Sound & haptic style
+  mFeedbackStyle = new FeedbackStyle();
+}
+
+StyleManager::~StyleManager()
+{
+  delete mFeedbackStyle;
+}
+
+void StyleManager::ApplyTheme( const std::string& themeFile )
+{
+  SetTheme( themeFile );
+}
+
+void StyleManager::ApplyDefaultTheme()
+{
+  SetTheme(mDefaultThemeFilePath);
+}
+
+const std::string& StyleManager::GetDefaultFontFamily() const
+{
+  return mDefaultFontFamily;
+}
+
+void StyleManager::SetStyleConstant( const std::string& key, const Property::Value& value )
+{
+  mStyleBuilderConstants[ key ] = value;
+}
+
+bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& valueOut )
+{
+  Property::Value* value = mStyleBuilderConstants.Find( key );
+  if( value )
+  {
+    valueOut = *value;
+    return true;
+  }
+
+  return false;
+}
+
+void StyleManager::ApplyThemeStyle( Toolkit::Control control )
+{
+  if( !mThemeBuilder )
+  {
+    ApplyDefaultTheme();
+  }
+
+  if( mThemeBuilder )
+  {
+    ApplyStyle( mThemeBuilder, control );
+  }
+}
+
+void StyleManager::ApplyThemeStyleAtInit( Toolkit::Control control )
+{
+  ApplyThemeStyle( control );
+
+  if(mFeedbackStyle)
+  {
+    mFeedbackStyle->ObjectCreated( control );
+  }
+}
+
+void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName )
+{
+  bool builderReady = false;
+
+  // First look in the cache
+  Toolkit::Builder builder = FindCachedBuilder( jsonFileName );
+  if( builder )
+  {
+    builderReady = true;
+  }
+  else
+  {
+    // Merge theme and style constants
+    Property::Map constants( mThemeBuilderConstants );
+    constants.Merge( mStyleBuilderConstants );
+
+    // Create it
+    builder = CreateBuilder( constants );
+
+    if( LoadJSON( builder, jsonFileName ) )
+    {
+      CacheBuilder( builder, jsonFileName );
+      builderReady = true;
+    }
+  }
+
+  // Apply the style to the control
+  if( builderReady )
+  {
+    builder.ApplyStyle( styleName, control );
+  }
+}
+
+Toolkit::StyleManager::StyleChangedSignalType& StyleManager::StyleChangedSignal()
+{
+  return mStyleChangedSignal;
+}
+
+Toolkit::StyleManager::StyleChangedSignalType& StyleManager::ControlStyleChangeSignal()
+{
+  return mControlStyleChangeSignal;
+}
+
+void StyleManager::SetTheme( const std::string& themeFile )
+{
+  bool themeLoaded = false;
+  bool loading = false;
+
+  // If we haven't loaded a theme, or the stored theme file is empty, or
+  // the previously loaded theme is different to the requested theme,
+  // first reset the builder and load the default theme.
+  if( ! mThemeBuilder || mThemeFile.empty() || mThemeFile.compare( themeFile ) != 0 )
+  {
+    loading = true;
+    mThemeBuilder = CreateBuilder( mThemeBuilderConstants );
+    themeLoaded = LoadJSON( mThemeBuilder, mDefaultThemeFilePath ); // Sets themeLoaded to true if theme exists
+  }
+
+  if( themeFile.compare(mDefaultThemeFilePath) != 0 )
+  {
+    // The theme is different to the default: Merge it
+    loading = true;
+    themeLoaded |= LoadJSON( mThemeBuilder, themeFile );
+  }
+
+  if( loading )
+  {
+    mThemeFile = themeFile;
+
+    if( themeLoaded )
+    {
+      // We've successfully loaded the theme file
+      if(mFeedbackStyle)
+      {
+        mFeedbackStyle->StyleChanged( mThemeFile, StyleChange::THEME_CHANGE );
+      }
+
+      EmitStyleChangeSignals(StyleChange::THEME_CHANGE);
+    }
+    else
+    {
+      // We tried to load a theme, but it failed. Ensure the builder is reset
+      mThemeBuilder.Reset();
+      mThemeFile.clear();
+    }
+  }
+}
+
+const Property::Map StyleManager::GetConfigurations()
+{
+  DALI_LOG_STREAM( gLogFilter, Debug::Concise, "GetConfigurations()\n On entry, mThemeBuilder: " << (bool(mThemeBuilder)?"Created":"Empty") << "  mThemeFile: " << mThemeFile);
+
+  Property::Map result;
+  if( mThemeBuilder )
+  {
+    result = mThemeBuilder.GetConfigurations();
+  }
+  else
+  {
+    DALI_LOG_STREAM( gLogFilter, Debug::Concise, "GetConfigurations()  Loading default theme" );
+
+    bool themeLoaded = false;
+
+    mThemeBuilder = CreateBuilder( mThemeBuilderConstants );
+
+    // Load default theme because this is first try to load stylesheet.
+    themeLoaded = LoadJSON( mThemeBuilder, mDefaultThemeFilePath );
+    mThemeFile = mDefaultThemeFilePath;
+
+    if( themeLoaded )
+    {
+      result = mThemeBuilder.GetConfigurations();
+    }
+    DALI_LOG_STREAM( gLogFilter, Debug::Concise, "  themeLoaded" << (themeLoaded?"success":"failure") );
+  }
+
+  DALI_LOG_STREAM( gLogFilter, Debug::Concise, "GetConfigurations()\n On exit, result Count: " << (result.Count() != 0) );
+  DALI_LOG_STREAM( gLogFilter, Debug::Verbose, "          result: " << result );
+
+  return result;
+}
+
+bool StyleManager::LoadFile( const std::string& filename, std::string& stringOut )
+{
+  DALI_ASSERT_DEBUG( 0 != filename.length());
+
+  // as toolkit is platform agnostic, it cannot load files from filesystem
+  // ask style monitor to load the style sheet
+  if( mStyleMonitor )
+  {
+    return mStyleMonitor.LoadThemeFile( filename, stringOut );
+  }
+
+  return false;
+}
+
+Toolkit::Builder StyleManager::CreateBuilder( const Property::Map& constants )
+{
+  Toolkit::Builder builder = Toolkit::Builder::New();
+  builder.AddConstants( constants );
+
+  return builder;
+}
+
+bool StyleManager::LoadJSON( Toolkit::Builder builder, const std::string& jsonFilePath )
+{
+  std::string fileString;
+  if( LoadFile( jsonFilePath, fileString ) )
+  {
+    builder.LoadFromString( fileString );
+    return true;
+  }
+  else
+  {
+    DALI_LOG_WARNING("Error loading file '%s'\n", jsonFilePath.c_str());
+    return false;
+  }
+}
+
+static void CollectQualifiers( std::vector<std::string>& qualifiersOut )
+{
+  // Append the relevant qualifier for orientation
+  // int orientation = 0; // Get the orientation from the system
+  /*
+  //// To Do /////
+  Getting orientation from the system, and determine Qualifie LANDSCAPE or PORTRAIT
+  orientation  0, 180 : PORTRAIT_QUALIFIER (default)
+  orientation 90, 270 : LANDSCAPE_QUALIFIER
+  */
+
+  qualifiersOut.push_back( std::string( PORTRAIT_QUALIFIER ) );
+
+}
+
+/**
+ * @brief Construct a qualified style name out of qualifiers
+ *
+ * A qualifed style name will be in the format: style-qualifier0-qualifier1-qualifierN
+ *
+ * @param[in] styleName The root name of the style
+ * @param[in] qualifiers List of qualifier names
+ * @param[out] qualifiedStyleOut The qualified style name
+ */
+static void BuildQualifiedStyleName(
+  const std::string& styleName,
+  const std::vector<std::string>& qualifiers,
+  std::string& qualifiedStyleOut )
+{
+  qualifiedStyleOut.append( styleName );
+
+  for( std::vector<std::string>::const_iterator it = qualifiers.begin(),
+         itEnd = qualifiers.end(); it != itEnd; ++it )
+  {
+    const std::string& str = *it;
+
+    qualifiedStyleOut.append( "-" );
+    qualifiedStyleOut.append( str );
+  }
+}
+
+static bool GetStyleNameForControl( Toolkit::Builder builder, Toolkit::Control control, std::string& styleName)
+{
+  styleName = control.GetStyleName();
+
+  if( styleName.empty() )
+  {
+    styleName = control.GetTypeName();
+  }
+
+  // Apply the style after choosing the correct actual style (e.g. landscape or portrait)
+  std::vector<std::string> qualifiers;
+  CollectQualifiers( qualifiers );
+
+  bool found = 0;
+  std::string qualifiedStyleName;
+  do
+  {
+    qualifiedStyleName.clear();
+    BuildQualifiedStyleName( styleName, qualifiers, qualifiedStyleName );
+
+    // Break if style found or we have tried the root style name (qualifiers is empty)
+    if( GetImpl(builder).LookupStyleName( qualifiedStyleName ) )
+    {
+      found = true;
+      break;
+    }
+    if( qualifiers.size() == 0 )
+    {
+      break;
+    }
+    // Remove the last qualifier in an attempt to find a style that is valid
+    qualifiers.pop_back();
+  } while (!found);
+
+  if(found)
+  {
+    styleName = qualifiedStyleName;
+  }
+  return found;
+}
+
+void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control control )
+{
+  std::string styleName = control.GetStyleName();
+  if( GetStyleNameForControl( builder, control, styleName ) )
+  {
+    builder.ApplyStyle( styleName, control );
+  }
+
+  if( mDefaultFontSize >= 0 )
+  {
+    // Apply the style for logical font size
+    std::stringstream fontSizeQualifier;
+    fontSizeQualifier << styleName << FONT_SIZE_QUALIFIER << mDefaultFontSize;
+    builder.ApplyStyle( fontSizeQualifier.str(), control );
+  }
+}
+
+const StylePtr StyleManager::GetRecordedStyle( Toolkit::Control control )
+{
+  if( mThemeBuilder )
+  {
+    std::string styleName = control.GetStyleName();
+
+    if( GetStyleNameForControl( mThemeBuilder, control, styleName ) )
+    {
+      const StylePtr style = GetImpl(mThemeBuilder).GetStyle( styleName );
+      return style;
+    }
+  }
+  return StylePtr(NULL);
+}
+
+Toolkit::Builder StyleManager::FindCachedBuilder( const std::string& key )
+{
+  BuilderMap::iterator builderIt = mBuilderCache.find( key );
+  if( builderIt != mBuilderCache.end() )
+  {
+    return builderIt->second;
+  }
+
+  return Toolkit::Builder();
+}
+
+void StyleManager::CacheBuilder( Toolkit::Builder builder, const std::string& key )
+{
+  mBuilderCache[ key ] = builder;
+}
+
+void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::Type styleChange )
+{
+  switch ( styleChange )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      mDefaultFontFamily = styleMonitor.GetDefaultFontFamily();
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      mDefaultFontSize = styleMonitor.GetDefaultFontSize();
+      break;
+    }
+
+    case StyleChange::THEME_CHANGE:
+    {
+      SetTheme( styleMonitor.GetTheme() );
+      break;
+    }
+  }
+  EmitStyleChangeSignals( styleChange );
+}
+
+void StyleManager::EmitStyleChangeSignals( StyleChange::Type styleChange )
+{
+  Toolkit::StyleManager styleManager = StyleManager::Get();
+
+  // Update Controls first
+  mControlStyleChangeSignal.Emit( styleManager, styleChange );
+
+  // Inform application last
+  mStyleChangedSignal.Emit( styleManager, styleChange );
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/styling/style-manager-impl.h b/dali-toolkit/internal/styling/style-manager-impl.h
new file mode 100644 (file)
index 0000000..7b3fd53
--- /dev/null
@@ -0,0 +1,271 @@
+#ifndef DALI_TOOLKIT_INTERNAL_STYLE_MANAGER_H
+#define DALI_TOOLKIT_INTERNAL_STYLE_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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/public-api/common/vector-wrapper.h>
+#include <dali/devel-api/common/map-wrapper.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/devel-api/builder/builder.h>
+#include <dali-toolkit/internal/builder/style.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class FeedbackStyle;
+
+/**
+ * @copydoc Toolkit::StyleManager
+ */
+class StyleManager : public Dali::BaseObject, public ConnectionTracker
+{
+public:
+  /**
+   * Singleton access
+   *
+   * @return The StyleManager object
+   */
+  static Toolkit::StyleManager Get();
+
+  /**
+   * Construct a new StyleManager.
+   */
+  StyleManager();
+
+protected:
+  /**
+   * @brief Destructor
+   */
+  virtual ~StyleManager();
+
+public: // Public API
+
+  /**
+   * @copydoc Toolkit::StyleManager::ApplyTheme
+   */
+  void ApplyTheme( const std::string& themeFile );
+
+  /**
+   * @copydoc Toolkit::StyleManager::ApplyDefaultTheme
+   */
+  void ApplyDefaultTheme();
+
+  /**
+   * @copydoc Toolkit::StyleManager::GetDefaultFontFamily
+   */
+  const std::string& GetDefaultFontFamily() const;
+
+  /**
+   * @copydoc Toolkit::StyleManager::SetStyleConstant
+   */
+  void SetStyleConstant( const std::string& key, const Property::Value& value );
+
+  /**
+   * @copydoc Toolkit::StyleManager::GetStyleConstant
+   */
+  bool GetStyleConstant( const std::string& key, Property::Value& valueOut );
+
+  /**
+   * @copydoc Toolkit::StyleManager::GetConfigurations
+   */
+  const Property::Map GetConfigurations();
+
+  /**
+   * @brief Apply the theme style to a control.
+   *
+   * @param[in] control The control to apply style.
+   */
+  void ApplyThemeStyle( Toolkit::Control control );
+
+  /**
+   * @brief Apply the theme style to a control at initialization.
+   *
+   * @param[in] control The control to apply style.
+   */
+  void ApplyThemeStyleAtInit( Toolkit::Control control );
+
+  /**
+   * @copydoc Toolkit::StyleManager::ApplyStyle
+   */
+  void ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName );
+
+  /**
+   * Get the state/style information for the given control
+   * @param[in] control The control to get state information for
+   * @return The style information (or empty ptr if not found)
+   */
+  const StylePtr GetRecordedStyle( Toolkit::Control control );
+
+public:
+  // SIGNALS
+
+  /**
+   * @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::StyleChangedSignalType& ControlStyleChangeSignal();
+
+private:
+  typedef std::vector<std::string> StringList;
+
+  /**
+   * @brief Set the current theme. Called only once per event processing cycle.
+   * @param[in] themeFile The name of the theme file to read.
+   */
+  void SetTheme( const std::string& themeFile );
+
+  /**
+   * @brief Internal helper method to read a file from file system.
+   * @param filename The name of the file to read.
+   * @param[out] stringOut The string to return the file in
+   *
+   * @param Return true if file was found
+   */
+  bool LoadFile(const std::string& filename, std::string& stringOut);
+
+  /**
+   * @brief Create a new builder.
+   *
+   * @param[in] constants A map of constants to be used by the builder
+   *
+   * @return Return the newly created builder
+   */
+  Toolkit::Builder CreateBuilder( const Property::Map& constants );
+
+  /**
+   * @brief Load a JSON file into given builder
+   *
+   * @param[in] builder The builder object to load the theme file
+   * @param[in] jsonFileName The name of the JSON file to load
+   * @return Return true if file was loaded
+   */
+  bool LoadJSON( Toolkit::Builder builder, const std::string& jsonFileName );
+
+  /**
+   * @brief Apply a style to the control using the given builder
+   *
+   * @param[in] builder The builder to apply the style from
+   * @param[in] control The control to apply the style to
+   */
+  void ApplyStyle( Toolkit::Builder builder, Toolkit::Control control );
+
+  /**
+   * Search for a builder in the cache
+   *
+   * @param[in] key The key the builder was cached under
+   * @return Return the cached builder if found or an empty builder object if not found
+   */
+  Toolkit::Builder FindCachedBuilder( const std::string& key );
+
+  /**
+   * Store a given builder in the cache keyed to the given key
+   *
+   * @param[in] builder The builder object to store
+   * @param[in] key The key to store the builder under
+   */
+  void CacheBuilder( Toolkit::Builder builder, const std::string& key );
+
+  /**
+   * Callback for when style monitor raises a signal
+   *
+   * @param[in] styleMonitor The style monitor object
+   * @param[in] styleChange The style change type
+   */
+  void StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::Type styleChange );
+
+  /**
+   * Emit signals to controls first, app second
+   */
+  void EmitStyleChangeSignals( StyleChange::Type styleChange );
+
+
+  // Undefined
+  StyleManager(const StyleManager&);
+
+  StyleManager& operator=(const StyleManager& rhs);
+
+private:
+
+  // Map to store builders keyed by JSON file name
+  typedef std::map< std::string, Toolkit::Builder > BuilderMap;
+
+  Toolkit::Builder mThemeBuilder;     ///< Builder for all default theme properties
+  StyleMonitor mStyleMonitor;         ///< Style monitor handle
+
+  int mDefaultFontSize;               ///< Logical size, not a point-size
+  std::string mDefaultFontFamily;
+  std::string mDefaultThemeFilePath;  ///< The full path of the default theme file
+  std::string mThemeFile;             ///< The full path of the current theme file
+
+  Property::Map mThemeBuilderConstants;   ///< Contants to give the theme builder
+  Property::Map mStyleBuilderConstants;   ///< Constants specific to building styles
+
+  BuilderMap mBuilderCache;           ///< Cache of builders keyed by JSON file name
+
+  Toolkit::Internal::FeedbackStyle* mFeedbackStyle; ///< Feedback style
+
+  // Signals
+  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
+
+inline Internal::StyleManager& GetImpl( Dali::Toolkit::StyleManager& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast< Internal::StyleManager& >( handle );
+}
+
+inline const Internal::StyleManager& GetImpl( const Dali::Toolkit::StyleManager& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  const Dali::BaseObject& handle = obj.GetBaseObject();
+
+  return static_cast< const Internal::StyleManager& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_STYLE_MANAGER_H
diff --git a/dali-toolkit/internal/text/bidirectional-line-info-run.h b/dali-toolkit/internal/text/bidirectional-line-info-run.h
new file mode 100644 (file)
index 0000000..c04918b
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef DALI_TOOLKIT_TEXT_BIDIRECTIONAL_LINE_INFO_RUN_H
+#define DALI_TOOLKIT_TEXT_BIDIRECTIONAL_LINE_INFO_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief BidirectionalLineInfoRun
+ */
+struct BidirectionalLineInfoRun
+{
+  CharacterRun       characterRun;       ///< The initial character index within the whole text and the number of characters of the run.
+  CharacterIndex*    visualToLogicalMap; ///< Pointer to the visual to logical map table.
+  CharacterDirection direction:1;        ///< Direction of the first character of the paragraph.
+  bool               isIdentity:1;       ///< Whether the map is the identity.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_BIDIRECTIONAL_LINE_INFO_RUN_H
diff --git a/dali-toolkit/internal/text/bidirectional-paragraph-info-run.h b/dali-toolkit/internal/text/bidirectional-paragraph-info-run.h
new file mode 100644 (file)
index 0000000..44a9614
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_TOOLKIT_TEXT_BIDIRECTIONAL_PARAGRAPH_INFO_RUN_H
+#define DALI_TOOLKIT_TEXT_BIDIRECTIONAL_PARAGRAPH_INFO_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief BidirectionalParagraphInfoRun
+ *
+ * In terms of the bidirectional algorithm, a 'paragraph' is understood as a run of characters between Paragraph Separators or appropriate Newline Functions.
+ * A 'paragraph' may also be determined by higher-level protocols like a mark-up tag.
+ */
+struct BidirectionalParagraphInfoRun
+{
+  CharacterRun  characterRun;           ///< The initial character index within the whole text and the number of characters of the run.
+  BidiInfoIndex bidirectionalInfoIndex; ///< Index to the table with the bidirectional info per paragraph.
+  CharacterDirection direction;         ///< The paragraph's direction.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_BIDIRECTIONAL_PARAGRAPH_INFO_RUN_H
diff --git a/dali-toolkit/internal/text/bidirectional-support.cpp b/dali-toolkit/internal/text/bidirectional-support.cpp
new file mode 100755 (executable)
index 0000000..165ae0d
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void SetBidirectionalInfo( const Vector<Character>& text,
+                           const Vector<ScriptRun>& scripts,
+                           const Vector<LineBreakInfo>& lineBreakInfo,
+                           CharacterIndex startIndex,
+                           Length numberOfCharacters,
+                           Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                           bool matchSystemLanguageDirection,
+                           Dali::LayoutDirection::Type layoutDirection )
+{
+  // Find where to insert the new paragraphs.
+  BidirectionalRunIndex bidiInfoIndex = 0u;
+  for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    const BidirectionalParagraphInfoRun& run = *it;
+
+    if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found where to insert the bidi info.
+      break;
+    }
+    ++bidiInfoIndex;
+  }
+
+  // Traverse the script runs. If there is one with a right to left script, create the bidirectional info for the paragraph containing that script is needed.
+  // From the bidirectional point of view, a paragraph is the piece of text between two LINE_MUST_BREAK.
+
+  // Index pointing the first character of the current paragraph.
+  CharacterIndex paragraphCharacterIndex = startIndex;
+
+  // Pointer to the text buffer.
+  const Character* textBuffer = text.Begin();
+
+  // Pointer to the line break info buffer.
+  const LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
+
+  // Handle to the bidirectional info module in text-abstraction.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
+  bool hasRightToLeftScript = false;
+
+  for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
+         endIt = scripts.End();
+       it != endIt;
+       ++it )
+  {
+    const ScriptRun& scriptRun = *it;
+    const CharacterIndex lastScriptRunIndex = scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters - 1u;
+
+    if( startIndex > lastScriptRunIndex )
+    {
+      // Skip the run as it has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= scriptRun.characterRun.characterIndex )
+    {
+      // Do not get bidirectional info beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    if( !hasRightToLeftScript && scriptRun.isRightToLeft )
+    {
+      // The script is right to left.
+      hasRightToLeftScript = true;
+    }
+
+    if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + lastScriptRunIndex ) )
+    {
+      // A new paragraph has been found.
+
+      if( hasRightToLeftScript )
+      {
+        // The Bidirectional run must have the same number of characters than the paragraph.
+        BidirectionalParagraphInfoRun bidirectionalRun;
+        bidirectionalRun.characterRun.characterIndex = paragraphCharacterIndex;
+        bidirectionalRun.characterRun.numberOfCharacters = ( lastScriptRunIndex - paragraphCharacterIndex ) + 1u; // The must break character is part of the paragrah.
+
+        // Create the bidirectional info for the whole paragraph and store the index to the table with this info in the run.
+        bidirectionalRun.bidirectionalInfoIndex = bidirectionalSupport.CreateInfo( textBuffer + bidirectionalRun.characterRun.characterIndex,
+                                                                                   bidirectionalRun.characterRun.numberOfCharacters,
+                                                                                   matchSystemLanguageDirection,
+                                                                                   layoutDirection );
+
+        bidirectionalRun.direction = bidirectionalSupport.GetParagraphDirection( bidirectionalRun.bidirectionalInfoIndex );
+
+        bidirectionalInfo.Insert( bidirectionalInfo.Begin() + bidiInfoIndex, bidirectionalRun );
+        ++bidiInfoIndex;
+      }
+
+      // Point to the next paragraph.
+      paragraphCharacterIndex = lastScriptRunIndex + 1u;
+
+      // Reset whether there is a right to left script.
+      hasRightToLeftScript = false;
+    }
+  }
+
+  // Update indices of the bidi runs.
+  for( Vector<BidirectionalParagraphInfoRun>::Iterator it = bidirectionalInfo.Begin() + bidiInfoIndex,
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    BidirectionalParagraphInfoRun& run = *it;
+
+    run.characterRun.characterIndex += numberOfCharacters;
+  }
+}
+
+void ReorderLine( const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
+                  Vector<BidirectionalLineInfoRun>& lineInfoRuns,
+                  BidirectionalLineRunIndex bidiLineIndex,
+                  CharacterIndex startIndex,
+                  Length numberOfCharacters,
+                  CharacterDirection direction )
+{
+  // Handle to the bidirectional info module in text-abstraction.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  // Creates a bidirectional info for the line run.
+  BidirectionalLineInfoRun lineInfoRun;
+  lineInfoRun.characterRun.characterIndex = startIndex;
+  lineInfoRun.characterRun.numberOfCharacters = numberOfCharacters;
+  lineInfoRun.direction = direction;
+  lineInfoRun.isIdentity = true;
+
+  // Allocate space for the conversion maps.
+  // The memory is freed after the visual to logical to visual conversion tables are built in the logical model.
+  lineInfoRun.visualToLogicalMap = reinterpret_cast<CharacterIndex*>( malloc( numberOfCharacters * sizeof( CharacterIndex ) ) );
+
+  if( nullptr != lineInfoRun.visualToLogicalMap )
+  {
+    // Reorders the line.
+    bidirectionalSupport.Reorder( bidirectionalParagraphInfo.bidirectionalInfoIndex,
+                                  lineInfoRun.characterRun.characterIndex - bidirectionalParagraphInfo.characterRun.characterIndex,
+                                  lineInfoRun.characterRun.numberOfCharacters,
+                                  lineInfoRun.visualToLogicalMap );
+
+    // For those LTR lines inside a bidirectional paragraph.
+    // It will save to relayout the line after reordering.
+    for( unsigned int i=0; i<numberOfCharacters; ++i )
+    {
+      if( i != *( lineInfoRun.visualToLogicalMap + i ) )
+      {
+        lineInfoRun.isIdentity = false;
+        break;
+      }
+    }
+  }
+
+  // Push the run into the vector.
+  lineInfoRuns.Insert( lineInfoRuns.Begin() + bidiLineIndex, lineInfoRun );
+}
+
+bool GetMirroredText( const Vector<Character>& text,
+                      const Vector<CharacterDirection>& directions,
+                      const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
+                      Vector<Character>& mirroredText )
+{
+  bool hasTextMirrored = false;
+
+  // Handle to the bidirectional info module in text-abstraction.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  mirroredText = text;
+
+  Character* mirroredTextBuffer = mirroredText.Begin();
+  CharacterDirection* directionsBuffer = directions.Begin();
+
+  CharacterIndex index = startIndex;
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+
+  // Traverse the paragraphs and mirror the right to left ones.
+  for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    const BidirectionalParagraphInfoRun& paragraph = *it;
+
+    if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+    {
+      // Skip the paragraph as it has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= paragraph.characterRun.characterIndex )
+    {
+      // Do not get mirror characters beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    index += paragraph.characterRun.numberOfCharacters;
+    const bool tmpMirrored = bidirectionalSupport.GetMirroredText( mirroredTextBuffer + paragraph.characterRun.characterIndex,
+                                                                   directionsBuffer + paragraph.characterRun.characterIndex,
+                                                                   paragraph.characterRun.numberOfCharacters );
+
+    hasTextMirrored = hasTextMirrored || tmpMirrored;
+  }
+
+  return hasTextMirrored;
+}
+
+void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                             Length totalNumberOfCharacters,
+                             CharacterIndex startIndex,
+                             Length numberOfCharacters,
+                             Vector<CharacterDirection>& directions )
+{
+  // Handle to the bidirectional info module in text-abstraction.
+  TextAbstraction::BidirectionalSupport bidirectionalSupport = TextAbstraction::BidirectionalSupport::Get();
+
+  // Resize the vector.
+  directions.Resize( totalNumberOfCharacters );
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  CharacterDirection* directionsBuffer = NULL;
+  Vector<CharacterDirection> newDirections;
+
+  if( updateCurrentBuffer )
+  {
+    newDirections.Resize( numberOfCharacters );
+    directionsBuffer = newDirections.Begin();
+  }
+  else
+  {
+    directionsBuffer = directions.Begin();
+  }
+
+  const CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+  CharacterIndex index = startIndex;
+
+  for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalInfo.Begin(),
+         endIt = bidirectionalInfo.End();
+       it != endIt;
+       ++it )
+  {
+    const BidirectionalParagraphInfoRun& paragraph = *it;
+
+    if( index >= paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+    {
+      // Skip the paragraph as it has already been processed.
+      continue;
+    }
+
+    if( lastCharacter <= paragraph.characterRun.characterIndex )
+    {
+      // Do not get the character directions beyond startIndex + numberOfCharacters.
+      break;
+    }
+
+    // Set the directions of any previous left to right characters.
+    const Length numberOfLeftToRightCharacters = paragraph.characterRun.characterIndex - index;
+    if( numberOfLeftToRightCharacters > 0u )
+    {
+      memset( directionsBuffer + index - startIndex, false, numberOfLeftToRightCharacters * sizeof( bool ) );
+    }
+
+    // Set the directions of the bidirectional text.
+    bidirectionalSupport.GetCharactersDirection( paragraph.bidirectionalInfoIndex,
+                                                 directionsBuffer + paragraph.characterRun.characterIndex - startIndex,
+                                                 paragraph.characterRun.numberOfCharacters );
+
+    // Update the index.
+    index += paragraph.characterRun.numberOfCharacters + numberOfLeftToRightCharacters;
+  }
+
+  // Fills with left to right those paragraphs without right to left characters.
+  memset( directionsBuffer + index - startIndex, false, ( lastCharacter - index ) * sizeof( bool ) );
+
+  // If the direction info is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    // Insert the directions in the given buffer.
+    directions.Insert( directions.Begin() + startIndex,
+                       newDirections.Begin(),
+                       newDirections.End() );
+    directions.Resize( totalNumberOfCharacters );
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/bidirectional-support.h b/dali-toolkit/internal/text/bidirectional-support.h
new file mode 100755 (executable)
index 0000000..4f92c62
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_TOOLKIT_TEXT_BIDIRECTIONAL_SUPPORT_H
+#define DALI_TOOLKIT_TEXT_BIDIRECTIONAL_SUPPORT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
+#include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * Sets the bidirectional info into the logical model.
+ *
+ * @param[in] text Vector of UTF-32 characters.
+ * @param[in] scripts Vector containing the script runs for the whole text.
+ * @param[in] lineBreakInfo The line break info.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[out] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] matchSystemLanguageDirection Whether match for system language direction or not.
+ * @param[in] layoutDirection The direction of the system language.
+ */
+void SetBidirectionalInfo( const Vector<Character>& text,
+                           const Vector<ScriptRun>& scripts,
+                           const Vector<LineBreakInfo>& lineBreakInfo,
+                           CharacterIndex startIndex,
+                           Length numberOfCharacters,
+                           Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                           bool matchSystemLanguageDirection = false,
+                           Dali::LayoutDirection::Type layoutDirection = LayoutDirection::LEFT_TO_RIGHT );
+
+/**
+ * @brief Sets the visual to logical map table for a given line.
+ *
+ * @param[in] bidirectionalParagraphInfo The paragraph's bidirectional info.
+ * @param[out] lineInfoRuns Line runs with the visual to logical conversion maps.
+ * @param[in] bidiLineIndex Index to the line's bidirectional info.
+ * @param[in] startIndex The character from where the bidirectional info is set.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[in] direction The direction of the line.
+ */
+void ReorderLine( const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
+                  Vector<BidirectionalLineInfoRun>& lineInfoRuns,
+                  BidirectionalLineRunIndex bidiLineIndex,
+                  CharacterIndex startIndex,
+                  Length numberOfCharacters,
+                  CharacterDirection direction );
+
+/**
+ * @brief Replaces any character in the right to left paragraphs which could be mirrored.
+ *
+ * @param[in] text The text.
+ * @param[in] directions Vector with the direction of each paragraph.
+ * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] startIndex The character from where the text is mirrored.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[out] mirroredText The mirroredText.
+ *
+ * @return @e true if a character has been replaced.
+ */
+bool GetMirroredText( const Vector<Character>& text,
+                      const Vector<CharacterDirection>& directions,
+                      const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
+                      Vector<Character>& mirroredText );
+
+/**
+ * @brief Retrieves the characters' directions.
+ *
+ * @pre The @p logicalModel needs to have a text set.
+ * @pre The @p logicalModel needs to have the bidirectional info indices for each paragraph set.
+ *
+ * @param[in] bidirectionalInfo Vector with the bidirectional infor for each paragraph.
+ * @param[in] totalNumberOfCharacters The number of characters of the whole text.
+ * @param[in] startIndex The character from where the direction info is set.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[out] directions The direction, @e false is left to right and @e true is right to left, of each character of the paragraph.
+ */
+void GetCharactersDirection( const Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo,
+                             Length totalNumberOfCharacters,
+                             CharacterIndex startIndex,
+                             Length numberOfCharacters,
+                             Vector<CharacterDirection>& directions );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_BIDIRECTIONAL_SUPPORT_H
diff --git a/dali-toolkit/internal/text/character-run.h b/dali-toolkit/internal/text/character-run.h
new file mode 100644 (file)
index 0000000..eb354c9
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef DALI_TOOLKIT_TEXT_CHARACTER_RUN_H
+#define DALI_TOOLKIT_TEXT_CHARACTER_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A run of consecutive characters.
+ */
+struct CharacterRun
+{
+  CharacterRun()
+  : characterIndex{ 0u },
+    numberOfCharacters{ 0u }
+  {}
+
+  CharacterRun( CharacterIndex characterIndex, Length numberOfCharacters )
+  : characterIndex{ characterIndex },
+    numberOfCharacters{ numberOfCharacters }
+  {}
+
+  CharacterIndex characterIndex;     ///< Index to the first character.
+  Length         numberOfCharacters; ///< Number of characters in the run.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CHARACTER_RUN_H
diff --git a/dali-toolkit/internal/text/character-set-conversion.cpp b/dali-toolkit/internal/text/character-set-conversion.cpp
new file mode 100644 (file)
index 0000000..7402292
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+  const static uint8_t U1 = 1u;
+  const static uint8_t U2 = 2u;
+  const static uint8_t U3 = 3u;
+  const static uint8_t U4 = 4u;
+  const static uint8_t U5 = 5u;
+  const static uint8_t U6 = 6u;
+  const static uint8_t U0 = 0u;
+  const static uint8_t UTF8_LENGTH[256] = {
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, // lead byte = 0xxx xxxx (U+0000 - U+007F + some extended ascii characters)
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+    U1, U1,                                 //
+
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, // lead byte = 110x xxxx (U+0080 - U+07FF)
+    U2, U2, U2, U2, U2, U2, U2, U2, U2, U2, //
+    U2, U2,                                 //
+
+    U3, U3, U3, U3, U3, U3, U3, U3, U3, U3, // lead byte = 1110 xxxx (U+0800 - U+FFFF)
+    U3, U3, U3, U3, U3, U3,                 //
+
+    U4, U4, U4, U4, U4, U4, U4, U4,         // lead byte = 1111 0xxx (U+10000 - U+1FFFFF)
+
+    U5, U5, U5, U5,                         // lead byte = 1111 10xx (U+200000 - U+3FFFFFF)
+
+    U6, U6,                                 // lead byte = 1111 110x (U+4000000 - U+7FFFFFFF)
+
+    U0, U0,                                 // Non valid.
+  };
+
+  const uint8_t CR = 0xd;
+  const uint8_t LF = 0xa;
+} // namespace
+
+uint8_t GetUtf8Length( uint8_t utf8LeadByte )
+{
+  return UTF8_LENGTH[utf8LeadByte];
+}
+
+uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length )
+{
+  uint32_t numberOfCharacters = 0u;
+
+  const uint8_t* begin = utf8;
+  const uint8_t* end = utf8 + length;
+
+  for( ; begin < end ; begin += UTF8_LENGTH[*begin], ++numberOfCharacters );
+
+  return numberOfCharacters;
+}
+
+uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters )
+{
+  uint32_t numberOfBytes = 0u;
+
+  const uint32_t* begin = utf32;
+  const uint32_t* end = utf32 + numberOfCharacters;
+
+  for( ; begin < end; ++begin )
+  {
+    const uint32_t code = *begin;
+
+    if( code < 0x80u )
+    {
+      ++numberOfBytes;
+    }
+    else if( code < 0x800u )
+    {
+      numberOfBytes += U2;
+    }
+    else if( code < 0x10000u )
+    {
+      numberOfBytes += U3;
+    }
+    else if( code < 0x200000u )
+    {
+      numberOfBytes += U4;
+    }
+    else if( code < 0x4000000u )
+    {
+      numberOfBytes += U5;
+    }
+    else if( code < 0x80000000u )
+    {
+      numberOfBytes += U6;
+    }
+  }
+
+  return numberOfBytes;
+}
+
+uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 )
+{
+  uint32_t numberOfCharacters = 0u;
+
+  const uint8_t* begin = utf8;
+  const uint8_t* end = utf8 + length;
+
+  for( ; begin < end ; ++numberOfCharacters )
+  {
+    const uint8_t leadByte = *begin;
+
+    switch( UTF8_LENGTH[leadByte] )
+    {
+      case U1:
+      {
+        if( CR == leadByte )
+        {
+          // Replace CR+LF or CR by LF
+          *utf32++ = LF;
+
+          // Look ahead if the next one is a LF.
+          ++begin;
+          if( begin < end )
+          {
+            if( LF == *begin )
+            {
+              ++begin;
+            }
+          }
+        }
+        else
+        {
+          *utf32++ = leadByte;
+          begin++;
+        }
+        break;
+      }
+
+      case U2:
+      {
+        uint32_t& code = *utf32++;
+        code = leadByte & 0x1fu;
+        begin++;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        break;
+      }
+
+      case U3:
+      {
+        uint32_t& code = *utf32++;
+        code = leadByte & 0x0fu;
+        begin++;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        break;
+      }
+
+      case U4:
+      {
+        uint32_t& code = *utf32++;
+        code = leadByte & 0x07u;
+        begin++;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        break;
+      }
+
+      case U5:
+      {
+        uint32_t& code = *utf32++;
+        code = leadByte & 0x03u;
+        begin++;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        break;
+      }
+
+      case U6:
+      {
+        uint32_t& code = *utf32++;
+        code = leadByte & 0x01u;
+        begin++;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        code <<= 6u;
+        code |= *begin++ & 0x3fu;
+        break;
+      }
+
+      case U0:    // Invalid case
+      {
+        begin++;
+        *utf32++ = 0x20;    // Use white space
+        break;
+      }
+    }
+  }
+
+  return numberOfCharacters;
+}
+
+uint32_t Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 )
+{
+  const uint32_t* begin = utf32;
+  const uint32_t* end = utf32 + numberOfCharacters;
+
+  uint8_t* utf8Begin = utf8;
+
+  for( ; begin < end; ++begin )
+  {
+    const uint32_t code = *begin;
+
+    if( code < 0x80u )
+    {
+      *utf8++ = code;
+    }
+    else if( code < 0x800u )
+    {
+      *utf8++ = static_cast<uint8_t>(   code >> 6u )           | 0xc0u; // lead byte for 2 byte sequence
+      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
+    }
+    else if( code < 0x10000u )
+    {
+      *utf8++ = static_cast<uint8_t>(   code >> 12u )          | 0xe0u; // lead byte for 3 byte sequence
+      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
+    }
+    else if( code < 0x200000u )
+    {
+      *utf8++ = static_cast<uint8_t>(   code >> 18u )          | 0xf0u; // lead byte for 4 byte sequence
+      *utf8++ = static_cast<uint8_t>( ( code >> 12u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
+    }
+    else if( code < 0x4000000u )
+    {
+      *utf8++ = static_cast<uint8_t>(   code >> 24u )          | 0xf8u; // lead byte for 5 byte sequence
+      *utf8++ = static_cast<uint8_t>( ( code >> 18u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 12u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
+    }
+    else if( code < 0x80000000u )
+    {
+      *utf8++ = static_cast<uint8_t>(   code >> 30u )          | 0xfcu; // lead byte for 6 byte sequence
+      *utf8++ = static_cast<uint8_t>( ( code >> 24u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 18u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 12u ) & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>( ( code >> 6u )  & 0x3f ) | 0x80u; // continuation byte
+      *utf8++ = static_cast<uint8_t>(   code          & 0x3f ) | 0x80u; // continuation byte
+    }
+  }
+
+  return utf8 - utf8Begin;
+}
+
+void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std::string& utf8 )
+{
+  utf8.clear();
+
+  uint32_t numberOfBytes = GetNumberOfUtf8Bytes( &utf32[0], numberOfCharacters );
+  utf8.resize( numberOfBytes );
+
+  // This is a bit horrible but std::string returns a (signed) char*
+  Utf32ToUtf8( utf32, numberOfCharacters, reinterpret_cast<uint8_t*>(&utf8[0]) );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/character-set-conversion.h b/dali-toolkit/internal/text/character-set-conversion.h
new file mode 100644 (file)
index 0000000..168c525
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_TOOLKIT_CHARACTER_SET_CONVERSION_H
+#define DALI_TOOLKIT_CHARACTER_SET_CONVERSION_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+#include <string>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Retrieves the number of bytes of a utf8 character.
+ *
+ * @param[in] utf8LeadByte The lead byte of the utf8 character.
+ *
+ * @return The number of bytes of the character.
+ */
+uint8_t GetUtf8Length( uint8_t utf8LeadByte );
+
+/**
+ * @brief Retrieves the number of characters of the text array encoded in UTF8
+ *
+ * @param[in] utf8 The pointer to the UTF8 array.
+ * @param[in] length The length of the UTF8 array.
+ *
+ * @return The number of characters.
+ */
+uint32_t GetNumberOfUtf8Characters( const uint8_t* const utf8, uint32_t length );
+
+/**
+ * @brief Retrieves the number of bytes needed to encode in UTF8 the given text array encoded in UTF32.
+ *
+ * @param[in] utf32 The pointer to the UTF32 array.
+ * @param[in] numberOfCharacters The number of characters of the UTF32 array.
+ *
+ * @return The number of bytes.
+ */
+uint32_t GetNumberOfUtf8Bytes( const uint32_t* const utf32, uint32_t numberOfCharacters );
+
+/**
+ * @brief Converts a text array encoded in UTF8 into a text array encoded in UTF32.
+ *
+ * The @p utf32 buffer needs to be big enough to store all the characters.
+ *
+ * If the text contains a single 'CR' character or a pair 'CR'+'LF', they are replaced by a 'LF'.
+ *
+ * @note GetNumberOfUtf8Characters() does not convert 'CR' or 'CR'+'LF' to 'LF' so the return number
+ * of characters of that method may be higher than the number of characters returned by this one.
+ *
+ * @param[in] utf8 The pointer to the UTF8 array.
+ * @param[in] length The length of the UTF8 array.
+ * @param[out] utf32 The pointer to the UTF32 array.
+ *
+ * @return The number of characters.
+ */
+uint32_t Utf8ToUtf32( const uint8_t* const utf8, uint32_t length, uint32_t* utf32 );
+
+/**
+ * @brief Converts a text array encoded in UTF32 into a text array encoded in UTF8.
+ *
+ * The @p utf8 buffer needs to be big enough to store all the characters.
+ *
+ * @param[in] utf32 The pointer to the UTF32 array.
+ * @param[in] numberOfCharacters The number of characters of the UTF32 array.
+ * @param[out] utf8 The pointer to the UTF8 array.
+ *
+ * @return The number of bytes.
+ */
+uint32_t Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, uint8_t* utf8 );
+
+/**
+ * @brief Converts a text array encoded in UTF32 into a text array encoded in UTF8.
+ *
+ * @param[in] utf32 The pointer to the UTF32 array.
+ * @param[in] numberOfCharacters The number of characters of the UTF32 array.
+ * @param[out] utf8 The UTF8 characters will be stored here.
+ */
+void Utf32ToUtf8( const uint32_t* const utf32, uint32_t numberOfCharacters, std::string& utf8 );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CHARACTER_SET_CONVERSION_H
diff --git a/dali-toolkit/internal/text/color-run.h b/dali-toolkit/internal/text/color-run.h
new file mode 100644 (file)
index 0000000..ad5e6db
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_TOOLKIT_TEXT_COLOR_RUN_H
+#define DALI_TOOLKIT_TEXT_COLOR_RUN_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Run of characters with the same color.
+ */
+struct ColorRun
+{
+  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+  Vector4      color;        ///< The color of the characters.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_COLOR_RUN_H
diff --git a/dali-toolkit/internal/text/color-segmentation.cpp b/dali-toolkit/internal/text/color-segmentation.cpp
new file mode 100644 (file)
index 0000000..3c2f76a
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/color-segmentation.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+#include <iostream>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @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,
+                               CharacterIndex startCharacterIndex,
+                               GlyphIndex startGlyphIndex,
+                               Length numberOfCharacters,
+                               Vector<Vector4>& colors,
+                               Vector<ColorIndex>& colorIndices )
+{
+  if( 0u == charactersToGlyph.Count() )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  // Get pointers to the buffers.
+  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 = colorRuns.Begin(),
+         endIt = colorRuns.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const ColorRun& colorRun = *it;
+
+    if( ( startCharacterIndex < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) &&
+        ( colorRun.characterRun.characterIndex < startCharacterIndex + numberOfCharacters ) )
+    {
+      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
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/color-segmentation.h b/dali-toolkit/internal/text/color-segmentation.h
new file mode 100644 (file)
index 0000000..cde9997
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H
+#define DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+
+/**
+ * @brief Creates color glyph runs.
+ *
+ * @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[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>& colorRuns,
+                               const Vector<GlyphIndex>& charactersToGlyph,
+                               const Vector<Length>& glyphsPerCharacter,
+                               CharacterIndex startCharacterIndex,
+                               GlyphIndex startGlyphIndex,
+                               Length numberOfCharacters,
+                               Vector<Vector4>& colors,
+                               Vector<ColorIndex>& colorIndices );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H
diff --git a/dali-toolkit/internal/text/cursor-helper-functions.cpp b/dali-toolkit/internal/text/cursor-helper-functions.cpp
new file mode 100644 (file)
index 0000000..19db7ae
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction.
+
+struct FindWordData
+{
+  FindWordData( const Dali::Toolkit::Text::Character* const textBuffer,
+                Dali::Toolkit::Text::Length totalNumberOfCharacters,
+                Dali::Toolkit::Text::CharacterIndex hitCharacter,
+                bool isWhiteSpace,
+                bool isNewParagraph )
+  : textBuffer( textBuffer ),
+    totalNumberOfCharacters( totalNumberOfCharacters ),
+    hitCharacter( hitCharacter ),
+    foundIndex( 0 ),
+    isWhiteSpace( isWhiteSpace ),
+    isNewParagraph( isNewParagraph )
+  {}
+
+  ~FindWordData()
+  {}
+
+  const Dali::Toolkit::Text::Character* const textBuffer;
+  Dali::Toolkit::Text::Length                 totalNumberOfCharacters;
+  Dali::Toolkit::Text::CharacterIndex         hitCharacter;
+  Dali::Toolkit::Text::CharacterIndex         foundIndex;
+  bool                                        isWhiteSpace   : 1u;
+  bool                                        isNewParagraph : 1u;
+};
+
+bool IsWhiteSpaceOrNewParagraph( Dali::Toolkit::Text::Character character,
+                                 bool isHitWhiteSpace,
+                                 bool isHitWhiteSpaceOrNewParagraph )
+{
+  bool isWhiteSpaceOrNewParagraph = false;
+  if( isHitWhiteSpaceOrNewParagraph )
+  {
+    if( isHitWhiteSpace )
+    {
+      // Whether the current character is a white space. Note a new paragraph character is a white space as well but here is not wanted.
+      isWhiteSpaceOrNewParagraph = Dali::TextAbstraction::IsWhiteSpace( character ) && !Dali::TextAbstraction::IsNewParagraph( character );
+    }
+    else
+    {
+      // Whether the current character is a new paragraph character.
+      isWhiteSpaceOrNewParagraph = Dali::TextAbstraction::IsNewParagraph( character );
+    }
+  }
+  else
+  {
+    // Whether the current character is a white space or a new paragraph character (note the new paragraph character is a white space as well).
+    isWhiteSpaceOrNewParagraph = Dali::TextAbstraction::IsWhiteSpace( character );
+  }
+
+  return isWhiteSpaceOrNewParagraph;
+}
+
+void FindStartOfWord( FindWordData& data )
+{
+  const bool isHitWhiteSpaceOrNewParagraph = data.isWhiteSpace || data.isNewParagraph;
+
+  for( data.foundIndex = data.hitCharacter; data.foundIndex > 0; --data.foundIndex )
+  {
+    const Dali::Toolkit::Text::Character character = *( data.textBuffer + data.foundIndex - 1u );
+
+    const bool isWhiteSpaceOrNewParagraph = IsWhiteSpaceOrNewParagraph( character,
+                                                                        data.isWhiteSpace,
+                                                                        isHitWhiteSpaceOrNewParagraph );
+
+    if( isHitWhiteSpaceOrNewParagraph != isWhiteSpaceOrNewParagraph )
+    {
+      break;
+    }
+  }
+}
+
+void FindEndOfWord( FindWordData& data )
+{
+  const bool isHitWhiteSpaceOrNewParagraph = data.isWhiteSpace || data.isNewParagraph;
+
+  for( data.foundIndex = data.hitCharacter + 1u; data.foundIndex < data.totalNumberOfCharacters; ++data.foundIndex )
+  {
+    const Dali::Toolkit::Text::Character character = *( data.textBuffer + data.foundIndex );
+
+    const bool isWhiteSpaceOrNewParagraph = IsWhiteSpaceOrNewParagraph( character,
+                                                                        data.isWhiteSpace,
+                                                                        isHitWhiteSpaceOrNewParagraph );
+
+    if( isHitWhiteSpaceOrNewParagraph != isWhiteSpaceOrNewParagraph )
+    {
+      break;
+    }
+  }
+}
+
+} //namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+LineIndex GetClosestLine( VisualModelPtr visualModel,
+                          float visualY,
+                          bool& matchedLine )
+{
+  float totalHeight = 0.f;
+  LineIndex lineIndex = 0;
+  matchedLine = false;
+
+  if( visualY < 0.f )
+  {
+    return 0;
+  }
+
+  const Vector<LineRun>& lines = visualModel->mLines;
+
+  for( Vector<LineRun>::ConstIterator it = lines.Begin(),
+         endIt = lines.End();
+       it != endIt;
+       ++it, ++lineIndex )
+  {
+    const LineRun& lineRun = *it;
+
+    // The line height is the addition of the line ascender and the line descender.
+    // However, the line descender has a negative value, hence the subtraction.
+    totalHeight += lineRun.ascender - lineRun.descender;
+
+    if( visualY < totalHeight )
+    {
+      matchedLine = true;
+      return lineIndex;
+    }
+  }
+
+  if( lineIndex == 0 )
+  {
+    return 0;
+  }
+
+  return lineIndex - 1u;
+}
+
+float CalculateLineOffset( const Vector<LineRun>& lines,
+                           LineIndex lineIndex )
+{
+  float offset = 0.f;
+
+  for( Vector<LineRun>::ConstIterator it = lines.Begin(),
+         endIt = lines.Begin() + lineIndex;
+       it != endIt;
+       ++it )
+  {
+    const LineRun& lineRun = *it;
+
+    // The line height is the addition of the line ascender and the line descender.
+    // However, the line descender has a negative value, hence the subtraction.
+    offset += lineRun.ascender - lineRun.descender;
+  }
+
+  return offset;
+}
+
+CharacterIndex GetClosestCursorIndex( VisualModelPtr visualModel,
+                                      LogicalModelPtr logicalModel,
+                                      MetricsPtr metrics,
+                                      float visualX,
+                                      float visualY,
+                                      CharacterHitTest::Mode mode,
+                                      bool& matchedCharacter )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetClosestCursorIndex, closest visualX %f visualY %f\n", visualX, visualY );
+
+  // Whether there is a hit on a glyph.
+  matchedCharacter = false;
+
+  CharacterIndex logicalIndex = 0;
+
+  const Length totalNumberOfGlyphs = visualModel->mGlyphs.Count();
+  const Length totalNumberOfLines  = visualModel->mLines.Count();
+  if( ( 0 == totalNumberOfGlyphs ) ||
+      ( 0 == totalNumberOfLines ) )
+  {
+    return logicalIndex;
+  }
+
+  // Whether there is a hit on a line.
+  bool matchedLine = false;
+
+  // Find which line is closest.
+  const LineIndex lineIndex = Text::GetClosestLine( visualModel,
+                                                    visualY,
+                                                    matchedLine );
+
+  if( !matchedLine && ( CharacterHitTest::TAP == mode ) )
+  {
+    // Return the first or the last character if the touch point doesn't hit a line.
+    return ( visualY < 0.f ) ? 0 : logicalModel->mText.Count();
+  }
+
+  // Convert from text's coords to line's coords.
+  const LineRun& line = *( visualModel->mLines.Begin() + lineIndex );
+
+  // Transform the tap point from text's coords to line's coords.
+  visualX -= line.alignmentOffset;
+
+  // Get the positions of the glyphs.
+  const Vector2* const positionsBuffer = visualModel->mGlyphPositions.Begin();
+
+  // Get the character to glyph conversion table.
+  const GlyphIndex* const charactersToGlyphBuffer = visualModel->mCharactersToGlyph.Begin();
+
+  // Get the glyphs per character table.
+  const Length* const glyphsPerCharacterBuffer = visualModel->mGlyphsPerCharacter.Begin();
+
+  // Get the characters per glyph table.
+  const Length* const charactersPerGlyphBuffer = visualModel->mCharactersPerGlyph.Begin();
+
+  // Get the glyph's info buffer.
+  const GlyphInfo* const glyphInfoBuffer = visualModel->mGlyphs.Begin();
+
+  const CharacterIndex startCharacter = line.characterRun.characterIndex;
+  const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
+  DALI_ASSERT_DEBUG( endCharacter <= logicalModel->mText.Count() && "Invalid line info" );
+
+  // Whether this line is a bidirectional line.
+  const bool bidiLineFetched = logicalModel->FetchBidirectionalLineInfo( startCharacter );
+
+  // The character's direction buffer.
+  const CharacterDirection* const directionsBuffer = bidiLineFetched ? logicalModel->mCharacterDirections.Begin() : NULL;
+
+  // Whether the touch point if before the first glyph.
+  bool isBeforeFirstGlyph = false;
+
+  // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
+  CharacterIndex visualIndex = startCharacter;
+  Length numberOfVisualCharacters = 0;
+  for( ; visualIndex < endCharacter; ++visualIndex )
+  {
+    // The character in logical order.
+    const CharacterIndex characterLogicalOrderIndex = ( bidiLineFetched ? logicalModel->GetLogicalCharacterIndex( visualIndex ) : visualIndex );
+    const CharacterDirection direction = ( bidiLineFetched ? *( directionsBuffer + characterLogicalOrderIndex ) : LTR );
+
+    // The number of glyphs for that character
+    const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
+    ++numberOfVisualCharacters;
+
+    if( 0 != numberOfGlyphs )
+    {
+      // Get the first character/glyph of the group of glyphs.
+      const CharacterIndex firstVisualCharacterIndex = 1u + visualIndex - numberOfVisualCharacters;
+      const CharacterIndex firstLogicalCharacterIndex = ( bidiLineFetched ? logicalModel->GetLogicalCharacterIndex( firstVisualCharacterIndex ) : firstVisualCharacterIndex );
+      const GlyphIndex firstLogicalGlyphIndex = *( charactersToGlyphBuffer + firstLogicalCharacterIndex );
+
+      // Get the metrics for the group of glyphs.
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( firstLogicalGlyphIndex,
+                        numberOfGlyphs,
+                        glyphMetrics,
+                        glyphInfoBuffer,
+                        metrics );
+
+      // Get the position of the first glyph.
+      const Vector2& position = *( positionsBuffer + firstLogicalGlyphIndex );
+
+      if( startCharacter == visualIndex )
+      {
+        const float glyphPosition = -glyphMetrics.xBearing + position.x;
+
+        if( visualX < glyphPosition )
+        {
+          isBeforeFirstGlyph = true;
+          break;
+        }
+      }
+
+      // Whether the glyph can be split, like Latin ligatures fi, ff or Arabic (ل + ا).
+      Length numberOfCharacters = *( charactersPerGlyphBuffer + firstLogicalGlyphIndex );
+      if( direction != LTR )
+      {
+        // As characters are being traversed in visual order,
+        // for right to left ligatures, the character which contains the
+        // number of glyphs in the table is found first.
+        // Jump the number of characters to the next glyph is needed.
+
+        if( 0 == numberOfCharacters )
+        {
+          // TODO: This is a workaround to fix an issue with complex characters in the arabic
+          // script like i.e. رّ or الأَبْجَدِيَّة العَرَبِيَّة
+          // There are characters that are not shaped in one glyph but in combination with
+          // the next one generates two of them.
+          // The visual to logical conversion table have characters in different order than
+          // expected even if all of them are arabic.
+
+          // The workaround doesn't fix the issue completely but it prevents the application
+          // to hang in an infinite loop.
+
+          // Find the number of characters.
+          for( GlyphIndex index = firstLogicalGlyphIndex + 1u;
+               ( 0 == numberOfCharacters ) && ( index < totalNumberOfGlyphs );
+               ++index )
+          {
+            numberOfCharacters = *( charactersPerGlyphBuffer + index );
+          }
+
+          if( 2u > numberOfCharacters )
+          {
+            continue;
+          }
+
+          --numberOfCharacters;
+        }
+
+        visualIndex += numberOfCharacters - 1u;
+      }
+
+      // Get the script of the character.
+      const Script script = logicalModel->GetScript( characterLogicalOrderIndex );
+
+      const bool isInterglyphIndex = ( numberOfCharacters > numberOfGlyphs ) && HasLigatureMustBreak( script );
+      const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u;
+      const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfBlocks );
+
+      CharacterIndex index = 0;
+      for( ; index < numberOfBlocks; ++index )
+      {
+        // Find the mid-point of the area containing the glyph
+        const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
+
+        if( visualX < glyphCenter )
+        {
+          matchedCharacter = true;
+          break;
+        }
+      }
+
+      if( matchedCharacter )
+      {
+        // If the glyph is shaped from more than one character, it matches the character of the glyph.
+        visualIndex = firstVisualCharacterIndex + index;
+        break;
+      }
+
+      numberOfVisualCharacters = 0;
+    }
+  } // for characters in visual order.
+
+  // The number of characters of the whole text.
+  const Length totalNumberOfCharacters = logicalModel->mText.Count();
+
+  // Return the logical position of the cursor in characters.
+
+  if( !matchedCharacter )
+  {
+    if( isBeforeFirstGlyph )
+    {
+      // If no character is matched, then the first character (in visual order) of the line is used.
+      visualIndex = startCharacter;
+    }
+    else
+    {
+      // If no character is matched, then the last character (in visual order) of the line is used.
+      visualIndex = endCharacter;
+    }
+  }
+
+  // Get the paragraph direction.
+  const CharacterDirection paragraphDirection = line.direction;
+
+  if( totalNumberOfCharacters != visualIndex )
+  {
+    // The visual index is not at the end of the text.
+
+    if( LTR == paragraphDirection )
+    {
+      // The paragraph direction is left to right.
+
+      if( visualIndex == endCharacter )
+      {
+        // It places the cursor just before the last character in visual order.
+        // i.e. it places the cursor just before the '\n' or before the last character
+        // if there is a long line with no word breaks which is wrapped.
+
+        // It doesn't check if the closest line is the last one like the RTL branch below
+        // because the total number of characters is different than the visual index and
+        // the visual index is the last character of the line.
+        --visualIndex;
+      }
+    }
+    else
+    {
+      // The paragraph direction is right to left.
+
+      if( ( lineIndex != totalNumberOfLines - 1u ) && // is not the last line.
+          ( visualIndex == startCharacter ) )
+      {
+        // It places the cursor just after the first character in visual order.
+        // i.e. it places the cursor just after the '\n' or after the last character
+        // if there is a long line with no word breaks which is wrapped.
+
+        // If the last line doesn't end with '\n' it won't increase the visual index
+        // placing the cursor at the beginning of the line (in visual order).
+        ++visualIndex;
+      }
+    }
+  }
+  else
+  {
+    // The visual index is at the end of text.
+
+    // If the text ends with a new paragraph character i.e. a '\n', an extra line with no characters is added at the end of the text.
+    // This branch checks if the closest line is the one with the last '\n'. If it is, it decrements the visual index to place
+    // the cursor just before the last '\n'.
+
+    if( ( lineIndex != totalNumberOfLines - 1u ) &&
+        TextAbstraction::IsNewParagraph( *( logicalModel->mText.Begin() + visualIndex - 1u ) ) )
+    {
+      --visualIndex;
+    }
+  }
+
+  logicalIndex = ( bidiLineFetched ? logicalModel->GetLogicalCursorIndex( visualIndex ) : visualIndex );
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "closest visualIndex %d logicalIndex %d\n", visualIndex, logicalIndex );
+
+  DALI_ASSERT_DEBUG( ( logicalIndex <= logicalModel->mText.Count() && logicalIndex >= 0 ) && "GetClosestCursorIndex - Out of bounds index" );
+
+  return logicalIndex;
+}
+
+
+void GetCursorPosition( GetCursorPositionParameters& parameters,
+                        CursorInfo& cursorInfo )
+{
+  const LineRun* const modelLines = parameters.visualModel->mLines.Begin();
+  if( NULL == modelLines )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  // Whether the logical cursor position is at the end of the whole text.
+  const bool isLastPosition = parameters.logicalModel->mText.Count() == parameters.logical;
+
+  // Get the line where the character is laid-out.
+  const CharacterIndex characterOfLine = isLastPosition ? ( parameters.logical - 1u ) : parameters.logical;
+
+  // Whether the cursor is in the last position and the last position is a new paragraph character.
+  const bool isLastNewParagraph = parameters.isMultiline && isLastPosition && TextAbstraction::IsNewParagraph( *( parameters.logicalModel->mText.Begin() + characterOfLine ) );
+
+  const LineIndex lineIndex = parameters.visualModel->GetLineOfCharacter( characterOfLine );
+  const LineRun& line = *( modelLines + lineIndex );
+
+  if( isLastNewParagraph )
+  {
+    // The cursor is in a new line with no characters. Place the cursor in that line.
+    const LineIndex newLineIndex = lineIndex + 1u;
+    const LineRun& newLine = *( modelLines + newLineIndex );
+
+    cursorInfo.isSecondaryCursor = false;
+
+    // Set the line offset and height.
+    cursorInfo.lineOffset = CalculateLineOffset( parameters.visualModel->mLines,
+                                                 newLineIndex );
+
+    // The line height is the addition of the line ascender and the line descender.
+    // However, the line descender has a negative value, hence the subtraction.
+    cursorInfo.lineHeight = newLine.ascender - newLine.descender;
+
+    // Set the primary cursor's height.
+    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+
+    // Set the primary cursor's position.
+    cursorInfo.primaryPosition.x = ( LTR == line.direction ) ? newLine.alignmentOffset : parameters.visualModel->mControlSize.width - newLine.alignmentOffset;
+    cursorInfo.primaryPosition.y = cursorInfo.lineOffset;
+  }
+  else
+  {
+    // Whether this line is a bidirectional line.
+    const bool bidiLineFetched = parameters.logicalModel->FetchBidirectionalLineInfo( characterOfLine );
+
+    // Check if the logical position is the first or the last one of the line.
+    const bool isFirstPositionOfLine = line.characterRun.characterIndex == parameters.logical;
+    const bool isLastPositionOfLine = line.characterRun.characterIndex + line.characterRun.numberOfCharacters == parameters.logical;
+
+    // 'logical' is the logical 'cursor' index.
+    // Get the next and current logical 'character' index.
+    const CharacterIndex characterIndex = isFirstPositionOfLine ? parameters.logical : parameters.logical - 1u;
+    const CharacterIndex nextCharacterIndex = isLastPositionOfLine ? characterIndex : parameters.logical;
+
+    // The character's direction buffer.
+    const CharacterDirection* const directionsBuffer = bidiLineFetched ? parameters.logicalModel->mCharacterDirections.Begin() : NULL;
+
+    CharacterDirection isCurrentRightToLeft = false;
+    CharacterDirection isNextRightToLeft = false;
+    if( bidiLineFetched ) // If bidiLineFetched is false, it means the whole text is left to right.
+    {
+      isCurrentRightToLeft = *( directionsBuffer + characterIndex );
+      isNextRightToLeft = *( directionsBuffer + nextCharacterIndex );
+    }
+
+    // Get the paragraph's direction.
+    const CharacterDirection isRightToLeftParagraph = line.direction;
+
+    // Check whether there is an alternative position:
+    cursorInfo.isSecondaryCursor = ( ( !isLastPositionOfLine && ( isCurrentRightToLeft != isNextRightToLeft ) )     ||
+                                     ( isLastPositionOfLine && ( isRightToLeftParagraph != isCurrentRightToLeft ) ) ||
+                                     ( isFirstPositionOfLine && ( isRightToLeftParagraph != isCurrentRightToLeft ) ) );
+
+    // Set the line offset and height.
+    cursorInfo.lineOffset = CalculateLineOffset( parameters.visualModel->mLines,
+                                                 lineIndex );
+
+    // The line height is the addition of the line ascender and the line descender.
+    // However, the line descender has a negative value, hence the subtraction.
+    cursorInfo.lineHeight = line.ascender - line.descender;
+
+    // Calculate the primary cursor.
+
+    CharacterIndex index = characterIndex;
+    if( cursorInfo.isSecondaryCursor )
+    {
+      // If there is a secondary position, the primary cursor may be in a different place than the logical index.
+
+      if( isLastPositionOfLine )
+      {
+        // The position of the cursor after the last character needs special
+        // care depending on its direction and the direction of the paragraph.
+
+        // Need to find the first character after the last character with the paragraph's direction.
+        // i.e l0 l1 l2 r0 r1 should find r0.
+
+        index = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
+        if( bidiLineFetched )
+        {
+          index = parameters.logicalModel->GetLogicalCharacterIndex( index );
+        }
+      }
+      else if( isFirstPositionOfLine )
+      {
+        index = isRightToLeftParagraph ? line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u : line.characterRun.characterIndex;
+        if( bidiLineFetched )
+        {
+          index = parameters.logicalModel->GetLogicalCharacterIndex( index );
+        }
+      }
+      else
+      {
+        index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? characterIndex : nextCharacterIndex;
+      }
+    }
+
+    const GlyphIndex* const charactersToGlyphBuffer = parameters.visualModel->mCharactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = parameters.visualModel->mGlyphsPerCharacter.Begin();
+    const Length* const charactersPerGlyphBuffer = parameters.visualModel->mCharactersPerGlyph.Begin();
+    const CharacterIndex* const glyphsToCharactersBuffer = parameters.visualModel->mGlyphsToCharacters.Begin();
+    const Vector2* const glyphPositionsBuffer = parameters.visualModel->mGlyphPositions.Begin();
+    const GlyphInfo* const glyphInfoBuffer = parameters.visualModel->mGlyphs.Begin();
+
+    // Convert the cursor position into the glyph position.
+    const GlyphIndex primaryGlyphIndex = *( charactersToGlyphBuffer + index );
+    const Length primaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
+    const Length primaryNumberOfCharacters = *( charactersPerGlyphBuffer + primaryGlyphIndex );
+
+    // Get the metrics for the group of glyphs.
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( primaryGlyphIndex,
+                      primaryNumberOfGlyphs,
+                      glyphMetrics,
+                      glyphInfoBuffer,
+                      parameters.metrics );
+
+    // Whether to add the glyph's advance to the cursor position.
+    // i.e if the paragraph is left to right and the logical cursor is zero, the position is the position of the first glyph and the advance is not added,
+    //     if the logical cursor is one, the position is the position of the first glyph and the advance is added.
+    // A 'truth table' was build and an online Karnaugh map tool was used to simplify the logic.
+    //
+    // FLCP A
+    // ------
+    // 0000 1
+    // 0001 1
+    // 0010 0
+    // 0011 0
+    // 0100 1
+    // 0101 0
+    // 0110 1
+    // 0111 0
+    // 1000 0
+    // 1001 1
+    // 1010 0
+    // 1011 1
+    // 1100 x
+    // 1101 x
+    // 1110 x
+    // 1111 x
+    //
+    // Where F -> isFirstPosition
+    //       L -> isLastPosition
+    //       C -> isCurrentRightToLeft
+    //       P -> isRightToLeftParagraph
+    //       A -> Whether to add the glyph's advance.
+
+    const bool addGlyphAdvance = ( ( isLastPositionOfLine && !isRightToLeftParagraph ) ||
+                                   ( isFirstPositionOfLine && isRightToLeftParagraph ) ||
+                                   ( !isFirstPositionOfLine && !isLastPosition && !isCurrentRightToLeft ) );
+
+    float glyphAdvance = addGlyphAdvance ? glyphMetrics.advance : 0.f;
+
+    if( !isLastPositionOfLine &&
+        ( primaryNumberOfCharacters > 1u ) )
+    {
+      const CharacterIndex firstIndex = *( glyphsToCharactersBuffer + primaryGlyphIndex );
+
+      bool isCurrentRightToLeft = false;
+      if( bidiLineFetched ) // If bidiLineFetched is false, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( directionsBuffer + index );
+      }
+
+      Length numberOfGlyphAdvance = ( isFirstPositionOfLine ? 0 : 1u ) + characterIndex - firstIndex;
+      if( isCurrentRightToLeft )
+      {
+        numberOfGlyphAdvance = primaryNumberOfCharacters - numberOfGlyphAdvance;
+      }
+
+      glyphAdvance = static_cast<float>( numberOfGlyphAdvance ) * glyphMetrics.advance / static_cast<float>( primaryNumberOfCharacters );
+    }
+
+    // Get the glyph position and x bearing (in the line's coords).
+    const Vector2& primaryPosition = *( glyphPositionsBuffer + primaryGlyphIndex );
+
+    // Set the primary cursor's height.
+    cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
+
+    cursorInfo.glyphOffset = line.ascender - glyphMetrics.ascender;
+    // Set the primary cursor's position.
+    cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + glyphAdvance;
+    cursorInfo.primaryPosition.y = cursorInfo.lineOffset + cursorInfo.glyphOffset;
+
+    // Transform the cursor info from line's coords to text's coords.
+    cursorInfo.primaryPosition.x += line.alignmentOffset;
+
+    // Calculate the secondary cursor.
+    if( cursorInfo.isSecondaryCursor )
+    {
+      // Set the secondary cursor's height.
+      cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
+
+      CharacterIndex index = characterIndex;
+      if( !isLastPositionOfLine )
+      {
+        index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? nextCharacterIndex : characterIndex;
+      }
+
+      const GlyphIndex secondaryGlyphIndex = *( charactersToGlyphBuffer + index );
+      const Length secondaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
+
+      const Vector2& secondaryPosition = *( glyphPositionsBuffer + secondaryGlyphIndex );
+
+      GetGlyphsMetrics( secondaryGlyphIndex,
+                        secondaryNumberOfGlyphs,
+                        glyphMetrics,
+                        glyphInfoBuffer,
+                        parameters.metrics );
+
+      // Set the secondary cursor's position.
+
+      // FCP A
+      // ------
+      // 000 1
+      // 001 x
+      // 010 0
+      // 011 0
+      // 100 x
+      // 101 0
+      // 110 1
+      // 111 x
+      //
+      // Where F -> isFirstPosition
+      //       C -> isCurrentRightToLeft
+      //       P -> isRightToLeftParagraph
+      //       A -> Whether to add the glyph's advance.
+
+      const bool addGlyphAdvance = ( ( !isFirstPositionOfLine && !isCurrentRightToLeft ) ||
+                                     ( isFirstPositionOfLine && !isRightToLeftParagraph ) );
+
+      cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + ( addGlyphAdvance ? glyphMetrics.advance : 0.f );
+      cursorInfo.secondaryPosition.y = cursorInfo.lineOffset + cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight;
+
+      // Transform the cursor info from line's coords to text's coords.
+      cursorInfo.secondaryPosition.x += line.alignmentOffset;
+    }
+  }
+}
+
+bool FindSelectionIndices( VisualModelPtr visualModel,
+                           LogicalModelPtr logicalModel,
+                           MetricsPtr metrics,
+                           float visualX,
+                           float visualY,
+                           CharacterIndex& startIndex,
+                           CharacterIndex& endIndex,
+                           CharacterIndex& noTextHitIndex )
+{
+/*
+  Hit character                                           Select
+|-------------------------------------------------------|------------------------------------------|
+| On a word                                             | The word                                 |
+| On a single white space between words                 | The word before or after the white space |
+| On one of the multiple contiguous white spaces        | The white spaces                         |
+| On a single white space which is in the position zero | The white space and the next word        |
+| On a new paragraph character                          | The word or group of white spaces before |
+|-------------------------------------------------------|------------------------------------------|
+*/
+  const Length totalNumberOfCharacters = logicalModel->mText.Count();
+  startIndex = 0;
+  endIndex = 0;
+  noTextHitIndex = 0;
+
+  if( 0 == totalNumberOfCharacters )
+  {
+    // Nothing to do if the model is empty.
+    return false;
+  }
+
+  bool matchedCharacter = false;
+  CharacterIndex hitCharacter = Text::GetClosestCursorIndex( visualModel,
+                                                             logicalModel,
+                                                             metrics,
+                                                             visualX,
+                                                             visualY,
+                                                             CharacterHitTest::TAP,
+                                                             matchedCharacter );
+
+  if( !matchedCharacter )
+  {
+    noTextHitIndex = hitCharacter;
+  }
+
+  DALI_ASSERT_DEBUG( ( hitCharacter <= totalNumberOfCharacters ) && "GetClosestCursorIndex returned out of bounds index" );
+
+  if( hitCharacter >= totalNumberOfCharacters )
+  {
+    // Closest hit character is the last character.
+    if( hitCharacter == totalNumberOfCharacters )
+    {
+      hitCharacter--; //Hit character index set to last character in logical model
+    }
+    else
+    {
+      // hitCharacter is out of bounds
+      return false;
+    }
+  }
+
+  const Character* const textBuffer = logicalModel->mText.Begin();
+
+  startIndex = hitCharacter;
+  endIndex = hitCharacter;
+
+  // Whether the hit character is a new paragraph character.
+  const bool isHitCharacterNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + hitCharacter ) );
+
+  // Whether the hit character is a white space. Note a new paragraph character is a white space as well but here is not wanted.
+  const bool isHitCharacterWhiteSpace = TextAbstraction::IsWhiteSpace( *( textBuffer + hitCharacter ) ) && !isHitCharacterNewParagraph;
+
+  FindWordData data( textBuffer,
+                     totalNumberOfCharacters,
+                     hitCharacter,
+                     isHitCharacterWhiteSpace,
+                     isHitCharacterNewParagraph );
+
+  if( isHitCharacterNewParagraph )
+  {
+    // Find the first character before the hit one which is not a new paragraph character.
+
+    if( hitCharacter > 0 )
+    {
+      endIndex = hitCharacter - 1u;
+      for( ; endIndex > 0; --endIndex )
+      {
+        const Dali::Toolkit::Text::Character character = *( data.textBuffer + endIndex );
+
+        if( !Dali::TextAbstraction::IsNewParagraph( character ) )
+        {
+          break;
+        }
+      }
+    }
+
+    data.hitCharacter = endIndex;
+    data.isNewParagraph = false;
+    data.isWhiteSpace = TextAbstraction::IsWhiteSpace( *( textBuffer + data.hitCharacter ) );
+  }
+
+  // Find the start of the word.
+  FindStartOfWord( data );
+  startIndex = data.foundIndex;
+
+  // Find the end of the word.
+  FindEndOfWord( data );
+  endIndex = data.foundIndex;
+
+  if( 1u == ( endIndex - startIndex ) )
+  {
+    if( isHitCharacterWhiteSpace )
+    {
+      // Select the word before or after the white space
+
+      if( 0 == hitCharacter )
+      {
+        data.isWhiteSpace = false;
+        FindEndOfWord( data );
+        endIndex = data.foundIndex;
+      }
+      else if( hitCharacter > 0 )
+      {
+        // Find the start of the word.
+        data.hitCharacter = hitCharacter - 1u;
+        data.isWhiteSpace = false;
+        FindStartOfWord( data );
+        startIndex = data.foundIndex;
+
+        --endIndex;
+      }
+    }
+  }
+
+  return matchedCharacter;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/cursor-helper-functions.h b/dali-toolkit/internal/text/cursor-helper-functions.h
new file mode 100644 (file)
index 0000000..ad17b31
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef DALI_TOOLKIT_TEXT_CURSOR_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_CURSOR_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/metrics.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct CharacterHitTest
+{
+  /**
+   * @brief Enumeration of the types of hit test.
+   */
+  enum Mode
+  {
+    TAP,   ///< Retrieves the first or last character of the line if the touch point is outside of the boundaries of the text.
+    SCROLL ///< Retrieves the character above or below to the touch point if it's outside of the boundaries of the text.
+  };
+};
+
+struct CursorInfo
+{
+  CursorInfo()
+  : primaryPosition(),
+    secondaryPosition(),
+    lineOffset( 0.f ),
+    glyphOffset( 0.f ),
+    lineHeight( 0.f ),
+    primaryCursorHeight( 0.f ),
+    secondaryCursorHeight( 0.f ),
+    isSecondaryCursor( false )
+  {}
+
+  ~CursorInfo()
+  {}
+
+  Vector2 primaryPosition;       ///< The primary cursor's position (in text's coords).
+  Vector2 secondaryPosition;     ///< The secondary cursor's position (in text's coords).
+  float   lineOffset;            ///< The vertical offset where the line containing the cursor starts.
+  float   glyphOffset;           ///< The difference of line ascender and glyph ascender.
+  float   lineHeight;            ///< The height of the line where the cursor is placed.
+  float   primaryCursorHeight;   ///< The primary cursor's height.
+  float   secondaryCursorHeight; ///< The secondary cursor's height.
+  bool    isSecondaryCursor;     ///< Whether the secondary cursor is valid.
+};
+
+/**
+ * @brief Parameters passed to the GetCursorPosition() function.
+ */
+struct GetCursorPositionParameters
+{
+  VisualModelPtr visualModel;    ///< The visual model.
+  LogicalModelPtr logicalModel;  ///< The logical model.
+  MetricsPtr metrics;            ///< A wrapper around FontClient used to get metrics.
+  CharacterIndex logical;        ///< The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+  bool isMultiline;              ///< Whether the text control is multi-line.
+};
+
+/**
+ * @brief Retrieves the closest line for a given touch point.
+ *
+ * It returns the first line if the touch point is above the text and the last line if the touch point is below.
+ *
+ * @param[in] visualModel The visual model.
+ * @param[in] visualY The touch point 'y' in text's coords.
+ * @param[out] matchedLine Whether the touch point actually hits a line.
+ *
+ * @return A line index.
+ */
+LineIndex GetClosestLine( VisualModelPtr visualModel,
+                          float visualY,
+                          bool& matchedLine );
+
+/**
+ * @brief Calculates the vertical line's offset for a given line.
+ *
+ * @pre @p lineIndex must be between 0 and the number of lines (both inclusive).
+ *
+ * @param[in] lines The laid-out lines.
+ * @param[in] lineIndex Index to the line.
+ *
+ * @return The vertical offset of the given line.
+ */
+float CalculateLineOffset( const Vector<LineRun>& lines,
+                           LineIndex lineIndex );
+
+/**
+ * @brief Retrieves the cursor's logical position for a given touch point x,y
+ *
+ * There are two types of hit test: CharacterHitTest::TAP retrieves the first or
+ * last character of a line if the touch point is outside the boundaries of the
+ * text, CharacterHitTest::SCROLL retrieves the character above or below to the
+ * touch point if it's outside the boundaries of the text.
+ *
+ * @param[in] visualModel The visual model.
+ * @param[in] logicalModel The logical model.
+ * @param[in] metrics A wrapper around FontClient used to get metrics.
+ * @param[in] visualX The touch point 'x' in text's coords.
+ * @param[in] visualY The touch point 'y' in text's coords.
+ * @param[in] mode The type of hit test.
+ * @param[out] matchedCharacter Whether the touch point actually hits a character.
+ *
+ * @return The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+ */
+CharacterIndex GetClosestCursorIndex( VisualModelPtr visualModel,
+                                      LogicalModelPtr logicalModel,
+                                      MetricsPtr metrics,
+                                      float visualX,
+                                      float visualY,
+                                      CharacterHitTest::Mode mode,
+                                      bool& matchedCharacter );
+
+/**
+ * @brief Calculates the cursor's position for a given character index in the logical order.
+ *
+ * It retrieves as well the line's height and the cursor's height and
+ * if there is a valid alternative cursor, its position and height.
+ *
+ * @param[in] parameters Parameters used to calculate the cursor's position.
+ * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
+ */
+void GetCursorPosition( GetCursorPositionParameters& parameters,
+                        CursorInfo& cursorInfo );
+
+/**
+ * @brief Find the indices to the first and last characters of a word for the given touch point.
+ *
+ * @param[in] visualModel The visual model.
+ * @param[in] logicalModel The logical model.
+ * @param[in] metrics A wrapper around FontClient used to get metrics.
+ * @param[in] visualX The touch point 'x' in text's coords.
+ * @param[in] visualY The touch point 'y' in text's coords.
+ * @param[out] startIndex Index to the first character of the selected word.
+ * @param[out] endIndex Index to the last character of the selected word.
+ * @param[out] noTextHitIndex Index to the nearest character when there is no hit.
+ *
+ * @return @e true if the touch point hits a character.
+ */
+bool FindSelectionIndices( VisualModelPtr visualModel,
+                           LogicalModelPtr logicalModel,
+                           MetricsPtr metrics,
+                           float visualX,
+                           float visualY,
+                           CharacterIndex& startIndex,
+                           CharacterIndex& endIndex,
+                           CharacterIndex& noTextHitIndex );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CURSOR_HELPER_FUNCTIONS_H
diff --git a/dali-toolkit/internal/text/decorator/text-decorator.cpp b/dali-toolkit/internal/text/decorator/text-decorator.cpp
new file mode 100644 (file)
index 0000000..0cb8b4c
--- /dev/null
@@ -0,0 +1,2358 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/events/touch-data.h>
+#include <dali/public-api/events/pan-gesture.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
+
+#ifdef DEBUG_ENABLED
+#define DECORATOR_DEBUG
+
+#endif
+
+#define MAKE_SHADER(A)#A
+
+namespace
+{
+const char* VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec2    aPosition;
+uniform   highp mat4      uMvpMatrix;
+
+void main()
+{
+  mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+  gl_Position = uMvpMatrix * position;
+}
+);
+
+const char* FRAGMENT_SHADER = MAKE_SHADER(
+uniform      lowp vec4 uColor;
+
+void main()
+{
+  gl_FragColor = uColor;
+}
+);
+}
+
+namespace Dali
+{
+namespace Internal
+{
+namespace
+{
+#ifdef DECORATOR_DEBUG
+Integration::Log::Filter* gLogFilter( Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_TEXT_DECORATOR") );
+#endif
+}
+}
+}
+
+
+// Local Data
+namespace
+{
+const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.25f, 1.5f, 1.0f );
+const Dali::Vector3 ACTIVE_LAYER_ANCHOR_POINT( 0.5f, 0.5f, 0.5f );
+
+const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight color. TODO: due some problems, maybe with the blending function in the text clipping, the color is fully opaque.
+
+const Dali::Vector4 HANDLE_COLOR( 0.0f, (183.0f / 255.0f), (229.0f / 255.0f), 1.0f  );
+
+const unsigned int CURSOR_BLINK_INTERVAL = 500u; ///< Cursor blink interval in milliseconds.
+const float TO_MILLISECONDS = 1000.f;            ///< Converts from seconds to milliseconds.
+const float TO_SECONDS = 1.f / TO_MILLISECONDS;  ///< Converts from milliseconds to seconds.
+
+const unsigned int SCROLL_TICK_INTERVAL = 50u; ///< Scroll interval in milliseconds.
+const float SCROLL_THRESHOLD = 10.f;           ///< Threshold in pixels close to the edges of the decorator boundaries from where the scroll timer starts to emit signals.
+const float SCROLL_SPEED = 300.f;              ///< The scroll speed in pixels/second.
+
+const float SCROLL_DISTANCE = SCROLL_SPEED * SCROLL_TICK_INTERVAL * TO_SECONDS; ///< Distance in pixels scrolled in one second.
+
+const float CURSOR_WIDTH = 1.f; ///< The cursor's width in pixels.
+
+const float POPUP_PADDING = 2.f; ///< Padding space between the highlight box and the text's popup.
+
+typedef Dali::Vector<Dali::Vector4> QuadContainer;
+
+/**
+ * @brief Takes a bounding rectangle in the local coordinates of an actor and returns the world coordinates Bounding Box.
+ * @param[in] boundingRectangle local bounding
+ * @param[out] Vector4 World coordinate bounding Box.
+ */
+void LocalToWorldCoordinatesBoundingBox( const Dali::Rect<int>& boundingRectangle, Dali::Vector4& boundingBox )
+{
+  // Convert to world coordinates and store as a Vector4 to be compatible with Property Notifications.
+  Dali::Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
+
+  const float originX = boundingRectangle.x - 0.5f * stageSize.width;
+  const float originY = boundingRectangle.y - 0.5f * stageSize.height;
+
+  boundingBox = Dali::Vector4( originX,
+                               originY,
+                               originX + boundingRectangle.width,
+                               originY + boundingRectangle.height );
+}
+
+void WorldToLocalCoordinatesBoundingBox( const Dali::Vector4& boundingBox, Dali::Rect<int>& boundingRectangle )
+{
+  // Convert to local coordinates and store as a Dali::Rect.
+  Dali::Vector2 stageSize = Dali::Stage::GetCurrent().GetSize();
+
+  boundingRectangle.x = boundingBox.x + 0.5f * stageSize.width;
+  boundingRectangle.y = boundingBox.y + 0.5f * stageSize.height;
+  boundingRectangle.width = boundingBox.z - boundingBox.x;
+  boundingRectangle.height = boundingBox.w - boundingBox.y;
+}
+
+} // end of namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct Decorator::Impl : public ConnectionTracker
+{
+  enum ScrollDirection
+  {
+    SCROLL_NONE,
+    SCROLL_RIGHT,
+    SCROLL_LEFT,
+    SCROLL_TOP,
+    SCROLL_BOTTOM
+  };
+
+  struct CursorImpl
+  {
+    CursorImpl()
+    : color( Dali::Color::BLACK ),
+      position(),
+      cursorHeight( 0.0f ),
+      lineHeight( 0.0f ),
+      glyphOffset( 0.0f )
+    {
+    }
+
+    Vector4 color;
+    Vector2 position;
+    float cursorHeight;
+    float lineHeight;
+    float glyphOffset;
+  };
+
+  struct HandleImpl
+  {
+    HandleImpl()
+    : position(),
+      globalPosition(),
+      size(),
+      lineHeight( 0.0f ),
+      grabDisplacementX( 0.f ),
+      grabDisplacementY( 0.f ),
+      active( false ),
+      horizontallyVisible( false ),
+      verticallyVisible( false ),
+      pressed( false ),
+      verticallyFlippedPreferred( false ),
+      horizontallyFlipped( false ),
+      verticallyFlipped( false ),
+      verticallyFlippedOnTouch( false )
+    {
+    }
+
+    ImageView actor;
+    Actor grabArea;
+    ImageView markerActor;
+
+    Vector2 position;
+    Vector2 globalPosition;
+    Size    size;
+    float   lineHeight;              ///< Not the handle height
+    float   grabDisplacementX;
+    float   grabDisplacementY;
+    bool    active                     : 1;
+    bool    horizontallyVisible        : 1;
+    bool    verticallyVisible          : 1;
+    bool    pressed                    : 1;
+    bool    verticallyFlippedPreferred : 1; ///< Whether the handle is preferred to be vertically flipped.
+    bool    horizontallyFlipped        : 1; ///< Whether the handle has been horizontally flipped.
+    bool    verticallyFlipped          : 1; ///< Whether the handle has been vertically flipped.
+    bool    verticallyFlippedOnTouch   : 1; ///< Whether the handle is vertically flipped on touch.
+  };
+
+  struct PopupImpl
+  {
+    PopupImpl()
+    : position()
+    {
+    }
+
+    TextSelectionPopup actor;
+    Vector3 position;
+  };
+
+  Impl( ControllerInterface& controller,
+        TextSelectionPopupCallbackInterface& callbackInterface )
+  : mController( controller ),
+    mEnabledPopupButtons( TextSelectionPopup::NONE ),
+    mTextSelectionPopupCallbackInterface( callbackInterface ),
+    mHandleColor( HANDLE_COLOR ),
+    mBoundingBox(),
+    mHighlightColor( LIGHT_BLUE ),
+    mHighlightPosition( Vector2::ZERO ),
+    mHighlightSize( Vector2::ZERO ),
+    mControlSize( Vector2::ZERO ),
+    mHighlightOutlineOffset( 0.f ),
+    mActiveCursor( ACTIVE_CURSOR_NONE ),
+    mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
+    mCursorBlinkDuration( 0.0f ),
+    mCursorWidth( CURSOR_WIDTH ),
+    mHandleScrolling( HANDLE_TYPE_COUNT ),
+    mHandleReleased( HANDLE_TYPE_COUNT ),
+    mScrollDirection( SCROLL_NONE ),
+    mScrollThreshold( SCROLL_THRESHOLD ),
+    mScrollSpeed( SCROLL_SPEED ),
+    mScrollDistance( SCROLL_DISTANCE ),
+    mTextDepth( 0u ),
+    mActiveCopyPastePopup( false ),
+    mPopupSetNewPosition( true ),
+    mCursorBlinkStatus( true ),
+    mDelayCursorBlink( false ),
+    mPrimaryCursorVisible( false ),
+    mSecondaryCursorVisible( false ),
+    mFlipSelectionHandlesOnCross( false ),
+    mFlipLeftSelectionHandleDirection( false ),
+    mFlipRightSelectionHandleDirection( false ),
+    mIsHandlePanning( false ),
+    mIsHandleCurrentlyCrossed( false ),
+    mIsHandlePreviouslyCrossed( false ),
+    mNotifyEndOfScroll( false ),
+    mHorizontalScrollingEnabled( false ),
+    mVerticalScrollingEnabled( false ),
+    mSmoothHandlePanEnabled( false ),
+    mIsHighlightBoxActive( false )
+  {
+    mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+    mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    SetupGestures();
+  }
+
+  /**
+   * Relayout of the decorations owned by the decorator.
+   * @param[in] size The Size of the UI control the decorator is adding it's decorations to.
+   */
+  void Relayout( const Vector2& size )
+  {
+    mControlSize = size;
+
+    // TODO - Remove this if nothing is active
+    CreateActiveLayer();
+
+    // Show or hide the cursors
+    CreateCursors();
+
+    if( mPrimaryCursor )
+    {
+      const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
+      mPrimaryCursorVisible = ( ( mControlSize.width - ( cursor.position.x + mCursorWidth ) > -Math::MACHINE_EPSILON_1000 ) &&
+                                ( cursor.position.x > -Math::MACHINE_EPSILON_1000 ) &&
+                                ( mControlSize.height - ( cursor.position.y + cursor.cursorHeight ) > -Math::MACHINE_EPSILON_1000 ) &&
+                                ( cursor.position.y > -Math::MACHINE_EPSILON_1000 ) );
+      if( mPrimaryCursorVisible )
+      {
+        mPrimaryCursor.SetPosition( cursor.position.x,
+                                    cursor.position.y );
+        mPrimaryCursor.SetSize( Size( mCursorWidth, cursor.cursorHeight ) );
+      }
+      mPrimaryCursor.SetVisible( mPrimaryCursorVisible && mCursorBlinkStatus );
+    }
+    if( mSecondaryCursor )
+    {
+      const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
+      mSecondaryCursorVisible = ( ( mControlSize.width - ( cursor.position.x + mCursorWidth ) > -Math::MACHINE_EPSILON_1000 ) &&
+                                  ( cursor.position.x > -Math::MACHINE_EPSILON_1000 ) &&
+                                  ( mControlSize.height - ( cursor.position.y + cursor.cursorHeight ) > -Math::MACHINE_EPSILON_1000 ) &&
+                                  ( cursor.position.y > -Math::MACHINE_EPSILON_1000 ) );
+      if( mSecondaryCursorVisible )
+      {
+        mSecondaryCursor.SetPosition( cursor.position.x,
+                                      cursor.position.y );
+        mSecondaryCursor.SetSize( Size( mCursorWidth, cursor.cursorHeight ) );
+      }
+      mSecondaryCursor.SetVisible( mSecondaryCursorVisible && mCursorBlinkStatus );
+    }
+
+    // Show or hide the grab handle
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    bool newGrabHandlePosition = false;
+    grabHandle.horizontallyVisible = false;
+    grabHandle.verticallyVisible = false;
+    if( grabHandle.active )
+    {
+      grabHandle.horizontallyVisible = ( ( mControlSize.width - ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) ) > -Math::MACHINE_EPSILON_1000 ) &&
+                                         ( grabHandle.position.x > -Math::MACHINE_EPSILON_1000 ) );
+      grabHandle.verticallyVisible = ( ( ( mControlSize.height - grabHandle.lineHeight ) - grabHandle.position.y > -Math::MACHINE_EPSILON_1000 ) &&
+                                       ( grabHandle.position.y > -Math::MACHINE_EPSILON_1000 ) );
+
+      const bool isVisible = grabHandle.horizontallyVisible && grabHandle.verticallyVisible;
+      if( isVisible )
+      {
+        CreateGrabHandle();
+
+        // Sets the grab handle position and calculate if it needs to be vertically flipped if it exceeds the boundary box.
+        SetGrabHandlePosition();
+
+        // Sets the grab handle image according if it's pressed, flipped, etc.
+        SetHandleImage( GRAB_HANDLE );
+
+        newGrabHandlePosition = true;
+      }
+
+      if( grabHandle.actor )
+      {
+        grabHandle.actor.SetVisible( isVisible );
+      }
+    }
+    else if( grabHandle.actor )
+    {
+      grabHandle.actor.Unparent();
+    }
+
+    // Show or hide the selection handles/highlight
+    HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
+    HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    bool newPrimaryHandlePosition = false;
+    bool newSecondaryHandlePosition = false;
+
+    primary.horizontallyVisible = ( ( mControlSize.width - primary.position.x > -Math::MACHINE_EPSILON_1000 ) &&
+                                    ( primary.position.x > -Math::MACHINE_EPSILON_1000 ) );
+    primary.verticallyVisible = ( ( ( mControlSize.height - primary.lineHeight ) - primary.position.y > -Math::MACHINE_EPSILON_1000 ) &&
+                                  ( primary.position.y + ( primary.verticallyFlipped ? 0.f : primary.lineHeight ) > -Math::MACHINE_EPSILON_1000 ) );
+    secondary.horizontallyVisible = ( ( mControlSize.width - secondary.position.x > -Math::MACHINE_EPSILON_1000 ) &&
+                                      ( secondary.position.x > -Math::MACHINE_EPSILON_1000 ) );
+    secondary.verticallyVisible = ( ( ( mControlSize.height - secondary.lineHeight ) - secondary.position.y > -Math::MACHINE_EPSILON_1000 ) &&
+                                    ( secondary.position.y + ( secondary.verticallyFlipped ? 0.f : secondary.lineHeight ) > -Math::MACHINE_EPSILON_1000 ) );
+
+    const bool primaryVisible = primary.horizontallyVisible && primary.verticallyVisible;
+    const bool secondaryVisible = secondary.horizontallyVisible && secondary.verticallyVisible;
+
+    if( primary.active || secondary.active )
+    {
+      if( primaryVisible || secondaryVisible )
+      {
+        CreateSelectionHandles();
+
+        if( primaryVisible )
+        {
+          SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
+
+          // Sets the primary handle image according if it's pressed, flipped, etc.
+          SetHandleImage( LEFT_SELECTION_HANDLE );
+
+          SetSelectionHandleMarkerSize( primary );
+
+          newPrimaryHandlePosition = true;
+        }
+
+        if( secondaryVisible )
+        {
+          SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
+
+          // Sets the secondary handle image according if it's pressed, flipped, etc.
+          SetHandleImage( RIGHT_SELECTION_HANDLE );
+
+          SetSelectionHandleMarkerSize( secondary );
+
+          newSecondaryHandlePosition = true;
+        }
+      }
+
+      if( primary.actor )
+      {
+        primary.actor.SetVisible( primaryVisible );
+      }
+      if( secondary.actor )
+      {
+        secondary.actor.SetVisible( secondaryVisible );
+      }
+
+    }
+    else
+    {
+      if( primary.actor )
+      {
+        primary.actor.Unparent();
+      }
+      if( secondary.actor )
+      {
+        secondary.actor.Unparent();
+      }
+    }
+
+    if( mIsHighlightBoxActive )
+    {
+      CreateHighlight();
+      UpdateHighlight();
+    }
+    else
+    {
+      if( mHighlightActor )
+      {
+        mHighlightActor.Unparent();
+      }
+    }
+
+    if( newGrabHandlePosition    ||
+        newPrimaryHandlePosition ||
+        newSecondaryHandlePosition )
+    {
+      // Setup property notifications to find whether the handles leave the boundaries of the current display.
+      SetupActiveLayerPropertyNotifications();
+    }
+
+    if( mActiveCopyPastePopup &&
+        ( primaryVisible || secondaryVisible ) )
+    {
+      ShowPopup();
+      mPopupSetNewPosition = true;
+    }
+    else
+    {
+      if( mCopyPastePopup.actor )
+      {
+        mCopyPastePopup.actor.HidePopup();
+        mPopupSetNewPosition = true;
+      }
+    }
+  }
+
+  void UpdatePositions( const Vector2& scrollOffset )
+  {
+    mCursor[PRIMARY_CURSOR].position += scrollOffset;
+    mCursor[SECONDARY_CURSOR].position += scrollOffset;
+    mHandle[ GRAB_HANDLE ].position += scrollOffset;
+    mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset;
+    mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset;
+    mHighlightPosition += scrollOffset;
+  }
+
+  void ShowPopup()
+  {
+    if( !mCopyPastePopup.actor )
+    {
+      return;
+    }
+
+    if( !mCopyPastePopup.actor.GetParent() )
+    {
+      mActiveLayer.Add( mCopyPastePopup.actor );
+    }
+
+    mCopyPastePopup.actor.RaiseAbove( mActiveLayer );
+    mCopyPastePopup.actor.ShowPopup();
+  }
+
+  float CalculateVerticalPopUpPosition( float halfHeight, bool preferBelow )
+  {
+    float yPosition = 0.f;
+
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      // The origin of the decorator's coordinate system in world coords.
+      const Vector3 originWorldCoords = mActiveLayer.GetCurrentWorldPosition() - mActiveLayer.GetCurrentSize() * ACTIVE_LAYER_ANCHOR_POINT;
+
+      if( preferBelow )
+      {
+        // Find out if there is enough space for the popup at the bottom.
+        const float primaryBelowY = primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height;
+        const float secondaryBelowY = secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height;
+
+        float maxY = std::max( primaryBelowY, secondaryBelowY );
+
+        yPosition = halfHeight + maxY;
+
+        if( originWorldCoords.y + yPosition + halfHeight > mBoundingBox.w )
+        {
+          // Does not fit below.
+
+          // Try to fit first below the non active handle. Otherwise above the active handle.
+          if( RIGHT_SELECTION_HANDLE == mHandleReleased )
+          {
+            if( primaryBelowY < secondaryBelowY )
+            {
+              yPosition = halfHeight + primaryBelowY;
+            }
+            else
+            {
+              yPosition = primaryHandle.position.y - primaryHandle.size.height - halfHeight;
+            }
+          }
+          else if( LEFT_SELECTION_HANDLE == mHandleReleased )
+          {
+            if( secondaryBelowY < primaryBelowY )
+            {
+              yPosition = halfHeight + secondaryBelowY;
+            }
+            else
+            {
+              yPosition = secondaryHandle.position.y - secondaryHandle.size.height - halfHeight;
+            }
+          }
+
+          // Check the handle is whithin the decoration box.
+          if( originWorldCoords.y + yPosition < mBoundingBox.y )
+          {
+            yPosition = mBoundingBox.y - originWorldCoords.y + halfHeight;
+          }
+
+          if( originWorldCoords.y + yPosition > mBoundingBox.w )
+          {
+            yPosition = mBoundingBox.w - originWorldCoords.y - halfHeight;
+          }
+        }
+      } // preferBelow
+      else
+      {
+        // Find out if there is enough space for the popup at the top.
+        const float primaryTopY = primaryHandle.position.y - primaryHandle.size.height;
+        const float secondaryTopY = secondaryHandle.position.y - secondaryHandle.size.height;
+
+        float minY = std::min( primaryTopY, secondaryTopY );
+
+        yPosition = -halfHeight + minY;
+      } // !preferBelow
+    } // ( primaryHandle.active || secondaryHandle.active )
+    else if( grabHandle.active )
+    {
+      if( preferBelow )
+      {
+        yPosition = halfHeight + grabHandle.lineHeight + grabHandle.size.height + grabHandle.position.y;
+      }
+      else
+      {
+        yPosition = -halfHeight + grabHandle.position.y - POPUP_PADDING;
+      }
+    }
+
+    return yPosition;
+  }
+
+  void ConstrainPopupPosition( const Vector3& popupHalfSize )
+  {
+    // Check if the popup is within the boundaries of the decoration box.
+
+    // Check first the horizontal dimension. If is not within the boundaries, it calculates the offset.
+
+    // The origin of the decorator's coordinate system in world coords.
+    const Vector3 originWorldCoords = mActiveLayer.GetCurrentWorldPosition() - mActiveLayer.GetCurrentSize() * ACTIVE_LAYER_ANCHOR_POINT;
+
+    // The popup's position in world coords.
+    Vector3 popupPositionWorldCoords = originWorldCoords + mCopyPastePopup.position;
+
+    if( popupPositionWorldCoords.x - popupHalfSize.width < mBoundingBox.x )
+    {
+       mCopyPastePopup.position.x += mBoundingBox.x - ( popupPositionWorldCoords.x - popupHalfSize.width );
+    }
+    else if( popupPositionWorldCoords.x + popupHalfSize.width > mBoundingBox.z )
+    {
+       mCopyPastePopup.position.x += mBoundingBox.z - ( popupPositionWorldCoords.x + popupHalfSize.width );
+    }
+
+    // Check the vertical dimension. If the popup doesn't fit above the handles, it looks for a valid position below.
+    if( popupPositionWorldCoords.y - popupHalfSize.height < mBoundingBox.y )
+    {
+      mCopyPastePopup.position.y = CalculateVerticalPopUpPosition( popupHalfSize.height, true ); // true -> prefer to set the popup's position below.
+    }
+  }
+
+  void SetPopupPosition( Actor actor )
+  {
+    if( !mActiveCopyPastePopup )
+    {
+      return;
+    }
+
+    // Retrieves the popup's size after relayout.
+    const Vector3 popupSize( mCopyPastePopup.actor.GetRelayoutSize( Dimension::WIDTH ), mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT ), 0.0f );
+    const Vector3 popupHalfSize = popupSize * 0.5f;
+
+    if( mPopupSetNewPosition )
+    {
+      const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+      const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+      const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+      if( primaryHandle.active || secondaryHandle.active )
+      {
+        const float minHandleXPosition = std::min( primaryHandle.position.x, secondaryHandle.position.x );
+        const float maxHandleXPosition = std::max( primaryHandle.position.x, secondaryHandle.position.x );
+
+        mCopyPastePopup.position.x = minHandleXPosition + ( ( maxHandleXPosition - minHandleXPosition ) * 0.5f );
+
+        const float primaryY = -popupHalfSize.height + primaryHandle.position.y - ( primaryHandle.verticallyFlipped ? primaryHandle.size.height : POPUP_PADDING );
+        const float secondaryY = -popupHalfSize.height + secondaryHandle.position.y - ( secondaryHandle.verticallyFlipped ? secondaryHandle.size.height : POPUP_PADDING );
+
+        mCopyPastePopup.position.y = std::min( primaryY, secondaryY );
+      }
+      else if( grabHandle.active )
+      {
+        mCopyPastePopup.position.x = grabHandle.position.x;
+
+        mCopyPastePopup.position.y = -popupHalfSize.height + grabHandle.position.y - ( grabHandle.verticallyFlipped ? grabHandle.size.height : POPUP_PADDING );
+      }
+    } // mPopupSetNewPosition
+
+    // It may change the popup's position to fit within the decoration box.
+    ConstrainPopupPosition( popupHalfSize );
+
+    SetUpPopupPositionNotifications( popupHalfSize );
+
+    // Prevent pixel mis-alignment by rounding down.
+    mCopyPastePopup.position.x = floorf( mCopyPastePopup.position.x );
+    mCopyPastePopup.position.y = floorf( mCopyPastePopup.position.y );
+
+    mCopyPastePopup.actor.SetPosition( mCopyPastePopup.position );
+    mPopupSetNewPosition = false;
+  }
+
+  void CreateCursor( Control& cursor, const Vector4& color )
+  {
+    cursor = Control::New();
+    cursor.SetBackgroundColor( color );
+    cursor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    cursor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+  }
+
+  // Add or Remove cursor(s) from parent
+  void CreateCursors()
+  {
+    if( mActiveCursor == ACTIVE_CURSOR_NONE )
+    {
+      if( mPrimaryCursor )
+      {
+        mPrimaryCursor.Unparent();
+      }
+      if( mSecondaryCursor )
+      {
+        mSecondaryCursor.Unparent();
+      }
+    }
+    else
+    {
+      // Create Primary and or Secondary Cursor(s) if active and add to parent
+      if ( mActiveCursor == ACTIVE_CURSOR_PRIMARY ||
+           mActiveCursor == ACTIVE_CURSOR_BOTH )
+      {
+        if ( !mPrimaryCursor )
+        {
+          CreateCursor( mPrimaryCursor, mCursor[PRIMARY_CURSOR].color );
+#ifdef DECORATOR_DEBUG
+          mPrimaryCursor.SetName( "PrimaryCursorActor" );
+#endif
+        }
+
+        if( !mPrimaryCursor.GetParent() )
+        {
+          mActiveLayer.Add( mPrimaryCursor );
+        }
+      }
+
+      if ( mActiveCursor == ACTIVE_CURSOR_BOTH )
+      {
+        if ( !mSecondaryCursor )
+        {
+          CreateCursor( mSecondaryCursor, mCursor[SECONDARY_CURSOR].color );
+#ifdef DECORATOR_DEBUG
+          mSecondaryCursor.SetName( "SecondaryCursorActor" );
+#endif
+        }
+
+        if( !mSecondaryCursor.GetParent() )
+        {
+          mActiveLayer.Add( mSecondaryCursor );
+        }
+      }
+      else
+      {
+        if( mSecondaryCursor )
+        {
+          mSecondaryCursor.Unparent();
+        }
+      }
+    }
+  }
+
+  bool OnCursorBlinkTimerTick()
+  {
+    if( !mDelayCursorBlink )
+    {
+      // Cursor blinking
+      if ( mPrimaryCursor )
+      {
+        mPrimaryCursor.SetVisible( mPrimaryCursorVisible && mCursorBlinkStatus );
+      }
+      if ( mSecondaryCursor )
+      {
+        mSecondaryCursor.SetVisible( mSecondaryCursorVisible && mCursorBlinkStatus );
+      }
+
+      mCursorBlinkStatus = !mCursorBlinkStatus;
+    }
+    else
+    {
+      // Resume blinking
+      mDelayCursorBlink = false;
+    }
+
+    return true;
+  }
+
+  void SetupGestures()
+  {
+    // Will consume tap gestures on handles.
+    mTapDetector = TapGestureDetector::New();
+
+    // Will consume double tap gestures on handles.
+    mTapDetector.SetMaximumTapsRequired( 2u );
+
+    // Will consume long press gestures on handles.
+    mLongPressDetector = LongPressGestureDetector::New();
+
+    // Detects pan gestures on handles.
+    mPanDetector = PanGestureDetector::New();
+    mPanDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
+  }
+
+  void CreateActiveLayer()
+  {
+    if( !mActiveLayer )
+    {
+      mActiveLayer = Layer::New();
+#ifdef DECORATOR_DEBUG
+      mActiveLayer.SetName ( "ActiveLayerActor" );
+#endif
+
+      mActiveLayer.SetParentOrigin( ParentOrigin::CENTER );
+      mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+
+      // Add the active layer telling the controller it doesn't need clipping.
+      mController.AddDecoration( mActiveLayer, false );
+    }
+
+    mActiveLayer.RaiseToTop();
+  }
+
+  void SetSelectionHandleMarkerSize( HandleImpl& handle )
+  {
+    if( handle.markerActor )
+    {
+      handle.markerActor.SetSize( 0, handle.lineHeight );
+    }
+  }
+
+  void CreateGrabHandle()
+  {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    if( !grabHandle.actor )
+    {
+      if( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
+      {
+        grabHandle.actor = ImageView::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
+        GetImpl( grabHandle.actor).SetDepthIndex( DepthIndex::DECORATION );
+        grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+
+        // Area that Grab handle responds to, larger than actual handle so easier to move
+#ifdef DECORATOR_DEBUG
+        grabHandle.actor.SetName( "GrabHandleActor" );
+        if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) )
+        {
+          grabHandle.grabArea = Control::New();
+          Toolkit::Control control = Toolkit::Control::DownCast( grabHandle.grabArea );
+          control.SetBackgroundColor( Vector4( 1.0f, 1.0f, 1.0f, 0.5f ) );
+          grabHandle.grabArea.SetName( "GrabArea" );
+        }
+        else
+        {
+          grabHandle.grabArea = Actor::New();
+          grabHandle.grabArea.SetName( "GrabArea" );
+        }
+#else
+        grabHandle.grabArea = Actor::New();
+#endif
+
+        grabHandle.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        grabHandle.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        grabHandle.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        grabHandle.grabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
+        grabHandle.actor.Add( grabHandle.grabArea );
+        grabHandle.actor.SetColor( mHandleColor );
+
+        grabHandle.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
+
+        // The grab handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( grabHandle.actor );
+        mLongPressDetector.Attach( grabHandle.actor );
+
+        // The grab handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( grabHandle.grabArea );
+
+        mActiveLayer.Add( grabHandle.actor );
+      }
+    }
+
+    if( grabHandle.actor && !grabHandle.actor.GetParent() )
+    {
+      mActiveLayer.Add( grabHandle.actor );
+    }
+  }
+
+  void CreateHandleMarker( HandleImpl& handle, Image& image, HandleType handleType )
+  {
+    if( image )
+    {
+      handle.markerActor = ImageView::New( image );
+      handle.markerActor.SetColor( mHandleColor );
+      handle.actor.Add( handle.markerActor );
+
+      handle.markerActor.SetResizePolicy ( ResizePolicy::FIXED, Dimension::HEIGHT );
+
+      if( LEFT_SELECTION_HANDLE == handleType )
+      {
+        handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_RIGHT );
+        handle.markerActor.SetParentOrigin( ParentOrigin::TOP_RIGHT );
+      }
+      else if( RIGHT_SELECTION_HANDLE == handleType )
+      {
+        handle.markerActor.SetAnchorPoint( AnchorPoint::BOTTOM_LEFT );
+        handle.markerActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      }
+    }
+  }
+
+  void CreateSelectionHandles()
+  {
+    HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
+    if( !primary.actor )
+    {
+      if( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
+      {
+        primary.actor = ImageView::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
+#ifdef DECORATOR_DEBUG
+        primary.actor.SetName("SelectionHandleOne");
+#endif
+        primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
+        GetImpl( primary.actor ).SetDepthIndex( DepthIndex::DECORATION );
+        primary.actor.SetColor( mHandleColor );
+
+        primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
+#ifdef DECORATOR_DEBUG
+        primary.grabArea.SetName("SelectionHandleOneGrabArea");
+#endif
+        primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        primary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
+
+        primary.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
+
+        // The handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( primary.actor );
+        mLongPressDetector.Attach( primary.actor );
+
+        // The handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( primary.grabArea );
+
+        primary.actor.Add( primary.grabArea );
+
+        CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
+      }
+    }
+
+    if( primary.actor && !primary.actor.GetParent() )
+    {
+      mActiveLayer.Add( primary.actor );
+    }
+
+    HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    if( !secondary.actor )
+    {
+      if( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
+      {
+        secondary.actor = ImageView::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
+#ifdef DECORATOR_DEBUG
+        secondary.actor.SetName("SelectionHandleTwo");
+#endif
+        secondary.actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text.
+        GetImpl( secondary.actor ).SetDepthIndex( DepthIndex::DECORATION );
+        secondary.actor.SetColor( mHandleColor );
+
+        secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
+#ifdef DECORATOR_DEBUG
+        secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
+#endif
+        secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        secondary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
+
+        secondary.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
+
+        // The handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( secondary.actor );
+        mLongPressDetector.Attach( secondary.actor );
+
+        // The handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( secondary.grabArea );
+
+        secondary.actor.Add( secondary.grabArea );
+
+        CreateHandleMarker( secondary, mHandleImages[RIGHT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], RIGHT_SELECTION_HANDLE  );
+      }
+    }
+
+    if( secondary.actor && !secondary.actor.GetParent() )
+    {
+      mActiveLayer.Add( secondary.actor );
+    }
+  }
+
+  void CalculateHandleWorldCoordinates( HandleImpl& handle, Vector2& position )
+  {
+    // Gets the world position of the active layer. The active layer is where the handles are added.
+    const Vector3 parentWorldPosition = mActiveLayer.GetCurrentWorldPosition();
+
+    // The grab handle position in world coords.
+    // The active layer's world position is the center of the active layer. The origin of the
+    // coord system of the handles is the top left of the active layer.
+    position.x = parentWorldPosition.x - 0.5f * mControlSize.width + handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f );
+    position.y = parentWorldPosition.y - 0.5f * mControlSize.height + handle.position.y + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f );
+  }
+
+  void SetGrabHandlePosition()
+  {
+    // Reference to the grab handle.
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as grabHandle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
+    Vector2 grabHandleWorldPosition;
+    CalculateHandleWorldCoordinates( grabHandle, grabHandleWorldPosition );
+
+    // Check if the grab handle exceeds the boundaries of the decoration box.
+    // At the moment only the height is checked for the grab handle.
+
+    grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
+                                     ( ( grabHandleWorldPosition.y - grabHandle.size.height ) > mBoundingBox.y ) ) ||
+                                   ( grabHandleWorldPosition.y + grabHandle.lineHeight + grabHandle.size.height > mBoundingBox.w );
+
+    // The grab handle 'y' position in local coords.
+    // If the grab handle exceeds the bottom of the decoration box,
+    // set the 'y' position to the top of the line.
+    // The SetGrabHandleImage() method will change the orientation.
+    const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
+
+    if( grabHandle.actor )
+    {
+      grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ) + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementX : 0.f ),
+                                    yLocalPosition + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementY : 0.f ) );
+    }
+  }
+
+  void SetSelectionHandlePosition( HandleType type )
+  {
+    const bool isPrimaryHandle = LEFT_SELECTION_HANDLE == type;
+
+    // Reference to the selection handle.
+    HandleImpl& handle = mHandle[type];
+
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as handle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
+    Vector2 handleWorldPosition;
+    CalculateHandleWorldCoordinates( handle, handleWorldPosition );
+
+    // Whether to flip the handle (horizontally).
+    bool flipHandle = isPrimaryHandle ? mFlipLeftSelectionHandleDirection : mFlipRightSelectionHandleDirection;
+
+    // Whether to flip the handles if they are crossed.
+    bool crossFlip = false;
+    if( mFlipSelectionHandlesOnCross || !mIsHandlePanning )
+    {
+      crossFlip = mIsHandleCurrentlyCrossed;
+    }
+
+    // Whether the handle was crossed before start the panning.
+    const bool isHandlePreviouslyCrossed = mFlipSelectionHandlesOnCross ? false : mIsHandlePreviouslyCrossed;
+
+    // Does not flip if both conditions are true (double flip)
+    flipHandle = flipHandle != ( crossFlip || isHandlePreviouslyCrossed );
+
+    // Will flip the handles vertically if the user prefers it.
+    bool verticallyFlippedPreferred = handle.verticallyFlippedPreferred;
+
+    if( crossFlip || isHandlePreviouslyCrossed )
+    {
+      if( isPrimaryHandle )
+      {
+        verticallyFlippedPreferred = mHandle[RIGHT_SELECTION_HANDLE].verticallyFlippedPreferred;
+      }
+      else
+      {
+        verticallyFlippedPreferred = mHandle[LEFT_SELECTION_HANDLE].verticallyFlippedPreferred;
+      }
+    }
+
+    // Check if the selection handle exceeds the boundaries of the decoration box.
+    const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
+    const bool exceedsRightEdge = ( isPrimaryHandle ? flipHandle : !flipHandle ) && ( handleWorldPosition.x + handle.size.width > mBoundingBox.z );
+
+    // Does not flip if both conditions are true (double flip)
+    flipHandle = flipHandle != ( exceedsLeftEdge || exceedsRightEdge );
+
+    if( flipHandle )
+    {
+      if( handle.actor && !handle.horizontallyFlipped )
+      {
+        // Change the anchor point to flip the image.
+        handle.actor.SetAnchorPoint( isPrimaryHandle ? AnchorPoint::TOP_LEFT : AnchorPoint::TOP_RIGHT );
+
+        handle.horizontallyFlipped = true;
+      }
+    }
+    else
+    {
+      if( handle.actor && handle.horizontallyFlipped )
+      {
+        // Reset the anchor point.
+        handle.actor.SetAnchorPoint( isPrimaryHandle ? AnchorPoint::TOP_RIGHT : AnchorPoint::TOP_LEFT );
+
+        handle.horizontallyFlipped = false;
+      }
+    }
+
+    // Whether to flip the handle vertically.
+    handle.verticallyFlipped = ( verticallyFlippedPreferred &&
+                                 ( ( handleWorldPosition.y - handle.size.height ) > mBoundingBox.y ) ) ||
+                               ( handleWorldPosition.y + handle.lineHeight + handle.size.height > mBoundingBox.w );
+
+    // The primary selection handle 'y' position in local coords.
+    // If the handle exceeds the bottom of the decoration box,
+    // set the 'y' position to the top of the line.
+    // The SetHandleImage() method will change the orientation.
+    const float yLocalPosition = handle.verticallyFlipped ? handle.position.y : handle.position.y + handle.lineHeight;
+
+    if( handle.actor )
+    {
+      handle.actor.SetPosition( handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f ),
+                                yLocalPosition + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f ) );
+    }
+  }
+
+  void SetHandleImage( HandleType type )
+  {
+    HandleImpl& handle = mHandle[type];
+
+    HandleType markerType = HANDLE_TYPE_COUNT;
+    // If the selection handle is flipped it chooses the image of the other selection handle. Does nothing for the grab handle.
+    if( LEFT_SELECTION_HANDLE == type )
+    {
+      type = handle.horizontallyFlipped ? RIGHT_SELECTION_HANDLE : LEFT_SELECTION_HANDLE;
+      markerType = handle.horizontallyFlipped ? RIGHT_SELECTION_HANDLE_MARKER : LEFT_SELECTION_HANDLE_MARKER;
+    }
+    else if( RIGHT_SELECTION_HANDLE == type )
+    {
+      type = handle.horizontallyFlipped ? LEFT_SELECTION_HANDLE : RIGHT_SELECTION_HANDLE;
+      markerType = handle.horizontallyFlipped ? LEFT_SELECTION_HANDLE_MARKER : RIGHT_SELECTION_HANDLE_MARKER;
+    }
+
+    // Chooses between the released or pressed image. It checks whether the pressed image exists.
+    if( handle.actor )
+    {
+      const HandleImageType imageType = ( handle.pressed ? ( mHandleImages[type][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+
+      handle.actor.SetImage( mHandleImages[type][imageType] );
+    }
+
+    if( HANDLE_TYPE_COUNT != markerType )
+    {
+      if( handle.markerActor )
+      {
+        const HandleImageType markerImageType = ( handle.pressed ? ( mHandleImages[markerType][HANDLE_IMAGE_PRESSED] ? HANDLE_IMAGE_PRESSED : HANDLE_IMAGE_RELEASED ) : HANDLE_IMAGE_RELEASED );
+        handle.markerActor.SetImage( mHandleImages[markerType][markerImageType] );
+      }
+    }
+
+    // Whether to flip the handle vertically.
+    if( handle.actor )
+    {
+      handle.actor.SetOrientation( handle.verticallyFlipped ? ANGLE_180 : ANGLE_0, Vector3::XAXIS );
+    }
+  }
+
+  void CreateHighlight()
+  {
+    if( !mHighlightActor )
+    {
+      mHighlightActor = Actor::New();
+
+      mHighlightActor.SetName( "HighlightActor" );
+      mHighlightActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      mHighlightActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      mHighlightActor.SetColor( mHighlightColor );
+      mHighlightActor.SetColorMode( USE_OWN_COLOR );
+    }
+
+    // Add the highlight box telling the controller it needs clipping.
+    mController.AddDecoration( mHighlightActor, true );
+  }
+
+  void UpdateHighlight()
+  {
+    if ( mHighlightActor )
+    {
+      // Sets the position of the highlight actor inside the decorator.
+      mHighlightActor.SetPosition( mHighlightPosition.x + mHighlightOutlineOffset,
+                                   mHighlightPosition.y + mHighlightOutlineOffset );
+
+      const unsigned int numberOfQuads = mHighlightQuadList.Count();
+      if( 0u != numberOfQuads )
+      {
+        // Set the size of the highlighted text to the actor.
+        mHighlightActor.SetSize( mHighlightSize );
+
+        // Used to translate the vertices given in decorator's coords to the mHighlightActor's local coords.
+        const float offsetX = mHighlightPosition.x + 0.5f * mHighlightSize.width;
+        const float offsetY = mHighlightPosition.y + 0.5f * mHighlightSize.height;
+
+        Vector<Vector2> vertices;
+        Vector<unsigned short> indices;
+
+        vertices.Reserve( 4u * numberOfQuads );
+        indices.Reserve( 6u * numberOfQuads );
+
+        // Index to the vertex.
+        unsigned int v = 0u;
+
+        // Traverse all quads.
+        for( Vector<Vector4>::ConstIterator it = mHighlightQuadList.Begin(),
+               endIt = mHighlightQuadList.End();
+             it != endIt;
+             ++it, v += 4u )
+        {
+          const Vector4& quad = *it;
+
+          Vector2 vertex;
+
+          // top-left (v+0)
+          vertex.x = quad.x - offsetX;
+          vertex.y = quad.y - offsetY;
+          vertices.PushBack( vertex );
+
+          // top-right (v+1)
+          vertex.x = quad.z - offsetX;
+          vertex.y = quad.y - offsetY;
+          vertices.PushBack( vertex );
+
+          // bottom-left (v+2)
+          vertex.x = quad.x - offsetX;
+          vertex.y = quad.w - offsetY;
+          vertices.PushBack( vertex );
+
+          // bottom-right (v+3)
+          vertex.x = quad.z - offsetX;
+          vertex.y = quad.w - offsetY;
+          vertices.PushBack( vertex );
+
+          // triangle A (3, 1, 0)
+          indices.PushBack( v + 3 );
+          indices.PushBack( v + 1 );
+          indices.PushBack( v );
+
+          // triangle B (0, 2, 3)
+          indices.PushBack( v );
+          indices.PushBack( v + 2 );
+          indices.PushBack( v + 3 );
+        }
+
+        if( ! mQuadVertices )
+        {
+          mQuadVertices = PropertyBuffer::New( mQuadVertexFormat );
+        }
+
+        mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
+
+        if( !mQuadGeometry )
+        {
+          mQuadGeometry = Geometry::New();
+          mQuadGeometry.AddVertexBuffer( mQuadVertices );
+        }
+        mQuadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+
+        if( !mHighlightRenderer )
+        {
+          mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightShader );
+          mHighlightActor.AddRenderer( mHighlightRenderer );
+        }
+      }
+
+      mHighlightQuadList.Clear();
+
+      if( mHighlightRenderer )
+      {
+        mHighlightRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mTextDepth - 2 ); // text is rendered at mTextDepth and text's shadow at mTextDepth -1u.
+      }
+    }
+  }
+
+  void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture )
+  {
+    if( Gesture::Started == gesture.state )
+    {
+      handle.grabDisplacementX = handle.grabDisplacementY = 0.f;
+
+      handle.globalPosition.x = handle.position.x;
+      handle.globalPosition.y = handle.position.y;
+    }
+
+    handle.grabDisplacementX += gesture.displacement.x;
+    handle.grabDisplacementY += ( handle.verticallyFlipped ? -gesture.displacement.y : gesture.displacement.y );
+
+    const float x = handle.globalPosition.x + handle.grabDisplacementX;
+    const float y = handle.globalPosition.y + handle.grabDisplacementY + 0.5f * handle.lineHeight;
+    const float yVerticallyFlippedCorrected = y - ( handle.verticallyFlippedOnTouch ? handle.lineHeight : 0.f );
+
+    if( ( Gesture::Started    == gesture.state ) ||
+        ( Gesture::Continuing == gesture.state ) )
+    {
+      Vector2 targetSize;
+      mController.GetTargetSize( targetSize );
+
+      if( mHorizontalScrollingEnabled &&
+          ( x < mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_RIGHT;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else if( mHorizontalScrollingEnabled &&
+               ( x > targetSize.width - mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_LEFT;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else if( mVerticalScrollingEnabled &&
+               ( yVerticallyFlippedCorrected < mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_TOP;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else if( mVerticalScrollingEnabled &&
+               ( yVerticallyFlippedCorrected + handle.lineHeight > targetSize.height - mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_BOTTOM;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else
+      {
+        mHandleScrolling = HANDLE_TYPE_COUNT;
+        StopScrollTimer();
+        mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
+      }
+
+      mIsHandlePanning = true;
+    }
+    else if( ( Gesture::Finished  == gesture.state ) ||
+             ( Gesture::Cancelled == gesture.state ) )
+    {
+      if( mScrollTimer &&
+          ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
+      {
+        mNotifyEndOfScroll = false;
+        mHandleScrolling = HANDLE_TYPE_COUNT;
+        StopScrollTimer();
+        mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
+      }
+      else
+      {
+        mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
+      }
+
+      if( handle.actor )
+      {
+        handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+      }
+      handle.pressed = false;
+
+      mIsHandlePanning = false;
+    }
+  }
+
+  void OnPan( Actor actor, const PanGesture& gesture )
+  {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+    HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    if( actor == grabHandle.grabArea )
+    {
+      DoPan( grabHandle, GRAB_HANDLE, gesture );
+    }
+    else if( actor == primarySelectionHandle.grabArea )
+    {
+      DoPan( primarySelectionHandle, LEFT_SELECTION_HANDLE, gesture );
+    }
+    else if( actor == secondarySelectionHandle.grabArea )
+    {
+      DoPan( secondarySelectionHandle, RIGHT_SELECTION_HANDLE, gesture );
+    }
+  }
+
+  bool OnGrabHandleTouched( Actor actor, const TouchData& touch )
+  {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+    // Switch between pressed/release grab-handle images
+    if( touch.GetPointCount() > 0 &&
+        grabHandle.actor )
+    {
+      const PointState::Type state = touch.GetState( 0 );
+
+      if( PointState::DOWN == state )
+      {
+        grabHandle.pressed = true;
+      }
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
+      {
+        grabHandle.pressed = false;
+      }
+
+      SetHandleImage( GRAB_HANDLE );
+    }
+
+    // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+    return true;
+  }
+
+  bool OnHandleOneTouched( Actor actor, const TouchData& touch )
+  {
+    HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+
+    // Switch between pressed/release selection handle images
+    if( touch.GetPointCount() > 0 &&
+        primarySelectionHandle.actor )
+    {
+      const PointState::Type state = touch.GetState( 0 );
+
+      if( PointState::DOWN == state )
+      {
+        primarySelectionHandle.pressed = true;
+        primarySelectionHandle.verticallyFlippedOnTouch = primarySelectionHandle.verticallyFlipped;
+      }
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
+      {
+        primarySelectionHandle.pressed = false;
+        mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+        mIsHandlePanning = false;
+        mHandleReleased = LEFT_SELECTION_HANDLE;
+      }
+
+      SetHandleImage( LEFT_SELECTION_HANDLE );
+    }
+
+    // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+    return true;
+  }
+
+  bool OnHandleTwoTouched( Actor actor, const TouchData& touch )
+  {
+    HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    // Switch between pressed/release selection handle images
+    if( touch.GetPointCount() > 0 &&
+        secondarySelectionHandle.actor )
+    {
+      const PointState::Type state = touch.GetState( 0 );
+
+      if( PointState::DOWN == state )
+      {
+        secondarySelectionHandle.pressed = true;
+        secondarySelectionHandle.verticallyFlippedOnTouch = secondarySelectionHandle.verticallyFlipped;
+      }
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
+      {
+        secondarySelectionHandle.pressed = false;
+        mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+        mIsHandlePanning = false;
+        mHandleReleased = RIGHT_SELECTION_HANDLE;
+      }
+
+      SetHandleImage( RIGHT_SELECTION_HANDLE );
+    }
+
+    // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+    return true;
+  }
+
+  void HandleResetPosition( PropertyNotification& source )
+  {
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+    if( grabHandle.active )
+    {
+      // Sets the grab handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetGrabHandlePosition();
+
+      // Sets the grab handle image according if it's pressed, flipped, etc.
+      SetHandleImage( GRAB_HANDLE );
+    }
+    else
+    {
+      // Sets the primary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
+
+      // Sets the primary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( LEFT_SELECTION_HANDLE );
+
+      // Sets the secondary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
+
+      // Sets the secondary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( RIGHT_SELECTION_HANDLE );
+    }
+  }
+
+  void SetupActiveLayerPropertyNotifications()
+  {
+    if( !mActiveLayer )
+    {
+      return;
+    }
+
+    // Vertical notifications.
+
+    // Disconnect any previous connected callback.
+    if( mHandleVerticalLessThanNotification )
+    {
+      mHandleVerticalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHandleVerticalLessThanNotification );
+    }
+
+    if( mHandleVerticalGreaterThanNotification )
+    {
+      mHandleVerticalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHandleVerticalGreaterThanNotification );
+    }
+
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    if( grabHandle.active )
+    {
+      if( grabHandle.verticallyFlipped )
+      {
+        // The grab handle is vertically flipped. Never is going to exceed the bottom edje of the display.
+        mHandleVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height - grabHandle.position.y + grabHandle.size.height;
+
+        mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                    LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // The grab handle is not vertically flipped. Never is going to exceed the top edje of the display.
+        mHandleVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + grabHandle.position.y + grabHandle.lineHeight + grabHandle.size.height;
+
+        mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                       GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+    }
+    else // The selection handles are active
+    {
+      if( primaryHandle.verticallyFlipped && secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles are vertically flipped. Never are going to exceed the bottom edje of the display.
+        mHandleVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + std::max( -primaryHandle.position.y + primaryHandle.size.height, -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                    LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else if( !primaryHandle.verticallyFlipped && !secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles aren't vertically flipped. Never are going to exceed the top edje of the display.
+        mHandleVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + std::max( primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height,
+                                                                           secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height );
+
+        mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                       GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // Only one of the selection handles is vertically flipped. Both vertical notifications are needed.
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                              ?
+                                                               -primaryHandle.position.y + primaryHandle.size.height        :
+                                                               -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                    LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                                                       ?
+                                                                   secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height :
+                                                                   primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height );
+
+        mHandleVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                       GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mHandleVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mHandleVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+    }
+
+    // Horizontal notifications.
+
+    // Disconnect any previous connected callback.
+    if( mHandleHorizontalLessThanNotification )
+    {
+      mHandleHorizontalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHandleHorizontalLessThanNotification );
+    }
+
+    if( mHandleHorizontalGreaterThanNotification )
+    {
+      mHandleHorizontalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHandleHorizontalGreaterThanNotification );
+    }
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      // The horizontal distance from the center of the active layer to the left edje of the display.
+      const float leftWidth = 0.5f * mControlSize.width + std::max( -primaryHandle.position.x + primaryHandle.size.width,
+                                                                    -secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHandleHorizontalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                                    LessThanCondition( mBoundingBox.x + leftWidth ) );
+
+      // Notifies the change from false to true and from true to false.
+      mHandleHorizontalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHandleHorizontalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+      // The horizontal distance from the center of the active layer to the right edje of the display.
+      const float rightWidth = -0.5f * mControlSize.width + std::max( primaryHandle.position.x + primaryHandle.size.width,
+                                                                      secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHandleHorizontalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                                       GreaterThanCondition( mBoundingBox.z - rightWidth ) );
+
+      // Notifies the change from false to true and from true to false.
+      mHandleHorizontalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHandleHorizontalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+    }
+  }
+
+  // Popup
+
+  float AlternatePopUpPositionRelativeToCursor( bool topBottom )
+  {
+    float alternativePosition = 0.0f;
+
+    const float halfPopupHeight = 0.5f * mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
+
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      float handleY = 0.f;
+      float maxHandleHeight = 0.f;
+
+      const bool primaryVisible = primaryHandle.horizontallyVisible && primaryHandle.verticallyVisible;
+      const bool secondaryVisible = secondaryHandle.horizontallyVisible && secondaryHandle.verticallyVisible;
+
+      if( primaryVisible && secondaryVisible )
+      {
+        handleY = std::max( primaryHandle.position.y, secondaryHandle.position.y );
+        maxHandleHeight = std::max( primaryHandle.size.height, secondaryHandle.size.height );
+      }
+      else if( primaryVisible && !secondaryVisible )
+      {
+        handleY = primaryHandle.position.y;
+        maxHandleHeight = primaryHandle.size.height;
+      }
+      else if( !primaryVisible && secondaryVisible )
+      {
+        handleY = secondaryHandle.position.y;
+        maxHandleHeight = secondaryHandle.size.height;
+      }
+
+      alternativePosition = handleY + ( topBottom ? halfPopupHeight + maxHandleHeight + cursor.lineHeight : -halfPopupHeight - maxHandleHeight );
+    }
+    else
+    {
+      alternativePosition = cursor.position.y + ( topBottom ? halfPopupHeight + grabHandle.size.height + cursor.lineHeight : -halfPopupHeight - grabHandle.size.height );
+    }
+
+    return alternativePosition;
+  }
+
+  void PopUpLeavesTopBoundary( PropertyNotification& source )
+  {
+    const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
+
+    // Sets the position of the popup below.
+    mCopyPastePopup.actor.SetY( floorf( CalculateVerticalPopUpPosition( 0.5f * popupHeight, true ) ) );
+  }
+
+  void PopUpLeavesBottomBoundary( PropertyNotification& source )
+  {
+    const float popupHeight = mCopyPastePopup.actor.GetRelayoutSize( Dimension::HEIGHT );
+
+    // Sets the position of the popup above.
+    mCopyPastePopup.actor.SetY( floorf( CalculateVerticalPopUpPosition( 0.5f * popupHeight, false ) ) );
+  }
+
+  void SetUpPopupPositionNotifications( const Vector3& popupHalfSize )
+  {
+    // Disconnect any previous connected callback.
+    if( mPopupTopExceedNotification )
+    {
+      mPopupTopExceedNotification.NotifySignal().Disconnect( this, &Decorator::Impl::PopUpLeavesTopBoundary );
+      mCopyPastePopup.actor.RemovePropertyNotification( mPopupTopExceedNotification );
+    }
+
+    if( mPopupBottomExceedNotification )
+    {
+      mPopupBottomExceedNotification.NotifySignal().Disconnect( this, &Decorator::Impl::PopUpLeavesBottomBoundary );
+      mCopyPastePopup.actor.RemovePropertyNotification( mPopupBottomExceedNotification );
+    }
+
+    // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
+
+    // Exceeding vertical boundary
+
+    mPopupTopExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 LessThanCondition( mBoundingBox.y + popupHalfSize.height ) );
+
+    mPopupBottomExceedNotification = mCopyPastePopup.actor.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                    GreaterThanCondition( mBoundingBox.w - popupHalfSize.height ) );
+
+    // Notifies the change from false to true and from true to false.
+    mPopupTopExceedNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+    mPopupBottomExceedNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+    mPopupTopExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesTopBoundary );
+    mPopupBottomExceedNotification.NotifySignal().Connect( this, &Decorator::Impl::PopUpLeavesBottomBoundary );
+  }
+
+  void SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image )
+  {
+    HandleImpl& handle = mHandle[handleType];
+    handle.size = Size( image.GetWidth(), image.GetHeight() );
+
+    mHandleImages[handleType][handleImageType] = image;
+  }
+
+  void SetScrollThreshold( float threshold )
+  {
+    mScrollThreshold = threshold;
+  }
+
+  float GetScrollThreshold() const
+  {
+    return mScrollThreshold;
+  }
+
+  void SetScrollSpeed( float speed )
+  {
+    mScrollSpeed = speed;
+    mScrollDistance = speed * SCROLL_TICK_INTERVAL * TO_SECONDS;
+  }
+
+  float GetScrollSpeed() const
+  {
+    return mScrollSpeed;
+  }
+
+  void NotifyEndOfScroll()
+  {
+    StopScrollTimer();
+
+    if( mScrollTimer )
+    {
+      mNotifyEndOfScroll = true;
+    }
+  }
+
+  /**
+   * Creates and starts a timer to scroll the text when handles are close to the edges of the text.
+   *
+   * It only starts the timer if it's already created.
+   */
+  void StartScrollTimer()
+  {
+    if( !mScrollTimer )
+    {
+      mScrollTimer = Timer::New( SCROLL_TICK_INTERVAL );
+      mScrollTimer.TickSignal().Connect( this, &Decorator::Impl::OnScrollTimerTick );
+    }
+
+    if( !mScrollTimer.IsRunning() )
+    {
+      mScrollTimer.Start();
+    }
+  }
+
+  /**
+   * Stops the timer used to scroll the text.
+   */
+  void StopScrollTimer()
+  {
+    if( mScrollTimer )
+    {
+      mScrollTimer.Stop();
+    }
+  }
+
+  /**
+   * Callback called by the timer used to scroll the text.
+   *
+   * It calculates and sets a new scroll position.
+   */
+  bool OnScrollTimerTick()
+  {
+    if( HANDLE_TYPE_COUNT != mHandleScrolling )
+    {
+      float x = 0.f;
+      float y = 0.f;
+
+      switch( mScrollDirection )
+      {
+        case SCROLL_RIGHT:
+        {
+          x = mScrollDistance;
+          break;
+        }
+        case SCROLL_LEFT:
+        {
+          x = -mScrollDistance;
+          break;
+        }
+        case SCROLL_TOP:
+        {
+          y = mScrollDistance;
+          break;
+        }
+        case SCROLL_BOTTOM:
+        {
+          y = -mScrollDistance;
+          break;
+        }
+        default:
+          break;
+      }
+
+      mController.DecorationEvent( mHandleScrolling,
+                                   HANDLE_SCROLLING,
+                                   x,
+                                   y );
+    }
+
+    return true;
+  }
+
+  ControllerInterface& mController;
+
+  TapGestureDetector       mTapDetector;
+  PanGestureDetector       mPanDetector;
+  LongPressGestureDetector mLongPressDetector;
+
+  Timer               mCursorBlinkTimer;          ///< Timer to signal cursor to blink
+  Timer               mScrollTimer;               ///< Timer used to scroll the text when the grab handle is moved close to the edges.
+
+  Layer                mActiveLayer;                             ///< Layer for active handles and alike that ensures they are above all else.
+  PropertyNotification mHandleVerticalLessThanNotification;      ///< Notifies when the 'y' coord of the active layer is less than a given value.
+  PropertyNotification mHandleVerticalGreaterThanNotification;   ///< Notifies when the 'y' coord of the active layer is grater than a given value.
+  PropertyNotification mHandleHorizontalLessThanNotification;    ///< Notifies when the 'x' coord of the active layer is less than a given value.
+  PropertyNotification mHandleHorizontalGreaterThanNotification; ///< Notifies when the 'x' coord of the active layer is grater than a given value.
+  PropertyNotification mPopupTopExceedNotification;              ///< Notifies when the popup leaves the bounding box through the top.
+  PropertyNotification mPopupBottomExceedNotification;           ///< Notifies when the popup leaves the bounding box through the bottom.
+  Control              mPrimaryCursor;
+  Control              mSecondaryCursor;
+
+  Actor               mHighlightActor;            ///< Actor to display highlight
+  Renderer            mHighlightRenderer;
+  Shader              mHighlightShader;           ///< Shader used for highlight
+  Property::Map       mQuadVertexFormat;
+  PopupImpl           mCopyPastePopup;
+  TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
+  TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
+
+  Image               mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
+  Vector4             mHandleColor;
+
+  CursorImpl          mCursor[CURSOR_COUNT];
+  HandleImpl          mHandle[HANDLE_TYPE_COUNT];
+
+  PropertyBuffer      mQuadVertices;
+  Geometry            mQuadGeometry;
+  QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight.
+
+  Vector4             mBoundingBox;               ///< The bounding box in world coords.
+  Vector4             mHighlightColor;            ///< Color of the highlight
+  Vector2             mHighlightPosition;         ///< The position of the highlight actor.
+  Size                mHighlightSize;             ///< The size of the highlighted text.
+  Size                mControlSize;               ///< The control's size. Set by the Relayout.
+  float               mHighlightOutlineOffset;    ///< The outline's offset.
+
+  unsigned int        mActiveCursor;
+  unsigned int        mCursorBlinkInterval;
+  float               mCursorBlinkDuration;
+  float               mCursorWidth;             ///< The width of the cursors in pixels.
+  HandleType          mHandleScrolling;         ///< The handle which is scrolling.
+  HandleType          mHandleReleased;          ///< The last handle released.
+  ScrollDirection     mScrollDirection;         ///< The direction of the scroll.
+  float               mScrollThreshold;         ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
+  float               mScrollSpeed;             ///< The scroll speed in pixels per second.
+  float               mScrollDistance;          ///< Distance the text scrolls during a scroll interval.
+  int                 mTextDepth;               ///< The depth used to render the text.
+
+  bool                mActiveCopyPastePopup              : 1;
+  bool                mPopupSetNewPosition               : 1;
+  bool                mCursorBlinkStatus                 : 1; ///< Flag to switch between blink on and blink off.
+  bool                mDelayCursorBlink                  : 1; ///< Used to avoid cursor blinking when entering text.
+  bool                mPrimaryCursorVisible              : 1; ///< Whether the primary cursor is visible.
+  bool                mSecondaryCursorVisible            : 1; ///< Whether the secondary cursor is visible.
+  bool                mFlipSelectionHandlesOnCross       : 1; ///< Whether to flip the selection handles as soon as they cross.
+  bool                mFlipLeftSelectionHandleDirection  : 1; ///< Whether to flip the left selection handle image because of the character's direction.
+  bool                mFlipRightSelectionHandleDirection : 1; ///< Whether to flip the right selection handle image because of the character's direction.
+  bool                mIsHandlePanning                   : 1; ///< Whether any of the handles is moving.
+  bool                mIsHandleCurrentlyCrossed          : 1; ///< Whether the handles are crossed.
+  bool                mIsHandlePreviouslyCrossed         : 1; ///< Whether the handles where crossed at the last handle touch up.
+  bool                mNotifyEndOfScroll                 : 1; ///< Whether to notify the end of the scroll.
+  bool                mHorizontalScrollingEnabled        : 1; ///< Whether the horizontal scrolling is enabled.
+  bool                mVerticalScrollingEnabled          : 1; ///< Whether the vertical scrolling is enabled.
+  bool                mSmoothHandlePanEnabled            : 1; ///< Whether to pan smoothly the handles.
+  bool                mIsHighlightBoxActive              : 1; ///< Whether the highlight box is active.
+};
+
+DecoratorPtr Decorator::New( ControllerInterface& controller,
+                             TextSelectionPopupCallbackInterface& callbackInterface )
+{
+  return DecoratorPtr( new Decorator( controller,
+                                      callbackInterface ) );
+}
+
+void Decorator::SetBoundingBox( const Rect<int>& boundingBox )
+{
+  LocalToWorldCoordinatesBoundingBox( boundingBox, mImpl->mBoundingBox );
+}
+
+void Decorator::GetBoundingBox( Rect<int>& boundingBox ) const
+{
+  WorldToLocalCoordinatesBoundingBox( mImpl->mBoundingBox, boundingBox );
+}
+
+void Decorator::Relayout( const Vector2& size )
+{
+  mImpl->Relayout( size );
+}
+
+void Decorator::UpdatePositions( const Vector2& scrollOffset )
+{
+  mImpl->UpdatePositions( scrollOffset );
+}
+
+/** Cursor **/
+
+void Decorator::SetActiveCursor( ActiveCursor activeCursor )
+{
+  mImpl->mActiveCursor = activeCursor;
+}
+
+unsigned int Decorator::GetActiveCursor() const
+{
+  return mImpl->mActiveCursor;
+}
+
+void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight )
+{
+  Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
+
+  cursorImpl.position.x = x;
+  cursorImpl.position.y = y;
+  cursorImpl.cursorHeight = cursorHeight;
+  cursorImpl.lineHeight = lineHeight;
+}
+
+void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& cursorHeight, float& lineHeight ) const
+{
+  const Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
+
+  x = cursorImpl.position.x;
+  y = cursorImpl.position.y;
+  cursorHeight = cursorImpl.cursorHeight;
+  lineHeight = cursorImpl.lineHeight;
+}
+
+const Vector2& Decorator::GetPosition( Cursor cursor ) const
+{
+  return mImpl->mCursor[cursor].position;
+}
+
+void Decorator::SetGlyphOffset( Cursor cursor, float glyphOffset )
+{
+  Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
+
+  cursorImpl.glyphOffset = glyphOffset;
+}
+
+const float Decorator::GetGlyphOffset( Cursor cursor) const
+{
+  return mImpl->mCursor[cursor].glyphOffset;
+}
+
+void Decorator::SetCursorColor( Cursor cursor, const Dali::Vector4& color )
+{
+  mImpl->mCursor[cursor].color = color;
+}
+
+const Dali::Vector4& Decorator::GetColor( Cursor cursor ) const
+{
+  return mImpl->mCursor[cursor].color;
+}
+
+void Decorator::StartCursorBlink()
+{
+  if ( !mImpl->mCursorBlinkTimer )
+  {
+    mImpl->mCursorBlinkTimer = Timer::New( mImpl->mCursorBlinkInterval );
+    mImpl->mCursorBlinkTimer.TickSignal().Connect( mImpl, &Decorator::Impl::OnCursorBlinkTimerTick );
+  }
+
+  if ( !mImpl->mCursorBlinkTimer.IsRunning() )
+  {
+    mImpl->mCursorBlinkTimer.Start();
+  }
+}
+
+void Decorator::StopCursorBlink()
+{
+  if ( mImpl->mCursorBlinkTimer )
+  {
+    mImpl->mCursorBlinkTimer.Stop();
+  }
+
+  mImpl->mCursorBlinkStatus = true; // Keep cursor permanently shown
+}
+
+void Decorator::DelayCursorBlink()
+{
+  mImpl->mCursorBlinkStatus = true; // Show cursor for a bit longer
+  mImpl->mDelayCursorBlink = true;
+}
+
+void Decorator::SetCursorBlinkInterval( float seconds )
+{
+  mImpl->mCursorBlinkInterval = static_cast<unsigned int>( seconds * TO_MILLISECONDS ); // Convert to milliseconds
+}
+
+float Decorator::GetCursorBlinkInterval() const
+{
+  return static_cast<float>( mImpl->mCursorBlinkInterval ) * TO_SECONDS;
+}
+
+void Decorator::SetCursorBlinkDuration( float seconds )
+{
+  mImpl->mCursorBlinkDuration = seconds;
+}
+
+float Decorator::GetCursorBlinkDuration() const
+{
+  return mImpl->mCursorBlinkDuration;
+}
+
+void Decorator::SetCursorWidth( int width )
+{
+  mImpl->mCursorWidth = static_cast<float>( width );
+}
+
+int Decorator::GetCursorWidth() const
+{
+  return static_cast<int>( mImpl->mCursorWidth );
+}
+
+/** Handles **/
+
+void Decorator::SetHandleActive( HandleType handleType, bool active )
+{
+  mImpl->mHandle[handleType].active = active;
+
+  if( !active )
+  {
+    if( ( LEFT_SELECTION_HANDLE == handleType ) || ( RIGHT_SELECTION_HANDLE == handleType ) )
+    {
+      mImpl->mIsHandlePreviouslyCrossed = false;
+    }
+
+    // TODO: this is a work-around.
+    // The problem is the handle actor does not receive the touch event with the Interrupt
+    // state when the power button is pressed and the application goes to background.
+    mImpl->mHandle[handleType].pressed = false;
+    Image imageReleased = mImpl->mHandleImages[handleType][HANDLE_IMAGE_RELEASED];
+    ImageView imageView = mImpl->mHandle[handleType].actor;
+    if( imageReleased && imageView )
+    {
+      imageView.SetImage( imageReleased );
+    }
+  }
+
+}
+
+bool Decorator::IsHandleActive( HandleType handleType ) const
+{
+  return mImpl->mHandle[handleType].active ;
+}
+
+void Decorator::SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image )
+{
+  mImpl->SetHandleImage( handleType, handleImageType, image );
+}
+
+Dali::Image Decorator::GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const
+{
+  return mImpl->mHandleImages[handleType][handleImageType];
+}
+
+void Decorator::SetHandleColor( const Vector4& color )
+{
+  mImpl->mHandleColor = color;
+}
+
+const Vector4& Decorator::GetHandleColor() const
+{
+  return mImpl->mHandleColor;
+}
+
+void Decorator::SetPosition( HandleType handleType, float x, float y, float height )
+{
+  // Adjust handle's displacement
+  Impl::HandleImpl& handle = mImpl->mHandle[handleType];
+
+  handle.position.x = x;
+  handle.position.y = y;
+  handle.lineHeight = height;
+
+  if( mImpl->mSmoothHandlePanEnabled )
+  {
+    handle.grabDisplacementX = 0.f;
+    handle.grabDisplacementY = 0.f;
+  }
+}
+
+void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& height ) const
+{
+  Impl::HandleImpl& handle = mImpl->mHandle[handleType];
+
+  x = handle.position.x;
+  y = handle.position.y;
+  height = handle.lineHeight;
+}
+
+const Vector2& Decorator::GetPosition( HandleType handleType ) const
+{
+  return mImpl->mHandle[handleType].position;
+}
+
+void Decorator::FlipHandleVertically( HandleType handleType, bool flip )
+{
+  mImpl->mHandle[handleType].verticallyFlippedPreferred = flip;
+}
+
+bool Decorator::IsHandleVerticallyFlipped( HandleType handleType ) const
+{
+  return mImpl->mHandle[handleType].verticallyFlippedPreferred;
+}
+
+void Decorator::FlipSelectionHandlesOnCrossEnabled( bool enable )
+{
+  mImpl->mFlipSelectionHandlesOnCross = enable;
+}
+
+void Decorator::SetSelectionHandleFlipState( bool indicesSwapped, bool left, bool right )
+{
+  mImpl->mIsHandleCurrentlyCrossed = indicesSwapped;
+  mImpl->mFlipLeftSelectionHandleDirection = left;
+  mImpl->mFlipRightSelectionHandleDirection = right;
+}
+
+void Decorator::AddHighlight( unsigned int index, const Vector4& quad )
+{
+  *( mImpl->mHighlightQuadList.Begin() + index ) = quad;
+}
+
+void Decorator::SetHighLightBox( const Vector2& position, const Size& size, float outlineOffset )
+{
+  mImpl->mHighlightPosition = position;
+  mImpl->mHighlightSize = size;
+  mImpl->mHighlightOutlineOffset = outlineOffset;
+}
+
+void Decorator::ClearHighlights()
+{
+  mImpl->mHighlightQuadList.Clear();
+  mImpl->mHighlightPosition = Vector2::ZERO;
+  mImpl->mHighlightOutlineOffset = 0.f;
+}
+
+void Decorator::ResizeHighlightQuads( unsigned int numberOfQuads )
+{
+  mImpl->mHighlightQuadList.Resize( numberOfQuads );
+}
+
+void Decorator::SetHighlightColor( const Vector4& color )
+{
+  mImpl->mHighlightColor = color;
+}
+
+const Vector4& Decorator::GetHighlightColor() const
+{
+  return mImpl->mHighlightColor;
+}
+
+void Decorator::SetHighlightActive( bool active )
+{
+  mImpl->mIsHighlightBoxActive = active;
+}
+
+bool Decorator::IsHighlightActive() const
+{
+  return mImpl->mIsHighlightBoxActive;
+}
+
+bool Decorator::IsHighlightVisible() const
+{
+  return ( mImpl->mHighlightActor && mImpl->mHighlightActor.GetParent() );
+}
+
+void Decorator::SetTextDepth( int textDepth )
+{
+  mImpl->mTextDepth = textDepth;
+}
+
+void Decorator::SetPopupActive( bool active )
+{
+  mImpl->mActiveCopyPastePopup = active;
+}
+
+bool Decorator::IsPopupActive() const
+{
+  return mImpl->mActiveCopyPastePopup;
+}
+
+void Decorator::SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask )
+{
+  mImpl->mEnabledPopupButtons = enabledButtonsBitMask;
+
+  if ( !mImpl->mCopyPastePopup.actor )
+  {
+    mImpl->mCopyPastePopup.actor = TextSelectionPopup::New( &mImpl->mTextSelectionPopupCallbackInterface );
+#ifdef DECORATOR_DEBUG
+    mImpl->mCopyPastePopup.actor.SetName("mCopyPastePopup");
+#endif
+    mImpl->mCopyPastePopup.actor.SetAnchorPoint( AnchorPoint::CENTER );
+    mImpl->mCopyPastePopup.actor.OnRelayoutSignal().Connect( mImpl, &Decorator::Impl::SetPopupPosition ); // Position popup after size negotiation
+  }
+
+  mImpl->mCopyPastePopup.actor.EnableButtons( mImpl->mEnabledPopupButtons );
+}
+
+TextSelectionPopup::Buttons& Decorator::GetEnabledPopupButtons()
+{
+  return mImpl->mEnabledPopupButtons;
+}
+
+/** Scroll **/
+
+void Decorator::SetScrollThreshold( float threshold )
+{
+  mImpl->SetScrollThreshold( threshold );
+}
+
+float Decorator::GetScrollThreshold() const
+{
+  return mImpl->GetScrollThreshold();
+}
+
+void Decorator::SetScrollSpeed( float speed )
+{
+  mImpl->SetScrollSpeed( speed );
+}
+
+float Decorator::GetScrollSpeed() const
+{
+  return mImpl->GetScrollSpeed();
+}
+
+void Decorator::NotifyEndOfScroll()
+{
+  mImpl->NotifyEndOfScroll();
+}
+
+void Decorator::SetHorizontalScrollEnabled( bool enable )
+{
+  mImpl->mHorizontalScrollingEnabled = enable;
+}
+
+bool Decorator::IsHorizontalScrollEnabled() const
+{
+  return mImpl->mHorizontalScrollingEnabled;
+}
+
+void Decorator::SetVerticalScrollEnabled( bool enable )
+{
+  mImpl->mVerticalScrollingEnabled = enable;
+}
+
+bool Decorator::IsVerticalScrollEnabled() const
+{
+  return mImpl->mVerticalScrollingEnabled;
+}
+
+void Decorator::SetSmoothHandlePanEnabled( bool enable )
+{
+  mImpl->mSmoothHandlePanEnabled = enable;
+}
+
+bool Decorator::IsSmoothHandlePanEnabled() const
+{
+  return mImpl->mSmoothHandlePanEnabled;
+}
+
+Decorator::~Decorator()
+{
+  delete mImpl;
+}
+
+Decorator::Decorator( ControllerInterface& controller,
+                      TextSelectionPopupCallbackInterface& callbackInterface )
+: mImpl( NULL )
+{
+  mImpl = new Decorator::Impl( controller, callbackInterface );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/decorator/text-decorator.h b/dali-toolkit/internal/text/decorator/text-decorator.h
new file mode 100644 (file)
index 0000000..36adee4
--- /dev/null
@@ -0,0 +1,658 @@
+#ifndef DALI_TOOLKIT_TEXT_DECORATOR_H
+#define DALI_TOOLKIT_TEXT_DECORATOR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/math/rect.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup.h>
+
+namespace Dali
+{
+
+struct Vector2;
+struct Vector4;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class Decorator;
+typedef IntrusivePtr<Decorator> DecoratorPtr;
+
+// Used to set the cursor positions etc.
+enum Cursor
+{
+  PRIMARY_CURSOR,   ///< The primary cursor for bidirectional text (or the regular cursor for single-direction text)
+  SECONDARY_CURSOR, ///< The secondary cursor for bidirectional text
+  CURSOR_COUNT
+};
+
+// Determines which of the cursors are active (if any).
+enum ActiveCursor
+{
+  ACTIVE_CURSOR_NONE,    ///< Neither primary nor secondary cursor are active
+  ACTIVE_CURSOR_PRIMARY, ///< Primary cursor is active (only)
+  ACTIVE_CURSOR_BOTH     ///< Both primary and secondary cursor are active
+};
+
+// The state information for handle events.
+enum HandleState
+{
+  HANDLE_TAPPED,
+  HANDLE_PRESSED,
+  HANDLE_RELEASED,
+  HANDLE_SCROLLING,
+  HANDLE_STOP_SCROLLING
+};
+
+// Used to set different handle images
+enum HandleImageType
+{
+  HANDLE_IMAGE_PRESSED,
+  HANDLE_IMAGE_RELEASED,
+  HANDLE_IMAGE_TYPE_COUNT
+};
+
+// Types of handles.
+enum HandleType
+{
+  GRAB_HANDLE,
+  LEFT_SELECTION_HANDLE,
+  RIGHT_SELECTION_HANDLE,
+  LEFT_SELECTION_HANDLE_MARKER,
+  RIGHT_SELECTION_HANDLE_MARKER,
+  HANDLE_TYPE_COUNT
+};
+
+/**
+ * @brief A Text Decorator is used to display cursors, handles, selection highlights and pop-ups.
+ *
+ * The decorator is responsible for clipping decorations which are positioned outside of the parent area.
+ *
+ * The Popup decoration will be positioned either above the Grab handle or above the selection handles but if doing so
+ * would cause the Popup to exceed the Decoration Bounding Box ( see SetBoundingBox API ) the the Popup will be repositioned below the handle(s).
+ *
+ * Selection handles will be flipped around to ensure they do not exceed the Decoration Bounding Box. ( Stay visible ).
+ *
+ * Decorator components forward input events to a controller class through an interface.
+ * The controller is responsible for selecting which components are active.
+ */
+class Decorator : public RefObject
+{
+public:
+
+  class ControllerInterface
+  {
+  public:
+
+    /**
+     * @brief Constructor.
+     */
+    ControllerInterface() {};
+
+    /**
+     * @brief Virtual destructor.
+     */
+    virtual ~ControllerInterface() {};
+
+    /**
+     * @brief Query the target size of the UI control.
+     *
+     * @param[out] targetSize The size of the UI control the decorator is adding it's decorations to.
+     */
+    virtual void GetTargetSize( Vector2& targetSize ) = 0;
+
+    /**
+     * @brief Add a decoration to the parent UI control.
+     *
+     * @param[in] decoration The actor displaying a decoration.
+     */
+    virtual void AddDecoration( Actor& actor, bool needsClipping ) = 0;
+
+    /**
+     * @brief An input event from one of the handles.
+     *
+     * @param[in] handleType The handle's type.
+     * @param[in] state The handle's state.
+     * @param[in] x The x position relative to the top-left of the parent control.
+     * @param[in] y The y position relative to the top-left of the parent control.
+     */
+    virtual void DecorationEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
+  };
+
+  /**
+   * @brief Create a new instance of a Decorator.
+   *
+   * @param[in] controller The controller which receives input events from Decorator components.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   *
+   * @return A pointer to a new Decorator.
+   */
+  static DecoratorPtr New( ControllerInterface& controller,
+                           TextSelectionPopupCallbackInterface& callbackInterface );
+
+  /**
+   * @brief Set the bounding box which handles, popup and similar decorations will not exceed.
+   *
+   * The default value is the width and height of the stage from the top left origin.
+   * If a title bar for example is on the top of the screen then the y should be the title's height and
+   * the boundary height the stage height minus the title's height.
+   * Restrictions - The boundary box should be set up with a fixed z position for the text-input and the default camera.
+   *
+   * ------------------------------------------
+   * |(x,y)                                   |
+   * |o---------------------------------------|
+   * ||                                      ||
+   * ||            Bounding Box              || boundary height
+   * ||                                      ||
+   * |----------------------------------------|
+   * ------------------------------------------
+   *               boundary width
+   *
+   * @param[in] boundingBox Vector( x coordinate, y coordinate, width, height )
+   */
+  void SetBoundingBox( const Rect<int>& boundingBox );
+
+  /**
+   * @brief Retrieve the bounding box origin and dimensions.
+   *
+   * default is set once control is added to stage, before this the return vector will be Vector4:ZERO
+   * @param[out] boundingBox The bounding box origin, width and height.
+   */
+  void GetBoundingBox( Rect<int>& boundingBox ) const;
+
+  /**
+   * @brief The decorator waits until a relayout before creating actors etc.
+   *
+   * @param[in] size The size of the parent control after size-negotiation.
+   */
+  void Relayout( const Dali::Vector2& size );
+
+  /**
+   * @brief Updates the decorator's actor positions after scrolling.
+   *
+   * @param[in] scrollOffset The scroll offset.
+   */
+  void UpdatePositions( const Vector2& scrollOffset );
+
+  /**
+   * @brief Sets which of the cursors are active.
+   *
+   * @note Cursor will only be visible if within the parent area.
+   * @param[in] activeCursor Which of the cursors should be active (if any).
+   */
+  void SetActiveCursor( ActiveCursor activeCursor );
+
+  /**
+   * @brief Query which of the cursors are active.
+   *
+   * @return  Which of the cursors are active (if any).
+   */
+  unsigned int GetActiveCursor() const;
+
+  /**
+   * @brief Sets the position of a cursor.
+   *
+   * @param[in] cursor The cursor to set.
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   * @param[in] cursorHeight The logical height of the cursor.
+   * @param[in] lineHeight The logical height of the line.
+   */
+  void SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight );
+
+  /**
+   * @brief Retrieves the position, height and lineHeight of a cursor.
+   *
+   * @param[in] cursor The cursor to get.
+   * @param[out] x The x position relative to the top-left of the parent control.
+   * @param[out] y The y position relative to the top-left of the parent control.
+   * @param[out] cursorHeight The logical height of the cursor.
+   * @param[out] lineHeight The logical height of the line.
+   */
+  void GetPosition( Cursor cursor, float& x, float& y, float& cursorHeight, float& lineHeight ) const;
+
+  /**
+   * @brief Retrieves the position of a cursor.
+   *
+   * @param[in] cursor The cursor to get.
+   *
+   * @return The position.
+   */
+  const Vector2& GetPosition( Cursor cursor ) const;
+
+
+  /**
+   * @brief Sets the glyph offset of a cursor.
+   *
+   * @param[in] cursor The cursor to set.
+   * @param[in] glyphoffset The difference of line ascender and glyph ascender.
+   */
+  void SetGlyphOffset( Cursor cursor, float glyphOffset );
+
+  /**
+   * @brief Retrieves the glyph offset of a cursor.
+   *
+   * @param[in] cursor The cursor to get.
+   *
+   * @return The glyph offset. glyph offset means difference of line ascender and glyph ascender.
+   */
+  const float GetGlyphOffset( Cursor cursor ) const;
+
+  /**
+   * @brief Sets the color for a cursor.
+   *
+   * @param[in] cursor Whether this color is for the primary or secondary cursor.
+   * @param[in] color The color to use.
+   */
+  void SetCursorColor( Cursor cursor, const Dali::Vector4& color );
+
+  /**
+   * @brief Retrieves the color for a cursor.
+   *
+   * @param[in] cursor Whether this color is for the primary or secondary cursor.
+   * @return The cursor color.
+   */
+  const Dali::Vector4& GetColor( Cursor cursor ) const;
+
+  /**
+   * @brief Start blinking the cursor; see also SetCursorBlinkDuration().
+   */
+  void StartCursorBlink();
+
+  /**
+   * @brief Stop blinking the cursor.
+   */
+  void StopCursorBlink();
+
+  /**
+   * @brief Temporarily stops the cursor from blinking.
+   */
+  void DelayCursorBlink();
+
+  /**
+   * @brief Set the interval between cursor blinks.
+   *
+   * @param[in] seconds The interval in seconds.
+   */
+  void SetCursorBlinkInterval( float seconds );
+
+  /**
+   * @brief Retrieves the blink-interval for a cursor.
+   *
+   * @return The cursor blink-interval in seconds.
+   */
+  float GetCursorBlinkInterval() const;
+
+  /**
+   * @brief The cursor will stop blinking after this duration.
+   *
+   * @param[in] seconds The duration in seconds.
+   */
+  void SetCursorBlinkDuration( float seconds );
+
+  /**
+   * @brief Retrieves the blink-duration for a cursor.
+   *
+   * @return The cursor blink-duration in seconds.
+   */
+  float GetCursorBlinkDuration() const;
+
+  /**
+   * @brief Sets the width of the cursors.
+   *
+   * @param[in] width The width of the cursor in pixels.
+   */
+  void SetCursorWidth( int width );
+
+  /**
+   * @brief Retrieves the width of the cursors.
+   *
+   * @return The width of the cursors in pixels.
+   */
+  int GetCursorWidth() const;
+
+  /**
+   * @brief Sets whether a handle is active.
+   *
+   * @param[in] handleType One of the handles.
+   * @param[in] active True if the handle should be active.
+   */
+  void SetHandleActive( HandleType handleType,
+                        bool active );
+
+  /**
+   * @brief Query whether a handle is active.
+   *
+   * @param[in] handleType One of the handles.
+   *
+   * @return True if the handle is active.
+   */
+  bool IsHandleActive( HandleType handleType ) const;
+
+  /**
+   * @brief Sets the image for one of the handles.
+   *
+   * @param[in] handleType One of the handles.
+   * @param[in] handleImageType A different image can be set for the pressed/released states.
+   * @param[in] image The image to use.
+   */
+  void SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image );
+
+  /**
+   * @brief Retrieves the image for one of the handles.
+   *
+   * @param[in] handleType One of the handles.
+   * @param[in] handleImageType A different image can be set for the pressed/released states.
+   *
+   * @return The grab handle image.
+   */
+  Dali::Image GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const;
+
+  /**
+   * @brief Sets the color of the handles
+   *
+   * @param[in] color The color to use.
+   */
+  void SetHandleColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the handles color.
+   *
+   * @return The color of the handles.
+   */
+  const Vector4& GetHandleColor() const;
+
+  /**
+   * @brief Sets the position of a selection handle.
+   *
+   * @param[in] handleType The handle to set.
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   * @param[in] lineHeight The logical line height at this position.
+   */
+  void SetPosition( HandleType handleType, float x, float y, float lineHeight );
+
+  /**
+   * @brief Retrieves the position of a selection handle.
+   *
+   * @param[in] handleType The handle to get.
+   * @param[out] x The x position relative to the top-left of the parent control.
+   * @param[out] y The y position relative to the top-left of the parent control.
+   * @param[out] lineHeight The logical line height at this position.
+   */
+  void GetPosition( HandleType handleType, float& x, float& y, float& lineHeight ) const;
+
+  /**
+   * @brief Retrieves the position of a selection handle.
+   *
+   * @param[in] handleType The handle to get.
+   *
+   * @return The position of the selection handle relative to the top-left of the parent control.
+   */
+  const Vector2& GetPosition( HandleType handleType ) const;
+
+  /**
+   * @brief Whether to flip vertically a handle.
+   *
+   * @param[in] handleType The handle to flip vertically.
+   * @param[in] flip Whether to flip vertically.
+   */
+  void FlipHandleVertically( HandleType handleType, bool flip );
+
+  /**
+   * @brief Retrieves whether the handle is vertically flipped.
+   *
+   * @param[in] handleType The handle to query.
+   *
+   * @return @e ture if the handle is vertically flipped.
+   */
+  bool IsHandleVerticallyFlipped( HandleType handleType ) const;
+
+  /**
+   * @brief Whether to flip the selection handles as soon as they are crossed.
+   *
+   * By default they flip when the handle is released.
+   *
+   * @param[in] enable If @e true the selection handles will flip as soon as they are crossed.
+   */
+  void FlipSelectionHandlesOnCrossEnabled( bool enable );
+
+  /**
+   * @brief Sets info to calculate the handle flip state.
+   *
+   * Sets the character's direction where the handles are pointing.
+   * It resets the decorator internal flip state when there is a new selection.
+   *
+   * @param[in] indicesSwapped Whether the selection handle indices are swapped (start > end).
+   * @param[in] left The direction of the character pointed by the primary selection handle.
+   * @param[in] right The direction of the character pointed by the secondary selection handle.
+   */
+  void SetSelectionHandleFlipState( bool indicesSwapped, bool left, bool right );
+
+  /**
+   * @brief Adds a quad to the existing selection highlights. Vertices are in decorator's coordinates.
+   *
+   * @param[in] index Position in the vector where to add the quad.
+   * @param[in] quad The quad. The 'x' and 'y' coordinates store the min 'x' and min 'y'. The 'z' and 'w' coordinates store the max 'x' and max 'y'.
+   */
+  void AddHighlight( unsigned int index, const Vector4& quad );
+
+  /**
+   * @brief Sets the min 'x,y' coordinates and the size of the highlighted box.
+   *
+   * It's used to set the size and position of the highlight's actor and to translate each highlight quad from
+   * decorator's coordinates to the local coords of the highlight's actor.
+   *
+   * @param[in] position The position of the highlighted text in decorator's coords.
+   * @param[in] size The size of the highlighted text.
+   * @param[in] outlineOffset The outline's offset.
+   */
+  void SetHighLightBox( const Vector2& position,
+                        const Size& size,
+                        float outlineOffset );
+
+  /**
+   * @brief Removes all of the previously added highlights.
+   */
+  void ClearHighlights();
+
+  /**
+   * @brief Reserves space for the highlight quads.
+   *
+   * @param[in] numberOfQuads The expected number of quads.
+   */
+  void ResizeHighlightQuads( unsigned int numberOfQuads );
+
+  /**
+   * @brief Sets the selection highlight color.
+   *
+   * @param[in] color The color to use.
+   */
+  void SetHighlightColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the selection highlight color.
+   *
+   * @return The color of the highlight
+   */
+  const Vector4& GetHighlightColor() const;
+
+  /**
+   * @brief Sets whether the highlight is active.
+   *
+   * @param[in] active Whether the highlight is active.
+   */
+  void SetHighlightActive( bool active );
+
+  /**
+   * @brief Retrieves whether the highlight is active.
+   *
+   * @return @e true if the highlight is active, @e false otherwise.
+   */
+  bool IsHighlightActive() const;
+
+  /**
+   * @brief Retreives whether the highlight is shown or not.
+   *
+   * @return true if the highlight is visible, false otherwise.
+   */
+  bool IsHighlightVisible() const;
+
+  /**
+   * @brief Sets into the decorator the depth used to render the text.
+   *
+   * @param[in] depth The text's depth.
+   */
+  void SetTextDepth( int textDepth );
+
+  /**
+   * @brief Set the Selection Popup to show or hide via the active flaf
+   * @param[in] active true to show, false to hide
+   */
+  void SetPopupActive( bool active );
+
+  /**
+   * @brief Query whether the Selection Popup is active.
+   *
+   * @return True if the Selection Popup should be active.
+   */
+  bool IsPopupActive() const;
+
+  /**
+   * @brief Set a bit mask of the buttons to be shown by Popup
+   * @param[in] enabledButtonsBitMask from TextSelectionPopup::Buttons enum
+   */
+  void SetEnabledPopupButtons( TextSelectionPopup::Buttons& enabledButtonsBitMask );
+
+  /**
+   * @brief Get the current bit mask of buttons to be shown by Popup
+   * @return bitmask of TextSelectionPopup::Buttons
+   */
+  TextSelectionPopup::Buttons& GetEnabledPopupButtons();
+
+  /**
+   * @brief Sets the scroll threshold.
+   *
+   * It defines a square area inside the control, close to the edge.
+   * When the cursor enters this area, the decorator starts to send scroll events.
+   *
+   * @param[in] threshold The scroll threshold in pixels.
+   */
+  void SetScrollThreshold( float threshold );
+
+  /**
+   * @brief Retrieves the scroll threshold.
+   *
+   * @retunr The scroll threshold in pixels.
+   */
+  float GetScrollThreshold() const;
+
+  /**
+   * @brief Sets the scroll speed.
+   *
+   * Is the distance the text is going to be scrolled during a scroll interval.
+   *
+   * @param[in] speed The scroll speed in pixels/second.
+   */
+  void SetScrollSpeed( float speed );
+
+  /**
+   * @brief Retrieves the scroll speed.
+   *
+   * @return The scroll speed in pixels/second.
+   */
+  float GetScrollSpeed() const;
+
+  /**
+   * @brief Notifies the decorator the whole text has been scrolled.
+   */
+  void NotifyEndOfScroll();
+
+  /**
+   * @copydoc Text::Controller::SetHorizontalScrollEnabled()
+   */
+  void SetHorizontalScrollEnabled( bool enable );
+
+  /**
+   * @copydoc Text::Controller::IsHorizontalScrollEnabled()
+   */
+  bool IsHorizontalScrollEnabled() const;
+
+  /**
+   * @copydoc Text::Controller::SetVerticalScrollEnabled()
+   */
+  void SetVerticalScrollEnabled( bool enable );
+
+  /**
+   * @copydoc Text::Controller::IsVerticalScrollEnabled()
+   */
+  bool IsVerticalScrollEnabled() const;
+
+  /**
+   * @copydoc Text::Controller::SetSmoothHandlePanEnabled()
+   */
+  void SetSmoothHandlePanEnabled( bool enable );
+
+  /**
+   * @copydoc Text::Controller::IsSmoothHandlePanEnabled()
+   */
+  bool IsSmoothHandlePanEnabled() const;
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Decorator();
+
+private:
+
+  /**
+   * @brief Private constructor.
+   * @param[in] controller The controller which receives input events from Decorator components.
+   * @param[in] callbackInterface The text popup callback interface which receives the button click callbacks.
+   */
+  Decorator( ControllerInterface& controller,
+             TextSelectionPopupCallbackInterface& callbackInterface );
+
+  // Undefined
+  Decorator( const Decorator& handle );
+
+  // Undefined
+  Decorator& operator=( const Decorator& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_DECORATOR_H
diff --git a/dali-toolkit/internal/text/embedded-item.h b/dali-toolkit/internal/text/embedded-item.h
new file mode 100755 (executable)
index 0000000..496c207
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H
+#define DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief An embedded item within the text.
+ *
+ * The @e url of the image is optional. If there is no image
+ * the layout engine will use the @e width and @e height to
+ * create a space inside the text. This gap can be filled later.
+ *
+ * A color blending mode can be set. The default is NONE, the
+ * image will use its own color. If MULTIPLY is set, the color
+ * of the image will be multiplied by the color of the text.
+ */
+struct EmbeddedItem
+{
+  CharacterIndex    characterIndex;    ///< The character's index of the embedded item within the string.
+  char*             url;               ///< The url path of the image.
+  Length            urlLength;         ///< The length of the url.
+  unsigned int      width;             ///< The width of the item.
+  unsigned int      height;            ///< The height of the item.
+  ColorBlendingMode colorBlendingMode; ///< Whether the color of the image is multiplied by the color of the text.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H
diff --git a/dali-toolkit/internal/text/font-description-run.h b/dali-toolkit/internal/text/font-description-run.h
new file mode 100644 (file)
index 0000000..b14ab1d
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_TOOLKIT_TEXT_FONT_DESCRIPTION_RUN_H
+#define DALI_TOOLKIT_TEXT_FONT_DESCRIPTION_RUN_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/font-list.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Run of characters with the same font.
+ */
+struct FontDescriptionRun
+{
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  FontDescriptionRun()
+  : characterRun{},
+    familyName{ nullptr },
+    familyLength{ 0u },
+    weight{ FontWeight::NONE },
+    width{ FontWidth::NONE },
+    slant{ FontSlant::NONE },
+    size{ 0u },
+    familyDefined{ false },
+    weightDefined{ false },
+    widthDefined{ false },
+    slantDefined{ false },
+    sizeDefined{ false }
+  {}
+
+  FontDescriptionRun( const CharacterRun& characterRun,
+                      char* familyName,
+                      Length familyLength,
+                      FontWeight weight,
+                      FontWidth width,
+                      FontSlant slant,
+                      PointSize26Dot6 size,
+                      bool familyDefined,
+                      bool weightDefined,
+                      bool widthDefined,
+                      bool slantDefined,
+                      bool sizeDefined )
+  : characterRun{ characterRun },
+    familyName{ familyName },
+    familyLength{ familyLength },
+    weight{ weight },
+    width{ width },
+    slant{ slant },
+    size{ size },
+    familyDefined{ familyDefined },
+    weightDefined{ weightDefined },
+    widthDefined{ widthDefined },
+    slantDefined{ slantDefined },
+    sizeDefined{ sizeDefined }
+  {}
+
+  CharacterRun    characterRun; ///< The initial character index and the number of characters of the run.
+  char*           familyName;   ///< The font's family name.
+  Length          familyLength; ///< The length of the font's family name.
+  FontWeight      weight;       ///< The font's weight.
+  FontWidth       width;        ///< The font's width.
+  FontSlant       slant;        ///< The font's slant.
+  PointSize26Dot6 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.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_FONT_DESCRIPTION_RUN_H
diff --git a/dali-toolkit/internal/text/font-run.h b/dali-toolkit/internal/text/font-run.h
new file mode 100644 (file)
index 0000000..8190fcd
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef DALI_TOOLKIT_TEXT_FONT_RUN_H
+#define DALI_TOOLKIT_TEXT_FONT_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Run of characters with the same font.
+ */
+struct FontRun
+{
+  CharacterRun characterRun;       ///< The initial character index and the number of characters of the run.
+  FontId       fontId;             ///< Font id of the run.
+  bool         isItalicRequired:1; ///< Whether the italic style is required.
+  bool         isBoldRequired:1;   ///< Whether the bold style is required.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_FONT_RUN_H
diff --git a/dali-toolkit/internal/text/glyph-metrics-helper.cpp b/dali-toolkit/internal/text/glyph-metrics-helper.cpp
new file mode 100755 (executable)
index 0000000..b47889e
--- /dev/null
@@ -0,0 +1,110 @@
+
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+Length GetNumberOfGlyphsOfGroup( GlyphIndex glyphIndex,
+                                 GlyphIndex lastGlyphPlusOne,
+                                 const Length* const charactersPerGlyphBuffer )
+{
+  Length numberOfGLyphsInGroup = 1u;
+
+  for( GlyphIndex index = glyphIndex; index < lastGlyphPlusOne; ++index )
+  {
+    if( 0u == *( charactersPerGlyphBuffer + index ) )
+    {
+      ++numberOfGLyphsInGroup;
+    }
+    else
+    {
+      break;
+    }
+  }
+
+  return numberOfGLyphsInGroup;
+}
+
+void GetGlyphsMetrics( GlyphIndex glyphIndex,
+                       Length numberOfGlyphs,
+                       GlyphMetrics& glyphMetrics,
+                       const GlyphInfo* const glyphsBuffer,
+                       MetricsPtr& metrics )
+{
+  const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
+
+  Text::FontMetrics fontMetrics;
+  if( 0u != firstGlyph.fontId )
+  {
+    metrics->GetFontMetrics( firstGlyph.fontId, fontMetrics );
+  }
+  else if( 0u != firstGlyph.index )
+  {
+    // It may be an embedded image.
+    fontMetrics.ascender = firstGlyph.height;
+    fontMetrics.descender = 0.f;
+    fontMetrics.height = fontMetrics.ascender;
+  }
+
+  const bool isItalicFont = metrics->HasItalicStyle( firstGlyph.fontId );
+
+  glyphMetrics.fontId = firstGlyph.fontId;
+  glyphMetrics.fontHeight = fontMetrics.height;
+  glyphMetrics.width = firstGlyph.width;
+  glyphMetrics.advance = firstGlyph.advance;
+  glyphMetrics.ascender = fontMetrics.ascender;
+  glyphMetrics.xBearing = firstGlyph.xBearing;
+
+  if( 1u < numberOfGlyphs )
+  {
+    float  maxWidthEdge = firstGlyph.xBearing + firstGlyph.width;
+
+    for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
+    {
+      const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
+
+      // update the initial xBearing if smaller.
+      glyphMetrics.xBearing = std::min( glyphMetrics.xBearing, glyphMetrics.advance + glyphInfo.xBearing );
+
+      // update the max width edge if bigger.
+      const float currentMaxGlyphWidthEdge = glyphMetrics.advance + glyphInfo.xBearing + glyphInfo.width;
+      maxWidthEdge = std::max( maxWidthEdge, currentMaxGlyphWidthEdge );
+
+      glyphMetrics.advance += glyphInfo.advance;
+    }
+
+    glyphMetrics.width = maxWidthEdge - glyphMetrics.xBearing;
+  }
+
+  glyphMetrics.width += ( firstGlyph.isItalicRequired && !isItalicFont ) ? TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * firstGlyph.height : 0.f;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/glyph-metrics-helper.h b/dali-toolkit/internal/text/glyph-metrics-helper.h
new file mode 100644 (file)
index 0000000..6856d27
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_TOOLKIT_TEXT_GLYPH_METRICS_HELPER_H
+#define DALI_TOOLKIT_TEXT_GLYPH_METRICS_HELPER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/metrics.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Some characters can be shaped in more than one glyph.
+ * This struct is used to retrieve metrics from these group of glyphs.
+ */
+struct GlyphMetrics
+{
+  GlyphMetrics()
+  : fontId( 0u ),
+    fontHeight( 0.f ),
+    width( 0.f ),
+    advance( 0.f ),
+    ascender( 0.f ),
+    xBearing( 0.f )
+  {}
+
+  ~GlyphMetrics()
+  {}
+
+  FontId fontId;     ///< The font id of the glyphs.
+  float  fontHeight; ///< The font's height of those glyphs.
+  float  width;      ///< The width of the group.
+  float  advance;    ///< The sum of all the advances of all the glyphs.
+  float  ascender;   ///< The font's ascender.
+  float  xBearing;   ///< The x bearing of the group.
+};
+
+/**
+ * @brief Returns the number of glyphs of a group of glyphs.
+ *
+ * @param[in] glyphIndex The first glyph of the group.
+ * @param[in] lastGlyphPlusOne Index to one after the last glyph.
+ * @param[in] charactersPerGlyphBuffer The number of characters per glyph buffer.
+ *
+ * @return The number of glyphs of the group.
+ */
+Length GetNumberOfGlyphsOfGroup( GlyphIndex glyphIndex,
+                                 GlyphIndex lastGlyphPlusOne,
+                                 const Length* const charactersPerGlyphBuffer );
+
+/**
+ * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
+ *
+ * @param[in] glyphIndex The index to the first glyph.
+ * @param[in] numberOfGlyphs The number of glyphs.
+ * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
+ * @param[in] glyphsBuffer The glyphs buffer.
+ * @param[in] metrics Used to access metrics from FontClient.
+ */
+void GetGlyphsMetrics( GlyphIndex glyphIndex,
+                       Length numberOfGlyphs,
+                       GlyphMetrics& glyphMetrics,
+                       const GlyphInfo* const glyphsBuffer,
+                       MetricsPtr& metrics );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_GLYPH_METRICS_HELPER_H
diff --git a/dali-toolkit/internal/text/glyph-run.h b/dali-toolkit/internal/text/glyph-run.h
new file mode 100644 (file)
index 0000000..9524f01
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef DALI_TOOLKIT_TEXT_GLYPH_RUN_H
+#define DALI_TOOLKIT_TEXT_GLYPH_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A run of consecutive glyphs.
+ */
+struct GlyphRun
+{
+  GlyphIndex glyphIndex;     ///< Index to the first glyph.
+  Length     numberOfGlyphs; ///< Number of glyphs in the run.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_GLYPH_RUN_H
diff --git a/dali-toolkit/internal/text/hidden-text.cpp b/dali-toolkit/internal/text/hidden-text.cpp
new file mode 100644 (file)
index 0000000..0dc8b9e
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/text/hidden-text.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+
+using namespace Dali::Toolkit;
+
+const uint32_t STAR = 0x2A;   // Set default substitute character as '*'
+const int DEFAULT_SHOW_DURATION = 1000;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+const char * const PROPERTY_MODE                      = "mode";
+const char * const PROPERTY_SUBSTITUTE_CHARACTER      = "substituteCharacter";
+const char * const PROPERTY_SUBSTITUTE_COUNT          = "substituteCount";
+const char * const PROPERTY_SHOW_DURATION             = "showDuration";
+
+HiddenText::HiddenText( Observer* observer )
+: mObserver( observer ),
+  mHideMode( static_cast< int >( Toolkit::HiddenInput::Mode::HIDE_NONE ) ),
+  mSubstituteText( STAR ),
+  mDisplayDuration( DEFAULT_SHOW_DURATION ),
+  mSubstituteCount( 0 ),
+  mPreviousTextCount( 0 )
+{
+  mTimer = Timer::New( mDisplayDuration );
+  mTimer.TickSignal().Connect( this, &HiddenText::OnTick );
+}
+
+void HiddenText::SetProperties( const Property::Map& map )
+{
+    const Property::Map::SizeType count = map.Count();
+
+    for ( Property::Map::SizeType position = 0; position < count; ++position )
+    {
+      KeyValuePair keyValue = map.GetKeyValue( position );
+      Property::Key& key = keyValue.first;
+      Property::Value& value = keyValue.second;
+
+      if( key == Toolkit::HiddenInput::Property::MODE || key == PROPERTY_MODE )
+      {
+        value.Get( mHideMode );
+      }
+      else if( key == Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER || key == PROPERTY_SUBSTITUTE_CHARACTER )
+      {
+        value.Get( mSubstituteText );
+      }
+      else if( key == Toolkit::HiddenInput::Property::SUBSTITUTE_COUNT || key == PROPERTY_SUBSTITUTE_COUNT )
+      {
+        value.Get( mSubstituteCount );
+      }
+      else if( key == Toolkit::HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION || key == PROPERTY_SHOW_DURATION )
+      {
+        value.Get( mDisplayDuration );
+      }
+    }
+}
+
+void HiddenText::GetProperties( Property::Map& map )
+{
+  map[Toolkit::HiddenInput::Property::MODE] = mHideMode;
+  map[Toolkit::HiddenInput::Property::SUBSTITUTE_CHARACTER] = mSubstituteText;
+  map[Toolkit::HiddenInput::Property::SUBSTITUTE_COUNT] = mSubstituteCount;
+  map[Toolkit::HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION] = mDisplayDuration;
+}
+
+void HiddenText::Substitute( const Vector<Character>& source, Vector<Character>& destination )
+{
+  const Length characterCount = source.Count();
+
+  destination.Resize( characterCount );
+
+  uint32_t* begin = destination.Begin();
+  uint32_t* end = begin + characterCount;
+  uint32_t* hideStart = NULL;
+  uint32_t* hideEnd = NULL;
+  uint32_t* sourcePos = source.Begin();
+
+  switch ( mHideMode )
+  {
+    case Toolkit::HiddenInput::Mode::HIDE_NONE:
+    {
+      hideStart = NULL;
+      hideEnd = NULL;
+      break;
+    }
+    case Toolkit::HiddenInput::Mode::HIDE_ALL:
+    {
+      hideStart = begin;
+      hideEnd = end;
+      break;
+    }
+    case Toolkit::HiddenInput::Mode::HIDE_COUNT:
+    {
+      hideStart = begin;
+      hideEnd = begin + mSubstituteCount;
+      break;
+    }
+    case Toolkit::HiddenInput::Mode::SHOW_COUNT:
+    {
+      hideStart = begin + mSubstituteCount;
+      hideEnd = end;
+      break;
+    }
+    case Toolkit::HiddenInput::Mode::SHOW_LAST_CHARACTER:
+    {
+      if (mPreviousTextCount < characterCount)
+      {
+        hideStart = begin;
+        hideEnd = end-1;
+        if ( mDisplayDuration > 0 )
+        {
+          mTimer.SetInterval( mDisplayDuration );
+          mTimer.Start();
+        }
+        else
+        {
+          OnTick();
+        }
+      }
+      else
+      {
+        hideStart = begin;
+        hideEnd = end;
+      }
+      break;
+    }
+  }
+  for (; begin < end; ++begin )
+  {
+    if (begin >= hideStart && begin < hideEnd)
+    {
+      *begin = static_cast<uint32_t>(mSubstituteText);
+      sourcePos++;
+    }
+    else
+    {
+      *begin = *sourcePos++;
+    }
+  }
+  mPreviousTextCount = characterCount;
+}
+
+bool HiddenText::OnTick()
+{
+  if( mObserver != NULL )
+  {
+    mObserver->DisplayTimeExpired();
+  }
+
+  return false;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/hidden-text.h b/dali-toolkit/internal/text/hidden-text.h
new file mode 100644 (file)
index 0000000..2480a4e
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_HIDDEN_TEXT_H
+#define DALI_HIDDEN_TEXT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * Class to handle the hidden text
+ */
+class HiddenText : public ConnectionTracker
+{
+public:
+  class Observer
+  {
+  public:
+
+    /**
+     * @brief Invoked when the time to show last character is expired
+     */
+    virtual void DisplayTimeExpired() = 0;
+  };
+
+  /**
+   * @brief Constructor
+   * @param[in] observer The Observer pointer.
+   */
+  HiddenText( Observer* observer );
+
+public: // Intended for internal use
+
+  /**
+   * @brief Used to set options of hidden text
+   * @param[in] map The property map describing the option
+   */
+  void SetProperties( const Property::Map& map );
+
+  /**
+   * @brief Retrieve property map of hidden text options
+   * @param[out] map The hidden text option
+   */
+  void GetProperties( Property::Map& map );
+
+  /**
+   * @brief Convert source text to destination text according to current option
+   * @param[in] source The original text
+   * @param[out] destination The applied text
+   */
+  void Substitute( const Vector<Character>& source, Vector<Character>& destination );
+
+  /**
+   * @brief Invoked when the timer is expired
+   */
+  bool OnTick();
+
+private:
+
+  Timer mTimer;
+  Observer* mObserver;
+  int mHideMode;
+  int mSubstituteText;
+  int mDisplayDuration;
+  int mSubstituteCount;
+  Length mPreviousTextCount;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_HIDDEN_TEXT_H
diff --git a/dali-toolkit/internal/text/input-style.h b/dali-toolkit/internal/text/input-style.h
new file mode 100644 (file)
index 0000000..0a10d90
--- /dev/null
@@ -0,0 +1,248 @@
+#ifndef DALI_TOOLKIT_TEXT_INPUT_STYLE_H
+#define DALI_TOOLKIT_TEXT_INPUT_STYLE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/constants.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * The input text's style.
+ */
+struct InputStyle
+{
+  enum Mask
+  {
+    NONE               = 0x0000,
+    INPUT_COLOR        = 0x0001,
+    INPUT_FONT_FAMILY  = 0x0002,
+    INPUT_POINT_SIZE   = 0x0004,
+    INPUT_FONT_WEIGHT  = 0x0008,
+    INPUT_FONT_WIDTH   = 0x0010,
+    INPUT_FONT_SLANT   = 0x0020,
+    INPUT_LINE_SPACING = 0x0040,
+    INPUT_UNDERLINE    = 0x0080,
+    INPUT_SHADOW       = 0x0100,
+    INPUT_EMBOSS       = 0x0200,
+    INPUT_OUTLINE      = 0x0400
+  };
+
+  InputStyle()
+  : textColor( Color::BLACK ),
+    familyName(),
+    weight( TextAbstraction::FontWeight::NORMAL ),
+    width( TextAbstraction::FontWidth::NORMAL ),
+    slant( TextAbstraction::FontSlant::NORMAL ),
+    size( 0.f ),
+    lineSpacing( 0.f ),
+    underlineProperties(),
+    shadowProperties(),
+    embossProperties(),
+    outlineProperties(),
+    isDefaultColor( true ),
+    isFamilyDefined( false ),
+    isWeightDefined( false ),
+    isWidthDefined( false ),
+    isSlantDefined( false ),
+    isSizeDefined( false ),
+    isLineSpacingDefined( false ),
+    isUnderlineDefined( false ),
+    isShadowDefined( false ),
+    isEmbossDefined( false ),
+    isOutlineDefined( false )
+    {}
+
+  ~InputStyle()
+  {};
+
+  /**
+   * @brief
+   *
+   * Does not copy the font-style, underline, shadow, emboss and outline property strings.
+   */
+  void Copy( const InputStyle& inputStyle )
+  {
+    isDefaultColor = inputStyle.isDefaultColor;
+    textColor = inputStyle.textColor;
+
+    isFamilyDefined = inputStyle.isFamilyDefined;
+    familyName = inputStyle.familyName;
+
+    isWeightDefined = inputStyle.isWeightDefined;
+    weight = inputStyle.weight;
+
+    isWidthDefined = inputStyle.isWidthDefined;
+    width = inputStyle.width;
+
+    isSlantDefined = inputStyle.isSlantDefined;
+    slant = inputStyle.slant;
+
+    isSizeDefined = inputStyle.isSizeDefined;
+    size = inputStyle.size;
+
+    isLineSpacingDefined = inputStyle.isLineSpacingDefined;
+    lineSpacing = inputStyle.lineSpacing;
+
+    isUnderlineDefined = inputStyle.isUnderlineDefined;
+    underlineProperties = inputStyle.underlineProperties;
+
+    isShadowDefined = inputStyle.isShadowDefined;
+    shadowProperties = inputStyle.shadowProperties;
+
+    isEmbossDefined = inputStyle.isEmbossDefined;
+    embossProperties = inputStyle.embossProperties;
+
+    isOutlineDefined = inputStyle.isOutlineDefined;
+    outlineProperties = inputStyle.outlineProperties;
+  }
+
+  /**
+   * @brief
+   *
+   * Does not compare the font-style, underline, shadow, emboss and outline property strings.
+   */
+  bool Equal( const InputStyle& inputStyle ) const
+  {
+    if( ( isDefaultColor != inputStyle.isDefaultColor )             ||
+        ( isFamilyDefined != inputStyle.isFamilyDefined )           ||
+        ( isWeightDefined != inputStyle.isWeightDefined )           ||
+        ( isWidthDefined != inputStyle.isWidthDefined )             ||
+        ( isSlantDefined != inputStyle.isSlantDefined )             ||
+        ( isSizeDefined != inputStyle.isSizeDefined )               ||
+        ( isLineSpacingDefined != inputStyle.isLineSpacingDefined ) ||
+        ( isUnderlineDefined != inputStyle.isUnderlineDefined )     ||
+        ( isShadowDefined != inputStyle.isShadowDefined )           ||
+        ( isEmbossDefined != inputStyle.isEmbossDefined )           ||
+        ( isOutlineDefined != inputStyle.isOutlineDefined )         ||
+        ( textColor != inputStyle.textColor )                       ||
+        ( familyName != inputStyle.familyName )                     ||
+        ( weight != inputStyle.weight )                             ||
+        ( width != inputStyle.width )                               ||
+        ( slant != inputStyle.slant )                               ||
+        ( size != inputStyle.size )                                 ||
+        ( lineSpacing != inputStyle.lineSpacing )                   ||
+        ( underlineProperties != inputStyle.underlineProperties )   ||
+        ( shadowProperties != inputStyle.shadowProperties )         ||
+        ( embossProperties != inputStyle.embossProperties )         ||
+        ( outlineProperties != inputStyle.outlineProperties ) )
+    {
+      return false;
+    }
+
+    return true;
+  }
+
+  Mask GetInputStyleChangeMask( const InputStyle& inputStyle ) const
+  {
+    Mask mask = NONE;
+
+    if( textColor != inputStyle.textColor )
+    {
+      mask = static_cast<Mask>( mask | INPUT_COLOR );
+    }
+    if( familyName != inputStyle.familyName )
+    {
+      mask = static_cast<Mask>( mask | INPUT_FONT_FAMILY );
+    }
+    if( weight != inputStyle.weight )
+    {
+      mask = static_cast<Mask>( mask | INPUT_FONT_WEIGHT );
+    }
+    if( width != inputStyle.width )
+    {
+      mask = static_cast<Mask>( mask | INPUT_FONT_WIDTH );
+    }
+    if( slant != inputStyle.slant )
+    {
+      mask = static_cast<Mask>( mask | INPUT_FONT_SLANT );
+    }
+    if( size != inputStyle.size )
+    {
+      mask = static_cast<Mask>( mask | INPUT_POINT_SIZE );
+    }
+    if( lineSpacing != inputStyle.lineSpacing )
+    {
+      mask = static_cast<Mask>( mask | INPUT_LINE_SPACING );
+    }
+    if( underlineProperties != inputStyle.underlineProperties )
+    {
+      mask = static_cast<Mask>( mask | INPUT_UNDERLINE );
+    }
+    if( shadowProperties != inputStyle.shadowProperties )
+    {
+      mask = static_cast<Mask>( mask | INPUT_SHADOW );
+    }
+    if( embossProperties != inputStyle.embossProperties )
+    {
+      mask = static_cast<Mask>( mask | INPUT_EMBOSS );
+    }
+    if( outlineProperties != inputStyle.outlineProperties )
+    {
+      mask = static_cast<Mask>( mask | INPUT_OUTLINE );
+    }
+
+    return mask;
+  }
+
+  Vector4     textColor;           ///< The text's color.
+  std::string familyName;          ///< The font's family name.
+  FontWeight  weight;              ///< The font's weight.
+  FontWidth   width;               ///< The font's width.
+  FontSlant   slant;               ///< The font's slant.
+  float       size;                ///< The font's size.
+
+  float       lineSpacing;         ///< The line's spacing.
+
+  std::string underlineProperties; ///< The underline properties string.
+  std::string shadowProperties;    ///< The shadow properties string.
+  std::string embossProperties;    ///< The emboss properties string.
+  std::string outlineProperties;   ///< The outline properties string.
+
+  bool        isDefaultColor       : 1; ///< Whether the text's color is the default.
+  bool        isFamilyDefined      : 1; ///< Whether the font's family is defined.
+  bool        isWeightDefined      : 1; ///< Whether the font's weight is defined.
+  bool        isWidthDefined       : 1; ///< Whether the font's width is defined.
+  bool        isSlantDefined       : 1; ///< Whether the font's slant is defined.
+  bool        isSizeDefined        : 1; ///< Whether the font's size is defined.
+
+  bool        isLineSpacingDefined : 1; ///< Whether the line spacing is defined.
+  bool        isUnderlineDefined   : 1; ///< Whether the underline parameters are defined.
+  bool        isShadowDefined      : 1; ///< Whether the shadow parameters are defined.
+  bool        isEmbossDefined      : 1; ///< Whether the emboss parameters are defined.
+  bool        isOutlineDefined     : 1; ///< Whether the outline parameters are defined.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_INPUT_STYLE_H
diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp
new file mode 100755 (executable)
index 0000000..e91ebae
--- /dev/null
@@ -0,0 +1,1641 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/text/layouts/layout-engine.h>
+
+// EXTERNAL INCLUDES
+#include <limits>
+#include <cmath>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Layout
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
+#endif
+
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+const CharacterDirection LTR = false;
+const CharacterDirection RTL = !LTR;
+const float LINE_SPACING= 0.f;
+
+inline bool isEmptyLineAtLast( const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line )
+{
+  return ( (*line).characterRun.numberOfCharacters == 0 && line + 1u == lines.End() );
+}
+
+} //namespace
+
+/**
+ * @brief Stores temporary layout info of the line.
+ */
+struct LineLayout
+{
+  LineLayout()
+  : glyphIndex{ 0u },
+    characterIndex{ 0u },
+    numberOfGlyphs{ 0u },
+    numberOfCharacters{ 0u },
+    ascender{ -MAX_FLOAT },
+    descender{ MAX_FLOAT },
+    lineSpacing{ 0.f },
+    penX{ 0.f },
+    previousAdvance{ 0.f },
+    length{ 0.f },
+    whiteSpaceLengthEndOfLine{ 0.f },
+    direction{ LTR }
+  {}
+
+  ~LineLayout()
+  {}
+
+  void Clear()
+  {
+    glyphIndex = 0u;
+    characterIndex = 0u;
+    numberOfGlyphs = 0u;
+    numberOfCharacters = 0u;
+    ascender = -MAX_FLOAT;
+    descender = MAX_FLOAT;
+    direction = LTR;
+  }
+
+  GlyphIndex         glyphIndex;                ///< Index of the first glyph to be laid-out.
+  CharacterIndex     characterIndex;            ///< Index of the first character to be laid-out.
+  Length             numberOfGlyphs;            ///< The number of glyph which fit in one line.
+  Length             numberOfCharacters;        ///< The number of characters which fit in one line.
+  float              ascender;                  ///< The maximum ascender of all fonts in the line.
+  float              descender;                 ///< The minimum descender of all fonts in the line.
+  float              lineSpacing;               ///< The line spacing
+  float              penX;                      ///< The origin of the current glyph ( is the start point plus the accumulation of all advances ).
+  float              previousAdvance;           ///< The advance of the previous glyph.
+  float              length;                    ///< The current length of the line.
+  float              whiteSpaceLengthEndOfLine; ///< The length of the white spaces at the end of the line.
+  CharacterDirection direction;
+};
+
+struct LayoutBidiParameters
+{
+  void Clear()
+  {
+    paragraphDirection = LTR;
+    bidiParagraphIndex = 0u;
+    bidiLineIndex = 0u;
+    isBidirectional = false;
+  }
+
+  CharacterDirection paragraphDirection = LTR;   ///< The paragraph's direction.
+  BidirectionalRunIndex bidiParagraphIndex = 0u; ///< Index to the paragraph's bidi info.
+  BidirectionalLineRunIndex bidiLineIndex = 0u;  ///< Index where to insert the next bidi line info.
+  bool isBidirectional = false;                  ///< Whether the text is bidirectional.
+};
+
+struct Engine::Impl
+{
+  Impl()
+  : mLayout{ Layout::Engine::SINGLE_LINE_BOX },
+    mCursorWidth{ 0.f },
+    mDefaultLineSpacing{ LINE_SPACING }
+  {
+  }
+
+  /**
+   * @brief Updates the line ascender and descender with the metrics of a new font.
+   *
+   * @param[in] glyphMetrics The metrics of the new font.
+   * @param[in,out] lineLayout The line layout.
+   */
+  void UpdateLineHeight( const GlyphMetrics& glyphMetrics, LineLayout& lineLayout )
+  {
+    Text::FontMetrics fontMetrics;
+    if( 0u != glyphMetrics.fontId )
+    {
+      mMetrics->GetFontMetrics( glyphMetrics.fontId, fontMetrics );
+    }
+    else
+    {
+      fontMetrics.ascender = glyphMetrics.fontHeight;
+      fontMetrics.descender = 0.f;
+      fontMetrics.height = fontMetrics.ascender;
+      fontMetrics.underlinePosition = 0.f;
+      fontMetrics.underlineThickness = 1.f;
+    }
+
+    // Sets the maximum ascender.
+    lineLayout.ascender = std::max( lineLayout.ascender, fontMetrics.ascender );
+
+    // Sets the minimum descender.
+    lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender );
+
+    // set the line spacing
+    lineLayout.lineSpacing = mDefaultLineSpacing;
+  }
+
+  /**
+   * @brief Merges a temporary line layout into the line layout.
+   *
+   * @param[in,out] lineLayout The line layout.
+   * @param[in] tmpLineLayout A temporary line layout.
+   */
+  void MergeLineLayout( LineLayout& lineLayout,
+                        const LineLayout& tmpLineLayout )
+  {
+    lineLayout.numberOfCharacters += tmpLineLayout.numberOfCharacters;
+    lineLayout.numberOfGlyphs += tmpLineLayout.numberOfGlyphs;
+
+    lineLayout.penX = tmpLineLayout.penX;
+    lineLayout.previousAdvance = tmpLineLayout.previousAdvance;
+
+    lineLayout.length = tmpLineLayout.length;
+    lineLayout.whiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
+
+    // Sets the maximum ascender.
+    lineLayout.ascender = std::max( lineLayout.ascender, tmpLineLayout.ascender );
+
+    // Sets the minimum descender.
+    lineLayout.descender = std::min( lineLayout.descender, tmpLineLayout.descender );
+  }
+
+  void LayoutRightToLeft( const Parameters& parameters,
+                          const BidirectionalLineInfoRun& bidirectionalLineInfo,
+                          float& length,
+                          float& whiteSpaceLengthEndOfLine )
+  {
+    const Character* const textBuffer = parameters.textModel->mLogicalModel->mText.Begin();
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+    const GlyphInfo* const glyphsBuffer = parameters.textModel->mVisualModel->mGlyphs.Begin();
+    const GlyphIndex* const charactersToGlyphsBuffer = parameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
+
+    const float outlineWidth = static_cast<float>( parameters.textModel->GetOutlineWidth() );
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+    CharacterIndex characterLogicalIndex = 0u;
+    CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+
+    if( RTL == bidirectionalLineInfo.direction )
+    {
+      while( TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) ) )
+      {
+        const GlyphInfo& glyphInfo = *( glyphsBuffer + *( charactersToGlyphsBuffer + characterVisualIndex ) );
+
+        whiteSpaceLengthEndOfLine += glyphInfo.advance;
+
+        ++characterLogicalIndex;
+        characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+      }
+    }
+
+    const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+    // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
+    const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                   lastGlyphOfParagraphPlusOne,
+                                                                   charactersPerGlyphBuffer );
+
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( glyphIndex,
+                      numberOfGLyphsInGroup,
+                      glyphMetrics,
+                      glyphsBuffer,
+                      mMetrics );
+
+    float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+
+    // Traverses the characters of the right to left paragraph.
+    for( ; characterLogicalIndex < bidirectionalLineInfo.characterRun.numberOfCharacters; )
+    {
+      // Convert the character in the logical order into the character in the visual order.
+      const CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+      const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) );
+
+      const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+      // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+      const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                     lastGlyphOfParagraphPlusOne,
+                                                                     charactersPerGlyphBuffer );
+
+      characterLogicalIndex += *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( glyphIndex,
+                        numberOfGLyphsInGroup,
+                        glyphMetrics,
+                        glyphsBuffer,
+                        mMetrics );
+
+      if( isWhiteSpace )
+      {
+        if( RTL == bidirectionalLineInfo.direction )
+        {
+          length += glyphMetrics.advance;
+        }
+        else
+        {
+          whiteSpaceLengthEndOfLine += glyphMetrics.advance;
+        }
+        penX += glyphMetrics.advance;
+      }
+      else
+      {
+        if( LTR == bidirectionalLineInfo.direction )
+        {
+          whiteSpaceLengthEndOfLine = 0.f;
+        }
+        length = std::max( length, penX + glyphMetrics.xBearing + glyphMetrics.width );
+        penX += ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
+      }
+    }
+  }
+
+  void ReorderBiDiLayout( const Parameters& parameters,
+                          LayoutBidiParameters& bidiParameters,
+                          const LineLayout& currentLineLayout,
+                          LineLayout& lineLayout,
+                          bool breakInCharacters )
+  {
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+
+    // The last glyph to be laid-out.
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+    const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = parameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
+
+    const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo = bidirectionalParagraphsInfo[bidiParameters.bidiParagraphIndex];
+    if( ( lineLayout.characterIndex >= bidirectionalParagraphInfo.characterRun.characterIndex ) &&
+        ( lineLayout.characterIndex < bidirectionalParagraphInfo.characterRun.characterIndex + bidirectionalParagraphInfo.characterRun.numberOfCharacters ) )
+    {
+      Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+      // Sets the visual to logical map tables needed to reorder the text.
+      ReorderLine( bidirectionalParagraphInfo,
+                   bidirectionalLinesInfo,
+                   bidiParameters.bidiLineIndex,
+                   lineLayout.characterIndex,
+                   lineLayout.numberOfCharacters,
+                   bidiParameters.paragraphDirection );
+
+      // Recalculate the length of the line and update the layout.
+      const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+      if( !bidirectionalLineInfo.isIdentity )
+      {
+        float length = 0.f;
+        float whiteSpaceLengthEndOfLine = 0.f;
+        LayoutRightToLeft( parameters,
+                           bidirectionalLineInfo,
+                           length,
+                           whiteSpaceLengthEndOfLine );
+
+        lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+        if( !Equals( length, lineLayout.length ) )
+        {
+          const bool isMultiline = mLayout == MULTI_LINE_BOX;
+
+          if( isMultiline && ( length > parameters.boundingBox.width ) )
+          {
+            if( breakInCharacters || ( isMultiline && ( 0u == currentLineLayout.numberOfGlyphs ) ) )
+            {
+              // The word doesn't fit in one line. It has to be split by character.
+
+              // Remove the last laid out glyph(s) as they doesn't fit.
+              for( GlyphIndex glyphIndex = lineLayout.glyphIndex + lineLayout.numberOfGlyphs - 1u; glyphIndex >= lineLayout.glyphIndex; )
+              {
+                const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                               lastGlyphOfParagraphPlusOne,
+                                                                               charactersPerGlyphBuffer );
+
+                const Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+                lineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+                lineLayout.numberOfCharacters -= numberOfCharacters;
+
+                AdjustLayout( parameters,
+                              bidiParameters,
+                              bidirectionalParagraphInfo,
+                              lineLayout );
+
+                if( lineLayout.length < parameters.boundingBox.width )
+                {
+                  break;
+                }
+
+                if( glyphIndex < numberOfGLyphsInGroup )
+                {
+                  // avoids go under zero for an unsigned int.
+                  break;
+                }
+
+                glyphIndex -= numberOfGLyphsInGroup;
+              }
+            }
+            else
+            {
+              lineLayout  = currentLineLayout;
+
+              AdjustLayout( parameters,
+                            bidiParameters,
+                            bidirectionalParagraphInfo,
+                            lineLayout );
+            }
+          }
+          else
+          {
+            lineLayout.length = std::max( length, lineLayout.length );
+          }
+        }
+      }
+    }
+  }
+
+  void AdjustLayout( const Parameters& parameters,
+                     LayoutBidiParameters& bidiParameters,
+                     const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
+                     LineLayout& lineLayout )
+  {
+    Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+    // Remove current reordered line.
+    bidirectionalLinesInfo.Erase( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+    // Re-build the conversion table without the removed glyphs.
+    ReorderLine( bidirectionalParagraphInfo,
+                 bidirectionalLinesInfo,
+                 bidiParameters.bidiLineIndex,
+                 lineLayout.characterIndex,
+                 lineLayout.numberOfCharacters,
+                 bidiParameters.paragraphDirection );
+
+    const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+    float length = 0.f;
+    float whiteSpaceLengthEndOfLine = 0.f;
+    LayoutRightToLeft( parameters,
+                       bidirectionalLineInfo,
+                       length,
+                       whiteSpaceLengthEndOfLine );
+
+    lineLayout.length = length;
+    lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+  }
+
+  /**
+   * Retrieves the line layout for a given box width.
+   *
+   * @note This method starts to layout text as if it was left to right. However, it might be differences in the length
+   *       of the line if it's a bidirectional one. If the paragraph is bidirectional, this method will call a function
+   *       to reorder the line and recalculate its length.
+   *
+
+   * @param[in] parameters The layout parameters.
+   * @param[] bidiParameters Bidirectional info for the current line.
+   * @param[out] lineLayout The line layout.
+   * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
+   */
+  void GetLineLayoutForBox( const Parameters& parameters,
+                            LayoutBidiParameters& bidiParameters,
+                            LineLayout& lineLayout,
+                            bool completelyFill )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex );
+
+    const Character* const textBuffer = parameters.textModel->mLogicalModel->mText.Begin();
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+    const GlyphInfo* const glyphsBuffer = parameters.textModel->mVisualModel->mGlyphs.Begin();
+    const CharacterIndex* const glyphsToCharactersBuffer = parameters.textModel->mVisualModel->mGlyphsToCharacters.Begin();
+    const LineBreakInfo* const lineBreakInfoBuffer = parameters.textModel->mLogicalModel->mLineBreakInfo.Begin();
+
+    const float outlineWidth = static_cast<float>( parameters.textModel->GetOutlineWidth() );
+    const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
+
+    const bool isMultiline = mLayout == MULTI_LINE_BOX;
+    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
+
+    // The last glyph to be laid-out.
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+    // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
+    // In the case the line starts with a right to left character, if the width is longer than the advance,
+    // the difference needs to be added to the line length.
+
+    // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
+    const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( lineLayout.glyphIndex,
+                                                                   lastGlyphOfParagraphPlusOne,
+                                                                   charactersPerGlyphBuffer );
+
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( lineLayout.glyphIndex,
+                      numberOfGLyphsInGroup,
+                      glyphMetrics,
+                      glyphsBuffer,
+                      mMetrics );
+
+    // Set the direction of the first character of the line.
+    lineLayout.characterIndex = *( glyphsToCharactersBuffer + lineLayout.glyphIndex );
+
+    // Stores temporary line layout which has not been added to the final line layout.
+    LineLayout tmpLineLayout;
+
+    // Initialize the start point.
+
+    // The initial start point is zero. However it needs a correction according the 'x' bearing of the first glyph.
+    // i.e. if the bearing of the first glyph is negative it may exceed the boundaries of the text area.
+    // It needs to add as well space for the cursor if the text is in edit mode and extra space in case the text is outlined.
+    tmpLineLayout.penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+
+    // Calculate the line height if there is no characters.
+    FontId lastFontId = glyphMetrics.fontId;
+    UpdateLineHeight( glyphMetrics, tmpLineLayout );
+
+    bool oneWordLaidOut = false;
+
+    for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
+         glyphIndex < lastGlyphOfParagraphPlusOne; )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  glyph index : %d\n", glyphIndex );
+
+      // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+      const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                     lastGlyphOfParagraphPlusOne,
+                                                                     charactersPerGlyphBuffer );
+
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( glyphIndex,
+                        numberOfGLyphsInGroup,
+                        glyphMetrics,
+                        glyphsBuffer,
+                        mMetrics );
+
+      const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == totalNumberOfGlyphs;
+
+      // Check if the font of the current glyph is the same of the previous one.
+      // If it's different the ascender and descender need to be updated.
+      if( lastFontId != glyphMetrics.fontId )
+      {
+        UpdateLineHeight( glyphMetrics, tmpLineLayout );
+        lastFontId = glyphMetrics.fontId;
+      }
+
+      // Get the character indices for the current glyph. The last character index is needed
+      // because there are glyphs formed by more than one character but their break info is
+      // given only for the last character.
+      const Length charactersPerGlyph = *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+      const bool hasCharacters = charactersPerGlyph > 0u;
+      const CharacterIndex characterFirstIndex = *( glyphsToCharactersBuffer + glyphIndex );
+      const CharacterIndex characterLastIndex = characterFirstIndex + ( hasCharacters ? charactersPerGlyph - 1u : 0u );
+
+      // Get the line break info for the current character.
+      const LineBreakInfo lineBreakInfo = hasCharacters ? *( lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
+
+      // Increase the number of characters.
+      tmpLineLayout.numberOfCharacters += charactersPerGlyph;
+
+      // Increase the number of glyphs.
+      tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
+
+      // Check whether is a white space.
+      const Character character = *( textBuffer + characterFirstIndex );
+      const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( character );
+
+      // Calculate the length of the line.
+
+      // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
+      const float previousTmpPenX = tmpLineLayout.penX;
+      const float previousTmpAdvance = tmpLineLayout.previousAdvance;
+      const float previousTmpLength = tmpLineLayout.length;
+      const float previousTmpWhiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
+
+      if( isWhiteSpace )
+      {
+        // Add the length to the length of white spaces at the end of the line.
+        tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
+      }
+      else
+      {
+        tmpLineLayout.penX += tmpLineLayout.previousAdvance + tmpLineLayout.whiteSpaceLengthEndOfLine;
+        tmpLineLayout.previousAdvance = ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
+
+        tmpLineLayout.length = std::max( tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width );
+
+        // Clear the white space length at the end of the line.
+        tmpLineLayout.whiteSpaceLengthEndOfLine = 0.f;
+      }
+
+      // Check if the accumulated length fits in the width of the box.
+      if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
+          ( tmpLineLayout.length > parameters.boundingBox.width ) )
+      {
+        // Current word does not fit in the box's width.
+        if( !oneWordLaidOut || completelyFill )
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Break the word by character\n" );
+
+          // The word doesn't fit in the control's width. It needs to be split by character.
+          if( tmpLineLayout.numberOfGlyphs > 0u )
+          {
+            tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
+            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+
+            tmpLineLayout.penX = previousTmpPenX;
+            tmpLineLayout.previousAdvance = previousTmpAdvance;
+            tmpLineLayout.length = previousTmpLength;
+            tmpLineLayout.whiteSpaceLengthEndOfLine = previousTmpWhiteSpaceLengthEndOfLine;
+          }
+
+          // Add part of the word to the line layout.
+          MergeLineLayout( lineLayout, tmpLineLayout );
+        }
+        else
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Current word does not fit.\n" );
+        }
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox.\n" );
+
+        // Reorder the RTL line.
+        if( bidiParameters.isBidirectional )
+        {
+          ReorderBiDiLayout( parameters,
+                             bidiParameters,
+                             lineLayout,
+                             lineLayout,
+                             true );
+        }
+
+        return;
+      }
+
+      if( ( isMultiline || isLastGlyph ) &&
+          ( TextAbstraction::LINE_MUST_BREAK == lineBreakInfo ) )
+      {
+        LineLayout currentLineLayout = lineLayout;
+
+        // Must break the line. Update the line layout and return.
+        MergeLineLayout( lineLayout, tmpLineLayout );
+
+       // Reorder the RTL line.
+        if( bidiParameters.isBidirectional )
+        {
+          ReorderBiDiLayout( parameters,
+                             bidiParameters,
+                             currentLineLayout,
+                             lineLayout,
+                             false );
+        }
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
+
+        return;
+      }
+
+      if( isMultiline &&
+          ( TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo ) )
+      {
+        oneWordLaidOut = isWordLaidOut;
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid-out\n" );
+
+        // Current glyph is the last one of the current word.
+        // Add the temporal layout to the current one.
+        MergeLineLayout( lineLayout, tmpLineLayout );
+
+        tmpLineLayout.Clear();
+      }
+
+      glyphIndex += numberOfGLyphsInGroup;
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
+  }
+
+  void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
+                          Length numberOfGlyphs,
+                          float outlineWidth,
+                          float interGlyphExtraAdvance,
+                          Vector2* glyphPositionsBuffer )
+  {
+    // Traverse the glyphs and set the positions.
+
+    // Check if the x bearing of the first character is negative.
+    // If it has a negative x bearing, it will exceed the boundaries of the actor,
+    // so the penX position needs to be moved to the right.
+
+    const GlyphInfo& glyph = *glyphsBuffer;
+    float penX = -glyph.xBearing + mCursorWidth + outlineWidth;
+
+    for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
+    {
+      const GlyphInfo& glyph = *( glyphsBuffer + i );
+      Vector2& position = *( glyphPositionsBuffer + i );
+
+      position.x = std::roundf( penX + glyph.xBearing );
+      position.y = -glyph.yBearing;
+
+      penX += ( glyph.advance + interGlyphExtraAdvance );
+    }
+  }
+
+  void SetGlyphPositions( const Parameters& layoutParameters,
+                          Vector2* glyphPositionsBuffer,
+                          LayoutBidiParameters& layoutBidiParameters,
+                          const LineLayout& layout )
+  {
+    const Character* const textBuffer = layoutParameters.textModel->mLogicalModel->mText.Begin();
+    const BidirectionalLineInfoRun& bidiLine = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo[layoutBidiParameters.bidiLineIndex];
+    const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+    const GlyphIndex* const charactersToGlyphsBuffer = layoutParameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = layoutParameters.textModel->mVisualModel->mGlyphsPerCharacter.Begin();
+
+    CharacterIndex characterLogicalIndex = 0u;
+    CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+    float penX = 0.f;
+    while( TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) ) )
+    {
+      const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+      const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+
+      Vector2& position = *( glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex );
+      position.x = penX;
+      position.y = -glyph.yBearing;
+
+      penX += glyph.advance;
+
+      ++characterLogicalIndex;
+      characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+    }
+
+    const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+    const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+
+    penX += -glyph.xBearing;
+
+    // Traverses the characters of the right to left paragraph.
+    for( ; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
+         ++characterLogicalIndex )
+    {
+      // Convert the character in the logical order into the character in the visual order.
+      const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+      // Get the number of glyphs of the character.
+      const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterVisualIndex );
+
+      for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
+      {
+        // Convert the character in the visual order into the glyph in the visual order.
+        const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex ) + index;
+
+        DALI_ASSERT_DEBUG( glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count() );
+
+        const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+        Vector2& position = *( glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex );
+
+        position.x = std::round( penX + glyph.xBearing );
+        position.y = -glyph.yBearing;
+
+       penX += ( glyph.advance + layoutParameters.interGlyphExtraAdvance );
+      }
+    }
+  }
+
+  /**
+   * @brief Resizes the line buffer.
+   *
+   * @param[in,out] lines The vector of lines. Used when the layout is created from scratch.
+   * @param[in,out] newLines The vector of lines used instead of @p lines when the layout is updated.
+   * @param[in,out] linesCapacity The capacity of the vector (either lines or newLines).
+   * @param[in] updateCurrentBuffer Whether the layout is updated.
+   *
+   * @return Pointer to either lines or newLines.
+   */
+  LineRun* ResizeLinesBuffer( Vector<LineRun>& lines,
+                              Vector<LineRun>& newLines,
+                              Length& linesCapacity,
+                              bool updateCurrentBuffer )
+  {
+    LineRun* linesBuffer = nullptr;
+    // Reserve more space for the next lines.
+    linesCapacity *= 2u;
+    if( updateCurrentBuffer )
+    {
+      newLines.Resize( linesCapacity );
+      linesBuffer = newLines.Begin();
+    }
+    else
+    {
+      lines.Resize( linesCapacity );
+      linesBuffer = lines.Begin();
+    }
+
+    return linesBuffer;
+  }
+
+  /**
+   * Ellipsis a line if it exceeds the width's of the bounding box.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] layout The line layout.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in,out] glyphPositionsBuffer Pointer to the position's buffer.
+   * @param[in,out] numberOfLines The number of laid-out lines.
+   * @param[in] penY The vertical layout position.
+   * @param[in] currentParagraphDirection The current paragraph's direction.
+   * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   *
+   * return Whether the line is ellipsized.
+   */
+  bool EllipsisLine( const Parameters& layoutParameters,
+                     LayoutBidiParameters& layoutBidiParameters,
+                     const LineLayout& layout,
+                     Size& layoutSize,
+                     LineRun* linesBuffer,
+                     Vector2* glyphPositionsBuffer,
+                     Length& numberOfLines,
+                     float penY,
+                     bool& isAutoScrollEnabled )
+  {
+    const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
+                                                ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
+                                                  ( ( mLayout == SINGLE_LINE_BOX ) &&
+                                                    ( layout.length > layoutParameters.boundingBox.width ) ) );
+
+    if( ellipsis )
+    {
+      isAutoScrollEnabled = false;
+      // Do not layout more lines if ellipsis is enabled.
+
+      // The last line needs to be completely filled with characters.
+      // Part of a word may be used.
+
+      LineRun* lineRun = nullptr;
+      LineLayout ellipsisLayout;
+      if( 0u != numberOfLines )
+      {
+        // Get the last line and layout it again with the 'completelyFill' flag to true.
+        lineRun = linesBuffer + ( numberOfLines - 1u );
+
+        penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
+
+        ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
+      }
+      else
+      {
+        // At least there is space reserved for one line.
+        lineRun = linesBuffer;
+
+        lineRun->glyphRun.glyphIndex = 0u;
+        ellipsisLayout.glyphIndex = 0u;
+
+        ++numberOfLines;
+      }
+
+      GetLineLayoutForBox( layoutParameters,
+                           layoutBidiParameters,
+                           ellipsisLayout,
+                           true );
+
+      lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
+      lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
+      lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
+      lineRun->width = ellipsisLayout.length;
+      lineRun->extraLength = std::ceil( ellipsisLayout.whiteSpaceLengthEndOfLine );
+      lineRun->ascender = ellipsisLayout.ascender;
+      lineRun->descender = ellipsisLayout.descender;
+      lineRun->ellipsis = true;
+
+      layoutSize.width = layoutParameters.boundingBox.width;
+      if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
+      {
+        layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
+      }
+
+      const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+      const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+      const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+      if( layoutBidiParameters.isBidirectional )
+      {
+        layoutBidiParameters.bidiLineIndex = 0u;
+        for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLinesInfo.Begin(),
+               endIt = bidirectionalLinesInfo.End();
+             it != endIt;
+             ++it, ++layoutBidiParameters.bidiLineIndex )
+        {
+          const BidirectionalLineInfoRun& run = *it;
+
+          if( ellipsisLayout.characterIndex == run.characterRun.characterIndex )
+          {
+            // Found where to insert the bidi line info.
+            break;
+          }
+        }
+      }
+
+      const BidirectionalLineInfoRun* const bidirectionalLineInfo = ( layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty() ) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
+
+      if( ( nullptr != bidirectionalLineInfo ) &&
+          !bidirectionalLineInfo->isIdentity &&
+          ( ellipsisLayout.characterIndex == bidirectionalLineInfo->characterRun.characterIndex ) )
+      {
+        lineRun->direction = RTL;
+        SetGlyphPositions( layoutParameters,
+                           glyphPositionsBuffer,
+                           layoutBidiParameters,
+                           ellipsisLayout );
+      }
+      else
+      {
+        lineRun->direction = LTR;
+        SetGlyphPositions( glyphsBuffer + lineRun->glyphRun.glyphIndex,
+                           ellipsisLayout.numberOfGlyphs,
+                           outlineWidth,
+                           layoutParameters.interGlyphExtraAdvance,
+                           glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
+      }
+    }
+
+    return ellipsis;
+  }
+
+  /**
+   * @brief Updates the text layout with a new laid-out line.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] layout The line layout.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in] index Index to the vector of glyphs.
+   * @param[in,out] numberOfLines The number of laid-out lines.
+   * @param[in] isLastLine Whether the laid-out line is the last one.
+   */
+  void UpdateTextLayout( const Parameters& layoutParameters,
+                         const LineLayout& layout,
+                         Size& layoutSize,
+                         LineRun* linesBuffer,
+                         GlyphIndex index,
+                         Length& numberOfLines,
+                         bool isLastLine )
+  {
+    LineRun& lineRun = *( linesBuffer + numberOfLines );
+    ++numberOfLines;
+
+    lineRun.glyphRun.glyphIndex = index;
+    lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
+    lineRun.characterRun.characterIndex = layout.characterIndex;
+    lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
+    lineRun.lineSpacing = mDefaultLineSpacing;
+
+    lineRun.width = layout.length;
+    lineRun.extraLength = std::ceil( layout.whiteSpaceLengthEndOfLine );
+
+
+    // Rounds upward to avoid a non integer size.
+    lineRun.width = std::ceil( lineRun.width );
+
+    lineRun.ascender = layout.ascender;
+    lineRun.descender = layout.descender;
+    lineRun.direction = layout.direction;
+    lineRun.ellipsis = false;
+
+    // Update the actual size.
+    if( lineRun.width > layoutSize.width )
+    {
+      layoutSize.width = lineRun.width;
+    }
+
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+  }
+
+  /**
+   * @brief Updates the text layout with the last laid-out line.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] characterIndex The character index of the line.
+   * @param[in] glyphIndex The glyph index of the line.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in,out] numberOfLines The number of laid-out lines.
+   */
+  void UpdateTextLayout( const Parameters& layoutParameters,
+                         CharacterIndex characterIndex,
+                         GlyphIndex glyphIndex,
+                         Size& layoutSize,
+                         LineRun* linesBuffer,
+                         Length& numberOfLines )
+  {
+    const Vector<GlyphInfo>& glyphs = layoutParameters.textModel->mVisualModel->mGlyphs;
+
+    // Need to add a new line with no characters but with height to increase the layoutSize.height
+    const GlyphInfo& glyphInfo = glyphs[glyphs.Count() - 1u];
+
+    Text::FontMetrics fontMetrics;
+    if( 0u != glyphInfo.fontId )
+    {
+      mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
+    }
+
+    LineRun& lineRun = *( linesBuffer + numberOfLines );
+    ++numberOfLines;
+
+    lineRun.glyphRun.glyphIndex = glyphIndex;
+    lineRun.glyphRun.numberOfGlyphs = 0u;
+    lineRun.characterRun.characterIndex = characterIndex;
+    lineRun.characterRun.numberOfCharacters = 0u;
+    lineRun.width = 0.f;
+    lineRun.ascender = fontMetrics.ascender;
+    lineRun.descender = fontMetrics.descender;
+    lineRun.extraLength = 0.f;
+    lineRun.alignmentOffset = 0.f;
+    lineRun.direction = LTR;
+    lineRun.ellipsis = false;
+    lineRun.lineSpacing = mDefaultLineSpacing;
+
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+  }
+
+  /**
+   * @brief Updates the text's layout size adding the size of the previously laid-out lines.
+   *
+   * @param[in] lines The vector of lines (before the new laid-out lines are inserted).
+   * @param[in,out] layoutSize The text's layout size.
+   */
+  void UpdateLayoutSize( const Vector<LineRun>& lines,
+                         Size& layoutSize )
+  {
+    for( Vector<LineRun>::ConstIterator it = lines.Begin(),
+           endIt = lines.End();
+         it != endIt;
+         ++it )
+    {
+      const LineRun& line = *it;
+
+      if( line.width > layoutSize.width )
+      {
+        layoutSize.width = line.width;
+      }
+
+      layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
+    }
+  }
+
+  /**
+   * @brief Updates the indices of the character and glyph runs of the lines before the new lines are inserted.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in,out] lines The vector of lines (before the new laid-out lines are inserted).
+   * @param[in] characterOffset The offset to be added to the runs of characters.
+   * @param[in] glyphOffset The offset to be added to the runs of glyphs.
+   */
+  void UpdateLineIndexOffsets( const Parameters& layoutParameters,
+                               Vector<LineRun>& lines,
+                               Length characterOffset,
+                               Length glyphOffset )
+  {
+    // Update the glyph and character runs.
+    for( Vector<LineRun>::Iterator it = lines.Begin() + layoutParameters.startLineIndex,
+           endIt = lines.End();
+         it != endIt;
+         ++it )
+    {
+      LineRun& line = *it;
+
+      line.glyphRun.glyphIndex = glyphOffset;
+      line.characterRun.characterIndex = characterOffset;
+
+      glyphOffset += line.glyphRun.numberOfGlyphs;
+      characterOffset += line.characterRun.numberOfCharacters;
+    }
+  }
+
+  bool LayoutText( Parameters& layoutParameters,
+                   Size& layoutSize,
+                   bool elideTextEnabled,
+                   bool& isAutoScrollEnabled )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
+
+    Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
+
+    if( 0u == layoutParameters.numberOfGlyphs )
+    {
+      // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
+      if( layoutParameters.isLastNewParagraph )
+      {
+        Length numberOfLines = lines.Count();
+        if( 0u != numberOfLines )
+        {
+          const LineRun& lastLine = *( lines.End() - 1u );
+
+          if( 0u != lastLine.characterRun.numberOfCharacters )
+          {
+            // Need to add a new line with no characters but with height to increase the layoutSize.height
+            LineRun newLine;
+            Initialize( newLine );
+            lines.PushBack( newLine );
+
+            UpdateTextLayout( layoutParameters,
+                              lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
+                              lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
+                              layoutSize,
+                              lines.Begin(),
+                              numberOfLines );
+          }
+        }
+      }
+
+      // Calculates the layout size.
+      UpdateLayoutSize( lines,
+                        layoutSize );
+
+      // Rounds upward to avoid a non integer size.
+      layoutSize.height = std::ceil( layoutSize.height );
+
+      // Nothing else do if there are no glyphs to layout.
+      return false;
+    }
+
+    const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+    const Length totalNumberOfGlyphs = layoutParameters.textModel->mVisualModel->mGlyphs.Count();
+    Vector<Vector2>& glyphPositions = layoutParameters.textModel->mVisualModel->mGlyphPositions;
+
+    // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
+    // This extra line needs to be removed.
+    if( 0u != lines.Count() )
+    {
+      Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
+
+      if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
+          ( lastGlyphPlusOne == totalNumberOfGlyphs ) )
+      {
+        lines.Remove( lastLine );
+      }
+    }
+
+    // Retrieve BiDi info.
+    const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
+
+    const CharacterIndex* const glyphsToCharactersBuffer = hasBidiParagraphs ? layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin() : nullptr;
+    const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
+    const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+    // Set the layout bidirectional paramters.
+    LayoutBidiParameters layoutBidiParameters;
+
+    // Whether the layout is being updated or set from scratch.
+    const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < totalNumberOfGlyphs;
+
+    Vector2* glyphPositionsBuffer = nullptr;
+    Vector<Vector2> newGlyphPositions;
+
+    LineRun* linesBuffer = nullptr;
+    Vector<LineRun> newLines;
+
+    // Estimate the number of lines.
+    Length linesCapacity = std::max( 1u, layoutParameters.estimatedNumberOfLines );
+    Length numberOfLines = 0u;
+
+    if( updateCurrentBuffer )
+    {
+      newGlyphPositions.Resize( layoutParameters.numberOfGlyphs );
+      glyphPositionsBuffer = newGlyphPositions.Begin();
+
+      newLines.Resize( linesCapacity );
+      linesBuffer = newLines.Begin();
+    }
+    else
+    {
+      glyphPositionsBuffer = glyphPositions.Begin();
+
+      lines.Resize( linesCapacity );
+      linesBuffer = lines.Begin();
+    }
+
+    float penY = CalculateLineOffset( lines,
+                                      layoutParameters.startLineIndex );
+    for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
+    {
+      layoutBidiParameters.Clear();
+
+      if( hasBidiParagraphs )
+      {
+        const CharacterIndex startCharacterIndex = *( glyphsToCharactersBuffer + index );
+
+        for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalParagraphsInfo.Begin(),
+               endIt = bidirectionalParagraphsInfo.End();
+             it != endIt;
+             ++it, ++layoutBidiParameters.bidiParagraphIndex )
+        {
+          const BidirectionalParagraphInfoRun& run = *it;
+
+          const CharacterIndex lastCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+          if( lastCharacterIndex <= startCharacterIndex )
+          {
+            // Do not process, the paragraph has already been processed.
+            continue;
+          }
+
+          if( startCharacterIndex >= run.characterRun.characterIndex && startCharacterIndex < lastCharacterIndex )
+          {
+            layoutBidiParameters.paragraphDirection = run.direction;
+            layoutBidiParameters.isBidirectional = true;
+          }
+
+          // Has already been found.
+          break;
+        }
+
+        if( layoutBidiParameters.isBidirectional )
+        {
+          for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLinesInfo.Begin(),
+                 endIt = bidirectionalLinesInfo.End();
+               it != endIt;
+               ++it, ++layoutBidiParameters.bidiLineIndex )
+          {
+            const BidirectionalLineInfoRun& run = *it;
+
+            const CharacterIndex lastCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+            if( lastCharacterIndex <= startCharacterIndex )
+            {
+              // skip
+              continue;
+            }
+
+            if( startCharacterIndex < lastCharacterIndex )
+            {
+              // Found where to insert the bidi line info.
+              break;
+            }
+          }
+        }
+      }
+
+      CharacterDirection currentParagraphDirection = layoutBidiParameters.paragraphDirection;
+
+      // Get the layout for the line.
+      LineLayout layout;
+      layout.direction = layoutBidiParameters.paragraphDirection;
+      layout.glyphIndex = index;
+      GetLineLayoutForBox( layoutParameters,
+                           layoutBidiParameters,
+                           layout,
+                           false );
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "      number of glyphs %d\n", layout.numberOfGlyphs );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                length %f\n", layout.length );
+
+      if( 0u == layout.numberOfGlyphs )
+      {
+        // The width is too small and no characters are laid-out.
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
+
+        lines.Resize( numberOfLines );
+
+        // Rounds upward to avoid a non integer size.
+        layoutSize.height = std::ceil( layoutSize.height );
+
+        return false;
+      }
+
+      // Set the line position. Discard if ellipsis is enabled and the position exceeds the boundaries
+      // of the box.
+      penY += layout.ascender;
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  pen y %f\n", penY );
+
+      bool ellipsis = false;
+      if( elideTextEnabled )
+      {
+        layoutBidiParameters.paragraphDirection = currentParagraphDirection;
+
+        // Does the ellipsis of the last line.
+        ellipsis = EllipsisLine( layoutParameters,
+                                 layoutBidiParameters,
+                                 layout,
+                                 layoutSize,
+                                 linesBuffer,
+                                 glyphPositionsBuffer,
+                                 numberOfLines,
+                                 penY,
+                                 isAutoScrollEnabled );
+      }
+
+      if( ellipsis )
+      {
+        // No more lines to layout.
+        break;
+      }
+      else
+      {
+        // Whether the last line has been laid-out.
+        const bool isLastLine = index + layout.numberOfGlyphs == totalNumberOfGlyphs;
+
+        if( numberOfLines == linesCapacity )
+        {
+
+          // Reserve more space for the next lines.
+          linesBuffer = ResizeLinesBuffer( lines,
+                                           newLines,
+                                           linesCapacity,
+                                           updateCurrentBuffer );
+        }
+
+        // Updates the current text's layout with the line's layout.
+        UpdateTextLayout( layoutParameters,
+                          layout,
+                          layoutSize,
+                          linesBuffer,
+                          index,
+                          numberOfLines,
+                          isLastLine );
+
+        const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
+
+        if( ( nextIndex == totalNumberOfGlyphs ) &&
+            layoutParameters.isLastNewParagraph &&
+            ( mLayout == MULTI_LINE_BOX ) )
+        {
+          // The last character of the text is a new paragraph character.
+          // An extra line with no characters is added to increase the text's height
+          // in order to place the cursor.
+
+          if( numberOfLines == linesCapacity )
+          {
+            // Reserve more space for the next lines.
+            linesBuffer = ResizeLinesBuffer( lines,
+                                             newLines,
+                                             linesCapacity,
+                                             updateCurrentBuffer );
+          }
+
+          UpdateTextLayout( layoutParameters,
+                            layout.characterIndex + layout.numberOfCharacters,
+                            index + layout.numberOfGlyphs,
+                            layoutSize,
+                            linesBuffer,
+                            numberOfLines );
+        } // whether to add a last line.
+
+        const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+        const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+        const BidirectionalLineInfoRun* const bidirectionalLineInfo = ( layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty() ) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
+
+        if( ( nullptr != bidirectionalLineInfo ) &&
+            !bidirectionalLineInfo->isIdentity &&
+            ( layout.characterIndex == bidirectionalLineInfo->characterRun.characterIndex ) )
+        {
+          SetGlyphPositions( layoutParameters,
+                             glyphPositionsBuffer,
+                             layoutBidiParameters,
+                             layout );
+        }
+        else
+        {
+
+          // Sets the positions of the glyphs.
+          SetGlyphPositions( glyphsBuffer + index,
+                             layout.numberOfGlyphs,
+                             outlineWidth,
+                             layoutParameters.interGlyphExtraAdvance,
+                             glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
+        }
+
+        // Updates the vertical pen's position.
+        penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
+
+        // Increase the glyph index.
+        index = nextIndex;
+      } // no ellipsis
+    } // end for() traversing glyphs.
+
+    if( updateCurrentBuffer )
+    {
+      glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
+                             newGlyphPositions.Begin(),
+                             newGlyphPositions.End() );
+      glyphPositions.Resize( totalNumberOfGlyphs );
+
+      newLines.Resize( numberOfLines );
+
+      // Current text's layout size adds only the newly laid-out lines.
+      // Updates the layout size with the previously laid-out lines.
+      UpdateLayoutSize( lines,
+                        layoutSize );
+
+      if( 0u != newLines.Count() )
+      {
+        const LineRun& lastLine = *( newLines.End() - 1u );
+
+        const Length characterOffset = lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters;
+        const Length glyphOffset = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+
+        // Update the indices of the runs before the new laid-out lines are inserted.
+        UpdateLineIndexOffsets( layoutParameters,
+                                lines,
+                                characterOffset,
+                                glyphOffset );
+
+        // Insert the lines.
+        lines.Insert( lines.Begin() + layoutParameters.startLineIndex,
+                      newLines.Begin(),
+                      newLines.End() );
+      }
+    }
+    else
+    {
+      lines.Resize( numberOfLines );
+    }
+
+    // Rounds upward to avoid a non integer size.
+    layoutSize.height = std::ceil( layoutSize.height );
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
+
+    return true;
+  }
+
+  void Align( const Size& size,
+              CharacterIndex startIndex,
+              Length numberOfCharacters,
+              Text::HorizontalAlignment::Type horizontalAlignment,
+              Vector<LineRun>& lines,
+              float& alignmentOffset,
+              Dali::LayoutDirection::Type layoutDirection,
+              bool matchSystemLanguageDirection )
+  {
+    const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
+
+    alignmentOffset = MAX_FLOAT;
+    // Traverse all lines and align the glyphs.
+    for( Vector<LineRun>::Iterator it = lines.Begin(), endIt = lines.End();
+         it != endIt;
+         ++it )
+    {
+      LineRun& line = *it;
+
+      if( line.characterRun.characterIndex < startIndex )
+      {
+        // Do not align lines which have already been aligned.
+        continue;
+      }
+
+      if( line.characterRun.characterIndex > lastCharacterPlusOne )
+      {
+        // Do not align lines beyond the last laid-out character.
+        break;
+      }
+
+      if( line.characterRun.characterIndex == lastCharacterPlusOne && !isEmptyLineAtLast( lines, it ) )
+      {
+        // Do not align lines beyond the last laid-out character unless the line is last and empty.
+        break;
+      }
+
+      // Calculate the line's alignment offset accordingly with the align option,
+      // the box width, line length, and the paragraph's direction.
+      CalculateHorizontalAlignment( size.width,
+                                    horizontalAlignment,
+                                    line,
+                                    layoutDirection,
+                                    matchSystemLanguageDirection );
+
+      // Updates the alignment offset.
+      alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
+    }
+  }
+
+  void CalculateHorizontalAlignment( float boxWidth,
+                                     HorizontalAlignment::Type horizontalAlignment,
+                                     LineRun& line,
+                                     Dali::LayoutDirection::Type layoutDirection,
+                                     bool matchSystemLanguageDirection )
+  {
+    line.alignmentOffset = 0.f;
+    const bool isLineRTL = RTL == line.direction;
+
+    // Whether to swap the alignment.
+    // Swap if the line is RTL and is not required to match the direction of the system's language or if it's required to match the direction of the system's language and it's RTL.
+    bool isLayoutRTL = isLineRTL;
+    float lineLength = line.width;
+
+    // match align for system language direction
+    if( matchSystemLanguageDirection )
+    {
+      // Swap the alignment type if the line is right to left.
+      isLayoutRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
+    }
+    // Calculate the horizontal line offset.
+    switch( horizontalAlignment )
+    {
+      case HorizontalAlignment::BEGIN:
+      {
+        if( isLayoutRTL )
+        {
+          if( isLineRTL )
+          {
+            lineLength += line.extraLength;
+          }
+
+          line.alignmentOffset = boxWidth - lineLength;
+        }
+        else
+        {
+          line.alignmentOffset = 0.f;
+
+          if( isLineRTL )
+          {
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
+          }
+        }
+        break;
+      }
+      case HorizontalAlignment::CENTER:
+      {
+        line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
+
+        if( isLineRTL )
+        {
+          line.alignmentOffset -= line.extraLength;
+        }
+
+        line.alignmentOffset = std::floor( line.alignmentOffset ); // floor() avoids pixel alignment issues.
+        break;
+      }
+      case HorizontalAlignment::END:
+      {
+        if( isLayoutRTL )
+        {
+          line.alignmentOffset = 0.f;
+
+          if( isLineRTL )
+          {
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
+          }
+        }
+        else
+        {
+          if( isLineRTL )
+          {
+            lineLength += line.extraLength;
+          }
+
+          line.alignmentOffset = boxWidth - lineLength;
+        }
+        break;
+      }
+    }
+  }
+
+  void Initialize( LineRun& line )
+  {
+    line.glyphRun.glyphIndex = 0u;
+    line.glyphRun.numberOfGlyphs = 0u;
+    line.characterRun.characterIndex = 0u;
+    line.characterRun.numberOfCharacters = 0u;
+    line.width = 0.f;
+    line.ascender = 0.f;
+    line.descender = 0.f;
+    line.extraLength = 0.f;
+    line.alignmentOffset = 0.f;
+    line.direction = LTR;
+    line.ellipsis = false;
+    line.lineSpacing = mDefaultLineSpacing;
+  }
+
+  Type mLayout;
+  float mCursorWidth;
+  float mDefaultLineSpacing;
+
+  IntrusivePtr<Metrics> mMetrics;
+};
+
+Engine::Engine()
+: mImpl{ nullptr }
+{
+  mImpl = new Engine::Impl();
+}
+
+Engine::~Engine()
+{
+  delete mImpl;
+}
+
+void Engine::SetMetrics( MetricsPtr& metrics )
+{
+  mImpl->mMetrics = metrics;
+}
+
+void Engine::SetLayout( Type layout )
+{
+  mImpl->mLayout = layout;
+}
+
+Engine::Type Engine::GetLayout() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetLayout[%d]\n", mImpl->mLayout);
+  return mImpl->mLayout;
+}
+
+void Engine::SetCursorWidth( int width )
+{
+  mImpl->mCursorWidth = static_cast<float>( width );
+}
+
+int Engine::GetCursorWidth() const
+{
+  return static_cast<int>( mImpl->mCursorWidth );
+}
+
+bool Engine::LayoutText( Parameters& layoutParameters,
+                         Size& layoutSize,
+                         bool elideTextEnabled,
+                         bool& isAutoScrollEnabled )
+{
+  return mImpl->LayoutText( layoutParameters,
+                            layoutSize,
+                            elideTextEnabled,
+                            isAutoScrollEnabled );
+}
+
+void Engine::Align( const Size& size,
+                    CharacterIndex startIndex,
+                    Length numberOfCharacters,
+                    Text::HorizontalAlignment::Type horizontalAlignment,
+                    Vector<LineRun>& lines,
+                    float& alignmentOffset,
+                    Dali::LayoutDirection::Type layoutDirection,
+                    bool matchSystemLanguageDirection )
+{
+  mImpl->Align( size,
+                startIndex,
+                numberOfCharacters,
+                horizontalAlignment,
+                lines,
+                alignmentOffset,
+                layoutDirection,
+                matchSystemLanguageDirection );
+}
+
+void Engine::SetDefaultLineSpacing( float lineSpacing )
+{
+  mImpl->mDefaultLineSpacing = lineSpacing;
+}
+
+float Engine::GetDefaultLineSpacing() const
+{
+  return mImpl->mDefaultLineSpacing;
+}
+
+} // namespace Layout
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/layouts/layout-engine.h b/dali-toolkit/internal/text/layouts/layout-engine.h
new file mode 100755 (executable)
index 0000000..af693da
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H
+#define DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_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.
+ *
+ */
+
+// EXTERNAL INCLUDE
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+
+// INTERNAL INCLUDE
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/metrics.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Layout
+{
+
+struct Parameters;
+
+/**
+ * @brief LayoutEngine is responsible for calculating the visual position of glyphs in layout.
+ */
+class Engine
+{
+public:
+
+  enum Type
+  {
+    SINGLE_LINE_BOX,
+    MULTI_LINE_BOX
+  };
+
+  /**
+   * @brief Create a new instance of a LayoutEngine.
+   */
+  Engine();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  ~Engine();
+
+  /**
+   * @brief Provide the wrapper around FontClient used to get metrics
+   *
+   * @param[in] metrics Used to get metrics
+   */
+  void SetMetrics( MetricsPtr& metrics );
+
+  /**
+   * @brief Choose the required layout.
+   *
+   * @param[in] layout The required layout.
+   */
+  void SetLayout( Type layout );
+
+  /**
+   * @brief Query the required layout.
+   *
+   * @return The required layout.
+   */
+  Type GetLayout() const;
+
+  /**
+   * @brief Sets the width of the cursor.
+   *
+   * @param[in] width The width of the cursor in pixels.
+   */
+  void SetCursorWidth( int width );
+
+  /**
+   * @brief Retrieves the width of the cursor.
+   *
+   * @return The width of the cursor in pixels.
+   */
+  int GetCursorWidth() const;
+
+  /**
+   * @brief Store the visual position of glyphs in the VisualModel.
+   *
+   * Builds the bidirectional info and reorders RTL lines.
+   *
+   * @param[in,out] layoutParameters The parameters needed to layout the text.
+   * @param[out] layoutSize The size of the text after it has been laid-out.
+   * @param[in] elideTextEnabled Whether the text elide is enabled.
+   * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   *
+   * @return \e true if the text has been re-laid-out. \e false means the given width is too small to layout even a single character.
+   */
+  bool LayoutText( Parameters& layoutParameters,
+                   Size& layoutSize,
+                   bool elideTextEnabled,
+                   bool& isAutoScrollEnabled );
+
+  /**
+   * @brief Aligns the laid out lines.
+   *
+   * @param[in] size The size of the container where the text is laid-out.
+   * @param[in] startIndex Character index of the line from where the lines are aligned.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[in] horizontalAlignment The horizontal alignment.
+   * @param[in,out] lines The laid-out lines.
+   * @param[out] alignmentOffset The alignment offset.
+   * @param[in] layoutDirection The direction of the system language.
+   * @param[in] matchSystemLanguageDirection Whether match align for system language direction or not.
+   */
+  void Align( const Size& size,
+              CharacterIndex startIndex,
+              Length numberOfCharacters,
+              Text::HorizontalAlignment::Type horizontalAlignment,
+              Vector<LineRun>& lines,
+              float& alignmentOffset,
+              Dali::LayoutDirection::Type layoutDirection,
+              bool matchSystemLanguageDirection );
+
+  /**
+   * @brief Sets the default line spacing.
+   *
+   * @param[in] lineSpacing The line spacing.
+   */
+  void SetDefaultLineSpacing( float lineSpacing );
+
+  /**
+   * @brief Retrieves the default line spacing.
+   *
+   * @return The line spacing.
+   */
+  float GetDefaultLineSpacing() const;
+
+private:
+
+  // Undefined
+  Engine( const Engine& handle );
+
+  // Undefined
+  Engine& operator=( const Engine& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Layout
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H
diff --git a/dali-toolkit/internal/text/layouts/layout-parameters.h b/dali-toolkit/internal/text/layouts/layout-parameters.h
new file mode 100755 (executable)
index 0000000..b3aeaad
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DALI_TOOLKIT_TEXT_LAYOUT_PARAMETERS_H
+#define DALI_TOOLKIT_TEXT_LAYOUT_PARAMETERS_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/internal/text/text-model.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct BidirectionalLineInfoRun;
+
+namespace Layout
+{
+
+/**
+ * @brief Struct used to pass parameters.
+ */
+struct Parameters
+{
+  /**
+   * Constructor with the needed parameters to layout the text.
+   *
+   * @param[in] boundingBox The size of the box containing the text.
+   * @param[in,out] textModel The text's model.
+   */
+  Parameters( const Vector2& boundingBox,
+              ModelPtr textModel )
+  : boundingBox{ boundingBox },
+    textModel{ textModel },
+    lineBidirectionalInfoRunsBuffer{ nullptr },
+    numberOfBidirectionalInfoRuns{ 0u },
+    startGlyphIndex{ 0u },
+    numberOfGlyphs{ 0u },
+    startLineIndex{ 0u },
+    estimatedNumberOfLines{ 0u },
+    interGlyphExtraAdvance{ 0.f },
+    isLastNewParagraph{ false }
+  {}
+
+  Vector2                         boundingBox;                     ///< The size of the box containing the text.
+  ModelPtr textModel;
+  BidirectionalLineInfoRun*       lineBidirectionalInfoRunsBuffer; ///< Bidirectional conversion tables per line.
+  Length                          numberOfBidirectionalInfoRuns;   ///< The number of lines with bidirectional info.
+  GlyphIndex                      startGlyphIndex;                 ///< Index to the first glyph to layout.
+  Length                          numberOfGlyphs;                  ///< The number of glyphs to layout.
+  LineIndex                       startLineIndex;                  ///< The line index where to insert the new lines.
+  Length                          estimatedNumberOfLines;          ///< The estimated number of lines.
+  float                           interGlyphExtraAdvance;          ///< Extra advance added to each glyph.
+  bool                            isLastNewParagraph:1;            ///< Whether the last character is a new paragraph character.
+};
+
+} // namespace Layout
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LAYOUT_PARAMETERS_H
diff --git a/dali-toolkit/internal/text/line-run.h b/dali-toolkit/internal/text/line-run.h
new file mode 100644 (file)
index 0000000..84fde1c
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef DALI_TOOLKIT_TEXT_LINE_RUN_H
+#define DALI_TOOLKIT_TEXT_LINE_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief LineRun
+ */
+struct LineRun
+{
+  GlyphRun           glyphRun;        ///< The initial glyph index and the number of glyphs of the run.
+  CharacterRun       characterRun;    ///< The initial character index and the number of characters of the run.
+  float              width;           ///< The line's width.
+  float              ascender;        ///< The line's ascender.
+  float              descender;       ///< The line's descender.
+  float              extraLength;     ///< The length of the white spaces at the end of the line.
+  float              alignmentOffset; ///< The horizontal alignment offset.
+  float              lineSpacing;     ///< The line's spacing
+  CharacterDirection direction : 1;   ///< Direction of the first character of the paragraph.
+  bool               ellipsis  : 1;   ///< Wheter ellipsis is added to the line.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LINE_RUN_H
diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp
new file mode 100755 (executable)
index 0000000..3d9440e
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/logical-model-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void FreeFontFamilyNames( Vector<FontDescriptionRun>& fontDescriptionRuns )
+{
+  for( Vector<FontDescriptionRun>::Iterator it = fontDescriptionRuns.Begin(),
+         endIt = fontDescriptionRuns.End();
+       it != endIt;
+       ++it )
+  {
+    delete[] (*it).familyName;
+  }
+
+  fontDescriptionRuns.Clear();
+}
+
+void FreeEmbeddedItems( Vector<EmbeddedItem>& embeddedItem )
+{
+  for( Vector<EmbeddedItem>::Iterator it = embeddedItem.Begin(),
+         endIt = embeddedItem.End();
+       it != endIt;
+       ++it )
+  {
+    EmbeddedItem& item = *it;
+    delete[] item.url;
+  }
+
+  embeddedItem.Clear();
+}
+
+LogicalModelPtr LogicalModel::New()
+{
+  return LogicalModelPtr( new LogicalModel() );
+}
+
+Script LogicalModel::GetScript( CharacterIndex characterIndex ) const
+{
+  // If this operation is too slow, consider a binary search.
+
+  const ScriptRun* const scriptRunBuffer = mScriptRuns.Begin();
+  for( Length index = 0u, length = mScriptRuns.Count(); index < length; ++index )
+  {
+    const ScriptRun* const scriptRun = scriptRunBuffer + index;
+
+    if( ( scriptRun->characterRun.characterIndex <= characterIndex ) &&
+        ( characterIndex < scriptRun->characterRun.characterIndex + scriptRun->characterRun.numberOfCharacters ) )
+    {
+      return scriptRun->script;
+    }
+  }
+
+  return TextAbstraction::UNKNOWN;
+}
+
+CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex characterIndex ) const
+{
+  if( characterIndex >= mCharacterDirections.Count() )
+  {
+    // The model has no right to left characters, so the vector of directions is void.
+    return false;
+  }
+
+  return *( mCharacterDirections.Begin() + characterIndex );
+}
+
+CharacterIndex LogicalModel::GetLogicalCursorIndex( CharacterIndex visualCursorIndex )
+{
+  // The character's directions buffer.
+  const CharacterDirection* const modelCharacterDirections = mCharacterDirections.Begin();
+
+  // The bidirectional line info.
+  const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
+
+  // Whether the paragraph starts with a right to left character.
+  const bool isRightToLeftParagraph = bidirectionalLineInfo->direction;
+
+  // The total number of characters of the line.
+  const Length lastCharacterIndex = bidirectionalLineInfo->characterRun.characterIndex + bidirectionalLineInfo->characterRun.numberOfCharacters;
+
+  CharacterIndex logicalCursorIndex = 0u;
+
+  if( bidirectionalLineInfo->characterRun.characterIndex == visualCursorIndex )
+  {
+    if( isRightToLeftParagraph )
+    {
+      logicalCursorIndex = lastCharacterIndex;
+    }
+    else // else logical position is the first of the line.
+    {
+      logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
+    }
+  }
+  else if( lastCharacterIndex == visualCursorIndex )
+  {
+    if( isRightToLeftParagraph )
+    {
+      logicalCursorIndex = bidirectionalLineInfo->characterRun.characterIndex;
+    }
+    else // else logical position is the number of characters.
+    {
+      logicalCursorIndex = lastCharacterIndex;
+    }
+  }
+  else
+  {
+    // Get the character indexed by  index - 1 and index
+    // and calculate the logical position according the directions of
+    // both characters and the direction of the paragraph.
+
+    const CharacterIndex previousVisualCursorIndex = visualCursorIndex - 1u;
+    const CharacterIndex previousLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + previousVisualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+    const CharacterIndex currentLogicalCursorIndex = *( bidirectionalLineInfo->visualToLogicalMap + visualCursorIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+
+    const CharacterDirection previousCharacterDirection = *( modelCharacterDirections + previousLogicalCursorIndex );
+    const CharacterDirection currentCharacterDirection = *( modelCharacterDirections + currentLogicalCursorIndex );
+
+    if( previousCharacterDirection == currentCharacterDirection )
+    {
+      // Both glyphs have the same direction.
+      if( previousCharacterDirection )
+      {
+        logicalCursorIndex = previousLogicalCursorIndex;
+      }
+      else
+      {
+        logicalCursorIndex = currentLogicalCursorIndex;
+      }
+    }
+    else
+    {
+      if( isRightToLeftParagraph )
+      {
+        if( currentCharacterDirection )
+        {
+          logicalCursorIndex = currentLogicalCursorIndex + 1u;
+        }
+        else
+        {
+          logicalCursorIndex = previousLogicalCursorIndex;
+        }
+      }
+      else
+      {
+        if( previousCharacterDirection )
+        {
+          logicalCursorIndex = currentLogicalCursorIndex;
+        }
+        else
+        {
+          logicalCursorIndex = previousLogicalCursorIndex + 1u;
+        }
+      }
+    }
+  }
+
+  return logicalCursorIndex;
+}
+
+CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex )
+{
+  // The bidirectional line info.
+  const BidirectionalLineInfoRun* const bidirectionalLineInfo = mBidirectionalLineInfo.Begin() + mBidirectionalLineIndex;
+
+  return *( bidirectionalLineInfo->visualToLogicalMap + visualCharacterIndex - bidirectionalLineInfo->characterRun.characterIndex ) + bidirectionalLineInfo->characterRun.characterIndex;
+}
+
+bool LogicalModel::FetchBidirectionalLineInfo( CharacterIndex characterIndex )
+{
+  // The number of bidirectional lines.
+  const Length numberOfBidirectionalLines = mBidirectionalLineInfo.Count();
+
+  if( 0u == numberOfBidirectionalLines )
+  {
+    // If there is no bidirectional info.
+    return false;
+  }
+
+  // Find the bidi line where the character is laid-out.
+
+  const BidirectionalLineInfoRun* const bidirectionalLineInfoBuffer = mBidirectionalLineInfo.Begin();
+
+  // Check first if the character is in the previously fetched line.
+
+  BidirectionalLineRunIndex bidiLineIndex = 0u;
+  CharacterIndex lastCharacterOfRightToLeftRun = 0u;
+  if( mBidirectionalLineIndex < numberOfBidirectionalLines )
+  {
+    const BidirectionalLineInfoRun& bidiLineRun = *( bidirectionalLineInfoBuffer + mBidirectionalLineIndex );
+
+    const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+    if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
+        ( characterIndex < lastCharacterOfRunPlusOne ) )
+    {
+      // The character is in the previously fetched bidi line.
+      return true;
+    }
+    else
+    {
+      // The character is not in the previously fetched line.
+      // Set the bidi line index from where to start the fetch.
+
+      if( characterIndex < bidiLineRun.characterRun.characterIndex )
+      {
+        // Start the fetch from the beginning.
+        bidiLineIndex = 0u;
+      }
+      else
+      {
+        // Start the fetch from the next line.
+        bidiLineIndex = mBidirectionalLineIndex + 1u;
+        lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
+      }
+    }
+  }
+
+  // The character has not been found in the previously fetched bidi line.
+  for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLineInfoBuffer + bidiLineIndex,
+         endIt = mBidirectionalLineInfo.End();
+       it != endIt;
+       ++it, ++bidiLineIndex )
+  {
+    const BidirectionalLineInfoRun& bidiLineRun = *it;
+
+    if( ( lastCharacterOfRightToLeftRun < characterIndex ) &&
+        ( characterIndex < bidiLineRun.characterRun.characterIndex ) )
+    {
+      // The character is not inside a bidi line.
+      return false;
+    }
+
+    const CharacterIndex lastCharacterOfRunPlusOne = bidiLineRun.characterRun.characterIndex + bidiLineRun.characterRun.numberOfCharacters;
+    lastCharacterOfRightToLeftRun = lastCharacterOfRunPlusOne - 1u;
+    if( ( bidiLineRun.characterRun.characterIndex <= characterIndex ) &&
+        ( characterIndex < lastCharacterOfRunPlusOne ) )
+    {
+      // Bidi line found. Fetch the line.
+      mBidirectionalLineIndex = bidiLineIndex;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+BidirectionalLineRunIndex LogicalModel::GetBidirectionalLineInfo() const
+{
+  return mBidirectionalLineIndex;
+}
+
+void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
+{
+  const Length totalNumberOfCharacters = mText.Count();
+
+  // Process the color runs.
+  Vector<ColorRun> removedColorRuns;
+  UpdateCharacterRuns<ColorRun>( index,
+                                 numberOfCharacters,
+                                 totalNumberOfCharacters,
+                                 mColorRuns,
+                                 removedColorRuns );
+
+  // Process the background color runs.
+  Vector<ColorRun> removedBackgroundColorRuns;
+  UpdateCharacterRuns<ColorRun>( index,
+                                 numberOfCharacters,
+                                 totalNumberOfCharacters,
+                                 mBackgroundColorRuns,
+                                 removedBackgroundColorRuns );
+
+  // Process the font description runs.
+  Vector<FontDescriptionRun> removedFontDescriptionRuns;
+  UpdateCharacterRuns<FontDescriptionRun>( index,
+                                           numberOfCharacters,
+                                           totalNumberOfCharacters,
+                                           mFontDescriptionRuns,
+                                           removedFontDescriptionRuns );
+
+  // Free memory allocated for the font family name.
+  FreeFontFamilyNames( removedFontDescriptionRuns );
+}
+
+void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
+{
+  unsigned int runIndex = 0u;
+
+  // Set the text color.
+  bool colorOverriden = false;
+  unsigned int colorIndex = 0u;
+  const ColorRun* const colorRunsBuffer = mColorRuns.Begin();
+  for( Vector<ColorRun>::ConstIterator it = colorRunsBuffer,
+         endIt = mColorRuns.End();
+       it != endIt;
+       ++it, ++runIndex )
+  {
+    const ColorRun& colorRun = *it;
+
+    if( ( colorRun.characterRun.characterIndex <= index ) &&
+        ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
+    {
+      colorIndex = runIndex;
+      colorOverriden = true;
+    }
+  }
+
+  // Set the text's color if it's overriden.
+  if( colorOverriden )
+  {
+    style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color;
+    style.isDefaultColor = false;
+  }
+
+  // Reset the run index.
+  runIndex = 0u;
+
+  // Set the font's parameters.
+  bool nameOverriden = false;
+  bool weightOverriden = false;
+  bool widthOverriden = false;
+  bool slantOverriden = false;
+  bool sizeOverriden = false;
+  unsigned int nameIndex = 0u;
+  unsigned int weightIndex = 0u;
+  unsigned int widthIndex = 0u;
+  unsigned int slantIndex = 0u;
+  unsigned int sizeIndex = 0u;
+  const FontDescriptionRun* const fontDescriptionRunsBuffer = mFontDescriptionRuns.Begin();
+  for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionRunsBuffer,
+         endIt = mFontDescriptionRuns.End();
+       it != endIt;
+       ++it, ++runIndex )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *it;
+
+    if( ( fontDescriptionRun.characterRun.characterIndex <= index ) &&
+        ( index < fontDescriptionRun.characterRun.characterIndex + fontDescriptionRun.characterRun.numberOfCharacters ) )
+    {
+      if( fontDescriptionRun.familyDefined )
+      {
+        nameIndex = runIndex;
+        nameOverriden = true;
+      }
+
+      if( fontDescriptionRun.weightDefined )
+      {
+        weightIndex = runIndex;
+        weightOverriden = true;
+      }
+
+      if( fontDescriptionRun.widthDefined )
+      {
+        widthIndex = runIndex;
+        widthOverriden = true;
+      }
+
+      if( fontDescriptionRun.slantDefined )
+      {
+        slantIndex = runIndex;
+        slantOverriden = true;
+      }
+
+      if( fontDescriptionRun.sizeDefined )
+      {
+        sizeIndex = runIndex;
+        sizeOverriden = true;
+      }
+    }
+  }
+
+  // Set the font's family name if it's overriden.
+  if( nameOverriden )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + nameIndex );
+
+    style.familyName = std::string( fontDescriptionRun.familyName, fontDescriptionRun.familyLength );
+    style.isFamilyDefined = true;
+  }
+
+  // Set the font's weight if it's overriden.
+  if( weightOverriden )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + weightIndex );
+
+    style.weight = fontDescriptionRun.weight;
+    style.isWeightDefined = true;
+  }
+
+  // Set the font's width if it's overriden.
+  if( widthOverriden )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + widthIndex );
+
+    style.width = fontDescriptionRun.width;
+    style.isWidthDefined = true;
+  }
+
+  // Set the font's slant if it's overriden.
+  if( slantOverriden )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + slantIndex );
+
+    style.slant = fontDescriptionRun.slant;
+    style.isSlantDefined = true;
+  }
+
+  // Set the font's size if it's overriden.
+  if( sizeOverriden )
+  {
+    const FontDescriptionRun& fontDescriptionRun = *( fontDescriptionRunsBuffer + sizeIndex );
+
+    style.size = static_cast<float>( fontDescriptionRun.size ) / 64.f;
+    style.isSizeDefined = true;
+  }
+}
+
+void LogicalModel::ClearFontDescriptionRuns()
+{
+  FreeFontFamilyNames( mFontDescriptionRuns );
+}
+
+void LogicalModel::CreateParagraphInfo( CharacterIndex startIndex,
+                                        Length numberOfCharacters )
+{
+  const Length totalNumberOfCharacters = mLineBreakInfo.Count();
+
+  // Count the number of LINE_MUST_BREAK to reserve some space for the vector of paragraph's info.
+  Vector<CharacterIndex> paragraphs;
+  paragraphs.Reserve( numberOfCharacters );
+  const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = mLineBreakInfo.Begin();
+  const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
+  for( Length index = startIndex; index < lastCharacterIndexPlusOne; ++index )
+  {
+    if( TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index ) )
+    {
+      paragraphs.PushBack( index );
+    }
+  }
+
+  // Whether the current paragraphs are updated or set from scratch.
+  const bool updateCurrentParagraphs = numberOfCharacters < totalNumberOfCharacters;
+
+  // Reserve space for current paragraphs plus new ones.
+  const Length numberOfNewParagraphs = paragraphs.Count();
+  const Length totalNumberOfParagraphs = mParagraphInfo.Count() + numberOfNewParagraphs;
+  mParagraphInfo.Resize( totalNumberOfParagraphs );
+
+  ParagraphRun* paragraphInfoBuffer = NULL;
+  Vector<ParagraphRun> newParagraphs;
+
+  if( updateCurrentParagraphs )
+  {
+    newParagraphs.Resize( numberOfNewParagraphs );
+    paragraphInfoBuffer = newParagraphs.Begin();
+  }
+  else
+  {
+    paragraphInfoBuffer = mParagraphInfo.Begin();
+  }
+
+  // Find where to insert the new paragraphs.
+  ParagraphRunIndex paragraphIndex = 0u;
+  CharacterIndex firstIndex = startIndex;
+
+  if( updateCurrentParagraphs )
+  {
+    for( Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
+           endIt = mParagraphInfo.Begin() + totalNumberOfParagraphs - numberOfNewParagraphs;
+         it != endIt;
+         ++it )
+    {
+      const ParagraphRun& paragraph( *it );
+
+      if( startIndex < paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters )
+      {
+        firstIndex = paragraph.characterRun.characterIndex;
+        break;
+      }
+
+      ++paragraphIndex;
+    }
+  }
+
+  // Create the paragraph info.
+  ParagraphRunIndex newParagraphIndex = 0u;
+  for( Vector<CharacterIndex>::ConstIterator it = paragraphs.Begin(),
+         endIt = paragraphs.End();
+       it != endIt;
+       ++it, ++newParagraphIndex )
+  {
+    const CharacterIndex index = *it;
+
+    ParagraphRun& paragraph = *( paragraphInfoBuffer + newParagraphIndex );
+    paragraph.characterRun.characterIndex = firstIndex;
+    paragraph.characterRun.numberOfCharacters = 1u + index - firstIndex;
+
+    firstIndex += paragraph.characterRun.numberOfCharacters;
+  }
+
+
+  // Insert the new paragraphs.
+  if( updateCurrentParagraphs )
+  {
+    mParagraphInfo.Insert( mParagraphInfo.Begin() + paragraphIndex,
+                           newParagraphs.Begin(),
+                           newParagraphs.End() );
+
+    mParagraphInfo.Resize( totalNumberOfParagraphs );
+
+    // Update the next paragraph indices.
+    for( Vector<ParagraphRun>::Iterator it = mParagraphInfo.Begin() + paragraphIndex + newParagraphs.Count(),
+           endIt = mParagraphInfo.End();
+         it != endIt;
+         ++it )
+    {
+      ParagraphRun& paragraph( *it );
+
+      paragraph.characterRun.characterIndex += numberOfCharacters;
+    }
+  }
+}
+
+void LogicalModel::FindParagraphs( CharacterIndex index,
+                                   Length numberOfCharacters,
+                                   Vector<ParagraphRunIndex>& paragraphs )
+{
+  // Reserve som space for the paragraph indices.
+  paragraphs.Reserve( mParagraphInfo.Count() );
+
+  // Traverse the paragraphs to find which ones contain the given characters.
+  ParagraphRunIndex paragraphIndex = 0u;
+  for( Vector<ParagraphRun>::ConstIterator it = mParagraphInfo.Begin(),
+         endIt = mParagraphInfo.End();
+       it != endIt;
+       ++it, ++paragraphIndex )
+  {
+    const ParagraphRun& paragraph( *it );
+
+    if( ( paragraph.characterRun.characterIndex + paragraph.characterRun.numberOfCharacters > index ) &&
+        ( paragraph.characterRun.characterIndex < index + numberOfCharacters ) )
+    {
+      paragraphs.PushBack( paragraphIndex );
+    }
+  }
+}
+
+void LogicalModel::ClearEmbeddedImages()
+{
+  FreeEmbeddedItems( mEmbeddedItems );
+}
+
+LogicalModel::~LogicalModel()
+{
+  ClearFontDescriptionRuns();
+  ClearEmbeddedImages();
+}
+
+LogicalModel::LogicalModel()
+: mBidirectionalLineIndex( 0u )
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/logical-model-impl.h b/dali-toolkit/internal/text/logical-model-impl.h
new file mode 100755 (executable)
index 0000000..3c01dc6
--- /dev/null
@@ -0,0 +1,232 @@
+#ifndef DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H
+#define DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
+#include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/embedded-item.h>
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/paragraph-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+typedef IntrusivePtr<LogicalModel> LogicalModelPtr;
+struct InputStyle;
+
+/**
+ * @brief A logical text model contains layout independent information.
+ *
+ * This includes:
+ * - A series of UTF-32 characters in logical order
+ */
+class LogicalModel : public RefObject
+{
+public:
+
+  /**
+   * @brief Create a new instance of a LogicalModel.
+   *
+   * @return A pointer to a new LogicalModel.
+   */
+  static LogicalModelPtr New();
+
+  // Language support interface.
+
+  /**
+   * @brief Retrieves the script for the given character index.
+   *
+   * @param[in] characterIndex Index to the character.
+   *
+   * @return The character's script.
+   */
+  Script GetScript( CharacterIndex characterIndex ) const;
+
+  // Bidirectional support interface.
+
+  /**
+   * @brief Retrieves the direction of a characters.
+   *
+   * See GetCharacterDirections().
+   *
+   * @param[in] characterIndex Index to a character.
+   *
+   * @return The character's direction.
+   */
+  CharacterDirection GetCharacterDirection( CharacterIndex characterIndex ) const;
+
+  // Visual <--> Logical conversion tables.
+
+  /**
+   * @brief Retrieves the logical cursor index for the given visual cursor index.
+   *
+   * @pre The method FetchBidirectionalLineInfo() must be called before. If the result of FetchBidirectionalLineInfo() is false,
+   *      then the character is not in a bidirectional line and the result will be invalid.
+   *
+   * @param[in] visualCursorIndex The visual cursor index.
+   *
+   * @return The logical cursor index.
+   */
+  CharacterIndex GetLogicalCursorIndex( CharacterIndex visualCursorIndex );
+
+  /**
+   * @brief Retrieves the logical character index for the given visual character index.
+   *
+   * @pre The method FetchBidirectionalLineInfo() must be called before. If the result of FetchBidirectionalLineInfo() is false,
+   *      then the character is not in a bidirectional line and the result will be invalid.
+   *
+   * @param[in] visualCharacterIndex The visual character index.
+   *
+   * @return The logical character index.
+   */
+  CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex );
+
+  /**
+   * @brief Fetch the bidirectional line info for the given character.
+   *
+   * Call GetBidirectionalLineInfo() to retrieve the last fetched line.
+   *
+   * @param[in] characterIndex The character index.
+   *
+   * @return @e true if the given @e character is in a bidirectional line.
+   */
+  bool FetchBidirectionalLineInfo( CharacterIndex characterIndex );
+
+  /**
+   * @brief Retrieves the last fetched bidirectional line info.
+   *
+   * @return The index of the bidirectional line info.
+   */
+  BidirectionalLineRunIndex GetBidirectionalLineInfo() const;
+
+  // Text style.
+
+  /**
+   * @brief Updates the text's style runs with the added or removed text.
+   *
+   * @param[in] index The character's index.
+   * @param[in] numberOfCharacters The number of characters added or removed. If the value is negative the characters are removed.
+   */
+  void UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters );
+
+  /**
+   * @brief Retrieves the text's style for the given character index.
+   *
+   * @param[in] index The character index.
+   * @param[out] style The text's style in the given style.
+   */
+  void RetrieveStyle( CharacterIndex index, InputStyle& style );
+
+  /**
+   * @brief Clears the font description runs.
+   */
+  void ClearFontDescriptionRuns();
+
+  // Paragraphs
+
+  /**
+   * @brief Creates the paragraph info.
+   *
+   * @pre The line break info must be set.
+   *
+   * @param[in] startIndex The character from where the paragraph info is set.
+   * @param[in] numberOfCharacters The number of characters.
+   */
+  void CreateParagraphInfo( CharacterIndex startIndex,
+                            Length numberOfCharacters );
+
+  /**
+   * @brief Find the paragraphs which contains the given characters.
+   *
+   * @param[in] index The first character's index of the run.
+   * @param[in] numberOfCharacters The number of characters of the run.
+   * @param[out] paragraphs Indices to the paragraphs which contain the characters.
+   */
+  void FindParagraphs( CharacterIndex index,
+                       Length numberOfCharacters,
+                       Vector<ParagraphRunIndex>& paragraphs );
+
+  // Embedded images
+
+  /**
+   * @brief Clears the embedded images.
+   */
+  void ClearEmbeddedImages();
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~LogicalModel();
+
+private:
+
+  /**
+   * @brief Private constructor.
+   */
+  LogicalModel();
+
+  // Undefined
+  LogicalModel( const LogicalModel& handle );
+
+  // Undefined
+  LogicalModel& operator=( const LogicalModel& handle );
+
+public:
+
+  Vector<Character>                     mText;
+  Vector<ScriptRun>                     mScriptRuns;
+  Vector<FontRun>                       mFontRuns;
+  Vector<ColorRun>                      mColorRuns;
+  Vector<ColorRun>                      mBackgroundColorRuns;
+  Vector<FontDescriptionRun>            mFontDescriptionRuns;
+  Vector<LineBreakInfo>                 mLineBreakInfo;
+  Vector<ParagraphRun>                  mParagraphInfo;
+  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<EmbeddedItem>                  mEmbeddedItems;
+
+  BidirectionalLineRunIndex             mBidirectionalLineIndex;           ///< The last fetched bidirectional line info.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H
diff --git a/dali-toolkit/internal/text/markup-processor-color.cpp b/dali-toolkit/internal/text/markup-processor-color.cpp
new file mode 100644 (file)
index 0000000..2fd826d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-color.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string XHTML_VALUE_ATTRIBUTE("value");
+}
+
+void ProcessColorTag( const Tag& tag, ColorRun& colorRun )
+{
+  for( Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+         endIt = tag.attributes.End();
+       it != endIt;
+       ++it )
+  {
+    const Attribute& attribute( *it );
+    if( TokenComparison( XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      ColorStringToVector4( attribute.valueBuffer, attribute.valueLength, colorRun.color );
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-color.h b/dali-toolkit/internal/text/markup-processor-color.h
new file mode 100644 (file)
index 0000000..52fa73b
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
+
+/*
+ * Copyright (c) 2019 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 Text
+{
+
+struct Tag;
+struct ColorRun;
+
+/**
+ * @brief Retrieves the color value from the tag and sets it to the color run.
+ *
+ * @param[in] tag The color tag and its attributes.
+ * @param[in,out] colorRun The color run.
+ */
+void ProcessColorTag( const Tag& tag, ColorRun& colorRun );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H
diff --git a/dali-toolkit/internal/text/markup-processor-embedded-item.cpp b/dali-toolkit/internal/text/markup-processor-embedded-item.cpp
new file mode 100755 (executable)
index 0000000..7751c01
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/embedded-item.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string XHTML_URL_ATTRIBUTE("url");
+const std::string XHTML_WIDTH_ATTRIBUTE("width");
+const std::string XHTML_HEIGHT_ATTRIBUTE("height");
+const std::string XHTML_COLOR_BLENDING_ATTRIBUTE("color-blending");
+
+const std::string NONE("none");
+const std::string MULTIPLY("multiply");
+}
+
+void ProcessEmbeddedItem( const Tag& tag, EmbeddedItem& embeddedItem )
+{
+  embeddedItem.url = nullptr;
+  embeddedItem.urlLength = 0u;
+  embeddedItem.width = 0u;
+  embeddedItem.height = 0u;
+  embeddedItem.colorBlendingMode = ColorBlendingMode::NONE;
+
+  for( Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+         endIt = tag.attributes.End();
+       it != endIt;
+       ++it )
+  {
+    const Attribute& attribute( *it );
+    if( TokenComparison(XHTML_URL_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      embeddedItem.urlLength = attribute.valueLength;
+      embeddedItem.url = new char[embeddedItem.urlLength];
+      memcpy(embeddedItem.url, attribute.valueBuffer, embeddedItem.urlLength);
+      // The memory is freed when the font run is removed from the logical model.
+    }
+    else if (TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      embeddedItem.width = StringToUint(attribute.valueBuffer);
+    }
+    else if (TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      embeddedItem.height = StringToUint(attribute.valueBuffer);
+    }
+    else if (TokenComparison(XHTML_COLOR_BLENDING_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      if (TokenComparison(MULTIPLY, attribute.valueBuffer, attribute.valueLength))
+      {
+        embeddedItem.colorBlendingMode = ColorBlendingMode::MULTIPLY;
+      }
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-embedded-item.h b/dali-toolkit/internal/text/markup-processor-embedded-item.h
new file mode 100755 (executable)
index 0000000..6333c35
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
+
+/*
+ * Copyright (c) 2019 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 Text
+{
+
+struct Tag;
+struct EmbeddedItem;
+
+/**
+ * @brief Retrieves the @e embedded @e item from the @p tag.
+ *
+ * @param[in] tag The embedded item tag and its attributes.
+ * @param[in,out] embeddedItem The embedded item.
+ */
+void ProcessEmbeddedItem( const Tag& tag, EmbeddedItem& embeddedItem );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H
diff --git a/dali-toolkit/internal/text/markup-processor-font.cpp b/dali-toolkit/internal/text/markup-processor-font.cpp
new file mode 100644 (file)
index 0000000..b745317
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-font.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string XHTML_FAMILY_ATTRIBUTE("family");
+const std::string XHTML_SIZE_ATTRIBUTE("size");
+const std::string XHTML_WEIGHT_ATTRIBUTE("weight");
+const std::string XHTML_WIDTH_ATTRIBUTE("width");
+const std::string XHTML_SLANT_ATTRIBUTE("slant");
+
+const unsigned int MAX_FONT_ATTRIBUTE_SIZE = 15u; ///< The maximum length of any of the possible 'weight', 'width' or 'slant' values.
+}
+
+void ProcessFontTag( const Tag& tag, FontDescriptionRun& fontRun )
+{
+  for( Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+         endIt = tag.attributes.End();
+       it != endIt;
+       ++it )
+  {
+    const Attribute& attribute( *it );
+    if( TokenComparison( XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      fontRun.familyDefined = true;
+      fontRun.familyLength = attribute.valueLength;
+      fontRun.familyName = new char[fontRun.familyLength];
+      memcpy( fontRun.familyName, attribute.valueBuffer, fontRun.familyLength );
+      // The memory is freed when the font run is removed from the logical model.
+    }
+    else if( TokenComparison( XHTML_SIZE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      // 64.f is used to convert from point size to 26.6 pixel format.
+      fontRun.size = static_cast<PointSize26Dot6>( StringToFloat( attribute.valueBuffer ) * 64.f );
+      fontRun.sizeDefined = true;
+    }
+    else if( TokenComparison( XHTML_WEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      // The StringToWeight() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
+      char value[MAX_FONT_ATTRIBUTE_SIZE+1u];
+      const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
+      memcpy( value, attribute.valueBuffer, length );
+      value[length] = 0;
+
+      fontRun.weight = StringToWeight( value );
+      fontRun.weightDefined = true;
+    }
+    else if( TokenComparison( XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      // The StringToWidth() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
+      char value[MAX_FONT_ATTRIBUTE_SIZE+1u];
+      const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
+      memcpy( value, attribute.valueBuffer, length );
+      value[length] = 0;
+
+      fontRun.width = StringToWidth( value );
+      fontRun.widthDefined = true;
+    }
+    else if( TokenComparison( XHTML_SLANT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      // The StringToSlant() uses the Scripting::GetEnumeration() function which requires the input string to end with a '\0' char.
+      char value[MAX_FONT_ATTRIBUTE_SIZE+1u];
+      const Length length = attribute.valueLength > MAX_FONT_ATTRIBUTE_SIZE ? MAX_FONT_ATTRIBUTE_SIZE : attribute.valueLength;
+      memcpy( value, attribute.valueBuffer, length );
+      value[length] = 0;
+
+      fontRun.slant = StringToSlant( value );
+      fontRun.slantDefined = true;
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-font.h b/dali-toolkit/internal/text/markup-processor-font.h
new file mode 100644 (file)
index 0000000..954d471
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
+
+/*
+ * Copyright (c) 2019 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 Text
+{
+
+struct Tag;
+struct FontDescriptionRun;
+
+/**
+ * @brief Retrieves the font attributes from the tag and sets it to the font run.
+ *
+ * @param[in] tag The font tag and its attributes.
+ * @param[in,out] fontRun The font description run.
+ */
+void ProcessFontTag( const Tag& tag, FontDescriptionRun& fontRun );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_FONT_H
diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp
new file mode 100755 (executable)
index 0000000..6c133ae
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/constants.h>
+#include <dali/public-api/math/vector2.h>
+#include <stdlib.h>
+#include <sstream>
+#include <iomanip>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const char WHITE_SPACE      = 0x20; // ASCII value of the white space.
+const char FIRST_UPPER_CASE = 0x41; // ASCII value of the one after the first upper case character (A).
+const char LAST_UPPER_CASE  = 0x5b; // ASCII value of the one after the last upper case character (Z).
+const char TO_LOWER_CASE    = 32;   // Value to add to a upper case character to transform it into a lower case.
+
+const char WEB_COLOR_TOKEN( '#' );
+const char* const HEX_COLOR_TOKEN( "0x" );
+const char* const ALPHA_ONE( "FF" );
+
+const std::string BLACK_COLOR( "black" );
+const std::string WHITE_COLOR( "white" );
+const std::string RED_COLOR( "red" );
+const std::string GREEN_COLOR( "green" );
+const std::string BLUE_COLOR( "blue" );
+const std::string YELLOW_COLOR( "yellow" );
+const std::string MAGENTA_COLOR( "magenta" );
+const std::string CYAN_COLOR( "cyan" );
+const std::string TRANSPARENT_COLOR( "transparent" );
+}
+
+bool TokenComparison( const std::string& string1, const char* const stringBuffer2, Length length )
+{
+  const Length stringSize = string1.size();
+  if( stringSize != length )
+  {
+    // Early return. Strings have different sizes.
+    return false;
+  }
+
+  const char* const stringBuffer1 = string1.c_str();
+
+  for( std::size_t index = 0; index < stringSize; ++index )
+  {
+    const char character = *( stringBuffer2 + index );
+    const bool toLower = ( character < LAST_UPPER_CASE ) && ( character >= FIRST_UPPER_CASE );
+    if( *( stringBuffer1 + index ) != ( toLower ? character + TO_LOWER_CASE : character ) )
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void SkipWhiteSpace( const char*& stringBuffer,
+                     const char* const stringEndBuffer )
+{
+  for( ; ( WHITE_SPACE >= *stringBuffer ) && ( stringBuffer < stringEndBuffer ); ++stringBuffer );
+}
+
+void JumpToWhiteSpace( const char*& stringBuffer,
+                       const char* const stringEndBuffer )
+{
+  for( ; ( WHITE_SPACE != *stringBuffer ) && ( stringBuffer < stringEndBuffer ); ++stringBuffer );
+}
+
+unsigned int StringToUint( const char* const uintStr )
+{
+  return static_cast<unsigned int>( strtoul( uintStr, NULL, 10 ) );
+}
+
+unsigned int StringToHex( const char* const uintStr )
+{
+  return static_cast<unsigned int>( strtoul( uintStr, NULL, 16 ) );
+}
+
+float StringToFloat( const char* const floatStr )
+{
+  return static_cast<float>( strtod( floatStr, NULL ) );
+}
+
+void FloatToString( float value, std::string& floatStr )
+{
+  std::stringstream ss;
+  ss << value;
+  floatStr = ss.str();
+}
+
+void UintToString( unsigned int value, std::string& uIntStr )
+{
+  std::stringstream ss;
+  ss << value;
+  uIntStr = ss.str();
+}
+
+void UintColorToVector4( unsigned int color, Vector4& retColor )
+{
+  retColor.a = static_cast<float>( ( color & 0xFF000000 ) >> 24u ) / 255.f;
+  retColor.r = static_cast<float>( ( color & 0x00FF0000 ) >> 16u ) / 255.f;
+  retColor.g = static_cast<float>( ( color & 0x0000FF00 ) >> 8u ) / 255.f;
+  retColor.b = static_cast<float>( color & 0x000000FF ) / 255.f;
+}
+
+void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor )
+{
+  if( WEB_COLOR_TOKEN == *colorStr )
+  {
+    std::string webColor( colorStr + 1u, length - 1u );
+    if( 4u == length )                      // 3 component web color #F00 (red)
+    {
+      webColor.insert( 2u, &( webColor[2] ), 1u );
+      webColor.insert( 1u, &( webColor[1] ), 1u );
+      webColor.insert( 0u, &( webColor[0] ), 1u );
+      webColor.insert( 0u, ALPHA_ONE );
+    }
+    else if( 7u == length )                 // 6 component web color #FF0000 (red)
+    {
+      webColor.insert( 0u, ALPHA_ONE );
+    }
+
+    UintColorToVector4( StringToHex( webColor.c_str() ), retColor );
+  }
+  else if( TokenComparison( HEX_COLOR_TOKEN, colorStr, 2u ) )
+  {
+    UintColorToVector4( StringToHex( colorStr + 2u ), retColor );
+  }
+  else if( TokenComparison( BLACK_COLOR, colorStr, length ) )
+  {
+    retColor = Color::BLACK;
+  }
+  else if( TokenComparison( WHITE_COLOR, colorStr, length ) )
+  {
+    retColor = Color::WHITE;
+  }
+  else if( TokenComparison( RED_COLOR, colorStr, length ) )
+  {
+    retColor = Color::RED;
+  }
+  else if( TokenComparison( GREEN_COLOR, colorStr, length ) )
+  {
+    retColor = Color::GREEN;
+  }
+  else if( TokenComparison( BLUE_COLOR, colorStr, length ) )
+  {
+    retColor = Color::BLUE;
+  }
+  else if( TokenComparison( YELLOW_COLOR, colorStr, length ) )
+  {
+    retColor = Color::YELLOW;
+  }
+  else if( TokenComparison( MAGENTA_COLOR, colorStr, length ) )
+  {
+    retColor = Color::MAGENTA;
+  }
+  else if( TokenComparison( CYAN_COLOR, colorStr, length ) )
+  {
+    retColor = Color::CYAN;
+  }
+  else if( TokenComparison( TRANSPARENT_COLOR, colorStr, length ) )
+  {
+    retColor = Color::TRANSPARENT;
+  }
+}
+
+void Vector4ToColorString( const Vector4& value, std::string& vector2Str )
+{
+  if( Color::BLACK == value )
+  {
+    vector2Str = BLACK_COLOR;
+    return;
+  }
+
+  if( Color::WHITE == value )
+  {
+    vector2Str = WHITE_COLOR;
+    return;
+  }
+
+  if( Color::RED == value )
+  {
+    vector2Str = RED_COLOR;
+    return;
+  }
+
+  if( Color::GREEN == value )
+  {
+    vector2Str = GREEN_COLOR;
+    return;
+  }
+
+  if( Color::BLUE == value )
+  {
+    vector2Str = BLUE_COLOR;
+    return;
+  }
+
+  if( Color::YELLOW == value )
+  {
+    vector2Str = YELLOW_COLOR;
+    return;
+  }
+
+  if( Color::MAGENTA == value )
+  {
+    vector2Str = MAGENTA_COLOR;
+    return;
+  }
+
+  if( Color::CYAN == value )
+  {
+    vector2Str = CYAN_COLOR;
+    return;
+  }
+
+  if( Color::TRANSPARENT == value )
+  {
+    vector2Str = TRANSPARENT_COLOR;
+    return;
+  }
+
+  const unsigned int alpha = static_cast<unsigned int>( 255.f * value.a );
+  const unsigned int red = static_cast<unsigned int>( 255.f * value.r );
+  const unsigned int green = static_cast<unsigned int>( 255.f * value.g );
+  const unsigned int blue = static_cast<unsigned int>( 255.f * value.b );
+
+  std::stringstream ss;
+  const unsigned int size = 2u * sizeof( unsigned char );
+
+  ss << "0x"
+     << std::setfill('0') << std::setw( size )
+     << std::hex << alpha
+     << std::setfill('0') << std::setw( size )
+     << std::hex << red
+     << std::setfill('0') << std::setw( size )
+     << std::hex << green
+     << std::setfill('0') << std::setw( size )
+     << std::hex << blue;
+  vector2Str = ss.str();
+}
+
+void StringToVector2( const char* const vectorStr, Length length, Vector2& vector2 )
+{
+  // Points to the first character of the string.
+  const char* strBuffer = vectorStr;
+
+  // Points to the first character of the 'x' value.
+  const char* const xBuffer = strBuffer;
+
+  // Jumps to the next white space.
+  JumpToWhiteSpace( strBuffer, strBuffer + length );
+
+  // Points to the first character of the 'y' value.
+  const char* const yBuffer = strBuffer;
+
+  // Converts the shadow's offset to float.
+  vector2.x = StringToFloat( xBuffer );
+  vector2.y = StringToFloat( yBuffer );
+}
+
+void Vector2ToString( const Vector2& value, std::string& vector2Str )
+{
+  FloatToString( value.x, vector2Str );
+  vector2Str += " ";
+
+  std::string yStr;
+  FloatToString( value.y, yStr );
+
+  vector2Str += yStr;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.h b/dali-toolkit/internal/text/markup-processor-helper-functions.h
new file mode 100755 (executable)
index 0000000..d6f65c1
--- /dev/null
@@ -0,0 +1,195 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+struct Vector2;
+struct Vector4;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Stores an attribute pair: name, value.
+ */
+struct Attribute
+{
+  const char* nameBuffer;
+  const char* valueBuffer;
+  Length nameLength;
+  Length valueLength;
+};
+
+/**
+ * @brief Stores a tag and its attributes.
+ */
+ struct Tag
+ {
+   Vector<Attribute> attributes;
+   const char* buffer;
+   Length length;
+   bool isEndTag;
+ };
+
+/**
+ * @brief Compare if two tokens are equal.
+ *
+ * @pre @p string1 must be lower case. (The html-ish constant tokens)
+ * The @p stringBuffer2 parameter is transformed to lower case.
+ * This function is used in the mark-up parser.
+ * It has no sense to transform the constants html-ish tokens to lower case when
+ * it's known they already are.
+ *
+ * @param[in] string1 The html-ish constant token.
+ * @param[in] stringBuffer2 Pointer to the html-ish token buffer.
+ * @param[in] length The length of the html-ish token.
+ *
+ * @return @e true if both strings are equal.
+ */
+bool TokenComparison( const std::string& string1, const char* const stringBuffer2, Length length );
+
+/**
+ * @brief Skips any unnecessary white space.
+ *
+ * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
+ * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
+ */
+void SkipWhiteSpace( const char*& stringBuffer,
+                     const char* const stringEndBuffer );
+
+/**
+ * @Brief Jumps to the next white space.
+ *
+ * @param[in,out] stringBuffer The string buffer. It's a const iterator pointing the current character.
+ * @param[in] stringEndBuffer Pointer to one character after the end of the string buffer.
+ */
+void JumpToWhiteSpace( const char*& stringBuffer,
+                       const char* const stringEndBuffer );
+
+/**
+* @brief Converts a string into an unsigned int.
+*
+* @param[in] uintStr An unsigned int packed inside a string.
+*
+* @return The unsigned int value.
+*/
+unsigned int StringToUint( const char* const uintStr );
+
+/**
+ * @brief Converts a string into an hexadecimal unsigned int.
+ *
+ * @param[in] uintStr An hexadecimal unsigned int packed inside a string.
+ *
+ * @return The hexadecimal value.
+ */
+unsigned int StringToHex( const char* const uintStr );
+
+/**
+ * @brief Converts a string into a float value.
+ *
+ * @param[in] floatStr A float packed inside a string.
+ *
+ * @return The float value.
+ */
+float StringToFloat( const char* const floatStr );
+
+/**
+ * @brief Converts a float into a string.
+ *
+ * @param[in] value The float value.
+ * @param[out] floatStr The string.
+ */
+void FloatToString( float value, std::string& floatStr );
+
+/**
+ * @brief Converts an unsigned int into a string.
+ *
+ * @param[in] value The unsigned int value.
+ * @param[out] uIntStr The string.
+ */
+void UintToString( unsigned int value, std::string& uIntStr );
+
+/**
+ * @brief Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali.
+ *
+ * @param[in] color An ARGB color packed in an unsigned int.
+ * @param[out] retColor A Vector4 with the converted color.
+ */
+void UintColorToVector4( unsigned int color, Vector4& retColor );
+
+/**
+ * @brief Converts a color packed inside a string into an ARGB Vector4 color.
+ *
+ * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
+ * black, white, red, green, blue, yellow, magenta, cyan or transparent.
+ *
+ * @param[in] colorStr A color packed inside a string.
+ * @param[in] length The length of the color string.
+ * @param[out] retColor A color packed inside a Vector4.
+ */
+void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor );
+
+/**
+ * @brief Converts a color packed in a Vector4 into a string.
+ *
+ * Constant colors will be converted to the strings black, white, red, green, blue, yellow, magenta, cyan or transparent.
+ *
+ * If is not a constant color it will be converted to a string with hexadecimal ARGB content.
+ *
+ * @param[in] value The color value.
+ * @param[out] colorStr The string.
+ */
+void Vector4ToColorString( const Vector4& value, std::string& vector2Str );
+
+/**
+ * @brief Converts a two dimension vector packed inside a string into a Vector2.
+ *
+ * @param[in] vectorStr The two dimension vector packed inside a string.
+ * @param[in] length The length of the string.
+ * @param[out] vector2 The Vector2.
+ */
+void StringToVector2( const char* const vectorStr, Length length, Vector2& vector2 );
+
+/**
+ * @brief Converts a Vector2 into a string.
+ *
+ * @param[in] value The vector2 value.
+ * @param[out] vector2Str The string.
+ */
+void Vector2ToString( const Vector2& value, std::string& vector2Str );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_HELPER_FUNCTIONS_H
diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp
new file mode 100755 (executable)
index 0000000..dac4f92
--- /dev/null
@@ -0,0 +1,848 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor.h>
+
+// EXTERNAL INCLUDES
+#include <climits>  // for ULONG_MAX
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/markup-processor-color.h>
+#include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
+#include <dali-toolkit/internal/text/markup-processor-font.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/xhtml-entities.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+// HTML-ISH tag and attribute constants.
+// Note they must be lower case in order to make the comparison to work
+// as the parser converts all the read tags to lower case.
+const std::string XHTML_COLOR_TAG("color");
+const std::string XHTML_FONT_TAG("font");
+const std::string XHTML_B_TAG("b");
+const std::string XHTML_I_TAG("i");
+const std::string XHTML_U_TAG("u");
+const std::string XHTML_SHADOW_TAG("shadow");
+const std::string XHTML_GLOW_TAG("glow");
+const std::string XHTML_OUTLINE_TAG("outline");
+const std::string XHTML_ITEM_TAG("item");
+
+const char LESS_THAN      = '<';
+const char GREATER_THAN   = '>';
+const char EQUAL          = '=';
+const char QUOTATION_MARK = '\'';
+const char SLASH          = '/';
+const char BACK_SLASH     = '\\';
+const char AMPERSAND      = '&';
+const char HASH           = '#';
+const char SEMI_COLON     = ';';
+const char CHAR_ARRAY_END = '\0';
+const char HEX_CODE       = 'x';
+
+const char WHITE_SPACE    = 0x20;        // ASCII value of the white space.
+
+// Range 1 0x0u < XHTML_DECIMAL_ENTITY_RANGE <= 0xD7FFu
+// Range 2 0xE000u < XHTML_DECIMAL_ENTITY_RANGE <= 0xFFFDu
+// Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
+const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = { 0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu };
+
+const unsigned int MAX_NUM_OF_ATTRIBUTES =  5u; ///< The font tag has the 'family', 'size' 'weight', 'width' and 'slant' attrubutes.
+const unsigned int DEFAULT_VECTOR_SIZE   = 16u; ///< Default size of run vectors.
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MARKUP_PROCESSOR");
+#endif
+
+/**
+ * @brief Struct used to retrieve the style runs from the mark-up string.
+ */
+struct StyleStack
+{
+  typedef VectorBase::SizeType RunIndex;
+
+  Vector<RunIndex>  stack;    ///< Use a vector as a style stack. Stores the indices pointing where the run is stored inside the logical model.
+  unsigned int topIndex; ///< Points the top of the stack.
+
+  StyleStack()
+  : stack(),
+    topIndex( 0u )
+  {
+    stack.Resize( DEFAULT_VECTOR_SIZE );
+  }
+
+  void Push( RunIndex index )
+  {
+    // Check if there is space inside the style stack.
+    const VectorBase::SizeType size = stack.Count();
+    if( topIndex >= size )
+    {
+      // Resize the style stack.
+      stack.Resize( 2u * size );
+    }
+
+    // Set the run index in the top of the stack.
+    *( stack.Begin() + topIndex ) = index;
+
+    // Reposition the pointer to the top of the stack.
+    ++topIndex;
+  }
+
+  RunIndex Pop()
+  {
+    // Pop the top of the stack.
+    --topIndex;
+    return *( stack.Begin() + topIndex );
+  }
+};
+
+/**
+ * @brief Initializes a font run description to its defaults.
+ *
+ * @param[in,out] fontRun The font description run to initialize.
+ */
+void Initialize( FontDescriptionRun& fontRun )
+{
+  fontRun.characterRun.characterIndex = 0u;
+  fontRun.characterRun.numberOfCharacters = 0u;
+  fontRun.familyName = NULL;
+  fontRun.familyLength = 0u;
+  fontRun.weight = TextAbstraction::FontWeight::NORMAL;
+  fontRun.width = TextAbstraction::FontWidth::NORMAL;
+  fontRun.slant = TextAbstraction::FontSlant::NORMAL;
+  fontRun.size = 0u;
+  fontRun.familyDefined = false;
+  fontRun.weightDefined = false;
+  fontRun.widthDefined = false;
+  fontRun.slantDefined = false;
+  fontRun.sizeDefined = false;
+}
+
+/**
+ * @brief Splits the tag string into the tag name and its attributes.
+ *
+ * The attributes are stored in a vector in the tag.
+ *
+ * @param[in,out] tag The tag.
+ */
+void ParseAttributes( Tag& tag )
+{
+  if( tag.buffer == NULL )
+  {
+    return;
+  }
+
+  tag.attributes.Resize( MAX_NUM_OF_ATTRIBUTES );
+
+  // Find first the tag name.
+  bool isQuotationOpen = false;
+
+  const char* tagBuffer = tag.buffer;
+  const char* const tagEndBuffer = tagBuffer + tag.length;
+  tag.length = 0u;
+  for( ; tagBuffer < tagEndBuffer; ++tagBuffer )
+  {
+    const char character = *tagBuffer;
+    if( WHITE_SPACE < character )
+    {
+      ++tag.length;
+    }
+    else
+    {
+      // Stops counting the length of the tag when a white space is found.
+      // @note a white space is the WHITE_SPACE character and anything below as 'tab', 'return' or 'control characters'.
+      break;
+    }
+  }
+  SkipWhiteSpace( tagBuffer, tagEndBuffer );
+
+  // Find the attributes.
+  unsigned int attributeIndex = 0u;
+  const char* nameBuffer = NULL;
+  const char* valueBuffer = NULL;
+  Length nameLength = 0u;
+  Length valueLength = 0u;
+
+  bool addToNameValue = true;
+  Length numberOfWhiteSpace = 0u;
+  for( ; tagBuffer < tagEndBuffer; ++tagBuffer )
+  {
+    const char character = *tagBuffer;
+    if( ( WHITE_SPACE >= character ) && !isQuotationOpen )
+    {
+      if( NULL != valueBuffer )
+      {
+        // Remove white spaces at the end of the value.
+        valueLength -= numberOfWhiteSpace;
+      }
+
+      if( ( NULL != nameBuffer ) && ( NULL != valueBuffer ) )
+      {
+        // Every time a white space is found, a new attribute is created and stored in the attributes vector.
+        Attribute& attribute = *( tag.attributes.Begin() + attributeIndex );
+        ++attributeIndex;
+
+        attribute.nameBuffer = nameBuffer;
+        attribute.valueBuffer = valueBuffer;
+        attribute.nameLength = nameLength;
+        attribute.valueLength = valueLength;
+
+        nameBuffer = NULL;
+        valueBuffer = NULL;
+        nameLength = 0u;
+        valueLength = 0u;
+
+        addToNameValue = true; // next read characters will be added to the name.
+      }
+    }
+    else if( EQUAL == character ) // '='
+    {
+      addToNameValue = false; // next read characters will be added to the value.
+      SkipWhiteSpace( tagBuffer, tagEndBuffer );
+    }
+    else if( QUOTATION_MARK == character ) // '\''
+    {
+      // Do not add quotation marks to neither name nor value.
+      isQuotationOpen = !isQuotationOpen;
+
+      if( isQuotationOpen )
+      {
+        ++tagBuffer;
+        SkipWhiteSpace( tagBuffer, tagEndBuffer );
+        --tagBuffer;
+      }
+    }
+    else
+    {
+      // Adds characters to the name or the value.
+      if( addToNameValue )
+      {
+        if( NULL == nameBuffer )
+        {
+          nameBuffer = tagBuffer;
+        }
+        ++nameLength;
+      }
+      else
+      {
+        if( isQuotationOpen )
+        {
+          if( WHITE_SPACE >= character )
+          {
+            ++numberOfWhiteSpace;
+          }
+          else
+          {
+            numberOfWhiteSpace = 0u;
+          }
+        }
+        if( NULL == valueBuffer )
+        {
+          valueBuffer = tagBuffer;
+        }
+        ++valueLength;
+      }
+    }
+  }
+
+  if( NULL != valueBuffer )
+  {
+    // Remove white spaces at the end of the value.
+    valueLength -= numberOfWhiteSpace;
+  }
+
+  if( ( NULL != nameBuffer ) && ( NULL != valueBuffer ) )
+  {
+    // Checks if the last attribute needs to be added.
+    Attribute& attribute = *( tag.attributes.Begin() + attributeIndex );
+    ++attributeIndex;
+
+    attribute.nameBuffer = nameBuffer;
+    attribute.valueBuffer = valueBuffer;
+    attribute.nameLength = nameLength;
+    attribute.valueLength = valueLength;
+  }
+
+  // Resize the vector of attributes.
+  tag.attributes.Resize( attributeIndex );
+}
+
+/**
+ * @brief It parses a tag and its attributes if the given iterator @e it is pointing at a tag beginning.
+ *
+ * @param[in,out] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
+ * @param[in] markupStringEndBuffer Pointer to one character after the end of the mark-up string buffer.
+ * @param[out] tag The tag with its attributes.
+ *
+ * @return @e true if the iterator @e it is pointing a mark-up tag. Otherwise @e false.
+ */
+bool IsTag( const char*& markupStringBuffer,
+            const char* const markupStringEndBuffer,
+            Tag& tag )
+{
+  bool isTag = false;
+  bool isQuotationOpen = false;
+  bool attributesFound = false;
+  tag.isEndTag = false;
+  bool isPreviousLessThan = false;
+  bool isPreviousSlash = false;
+
+  const char character = *markupStringBuffer;
+  if( LESS_THAN == character ) // '<'
+  {
+    tag.buffer = NULL;
+    tag.length = 0u;
+    isPreviousLessThan = true;
+
+    // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed.
+    ++markupStringBuffer;
+    if( markupStringBuffer < markupStringEndBuffer )
+    {
+      SkipWhiteSpace( markupStringBuffer, markupStringEndBuffer );
+
+      for( ; ( !isTag ) && ( markupStringBuffer < markupStringEndBuffer ); ++markupStringBuffer )
+      {
+        const char character = *markupStringBuffer;
+
+        if( !isQuotationOpen && ( SLASH == character ) ) // '/'
+        {
+          if (isPreviousLessThan)
+          {
+            tag.isEndTag = true;
+          }
+          else
+          {
+            // if the tag has a '/' it may be an end tag.
+            isPreviousSlash = true;
+          }
+
+          isPreviousLessThan = false;
+          if( ( markupStringBuffer + 1u < markupStringEndBuffer ) && ( WHITE_SPACE >= *( markupStringBuffer + 1u ) ) )
+          {
+            ++markupStringBuffer;
+            SkipWhiteSpace( markupStringBuffer, markupStringEndBuffer );
+            --markupStringBuffer;
+          }
+        }
+        else if( GREATER_THAN == character ) // '>'
+        {
+          isTag = true;
+          if (isPreviousSlash)
+          {
+            tag.isEndTag = true;
+          }
+
+          isPreviousSlash = false;
+          isPreviousLessThan = false;
+        }
+        else if( QUOTATION_MARK == character )
+        {
+          isQuotationOpen = !isQuotationOpen;
+          ++tag.length;
+
+          isPreviousSlash = false;
+          isPreviousLessThan = false;
+        }
+        else if( WHITE_SPACE >= character ) // ' '
+        {
+          // If the tag contains white spaces then it may have attributes.
+          if( !isQuotationOpen )
+          {
+            attributesFound = true;
+          }
+          ++tag.length;
+        }
+        else
+        {
+          if( NULL == tag.buffer )
+          {
+            tag.buffer = markupStringBuffer;
+          }
+
+          // If it's not any of the 'special' characters then just add it to the tag string.
+          ++tag.length;
+
+          isPreviousSlash = false;
+          isPreviousLessThan = false;
+        }
+      }
+    }
+
+    // If the tag string has white spaces, then parse the attributes is needed.
+    if( attributesFound )
+    {
+      ParseAttributes( tag );
+    }
+  }
+
+  return isTag;
+}
+
+/**
+ * @brief Returns length of XHTML entity by parsing the text. It also determines if it is XHTML entity or not.
+ *
+ * @param[in] markupStringBuffer The mark-up string buffer. It's a const iterator pointing the current character.
+ * @param[in] markupStringEndBuffer Pointing to end of mark-up string buffer.
+ *
+ * @return Length of markupText in case of XHTML entity otherwise return 0.
+ */
+unsigned int GetXHTMLEntityLength( const char*& markupStringBuffer,
+                                   const char* const markupStringEndBuffer )
+{
+  char character = *markupStringBuffer;
+  if( AMPERSAND == character ) // '&'
+  {
+    // if the iterator is pointing to a '&' character, then check for ';' to find end to XHTML entity.
+    ++markupStringBuffer;
+    if( markupStringBuffer < markupStringEndBuffer )
+    {
+      unsigned int len = 1u;
+      for( ; markupStringBuffer < markupStringEndBuffer ; ++markupStringBuffer )
+      {
+        character = *markupStringBuffer;
+        ++len;
+        if( SEMI_COLON == character ) // ';'
+        {
+          // found end of XHTML entity
+          ++markupStringBuffer;
+          return len;
+        }
+        else if( ( AMPERSAND == character ) || ( BACK_SLASH == character ) || ( LESS_THAN == character ))
+        {
+          return 0;
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+/**
+ * @brief It parses a XHTML string which has hex/decimal entity and fill its corresponging utf-8 string.
+ *
+ * @param[in] markupText The mark-up text buffer.
+ * @param[out] utf-8 text Corresponding to markup Text
+ *
+ * @return true if string is successfully parsed otherwise false
+ */
+bool XHTMLNumericEntityToUtf8 ( const char* markupText, char* utf8 )
+{
+  bool result = false;
+
+  if( NULL != markupText )
+  {
+    bool isHex = false;
+
+    // check if hex or decimal entity
+    if( ( CHAR_ARRAY_END != *markupText ) && ( HEX_CODE == *markupText ) )
+    {
+      isHex = true;
+      ++markupText;
+    }
+
+    char* end = NULL;
+    unsigned long l = strtoul( markupText, &end, ( isHex ? 16 : 10 ) );  // l contains UTF-32 code in case of correct XHTML entity
+
+    // check for valid XHTML numeric entities (between '#' or "#x" and ';')
+    if( ( l > 0 ) && ( l < ULONG_MAX ) && ( *end == SEMI_COLON ) ) // in case wrong XHTML entity is set eg. "&#23abcdefs;" in that case *end will be 'a'
+    {
+      /* characters XML 1.1 permits */
+      if( ( ( XHTML_DECIMAL_ENTITY_RANGE[0] < l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[1] ) ) ||
+        ( ( XHTML_DECIMAL_ENTITY_RANGE[2] <= l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[3] ) ) ||
+        ( ( XHTML_DECIMAL_ENTITY_RANGE[4] <= l ) && ( l <= XHTML_DECIMAL_ENTITY_RANGE[5] ) ) )
+      {
+        // Convert UTF32 code to UTF8
+        Utf32ToUtf8( reinterpret_cast<const uint32_t* const>( &l ), 1, reinterpret_cast<uint8_t*>( utf8 ) );
+        result = true;
+       }
+    }
+  }
+  return result;
+}
+
+} // namespace
+
+void ProcessMarkupString( const std::string& markupString, MarkupProcessData& markupProcessData )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str() );
+
+  // Reserve space for the plain text.
+  const Length markupStringSize = markupString.size();
+  markupProcessData.markupProcessedText.reserve( markupStringSize );
+
+  // Stores a struct with the index to the first character of the run, the type of run and its parameters.
+  StyleStack styleStack;
+
+  // Points the next free position in the vector of runs.
+  StyleStack::RunIndex colorRunIndex = 0u;
+  StyleStack::RunIndex fontRunIndex = 0u;
+
+  // check tag reference
+  int colorTagReference = 0u;
+  int fontTagReference = 0u;
+  int iTagReference = 0u;
+  int bTagReference = 0u;
+
+  // Give an initial default value to the model's vectors.
+  markupProcessData.colorRuns.Reserve( DEFAULT_VECTOR_SIZE );
+  markupProcessData.fontRuns.Reserve( DEFAULT_VECTOR_SIZE );
+
+  // Get the mark-up string buffer.
+  const char* markupStringBuffer = markupString.c_str();
+  const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
+
+  Tag tag;
+  CharacterIndex characterIndex = 0u;
+  for( ; markupStringBuffer < markupStringEndBuffer; )
+  {
+    tag.attributes.Clear();
+    if( IsTag( markupStringBuffer,
+               markupStringEndBuffer,
+               tag ) )
+    {
+      if( TokenComparison( XHTML_COLOR_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new color run.
+          ColorRun colorRun;
+          colorRun.characterRun.numberOfCharacters = 0u;
+
+          // Set the start character index.
+          colorRun.characterRun.characterIndex = characterIndex;
+
+          // Fill the run with the attributes.
+          ProcessColorTag( tag, colorRun );
+
+          // Push the color run in the logical model.
+          markupProcessData.colorRuns.PushBack( colorRun );
+
+          // Push the index of the run into the stack.
+          styleStack.Push( colorRunIndex );
+
+          // Point the next color run.
+          ++colorRunIndex;
+
+          // Increase reference
+          ++colorTagReference;
+        }
+        else
+        {
+          if( colorTagReference > 0 )
+          {
+            // Pop the top of the stack and set the number of characters of the run.
+            ColorRun& colorRun = *( markupProcessData.colorRuns.Begin() + styleStack.Pop() );
+            colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
+            --colorTagReference;
+          }
+        }
+      } // <color></color>
+      else if( TokenComparison( XHTML_I_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new font run.
+          FontDescriptionRun fontRun;
+          Initialize( fontRun );
+
+          // Fill the run with the parameters.
+          fontRun.characterRun.characterIndex = characterIndex;
+          fontRun.slant = TextAbstraction::FontSlant::ITALIC;
+          fontRun.slantDefined = true;
+
+          // Push the font run in the logical model.
+          markupProcessData.fontRuns.PushBack( fontRun );
+
+          // Push the index of the run into the stack.
+          styleStack.Push( fontRunIndex );
+
+          // Point the next free font run.
+          ++fontRunIndex;
+
+          // Increase reference
+          ++iTagReference;
+        }
+        else
+        {
+          if( iTagReference > 0 )
+          {
+            // Pop the top of the stack and set the number of characters of the run.
+            FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
+            fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
+            --iTagReference;
+          }
+        }
+      } // <i></i>
+      else if( TokenComparison( XHTML_U_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new underline run.
+        }
+        else
+        {
+          // Pop the top of the stack and set the number of characters of the run.
+        }
+      } // <u></u>
+      else if( TokenComparison( XHTML_B_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new font run.
+          FontDescriptionRun fontRun;
+          Initialize( fontRun );
+
+          // Fill the run with the parameters.
+          fontRun.characterRun.characterIndex = characterIndex;
+          fontRun.weight = TextAbstraction::FontWeight::BOLD;
+          fontRun.weightDefined = true;
+
+          // Push the font run in the logical model.
+          markupProcessData.fontRuns.PushBack( fontRun );
+
+          // Push the index of the run into the stack.
+          styleStack.Push( fontRunIndex );
+
+          // Point the next free font run.
+          ++fontRunIndex;
+
+          // Increase reference
+          ++bTagReference;
+        }
+        else
+        {
+          if( bTagReference > 0 )
+          {
+            // Pop the top of the stack and set the number of characters of the run.
+            FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
+            fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
+            --bTagReference;
+          }
+        }
+      } // <b></b>
+      else if( TokenComparison( XHTML_FONT_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new font run.
+          FontDescriptionRun fontRun;
+          Initialize( fontRun );
+
+          // Fill the run with the parameters.
+          fontRun.characterRun.characterIndex = characterIndex;
+
+          ProcessFontTag( tag, fontRun );
+
+          // Push the font run in the logical model.
+          markupProcessData.fontRuns.PushBack( fontRun );
+
+          // Push the index of the run into the stack.
+          styleStack.Push( fontRunIndex );
+
+          // Point the next free font run.
+          ++fontRunIndex;
+
+          // Increase reference
+          ++fontTagReference;
+        }
+        else
+        {
+          if( fontTagReference > 0 )
+          {
+            // Pop the top of the stack and set the number of characters of the run.
+            FontDescriptionRun& fontRun = *( markupProcessData.fontRuns.Begin() + styleStack.Pop() );
+            fontRun.characterRun.numberOfCharacters = characterIndex - fontRun.characterRun.characterIndex;
+            --fontTagReference;
+          }
+        }
+      } // <font></font>
+      else if( TokenComparison( XHTML_SHADOW_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new shadow run.
+        }
+        else
+        {
+          // Pop the top of the stack and set the number of characters of the run.
+        }
+      } // <shadow></shadow>
+      else if( TokenComparison( XHTML_GLOW_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new glow run.
+        }
+        else
+        {
+          // Pop the top of the stack and set the number of characters of the run.
+        }
+      } // <glow></glow>
+      else if( TokenComparison( XHTML_OUTLINE_TAG, tag.buffer, tag.length ) )
+      {
+        if( !tag.isEndTag )
+        {
+          // Create a new outline run.
+        }
+        else
+        {
+          // Pop the top of the stack and set the number of characters of the run.
+        }
+      } // <outline></outline>
+      else if (TokenComparison(XHTML_ITEM_TAG, tag.buffer, tag.length))
+      {
+        if (tag.isEndTag)
+        {
+          // Create an embedded item instance.
+          EmbeddedItem item;
+          item.characterIndex = characterIndex;
+          ProcessEmbeddedItem(tag, item);
+
+          markupProcessData.items.PushBack(item);
+
+          // Insert white space character that will be replaced by the item.
+          markupProcessData.markupProcessedText.append( 1u, WHITE_SPACE );
+          ++characterIndex;
+        }
+      }
+    }  // end if( IsTag() )
+    else if( markupStringBuffer < markupStringEndBuffer )
+    {
+      unsigned char character = *markupStringBuffer;
+      const char* markupBuffer = markupStringBuffer;
+      unsigned char count = GetUtf8Length( character );
+      char utf8[8];
+
+      if( ( BACK_SLASH == character ) && ( markupStringBuffer + 1u < markupStringEndBuffer ) )
+      {
+        // Adding < , >  or & special character.
+        const unsigned char nextCharacter = *( markupStringBuffer + 1u );
+        if( ( LESS_THAN == nextCharacter ) || ( GREATER_THAN == nextCharacter ) || ( AMPERSAND == nextCharacter ) )
+        {
+          character = nextCharacter;
+          ++markupStringBuffer;
+
+          count = GetUtf8Length( character );
+          markupBuffer = markupStringBuffer;
+        }
+      }
+      else   // checking if conatins XHTML entity or not
+      {
+        const unsigned int len =  GetXHTMLEntityLength( markupStringBuffer, markupStringEndBuffer);
+
+        // Parse markupStringTxt if it contains XHTML Entity between '&' and ';'
+        if( len > 0 )
+        {
+          char* entityCode = NULL;
+          bool result = false;
+          count = 0;
+
+          // Checking if XHTML Numeric Entity
+          if( HASH == *( markupBuffer + 1u ) )
+          {
+            entityCode = &utf8[0];
+            // markupBuffer is currently pointing to '&'. By adding 2u to markupBuffer it will point to numeric string by skipping "&#'
+            result = XHTMLNumericEntityToUtf8( ( markupBuffer + 2u ), entityCode );
+          }
+          else    // Checking if XHTML Named Entity
+          {
+            entityCode = const_cast<char*> ( NamedEntityToUtf8( markupBuffer, len ) );
+            result = ( entityCode != NULL );
+          }
+          if ( result )
+          {
+            markupBuffer = entityCode; //utf8 text assigned to markupBuffer
+            character = markupBuffer[0];
+          }
+          else
+          {
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not valid XHTML entity : (%.*s) \n", len, markupBuffer );
+            markupBuffer = NULL;
+          }
+        }
+        else    // in case string conatins Start of XHTML Entity('&') but not its end character(';')
+        {
+          if( character == AMPERSAND )
+          {
+            markupBuffer = NULL;
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Not Well formed XHTML content \n" );
+          }
+        }
+      }
+
+      if( markupBuffer != NULL )
+      {
+        const unsigned char numberOfBytes = GetUtf8Length( character );
+        markupProcessData.markupProcessedText.push_back( character );
+
+        for( unsigned char i = 1u; i < numberOfBytes; ++i )
+        {
+          ++markupBuffer;
+          markupProcessData.markupProcessedText.push_back( *markupBuffer );
+        }
+
+        ++characterIndex;
+        markupStringBuffer += count;
+      }
+    }
+  }
+
+  // Resize the model's vectors.
+  if( 0u == fontRunIndex )
+  {
+    markupProcessData.fontRuns.Clear();
+  }
+  else
+  {
+    markupProcessData.fontRuns.Resize( fontRunIndex );
+  }
+
+  if( 0u == colorRunIndex )
+  {
+    markupProcessData.colorRuns.Clear();
+  }
+  else
+  {
+    markupProcessData.colorRuns.Resize( colorRunIndex );
+
+#ifdef DEBUG_ENABLED
+    for( unsigned int i=0; i<colorRunIndex; ++i )
+    {
+      ColorRun& run = markupProcessData.colorRuns[i];
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "run[%d] index: %d, length: %d, color %f,%f,%f,%f\n", i, run.characterRun.characterIndex, run.characterRun.numberOfCharacters, run.color.r, run.color.g, run.color.b, run.color.a );
+    }
+#endif
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor.h b/dali-toolkit/internal/text/markup-processor.h
new file mode 100755 (executable)
index 0000000..de66e7f
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/embedded-item.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Keeps the plain text and references to vectors from the model which stores runs with text styles.
+ */
+struct MarkupProcessData
+{
+MarkupProcessData( Vector<ColorRun>& colorRuns,
+                   Vector<FontDescriptionRun>& fontRuns,
+                   Vector<EmbeddedItem>& items )
+  : colorRuns( colorRuns ),
+    fontRuns( fontRuns ),
+    items(items),
+    markupProcessedText()
+  {}
+
+  Vector<ColorRun>&           colorRuns;           ///< The color runs.
+  Vector<FontDescriptionRun>& fontRuns;            ///< The font description runs.
+  Vector<EmbeddedItem>&       items;               ///< The embedded items.
+  std::string                 markupProcessedText; ///< The mark-up string.
+};
+
+/**
+ * @brief Process the mark-up string.
+ *
+ * @param[in] markupString The mark-up string.
+ * @param[out] markupProcessData The plain text and the style.
+ */
+void ProcessMarkupString( const std::string& markupString, MarkupProcessData& markupProcessData );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H
diff --git a/dali-toolkit/internal/text/metrics.h b/dali-toolkit/internal/text/metrics.h
new file mode 100755 (executable)
index 0000000..d85fff4
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef DALI_TOOLKIT_TEXT_METRICS_H
+#define DALI_TOOLKIT_TEXT_METRICS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class Metrics;
+typedef IntrusivePtr<Metrics> MetricsPtr;
+
+/**
+ * @brief A wrapper around FontClient used to get metrics.
+ */
+class Metrics : public RefObject
+{
+public:
+
+  /**
+   * Create a new Metrics object
+   */
+  static Metrics* New( TextAbstraction::FontClient& fontClient )
+  {
+    return new Metrics( fontClient );
+  }
+
+  /**
+   * @brief Used to switch between bitmap & vector based glyphs
+   *
+   * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
+   */
+  void SetGlyphType( TextAbstraction::GlyphType glyphType )
+  {
+    mGlyphType = glyphType;
+  }
+
+  /**
+   * @brief Query the metrics for a font.
+   *
+   * @param[in] fontId The ID of the font for the required glyph.
+   * @param[out] metrics The font metrics.
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics )
+  {
+    mFontClient.GetFontMetrics( fontId, metrics ); // inline for performance
+  }
+
+  /**
+   * @brief Retrieve the metrics for a series of glyphs.
+   *
+   * @param[in,out] array An array of glyph-info structures with initialized FontId & GlyphIndex values.
+   * It may contain the advance and an offset set into the bearing from the shaping tool.
+   * On return, the glyph's size value will be initialized. The bearing value will be updated by adding the font's glyph bearing to the one set by the shaping tool.
+   * @param[in] size The size of the array.
+   * @return True if all of the requested metrics were found.
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size )
+  {
+    return mFontClient.GetGlyphMetrics( array, size, mGlyphType, true ); // inline for performance
+  }
+
+  /**
+   * @brief Whether the font has Italic style.
+   *
+   * @param[in] fontId The font identifier.
+   *
+   * @return true if the font has italic style.
+   */
+  bool HasItalicStyle( FontId fontId ) const
+  {
+    return mFontClient.HasItalicStyle( fontId );
+  }
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Metrics() {}
+
+private:
+
+  /**
+   * Constructor.
+   */
+  Metrics( TextAbstraction::FontClient& fontClient )
+  : mFontClient( fontClient ),
+    mGlyphType( TextAbstraction::BITMAP_GLYPH )
+  {}
+
+  // Undefined
+  Metrics(const Metrics&);
+
+  // Undefined
+  Metrics& operator=(const Metrics& rhs);
+
+private:
+
+  TextAbstraction::FontClient mFontClient;
+  TextAbstraction::GlyphType mGlyphType;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_METRICS_H
diff --git a/dali-toolkit/internal/text/multi-language-helper-functions.cpp b/dali-toolkit/internal/text/multi-language-helper-functions.cpp
new file mode 100644 (file)
index 0000000..3fad598
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/multi-language-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
+                            const TextAbstraction::FontDescription& defaultFontDescription,
+                            TextAbstraction::PointSize26Dot6 defaultPointSize,
+                            CharacterIndex characterIndex,
+                            TextAbstraction::FontDescription& fontDescription,
+                            TextAbstraction::PointSize26Dot6& fontPointSize,
+                            bool& isDefaultFont )
+{
+  // Initialize with the default font's point size.
+  fontPointSize = defaultPointSize;
+
+  // Initialize with the style parameters of the default font's style.
+  fontDescription = defaultFontDescription;
+
+  // Initialize as a default font.
+  isDefaultFont = true;
+
+  Length runIndex = 0u;
+
+  Length familyIndex = 0u;
+  Length weightIndex = 0u;
+  Length widthIndex = 0u;
+  Length slantIndex = 0u;
+  Length sizeIndex = 0u;
+
+  bool familyOverriden = false;
+  bool weightOverriden = false;
+  bool widthOverriden = false;
+  bool slantOverriden = false;
+  bool sizeOverriden = false;
+
+  // Traverse all the font descriptions.
+  const FontDescriptionRun* const fontDescriptionsBuffer = fontDescriptions.Begin();
+  for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionsBuffer,
+         endIt = fontDescriptions.End();
+       it != endIt;
+       ++it, ++runIndex )
+  {
+    // Check whether the character's font is modified by the current font description.
+    const FontDescriptionRun& fontRun = *it;
+    if( ( characterIndex >= fontRun.characterRun.characterIndex ) &&
+        ( characterIndex < fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters ) )
+    {
+      if( fontRun.familyDefined )
+      {
+        isDefaultFont = false;
+        familyOverriden = true;
+        familyIndex = runIndex;
+      }
+      if( fontRun.weightDefined )
+      {
+        isDefaultFont = false;
+        weightOverriden = true;
+        weightIndex = runIndex;
+      }
+      if( fontRun.widthDefined )
+      {
+        isDefaultFont = false;
+        widthOverriden = true;
+        widthIndex = runIndex;
+      }
+      if( fontRun.slantDefined )
+      {
+        isDefaultFont = false;
+        slantOverriden = true;
+        slantIndex = runIndex;
+      }
+      if( fontRun.sizeDefined )
+      {
+        isDefaultFont = false;
+        sizeOverriden = true;
+        sizeIndex = runIndex;
+      }
+    }
+  }
+
+  // Get the font's description if is not the default font.
+  if( !isDefaultFont )
+  {
+    if( familyOverriden )
+    {
+      const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + familyIndex );
+      fontDescription.family = std::string( fontRun.familyName, fontRun.familyLength );
+    }
+
+    if( weightOverriden )
+    {
+      const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + weightIndex );
+      fontDescription.weight = fontRun.weight;
+    }
+
+    if( widthOverriden )
+    {
+      const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + widthIndex );
+      fontDescription.width = fontRun.width;
+    }
+
+    if( slantOverriden )
+    {
+      const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + slantIndex );
+      fontDescription.slant = fontRun.slant;
+    }
+
+    if( sizeOverriden )
+    {
+      const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + sizeIndex );
+      fontPointSize = fontRun.size;
+    }
+  }
+}
+
+Script GetScript( Length index,
+                  Vector<ScriptRun>::ConstIterator& scriptRunIt,
+                  const Vector<ScriptRun>::ConstIterator& scriptRunEndIt )
+{
+  Script script = TextAbstraction::UNKNOWN;
+
+  while( scriptRunIt != scriptRunEndIt )
+  {
+    const ScriptRun& scriptRun = *scriptRunIt;
+
+    if( index >= scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
+    {
+      ++scriptRunIt;
+    }
+    else if( index >= scriptRun.characterRun.characterIndex )
+    {
+      script = scriptRun.script;
+
+      if( index + 1u == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
+      {
+        // All the characters of the current run have been traversed. Get the next one for the next iteration.
+        ++scriptRunIt;
+      }
+
+      break;
+    }
+  }
+
+  return script;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/multi-language-helper-functions.h b/dali-toolkit/internal/text/multi-language-helper-functions.h
new file mode 100644 (file)
index 0000000..c5dc7cd
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Merges font's descriptions to retrieve the combined font's description for a given character.
+ *
+ * @param[in] fontDescriptions The font's descriptions for the whole text.
+ * @param[in] defaultFontDescription The default font's description.
+ * @param[in] defaultPointSize The default font's point size.
+ * @param[in] characterIndex Index to the character to retrieve its font's description.
+ * @param[out] fontDescription The font's description for the character.
+ * @param[out] fontPointSize The font's point size for the character.
+ * @param[out] isDefaultFont Whether the font is a default one.
+ */
+void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
+                            const TextAbstraction::FontDescription& defaultFontDescription,
+                            TextAbstraction::PointSize26Dot6 defaultPointSize,
+                            CharacterIndex characterIndex,
+                            TextAbstraction::FontDescription& fontDescription,
+                            TextAbstraction::PointSize26Dot6& fontPointSize,
+                            bool& isDefaultFont );
+
+/**
+ * @brief Retrieves the script Id from the script run for a given character's @p index.
+ *
+ * If the character's index exceeds the current script run it increases the iterator to get the next one.
+ *
+ * @param[in] index The character's index.
+ * @param[in,out] scriptRunIt Iterator to the current script run.
+ * @param[in] scriptRunEndIt Iterator to one after the last script run.
+ *
+ * @return The script.
+ */
+Script GetScript( Length index,
+                  Vector<ScriptRun>::ConstIterator& scriptRunIt,
+                  const Vector<ScriptRun>::ConstIterator& scriptRunEndIt );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_HELPER_FUNCTIONS_H
diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp
new file mode 100755 (executable)
index 0000000..99a969c
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/multi-language-support-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/multi-language-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_MULTI_LANGUAGE_SUPPORT");
+#endif
+
+const Dali::Toolkit::Text::Character UTF32_A = 0x0041;
+}
+
+namespace Text
+{
+
+namespace Internal
+{
+
+bool ValidateFontsPerScript::IsValidFont( FontId fontId ) const
+{
+  for( Vector<FontId>::ConstIterator it = mValidFonts.Begin(),
+         endIt = mValidFonts.End();
+       it != endIt;
+       ++it )
+  {
+    if( fontId == *it )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+FontId DefaultFonts::FindFont( TextAbstraction::FontClient& fontClient,
+                               const TextAbstraction::FontDescription& description,
+                               PointSize26Dot6 size ) const
+{
+  for( std::vector<CacheItem>::const_iterator it = mFonts.begin(),
+         endIt = mFonts.end();
+       it != endIt;
+       ++it )
+  {
+    const CacheItem& item = *it;
+
+    if( ( ( TextAbstraction::FontWeight::NONE == description.weight ) || ( description.weight == item.description.weight ) ) &&
+        ( ( TextAbstraction::FontWidth::NONE == description.width )   || ( description.width == item.description.width ) ) &&
+        ( ( TextAbstraction::FontSlant::NONE == description.slant )   || ( description.slant == item.description.slant ) ) &&
+        ( size == fontClient.GetPointSize( item.fontId ) ) &&
+        ( description.family.empty() || ( description.family == item.description.family ) ) )
+    {
+      return item.fontId;
+    }
+  }
+
+  return 0u;
+}
+
+void DefaultFonts::Cache( const TextAbstraction::FontDescription& description, FontId fontId )
+{
+  CacheItem item;
+  item.description = description;
+  item.fontId = fontId;
+  mFonts.push_back( item );
+}
+
+MultilanguageSupport::MultilanguageSupport()
+: mDefaultFontPerScriptCache(),
+  mValidFontsPerScriptCache()
+{
+  // Initializes the default font cache to zero (invalid font).
+  // Reserves space to cache the default fonts and access them with the script as an index.
+  mDefaultFontPerScriptCache.Resize( TextAbstraction::UNKNOWN + 1, NULL );
+
+  // Initializes the valid fonts cache to NULL (no valid fonts).
+  // Reserves space to cache the valid fonts and access them with the script as an index.
+  mValidFontsPerScriptCache.Resize( TextAbstraction::UNKNOWN + 1, NULL );
+}
+
+MultilanguageSupport::~MultilanguageSupport()
+{
+  // Destroy the default font per script cache.
+  for( Vector<DefaultFonts*>::Iterator it = mDefaultFontPerScriptCache.Begin(),
+         endIt = mDefaultFontPerScriptCache.End();
+       it != endIt;
+       ++it )
+  {
+    delete *it;
+  }
+
+  // Destroy the valid fonts per script cache.
+  for( Vector<ValidateFontsPerScript*>::Iterator it = mValidFontsPerScriptCache.Begin(),
+         endIt = mValidFontsPerScriptCache.End();
+       it != endIt;
+       ++it )
+  {
+    delete *it;
+  }
+}
+
+Text::MultilanguageSupport MultilanguageSupport::Get()
+{
+  Text::MultilanguageSupport multilanguageSupportHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Text::MultilanguageSupport ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      MultilanguageSupport* impl = dynamic_cast< Internal::MultilanguageSupport* >( handle.GetObjectPtr() );
+      multilanguageSupportHandle = Text::MultilanguageSupport( impl );
+    }
+    else // create and register the object
+    {
+      multilanguageSupportHandle = Text::MultilanguageSupport( new MultilanguageSupport );
+      service.Register( typeid( multilanguageSupportHandle ), multilanguageSupportHandle );
+    }
+  }
+
+  return multilanguageSupportHandle;
+}
+
+void MultilanguageSupport::SetScripts( const Vector<Character>& text,
+                                       CharacterIndex startIndex,
+                                       Length numberOfCharacters,
+                                       Vector<ScriptRun>& scripts )
+{
+  if( 0u == numberOfCharacters )
+  {
+    // Nothing to do if there are no characters.
+    return;
+  }
+
+  // Find the first index where to insert the script.
+  ScriptRunIndex scriptIndex = 0u;
+  if( 0u != startIndex )
+  {
+    for( Vector<ScriptRun>::ConstIterator it = scripts.Begin(),
+           endIt = scripts.End();
+         it != endIt;
+         ++it, ++scriptIndex )
+    {
+      const ScriptRun& run = *it;
+      if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+      {
+        // Run found.
+        break;
+      }
+    }
+  }
+
+  // Stores the current script run.
+  ScriptRun currentScriptRun;
+  currentScriptRun.characterRun.characterIndex = startIndex;
+  currentScriptRun.characterRun.numberOfCharacters = 0u;
+  currentScriptRun.script = TextAbstraction::UNKNOWN;
+
+  // Reserve some space to reduce the number of reallocations.
+  scripts.Reserve( text.Count() << 2u );
+
+  // Whether the first valid script needs to be set.
+  bool isFirstScriptToBeSet = true;
+
+  // Whether the first valid script is a right to left script.
+  bool isParagraphRTL = false;
+
+  // Count the number of characters which are valid for all scripts. i.e. white spaces or '\n'.
+  Length numberOfAllScriptCharacters = 0u;
+
+  // Pointers to the text buffer.
+  const Character* const textBuffer = text.Begin();
+
+  // Initialize whether is right to left direction
+  currentScriptRun.isRightToLeft = false;
+
+  // Traverse all characters and set the scripts.
+  const Length lastCharacter = startIndex + numberOfCharacters;
+  for( Length index = startIndex; index < lastCharacter; ++index )
+  {
+    Character character = *( textBuffer + index );
+
+    // Get the script of the character.
+    Script script = TextAbstraction::GetCharacterScript( character );
+
+    // Some characters (like white spaces) are valid for many scripts. The rules to set a script
+    // for them are:
+    // - If they are at the begining of a paragraph they get the script of the first character with
+    //   a defined script. If they are at the end, they get the script of the last one.
+    // - If they are between two scripts with the same direction, they get the script of the previous
+    //   character with a defined script. If the two scripts have different directions, they get the
+    //   script of the first character of the paragraph with a defined script.
+
+    // Skip those characters valid for many scripts like white spaces or '\n'.
+    bool endOfText = index == lastCharacter;
+    while( !endOfText &&
+           ( TextAbstraction::COMMON == script ) )
+    {
+      // Check if whether is right to left markup and Keeps true if the previous value was true.
+      currentScriptRun.isRightToLeft = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftMark( character );
+
+      if( TextAbstraction::EMOJI == currentScriptRun.script )
+      {
+        // Emojis doesn't mix well with characters common to all scripts. Insert the emoji run.
+        scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun );
+        ++scriptIndex;
+
+        // Initialize the new one.
+        currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
+        currentScriptRun.characterRun.numberOfCharacters = 0u;
+        currentScriptRun.script = TextAbstraction::UNKNOWN;
+        numberOfAllScriptCharacters = 0u;
+      }
+
+      // Count all these characters to be added into a script.
+      ++numberOfAllScriptCharacters;
+
+      if( TextAbstraction::IsNewParagraph( character ) )
+      {
+        // The character is a new paragraph.
+        // To know when there is a new paragraph is needed because if there is a white space
+        // between two scripts with different directions, it is added to the script with
+        // the same direction than the first script of the paragraph.
+        isFirstScriptToBeSet = true;
+
+        // Characters common to all scripts at the end of the paragraph are added to the last script.
+        currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+
+        // Store the script run.
+        scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun );
+        ++scriptIndex;
+
+        // Initialize the new one.
+        currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
+        currentScriptRun.characterRun.numberOfCharacters = 0u;
+        currentScriptRun.script = TextAbstraction::UNKNOWN;
+        numberOfAllScriptCharacters = 0u;
+        // Initialize whether is right to left direction
+        currentScriptRun.isRightToLeft = false;
+      }
+
+      // Get the next character.
+      ++index;
+      endOfText = index == lastCharacter;
+      if( !endOfText )
+      {
+        character = *( textBuffer + index );
+        script = TextAbstraction::GetCharacterScript( character );
+      }
+    } // end while( !endOfText && ( TextAbstraction::COMMON == script ) )
+
+    if( endOfText )
+    {
+      // Last characters of the text are 'white spaces'.
+      // There is nothing else to do. Just add the remaining characters to the last script after this bucle.
+      break;
+    }
+
+    // Check if it is the first character of a paragraph.
+    if( isFirstScriptToBeSet &&
+        ( TextAbstraction::UNKNOWN != script ) &&
+        ( TextAbstraction::COMMON != script ) &&
+        ( TextAbstraction::EMOJI != script ) )
+    {
+      // Sets the direction of the first valid script.
+      isParagraphRTL = currentScriptRun.isRightToLeft || TextAbstraction::IsRightToLeftScript( script );
+      isFirstScriptToBeSet = false;
+    }
+
+    if( ( script != currentScriptRun.script ) &&
+        ( TextAbstraction::COMMON != script ) )
+    {
+      // Current run needs to be stored and a new one initialized.
+
+      if( ( isParagraphRTL == TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) ) &&
+          ( TextAbstraction::UNKNOWN != currentScriptRun.script ) )
+      {
+        // Previous script has the same direction than the first script of the paragraph.
+        // All the previously skipped characters need to be added to the previous script before it's stored.
+        currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+        numberOfAllScriptCharacters = 0u;
+      }
+      else if( ( TextAbstraction::IsRightToLeftScript( currentScriptRun.script ) == TextAbstraction::IsRightToLeftScript( script ) ) &&
+               ( TextAbstraction::UNKNOWN != currentScriptRun.script ) )
+      {
+        // Current script and previous one have the same direction.
+        // All the previously skipped characters need to be added to the previous script before it's stored.
+        currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+        numberOfAllScriptCharacters = 0u;
+      }
+      else if( ( TextAbstraction::UNKNOWN == currentScriptRun.script ) &&
+               ( TextAbstraction::EMOJI == script ) )
+      {
+        currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+        numberOfAllScriptCharacters = 0u;
+      }
+
+      if( 0u != currentScriptRun.characterRun.numberOfCharacters )
+      {
+        // Store the script run.
+        scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun );
+        ++scriptIndex;
+      }
+
+      // Initialize the new one.
+      currentScriptRun.characterRun.characterIndex = currentScriptRun.characterRun.characterIndex + currentScriptRun.characterRun.numberOfCharacters;
+      currentScriptRun.characterRun.numberOfCharacters = numberOfAllScriptCharacters + 1u; // Adds the white spaces which are at the begining of the script.
+      currentScriptRun.script = script;
+      numberOfAllScriptCharacters = 0u;
+      // Check if whether is right to left script.
+      currentScriptRun.isRightToLeft = TextAbstraction::IsRightToLeftScript( currentScriptRun.script );
+    }
+    else
+    {
+      if( TextAbstraction::UNKNOWN != currentScriptRun.script )
+      {
+        // Adds white spaces between characters.
+        currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+        numberOfAllScriptCharacters = 0u;
+      }
+
+      // Add one more character to the run.
+      ++currentScriptRun.characterRun.numberOfCharacters;
+    }
+  }
+
+  // Add remaining characters into the last script.
+  currentScriptRun.characterRun.numberOfCharacters += numberOfAllScriptCharacters;
+
+  if( 0u != currentScriptRun.characterRun.numberOfCharacters )
+  {
+    // Store the last run.
+    scripts.Insert( scripts.Begin() + scriptIndex, currentScriptRun );
+    ++scriptIndex;
+  }
+
+  if( scriptIndex < scripts.Count() )
+  {
+    // Update the indices of the next script runs.
+    const ScriptRun& run = *( scripts.Begin() + scriptIndex - 1u );
+    CharacterIndex nextCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+    for( Vector<ScriptRun>::Iterator it = scripts.Begin() + scriptIndex,
+           endIt = scripts.End();
+         it != endIt;
+         ++it )
+    {
+      ScriptRun& run = *it;
+      run.characterRun.characterIndex = nextCharacterIndex;
+      nextCharacterIndex += run.characterRun.numberOfCharacters;
+    }
+  }
+}
+
+void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
+                                          const Vector<ScriptRun>& scripts,
+                                          const Vector<FontDescriptionRun>& fontDescriptions,
+                                          const TextAbstraction::FontDescription& defaultFontDescription,
+                                          TextAbstraction::PointSize26Dot6 defaultFontPointSize,
+                                          CharacterIndex startIndex,
+                                          Length numberOfCharacters,
+                                          Vector<FontRun>& fonts )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->MultilanguageSupport::ValidateFonts\n" );
+
+  if( 0u == numberOfCharacters )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "<--MultilanguageSupport::ValidateFonts\n" );
+    // Nothing to do if there are no characters.
+    return;
+  }
+
+  // Find the first index where to insert the font run.
+  FontRunIndex fontIndex = 0u;
+  if( 0u != startIndex )
+  {
+    for( Vector<FontRun>::ConstIterator it = fonts.Begin(),
+           endIt = fonts.End();
+         it != endIt;
+         ++it, ++fontIndex )
+    {
+      const FontRun& run = *it;
+      if( startIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+      {
+        // Run found.
+        break;
+      }
+    }
+  }
+
+  // Traverse the characters and validate/set the fonts.
+
+  // Get the caches.
+  DefaultFonts** defaultFontPerScriptCacheBuffer = mDefaultFontPerScriptCache.Begin();
+  ValidateFontsPerScript** validFontsPerScriptCacheBuffer = mValidFontsPerScriptCache.Begin();
+
+  // Stores the validated font runs.
+  fonts.Reserve( fontDescriptions.Count() );
+
+  // Initializes a validated font run.
+  FontRun currentFontRun;
+  currentFontRun.characterRun.characterIndex = startIndex;
+  currentFontRun.characterRun.numberOfCharacters = 0u;
+  currentFontRun.fontId = 0u;
+  currentFontRun.isBoldRequired = false;
+  currentFontRun.isItalicRequired = false;
+
+  // Get the font client.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  const Character* const textBuffer = text.Begin();
+
+  // Iterators of the script runs.
+  Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
+  Vector<ScriptRun>::ConstIterator scriptRunEndIt = scripts.End();
+  bool isNewParagraphCharacter = false;
+
+  bool isPreviousEmojiScript = false;
+
+  CharacterIndex lastCharacter = startIndex + numberOfCharacters;
+  for( Length index = startIndex; index < lastCharacter; ++index )
+  {
+    // Get the current character.
+    const Character character = *( textBuffer + index );
+    bool isItalicRequired = false;
+    bool isBoldRequired = false;
+
+    // new description for current character
+    TextAbstraction::FontDescription currentFontDescription;
+    TextAbstraction::PointSize26Dot6 currentFontPointSize = defaultFontPointSize;
+    bool isDefaultFont = true;
+    MergeFontDescriptions( fontDescriptions,
+                           defaultFontDescription,
+                           defaultFontPointSize,
+                           index,
+                           currentFontDescription,
+                           currentFontPointSize,
+                           isDefaultFont );
+
+    // Get the font for the current character.
+    FontId fontId = fontClient.GetFontId( currentFontDescription, currentFontPointSize );
+
+    // Get the script for the current character.
+    Script script = GetScript( index,
+                               scriptRunIt,
+                               scriptRunEndIt );
+
+#ifdef DEBUG_ENABLED
+    {
+      Dali::TextAbstraction::FontDescription description;
+      fontClient.GetDescription( fontId, description );
+
+      DALI_LOG_INFO( gLogFilter,
+                     Debug::Verbose,
+                     "  Initial font set\n  Character : %x, Script : %s, Font : %s \n",
+                     character,
+                     Dali::TextAbstraction::ScriptName[script],
+                     description.path.c_str() );
+    }
+#endif
+
+    // Validate whether the current character is supported by the given font.
+    bool isValidFont = false;
+
+    // Check first in the cache of default fonts per script and size.
+
+    FontId cachedDefaultFontId = 0u;
+    DefaultFonts* defaultFonts = *( defaultFontPerScriptCacheBuffer + script );
+    if( NULL != defaultFonts )
+    {
+      // This cache stores fall-back fonts.
+      cachedDefaultFontId = defaultFonts->FindFont( fontClient,
+                                                    currentFontDescription,
+                                                    currentFontPointSize );
+    }
+
+    // Whether the cached default font is valid.
+    const bool isValidCachedDefaultFont = 0u != cachedDefaultFontId;
+
+    // The font is valid if it matches with the default one for the current script and size and it's different than zero.
+    isValidFont = isValidCachedDefaultFont && ( fontId == cachedDefaultFontId );
+
+    if( isValidFont )
+    {
+      // Check if the font supports the character.
+      isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character );
+    }
+
+    bool isCommonScript = false;
+    bool isEmojiScript = TextAbstraction::EMOJI == script;
+
+    if( isEmojiScript && !isPreviousEmojiScript )
+    {
+      if( 0u != currentFontRun.characterRun.numberOfCharacters )
+      {
+        // Store the font run.
+        fonts.Insert( fonts.Begin() + fontIndex, currentFontRun );
+        ++fontIndex;
+      }
+
+      // Initialize the new one.
+      currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters;
+      currentFontRun.characterRun.numberOfCharacters = 0u;
+      currentFontRun.fontId = fontId;
+      currentFontRun.isItalicRequired = false;
+      currentFontRun.isBoldRequired = false;
+    }
+
+    // If the given font is not valid, it means either:
+    // - there is no cached font for the current script yet or,
+    // - the user has set a different font than the default one for the current script or,
+    // - the platform default font is different than the default font for the current script.
+
+    // Need to check if the given font supports the current character.
+    if( !isValidFont ) // (1)
+    {
+      // Whether the current character is common for all scripts (i.e. white spaces, ...)
+
+      // Is not desirable to cache fonts for the common script.
+      //
+      // i.e. Consider the text " हिंदी", the 'white space' has assigned the DEVANAGARI script.
+      //      The user may have set a font or the platform's default is used.
+      //
+      //      As the 'white space' is the first character, no font is cached so the font validation
+      //      retrieves a glyph from the given font.
+      //
+      //      Many fonts support 'white spaces' so probably the font set by the user or the platform's default
+      //      supports the 'white space'. However, that font may not support the DEVANAGARI script.
+      isCommonScript = TextAbstraction::IsCommonScript( character );
+
+      // Check in the valid fonts cache.
+      ValidateFontsPerScript* validateFontsPerScript = *( validFontsPerScriptCacheBuffer + script );
+
+      if( NULL != validateFontsPerScript )
+      {
+        // This cache stores valid fonts set by the user.
+        isValidFont = validateFontsPerScript->IsValidFont( fontId );
+
+        // It may happen that a validated font for a script doesn't have all the glyphs for that script.
+        // i.e a font validated for the CJK script may contain glyphs for the chinese language but not for the Japanese.
+        if( isValidFont )
+        {
+          // Checks if the current character is supported by the font is needed.
+          isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character );
+        }
+      }
+
+      if( !isValidFont ) // (2)
+      {
+        // The selected font is not stored in any cache.
+
+        // Checks if the current character is supported by the selected font.
+        isValidFont = fontClient.IsCharacterSupportedByFont( fontId, character );
+
+        // If there is a valid font, cache it.
+        if( isValidFont && !isCommonScript )
+        {
+          if( NULL == validateFontsPerScript )
+          {
+            validateFontsPerScript = new ValidateFontsPerScript();
+
+            *( validFontsPerScriptCacheBuffer + script ) = validateFontsPerScript;
+          }
+
+          validateFontsPerScript->mValidFonts.PushBack( fontId );
+        }
+
+        if( !isValidFont && ( fontId != cachedDefaultFontId ) && ( !TextAbstraction::IsNewParagraph( character ) )) // (3)
+        {
+          // The selected font by the user or the platform's default font has failed to validate the character.
+
+          // Checks if the previously discarted cached default font supports the character.
+          bool isValidCachedFont = false;
+          if( isValidCachedDefaultFont )
+          {
+            isValidCachedFont = fontClient.IsCharacterSupportedByFont( cachedDefaultFontId, character );
+          }
+
+          if( isValidCachedFont )
+          {
+            // Use the cached default font for the script if there is one.
+            fontId = cachedDefaultFontId;
+          }
+          else
+          {
+            // There is no valid cached default font for the script.
+
+            DefaultFonts* defaultFontsPerScript = NULL;
+
+            // Find a fallback-font.
+            fontId = fontClient.FindFallbackFont( character,
+                                                  currentFontDescription,
+                                                  currentFontPointSize,
+                                                  false );
+
+            if( 0u == fontId )
+            {
+              fontId = fontClient.FindDefaultFont( UTF32_A, currentFontPointSize );
+            }
+
+            if ( !isCommonScript && (script != TextAbstraction::UNKNOWN) )
+            {
+              // Cache the font if it is not an unknown script
+              if( NULL == defaultFontsPerScript )
+              {
+                defaultFontsPerScript = *( defaultFontPerScriptCacheBuffer + script );
+
+                if( NULL == defaultFontsPerScript )
+                {
+                  defaultFontsPerScript = new DefaultFonts();
+                  *( defaultFontPerScriptCacheBuffer + script ) = defaultFontsPerScript;
+                }
+              }
+              defaultFontsPerScript->Cache( currentFontDescription, fontId );
+            }
+          }
+        } // !isValidFont (3)
+      } // !isValidFont (2)
+    } // !isValidFont (1)
+
+#ifdef DEBUG_ENABLED
+    {
+      Dali::TextAbstraction::FontDescription description;
+      fontClient.GetDescription( fontId, description );
+      DALI_LOG_INFO( gLogFilter,
+                     Debug::Verbose,
+                     "  Validated font set\n  Character : %x, Script : %s, Font : %s \n",
+                     character,
+                     Dali::TextAbstraction::ScriptName[script],
+                     description.path.c_str() );
+    }
+#endif
+
+    // Whether bols style is required.
+    isBoldRequired = ( currentFontDescription.weight >= TextAbstraction::FontWeight::BOLD );
+
+    // Whether italic style is required.
+    isItalicRequired = ( currentFontDescription.slant >= TextAbstraction::FontSlant::ITALIC );
+
+    // The font is now validated.
+    if( ( fontId != currentFontRun.fontId ) ||
+        isNewParagraphCharacter ||
+        // If font id is same as previous but style is diffrent, initialize new one
+        ( ( fontId == currentFontRun.fontId ) && ( ( isBoldRequired != currentFontRun.isBoldRequired ) || ( isItalicRequired != currentFontRun.isItalicRequired ) ) ) )
+    {
+      // Current run needs to be stored and a new one initialized.
+
+      if( 0u != currentFontRun.characterRun.numberOfCharacters )
+      {
+        // Store the font run.
+        fonts.Insert( fonts.Begin() + fontIndex, currentFontRun );
+        ++fontIndex;
+      }
+
+      // Initialize the new one.
+      currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters;
+      currentFontRun.characterRun.numberOfCharacters = 0u;
+      currentFontRun.fontId = fontId;
+      currentFontRun.isBoldRequired = isBoldRequired;
+      currentFontRun.isItalicRequired = isItalicRequired;
+    }
+
+    // Add one more character to the run.
+    ++currentFontRun.characterRun.numberOfCharacters;
+
+    // Whether the current character is a new paragraph character.
+    isNewParagraphCharacter = TextAbstraction::IsNewParagraph( character );
+    isPreviousEmojiScript = isEmojiScript;
+  } // end traverse characters.
+
+  if( 0u != currentFontRun.characterRun.numberOfCharacters )
+  {
+    // Store the last run.
+    fonts.Insert( fonts.Begin() + fontIndex, currentFontRun );
+    ++fontIndex;
+  }
+
+  if( fontIndex < fonts.Count() )
+  {
+    // Update the indices of the next font runs.
+    const FontRun& run = *( fonts.Begin() + fontIndex - 1u );
+    CharacterIndex nextCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+    for( Vector<FontRun>::Iterator it = fonts.Begin() + fontIndex,
+           endIt = fonts.End();
+         it != endIt;
+         ++it )
+    {
+      FontRun& run = *it;
+
+      run.characterRun.characterIndex = nextCharacterIndex;
+      nextCharacterIndex += run.characterRun.numberOfCharacters;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--MultilanguageSupport::ValidateFonts\n" );
+}
+
+} // namespace Internal
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/multi-language-support-impl.h b/dali-toolkit/internal/text/multi-language-support-impl.h
new file mode 100644 (file)
index 0000000..cc6c985
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H
+#define DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/multi-language-support.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+//Forward declaration
+class FontClient;
+}
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Stores valid font ids per script.
+ */
+struct ValidateFontsPerScript
+{
+  /**
+   * Default constructor.
+   */
+  ValidateFontsPerScript()
+  : mValidFonts()
+  {}
+
+  /**
+   * Default destructor.
+   */
+  ~ValidateFontsPerScript()
+  {}
+
+  /**
+   * @brief Whether the given @p fontId is in the vector of valid fonts.
+   *
+   * @param[in] fontId The font id.
+   *
+   * @return @e true if the font is in the vector of valid fonts.
+   */
+  bool IsValidFont( FontId fontId ) const;
+
+  Vector<FontId> mValidFonts;
+};
+
+/**
+ * @brief Stores default font ids per script. It can be different sizes for a default font family.
+ */
+struct DefaultFonts
+{
+  struct CacheItem
+  {
+    TextAbstraction::FontDescription description;
+    FontId fontId;
+  };
+
+  /**
+   * Default constructor.
+   */
+  DefaultFonts()
+  : mFonts()
+  {}
+
+  /**
+   * Default destructor.
+   */
+  ~DefaultFonts()
+  {}
+
+  /**
+   * @brief Finds a default font for the given @p size.
+   *
+   * @param[in] fontClient The font client.
+   * @param[in] description The font's description.
+   * @param[in] size The given size.
+   *
+   * @return The font id of a default font for the given @p size. If there isn't any font cached it returns 0.
+   */
+  FontId FindFont( TextAbstraction::FontClient& fontClient,
+                   const TextAbstraction::FontDescription& description,
+                   PointSize26Dot6 size ) const;
+
+  void Cache( const TextAbstraction::FontDescription& description, FontId fontId );
+
+  std::vector<CacheItem> mFonts;
+};
+
+/**
+ * @brief Multi-language support implementation. @see Text::MultilanguageSupport.
+ */
+class MultilanguageSupport : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  MultilanguageSupport();
+
+  /**
+   * Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~MultilanguageSupport();
+
+  /**
+   * @copydoc Dali::MultilanguageSupport::Get()
+   */
+  static Text::MultilanguageSupport Get();
+
+  /**
+   * @copydoc Dali::MultilanguageSupport::SetScripts()
+   */
+  void SetScripts( const Vector<Character>& text,
+                   CharacterIndex startIndex,
+                   Length numberOfCharacters,
+                   Vector<ScriptRun>& scripts );
+
+  /**
+   * @copydoc Dali::MultilanguageSupport::ValidateFonts()
+   */
+  void ValidateFonts( const Vector<Character>& text,
+                      const Vector<ScriptRun>& scripts,
+                      const Vector<FontDescriptionRun>& fontDescriptions,
+                      const TextAbstraction::FontDescription& defaultFontDescription,
+                      TextAbstraction::PointSize26Dot6 defaultFontPointSize,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
+                      Vector<FontRun>& fonts );
+
+private:
+  Vector<DefaultFonts*>           mDefaultFontPerScriptCache; ///< Caches default fonts for a script.
+  Vector<ValidateFontsPerScript*> mValidFontsPerScriptCache;  ///< Caches valid fonts for a script.
+};
+
+} // namespace Internal
+
+inline static Internal::MultilanguageSupport& GetImplementation( MultilanguageSupport& multilanguageSupport )
+{
+  DALI_ASSERT_ALWAYS( multilanguageSupport && "multi-language handle is empty" );
+  BaseObject& handle = multilanguageSupport.GetBaseObject();
+  return static_cast<Internal::MultilanguageSupport&>( handle );
+}
+
+inline static const Internal::MultilanguageSupport& GetImplementation( const MultilanguageSupport& multilanguageSupport )
+{
+  DALI_ASSERT_ALWAYS( multilanguageSupport && "multi-language handle is empty" );
+  const BaseObject& handle = multilanguageSupport.GetBaseObject();
+  return static_cast<const Internal::MultilanguageSupport&>( handle );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_IMPL_H
diff --git a/dali-toolkit/internal/text/multi-language-support.cpp b/dali-toolkit/internal/text/multi-language-support.cpp
new file mode 100644 (file)
index 0000000..795e7ae
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/multi-language-support.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/multi-language-support-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+MultilanguageSupport::MultilanguageSupport()
+{
+}
+
+MultilanguageSupport::~MultilanguageSupport()
+{
+}
+
+MultilanguageSupport::MultilanguageSupport( Internal::MultilanguageSupport* implementation )
+: BaseHandle( implementation )
+{
+}
+
+MultilanguageSupport MultilanguageSupport::Get()
+{
+  return Internal::MultilanguageSupport::Get();
+}
+
+void MultilanguageSupport::SetScripts( const Vector<Character>& text,
+                                       CharacterIndex startIndex,
+                                       Length numberOfCharacters,
+                                       Vector<ScriptRun>& scripts )
+{
+  GetImplementation( *this ).SetScripts( text,
+                                         startIndex,
+                                         numberOfCharacters,
+                                         scripts );
+}
+
+void MultilanguageSupport::ValidateFonts( const Vector<Character>& text,
+                                          const Vector<ScriptRun>& scripts,
+                                          const Vector<FontDescriptionRun>& fontDescriptions,
+                                          const TextAbstraction::FontDescription& defaultFontDescription,
+                                          TextAbstraction::PointSize26Dot6 defaultFontPointSize,
+                                          CharacterIndex startIndex,
+                                          Length numberOfCharacters,
+                                          Vector<FontRun>& fonts )
+{
+  GetImplementation( *this ).ValidateFonts( text,
+                                            scripts,
+                                            fontDescriptions,
+                                            defaultFontDescription,
+                                            defaultFontPointSize,
+                                            startIndex,
+                                            numberOfCharacters,
+                                            fonts );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/multi-language-support.h b/dali-toolkit/internal/text/multi-language-support.h
new file mode 100644 (file)
index 0000000..f9749df
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_H
+#define DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class MultilanguageSupport;
+
+} // Internal
+
+/**
+ * @brief Sets the character's scripts to the model and validates the fonts set by the user or assigns default ones.
+ */
+class MultilanguageSupport : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized MultilanguageSupport handle.
+   */
+  MultilanguageSupport();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~MultilanguageSupport();
+
+  /**
+   * @brief This constructor is used by MultilanguageSupport::Get().
+   *
+   * @param[in] implementation A pointer to the internal multi-language support object.
+   */
+  explicit DALI_INTERNAL MultilanguageSupport( Internal::MultilanguageSupport* implementation );
+
+  /**
+   * @brief Retrieve a handle to the MultilanguageSupport instance.
+   *
+   * @return A handle to the MultilanguageSupport.
+   */
+  static MultilanguageSupport Get();
+
+  /**
+   * @brief Sets the scripts of the whole text.
+   *
+   * Scripts are used to validate and set default fonts and to shape the text in further steps.
+   *
+   * Some characters (like white spaces) are valid for many scripts. The rules to set a script
+   * for them are:
+   * - If they are at the begining of a paragraph they get the script of the first character with
+   *   a defined script. If they are at the end, they get the script of the last one.
+   * - If they are between two scripts with the same direction, they get the script of the previous
+   *   character with a defined script. If the two scripts have different directions, they get the
+   *   script of the first character of the paragraph with a defined script.
+   *
+   * @param[in] text Vector of UTF-32 characters.
+   * @param[in] startIndex The character from where the script info is set.
+   * @param[in] numberOfCharacters The number of characters to set the script.
+   * @param[out] scripts Vector containing the script runs for the whole text.
+   */
+  void SetScripts( const Vector<Character>& text,
+                   CharacterIndex startIndex,
+                   Length numberOfCharacters,
+                   Vector<ScriptRun>& scripts );
+
+  /**
+   * @brief Validates the character's font of the whole text.
+   *
+   * This method ensures all characters are going to be rendered using an appropriate font. Provided a valid font
+   * exists in the platform.
+   *
+   * For those characters with no font set, it sets a default one.
+   *
+   * If a font has been set by the application developer, this method checks if the font supports the character.
+   * If it doesn't, this method replaces it by a default one.
+   *
+   * @param[in] text Vector of UTF-32 characters.
+   * @param[in] scripts Vector containing the script runs for the whole text.
+   * @param[in] fontDescriptions The fonts set through the mark-up string or the input style set through the property system.
+   * @param[in] defaultFontDescription The default font's description set through the property system.
+   * @param[in] defaultFontPointSize The default font's point size set through the property system.
+   * @param[in] startIndex The character from where the font info is set.
+   * @param[in] numberOfCharacters The number of characters to set the font.
+   * @param[out] fonts The validated fonts.
+   */
+  void ValidateFonts( const Vector<Character>& text,
+                      const Vector<ScriptRun>& scripts,
+                      const Vector<FontDescriptionRun>& fontDescriptions,
+                      const TextAbstraction::FontDescription& defaultFontDescription,
+                      TextAbstraction::PointSize26Dot6 defaultFontPointSize,
+                      CharacterIndex startIndex,
+                      Length numberOfCharacters,
+                      Vector<FontRun>& fonts );
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MULTI_LANGUAGE_SUPPORT_H
diff --git a/dali-toolkit/internal/text/paragraph-run.h b/dali-toolkit/internal/text/paragraph-run.h
new file mode 100644 (file)
index 0000000..64f2fa1
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H
+#define DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief ParagraphRun
+ *
+ * In terms of the bidirectional algorithm, a 'paragraph' is understood as a run of characters between Paragraph Separators or appropriate Newline Functions.
+ * A 'paragraph' may also be determined by higher-level protocols like a mark-up tag.
+ */
+struct ParagraphRun
+{
+  CharacterRun  characterRun; ///< The initial character index within the whole text and the number of characters of the run.
+  Size          layoutSize;   ///< The size of the paragraph when is laid-out.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_PARAGRAPH_RUN_H
diff --git a/dali-toolkit/internal/text/property-string-parser.cpp b/dali-toolkit/internal/text/property-string-parser.cpp
new file mode 100644 (file)
index 0000000..2aa05e9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/property-string-parser.h>
+
+// EXTERNAL HEADERS
+#include <sstream>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/builder/json-parser.h>
+#include <dali-toolkit/devel-api/builder/tree-node.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void CreatePropertyMap( const TreeNode* const node, Property::Map& map )
+{
+  switch( node->GetType() )
+  {
+    case TreeNode::IS_NULL:
+    case TreeNode::OBJECT:
+    case TreeNode::ARRAY: // FALL THROUGH
+    {
+      break;
+    }
+    case TreeNode::STRING:
+    {
+      map.Insert( node->GetName(), Property::Value( node->GetString() ) );
+      break;
+    }
+    case TreeNode::INTEGER:
+    case TreeNode::FLOAT:
+    case TreeNode::BOOLEAN: // FALL THROUGH
+    {
+      break;
+    }
+  }
+
+  for( TreeNode::ConstIterator it = node->CBegin(), endIt = node->CEnd(); it != endIt; ++it )
+  {
+    const TreeNode::KeyNodePair& pair = *it;
+    CreatePropertyMap( &pair.second, map );
+  }
+}
+
+void ParsePropertyString( const std::string& property, Property::Map& map )
+{
+  Toolkit::JsonParser parser = Toolkit::JsonParser::New();
+
+  if( parser.Parse( property ) )
+  {
+    const TreeNode* const node = parser.GetRoot();
+    if( node )
+    {
+      CreatePropertyMap( node, map );
+    }
+  }
+}
+
+} //namespace Text
+
+} //namespace Toolkit
+
+} //namespace Dali
diff --git a/dali-toolkit/internal/text/property-string-parser.h b/dali-toolkit/internal/text/property-string-parser.h
new file mode 100644 (file)
index 0000000..3584f35
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef DALI_TOOLKIT_PROPERTY_STRING_PARSER_H
+#define DALI_TOOLKIT_PROPERTY_STRING_PARSER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+// Forward declaration
+struct Vector2;
+
+namespace Toolkit
+{
+
+// Forward declaration
+class TreeNode;
+
+namespace Text
+{
+
+/**
+ * @brief Creates a map with pairs 'key,value' with the property's parameters.
+ *
+ * @param[in] node Data structure with the property's parameters.
+ * @param[out] map A map with the property's parameters.
+ *
+ */
+void CreatePropertyMap( const TreeNode* const node, Property::Map& map );
+
+/**
+ * @brief Parses a property string.
+ *
+ * @param[in] property A property string.
+ * @param[out] map A map with the property's parameters.
+ *
+ */
+void ParsePropertyString( const std::string& property, Property::Map& map );
+
+} //namespace Text
+
+} //namespace Toolkit
+
+} //namespace Dali
+
+#endif //DALI_TOOLKIT_PROPERTY_STRING_PARSER_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
new file mode 100644 (file)
index 0000000..3fd324d
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+AtlasGlyphManager::AtlasGlyphManager()
+{
+  mAtlasManager = Dali::Toolkit::AtlasManager::New();
+}
+
+void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+                             const Toolkit::AtlasGlyphManager::GlyphStyle& style,
+                             const PixelData& bitmap,
+                             Dali::Toolkit::AtlasManager::AtlasSlot& slot )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Added glyph, font: %d index: %d\n", glyph.fontId, glyph.index );
+
+  // If glyph added to an existing or new atlas then a new glyph record is required.
+  // Check if an existing atlas will fit the image, create a new one if required.
+  if ( mAtlasManager.Add( bitmap, slot ) )
+  {
+    // A new atlas was created so set the texture set details for the atlas
+    Dali::Texture atlas = mAtlasManager.GetAtlasContainer( slot.mAtlasId );
+    TextureSet textureSet = TextureSet::New();
+    textureSet.SetTexture( 0u, atlas );
+    mAtlasManager.SetTextures( slot.mAtlasId, textureSet );
+  }
+
+  GlyphRecordEntry record;
+  record.mIndex = glyph.index;
+  record.mImageId = slot.mImageId;
+  record.mCount = 1;
+  record.mOutlineWidth = style.outline;
+  record.isItalic = style.isItalic;
+  record.isBold = style.isBold;
+
+  // Have glyph records been created for this fontId ?
+  bool foundGlyph = false;
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end(); ++fontGlyphRecordIt )
+  {
+    if ( fontGlyphRecordIt->mFontId == glyph.fontId )
+    {
+      fontGlyphRecordIt->mGlyphRecords.PushBack( record );
+      foundGlyph = true;
+      break;
+    }
+  }
+
+  if ( !foundGlyph )
+  {
+    // We need to add a new font entry
+    FontGlyphRecord fontGlyphRecord;
+    fontGlyphRecord.mFontId = glyph.fontId;
+    fontGlyphRecord.mGlyphRecords.PushBack( record );
+    mFontGlyphRecords.push_back( fontGlyphRecord );
+  }
+}
+
+void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
+                                          const Vector2& position,
+                                          Toolkit::AtlasManager::Mesh2D& mesh )
+{
+  // Generate mesh data and tell Atlas Manager not to handle reference counting ( we'll do it )
+  mAtlasManager.GenerateMeshData( imageId, position, mesh, false );
+}
+
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
+                                  Text::GlyphIndex index,
+                                  const Toolkit::AtlasGlyphManager::GlyphStyle& style,
+                                  Dali::Toolkit::AtlasManager::AtlasSlot& slot )
+{
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
+  {
+    if ( fontGlyphRecordIt->mFontId == fontId )
+    {
+      for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+            glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+            ++glyphRecordIt )
+      {
+        if ( ( glyphRecordIt->mIndex == index ) &&
+             ( glyphRecordIt->mOutlineWidth == style.outline ) &&
+             ( glyphRecordIt->isItalic == style.isItalic ) &&
+             ( glyphRecordIt->isBold == style.isBold ) )
+        {
+          slot.mImageId = glyphRecordIt->mImageId;
+          slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId );
+          return true;
+        }
+      }
+    }
+  }
+  slot.mImageId = 0;
+  return false;
+}
+
+Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
+{
+  Toolkit::AtlasManager::AtlasSize size = mAtlasManager.GetAtlasSize( atlasId );
+  return Vector2( static_cast< float >( size.mWidth ), static_cast< float >( size.mHeight ) );
+}
+
+void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
+{
+  Toolkit::AtlasManager::AtlasSize size;
+  size.mWidth = width;
+  size.mHeight = height;
+  size.mBlockWidth = blockWidth;
+  size.mBlockHeight = blockHeight;
+  mAtlasManager.SetNewAtlasSize( size );
+}
+
+Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
+{
+  return mAtlasManager.GetPixelFormat( atlasId );
+}
+
+const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
+{
+  std::ostringstream verboseMetrics;
+
+  mMetrics.mGlyphCount = 0u;
+  for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+        fontGlyphRecordIt != mFontGlyphRecords.end();
+        ++fontGlyphRecordIt )
+  {
+    mMetrics.mGlyphCount += fontGlyphRecordIt->mGlyphRecords.Size();
+
+    verboseMetrics << "[FontId " << fontGlyphRecordIt->mFontId << " Glyph ";
+    for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+          glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
+          ++glyphRecordEntryIt )
+    {
+      verboseMetrics << glyphRecordEntryIt->mIndex << "(" << glyphRecordEntryIt->mCount << ") ";
+    }
+    verboseMetrics << "] ";
+  }
+  mMetrics.mVerboseGlyphCounts = verboseMetrics.str();
+
+  mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
+
+  return mMetrics;
+}
+
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const Toolkit::AtlasGlyphManager::GlyphStyle& style, int32_t delta )
+{
+  if( 0 != delta )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "AdjustReferenceCount %d, font: %d index: %d\n", delta, fontId, index );
+
+    for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+          fontGlyphRecordIt != mFontGlyphRecords.end();
+          ++fontGlyphRecordIt )
+    {
+      if ( fontGlyphRecordIt->mFontId == fontId )
+      {
+        for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+              glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+              ++glyphRecordIt )
+        {
+          if ( ( glyphRecordIt->mIndex == index ) &&
+               ( glyphRecordIt->mOutlineWidth == style.outline ) &&
+               ( glyphRecordIt->isItalic == style.isItalic ) &&
+               ( glyphRecordIt->isBold == style.isBold ) )
+          {
+            glyphRecordIt->mCount += delta;
+            DALI_ASSERT_DEBUG( glyphRecordIt->mCount >= 0 && "Glyph ref-count should not be negative" );
+
+            if ( !glyphRecordIt->mCount )
+            {
+              mAtlasManager.Remove( glyphRecordIt->mImageId );
+              fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+            }
+            return;
+          }
+        }
+      }
+    }
+
+    // Should not arrive here
+    DALI_ASSERT_DEBUG( false && "Failed to adjust ref-count" );
+  }
+}
+
+TextureSet AtlasGlyphManager::GetTextures( uint32_t atlasId ) const
+{
+  return mAtlasManager.GetTextures( atlasId );
+}
+
+AtlasGlyphManager::~AtlasGlyphManager()
+{
+  // mAtlasManager handle is automatically released here
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
new file mode 100644 (file)
index 0000000..3d2613e
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H
+#define DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class AtlasGlyphManager;
+
+} // namespace Toolkit
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class AtlasGlyphManager;
+typedef IntrusivePtr<AtlasGlyphManager> AtlasGlyphManagerPtr;
+
+class AtlasGlyphManager : public Dali::BaseObject
+{
+public:
+
+  struct GlyphRecordEntry
+  {
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
+    int32_t mCount;
+    uint16_t mOutlineWidth;
+    bool isItalic:1;
+    bool isBold:1;
+  };
+
+  struct FontGlyphRecord
+  {
+    Text::FontId mFontId;
+    Vector< GlyphRecordEntry > mGlyphRecords;
+  };
+
+  /**
+   * @brief Constructor
+   */
+  AtlasGlyphManager();
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::Add
+   */
+  void Add( const Text::GlyphInfo& glyph,
+            const Toolkit::AtlasGlyphManager::GlyphStyle& style,
+            const PixelData& bitmap,
+            Dali::Toolkit::AtlasManager::AtlasSlot& slot );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::GenerateMeshData
+   */
+  void GenerateMeshData( uint32_t imageId,
+                         const Vector2& position,
+                         Toolkit::AtlasManager::Mesh2D& mesh );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::IsCached
+   */
+  bool IsCached( Text::FontId fontId,
+                 Text::GlyphIndex index,
+                 const Toolkit::AtlasGlyphManager::GlyphStyle& style,
+                 Dali::Toolkit::AtlasManager::AtlasSlot& slot );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::GetAtlasSize
+   */
+  Vector2 GetAtlasSize( uint32_t atlasId );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::SetNewAtlasSize
+   */
+  void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::GetPixelFormat
+   */
+  Pixel::Format GetPixelFormat( uint32_t atlasId );
+
+  /**
+   * @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount
+   */
+  void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const Toolkit::AtlasGlyphManager::GlyphStyle& style, int32_t delta );
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::GetTextures
+   */
+  TextureSet GetTextures( uint32_t atlasId ) const;
+
+  /**
+   * @copydoc Toolkit::AtlasGlyphManager::GetMetrics
+   */
+  const Toolkit::AtlasGlyphManager::Metrics& GetMetrics();
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~AtlasGlyphManager();
+
+private:
+
+  Dali::Toolkit::AtlasManager mAtlasManager;          ///> Atlas Manager created by GlyphManager
+  std::vector< FontGlyphRecord > mFontGlyphRecords;
+  Toolkit::AtlasGlyphManager::Metrics mMetrics;       ///> Metrics to pass back on GlyphManager status
+};
+
+} // namespace Internal
+
+inline const Internal::AtlasGlyphManager& GetImplementation(const Toolkit::AtlasGlyphManager& manager)
+{
+  DALI_ASSERT_ALWAYS( manager && "AtlasGlyphManager handle is empty" );
+
+  const BaseObject& handle = manager.GetBaseObject();
+
+  return static_cast<const Internal::AtlasGlyphManager&>(handle);
+}
+
+inline Internal::AtlasGlyphManager& GetImplementation(Toolkit::AtlasGlyphManager& manager)
+{
+  DALI_ASSERT_ALWAYS( manager && "AtlasGlyphManager handle is empty" );
+
+  BaseObject& handle = manager.GetBaseObject();
+
+  return static_cast<Internal::AtlasGlyphManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
new file mode 100644 (file)
index 0000000..4ce469e
--- /dev/null
@@ -0,0 +1,128 @@
+ /*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AtlasGlyphManager::AtlasGlyphManager()
+{
+}
+
+AtlasGlyphManager::~AtlasGlyphManager()
+{
+}
+
+AtlasGlyphManager AtlasGlyphManager::Get()
+{
+  AtlasGlyphManager manager;
+
+  // Check whether the AtlasGlyphManager is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton(typeid(AtlasGlyphManager));
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to AtlasGlyphManager
+      manager = AtlasGlyphManager(dynamic_cast<Internal::AtlasGlyphManager*>(handle.GetObjectPtr()));
+    }
+
+    if(!manager)
+    {
+      // If not, create the AtlasGlyphManager and register it as a singleton
+      manager = AtlasGlyphManager(new Internal::AtlasGlyphManager());
+      singletonService.Register(typeid(manager), manager);
+    }
+  }
+  return manager;
+}
+
+AtlasGlyphManager::AtlasGlyphManager(Internal::AtlasGlyphManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
+                             const GlyphStyle& style,
+                             const PixelData& bitmap,
+                             AtlasManager::AtlasSlot& slot )
+{
+  GetImplementation(*this).Add( glyph, style, bitmap, slot );
+}
+
+void AtlasGlyphManager::GenerateMeshData( uint32_t imageId,
+                                          const Vector2& position,
+                                          Toolkit::AtlasManager::Mesh2D& mesh )
+{
+  GetImplementation(*this).GenerateMeshData( imageId,
+                                             position,
+                                             mesh );
+}
+
+bool AtlasGlyphManager::IsCached( Text::FontId fontId,
+                                  Text::GlyphIndex index,
+                                  const GlyphStyle& style,
+                                  AtlasManager::AtlasSlot& slot )
+{
+  return GetImplementation(*this).IsCached( fontId, index, style, slot );
+}
+
+void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight )
+{
+  GetImplementation(*this).SetNewAtlasSize( width, height, blockWidth, blockHeight );
+}
+
+Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
+{
+  return GetImplementation(*this).GetAtlasSize( atlasId );
+}
+
+Pixel::Format AtlasGlyphManager::GetPixelFormat( uint32_t atlasId )
+{
+  return GetImplementation(*this).GetPixelFormat( atlasId );
+}
+
+TextureSet AtlasGlyphManager::GetTextures( uint32_t atlasId ) const
+{
+  return GetImplementation(*this).GetTextures( atlasId );
+}
+
+const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
+{
+  return GetImplementation(*this).GetMetrics();
+}
+
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const GlyphStyle& style, int32_t delta )
+{
+  GetImplementation(*this).AdjustReferenceCount( fontId, index, style, delta );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
new file mode 100644 (file)
index 0000000..592017b
--- /dev/null
@@ -0,0 +1,195 @@
+#ifndef DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H
+#define DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class AtlasGlyphManager;
+}
+
+
+class AtlasGlyphManager : public BaseHandle
+{
+public:
+
+  /**
+   * Description of GlyphManager state
+   */
+  struct Metrics
+  {
+    Metrics()
+    : mGlyphCount( 0u )
+    {}
+
+    ~Metrics()
+    {}
+
+    uint32_t mGlyphCount;                   ///< number of glyphs being managed
+    std::string mVerboseGlyphCounts;        ///< a verbose list of the glyphs + ref counts
+    AtlasManager::Metrics mAtlasMetrics;    ///< metrics from the Atlas Manager
+  };
+
+  struct GlyphStyle
+  {
+    GlyphStyle()
+    : outline{ 0u },
+      isItalic{ false },
+      isBold{ false }
+    {}
+
+    uint16_t outline; ///< The outline width of this glyph
+    bool isItalic:1;  ///< Whether the glyph is italic.
+    bool isBold:1;    ///< Whether the glyph is bold.
+  };
+
+  /**
+   * @brief Create a AtlasGlyphManager handle.
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  AtlasGlyphManager();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AtlasGlyphManager();
+
+  /**
+   * @brief Create or retrieve AtlasGlyphManager singleton.
+   *
+   * @return A handle to the AtlasGlyphManager control.
+   */
+  static AtlasGlyphManager Get();
+
+  /**
+   * @brief Ask Atlas Manager to add a glyph
+   *
+   * @param[in] glyph glyph to add to an atlas
+   * @param[in] style The style of this glyph
+   * @param[in] bitmap bitmap to use for glyph addition
+   * @param[out] slot information returned by atlas manager for addition
+   */
+  void Add( const Text::GlyphInfo& glyph,
+            const GlyphStyle& style,
+            const PixelData& bitmap,
+            AtlasManager::AtlasSlot& slot );
+
+  /**
+   * @brief Generate mesh data for an image contained in an atlas
+   *
+   * @param[in] imageId ID of image to generate geometry for
+   * @param[in] position top left of image
+   * @param[out] meshData generated MeshData
+   */
+  void GenerateMeshData( uint32_t imageId,
+                         const Vector2& position,
+                         Toolkit::AtlasManager::Mesh2D& mesh );
+
+  /**
+   * @brief Check to see if a glyph is being cached
+   *
+   * @param[in] fontId The font that this glyph comes from
+   * @param[in] index The GlyphIndex of this glyph
+   * @param[in] style The style of this glyph
+   * @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached )
+   *
+   * @return Whether glyph is cached or not ?
+   */
+  bool IsCached( Text::FontId fontId,
+                 Text::GlyphIndex index,
+                 const GlyphStyle& style,
+                 AtlasManager::AtlasSlot& slot );
+
+  /**
+   * @brief Retrieve the size of an atlas
+   *
+   * @param[in] atlasId Id of the atlas to interrogate
+   *
+   * @return The pixel size of the atlas
+   */
+  Vector2 GetAtlasSize( uint32_t atlasId );
+
+   /**
+    * @brief Set the atlas size and block size for subsequent Atlas generation
+    *
+    * @param[in] width width of atlas in pixels
+    * @param[in] height height of atlas in pixels
+    * @param[in] blockWidth width of a block in pixels
+    * @param[in] blockHeight height of a block in pixels
+    */
+  void SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight );
+
+  /**
+   * @brief Get the Pixel Format used by an atlas
+   *
+   * @param[in] atlasId Id of atlas to check
+   *
+   * @return The pixel format of the atlas
+   */
+  Pixel::Format GetPixelFormat( uint32_t atlasId );
+
+  /**
+   * @brief Get the texture set used by an atlas
+   *
+   * @param[in] atlasId Id of an atlas
+   *
+   * @return The texture set used by the atlas
+   */
+  TextureSet GetTextures( uint32_t atlasId ) const;
+
+  /**
+   * @brief Get Glyph Manager metrics
+   *
+   * @return const reference to glyph manager metrics
+   */
+  const Metrics& GetMetrics();
+
+  /**
+   * @brief Adjust the reference count for glyph
+   *
+   * @param[in] fontId The font this image came from
+   * @param[in] index The index of the glyph
+   * @param[in] style The style of this glyph
+   * @param[in] delta The adjustment to make to the reference count
+   */
+  void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const GlyphStyle& style, int32_t delta );
+
+private:
+
+  explicit DALI_INTERNAL AtlasGlyphManager(Internal::AtlasGlyphManager *impl);
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.cpp
new file mode 100644 (file)
index 0000000..ba07cef
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * 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 <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+  const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
+  const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
+  const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
+  const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
+  const uint32_t SINGLE_PIXEL_PADDING( 1u );
+  const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
+  Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
+
+  bool IsBlockSizeSufficient( uint32_t width, uint32_t height, uint32_t requiredBlockWidth, uint32_t requiredBlockHeight )
+  {
+    return ( width + DOUBLE_PIXEL_PADDING <= requiredBlockWidth ) && ( height + DOUBLE_PIXEL_PADDING <= requiredBlockHeight );
+  }
+}
+
+AtlasManager::AtlasManager()
+: mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES )
+{
+  mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
+  mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
+  mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
+  mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
+}
+
+AtlasManagerPtr AtlasManager::New()
+{
+  AtlasManagerPtr internal = new AtlasManager();
+  return internal;
+}
+
+AtlasManager::~AtlasManager()
+{
+}
+
+Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
+{
+  SizeType width = size.mWidth;
+  SizeType height = size.mHeight;
+  SizeType blockWidth = size.mBlockWidth;
+  SizeType blockHeight = size.mBlockHeight;
+
+  // Check to see if the atlas is large enough to hold a single block even ?
+  if ( blockWidth + DOUBLE_PIXEL_PADDING + 1u > width || blockHeight + DOUBLE_PIXEL_PADDING + 1u > height )
+  {
+    DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
+                    width, height, blockWidth + DOUBLE_PIXEL_PADDING + 1u, blockHeight + DOUBLE_PIXEL_PADDING + 1u );
+    return 0;
+  }
+
+  Dali::Texture atlas = Dali::Texture::New( TextureType::TEXTURE_2D, pixelformat, width, height );
+
+  // Clear the background
+  unsigned int bufferSize(  width * height * Dali::Pixel::GetBytesPerPixel( pixelformat ) );
+  unsigned char* background = new unsigned char[bufferSize];
+  memset( background, 0, bufferSize );
+  PixelData backgroundPixels = PixelData::New( background, bufferSize, width, height, pixelformat, PixelData::DELETE_ARRAY );
+  atlas.Upload( backgroundPixels, 0u, 0u, 0u, 0u, width, height );
+
+  AtlasDescriptor atlasDescriptor;
+  atlasDescriptor.mAtlas = atlas;
+  atlasDescriptor.mSize = size;
+  atlasDescriptor.mPixelFormat = pixelformat;
+  atlasDescriptor.mTotalBlocks = ( ( width - 1u ) / blockWidth ) * ( ( height - 1u ) / blockHeight );
+  atlasDescriptor.mAvailableBlocks = atlasDescriptor.mTotalBlocks;
+
+  bufferSize = blockWidth * SINGLE_PIXEL_PADDING * Dali::Pixel::GetBytesPerPixel(pixelformat);
+  unsigned char* bufferHorizontalStrip = new unsigned char[bufferSize];
+  memset( bufferHorizontalStrip, 0, bufferSize );
+  atlasDescriptor.mHorizontalStrip = PixelData::New( bufferHorizontalStrip, bufferSize, blockWidth, SINGLE_PIXEL_PADDING, pixelformat, PixelData::DELETE_ARRAY );
+
+  bufferSize = SINGLE_PIXEL_PADDING * (blockHeight - DOUBLE_PIXEL_PADDING) * Dali::Pixel::GetBytesPerPixel(pixelformat);
+  unsigned char* bufferVerticalStrip = new unsigned char[bufferSize];
+  memset( bufferVerticalStrip, 0, bufferSize );
+  atlasDescriptor.mVerticalStrip = PixelData::New( bufferVerticalStrip, bufferSize, SINGLE_PIXEL_PADDING, blockHeight - DOUBLE_PIXEL_PADDING, pixelformat, PixelData::DELETE_ARRAY );
+
+  bufferSize = Dali::Pixel::GetBytesPerPixel(pixelformat);
+  unsigned char* buffer = new unsigned char[bufferSize];
+  memset( buffer, 0xFF, bufferSize );
+  PixelData filledPixelImage = PixelData::New( buffer, bufferSize, 1u, 1u, pixelformat, PixelData::DELETE_ARRAY );
+  atlas.Upload( filledPixelImage, 0u, 0u, 0u, 0u, 1u, 1u );
+  mAtlasList.push_back( atlasDescriptor );
+  return mAtlasList.size();
+}
+
+void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
+{
+  mAddFailPolicy = policy;
+}
+
+bool AtlasManager::Add( const PixelData& image,
+                        Toolkit::AtlasManager::AtlasSlot& slot,
+                        Toolkit::AtlasManager::AtlasId atlas )
+{
+  bool created = false;
+  Pixel::Format pixelFormat = image.GetPixelFormat();
+  SizeType width = image.GetWidth();
+  SizeType height = image.GetHeight();
+  SizeType foundAtlas = 0;
+  SizeType index = 0;
+  slot.mImageId = 0;
+
+  AtlasSlotDescriptor desc;
+
+  // If there is a preferred atlas then check for room in that first
+  if ( atlas-- )
+  {
+    foundAtlas = CheckAtlas( atlas, width, height, pixelFormat );
+  }
+
+  // Search current atlases to see if there is a good match
+  while( ( 0u == foundAtlas ) && ( index < mAtlasList.size() ) )
+  {
+    foundAtlas = CheckAtlas( index, width, height, pixelFormat );
+    ++index;
+  }
+
+  // If we can't find a suitable atlas then check the policy to determine action
+  if ( 0u == foundAtlas )
+  {
+    if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
+    {
+      if ( IsBlockSizeSufficient( width, height, mNewAtlasSize.mBlockWidth, mNewAtlasSize.mBlockHeight ) ) // Checks if image fits within the atlas blocks
+      {
+        foundAtlas = CreateAtlas( mNewAtlasSize, pixelFormat ); // Creating atlas with mNewAtlasSize, may not be the needed size!
+        if (  0u == foundAtlas )
+        {
+          DALI_LOG_ERROR("Failed to create an atlas of %i x %i blocksize: %i x %i.\n",
+                         mNewAtlasSize.mWidth,
+                         mNewAtlasSize.mHeight,
+                         mNewAtlasSize.mBlockWidth,
+                         mNewAtlasSize.mBlockHeight );
+          return false;
+        }
+        else
+        {
+          created = true;
+        }
+      }
+    }
+
+    if ( (  0u == foundAtlas )  || Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy )
+    {
+      // Haven't found an atlas for this image ( may have failed to add image to atlas )
+      DALI_LOG_ERROR("Failed to create an atlas under current policy.\n");
+      return false;
+    }
+  }
+
+  foundAtlas--; // Atlas created successfully, decrement by 1 to get <vector> index (starts at 0 not 1)
+
+  // Work out which the block we're going to use
+  // Is there currently a next free block available ?
+  if ( mAtlasList[ foundAtlas ].mAvailableBlocks )
+  {
+    // Yes, so select our next block
+    desc.mBlock = mAtlasList[ foundAtlas ].mTotalBlocks - mAtlasList[ foundAtlas ].mAvailableBlocks--;
+  }
+  else
+  {
+    // Our next block must be from the free list, fetch from the start of the list
+    desc.mBlock = mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ];
+    mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
+  }
+
+  desc.mImageWidth = width;
+  desc.mImageHeight = height;
+  desc.mAtlasId = foundAtlas + 1u;  // Ids start from 1 not the 0 index
+  desc.mCount = 1u;
+
+  // See if there's a previously freed image ID that we can assign to this new image
+  uint32_t imageId = 0u;
+  for ( uint32_t i = 0u; i < mImageList.Size(); ++i )
+  {
+    if ( !mImageList[ i ].mCount )
+    {
+      imageId = i + 1u;
+      break;
+    }
+  }
+  if ( !imageId )
+  {
+    mImageList.PushBack( desc );
+    slot.mImageId = mImageList.Size();
+  }
+  else
+  {
+    mImageList[ imageId - 1u ] = desc;
+    slot.mImageId = imageId;
+  }
+  slot.mAtlasId = foundAtlas + 1u; // Ids start from 1 not the 0 index
+
+  // Upload the buffer image into the atlas
+  UploadImage( image, desc );
+  return created;
+}
+
+AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
+                                                 SizeType width,
+                                                 SizeType height,
+                                                 Pixel::Format pixelFormat )
+{
+  AtlasManager::SizeType result = 0u;
+  if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
+  {
+    // Check to see if the image will fit in these blocks
+
+    const SizeType availableBlocks = mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size();
+
+    if ( availableBlocks && IsBlockSizeSufficient( width, height,mAtlasList[ atlas ].mSize.mBlockWidth, mAtlasList[ atlas ].mSize.mBlockHeight ) )
+    {
+      result = atlas + 1u; // Atlas ids start from 1 not 0
+    }
+  }
+  return result;
+}
+
+void AtlasManager::UploadImage( const PixelData& image,
+                                const AtlasSlotDescriptor& desc )
+{
+  // Get the atlas to upload the image to
+  SizeType atlas = desc.mAtlasId - 1u;
+
+  // Check to see that the pixel formats are compatible
+  if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
+  {
+    DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
+    return;
+  }
+
+  SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
+  SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
+  SizeType atlasWidthInBlocks = ( mAtlasList[ atlas ].mSize.mWidth - 1u ) / mAtlasList[ atlas ].mSize.mBlockWidth;
+
+  SizeType blockX = desc.mBlock % atlasWidthInBlocks;
+  SizeType blockY = desc.mBlock / atlasWidthInBlocks;
+  SizeType blockOffsetX = ( blockX * atlasBlockWidth ) + 1u;
+  SizeType blockOffsetY = ( blockY * atlasBlockHeight) + 1u;
+
+  SizeType width = image.GetWidth();
+  SizeType height = image.GetHeight();
+
+  // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
+  if ( !mAtlasList[ atlas ].mAtlas.Upload( image, 0u, 0u,
+                                           blockOffsetX + SINGLE_PIXEL_PADDING,
+                                           blockOffsetY + SINGLE_PIXEL_PADDING,
+                                           width, height) )
+  {
+    DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
+  }
+
+  // Blit top strip
+  if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip, 0u, 0u,
+                                           blockOffsetX,
+                                           blockOffsetY,
+                                           mAtlasList[ atlas ].mHorizontalStrip.GetWidth(),
+                                           mAtlasList[ atlas ].mHorizontalStrip.GetHeight()) )
+  {
+    DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
+  }
+
+  // Blit left strip
+  if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip, 0u, 0u,
+                                           blockOffsetX,
+                                           blockOffsetY + SINGLE_PIXEL_PADDING,
+                                           mAtlasList[ atlas ].mVerticalStrip.GetWidth(),
+                                           mAtlasList[ atlas ].mVerticalStrip.GetHeight() ) )
+  {
+    DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
+  }
+
+  // Blit bottom strip
+  if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
+  {
+    if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip, 0u, 0u,
+                                             blockOffsetX,
+                                             blockOffsetY + height + SINGLE_PIXEL_PADDING,
+                                             mAtlasList[ atlas ].mHorizontalStrip.GetWidth(),
+                                             mAtlasList[ atlas ].mHorizontalStrip.GetHeight() ) )
+    {
+      DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
+    }
+  }
+
+  // Blit right strip
+  if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
+  {
+    if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip, 0u, 0u,
+                                             blockOffsetX + width + SINGLE_PIXEL_PADDING,
+                                             blockOffsetY + SINGLE_PIXEL_PADDING,
+                                             mAtlasList[ atlas ].mVerticalStrip.GetWidth(),
+                                             mAtlasList[ atlas ].mVerticalStrip.GetHeight() ) )
+    {
+      DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
+    }
+  }
+}
+
+void AtlasManager::GenerateMeshData( ImageId id,
+                                     const Vector2& position,
+                                     Toolkit::AtlasManager::Mesh2D& meshData,
+                                     bool addReference )
+{
+  if ( id )
+  {
+    // Read the atlas Id to use for this image
+    SizeType imageId = id - 1u;
+    SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
+    SizeType width = mImageList[ imageId ].mImageWidth;
+    SizeType height = mImageList[ imageId ].mImageHeight;
+
+    AtlasMeshFactory::CreateQuad( width,
+                                  height,
+                                  mImageList[ imageId ].mBlock,
+                                  mAtlasList[ atlas ].mSize,
+                                  position,
+                                  meshData );
+
+    // Mesh created so increase the reference count, if we're asked to
+    if ( addReference )
+    {
+      mImageList[ imageId ].mCount++;
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("Cannot generate mesh with invalid AtlasId\n");
+  }
+}
+
+Dali::Texture AtlasManager::GetAtlasContainer( AtlasId atlas ) const
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  Dali::Texture atlasContainer;
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    atlasContainer = mAtlasList[ atlas ].mAtlas;
+  }
+  return atlasContainer;
+}
+
+bool AtlasManager::Remove( ImageId id )
+{
+  // Decrements the reference count of this image, and removes the blocks if zero.
+  SizeType imageId = id - 1u;
+  bool removed = false;
+
+  if ( id > mImageList.Size() )
+     {
+    DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
+    return false;
+  }
+
+  // If we attempt to free an image that is already freed then do nothing, other than log
+  if ( !mImageList[ imageId ].mCount )
+  {
+    DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
+    return false;
+  }
+
+  if ( 2u > --mImageList[ imageId ].mCount )
+  {
+    // 'Remove the blocks' from this image and add to the atlas' freelist
+    removed = true;
+    mImageList[ imageId ].mCount = 0;
+    SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
+    mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlock );
+  }
+  return removed;
+}
+
+AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
+{
+  DALI_ASSERT_DEBUG( id && id <= mImageList.Size() );
+  AtlasManager::AtlasId atlasId = 0u;
+  if ( id && id-- <= mImageList.Size() )
+  {
+    atlasId = mImageList[ id ].mAtlasId;
+  }
+  return atlasId;
+}
+
+void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
+{
+  mNewAtlasSize = size;
+
+  // Add on padding for borders around atlas entries
+  mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
+  mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
+}
+
+const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    return mAtlasList[ atlas ].mSize;
+  }
+  return EMPTY_SIZE;
+}
+
+AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  AtlasManager::SizeType freeBlocks = 0u;
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    freeBlocks = mAtlasList[ atlas ].mAvailableBlocks + mAtlasList[ atlas ].mFreeBlocksList.Size();
+  }
+  return freeBlocks;
+}
+
+AtlasManager::SizeType AtlasManager::GetAtlasCount() const
+{
+  return mAtlasList.size();
+}
+
+Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas ) const
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    pixelFormat = mAtlasList[ atlas ].mPixelFormat;
+  }
+  return pixelFormat;
+}
+
+void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
+{
+  Toolkit::AtlasManager::AtlasMetricsEntry entry;
+  uint32_t textureMemoryUsed = 0;
+  uint32_t atlasCount = mAtlasList.size();
+  metrics.mAtlasCount = atlasCount;
+  metrics.mAtlasMetrics.Resize(0);
+
+  for ( uint32_t i = 0; i < atlasCount; ++i )
+  {
+    entry.mSize = mAtlasList[ i ].mSize;
+    entry.mTotalBlocks = mAtlasList[ i ].mTotalBlocks;
+    entry.mBlocksUsed = entry.mTotalBlocks - mAtlasList[ i ].mAvailableBlocks + mAtlasList[ i ].mFreeBlocksList.Size();
+    entry.mPixelFormat = GetPixelFormat( i + 1 );
+
+    metrics.mAtlasMetrics.PushBack( entry );
+
+    uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
+    if ( entry.mPixelFormat == Pixel::BGRA8888 )
+    {
+      size <<= 2;
+    }
+
+    textureMemoryUsed += size;
+
+  }
+  metrics.mTextureMemoryUsed = textureMemoryUsed;
+}
+
+TextureSet AtlasManager::GetTextures( AtlasId atlas ) const
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  TextureSet textureSet;
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    textureSet = mAtlasList[ atlas ].mTextureSet;
+  }
+  return textureSet;
+}
+
+void AtlasManager::SetTextures( AtlasId atlas, TextureSet& textureSet )
+{
+  DALI_ASSERT_DEBUG( atlas && atlas <= mAtlasList.size() );
+  if ( atlas && atlas-- <= mAtlasList.size() )
+  {
+    mAtlasList[ atlas ].mTextureSet = textureSet;
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h b/dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h
new file mode 100644 (file)
index 0000000..ed51450
--- /dev/null
@@ -0,0 +1,218 @@
+#ifndef DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H
+#define DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class AtlasManager;
+
+} // namespace Toolkit
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+typedef Dali::Vector< Toolkit::AtlasManager::AtlasSlot > slotContainer;
+
+class AtlasManager;
+typedef IntrusivePtr<AtlasManager> AtlasManagerPtr;
+
+class AtlasManager : public Dali::BaseObject
+{
+public:
+
+  typedef uint32_t SizeType;
+  typedef SizeType AtlasId;
+  typedef SizeType ImageId;
+
+  /**
+   * @brief Internal storage of atlas attributes and image upload results
+   */
+  struct AtlasDescriptor
+  {
+    Dali::Texture mAtlas;                                                 // atlas image
+    Toolkit::AtlasManager::AtlasSize mSize;                             // size of atlas
+    Pixel::Format mPixelFormat;                                         // pixel format used by atlas
+    PixelData mHorizontalStrip;                                       // Image used to pad upload
+    PixelData mVerticalStrip;                                         // Image used to pad upload
+    TextureSet mTextureSet;                                             // Texture set used for atlas texture
+    SizeType mTotalBlocks;                                              // total number of blocks in atlas
+    SizeType mAvailableBlocks;                                          // number of blocks available in atlas
+    Dali::Vector< SizeType > mFreeBlocksList;                           // unless there are any previously freed blocks
+  };
+
+  struct AtlasSlotDescriptor
+  {
+    SizeType mCount;                                                    // Reference count for this slot
+    SizeType mImageWidth;                                               // Width of image stored
+    SizeType mImageHeight;                                              // Height of image stored
+    AtlasId mAtlasId;                                                   // Image is stored in this Atlas
+    SizeType mBlock;                                                    // Block within atlas used for image
+  };
+
+  AtlasManager();
+
+  /**
+   * Create a new AtlasManager
+   */
+  static AtlasManagerPtr New();
+
+  virtual ~AtlasManager();
+
+  /**
+   * @copydoc: Toolkit::AtlasManager::CreateAtlas
+   */
+  AtlasId CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::SetAddPolicy
+   */
+  void SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::Add
+   */
+  bool Add( const PixelData& image,
+            Toolkit::AtlasManager::AtlasSlot& slot,
+            Toolkit::AtlasManager::AtlasId atlas );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GenerateMeshData
+   */
+  void GenerateMeshData( ImageId id,
+                         const Vector2& position,
+                         Toolkit::AtlasManager::Mesh2D& mesh,
+                         bool addReference );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::Remove
+   */
+  bool Remove( ImageId id );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetAtlasContainer
+   */
+  Dali::Texture GetAtlasContainer( AtlasId atlas ) const;
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetAtlas
+   */
+  AtlasId GetAtlas( ImageId id ) const;
+
+  /**
+   * @copydoc Toolkit::AtlasManager::SetNewAtlasSize
+   */
+  void SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetAtlasSize
+   */
+  const Toolkit::AtlasManager::AtlasSize& GetAtlasSize( AtlasId atlas );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetBlockSize
+   */
+  Vector2 GetBlockSize( AtlasId atlas );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetFreeBlocks
+   */
+  SizeType GetFreeBlocks( AtlasId atlas ) const;
+
+  /*
+   * @copydoc Toolkit::AtlasManager::GetAtlasCount
+   */
+  SizeType GetAtlasCount() const;
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetPixelFormat
+   */
+  Pixel::Format GetPixelFormat( AtlasId atlas ) const;
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetMetrics
+   */
+  void GetMetrics( Toolkit::AtlasManager::Metrics& metrics );
+
+  /**
+   * @copydoc Toolkit::AtlasManager::GetTextures
+   */
+  TextureSet GetTextures( AtlasId atlas ) const;
+
+  /**
+   * @copydoc Toolkit::AtlasManager::SetTextures
+   */
+  void SetTextures( AtlasId atlas, TextureSet& textureSet );
+
+private:
+
+  std::vector< AtlasDescriptor > mAtlasList;            // List of atlases created
+  Vector< AtlasSlotDescriptor > mImageList;             // List of bitmaps stored in atlases
+  Toolkit::AtlasManager::AtlasSize mNewAtlasSize;       // Atlas size to use in next creation
+  Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy;  // Policy for failing to add an Image
+
+  SizeType CheckAtlas( SizeType atlas,
+                       SizeType width,
+                       SizeType height,
+                       Pixel::Format pixelFormat );
+
+  void UploadImage( const PixelData& image,
+                    const AtlasSlotDescriptor& desc );
+
+};
+
+} // namespace Internal
+
+inline const Internal::AtlasManager& GetImplementation(const Toolkit::AtlasManager& manager)
+{
+  DALI_ASSERT_ALWAYS( manager && "AtlasManager handle is empty" );
+
+  const BaseObject& handle = manager.GetBaseObject();
+
+  return static_cast<const Internal::AtlasManager&>(handle);
+}
+
+inline Internal::AtlasManager& GetImplementation(Toolkit::AtlasManager& manager)
+{
+  DALI_ASSERT_ALWAYS( manager && "AtlasManager handle is empty" );
+
+  BaseObject& handle = manager.GetBaseObject();
+
+  return static_cast<Internal::AtlasManager&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+
+ #endif // DALI_TOOLKIT_ATLAS_MANAGER_IMPL_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.cpp
new file mode 100644 (file)
index 0000000..510da05
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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 <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AtlasManager::AtlasManager()
+{
+}
+
+AtlasManager::~AtlasManager()
+{
+}
+
+AtlasManager AtlasManager::New()
+{
+  Internal::AtlasManagerPtr internal = Internal::AtlasManager::New();
+  return AtlasManager(internal.Get());
+}
+
+AtlasManager::AtlasManager(Internal::AtlasManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+AtlasManager::AtlasId AtlasManager::CreateAtlas( const AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
+{
+  return GetImplementation(*this).CreateAtlas( size, pixelformat );
+}
+
+void AtlasManager::SetAddPolicy( AddFailPolicy policy )
+{
+  GetImplementation(*this).SetAddPolicy( policy );
+}
+
+bool AtlasManager::Add( const PixelData& image,
+                        AtlasManager::AtlasSlot& slot,
+                        AtlasManager::AtlasId atlas )
+{
+  return GetImplementation(*this).Add( image, slot, atlas );
+}
+
+bool AtlasManager::Remove( ImageId id )
+{
+  return GetImplementation(*this).Remove( id );
+}
+
+void AtlasManager::GenerateMeshData( ImageId id,
+                                     const Vector2& position,
+                                     Mesh2D& mesh,
+                                     bool addReference )
+{
+  GetImplementation(*this).GenerateMeshData( id,
+                                             position,
+                                             mesh,
+                                             addReference );
+}
+
+Dali::Texture AtlasManager::GetAtlasContainer( AtlasId atlas ) const
+{
+  return GetImplementation(*this).GetAtlasContainer( atlas );
+}
+
+AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id )
+{
+  return GetImplementation(*this).GetAtlas( id );
+}
+
+const AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
+{
+  return GetImplementation(*this).GetAtlasSize( atlas );
+}
+
+AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas )
+{
+  return GetImplementation(*this).GetFreeBlocks( atlas );
+}
+
+void AtlasManager::SetNewAtlasSize( const AtlasSize& size )
+{
+  GetImplementation(*this).SetNewAtlasSize( size );
+}
+
+AtlasManager::SizeType AtlasManager::GetAtlasCount() const
+{
+  return GetImplementation(*this).GetAtlasCount();
+}
+
+Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas ) const
+{
+  return GetImplementation(*this).GetPixelFormat( atlas );
+}
+
+void AtlasManager::GetMetrics( Metrics& metrics )
+{
+  GetImplementation(*this).GetMetrics( metrics );
+}
+
+TextureSet AtlasManager::GetTextures( AtlasId atlas ) const
+{
+  return GetImplementation(*this).GetTextures( atlas );
+}
+
+void AtlasManager::SetTextures( AtlasId atlas, TextureSet& textureSet )
+{
+  GetImplementation(*this).SetTextures( atlas, textureSet );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-manager.h b/dali-toolkit/internal/text/rendering/atlas/atlas-manager.h
new file mode 100644 (file)
index 0000000..3b567ef
--- /dev/null
@@ -0,0 +1,285 @@
+#ifndef DALI_TOOLKIT_ATLAS_MANAGER_H
+#define DALI_TOOLKIT_ATLAS_MANAGER_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/rendering/texture-set.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class AtlasManager;
+
+} // namespace Internal
+
+class AtlasManager : public BaseHandle
+{
+public:
+
+  typedef uint32_t SizeType;
+  typedef SizeType AtlasId;
+  typedef SizeType ImageId;
+
+  struct AtlasSize
+  {
+    SizeType mWidth;              ///< width of the atlas in pixels
+    SizeType mHeight;             ///< height of the atlas in pixels
+    SizeType mBlockWidth;         ///< width of a block in pixels
+    SizeType mBlockHeight;        ///< height of a block in pixels
+  };
+
+  /**
+   * Metrics structures to describe Atlas Manager state
+   *
+   */
+  struct AtlasMetricsEntry
+  {
+    AtlasSize mSize;                 ///< size of atlas and blocks
+    SizeType mBlocksUsed;            ///< number of blocks used in the atlas
+    SizeType mTotalBlocks;           ///< total blocks used by atlas
+    Pixel::Format mPixelFormat;      ///< pixel format of the atlas
+  };
+
+  struct Metrics
+  {
+    Metrics()
+    : mAtlasCount( 0u ),
+      mTextureMemoryUsed( 0u )
+    {}
+
+    ~Metrics()
+    {}
+
+    SizeType mAtlasCount;                               ///< number of atlases
+    SizeType mTextureMemoryUsed;                        ///< texture memory used by atlases
+    Dali::Vector< AtlasMetricsEntry > mAtlasMetrics;    ///< container of atlas information
+  };
+
+  struct Vertex2D
+  {
+    Vector2 mPosition;        ///< Vertex posiiton
+    Vector2 mTexCoords;       ///< Vertex texture co-ordinates
+    Vector4 mColor;           ///< Vertex color
+  };
+
+  struct Mesh2D
+  {
+    Vector< Vertex2D > mVertices;       ///< container of vertices
+    Vector< unsigned short > mIndices;        ///< container of indices
+  };
+
+  /**
+   * Create an AtlasManager handle; this can be initialised with AtlasManager::New()
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  AtlasManager();
+
+  /**
+   * @brief Get new instance of AtlasManager object.
+   *
+   * @return A handle to the AtlasManager control.
+   */
+  static AtlasManager New();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AtlasManager();
+
+  /**
+   * Policy on failing to add an image
+   */
+  enum AddFailPolicy
+  {
+    FAIL_ON_ADD_FAILS,
+    FAIL_ON_ADD_CREATES
+  };
+
+  /**
+   * @brief Container to hold result of placing texture into atlas
+   */
+  struct AtlasSlot
+  {
+    ImageId mImageId;                           ///< Id of stored Image
+    AtlasId mAtlasId;                           ///< Id of Atlas containing this slot
+  };
+
+  typedef Dali::Vector< AtlasManager::AtlasSlot > slotContainer;
+
+  /**
+   * @brief Create a blank atlas of specific dimensions and pixel format with a certain block size
+   *
+   * @param[in] size desired atlas dimensions
+   * @param[in] pixelformat format of a pixel in atlas
+   *
+   * @return atlas Id
+   */
+  AtlasId CreateAtlas( const AtlasSize& size, Pixel::Format pixelformat = Pixel::RGBA8888 );
+
+  /**
+   * @brief Set the policy on failure to add an image to an atlas
+   *
+   * @param policy policy to carry out if add fails
+   */
+  void SetAddPolicy( AddFailPolicy policy );
+
+  /**
+   * @brief Attempts to add an image to the most suitable atlas
+   *
+   * @details Add Policy may dictate that a new atlas is created if it can't presently be placed.
+   *          If an add is made before an atlas is created under this policy,
+   *          then a default size atlas will be created
+   *
+   * @param[in] image PixelData object containing the image data
+   * @param[out] slot result of add operation
+   * @param[in] atlas optional preferred atlas
+   *
+   * @return true if a new atlas was created
+   */
+  bool Add( const PixelData& image,
+            AtlasSlot& slot,
+            AtlasId atlas = 0 );
+
+  /**
+   * @brief Remove previously added bitmapimage from atlas
+   *
+   * @param[in] id ImageId returned in the AtlasSlot from the add operation
+   *
+   * @return if true then image has been removed from the atlas
+   */
+  bool Remove( ImageId id );
+
+  /**
+   * @brief Generate mesh data for a previously added image
+   *
+   * @param[in] id Image Id returned in the AtlasSlot from the add operation
+   * @param[in] position position of the resulting mesh in model space
+   * @param[out] mesh Mesh Data Object to populate with mesh data
+   * @param[in] addReference Whether to increase the internal reference count for image or not
+   */
+  void GenerateMeshData( ImageId id,
+                         const Vector2& position,
+                         Mesh2D& mesh,
+                         bool addReference = true );
+
+  /**
+   * @brief Get the BufferImage containing an atlas
+   *
+   * @param[in] atlas AtlasId returned when atlas was created
+   *
+   * @return Atlas Handle
+   */
+  Dali::Texture GetAtlasContainer( AtlasId atlas ) const;
+
+  /**
+   * @brief Get the Id of the atlas containing an image
+   *
+   * @param[in] id ImageId
+   *
+   * @return Atlas Id
+   */
+  AtlasId GetAtlas( ImageId id );
+  /**
+   * @brief Get the current size of an atlas
+   *
+   * @param[in] atlas AtlasId
+   *
+   * @return AtlasSize structure for the atlas
+   */
+  const AtlasSize& GetAtlasSize( AtlasId atlas );
+
+  /**
+   * @brief Get the number of blocks available in an atlas
+   *
+   * @param[in] atlas AtlasId
+   *
+   * @return Number of blocks free in this atlas
+   */
+  SizeType GetFreeBlocks( AtlasId atlas );
+
+  /**
+   * @brief Sets the pixel area of any new atlas and also the individual block size
+   *
+   * @param[in] size Atlas size structure
+   *
+   * @param blockSize pixel area in atlas for a block
+   */
+  void SetNewAtlasSize( const AtlasSize& size );
+
+  /**
+   * @brief Get the number of atlases created
+   *
+   * @return number of atlases
+   */
+  SizeType GetAtlasCount() const;
+
+  /**
+   * @brief Get the pixel format used by an atlas
+   *
+   * @param[in] atlas AtlasId
+   *
+   * @return Pixel format used by this atlas
+   */
+  Pixel::Format GetPixelFormat( AtlasId atlas ) const;
+
+  /**
+   * @brief Fill in a metrics structure showing current status of this Atlas Manager
+   *
+   * @param[in] metrics metrics structure to be filled
+   */
+  void GetMetrics( Metrics& metrics );
+
+  /**
+   * @brief Get TextureSet used by atlas
+   *
+   * @param[in] atlas AtlasId
+   *
+   * @return TextureSet used by atlas
+   */
+  TextureSet GetTextures( AtlasId atlas ) const;
+
+  /**
+   * @brief Set the texture set used by an atlas
+   *
+   * @param[in] atlas AtlasId
+   * @param[in] textureSet The texture set to assign
+   */
+  void SetTextures( AtlasId atlas, TextureSet& textureSet );
+
+private:
+
+  explicit DALI_INTERNAL AtlasManager(Internal::AtlasManager *impl);
+
+};
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_MANAGER_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp
new file mode 100644 (file)
index 0000000..4017f79
--- /dev/null
@@ -0,0 +1,169 @@
+ /*
+ * 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.
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+
+void CreateQuad( SizeType imageWidth,
+                 SizeType imageHeight,
+                 SizeType block,
+                 const Toolkit::AtlasManager::AtlasSize& atlasSize,
+                 const Vector2& position,
+                 Toolkit::AtlasManager::Mesh2D& mesh )
+{
+  Toolkit::AtlasManager::Vertex2D vertex;
+
+  SizeType blockWidth = atlasSize.mBlockWidth;
+  SizeType blockHeight = atlasSize.mBlockHeight;
+
+  float vertexBlockWidth = static_cast< float >( blockWidth );
+  float vertexBlockHeight = static_cast< float >( blockHeight );
+
+  SizeType atlasWidth = atlasSize.mWidth;
+  SizeType atlasHeight = atlasSize.mHeight;
+
+  SizeType atlasWidthInBlocks = ( atlasWidth - 1u ) / blockWidth;
+
+  // Get the normalized size of a texel in both directions
+  float texelX = 1.0f / static_cast< float >( atlasWidth );
+  float texelY = 1.0f / static_cast< float >( atlasHeight );
+
+  float oneAndAHalfTexelX = texelX + ( texelX * 0.5f );
+  float oneAndAHalfTexelY = texelY + ( texelY * 0.5f );
+
+  float texelBlockWidth = texelX * vertexBlockWidth;
+  float texelBlockHeight = texelY * vertexBlockHeight;
+
+  uint32_t pixelsX = imageWidth % blockWidth;
+  uint32_t pixelsY = imageHeight % blockHeight;
+
+  if ( !pixelsX )
+  {
+    pixelsX = blockWidth;
+  }
+  if ( !pixelsY )
+  {
+    pixelsY = blockHeight;
+  }
+  float vertexWidth = static_cast< float >( pixelsX );
+  float vertexHeight = static_cast< float >( pixelsY );
+  float texelWidth = texelX * vertexWidth;
+  float texelHeight = texelY * vertexHeight;
+
+  // We're going to 'blit' half a pixel more on each edge
+  vertexWidth++;
+  vertexHeight++;
+
+  // Move back half a pixel
+  Vector2 topLeft = Vector2( position.x - 0.5f, position.y - 0.5f );
+
+  float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
+
+  // In the next expression, we have purposely made ( block / atlasWidthInBlocks ) yield an integer value and then convert to float as
+  // we do not want the remainder in that expression to affect the value of fBlockY
+  float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
+
+  // Add on texture filtering compensation ( half a texel plus compensation for filled pixel in top left corner )
+  fBlockX += oneAndAHalfTexelX;
+  fBlockY += oneAndAHalfTexelY;
+
+  float texelWidthOffset = texelWidth + texelX;
+  float texelHeightOffset = texelHeight + texelY;
+
+  // Top left
+  vertex.mPosition.x = topLeft.x;
+  vertex.mPosition.y = topLeft.y;
+  vertex.mTexCoords.x = fBlockX;
+  vertex.mTexCoords.y = fBlockY;
+
+  mesh.mVertices.Reserve( 4u );
+  mesh.mVertices.PushBack( vertex );
+
+  // Top Right
+  vertex.mPosition.x = topLeft.x + vertexWidth;
+  vertex.mPosition.y = topLeft.y;
+  vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+  vertex.mTexCoords.y = fBlockY;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Bottom Left
+  vertex.mPosition.x = topLeft.x;
+  vertex.mPosition.y = topLeft.y + vertexHeight;
+  vertex.mTexCoords.x = fBlockX;
+  vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Bottom Right
+  vertex.mPosition.x = topLeft.x + vertexWidth;
+  vertex.mPosition.y = topLeft.y + vertexHeight;
+  vertex.mTexCoords.x = fBlockX + texelWidthOffset;
+  vertex.mTexCoords.y = fBlockY + texelHeightOffset;
+
+  mesh.mVertices.PushBack( vertex );
+
+  // Six indices in counter clockwise winding
+  mesh.mIndices.Reserve( 6u );
+  mesh.mIndices.PushBack( 1u );
+  mesh.mIndices.PushBack( 0u );
+  mesh.mIndices.PushBack( 2u );
+  mesh.mIndices.PushBack( 2u );
+  mesh.mIndices.PushBack( 3u );
+  mesh.mIndices.PushBack( 1u );
+}
+
+void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+                 const Toolkit::AtlasManager::Mesh2D& second )
+{
+  const uint32_t verticesCount = first.mVertices.Size();
+  first.mVertices.Insert( first.mVertices.End(),
+                          second.mVertices.Begin(),
+                          second.mVertices.End() );
+
+  const uint32_t indicesCount = first.mIndices.Size();
+  first.mIndices.Insert( first.mIndices.End(),
+                         second.mIndices.Begin(),
+                         second.mIndices.End() );
+
+  for( Vector<unsigned short>::Iterator it = first.mIndices.Begin() + indicesCount,
+         endIt = first.mIndices.End();
+       it != endIt;
+       ++it )
+  {
+    *it += verticesCount;
+  }
+}
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h b/dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h
new file mode 100644 (file)
index 0000000..bbc1d2f
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DALI_TOOLKIT_ATLAS_MESH_FACTORY_H
+#define DALI_TOOLKIT_ATLAS_MESH_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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.
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace AtlasMeshFactory
+{
+  typedef uint32_t SizeType;
+
+  /**
+   * @brief Create a Quad that describes an area in an atlas and a position.
+   *
+   * @param[in]  width Width of area in pixels.
+   * @param[in]  height Height of area in pixels.
+   * @param[in]  block Block position in atlas.
+   * @param[in]  atlasSize Atlas and block dimensions.
+   * @param[in]  position Position to place area in space.
+   * @param[out] mesh Mesh object to hold created quad.
+   */
+  void CreateQuad( SizeType width,
+                   SizeType height,
+                   SizeType block,
+                   const Toolkit::AtlasManager::AtlasSize& atlasSize,
+                   const Vector2& position,
+                   Toolkit::AtlasManager::Mesh2D& mesh );
+
+  /**
+   * @brief Append one mesh to another.
+   *
+   * @param[in,out] first Mesh to append to.
+   * @param[in]     second Mesh to append.
+   */
+  void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
+                   const Toolkit::AtlasManager::Mesh2D& second );
+
+} // namespace AtlasMeshFactory
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_MESH_FACTORY_H
diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
new file mode 100755 (executable)
index 0000000..dddb301
--- /dev/null
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/animation/constraints.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+#include <dali-toolkit/internal/text/text-view.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Toolkit::Text;
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_RENDERING");
+#endif
+
+#define MAKE_SHADER(A)#A
+
+const char* VERTEX_SHADER = MAKE_SHADER(
+attribute mediump vec2    aPosition;
+attribute mediump vec2    aTexCoord;
+attribute mediump vec4    aColor;
+uniform   mediump vec2    uOffset;
+uniform     highp mat4    uMvpMatrix;
+varying   mediump vec2    vTexCoord;
+varying   mediump vec4    vColor;
+
+void main()
+{
+  mediump vec4 position = vec4( aPosition.xy + uOffset, 0.0, 1.0 );
+  gl_Position = uMvpMatrix * position;
+  vTexCoord = aTexCoord;
+  vColor = aColor;
+}
+);
+
+const char* FRAGMENT_SHADER_L8 = MAKE_SHADER(
+uniform lowp    vec4      uColor;
+uniform lowp    vec4      textColorAnimatable;
+uniform         sampler2D sTexture;
+varying mediump vec2      vTexCoord;
+varying mediump vec4      vColor;
+
+void main()
+{
+  mediump vec4 color = texture2D( sTexture, vTexCoord );
+  gl_FragColor = vec4( vColor.rgb * uColor.rgb * textColorAnimatable.rgb, uColor.a * vColor.a * textColorAnimatable.a * color.r );
+}
+);
+
+const char* FRAGMENT_SHADER_RGBA = MAKE_SHADER(
+uniform lowp    vec4      uColor;
+uniform lowp    vec4      textColorAnimatable;
+uniform         sampler2D sTexture;
+varying mediump vec2      vTexCoord;
+
+void main()
+{
+  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * textColorAnimatable;
+}
+);
+
+const float ZERO( 0.0f );
+const float HALF( 0.5f );
+const float ONE( 1.0f );
+const uint32_t DEFAULT_ATLAS_WIDTH = 512u;
+const uint32_t DEFAULT_ATLAS_HEIGHT = 512u;
+const uint16_t NO_OUTLINE = 0u;
+}
+
+struct AtlasRenderer::Impl
+{
+  enum Style
+  {
+    STYLE_NORMAL,
+    STYLE_DROP_SHADOW
+  };
+
+  struct MeshRecord
+  {
+    MeshRecord()
+    : mAtlasId( 0u )
+    {
+    }
+
+    uint32_t mAtlasId;
+    AtlasManager::Mesh2D mMesh;
+  };
+
+  /**
+   * brief Struct used to generate the underline mesh.
+   * There is one Extent per line of text.
+   */
+  struct Extent
+  {
+    Extent()
+    : mBaseLine( 0.0f ),
+      mLeft( 0.0f ),
+      mRight( 0.0f ),
+      mUnderlinePosition( 0.0f ),
+      mUnderlineThickness( 0.0f ),
+      mMeshRecordIndex( 0u )
+    {
+    }
+
+    float mBaseLine;
+    float mLeft;
+    float mRight;
+    float mUnderlinePosition;
+    float mUnderlineThickness;
+    uint32_t mMeshRecordIndex;
+  };
+
+  struct MaxBlockSize
+  {
+    MaxBlockSize()
+    : mFontId( 0 ),
+      mNeededBlockWidth( 0 ),
+      mNeededBlockHeight( 0 )
+    {
+    }
+
+    FontId mFontId;
+    uint32_t mNeededBlockWidth;
+    uint32_t mNeededBlockHeight;
+  };
+
+  struct CheckEntry
+  {
+    CheckEntry()
+    : mFontId( 0 ),
+      mIndex( 0 )
+    {
+    }
+
+    FontId mFontId;
+    Text::GlyphIndex mIndex;
+  };
+
+  struct TextCacheEntry
+  {
+    TextCacheEntry()
+    : mFontId{ 0u },
+      mIndex{ 0u },
+      mImageId{ 0u },
+      mOutlineWidth{ 0u },
+      isItalic{ false },
+      isBold{ false }
+    {
+    }
+
+    FontId mFontId;
+    Text::GlyphIndex mIndex;
+    uint32_t mImageId;
+    uint16_t mOutlineWidth;
+    bool isItalic:1;
+    bool isBold:1;
+  };
+
+  Impl()
+  : mDepth( 0 )
+  {
+    mGlyphManager = AtlasGlyphManager::Get();
+    mFontClient = TextAbstraction::FontClient::Get();
+
+    mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+    mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+    mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
+  }
+
+  bool IsGlyphUnderlined( GlyphIndex index,
+                          const Vector<GlyphRun>& underlineRuns )
+  {
+    for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
+           endIt = underlineRuns.End();
+           it != endIt;
+         ++it )
+    {
+      const GlyphRun& run = *it;
+
+      if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
+      {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  void CacheGlyph( const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot )
+  {
+    const bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, style, slot );  // Check FontGlyphRecord vector for entry with glyph index and fontId
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached)?"not cached":"cached" );
+
+    if( glyphNotCached )
+    {
+      MaxBlockSize& blockSize = mBlockSizes[0u];
+
+      if ( lastFontId != glyph.fontId )
+      {
+        uint32_t index = 0u;
+        // Looks through all stored block sizes until finds the one which mataches required glyph font it.  Ensures new atlas block size will match existing for same font id.
+        // CalculateBlocksSize() above ensures a block size entry exists.
+        for( std::vector<MaxBlockSize>::const_iterator it = mBlockSizes.begin(),
+               endIt = mBlockSizes.end();
+             it != endIt;
+             ++it, ++index )
+        {
+          const MaxBlockSize& blockSizeEntry = *it;
+          if( blockSizeEntry.mFontId == glyph.fontId )
+          {
+            blockSize = mBlockSizes[index];
+          }
+        }
+      }
+
+      // Create a new image for the glyph
+      PixelData bitmap;
+
+      // Whether the glyph is an outline.
+      const bool isOutline = 0u != style.outline;
+
+      // Whether the current glyph is a color one.
+      const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index );
+
+      if( !isOutline || ( isOutline && !isColorGlyph) )
+      {
+        // Retrieve the emoji's bitmap.
+        TextAbstraction::FontClient::GlyphBufferData glyphBufferData;
+        glyphBufferData.width = isColorGlyph ? glyph.width : 0;   // Desired width and height.
+        glyphBufferData.height = isColorGlyph ? glyph.height : 0;
+
+        mFontClient.CreateBitmap( glyph.fontId,
+                                  glyph.index,
+                                  glyph.isItalicRequired,
+                                  glyph.isBoldRequired,
+                                  glyphBufferData,
+                                  style.outline );
+
+        // Create the pixel data.
+        bitmap = PixelData::New( glyphBufferData.buffer,
+                                 glyphBufferData.width * glyphBufferData.height * GetBytesPerPixel( glyphBufferData.format ),
+                                 glyphBufferData.width,
+                                 glyphBufferData.height,
+                                 glyphBufferData.format,
+                                 PixelData::DELETE_ARRAY );
+
+        if( bitmap )
+        {
+          // Ensure that the next image will fit into the current block size
+          if( bitmap.GetWidth() > blockSize.mNeededBlockWidth )
+          {
+            blockSize.mNeededBlockWidth = bitmap.GetWidth();
+          }
+
+          if( bitmap.GetHeight() > blockSize.mNeededBlockHeight )
+          {
+            blockSize.mNeededBlockHeight = bitmap.GetHeight();
+          }
+
+          // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas
+
+          // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice.
+          mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH,
+                                         DEFAULT_ATLAS_HEIGHT,
+                                         blockSize.mNeededBlockWidth,
+                                         blockSize.mNeededBlockHeight );
+
+          // Locate a new slot for our glyph
+          mGlyphManager.Add( glyph, style, bitmap, slot ); // slot will be 0 is glyph not added
+        }
+      }
+    }
+    else
+    {
+      // We have 2+ copies of the same glyph
+      mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, style, 1 ); //increment
+    }
+  }
+
+  void GenerateMesh( const GlyphInfo& glyph,
+                     const Vector2& position,
+                     const Vector4& color,
+                     uint16_t outline,
+                     AtlasManager::AtlasSlot& slot,
+                     bool underlineGlyph,
+                     float currentUnderlinePosition,
+                     float currentUnderlineThickness,
+                     std::vector<MeshRecord>& meshContainer,
+                     Vector<TextCacheEntry>& newTextCache,
+                     Vector<Extent>& extents )
+  {
+    // Generate mesh data for this quad, plugging in our supplied position
+    AtlasManager::Mesh2D newMesh;
+    mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
+
+    TextCacheEntry textCacheEntry;
+    textCacheEntry.mFontId = glyph.fontId;
+    textCacheEntry.mImageId = slot.mImageId;
+    textCacheEntry.mIndex = glyph.index;
+    textCacheEntry.mOutlineWidth = outline;
+    textCacheEntry.isItalic = glyph.isItalicRequired;
+    textCacheEntry.isBold = glyph.isBoldRequired;
+
+    newTextCache.PushBack( textCacheEntry );
+
+    AtlasManager::Vertex2D* verticesBuffer = newMesh.mVertices.Begin();
+
+    for( unsigned int index = 0u, size = newMesh.mVertices.Count();
+         index < size;
+         ++index )
+    {
+      AtlasManager::Vertex2D& vertex = *( verticesBuffer + index );
+
+      // Set the color of the vertex.
+      vertex.mColor = color;
+    }
+
+    // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
+    StitchTextMesh( meshContainer,
+                    newMesh,
+                    extents,
+                    position.y + glyph.yBearing,
+                    underlineGlyph,
+                    currentUnderlinePosition,
+                    currentUnderlineThickness,
+                    slot );
+  }
+
+  void CreateActors( const std::vector<MeshRecord>& meshContainer,
+                     const Size& textSize,
+                     const Vector4& color,
+                     const Vector4& shadowColor,
+                     const Vector2& shadowOffset,
+                     Actor textControl,
+                     Property::Index animatablePropertyIndex,
+                     bool drawShadow )
+  {
+    if( !mActor )
+    {
+      // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues.
+      mActor = Actor::New();
+      mActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      mActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      mActor.SetSize( textSize );
+      mActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+    }
+
+    for( std::vector< MeshRecord >::const_iterator it = meshContainer.begin(),
+           endIt = meshContainer.end();
+         it != endIt; ++it )
+    {
+      const MeshRecord& meshRecord = *it;
+
+      Actor actor = CreateMeshActor( textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_NORMAL );
+
+      // Whether the actor has renderers.
+      const bool hasRenderer = actor.GetRendererCount() > 0u;
+
+      // Create an effect if necessary
+      if( hasRenderer &&
+          drawShadow )
+      {
+        // Change the color of the vertices.
+        for( Vector<AtlasManager::Vertex2D>::Iterator vIt =  meshRecord.mMesh.mVertices.Begin(),
+               vEndIt = meshRecord.mMesh.mVertices.End();
+             vIt != vEndIt;
+             ++vIt )
+        {
+          AtlasManager::Vertex2D& vertex = *vIt;
+
+          vertex.mColor = shadowColor;
+        }
+
+        Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_DROP_SHADOW );
+#if defined(DEBUG_ENABLED)
+        shadowActor.SetName( "Text Shadow renderable actor" );
+#endif
+        // Offset shadow in x and y
+        shadowActor.RegisterProperty("uOffset", shadowOffset );
+        Dali::Renderer renderer( shadowActor.GetRendererAt( 0 ) );
+        int depthIndex = renderer.GetProperty<int>(Dali::Renderer::Property::DEPTH_INDEX);
+        renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex - 1 );
+        mActor.Add( shadowActor );
+      }
+
+      if( hasRenderer )
+      {
+        mActor.Add( actor );
+      }
+    }
+  }
+
+  void AddGlyphs( Text::ViewInterface& view,
+                  Actor textControl,
+                  Property::Index animatablePropertyIndex,
+                  const Vector<Vector2>& positions,
+                  const Vector<GlyphInfo>& glyphs,
+                  const Vector4& defaultColor,
+                  const Vector4* const colorsBuffer,
+                  const ColorIndex* const colorIndicesBuffer,
+                  int depth,
+                  float minLineOffset )
+  {
+    AtlasManager::AtlasSlot slot;
+    slot.mImageId = 0u;
+    slot.mAtlasId = 0u;
+
+    AtlasManager::AtlasSlot slotOutline;
+    slotOutline.mImageId = 0u;
+    slotOutline.mAtlasId = 0u;
+
+    std::vector< MeshRecord > meshContainer;
+    std::vector< MeshRecord > meshContainerOutline;
+    Vector< Extent > extents;
+    mDepth = depth;
+
+    const Vector2& textSize( view.GetLayoutSize() );
+    const Vector2 halfTextSize( textSize * 0.5f );
+    const Vector2& shadowOffset( view.GetShadowOffset() );
+    const Vector4& shadowColor( view.GetShadowColor() );
+    const bool underlineEnabled = view.IsUnderlineEnabled();
+    const Vector4& underlineColor( view.GetUnderlineColor() );
+    const float underlineHeight = view.GetUnderlineHeight();
+    const uint16_t outlineWidth = view.GetOutlineWidth();
+    const Vector4& outlineColor( view.GetOutlineColor() );
+    const bool isOutline = 0u != outlineWidth;
+
+    const bool useDefaultColor = ( NULL == colorsBuffer );
+
+    // Get the underline runs.
+    const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
+    Vector<GlyphRun> underlineRuns;
+    underlineRuns.Resize( numberOfUnderlineRuns );
+    view.GetUnderlineRuns( underlineRuns.Begin(),
+                           0u,
+                           numberOfUnderlineRuns );
+
+    bool thereAreUnderlinedGlyphs = false;
+
+    float currentUnderlinePosition = ZERO;
+    float currentUnderlineThickness = underlineHeight;
+    FontId lastFontId = 0;
+    FontId lastUnderlinedFontId = 0;
+    Style style = STYLE_NORMAL;
+
+    if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+    {
+      style = STYLE_DROP_SHADOW;
+    }
+
+    CalculateBlocksSize( glyphs );
+
+    // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
+    Vector< TextCacheEntry > newTextCache;
+    const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+    const Vector2* const positionsBuffer = positions.Begin();
+    const Vector2 lineOffsetPosition( minLineOffset, 0.f );
+
+    for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
+    {
+      const GlyphInfo& glyph = *( glyphsBuffer + i );
+      const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined( i, underlineRuns );
+      thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined;
+
+      // No operation for white space
+      if( glyph.width && glyph.height )
+      {
+        // Are we still using the same fontId as previous
+        if( isGlyphUnderlined && ( glyph.fontId != lastUnderlinedFontId ) )
+        {
+          // We need to fetch fresh font underline metrics
+          FontMetrics fontMetrics;
+          mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
+          currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
+          const float descender = ceil( fabsf( fontMetrics.descender ) );
+
+          if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
+          {
+            currentUnderlineThickness = fontMetrics.underlineThickness;
+
+            // Ensure underline will be at least a pixel high
+            if ( currentUnderlineThickness < ONE )
+            {
+              currentUnderlineThickness = ONE;
+            }
+            else
+            {
+              currentUnderlineThickness = ceil( currentUnderlineThickness );
+            }
+          }
+
+          // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
+          if( currentUnderlinePosition > descender )
+          {
+            currentUnderlinePosition = descender;
+          }
+
+          if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
+          {
+            // Move offset down by one ( EFL behavior )
+            currentUnderlinePosition = ONE;
+          }
+
+          lastUnderlinedFontId = glyph.fontId;
+        } // underline
+
+        AtlasGlyphManager::GlyphStyle style;
+        style.isItalic = glyph.isItalicRequired;
+        style.isBold = glyph.isBoldRequired;
+
+        // Retrieves and caches the glyph's bitmap.
+        CacheGlyph( glyph, lastFontId, style, slot );
+
+        // Retrieves and caches the outline glyph's bitmap.
+        if( isOutline )
+        {
+          style.outline = outlineWidth;
+          CacheGlyph( glyph, lastFontId, style, slotOutline );
+        }
+
+        // Move the origin (0,0) of the mesh to the center of the actor
+        const Vector2 position = *( positionsBuffer + i ) - halfTextSize - lineOffsetPosition;
+
+        if ( 0u != slot.mImageId ) // invalid slot id, glyph has failed to be added to atlas
+        {
+          Vector2 positionPlusOutlineOffset = position;
+          if( isOutline )
+          {
+            // Add an offset to the text.
+            const float outlineWidthOffset = static_cast<float>( outlineWidth );
+            positionPlusOutlineOffset += Vector2( outlineWidthOffset, outlineWidthOffset );
+          }
+
+          // Get the color of the character.
+          const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
+          const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
+
+          GenerateMesh( glyph,
+                        positionPlusOutlineOffset,
+                        color,
+                        NO_OUTLINE,
+                        slot,
+                        isGlyphUnderlined,
+                        currentUnderlinePosition,
+                        currentUnderlineThickness,
+                        meshContainer,
+                        newTextCache,
+                        extents);
+
+          lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
+        }
+
+        if( isOutline && ( 0u != slotOutline.mImageId ) ) // invalid slot id, glyph has failed to be added to atlas
+        {
+          GenerateMesh( glyph,
+                        position,
+                        outlineColor,
+                        outlineWidth,
+                        slotOutline,
+                        false,
+                        currentUnderlinePosition,
+                        currentUnderlineThickness,
+                        meshContainerOutline,
+                        newTextCache,
+                        extents);
+        }
+      }
+    } // glyphs
+
+    // Now remove references for the old text
+    RemoveText();
+    mTextCache.Swap( newTextCache );
+
+    if( thereAreUnderlinedGlyphs )
+    {
+      // Check to see if any of the text needs an underline
+      GenerateUnderlines( meshContainer, extents, underlineColor );
+    }
+
+    // For each MeshData object, create a mesh actor and add to the renderable actor
+    bool isShadowDrawn = false;
+    if( !meshContainerOutline.empty() )
+    {
+      const bool drawShadow = STYLE_DROP_SHADOW == style;
+      CreateActors( meshContainerOutline,
+                    textSize,
+                    outlineColor,
+                    shadowColor,
+                    shadowOffset,
+                    textControl,
+                    animatablePropertyIndex,
+                    drawShadow );
+
+      isShadowDrawn = drawShadow;
+    }
+
+    // For each MeshData object, create a mesh actor and add to the renderable actor
+    if( !meshContainer.empty() )
+    {
+      const bool drawShadow = !isShadowDrawn && ( STYLE_DROP_SHADOW == style );
+      CreateActors( meshContainer,
+                    textSize,
+                    defaultColor,
+                    shadowColor,
+                    shadowOffset,
+                    textControl,
+                    animatablePropertyIndex,
+                    drawShadow );
+    }
+
+#if defined(DEBUG_ENABLED)
+    Toolkit::AtlasGlyphManager::Metrics metrics = mGlyphManager.GetMetrics();
+    DALI_LOG_INFO( gLogFilter, Debug::General, "TextAtlasRenderer::GlyphManager::GlyphCount: %i, AtlasCount: %i, TextureMemoryUse: %iK\n",
+                                                metrics.mGlyphCount,
+                                                metrics.mAtlasMetrics.mAtlasCount,
+                                                metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
+
+    for( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "   Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
+                                                 i + 1, i > 8 ? "" : " ",
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8  " : "BGRA",
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mHeight,
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockWidth,
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mBlockHeight,
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mBlocksUsed,
+                                                 metrics.mAtlasMetrics.mAtlasMetrics[ i ].mTotalBlocks );
+    }
+#endif
+  }
+
+  void RemoveText()
+  {
+    for( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
+    {
+      AtlasGlyphManager::GlyphStyle style;
+      style.outline = oldTextIter->mOutlineWidth;
+      style.isItalic = oldTextIter->isItalic;
+      style.isBold = oldTextIter->isBold;
+      mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, style, -1/*decrement*/ );
+    }
+    mTextCache.Resize( 0 );
+  }
+
+  Actor CreateMeshActor( Actor textControl, Property::Index animatablePropertyIndex, const Vector4& defaultColor, const MeshRecord& meshRecord,
+                         const Vector2& actorSize, Style style )
+  {
+    PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat );
+    quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() );
+
+    Geometry quadGeometry = Geometry::New();
+    quadGeometry.AddVertexBuffer( quadVertices );
+    quadGeometry.SetIndexBuffer( &meshRecord.mMesh.mIndices[0],  meshRecord.mMesh.mIndices.Size() );
+
+    TextureSet textureSet( mGlyphManager.GetTextures( meshRecord.mAtlasId ) );
+
+    // Choose the shader to use.
+    const bool isColorShader = ( STYLE_DROP_SHADOW != style ) && ( Pixel::BGRA8888 == mGlyphManager.GetPixelFormat( meshRecord.mAtlasId ) );
+    Shader shader;
+    if( isColorShader )
+    {
+      // The glyph is an emoji and is not a shadow.
+      if( !mShaderRgba )
+      {
+        mShaderRgba = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_RGBA );
+      }
+      shader = mShaderRgba;
+    }
+    else
+    {
+      // The glyph is text or a shadow.
+      if( !mShaderL8 )
+      {
+        mShaderL8 = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_L8 );
+      }
+      shader = mShaderL8;
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "defaultColor[%f, %f, %f, %f ]\n", defaultColor.r, defaultColor.g, defaultColor.b, defaultColor.a  );
+
+    Dali::Property::Index shaderTextColorIndex = shader.RegisterProperty( "textColorAnimatable", defaultColor );
+
+    if ( animatablePropertyIndex != Property::INVALID_INDEX )
+    {
+      // create constraint for the animatable text's color Property with textColorAnimatable in the shader.
+      if( shaderTextColorIndex  )
+      {
+        Constraint constraint = Constraint::New<Vector4>( shader, shaderTextColorIndex, EqualToConstraint() );
+        constraint.AddSource( Source( textControl, animatablePropertyIndex ) );
+        constraint.Apply();
+      }
+    }
+    else
+    {
+      // If not animating the text colour then set to 1's so shader uses the current vertex color
+      shader.RegisterProperty( "textColorAnimatable", Vector4(1.0, 1.0, 1.0, 1.0 ) );
+    }
+
+    Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, shader );
+    renderer.SetTextures( textureSet );
+    renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
+    renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT + mDepth );
+
+    Actor actor = Actor::New();
+#if defined(DEBUG_ENABLED)
+    actor.SetName( "Text renderable actor" );
+#endif
+    actor.AddRenderer( renderer );
+    // Keep all of the origins aligned
+    actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+    actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    actor.SetSize( actorSize );
+    actor.RegisterProperty("uOffset", Vector2::ZERO );
+    actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+
+    return actor;
+  }
+
+  void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
+                       AtlasManager::Mesh2D& newMesh,
+                       Vector< Extent >& extents,
+                       float baseLine,
+                       bool underlineGlyph,
+                       float underlinePosition,
+                       float underlineThickness,
+                       AtlasManager::AtlasSlot& slot )
+  {
+    if ( slot.mImageId )
+    {
+      float left = newMesh.mVertices[ 0 ].mPosition.x;
+      float right = newMesh.mVertices[ 1 ].mPosition.x;
+
+      // Check to see if there's a mesh data object that references the same atlas ?
+      uint32_t index = 0;
+      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(),
+              mEndIt = meshContainer.end();
+            mIt != mEndIt;
+            ++mIt, ++index )
+      {
+        if( slot.mAtlasId == mIt->mAtlasId )
+        {
+          // Append the mesh to the existing mesh and adjust any extents
+          Toolkit::Internal::AtlasMeshFactory::AppendMesh( mIt->mMesh, newMesh );
+
+          if( underlineGlyph )
+          {
+            AdjustExtents( extents,
+                           meshContainer,
+                           index,
+                           left,
+                           right,
+                           baseLine,
+                           underlinePosition,
+                           underlineThickness );
+          }
+
+          return;
+        }
+      }
+
+      // No mesh data object currently exists that references this atlas, so create a new one
+      MeshRecord meshRecord;
+      meshRecord.mAtlasId = slot.mAtlasId;
+      meshRecord.mMesh = newMesh;
+      meshContainer.push_back( meshRecord );
+
+      if( underlineGlyph )
+      {
+        // Adjust extents for this new meshrecord
+        AdjustExtents( extents,
+                       meshContainer,
+                       meshContainer.size() - 1u,
+                       left,
+                       right,
+                       baseLine,
+                       underlinePosition,
+                       underlineThickness );
+      }
+    }
+  }
+
+  void AdjustExtents( Vector< Extent >& extents,
+                      std::vector< MeshRecord>& meshRecords,
+                      uint32_t index,
+                      float left,
+                      float right,
+                      float baseLine,
+                      float underlinePosition,
+                      float underlineThickness )
+  {
+    bool foundExtent = false;
+    for ( Vector< Extent >::Iterator eIt = extents.Begin(),
+            eEndIt = extents.End();
+          eIt != eEndIt;
+          ++eIt )
+    {
+      if ( Equals( baseLine, eIt->mBaseLine ) )
+      {
+        foundExtent = true;
+        if ( left < eIt->mLeft )
+        {
+          eIt->mLeft = left;
+        }
+        if ( right > eIt->mRight  )
+        {
+          eIt->mRight = right;
+        }
+
+        if ( underlinePosition > eIt->mUnderlinePosition )
+        {
+          eIt->mUnderlinePosition = underlinePosition;
+        }
+        if ( underlineThickness > eIt->mUnderlineThickness )
+        {
+          eIt->mUnderlineThickness = underlineThickness;
+        }
+      }
+    }
+    if ( !foundExtent )
+    {
+      Extent extent;
+      extent.mLeft = left;
+      extent.mRight = right;
+      extent.mBaseLine = baseLine;
+      extent.mUnderlinePosition = underlinePosition;
+      extent.mUnderlineThickness = underlineThickness;
+      extent.mMeshRecordIndex = index;
+      extents.PushBack( extent );
+    }
+  }
+
+  void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
+  {
+    for( Vector<GlyphInfo>::ConstIterator glyphIt = glyphs.Begin(),
+           glyphEndIt = glyphs.End();
+         glyphIt != glyphEndIt;
+         ++glyphIt )
+    {
+      const FontId fontId = (*glyphIt).fontId;
+      bool foundFont = false;
+
+      for( std::vector< MaxBlockSize >::const_iterator blockIt = mBlockSizes.begin(),
+             blockEndIt = mBlockSizes.end();
+           blockIt != blockEndIt;
+           ++blockIt )
+      {
+        if( (*blockIt).mFontId == fontId )  // Different size fonts will have a different fontId
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize match found fontID(%u) glyphIndex(%u)\n", fontId, (*glyphIt).index );
+          foundFont = true;
+          break;
+        }
+      }
+
+      if ( !foundFont )
+      {
+        FontMetrics fontMetrics;
+        mFontClient.GetFontMetrics( fontId, fontMetrics );
+
+        MaxBlockSize maxBlockSize;
+        maxBlockSize.mNeededBlockWidth = static_cast< uint32_t >( fontMetrics.height );
+        maxBlockSize.mNeededBlockHeight = maxBlockSize.mNeededBlockWidth;
+        maxBlockSize.mFontId = fontId;
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::CalculateBlocksSize New font with no matched blocksize, setting blocksize[%u]\n", maxBlockSize.mNeededBlockWidth );
+        mBlockSizes.push_back( maxBlockSize );
+      }
+    }
+  }
+
+  void GenerateUnderlines( std::vector< MeshRecord >& meshRecords,
+                           Vector< Extent >& extents,
+                           const Vector4& underlineColor )
+  {
+    AtlasManager::Mesh2D newMesh;
+    unsigned short faceIndex = 0;
+    for ( Vector< Extent >::ConstIterator eIt = extents.Begin(),
+            eEndIt = extents.End();
+          eIt != eEndIt;
+          ++eIt )
+    {
+      AtlasManager::Vertex2D vert;
+      uint32_t index = eIt->mMeshRecordIndex;
+      Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
+
+      // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
+      float u = HALF / uv.x;
+      float v = HALF / uv.y;
+      float thickness = eIt->mUnderlineThickness;
+      float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF );
+      float tlx = eIt->mLeft;
+      float brx = eIt->mRight;
+
+      vert.mPosition.x = tlx;
+      vert.mPosition.y = baseLine;
+      vert.mTexCoords.x = ZERO;
+      vert.mTexCoords.y = ZERO;
+      vert.mColor = underlineColor;
+      newMesh.mVertices.PushBack( vert );
+
+      vert.mPosition.x = brx;
+      vert.mPosition.y = baseLine;
+      vert.mTexCoords.x = u;
+      vert.mColor = underlineColor;
+      newMesh.mVertices.PushBack( vert );
+
+      vert.mPosition.x = tlx;
+      vert.mPosition.y = baseLine + thickness;
+      vert.mTexCoords.x = ZERO;
+      vert.mTexCoords.y = v;
+      vert.mColor = underlineColor;
+      newMesh.mVertices.PushBack( vert );
+
+      vert.mPosition.x = brx;
+      vert.mPosition.y = baseLine + thickness;
+      vert.mTexCoords.x = u;
+      vert.mColor = underlineColor;
+      newMesh.mVertices.PushBack( vert );
+
+      // Six indices in counter clockwise winding
+      newMesh.mIndices.PushBack( faceIndex + 1u );
+      newMesh.mIndices.PushBack( faceIndex );
+      newMesh.mIndices.PushBack( faceIndex + 2u );
+      newMesh.mIndices.PushBack( faceIndex + 2u );
+      newMesh.mIndices.PushBack( faceIndex + 3u );
+      newMesh.mIndices.PushBack( faceIndex + 1u );
+      faceIndex += 4;
+
+      Toolkit::Internal::AtlasMeshFactory::AppendMesh( meshRecords[ index ].mMesh, newMesh );
+    }
+  }
+
+  Actor mActor;                                       ///< The actor parent which renders the text
+  AtlasGlyphManager mGlyphManager;                    ///< Glyph Manager to handle upload and caching
+  TextAbstraction::FontClient mFontClient;            ///< The font client used to supply glyph information
+  Shader mShaderL8;                                   ///< The shader for glyphs and emoji's shadows.
+  Shader mShaderRgba;                                 ///< The shader for emojis.
+  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
+  int mDepth;                                         ///< DepthIndex passed by control when connect to stage
+};
+
+Text::RendererPtr AtlasRenderer::New()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::AtlasRenderer::New()\n" );
+
+  return Text::RendererPtr( new AtlasRenderer() );
+}
+
+Actor AtlasRenderer::Render( Text::ViewInterface& view,
+                             Actor textControl,
+                             Property::Index animatablePropertyIndex,
+                             float& alignmentOffset,
+                             int depth )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Text::AtlasRenderer::Render()\n" );
+
+  UnparentAndReset( mImpl->mActor );
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  if( numberOfGlyphs > 0u )
+  {
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize( numberOfGlyphs );
+
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
+
+    numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
+                                     positions.Begin(),
+                                     alignmentOffset,
+                                     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();
+
+    mImpl->AddGlyphs( view,
+                      textControl,
+                      animatablePropertyIndex,
+                      positions,
+                      glyphs,
+                      defaultColor,
+                      colorsBuffer,
+                      colorIndicesBuffer,
+                      depth,
+                      alignmentOffset );
+
+    /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */
+    /* This renderable actor is used to position the text, other "decorations" can rely on there always being an Actor regardless of it is whitespace or regular text. */
+    if ( !mImpl->mActor )
+    {
+      mImpl->mActor = Actor::New();
+    }
+  }
+
+  return mImpl->mActor;
+}
+
+AtlasRenderer::AtlasRenderer()
+{
+  mImpl = new Impl();
+
+}
+
+AtlasRenderer::~AtlasRenderer()
+{
+  mImpl->RemoveText();
+  delete mImpl;
+}
diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h
new file mode 100644 (file)
index 0000000..131dd26
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef DALI_TOOLKIT_TEXT_ATLAS_RENDERER_H
+#define DALI_TOOLKIT_TEXT_ATLAS_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Implementation of a text renderer based on dynamic atlases.
+ *
+ */
+class AtlasRenderer : public Renderer
+{
+public:
+
+  /**
+   * @brief Create the renderer.
+   */
+  static RendererPtr New();
+
+  /**
+   * @copydoc Renderer::Render()
+   */
+  virtual Actor Render( ViewInterface& view,
+                        Actor textControl,
+                        Property::Index animatablePropertyIndex,
+                        float& alignmentOffset,
+                        int depth );
+
+protected:
+
+  /**
+   * @brief Constructor.
+   */
+  AtlasRenderer();
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~AtlasRenderer();
+
+private:
+
+  // Undefined
+  AtlasRenderer( const AtlasRenderer& handle );
+
+  // Undefined
+  AtlasRenderer& operator=( const AtlasRenderer& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ATLAS_RENDERER_H
diff --git a/dali-toolkit/internal/text/rendering/text-backend-impl.cpp b/dali-toolkit/internal/text/rendering/text-backend-impl.cpp
new file mode 100644 (file)
index 0000000..10eb270
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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 <dali-toolkit/internal/text/rendering/text-backend-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/rendering-backend.h>
+#include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h>
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal
+{
+
+struct Backend::Impl
+{
+  int temp; // placeholder for future backend implemenations
+};
+
+Backend::Backend()
+: mImpl( NULL )
+{
+  mImpl = new Impl();
+}
+
+Backend::~Backend()
+{
+  delete mImpl;
+}
+
+Dali::Toolkit::Text::Backend Backend::Get()
+{
+  Dali::Toolkit::Text::Backend backendHandle;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Toolkit::Text::Backend ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      Backend* impl = dynamic_cast< Dali::Toolkit::Text::Internal::Backend* >( handle.GetObjectPtr() );
+      backendHandle = Dali::Toolkit::Text::Backend( impl );
+    }
+    else // create and register the object
+    {
+      backendHandle = Dali::Toolkit::Text::Backend( new Backend );
+      service.Register( typeid( backendHandle ), backendHandle );
+    }
+  }
+
+  return backendHandle;
+}
+
+RendererPtr Backend::NewRenderer( unsigned int renderingType )
+{
+  RendererPtr renderer;
+
+  switch( renderingType )
+  {
+    case Dali::Toolkit::Text::RENDERING_SHARED_ATLAS:
+    {
+      renderer = Dali::Toolkit::Text::AtlasRenderer::New();
+    }
+    break;
+
+    case Dali::Toolkit::Text::RENDERING_VECTOR_BASED:
+    {
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+      renderer = Dali::Toolkit::Text::VectorBasedRenderer::New();
+#else
+      renderer = Dali::Toolkit::Text::AtlasRenderer::New(); // Fallback to bitmap-based rendering
+#endif
+    }
+    break;
+
+    default:
+    {
+      DALI_LOG_WARNING( "Unknown renderer type: %d\n", renderingType );
+      break;
+    }
+  }
+
+  return renderer;
+}
+
+} // namespace Internal
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/text-backend-impl.h b/dali-toolkit/internal/text/rendering/text-backend-impl.h
new file mode 100644 (file)
index 0000000..fc52c5f
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_BACKEND_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_BACKEND_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-backend.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the text rendering backend
+ */
+class Backend : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  Backend();
+
+  /**
+   * Destructor
+   */
+  ~Backend();
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Backend::Get()
+   */
+  static Dali::Toolkit::Text::Backend Get();
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Backend::NewRenderer()
+   */
+  RendererPtr NewRenderer( unsigned int renderingType );
+
+private:
+
+  // Undefined copy constructor.
+  Backend( const Backend& );
+
+  // Undefined assignment constructor.
+  Backend& operator=( Backend& );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+
+}; // class Backend
+
+} // namespace Internal
+
+inline static Internal::Backend& GetImplementation(Backend& backend)
+{
+  DALI_ASSERT_ALWAYS( backend && "backend handle is empty" );
+  BaseObject& handle = backend.GetBaseObject();
+  return static_cast<Internal::Backend&>(handle);
+}
+
+inline static const Internal::Backend& GetImplementation(const Backend& backend)
+{
+  DALI_ASSERT_ALWAYS( backend && "backend handle is empty" );
+  const BaseObject& handle = backend.GetBaseObject();
+  return static_cast<const Internal::Backend&>(handle);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_BACKEND_H
diff --git a/dali-toolkit/internal/text/rendering/text-backend.cpp b/dali-toolkit/internal/text/rendering/text-backend.cpp
new file mode 100644 (file)
index 0000000..ee48026
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 <dali-toolkit/internal/text/rendering/text-backend.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-backend-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+Backend Backend::Get()
+{
+  return Internal::Backend::Get();
+}
+
+RendererPtr Backend::NewRenderer( unsigned int renderingType )
+{
+  return GetImplementation(*this).NewRenderer( renderingType );
+}
+
+Backend::Backend()
+{
+}
+
+Backend::~Backend()
+{
+}
+
+Backend::Backend( const Backend& handle )
+: BaseHandle( handle )
+{
+}
+
+Backend& Backend::operator=( const Backend& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+Backend::Backend( Internal::Backend* internal )
+: BaseHandle( internal )
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/text-backend.h b/dali-toolkit/internal/text/rendering/text-backend.h
new file mode 100644 (file)
index 0000000..2b554dc
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_TOOLKIT_TEXT_BACKEND_H
+#define DALI_TOOLKIT_TEXT_BACKEND_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Backend;
+}
+
+/**
+ * @brief Provides access to different text rendering backends.
+ */
+class Backend : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Retrieve a handle to the Backend instance.
+   *
+   * @return A handle to the Backend
+   */
+  static Backend Get();
+
+  /**
+   * @brief Create a renderer from a particluar rendering type.
+   *
+   * @param[in] renderingType The type of rendering required.
+   * @return A handle to the newly created renderer.
+   */
+  RendererPtr NewRenderer( unsigned int renderingType );
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   */
+  Backend();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Backend();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle.
+   */
+  Backend( const Backend& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  Backend& operator=( const Backend& handle );
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by Backend::Get().
+   *
+   * @param[in] backend A pointer to the internal backend object.
+   */
+  explicit DALI_INTERNAL Backend( Internal::Backend* backend );
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_BACKEND_H
diff --git a/dali-toolkit/internal/text/rendering/text-renderer.cpp b/dali-toolkit/internal/text/rendering/text-renderer.cpp
new file mode 100644 (file)
index 0000000..4d74934
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+Renderer::Renderer()
+{
+}
+
+Renderer::~Renderer()
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/text-renderer.h b/dali-toolkit/internal/text/rendering/text-renderer.h
new file mode 100644 (file)
index 0000000..65fbf50
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_TOOLKIT_TEXT_RENDERER_H
+#define DALI_TOOLKIT_TEXT_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/ref-object.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class Renderer;
+typedef IntrusivePtr<Renderer> RendererPtr;
+
+class ViewInterface;
+
+/**
+ * @brief Abstract base class for Text renderers.
+ *
+ * This is reponsible for rendering the glyphs from a ViewInterface in the specified positions.
+ * It is implemented by returning an Actor intended as the child of a UI control.
+ */
+class Renderer : public RefObject
+{
+public:
+
+  /**
+   * @brief Render the glyphs from a ViewInterface.
+   *
+   * @param[in] view The interface to a view.
+   * @param[in] textControl handle to the text control
+   * @param[in] animatablePropertyIndex textControl specific animatable property
+   * @param[out] alignmentOffset Offset used to internally align the placement actor.
+   * @param[in] depth The depth in the tree of the parent.
+   * @return The Renderable actor used to position the text.
+   */
+  virtual Actor Render( ViewInterface& view,
+                        Actor textContol,
+                        Property::Index animatablePropertyIndex,
+                        float& alignmentOffset,
+                        int depth ) = 0;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   */
+  Renderer();
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Renderer();
+
+private:
+
+  // Undefined
+  Renderer( const Renderer& handle );
+
+  // Undefined
+  Renderer& operator=( const Renderer& handle );
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_RENDERER_H
diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.cpp b/dali-toolkit/internal/text/rendering/text-typesetter.cpp
new file mode 100755 (executable)
index 0000000..5b424be
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/rendering/text-typesetter.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/public-api/common/constants.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/view-model.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+
+/**
+ * @brief Data struct used to set the buffer of the glyph's bitmap into the final bitmap's buffer.
+ */
+struct GlyphData
+{
+  Devel::PixelBuffer                           bitmapBuffer;     ///< The buffer of the whole bitmap. The format is RGBA8888.
+  Vector2*                                     position;         ///< The position of the glyph.
+  TextAbstraction::FontClient::GlyphBufferData glyphBitmap;      ///< The glyph's bitmap.
+  unsigned int                                 width;            ///< The bitmap's width.
+  unsigned int                                 height;           ///< The bitmap's height.
+  int                                          horizontalOffset; ///< The horizontal offset to be added to the 'x' glyph's position.
+  int                                          verticalOffset;   ///< The vertical offset to be added to the 'y' glyph's position.
+};
+
+/**
+ * @brief Sets the glyph's buffer into the bitmap's buffer.
+ *
+ * @param[in] data Struct which contains the glyph's data and the bitmap's data.
+ * @param[in] position The position of the glyph.
+ * @param[in] color The color of the glyph.
+ * @param[in] style The style of the text.
+ * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+ */
+void TypesetGlyph( GlyphData& data,
+                   const Vector2* const position,
+                   const Vector4* const color,
+                   Typesetter::Style style,
+                   Pixel::Format pixelFormat )
+{
+  if( ( 0u == data.glyphBitmap.width ) || ( 0u == data.glyphBitmap.height ) )
+  {
+    // Nothing to do if the width or height of the buffer is zero.
+    return;
+  }
+
+  const int widthMinusOne = static_cast<int>( data.width - 1u );
+  const int heightMinusOne = static_cast<int>( data.height - 1u );
+
+  if ( Pixel::RGBA8888 == pixelFormat )
+  {
+    // Whether the given glyph is a color one.
+    const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+    const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel( data.glyphBitmap.format );
+    const uint32_t alphaIndex = glyphPixelSize - 1u;
+    const bool swapChannelsBR = Pixel::BGRA8888 == data.glyphBitmap.format;
+
+    // Pointer to the color glyph if there is one.
+    const uint32_t* const colorGlyphBuffer = isColorGlyph ? reinterpret_cast<uint32_t*>( data.glyphBitmap.buffer ) : NULL;
+
+    // Initial vertical offset.
+    const int yOffset = data.verticalOffset + position->y;
+
+    uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( data.bitmapBuffer.GetBuffer() );
+
+    // Traverse the pixels of the glyph line per line.
+    for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
+    {
+      const int yOffsetIndex = yOffset + lineIndex;
+      if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
+      {
+        // Do not write out of bounds.
+        continue;
+      }
+
+      const int verticalOffset = yOffsetIndex * data.width;
+      const int xOffset = data.horizontalOffset + position->x;
+      const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+      for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
+      {
+        const int xOffsetIndex = xOffset + index;
+        if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+        {
+          // Don't write out of bounds.
+          continue;
+        }
+
+        if( isColorGlyph )
+        {
+          // Retrieves the color from the color glyph.
+          uint32_t packedColorGlyph = *( colorGlyphBuffer + glyphBufferOffset + index );
+          uint8_t* packedColorGlyphBuffer = reinterpret_cast<uint8_t*>( &packedColorGlyph );
+
+          // Update the alpha channel.
+          if( Typesetter::STYLE_MASK == style || Typesetter::STYLE_OUTLINE == style ) // Outline not shown for color glyph
+          {
+            // Create an alpha mask for color glyph.
+            *( packedColorGlyphBuffer + 3u ) = 0u;
+            *( packedColorGlyphBuffer + 2u ) = 0u;
+            *( packedColorGlyphBuffer + 1u ) = 0u;
+              *packedColorGlyphBuffer        = 0u;
+          }
+          else
+          {
+            const uint8_t colorAlpha = static_cast<uint8_t>( color->a * static_cast<float>( *( packedColorGlyphBuffer + 3u ) ) );
+            *( packedColorGlyphBuffer + 3u ) = colorAlpha;
+
+            if( Typesetter::STYLE_SHADOW == style )
+            {
+              // The shadow of color glyph needs to have the shadow color.
+              *( packedColorGlyphBuffer + 2u ) = static_cast<uint8_t>( color->b * colorAlpha );
+              *( packedColorGlyphBuffer + 1u ) = static_cast<uint8_t>( color->g * colorAlpha );
+                *packedColorGlyphBuffer        = static_cast<uint8_t>( color->r * colorAlpha );
+            }
+            else
+            {
+              if( swapChannelsBR )
+              {
+                std::swap( *packedColorGlyphBuffer, *( packedColorGlyphBuffer + 2u ) ); // Swap B and R.
+              }
+
+              *( packedColorGlyphBuffer + 2u ) = ( *( packedColorGlyphBuffer + 2u ) * colorAlpha / 255 );
+              *( packedColorGlyphBuffer + 1u ) = ( *( packedColorGlyphBuffer + 1u ) * colorAlpha / 255 );
+                *packedColorGlyphBuffer        = ( *( packedColorGlyphBuffer      ) * colorAlpha / 255 );
+
+              if( data.glyphBitmap.isColorBitmap )
+              {
+                *( packedColorGlyphBuffer + 2u ) = static_cast<uint8_t>( *( packedColorGlyphBuffer + 2u ) * color->b );
+                *( packedColorGlyphBuffer + 1u ) = static_cast<uint8_t>( *( packedColorGlyphBuffer + 1u ) * color->g );
+                  *packedColorGlyphBuffer        = static_cast<uint8_t>(   *packedColorGlyphBuffer * color->r );
+              }
+            }
+          }
+
+          // Set the color into the final pixel buffer.
+          *( bitmapBuffer + verticalOffset + xOffsetIndex ) = packedColorGlyph;
+        }
+        else
+        {
+          // Pack the given color into a 32bit buffer. The alpha channel will be updated later for each pixel.
+          // The format is RGBA8888.
+          uint32_t packedColor = 0u;
+          uint8_t* packedColorBuffer = reinterpret_cast<uint8_t*>( &packedColor );
+
+          // Update the alpha channel.
+          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphPixelSize * ( glyphBufferOffset + index ) + alphaIndex );
+
+          // Copy non-transparent pixels only
+          if ( alpha > 0u )
+          {
+            // Check alpha of overlapped pixels
+            uint32_t& currentColor = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+            uint8_t* packedCurrentColorBuffer = reinterpret_cast<uint8_t*>( &currentColor );
+
+            // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
+            // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
+            // semi-transparent gaps between joint glyphs with overlapped pixels, which could
+            // happen, for example, in the RTL text when we copy glyphs from right to left).
+            uint8_t currentAlpha = *( packedCurrentColorBuffer + 3u );
+            currentAlpha = std::max( currentAlpha, alpha );
+
+            // Color is pre-muliplied with its alpha.
+            *( packedColorBuffer + 3u ) = static_cast<uint8_t>( color->a * currentAlpha );
+            *( packedColorBuffer + 2u ) = static_cast<uint8_t>( color->b * currentAlpha );
+            *( packedColorBuffer + 1u ) = static_cast<uint8_t>( color->g * currentAlpha );
+            *( packedColorBuffer      ) = static_cast<uint8_t>( color->r * currentAlpha );
+
+            // Set the color into the final pixel buffer.
+            currentColor = packedColor;
+          }
+        }
+      }
+    }
+  }
+  else
+  {
+    // Whether the given glyph is a color one.
+    const bool isColorGlyph = data.glyphBitmap.isColorEmoji || data.glyphBitmap.isColorBitmap;
+    const uint32_t glyphPixelSize = Pixel::GetBytesPerPixel( data.glyphBitmap.format );
+    const uint32_t alphaIndex = glyphPixelSize - 1u;
+
+    // Initial vertical offset.
+    const int yOffset = data.verticalOffset + position->y;
+
+    uint8_t* bitmapBuffer = reinterpret_cast< uint8_t* >( data.bitmapBuffer.GetBuffer() );
+
+    // Traverse the pixels of the glyph line per line.
+    for( int lineIndex = 0, glyphHeight = static_cast<int>( data.glyphBitmap.height ); lineIndex < glyphHeight; ++lineIndex )
+    {
+      const int yOffsetIndex = yOffset + lineIndex;
+      if( ( 0 > yOffsetIndex ) || ( yOffsetIndex > heightMinusOne ) )
+      {
+        // Do not write out of bounds.
+        continue;
+      }
+
+      const int verticalOffset = yOffsetIndex * data.width;
+      const int xOffset = data.horizontalOffset + position->x;
+      const int glyphBufferOffset = lineIndex * static_cast<int>( data.glyphBitmap.width );
+      for( int index = 0, glyphWidth = static_cast<int>( data.glyphBitmap.width ); index < glyphWidth; ++index )
+      {
+        const int xOffsetIndex = xOffset + index;
+        if( ( 0 > xOffsetIndex ) || ( xOffsetIndex > widthMinusOne ) )
+        {
+          // Don't write out of bounds.
+          continue;
+        }
+
+        if ( !isColorGlyph )
+        {
+          // Update the alpha channel.
+          const uint8_t alpha = *( data.glyphBitmap.buffer + glyphPixelSize * ( glyphBufferOffset + index ) + alphaIndex );
+
+          // Copy non-transparent pixels only
+          if ( alpha > 0u )
+          {
+            // Check alpha of overlapped pixels
+            uint8_t& currentAlpha = *( bitmapBuffer + verticalOffset + xOffsetIndex );
+
+            // For any pixel overlapped with the pixel in previous glyphs, make sure we don't
+            // overwrite a previous bigger alpha with a smaller alpha (in order to avoid
+            // semi-transparent gaps between joint glyphs with overlapped pixels, which could
+            // happen, for example, in the RTL text when we copy glyphs from right to left).
+            currentAlpha = std::max( currentAlpha, alpha );
+          }
+        }
+      }
+    }
+  }
+}
+
+bool IsGlyphUnderlined( GlyphIndex index,
+                         const Vector<GlyphRun>& underlineRuns )
+{
+  for( Vector<GlyphRun>::ConstIterator it = underlineRuns.Begin(),
+         endIt = underlineRuns.End();
+         it != endIt;
+       ++it )
+  {
+    const GlyphRun& run = *it;
+
+    if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+} // namespace
+
+TypesetterPtr Typesetter::New( const ModelInterface* const model )
+{
+  return TypesetterPtr( new Typesetter( model ) );
+}
+
+ViewModel* Typesetter::GetViewModel()
+{
+  return mModel;
+}
+
+PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat )
+{
+  // @todo. This initial implementation for a TextLabel has only one visible page.
+
+  // Elides the text if needed.
+  mModel->ElideGlyphs();
+
+  // Retrieves the layout size.
+  const Size& layoutSize = mModel->GetLayoutSize();
+
+  const int outlineWidth = static_cast<int>( mModel->GetOutlineWidth() );
+
+  // Set the offset for the horizontal alignment according to the text direction and outline width.
+  int penX = 0;
+
+  switch( mModel->GetHorizontalAlignment() )
+  {
+    case HorizontalAlignment::BEGIN:
+    {
+      // No offset to add.
+      break;
+    }
+    case HorizontalAlignment::CENTER:
+    {
+      penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth : outlineWidth;
+      break;
+    }
+    case HorizontalAlignment::END:
+    {
+      penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth * 2 : outlineWidth * 2;
+      break;
+    }
+  }
+
+  // Set the offset for the vertical alignment.
+  int penY = 0u;
+
+  switch( mModel->GetVerticalAlignment() )
+  {
+    case VerticalAlignment::TOP:
+    {
+      // No offset to add.
+      break;
+    }
+    case VerticalAlignment::CENTER:
+    {
+      penY = static_cast<int>( 0.5f * ( size.height - layoutSize.height ) );
+      break;
+    }
+    case VerticalAlignment::BOTTOM:
+    {
+      penY = static_cast<int>( size.height - layoutSize.height );
+      break;
+    }
+  }
+
+  // Calculate vertical line alignment
+  switch( mModel->GetVerticalLineAlignment() )
+  {
+    case DevelText::VerticalLineAlignment::TOP:
+    {
+      break;
+    }
+    case DevelText::VerticalLineAlignment::MIDDLE:
+    {
+      const auto& line = *mModel->GetLines();
+      penY -= line.descender;
+      penY += static_cast<int>(line.lineSpacing*0.5f + line.descender);
+      break;
+    }
+    case DevelText::VerticalLineAlignment::BOTTOM:
+    {
+      const auto& line = *mModel->GetLines();
+      const auto lineHeight = line.ascender + (-line.descender) + line.lineSpacing;
+      penY += static_cast<int>(lineHeight - (line.ascender - line.descender));
+      break;
+    }
+  }
+
+  // Generate the image buffers of the text for each different style first,
+  // then combine all of them together as one final image buffer. We try to
+  // do all of these in CPU only, so that once the final texture is generated,
+  // no calculation is needed in GPU during each frame.
+
+  const unsigned int bufferWidth = static_cast<unsigned int>( size.width );
+  const unsigned int bufferHeight = static_cast<unsigned int>( size.height );
+
+  const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+  const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+
+  Length numberOfGlyphs = mModel->GetNumberOfGlyphs();
+
+  Devel::PixelBuffer imageBuffer;
+
+  if( RENDER_MASK == behaviour )
+  {
+    // Generate the image buffer as an alpha mask for color glyphs.
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_MASK, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
+  }
+  else if( RENDER_NO_TEXT == behaviour )
+  {
+    // Generate an empty image buffer so that it can been combined with the image buffers for styles
+    imageBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
+    memset( imageBuffer.GetBuffer(), 0u, bufferSizeChar );
+  }
+  else
+  {
+    // Generate the image buffer for the text with no style.
+    imageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_NONE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
+  }
+
+  if ( ( RENDER_NO_STYLES != behaviour ) && ( RENDER_MASK != behaviour ) )
+  {
+
+    // Generate the outline if enabled
+    const uint16_t outlineWidth = mModel->GetOutlineWidth();
+    if ( outlineWidth != 0u )
+    {
+      // Create the image buffer for outline
+      Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, outlineImageBuffer, bufferWidth, bufferHeight );
+    }
+
+    // @todo. Support shadow and underline for partial text later on.
+
+    // Generate the shadow if enabled
+    const Vector2& shadowOffset = mModel->GetShadowOffset();
+    if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+    {
+      // Create the image buffer for shadow
+      Devel::PixelBuffer shadowImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_SHADOW, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
+
+      // Check whether it will be a soft shadow
+      const float& blurRadius = mModel->GetShadowBlurRadius();
+
+      if ( blurRadius > Math::MACHINE_EPSILON_1 )
+      {
+        shadowImageBuffer.ApplyGaussianBlur( blurRadius );
+      }
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, shadowImageBuffer, bufferWidth, bufferHeight );
+    }
+
+    // Generate the underline if enabled
+    const bool underlineEnabled = mModel->IsUnderlineEnabled();
+    if ( underlineEnabled )
+    {
+      // Create the image buffer for underline
+      Devel::PixelBuffer underlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_UNDERLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1 );
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, underlineImageBuffer, bufferWidth, bufferHeight );
+    }
+
+    // Generate the background if enabled
+    const bool backgroundEnabled = mModel->IsBackgroundEnabled();
+    if ( backgroundEnabled )
+    {
+      Devel::PixelBuffer backgroundImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 );
+
+      // Combine the two buffers
+      imageBuffer = CombineImageBuffer( imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight );
+    }
+  }
+
+  // Create the final PixelData for the combined image buffer
+  PixelData pixelData = Devel::PixelBuffer::Convert( imageBuffer );
+
+  return pixelData;
+}
+
+Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, GlyphIndex fromGlyphIndex, GlyphIndex toGlyphIndex )
+{
+  // Retrieve lines, glyphs, positions and colors from the view model.
+  const Length modelNumberOfLines = mModel->GetNumberOfLines();
+  const LineRun* const modelLinesBuffer = mModel->GetLines();
+  const Length numberOfGlyphs = mModel->GetNumberOfGlyphs();
+  const GlyphInfo* const glyphsBuffer = mModel->GetGlyphs();
+  const Vector2* const positionBuffer = mModel->GetLayout();
+  const Vector4* const colorsBuffer = mModel->GetColors();
+  const ColorIndex* const colorIndexBuffer = mModel->GetColorIndices();
+
+  // Whether to use the default color.
+  const bool useDefaultColor = ( NULL == colorsBuffer );
+  const Vector4& defaultColor = mModel->GetDefaultColor();
+
+  // Create and initialize the pixel buffer.
+  GlyphData glyphData;
+  glyphData.verticalOffset = verticalOffset;
+  glyphData.width = bufferWidth;
+  glyphData.height = bufferHeight;
+  glyphData.bitmapBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, pixelFormat );
+  glyphData.horizontalOffset = 0;
+
+  if ( Pixel::RGBA8888 == pixelFormat )
+  {
+    const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+    const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+    memset( glyphData.bitmapBuffer.GetBuffer(), 0u, bufferSizeChar );
+  }
+  else
+  {
+    memset( glyphData.bitmapBuffer.GetBuffer(), 0, bufferWidth * bufferHeight );
+  }
+
+  // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  // Traverses the lines of the text.
+  for( LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex )
+  {
+    const LineRun& line = *( modelLinesBuffer + lineIndex );
+
+    // Sets the horizontal offset of the line.
+    glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int>( line.alignmentOffset );
+    glyphData.horizontalOffset += horizontalOffset;
+
+    // Increases the vertical offset with the line's ascender.
+    glyphData.verticalOffset += static_cast<int>( line.ascender );
+
+    // Include line spacing after first line
+    if( lineIndex > 0u )
+    {
+      glyphData.verticalOffset += static_cast<int>( line.lineSpacing );
+    }
+
+    // Retrieves the glyph's outline width
+    float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
+
+    if( style == Typesetter::STYLE_OUTLINE )
+    {
+      glyphData.horizontalOffset -= outlineWidth;
+      if( lineIndex == 0u )
+      {
+        // Only need to add the vertical outline offset for the first line
+        glyphData.verticalOffset -= outlineWidth;
+      }
+    }
+    else if ( style == Typesetter::STYLE_SHADOW )
+    {
+      const Vector2& shadowOffset = mModel->GetShadowOffset();
+      glyphData.horizontalOffset += shadowOffset.x - outlineWidth; // if outline enabled then shadow should offset from outline
+
+      if ( lineIndex == 0u )
+      {
+        // Only need to add the vertical shadow offset for first line
+        glyphData.verticalOffset += shadowOffset.y - outlineWidth;
+      }
+    }
+
+    const bool underlineEnabled = mModel->IsUnderlineEnabled();
+    const Vector4& underlineColor = mModel->GetUnderlineColor();
+    const float underlineHeight = mModel->GetUnderlineHeight();
+
+    // Get the underline runs.
+    const Length numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+    Vector<GlyphRun> underlineRuns;
+    underlineRuns.Resize( numberOfUnderlineRuns );
+    mModel->GetUnderlineRuns( underlineRuns.Begin(), 0u, numberOfUnderlineRuns );
+
+    bool thereAreUnderlinedGlyphs = false;
+
+    float currentUnderlinePosition = 0.0f;
+    float currentUnderlineThickness = underlineHeight;
+    float maxUnderlineThickness = currentUnderlineThickness;
+
+    FontId lastUnderlinedFontId = 0;
+
+    float lineExtentLeft = bufferWidth;
+    float lineExtentRight = 0.0f;
+    float baseline = 0.0f;
+
+    // Traverses the glyphs of the line.
+    const GlyphIndex endGlyphIndex = std::min( numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs );
+    for( GlyphIndex glyphIndex = line.glyphRun.glyphIndex; glyphIndex < endGlyphIndex; ++glyphIndex )
+    {
+      if ( glyphIndex < fromGlyphIndex || glyphIndex > toGlyphIndex )
+      {
+        // Ignore any glyph that out of the specified range
+        continue;
+      }
+
+      // Retrieve the glyph's info.
+      const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+
+      if( ( glyphInfo->width < Math::MACHINE_EPSILON_1000 ) ||
+          ( glyphInfo->height < Math::MACHINE_EPSILON_1000 ) )
+      {
+        // Nothing to do if the glyph's width or height is zero.
+        continue;
+      }
+
+      const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( glyphIndex, underlineRuns );
+      thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph;
+
+      // Are we still using the same fontId as previous
+      if( underlineGlyph && ( glyphInfo->fontId != lastUnderlinedFontId ) )
+      {
+        // We need to fetch fresh font underline metrics
+        FontMetrics fontMetrics;
+        fontClient.GetFontMetrics( glyphInfo->fontId, fontMetrics );
+        currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
+        const float descender = ceil( fabsf( fontMetrics.descender ) );
+
+        if( fabsf( underlineHeight ) < Math::MACHINE_EPSILON_1000 )
+        {
+          currentUnderlineThickness = fontMetrics.underlineThickness;
+
+          // Ensure underline will be at least a pixel high
+          if ( currentUnderlineThickness < 1.0f )
+          {
+            currentUnderlineThickness = 1.0f;
+          }
+          else
+          {
+            currentUnderlineThickness = ceil( currentUnderlineThickness );
+          }
+        }
+
+        // The underline thickness should be the max underline thickness of all glyphs of the line.
+        if ( currentUnderlineThickness > maxUnderlineThickness )
+        {
+          maxUnderlineThickness = currentUnderlineThickness;
+        }
+
+        // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
+        if( currentUnderlinePosition > descender )
+        {
+          currentUnderlinePosition = descender;
+        }
+
+        if( fabsf( currentUnderlinePosition ) < Math::MACHINE_EPSILON_1000 )
+        {
+          // Move offset down by one ( EFL behavior )
+          currentUnderlinePosition = 1.0f;
+        }
+
+        lastUnderlinedFontId = glyphInfo->fontId;
+      } // underline
+
+      // Retrieves the glyph's position.
+      const Vector2* const position = positionBuffer + glyphIndex;
+      if ( baseline < position->y + glyphInfo->yBearing )
+      {
+        baseline = position->y + glyphInfo->yBearing;
+      }
+
+      // Calculate the positions of leftmost and rightmost glyphs in the current line
+      if ( position->x < lineExtentLeft)
+      {
+        lineExtentLeft = position->x;
+      }
+
+      if ( position->x + glyphInfo->width > lineExtentRight)
+      {
+        lineExtentRight = position->x + glyphInfo->width;
+      }
+
+      // Retrieves the glyph's color.
+      const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndexBuffer + glyphIndex );
+
+      Vector4 color;
+      if ( style == Typesetter::STYLE_SHADOW )
+      {
+        color = mModel->GetShadowColor();
+      }
+      else if ( style == Typesetter::STYLE_OUTLINE )
+      {
+        color = mModel->GetOutlineColor();
+      }
+      else
+      {
+        color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + ( colorIndex - 1u ) );
+      }
+
+      // Premultiply alpha
+      color.r *= color.a;
+      color.g *= color.a;
+      color.b *= color.a;
+
+      // Retrieves the glyph's bitmap.
+      glyphData.glyphBitmap.buffer = NULL;
+      glyphData.glyphBitmap.width = glyphInfo->width;   // Desired width and height.
+      glyphData.glyphBitmap.height = glyphInfo->height;
+
+      if( style != Typesetter::STYLE_OUTLINE && style != Typesetter::STYLE_SHADOW )
+      {
+        // Don't render outline for other styles
+        outlineWidth = 0.0f;
+      }
+
+      if( style != Typesetter::STYLE_UNDERLINE )
+      {
+        fontClient.CreateBitmap( glyphInfo->fontId,
+                                 glyphInfo->index,
+                                 glyphInfo->isItalicRequired,
+                                 glyphInfo->isBoldRequired,
+                                 glyphData.glyphBitmap,
+                                 static_cast<int>( outlineWidth ) );
+      }
+
+      // Sets the glyph's bitmap into the bitmap of the whole text.
+      if( NULL != glyphData.glyphBitmap.buffer )
+      {
+        if ( style == Typesetter::STYLE_OUTLINE )
+        {
+          // Set the position offset for the current glyph
+          glyphData.horizontalOffset -= glyphData.glyphBitmap.outlineOffsetX;
+          glyphData.verticalOffset -= glyphData.glyphBitmap.outlineOffsetY;
+        }
+
+        // Set the buffer of the glyph's bitmap into the final bitmap's buffer
+        TypesetGlyph( glyphData,
+                      position,
+                      &color,
+                      style,
+                      pixelFormat);
+
+        if ( style == Typesetter::STYLE_OUTLINE )
+        {
+          // Reset the position offset for the next glyph
+          glyphData.horizontalOffset += glyphData.glyphBitmap.outlineOffsetX;
+          glyphData.verticalOffset += glyphData.glyphBitmap.outlineOffsetY;
+        }
+
+        // delete the glyphBitmap.buffer as it is now copied into glyphData.bitmapBuffer
+        delete []glyphData.glyphBitmap.buffer;
+        glyphData.glyphBitmap.buffer = NULL;
+      }
+    }
+
+    // Draw the underline from the leftmost glyph to the rightmost glyph
+    if ( thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE )
+    {
+      int underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
+
+      for( unsigned int y = underlineYOffset; y < underlineYOffset + maxUnderlineThickness; y++ )
+      {
+        if( y > bufferHeight - 1 )
+        {
+          // Do not write out of bounds.
+          break;
+        }
+
+        for( unsigned int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++ )
+        {
+          if( x > bufferWidth - 1 )
+          {
+            // Do not write out of bounds.
+            break;
+          }
+
+          // Always RGBA image for text with styles
+          uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
+          uint32_t underlinePixel = *( bitmapBuffer + y * glyphData.width + x );
+          uint8_t* underlinePixelBuffer = reinterpret_cast<uint8_t*>( &underlinePixel );
+
+          // Write the underline color to the pixel buffer
+          uint8_t colorAlpha = static_cast< uint8_t >( underlineColor.a * 255.f );
+          *( underlinePixelBuffer + 3u ) = colorAlpha;
+          *( underlinePixelBuffer + 2u ) = static_cast< uint8_t >( underlineColor.b * colorAlpha );
+          *( underlinePixelBuffer + 1u ) = static_cast< uint8_t >( underlineColor.g * colorAlpha );
+          *( underlinePixelBuffer      ) = static_cast< uint8_t >( underlineColor.r * colorAlpha );
+
+          *( bitmapBuffer + y * glyphData.width + x ) = underlinePixel;
+        }
+      }
+    }
+
+    // Draw the background color from the leftmost glyph to the rightmost glyph
+    if ( style == Typesetter::STYLE_BACKGROUND )
+    {
+      Vector4 backgroundColor = mModel->GetBackgroundColor();
+
+      for( int y = glyphData.verticalOffset + baseline - line.ascender; y < glyphData.verticalOffset + baseline - line.descender; y++ )
+      {
+        if( ( y < 0 ) || ( y > static_cast<int>(bufferHeight - 1) ) )
+        {
+          // Do not write out of bounds.
+          continue;
+        }
+
+        for( int x = glyphData.horizontalOffset + lineExtentLeft; x <= glyphData.horizontalOffset + lineExtentRight; x++ )
+        {
+          if( ( x < 0 ) || ( x > static_cast<int>(bufferWidth - 1) ) )
+          {
+            // Do not write out of bounds.
+            continue;
+          }
+
+          // Always RGBA image for text with styles
+          uint32_t* bitmapBuffer = reinterpret_cast< uint32_t* >( glyphData.bitmapBuffer.GetBuffer() );
+          uint32_t backgroundPixel = *( bitmapBuffer + y * glyphData.width + x );
+          uint8_t* backgroundPixelBuffer = reinterpret_cast<uint8_t*>( &backgroundPixel );
+
+          // Write the background color to the pixel buffer
+          uint8_t colorAlpha = static_cast< uint8_t >( backgroundColor.a * 255.f );
+          *( backgroundPixelBuffer + 3u ) = colorAlpha;
+          *( backgroundPixelBuffer + 2u ) = static_cast< uint8_t >( backgroundColor.b * colorAlpha );
+          *( backgroundPixelBuffer + 1u ) = static_cast< uint8_t >( backgroundColor.g * colorAlpha );
+          *( backgroundPixelBuffer      ) = static_cast< uint8_t >( backgroundColor.r * colorAlpha );
+
+          *( bitmapBuffer + y * glyphData.width + x ) = backgroundPixel;
+        }
+      }
+    }
+
+    // Increases the vertical offset with the line's descender.
+    glyphData.verticalOffset += static_cast<int>( -line.descender );
+  }
+
+  return glyphData.bitmapBuffer;
+}
+
+Devel::PixelBuffer Typesetter::CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight )
+{
+  unsigned char* topBuffer = topPixelBuffer.GetBuffer();
+  unsigned char* bottomBuffer = bottomPixelBuffer.GetBuffer();
+
+  Devel::PixelBuffer combinedPixelBuffer;
+
+  if ( topBuffer == NULL && bottomBuffer == NULL )
+  {
+    // Nothing to do if both buffers are empty.
+    return combinedPixelBuffer;
+  }
+
+  if ( topBuffer == NULL )
+  {
+    // Nothing to do if topBuffer is empty.
+    return bottomPixelBuffer;
+  }
+
+  if ( bottomBuffer == NULL )
+  {
+    // Nothing to do if bottomBuffer is empty.
+    return topPixelBuffer;
+  }
+
+  // Always combine two RGBA images
+  const unsigned int bufferSizeInt = bufferWidth * bufferHeight;
+  const unsigned int bufferSizeChar = 4u * bufferSizeInt;
+
+  combinedPixelBuffer = Devel::PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
+  uint8_t* combinedBuffer = reinterpret_cast< uint8_t* >( combinedPixelBuffer.GetBuffer() );
+  memset( combinedBuffer, 0u, bufferSizeChar );
+
+  for (unsigned int pixelIndex = 0; pixelIndex < bufferSizeInt; pixelIndex++)
+  {
+    // If the alpha of the pixel in either buffer is not fully opaque, blend the two pixels.
+    // Otherwise, copy pixel from topBuffer to combinedBuffer.
+
+    unsigned int alphaBuffer1 = topBuffer[pixelIndex*4+3];
+
+    if ( alphaBuffer1 != 255 )
+    {
+      // At least one pixel is not fully opaque
+      // "Over" blend the the pixel from topBuffer with the pixel in bottomBuffer
+      combinedBuffer[pixelIndex*4] = topBuffer[pixelIndex*4] + ( bottomBuffer[pixelIndex*4] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+      combinedBuffer[pixelIndex*4+1] = topBuffer[pixelIndex*4+1] + ( bottomBuffer[pixelIndex*4+1] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+      combinedBuffer[pixelIndex*4+2] = topBuffer[pixelIndex*4+2] + ( bottomBuffer[pixelIndex*4+2] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+      combinedBuffer[pixelIndex*4+3] = topBuffer[pixelIndex*4+3] + ( bottomBuffer[pixelIndex*4+3] * ( 255 - topBuffer[pixelIndex*4+3] ) / 255 );
+    }
+    else
+    {
+      // Copy the pixel from topBuffer to combinedBuffer
+      combinedBuffer[pixelIndex*4] = topBuffer[pixelIndex*4];
+      combinedBuffer[pixelIndex*4+1] = topBuffer[pixelIndex*4+1];
+      combinedBuffer[pixelIndex*4+2] = topBuffer[pixelIndex*4+2];
+      combinedBuffer[pixelIndex*4+3] = topBuffer[pixelIndex*4+3];
+    }
+  }
+
+  return combinedPixelBuffer;
+}
+
+Typesetter::Typesetter( const ModelInterface* const model )
+: mModel( new ViewModel( model ) )
+{
+}
+
+Typesetter::~Typesetter()
+{
+  delete mModel;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.h b/dali-toolkit/internal/text/rendering/text-typesetter.h
new file mode 100644 (file)
index 0000000..453541b
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef DALI_TOOLKIT_TEXT_TYPESETTER_H
+#define DALI_TOOLKIT_TEXT_TYPESETTER_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class ModelInterface;
+class ViewModel;
+class Typesetter;
+
+typedef IntrusivePtr<Typesetter> TypesetterPtr;
+
+/**
+ * @brief This class is responsible of controlling the data flow of the text's rendering process.
+ */
+class Typesetter : public RefObject
+{
+public:
+
+  /**
+   * @brief Behaviours of how to render the text.
+   */
+  enum RenderBehaviour
+  {
+    RENDER_TEXT_AND_STYLES,  ///< Render both the text and its styles
+    RENDER_NO_TEXT,          ///< Do not render the text itself
+    RENDER_NO_STYLES,        ///< Do not render any styles
+    RENDER_MASK              ///< Render an alpha mask (for color glyphs with no color animation, e.g. emoji)
+  };
+
+  /**
+   * @brief Styles of the text.
+   */
+  enum Style
+  {
+    STYLE_NONE,              ///< No style
+    STYLE_MASK,              ///< Alpha mask
+    STYLE_SHADOW,            ///< Hard shadow
+    STYLE_SOFT_SHADOW,       ///< Soft shadow
+    STYLE_UNDERLINE,         ///< Underline
+    STYLE_OUTLINE,           ///< Outline
+    STYLE_BACKGROUND         ///< Text background
+  };
+
+public: // Constructor.
+  /**
+   * @brief Creates a Typesetter instance.
+   *
+   * The typesetter composes the final text retrieving the glyphs and the
+   * styles from the text's model.
+   *
+   * @param[in] model Pointer to the text's data model.
+   */
+  static TypesetterPtr New( const ModelInterface* const model );
+
+public:
+  /**
+   * @brief Retrieves the pointer to the view model.
+   *
+   * @return A pointer to the view model.
+   */
+  ViewModel* GetViewModel();
+
+  /**
+   * @brief Renders the text.
+   *
+   * Does the following operations:
+   * - Finds the visible pages needed to be rendered.
+   * - Elide glyphs if needed.
+   * - Creates image buffers for diffrent text styles with the given size.
+   * - Combines different image buffers to create the pixel data used to generate the final image
+   *
+   * @param[in] size The renderer size.
+   * @param[in] textDirection The direction of the text.
+   * @param[in] behaviour The behaviour of how to render the text (i.e. whether to render the text only or the styles only or both).
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment (i.e. always render as if HORIZONTAL_ALIGN_BEGIN).
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   *
+   * @return A pixel data with the text rendered.
+   */
+  PixelData Render( const Vector2& size, Toolkit::DevelText::TextDirection::Type textDirection, RenderBehaviour behaviour = RENDER_TEXT_AND_STYLES, bool ignoreHorizontalAlignment = false, Pixel::Format pixelFormat = Pixel::RGBA8888 );
+
+private:
+  /**
+   * @brief Private constructor.
+   *
+   * @param[in] model Pointer to the text's data model.
+   */
+  Typesetter( const ModelInterface* const model );
+
+  // Declared private and left undefined to avoid copies.
+  Typesetter( const Typesetter& handle );
+
+  // Declared private and left undefined to avoid copies.
+  Typesetter& operator=( const Typesetter& handle );
+
+  /**
+   * @brief Create the image buffer for the given range of the glyphs in the given style.
+   *
+   * Does the following operations:
+   * - Retrieves the data buffers from the text model.
+   * - Creates the pixel data used to generate the final image with the given size.
+   * - Traverse the visible glyphs, retrieve their bitmaps and compose the final pixel data.
+   *
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   * @param[in] style The style of the text.
+   * @param[in] ignoreHorizontalAlignment Whether to ignore the horizontal alignment, not ignored by default.
+   * @param[in] pixelFormat The format of the pixel in the image that the text is rendered as (i.e. either Pixel::BGRA8888 or Pixel::L8).
+   * @param[in] horizontalOffset The horizontal offset to be added to the glyph's position.
+   * @param[in] verticalOffset The vertical offset to be added to the glyph's position.
+   * @param[in] fromGlyphIndex The index of the first glyph within the text to be drawn
+   * @param[in] toGlyphIndex The index of the last glyph within the text to be drawn
+   *
+   * @return An image buffer with the text.
+   */
+  Devel::PixelBuffer CreateImageBuffer( const unsigned int bufferWidth, const unsigned int bufferHeight, Typesetter::Style style, bool ignoreHorizontalAlignment, Pixel::Format pixelFormat, int horizontalOffset, int verticalOffset, TextAbstraction::GlyphIndex fromGlyphIndex, TextAbstraction::GlyphIndex toGlyphIndex );
+
+  /**
+   * @brief Combine the two RGBA image buffers together.
+   *
+   * The top layer buffer will blend over the bottom layer buffer:
+   * - If the pixel is not fully opaque from either buffer, it will be blended with
+   *   the pixel from the other buffer and copied to the combined buffer.
+   * - If the pixels from both buffers are fully opaque, the pixels from the top layer
+   *   buffer will be copied to the combined buffer.
+   *
+   * @param[in] topPixelBuffer The top layer buffer.
+   * @param[in] bottomPixelBuffer The bottom layer buffer.
+   * @param[in] bufferWidth The width of the image buffer.
+   * @param[in] bufferHeight The height of the image buffer.
+   *
+   * @return The combined image buffer with the text.
+   *
+   */
+  Devel::PixelBuffer CombineImageBuffer( Devel::PixelBuffer topPixelBuffer, Devel::PixelBuffer bottomPixelBuffer, const unsigned int bufferWidth, const unsigned int bufferHeightbool );
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   *
+   * Destroys the visual model.
+   */
+  virtual ~Typesetter();
+
+private:
+
+   ViewModel* mModel;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_TYPESETTER_H
diff --git a/dali-toolkit/internal/text/rendering/vector-based/file.list b/dali-toolkit/internal/text/rendering/vector-based/file.list
new file mode 100644 (file)
index 0000000..c2b81f4
--- /dev/null
@@ -0,0 +1,14 @@
+# Set the source directory
+SET( vector_based_text_src_dir ${ROOT_SRC_DIR}/dali-toolkit/internal/text/rendering/vector-based )
+
+# Add local source files here
+SET( vector_based_text_src_files
+   ${vector_based_text_src_dir}/vector-based-renderer.cpp
+   ${vector_based_text_src_dir}/vector-blob-atlas.cpp
+   ${vector_based_text_src_dir}/vector-blob-atlas-share.cpp
+   ${vector_based_text_src_dir}/glyphy-shader/glyphy-shader.cpp
+)
+
+SET( SOURCES ${SOURCES}
+  ${vector_based_text_src_files}
+)
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h
new file mode 100644 (file)
index 0000000..a3a1a30
--- /dev/null
@@ -0,0 +1,231 @@
+static const char *glyphy_common_glsl =
+"/*\n"
+" * Copyright 2012 Google, Inc. All Rights Reserved.\n"
+" *\n"
+" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+" * you may not use this file except in compliance with the License.\n"
+" * You may obtain a copy of the License at\n"
+" *\n"
+" *     http://www.apache.org/licenses/LICENSE-2.0\n"
+" *\n"
+" * Unless required by applicable law or agreed to in writing, software\n"
+" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+" * See the License for the specific language governing permissions and\n"
+" * limitations under the License.\n"
+" *\n"
+" * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
+" */\n"
+"\n"
+"\n"
+"#ifndef GLYPHY_INFINITY\n"
+"#  define GLYPHY_INFINITY 1e9\n"
+"#endif\n"
+"#ifndef GLYPHY_EPSILON\n"
+"#  define GLYPHY_EPSILON  1e-5\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_RGBA\n"
+"#  ifdef GLYPHY_BGRA\n"
+"#    define GLYPHY_RGBA(v) glyphy_bgra (v)\n"
+"#  else\n"
+"#    define GLYPHY_RGBA(v) glyphy_rgba (v)\n"
+"#  endif\n"
+"#endif\n"
+"\n"
+"vec4\n"
+"glyphy_rgba (const vec4 v)\n"
+"{\n"
+"  return v.rgba;\n"
+"}\n"
+"\n"
+"vec4\n"
+"glyphy_bgra (const vec4 v)\n"
+"{\n"
+"  return v.bgra;\n"
+"}\n"
+"\n"
+"\n"
+"struct glyphy_arc_t {\n"
+"  vec2  p0;\n"
+"  vec2  p1;\n"
+"  float d;\n"
+"};\n"
+"\n"
+"struct glyphy_arc_endpoint_t {\n"
+"  /* Second arc endpoint */\n"
+"  vec2  p;\n"
+"  /* Infinity if this endpoint does not form an arc with the previous\n"
+"   * endpoint.  Ie. a \"move_to\".  Test with glyphy_isinf().\n"
+"   * Arc depth otherwise.  */\n"
+"  float d;\n"
+"};\n"
+"\n"
+"struct glyphy_arc_list_t {\n"
+"  /* Number of endpoints in the list.\n"
+"   * Will be zero if we're far away inside or outside, in which case side is set.\n"
+"   * Will be -1 if this arc-list encodes a single line, in which case line_* are set. */\n"
+"  int num_endpoints;\n"
+"\n"
+"  /* If num_endpoints is zero, this specifies whether we are inside (-1)\n"
+"   * or outside (+1).  Otherwise we're unsure (0). */\n"
+"  int side;\n"
+"  /* Offset to the arc-endpoints from the beginning of the glyph blob */\n"
+"  int offset;\n"
+"\n"
+"  /* A single line is all we care about.  It's right here. */\n"
+"  float line_angle;\n"
+"  float line_distance; /* From nominal glyph center */\n"
+"};\n"
+"\n"
+"bool\n"
+"glyphy_isinf (const float v)\n"
+"{\n"
+"  return abs (v) >= GLYPHY_INFINITY * .5;\n"
+"}\n"
+"\n"
+"bool\n"
+"glyphy_iszero (const float v)\n"
+"{\n"
+"  return abs (v) <= GLYPHY_EPSILON * 2.;\n"
+"}\n"
+"\n"
+"vec2\n"
+"glyphy_ortho (const vec2 v)\n"
+"{\n"
+"  return vec2 (-v.y, v.x);\n"
+"}\n"
+"\n"
+"int\n"
+"glyphy_float_to_byte (const float v)\n"
+"{\n"
+"  return int (v * (256. - GLYPHY_EPSILON));\n"
+"}\n"
+"\n"
+"ivec4\n"
+"glyphy_vec4_to_bytes (const vec4 v)\n"
+"{\n"
+"  return ivec4 (v * (256. - GLYPHY_EPSILON));\n"
+"}\n"
+"\n"
+"ivec2\n"
+"glyphy_float_to_two_nimbles (const float v)\n"
+"{\n"
+"  int f = glyphy_float_to_byte (v);\n"
+"  return ivec2 (f / 16, int(mod (float(f), 16.)));\n"
+"}\n"
+"\n"
+"/* returns tan (2 * atan (d)) */\n"
+"float\n"
+"glyphy_tan2atan (const float d)\n"
+"{\n"
+"  return 2. * d / (1. - d * d);\n"
+"}\n"
+"\n"
+"glyphy_arc_endpoint_t\n"
+"glyphy_arc_endpoint_decode (const vec4 v, const ivec2 nominal_size)\n"
+"{\n"
+"  vec2 p = (vec2 (glyphy_float_to_two_nimbles (v.a)) + v.gb) / 16.;\n"
+"  float d = v.r;\n"
+"  if (d == 0.)\n"
+"    d = GLYPHY_INFINITY;\n"
+"  else\n"
+"#define GLYPHY_MAX_D .5\n"
+"    d = float(glyphy_float_to_byte (d) - 128) * GLYPHY_MAX_D / 127.;\n"
+"#undef GLYPHY_MAX_D\n"
+"  return glyphy_arc_endpoint_t (p * vec2(nominal_size), d);\n"
+"}\n"
+"\n"
+"vec2\n"
+"glyphy_arc_center (const glyphy_arc_t a)\n"
+"{\n"
+"  return mix (a.p0, a.p1, .5) +\n"
+"       glyphy_ortho (a.p1 - a.p0) / (2. * glyphy_tan2atan (a.d));\n"
+"}\n"
+"\n"
+"bool\n"
+"glyphy_arc_wedge_contains (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  float d2 = glyphy_tan2atan (a.d);\n"
+"  return dot (p - a.p0, (a.p1 - a.p0) * mat2(1,  d2, -d2, 1)) >= 0. &&\n"
+"       dot (p - a.p1, (a.p1 - a.p0) * mat2(1, -d2,  d2, 1)) <= 0.;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_wedge_signed_dist_shallow (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  vec2 v = normalize (a.p1 - a.p0);\n"
+"  float line_d = dot (p - a.p0, glyphy_ortho (v));\n"
+"  if (a.d == 0.)\n"
+"    return line_d;\n"
+"\n"
+"  float d0 = dot ((p - a.p0), v);\n"
+"  if (d0 < 0.)\n"
+"    return sign (line_d) * distance (p, a.p0);\n"
+"  float d1 = dot ((a.p1 - p), v);\n"
+"  if (d1 < 0.)\n"
+"    return sign (line_d) * distance (p, a.p1);\n"
+"  float r = 2. * a.d * (d0 * d1) / (d0 + d1);\n"
+"  if (r * line_d > 0.)\n"
+"    return sign (line_d) * min (abs (line_d + r), min (distance (p, a.p0), distance (p, a.p1)));\n"
+"  return line_d + r;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_wedge_signed_dist (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  if (abs (a.d) <= .03)\n"
+"    return glyphy_arc_wedge_signed_dist_shallow (a, p);\n"
+"  vec2 c = glyphy_arc_center (a);\n"
+"  return sign (a.d) * (distance (a.p0, c) - distance (p, c));\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_arc_extended_dist (const glyphy_arc_t a, const vec2 p)\n"
+"{\n"
+"  /* Note: this doesn't handle points inside the wedge. */\n"
+"  vec2 m = mix (a.p0, a.p1, .5);\n"
+"  float d2 = glyphy_tan2atan (a.d);\n"
+"  if (dot (p - m, a.p1 - m) < 0.)\n"
+"    return dot (p - a.p0, normalize ((a.p1 - a.p0) * mat2(+d2, -1, +1, +d2)));\n"
+"  else\n"
+"    return dot (p - a.p1, normalize ((a.p1 - a.p0) * mat2(-d2, -1, +1, -d2)));\n"
+"}\n"
+"\n"
+"int\n"
+"glyphy_arc_list_offset (const vec2 p, const ivec2 nominal_size)\n"
+"{\n"
+"  ivec2 cell = ivec2 (clamp (floor (p), vec2 (0.,0.), vec2(nominal_size - 1)));\n"
+"  return cell.y * nominal_size.x + cell.x;\n"
+"}\n"
+"\n"
+"glyphy_arc_list_t\n"
+"glyphy_arc_list_decode (const vec4 v, const ivec2 nominal_size)\n"
+"{\n"
+"  glyphy_arc_list_t l;\n"
+"  ivec4 iv = glyphy_vec4_to_bytes (v);\n"
+"  l.side = 0; /* unsure */\n"
+"  if (iv.r == 0) { /* arc-list encoded */\n"
+"    l.offset = (iv.g * 256) + iv.b;\n"
+"    l.num_endpoints = iv.a;\n"
+"    if (l.num_endpoints == 255) {\n"
+"      l.num_endpoints = 0;\n"
+"      l.side = -1;\n"
+"    } else if (l.num_endpoints == 0)\n"
+"      l.side = +1;\n"
+"  } else { /* single line encoded */\n"
+"    l.num_endpoints = -1;\n"
+/*"    l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 0x4000) / float (0x1FFF)\n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = float(-((iv.b * 256 + iv.a) - 0x8000)) / float (0x7FFF) * 3.14159265358979;\n"*/
+/*"    l.line_distance = float(((iv.r - 128) * 256 + iv.g) - 16384) / 8191.0 \n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = float(-((iv.b * 256 + iv.a) - 32768)) / 32767. * 3.14159;\n"*/
+
+"    l.line_distance = ( float(iv.r)/32. + 0.01*float(iv.g)/82.0 - 6.) \n"
+"                    * max (float (nominal_size.x), float (nominal_size.y));\n"
+"    l.line_angle = ( -float(iv.b)/40.74 - float( iv.a )*0.0001 )-3.142;\n"
+"  }\n"
+"  return l;\n"
+"}\n"
+;
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h
new file mode 100644 (file)
index 0000000..5de751f
--- /dev/null
@@ -0,0 +1,152 @@
+static const char *glyphy_sdf_glsl =
+"/*\n"
+" * Copyright 2012 Google, Inc. All Rights Reserved.\n"
+" *\n"
+" * Licensed under the Apache License, Version 2.0 (the \"License\");\n"
+" * you may not use this file except in compliance with the License.\n"
+" * You may obtain a copy of the License at\n"
+" *\n"
+" *     http://www.apache.org/licenses/LICENSE-2.0\n"
+" *\n"
+" * Unless required by applicable law or agreed to in writing, software\n"
+" * distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+" * See the License for the specific language governing permissions and\n"
+" * limitations under the License.\n"
+" *\n"
+" * Google Author(s): Behdad Esfahbod, Maysum Panju\n"
+" */\n"
+"\n"
+"#ifndef GLYPHY_TEXTURE1D_FUNC\n"
+"#define GLYPHY_TEXTURE1D_FUNC glyphy_texture1D_func\n"
+"#endif\n"
+"#ifndef GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#endif\n"
+"#ifndef GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_FUNC\n"
+"#define GLYPHY_SDF_TEXTURE1D_FUNC GLYPHY_TEXTURE1D_FUNC\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS\n"
+"#define GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS GLYPHY_TEXTURE1D_EXTRA_DECLS\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS\n"
+"#define GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS GLYPHY_TEXTURE1D_EXTRA_ARGS\n"
+"#endif\n"
+"#ifndef GLYPHY_SDF_TEXTURE1D\n"
+"#define GLYPHY_SDF_TEXTURE1D(offset) GLYPHY_RGBA(GLYPHY_SDF_TEXTURE1D_FUNC (offset GLYPHY_TEXTURE1D_EXTRA_ARGS))\n"
+"#endif\n"
+"\n"
+"#ifndef GLYPHY_MAX_NUM_ENDPOINTS\n"
+"#define GLYPHY_MAX_NUM_ENDPOINTS 32\n"
+"#endif\n"
+"\n"
+"glyphy_arc_list_t\n"
+"glyphy_arc_list (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  int cell_offset = glyphy_arc_list_offset (p, nominal_size);\n"
+"  vec4 arc_list_data = GLYPHY_SDF_TEXTURE1D (cell_offset);\n"
+"  return glyphy_arc_list_decode (arc_list_data, nominal_size);\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_sdf (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
+"\n"
+"  /* Short-circuits */\n"
+"  if (arc_list.num_endpoints == 0) {\n"
+"    /* far-away cell */\n"
+"    return GLYPHY_INFINITY * float(arc_list.side);\n"
+"  } if (arc_list.num_endpoints == -1) {\n"
+"    /* single-line */\n"
+"    float angle = arc_list.line_angle;\n"
+"    vec2 n = vec2 (cos (angle), sin (angle));\n"
+"    return dot (p - (vec2(nominal_size) * .5), n) - arc_list.line_distance;\n"
+"  }\n"
+"\n"
+"  float side = float(arc_list.side);\n"
+"  float min_dist = GLYPHY_INFINITY;\n"
+"  glyphy_arc_t closest_arc;\n"
+"\n"
+"  glyphy_arc_endpoint_t endpoint_prev, endpoint;\n"
+"  endpoint_prev = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset), nominal_size);\n"
+"  for (int i = 1; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
+"  {\n"
+"    if (i >= arc_list.num_endpoints) {\n"
+"      break;\n"
+"    }\n"
+"    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
+"    glyphy_arc_t a = glyphy_arc_t (endpoint_prev.p, endpoint.p, endpoint.d);\n"
+"    endpoint_prev = endpoint;\n"
+"    if (glyphy_isinf (a.d)) continue;\n"
+"\n"
+"    if (glyphy_arc_wedge_contains (a, p))\n"
+"    {\n"
+"      float sdist = glyphy_arc_wedge_signed_dist (a, p);\n"
+"      float udist = abs (sdist) * (1. - GLYPHY_EPSILON);\n"
+"      if (udist <= min_dist) {\n"
+"       min_dist = udist;\n"
+"       side = sign (sdist);"
+"      }\n"
+"    } else {\n"
+"      float udist = min (distance (p, a.p0), distance (p, a.p1));\n"
+"      if (udist < min_dist) {\n"
+"       min_dist = udist;\n"
+"       side = 0.; /* unsure */\n"
+"       closest_arc = a;\n"
+"      } else if (side == 0. && udist == min_dist) {\n"
+"       /* If this new distance is the same as the current minimum,\n"
+"        * compare extended distances.  Take the sign from the arc\n"
+"        * with larger extended distance. */\n"
+"       float old_ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
+"       float new_ext_dist = glyphy_arc_extended_dist (a, p);\n"
+"\n"
+"       float ext_dist = abs (new_ext_dist) <= abs (old_ext_dist) ?\n"
+"                        old_ext_dist : new_ext_dist;\n"
+"\n"
+"#ifdef GLYPHY_SDF_PSEUDO_DISTANCE\n"
+"       /* For emboldening and stuff: */\n"
+"       min_dist = abs (ext_dist);\n"
+"#endif\n"
+"       side = sign (ext_dist);\n"
+"      }\n"
+"    }\n"
+"  }\n"
+"\n"
+"  if (side == 0.) {\n"
+"    // Technically speaking this should not happen, but it does.  So try to fix it.\n"
+"    float ext_dist = glyphy_arc_extended_dist (closest_arc, p);\n"
+"    side = sign (ext_dist);\n"
+"  }\n"
+"\n"
+"  return min_dist * side;\n"
+"}\n"
+"\n"
+"float\n"
+"glyphy_point_dist (const vec2 p, const ivec2 nominal_size GLYPHY_SDF_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  glyphy_arc_list_t arc_list = glyphy_arc_list (p, nominal_size  GLYPHY_SDF_TEXTURE1D_EXTRA_ARGS);\n"
+"\n"
+"  float side = float(arc_list.side);\n"
+"  float min_dist = GLYPHY_INFINITY;\n"
+"\n"
+"  if (arc_list.num_endpoints == 0)\n"
+"    return min_dist;\n"
+"\n"
+"  glyphy_arc_endpoint_t endpoint;\n"
+"  for (int i = 0; i < GLYPHY_MAX_NUM_ENDPOINTS; i++)\n"
+"  {\n"
+"    if (i >= arc_list.num_endpoints) {\n"
+"      break;\n"
+"    }\n"
+"    endpoint = glyphy_arc_endpoint_decode (GLYPHY_SDF_TEXTURE1D (arc_list.offset + i), nominal_size);\n"
+"    if (glyphy_isinf (endpoint.d)) continue;\n"
+"    min_dist = min (min_dist, distance (p, endpoint.p));\n"
+"  }\n"
+"  return min_dist;\n"
+"}\n"
+;
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp
new file mode 100644 (file)
index 0000000..71d3f19
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h>
+
+// EXTERNAL HEADERS
+#include <sstream>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-common-glsl.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-sdf-glsl.h>
+
+using namespace Dali;
+
+namespace
+{
+
+const char* const ENABLE_EXTENSION_PREFIX =
+"#extension GL_OES_standard_derivatives : enable\n"
+"precision highp float;\n"
+"precision highp int;\n";
+
+const char* const VERTEX_SHADER_MAIN =
+"uniform   mediump mat4    uProjection;\n"
+"uniform   mediump mat4    uModelView;\n"
+"uniform   mediump mat4    uMvpMatrix;\n"
+"uniform           bool    uTextureMapped;\n"
+"uniform   mediump vec4    uCustomTextureCoords;\n"
+"attribute highp   vec2    aTexCoord;\n"
+"varying   mediump vec2    vTexCoord;\n"
+"uniform   mat3            uModelViewIT;\n"
+"attribute mediump vec3    aNormal;\n"
+"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"
+"glyph_vertex_transcode (vec2 v)\n"
+"{\n"
+"  ivec2 g = ivec2 (v);\n"
+"  ivec2 corner = ivec2 (mod (v, 2.));\n"
+"  g /= 2;\n"
+"  ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n"
+"  return vec4 (corner * nominal_size, g * 4);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+"  gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);\n"
+"  v_glyph = glyph_vertex_transcode (aTexCoord);\n"
+"  vColor = aColor;\n"
+"}\n"
+;
+
+const char* const FRAGMENT_SHADER_PREFIX =
+"struct Material\n"
+"{\n"
+"  mediump float mOpacity;\n"
+"  mediump float mShininess;\n"
+"  lowp    vec4  mAmbient;\n"
+"  lowp    vec4  mDiffuse;\n"
+"  lowp    vec4  mSpecular;\n"
+"  lowp    vec4  mEmissive;\n"
+"};\n"
+"uniform sampler2D     sTexture;\n"
+"uniform sampler2D     sOpacityTexture;\n"
+"uniform sampler2D     sNormalMapTexture;\n"
+"uniform sampler2D     sEffect;\n"
+"varying mediump vec2 vTexCoord;\n"
+"uniform Material      uMaterial;\n"
+"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"
+"#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n"
+"#define GLYPHY_DEMO_EXTRA_ARGS , sTexture, uu_atlas_info, gi.atlas_pos\n"
+"\n"
+"vec4\n"
+"glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+"  ivec2 item_geom = _atlas_info.zw;\n"
+"  vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n"
+"                    ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n"
+"             + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n"
+"  return texture2D (_tex, pos);\n"
+"}\n"
+;
+
+static const char* FRAGMENT_SHADER_MAIN =
+"uniform float u_contrast;\n"
+"uniform float u_gamma_adjust;\n"
+"uniform float u_outline_thickness;\n"
+"uniform float u_outline;\n"
+"uniform float u_boldness;\n"
+"\n"
+"varying vec4 v_glyph;\n"
+"\n"
+"\n"
+"#define SQRT2_2 0.70711 /* 1 / sqrt(2.) */\n"
+"#define SQRT2   1.41421\n"
+"\n"
+"struct glyph_info_t {\n"
+"  ivec2 nominal_size;\n"
+"  ivec2 atlas_pos;\n"
+"};\n"
+"\n"
+"glyph_info_t\n"
+"glyph_info_decode (vec4 v)\n"
+"{\n"
+"  glyph_info_t gi;\n"
+"  gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n"
+"  gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n"
+"  return gi;\n"
+"}\n"
+"\n"
+"\n"
+"float\n"
+"antialias (float d)\n"
+"{\n"
+"  return smoothstep (-.75, +.75, d);\n"
+"}\n"
+"\n"
+"vec4\n"
+"source_over (const vec4 src, const vec4 dst)\n"
+"{\n"
+"  // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n"
+"  float alpha = src.a + (dst.a * (1. - src.a));\n"
+"  return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+"  vec2 p = v_glyph.xy;\n"
+"  glyph_info_t gi = glyph_info_decode (v_glyph);\n"
+"\n"
+"  /* isotropic antialiasing */\n"
+"  vec2 dpdx = dFdx (p);\n"
+"  vec2 dpdy = dFdy (p);\n"
+"  float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n"
+"\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"
+"  float sdist = gsdist / m * u_contrast;\n"
+"\n"
+"    sdist -= u_boldness * 10.;\n"
+"    if ( glyphy_iszero( u_outline ) )\n"
+"      sdist = abs (sdist) - u_outline_thickness * .5;\n"
+"    if (sdist > 1.)\n"
+"      discard;\n"
+"    float alpha = antialias (-sdist);\n"
+"    if (u_gamma_adjust != 1.)\n"
+"      alpha = pow (alpha, 1./u_gamma_adjust);\n"
+"    color = vec4 (color.rgb,color.a * alpha);\n"
+"\n"
+"  gl_FragColor = color;\n"
+"}\n"
+;
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+GlyphyShader::GlyphyShader()
+{
+}
+
+GlyphyShader::GlyphyShader( Shader handle )
+: Shader( handle )
+{
+}
+
+GlyphyShader::~GlyphyShader()
+{
+}
+
+GlyphyShader GlyphyShader::New( const Dali::Vector4& atlasInfo )
+{
+  std::ostringstream vertexShaderStringStream;
+  std::ostringstream fragmentShaderStringStream;
+
+  vertexShaderStringStream << ENABLE_EXTENSION_PREFIX << VERTEX_SHADER_MAIN;
+
+  fragmentShaderStringStream << ENABLE_EXTENSION_PREFIX
+                             << FRAGMENT_SHADER_PREFIX
+                             << glyphy_common_glsl
+                             << "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n"
+                             << glyphy_sdf_glsl
+                             << FRAGMENT_SHADER_MAIN;
+
+  Shader shaderEffectCustom = Shader::New( vertexShaderStringStream.str(),
+                                           fragmentShaderStringStream.str(),
+                                           Shader::Hint::OUTPUT_IS_TRANSPARENT );
+
+  GlyphyShader handle( shaderEffectCustom );
+
+  handle.RegisterProperty( "u_atlas_info",  atlasInfo );
+  handle.RegisterProperty( "u_contrast",          1.f );
+  handle.RegisterProperty( "u_gamma_adjust",      1.f );
+  handle.RegisterProperty( "u_outline_thickness", 1.f );
+  handle.RegisterProperty( "u_outline",           1.f );
+  handle.RegisterProperty( "u_boldness",          0.f );
+
+  return handle;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h b/dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h
new file mode 100644 (file)
index 0000000..a7d2061
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_TOOLKIT_TEXT_GLYPHY_SHADER_H
+#define DALI_TOOLKIT_TEXT_GLYPHY_SHADER_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.
+ *
+ */
+
+// INTERNEL INCLUDES
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/rendering/shader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A Shader based on GLyphy authored by Behdad Esfahbod & Maysum Panju.
+ *
+ * See https://github.com/behdad/glyphy for more details of GLyphy.
+ */
+class GlyphyShader : public Shader
+{
+public:
+
+  /**
+   * @brief Create the blob atlas.
+   *
+   * @param[in] atlasInfo The metrics of the texture atlas storing vector data.
+   */
+  static GlyphyShader New( const Vector4& atlasInfo );
+
+  /**
+   * @brief Create an uninitialized GlyphyShader handle.
+   */
+  GlyphyShader();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~GlyphyShader();
+
+private: // Not intended for application developer
+
+  GlyphyShader( Shader handle );
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_GLYPHY_SHADER_H
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp
new file mode 100644 (file)
index 0000000..7fccc8d
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Toolkit::Text;
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
+const float DEFAULT_POINT_SIZE = 13.f;
+
+struct Vertex2D
+{
+  float x;
+  float y;
+  float u;
+  float v;
+  Vector4 color;
+};
+
+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 short>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
+{
+  indices.PushBack( v0 );
+  indices.PushBack( v1 );
+  indices.PushBack( v2 );
+}
+
+bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
+                     unsigned int numberOfGlyphs,
+                     const Vector<Vector2>& positions,
+                     float xOffset,
+                     float yOffset,
+                     VectorBlobAtlas& atlas,
+                     Dali::TextAbstraction::FontClient& fontClient,
+                     Vector< Vertex2D >& vertices,
+                     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 )
+  {
+    if( glyphs[i].width  > 0 &&
+        glyphs[i].height > 0 )
+    {
+      bool foundBlob( true );
+
+      BlobCoordinate blobCoords[4];
+
+      if( ! atlas.FindGlyph( glyphs[i].fontId, glyphs[i].index, blobCoords )  )
+      {
+        // Add blob to atlas
+        VectorBlob* blob( NULL );
+        unsigned int blobLength( 0 );
+        unsigned int nominalWidth( 0 );
+        unsigned int nominalHeight( 0 );
+        fontClient.CreateVectorBlob( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight );
+
+        if( 0 != blobLength )
+        {
+          bool glyphAdded = atlas.AddGlyph( glyphs[i].fontId, glyphs[i].index, blob, blobLength, nominalWidth, nominalHeight, blobCoords );
+
+          foundBlob = glyphAdded;
+          atlasFull = !glyphAdded;
+        }
+        else
+        {
+          foundBlob = false;
+        }
+      }
+
+      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, 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, 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;
+      }
+    }
+  }
+
+  // If the atlas is still partially empty, all the glyphs were added
+  return !atlasFull;
+}
+
+} // unnamed namespace
+
+struct VectorBasedRenderer::Impl
+{
+  Impl()
+  {
+    mFontClient = TextAbstraction::FontClient::Get();
+
+    mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+    mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+    mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
+  }
+
+  Actor mActor;                            ///< The actor parent which renders the text
+
+  TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
+
+  Property::Map mQuadVertexFormat;         ///> Describes the vertex format for text
+
+  Shader mShaderEffect;
+
+  IntrusivePtr<VectorBlobAtlas> mAtlas;
+};
+
+Text::RendererPtr VectorBasedRenderer::New()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Text::VectorBasedRenderer::New()\n" );
+
+  return Text::RendererPtr( new VectorBasedRenderer() );
+}
+
+Actor VectorBasedRenderer::Render( Text::ViewInterface& view,
+                                   Actor textControl,
+                                   Property::Index animatablePropertyIndex,
+                                   float& alignmentOffset,
+                                   int /*depth*/ )
+{
+  UnparentAndReset( mImpl->mActor );
+
+  mImpl->mActor = Actor::New();
+  mImpl->mActor.SetParentOrigin( ParentOrigin::CENTER );
+  mImpl->mActor.SetSize( view.GetControlSize() );
+  mImpl->mActor.SetColor( Color::WHITE );
+#if defined(DEBUG_ENABLED)
+  mImpl->mActor.SetName( "Text renderable actor" );
+#endif
+
+  Length numberOfGlyphs = view.GetNumberOfGlyphs();
+
+  if( numberOfGlyphs > 0u )
+  {
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize( numberOfGlyphs );
+
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
+
+    numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
+                                     positions.Begin(),
+                                     alignmentOffset,
+                                     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 short > indices;
+
+    const Vector2& controlSize = view.GetControlSize();
+    float xOffset = -alignmentOffset + controlSize.width * -0.5f;
+    float yOffset = controlSize.height * -0.5f;
+
+    if( ! mImpl->mAtlas ||
+          mImpl->mAtlas->IsFull() )
+    {
+      VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
+      mImpl->mAtlas = atlasShare.GetCurrentAtlas();
+    }
+
+    // First try adding the glyphs to the previous shared atlas
+    bool allGlyphsAdded = CreateGeometry( glyphs,
+                                          numberOfGlyphs,
+                                          positions,
+                                          xOffset,
+                                          yOffset,
+                                          *mImpl->mAtlas,
+                                          mImpl->mFontClient,
+                                          vertices,
+                                          indices,
+                                          colorsBuffer,
+                                          colorIndicesBuffer,
+                                          defaultColor );
+
+    if( ! allGlyphsAdded )
+    {
+      // The current atlas is full, abandon it and use a new one
+      mImpl->mAtlas.Reset();
+      vertices.Clear();
+      indices.Clear();
+
+      VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
+      mImpl->mAtlas = atlasShare.GetNewAtlas();
+
+      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 );
+
+      quadVertices.SetData( &vertices[ 0 ], vertices.Size() );
+
+
+      Geometry quadGeometry = Geometry::New();
+      quadGeometry.AddVertexBuffer( quadVertices );
+      quadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+
+      TextureSet texture = mImpl->mAtlas->GetTextureSet();
+
+      const Vector4 atlasInfo = mImpl->mAtlas->GetInfo();
+      mImpl->mShaderEffect = GlyphyShader::New( atlasInfo );
+
+      Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mImpl->mShaderEffect );
+      renderer.SetTextures( texture );
+      mImpl->mActor.AddRenderer( renderer );
+    }
+  }
+
+  return mImpl->mActor;
+}
+
+VectorBasedRenderer::VectorBasedRenderer()
+{
+  mImpl = new Impl();
+}
+
+VectorBasedRenderer::~VectorBasedRenderer()
+{
+  delete mImpl;
+}
+
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h b/dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.h
new file mode 100644 (file)
index 0000000..4a7e75b
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_H
+#define DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/text-renderer.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A vector-based renderer
+ *
+ */
+class VectorBasedRenderer : public Renderer
+{
+public:
+
+  /**
+   * @brief Create the renderer.
+   */
+  static RendererPtr New();
+
+  /**
+   * @copydoc Renderer::Render()
+   */
+  virtual Actor Render( ViewInterface& view,
+                        Actor textControl,  // Functionality not supported but defined in interface
+                        Property::Index animatablePropertyIndex, // Functionality not supported but defined in interface
+                        float& alignmentOffset,
+                        int depth );
+
+protected:
+
+  /**
+   * @brief Constructor.
+   */
+  VectorBasedRenderer();
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~VectorBasedRenderer();
+
+private:
+
+  // Undefined
+  VectorBasedRenderer( const VectorBasedRenderer& handle );
+
+  // Undefined
+  VectorBasedRenderer& operator=( const VectorBasedRenderer& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VECTOR_BASED_RENDERER_H
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.cpp
new file mode 100644 (file)
index 0000000..98c94a8
--- /dev/null
@@ -0,0 +1,150 @@
+ /*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace
+{
+
+const int INITIAL_VECTOR_BLOB_ATLAS_WIDTH = 512;
+const int INITIAL_VECTOR_BLOB_ATLAS_HEIGHT = 512;
+
+const int NEW_VECTOR_BLOB_ATLAS_WIDTH = 1024;
+const int NEW_VECTOR_BLOB_ATLAS_HEIGHT = 1024;
+
+const int VECTOR_BLOB_ATLAS_ITEM_WIDTH = 64;
+const int VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM = 8;
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class VectorBlobAtlasShare::Impl : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  Impl()
+  {
+  }
+
+  VectorBlobAtlas* GetCurrentAtlas()
+  {
+    if( ! mCurrentAtlas )
+    {
+      mCurrentAtlas = new VectorBlobAtlas( INITIAL_VECTOR_BLOB_ATLAS_WIDTH, INITIAL_VECTOR_BLOB_ATLAS_HEIGHT, VECTOR_BLOB_ATLAS_ITEM_WIDTH, VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM );
+    }
+
+    return mCurrentAtlas.Get();
+  }
+
+  VectorBlobAtlas* GetNewAtlas()
+  {
+    // The current atlas should have been filled, before asking for a new one
+    DALI_ASSERT_DEBUG( mCurrentAtlas->IsFull() && "Current atlas is not full yet" );
+
+    mCurrentAtlas = new VectorBlobAtlas( NEW_VECTOR_BLOB_ATLAS_WIDTH, NEW_VECTOR_BLOB_ATLAS_HEIGHT, VECTOR_BLOB_ATLAS_ITEM_WIDTH, VECTOR_BLOB_ATLAS_HEIGHT_QUANTUM );
+
+    return mCurrentAtlas.Get();
+  }
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Impl()
+  {
+  }
+
+private:
+
+  IntrusivePtr<VectorBlobAtlas> mCurrentAtlas;
+};
+
+VectorBlobAtlasShare::VectorBlobAtlasShare()
+{
+}
+
+VectorBlobAtlasShare::~VectorBlobAtlasShare()
+{
+}
+
+VectorBlobAtlasShare VectorBlobAtlasShare::Get()
+{
+  VectorBlobAtlasShare manager;
+
+  // Check whether the VectorBlobAtlasShare is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton( typeid( VectorBlobAtlasShare ) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton to VectorBlobAtlasShare
+      manager = VectorBlobAtlasShare( dynamic_cast<VectorBlobAtlasShare::Impl*>( handle.GetObjectPtr() ) );
+    }
+
+    if( !manager )
+    {
+      // If not, create the VectorBlobAtlasShare and register it as a singleton
+      manager = VectorBlobAtlasShare( new VectorBlobAtlasShare::Impl() );
+      singletonService.Register( typeid( manager ), manager );
+    }
+  }
+
+  return manager;
+}
+
+VectorBlobAtlasShare::VectorBlobAtlasShare( VectorBlobAtlasShare::Impl* impl )
+: BaseHandle( impl )
+{
+}
+
+VectorBlobAtlas* VectorBlobAtlasShare::GetCurrentAtlas()
+{
+  VectorBlobAtlasShare::Impl& impl = static_cast<VectorBlobAtlasShare::Impl&>( GetBaseObject() );
+
+  return impl.GetCurrentAtlas();
+}
+
+VectorBlobAtlas* VectorBlobAtlasShare::GetNewAtlas()
+{
+  VectorBlobAtlasShare::Impl& impl = static_cast<VectorBlobAtlasShare::Impl&>( GetBaseObject() );
+
+  return impl.GetNewAtlas();
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas-share.h
new file mode 100644 (file)
index 0000000..c9a7590
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_H
+#define DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief A singleton for sharing atlases containing vector data
+ *
+ */
+class VectorBlobAtlasShare : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create a VectorBlobAtlasShare handle.
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  VectorBlobAtlasShare();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~VectorBlobAtlasShare();
+
+  /**
+   * @brief Create or retrieve VectorBlobAtlasShare singleton.
+   *
+   * @return A handle to the VectorBlobAtlasShare control.
+   */
+  static VectorBlobAtlasShare Get();
+
+  /**
+   * @brief Retrieve the current (empty or partially empty) atlas.
+   *
+   * @return The current atlas.
+   */
+  VectorBlobAtlas* GetCurrentAtlas();
+
+  /**
+   * @brief Retrieve a new empty atlas.
+   *
+   * @pre The current atlas should be full.
+   * @return A new atlas.
+   */
+  VectorBlobAtlas* GetNewAtlas();
+
+private:
+
+  class Impl;
+
+  explicit DALI_INTERNAL VectorBlobAtlasShare( VectorBlobAtlasShare::Impl* impl );
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VECTOR_BLOB_ATLAS_SHARE_H
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.cpp
new file mode 100644 (file)
index 0000000..d9c0a7c
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
+}
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+static void
+EncodeBlobCoordinate( unsigned int cornerX, unsigned int cornerY,
+                      unsigned int atlasX, unsigned int atlasY,
+                      unsigned int nominalWidth, unsigned int nominalHeight,
+                      BlobCoordinate* v )
+{
+  DALI_ASSERT_DEBUG(0 == (atlasX & ~0x7F));
+  DALI_ASSERT_DEBUG(0 == (atlasY & ~0x7F));
+  DALI_ASSERT_DEBUG(0 == (cornerX & ~1));
+  DALI_ASSERT_DEBUG(0 == (cornerY & ~1));
+  DALI_ASSERT_DEBUG(0 == (nominalWidth & ~0x3F));
+  DALI_ASSERT_DEBUG(0 == (nominalHeight & ~0x3F));
+
+  unsigned int x = (((atlasX << 6) | nominalWidth) << 1)  | cornerX;
+  unsigned int y = (((atlasY << 6) | nominalHeight) << 1) | cornerY;
+
+  unsigned int encoded = (x << 16) | y;
+
+  v->u = encoded >> 16;
+  v->v = encoded & 0xFFFF;
+}
+
+VectorBlobAtlas::VectorBlobAtlas( unsigned int textureWidth,
+                                  unsigned int textureHeight,
+                                  unsigned int itemWidth,
+                                  unsigned int itemHeightQuantum )
+: mTextureWidth( textureWidth ),
+  mTextureHeight( textureHeight ),
+  mItemWidth( itemWidth ),
+  mItemHeightQuantum( itemHeightQuantum ),
+  mCursorX( 0 ),
+  mCursorY( 0 ),
+  mIsFull( false )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p size %dx%d, item width %d, height quantum %d\n", this, textureWidth, textureHeight, itemWidth, itemHeightQuantum );
+
+  mAtlasTexture = BufferImage::New( textureWidth, textureHeight, Pixel::RGBA8888 );
+
+  mTextureSet = TextureSet::New();
+  TextureSetImage( mTextureSet, 0, mAtlasTexture );
+}
+
+bool VectorBlobAtlas::IsFull() const
+{
+  return mIsFull;
+}
+
+bool VectorBlobAtlas::FindGlyph( FontId fontId,
+                                 GlyphIndex glyphIndex,
+                                 BlobCoordinate* coords )
+{
+  const unsigned int size( mItemLookup.size() );
+
+  for( unsigned int i=0; i<size; ++i )
+  {
+    if( mItemLookup[i].fontId     == fontId &&
+        mItemLookup[i].glyphIndex == glyphIndex )
+    {
+      const Item& item = mItemCache[ mItemLookup[i].cacheIndex ];
+
+      coords[0] = item.coords[0];
+      coords[1] = item.coords[1];
+      coords[2] = item.coords[2];
+      coords[3] = item.coords[3];
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool VectorBlobAtlas::AddGlyph( unsigned int fontId,
+                                unsigned int glyphIndex,
+                                VectorBlob* blob,
+                                unsigned int length,
+                                unsigned int nominalWidth,
+                                unsigned int nominalHeight,
+                                BlobCoordinate* coords )
+{
+  if( mIsFull )
+  {
+    return false;
+  }
+
+  unsigned int w, h, x, y;
+
+  w = mItemWidth;
+  h = (length + w - 1) / w;
+
+  if( mCursorY + h > mTextureHeight )
+  {
+    // Go to next column
+    mCursorX += mItemWidth;
+    mCursorY = 0;
+  }
+
+  if( mCursorX + w <= mTextureWidth && mCursorY + h <= mTextureHeight )
+  {
+    x = mCursorX;
+    y = mCursorY;
+    mCursorY += (h + mItemHeightQuantum - 1) & ~(mItemHeightQuantum - 1);
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p is now FULL\n", this );
+
+    // The atlas is now considered to be full
+    mIsFull = true;
+    return false;
+  }
+
+  if (w * h == length)
+  {
+    TexSubImage( x, y, w, h, blob );
+  }
+  else
+  {
+    TexSubImage( x, y, w, h-1, blob );
+
+    // Upload the last row separately
+    TexSubImage( x, y + h - 1, length - (w * (h - 1)), 1 , blob + w * (h - 1));
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Blob atlas %p capacity %d filled %d %f\%\n",
+                 this,
+                 mTextureWidth*mTextureHeight,
+                 mCursorY*mItemWidth + mCursorX*mTextureHeight,
+                 100.0f * (float)(mCursorY*mItemWidth + mCursorX*mTextureHeight) / (float)(mTextureWidth*mTextureHeight) );
+
+  Key key;
+  key.fontId = fontId;
+  key.glyphIndex = glyphIndex;
+  key.cacheIndex = mItemCache.size();
+  mItemLookup.push_back( key );
+
+  x /= mItemWidth;
+  y /= mItemHeightQuantum;
+
+  Item item;
+  EncodeBlobCoordinate( 0, 0, x, y, nominalWidth, nominalHeight, &item.coords[0] ); // BOTTOM_LEFT
+  EncodeBlobCoordinate( 0, 1, x, y, nominalWidth, nominalHeight, &item.coords[1] ); // TOP_LEFT
+  EncodeBlobCoordinate( 1, 0, x, y, nominalWidth, nominalHeight, &item.coords[2] ); // BOTTOM_RIGHT
+  EncodeBlobCoordinate( 1, 1, x, y, nominalWidth, nominalHeight, &item.coords[3] ); // TOP_RIGHT
+  mItemCache.push_back( item );
+
+  coords[0] = item.coords[0];
+  coords[1] = item.coords[1];
+  coords[2] = item.coords[2];
+  coords[3] = item.coords[3];
+
+  return true;
+}
+
+void VectorBlobAtlas::TexSubImage( unsigned int offsetX,
+                                   unsigned int offsetY,
+                                   unsigned int width,
+                                   unsigned int height,
+                                   VectorBlob* blob )
+{
+  PixelBuffer* pixbuf = mAtlasTexture.GetBuffer();
+  size_t pos;
+  size_t dataIndex = 0;
+  for( size_t y= offsetY; y< height + offsetY; y++ )
+  {
+    pos = y * mTextureWidth * 4;
+    for( size_t x = offsetX; x < width + offsetX; x++ )
+    {
+      pixbuf[pos+x*4] =  0xFF & blob[dataIndex].r;
+      pixbuf[pos+x*4+1] = 0xFF & blob[dataIndex].g;
+      pixbuf[pos+x*4+2] = 0xFF & blob[dataIndex].b;
+      pixbuf[pos+x*4+3] = 0xFF & blob[dataIndex].a;
+      dataIndex++;
+    }
+  }
+
+  mAtlasTexture.Update();
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h b/dali-toolkit/internal/text/rendering/vector-based/vector-blob-atlas.h
new file mode 100644 (file)
index 0000000..14af3bb
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_H
+#define DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+typedef Dali::TextAbstraction::VectorBlob VectorBlob;
+
+struct BlobCoordinate
+{
+  float u;
+  float v;
+};
+
+/**
+ * @brief An atlas for vector blob data
+ *
+ */
+class VectorBlobAtlas : public RefObject
+{
+public:
+
+  /**
+   * @brief Create a blob atlas.
+   *
+   * @param[in] textureWidth The atlas width.
+   * @param[in] textureHeight The atlas height.
+   * @param[in] itemWidth The width of an item in the atlas.
+   * @param[in] itemHeightQuantum The item height quantum.
+   * When blobs are added to columns in the atlas, the Y position is advanced by a multiple of this value.
+   */
+  VectorBlobAtlas( unsigned int textureWidth,
+                   unsigned int textureHeight,
+                   unsigned int itemWidth,
+                   unsigned int itemHeightQuantum );
+
+  /**
+   * @brief Query whether the atlas is full.
+   *
+   * @return True if the atlas is full.
+   */
+  bool IsFull() const;
+
+  /**
+   * @brief Find the UV coordinates for a glyph in the atlas.
+   *
+   * @param[in] fontId The ID of the font containing the glyph.
+   * @param[in] glyphIndex The index of the glyph within the font.
+   * @param[out] coords If the glyph was found, an array of 4 UV coordinates will be returned.
+   * Otherwise coords will not be written into.
+   * @return True if the glyph was found.
+   */
+  bool FindGlyph( FontId fontId,
+                  GlyphIndex glyphIndex,
+                  BlobCoordinate* coords );
+
+  /**
+   * @brief Add a glyph to the atlas.
+   *
+   * @param[in] fontId The ID of the font containing the glyph.
+   * @param[in] glyphIndex The index of the glyph within the font.
+   * @param[in] blobData A blob of vector data representing the glyph.
+   * @param[in] length The length of the blob data.
+   * @param[in] nominalWidth The width of the blob.
+   * @param[in] nominalHeight The height of the blob.
+   * @param[out] coords An array of 4 UV coordinates will be returned.
+   * @return True if the glyph was added. Otherwise the atlas is now full.
+   */
+  bool AddGlyph( unsigned int fontId,
+                 unsigned int glyphIndex,
+                 VectorBlob* blob,
+                 unsigned int length,
+                 unsigned int nominalWidth,
+                 unsigned int nominalHeight,
+                 BlobCoordinate* coords );
+
+  /**
+   * @brief Get the info required by the GLyphy shader.
+   *
+   * @return The shader uniform value.
+   */
+  Vector4 GetInfo() const
+  {
+    return Vector4( mTextureWidth, mTextureHeight, mItemWidth, mItemHeightQuantum );
+  }
+
+  /**
+   * @brief Retrieve the atlas texture.
+   *
+   * @return The texture used for rendering.
+   */
+  TextureSet GetTextureSet()
+  {
+    return mTextureSet;
+  }
+
+private:
+
+  /**
+   * @brief Helper for uploading data to the texture atlas.
+   *
+   * @param[in] offsetX The x position within the atlas.
+   * @param[in] offsetY The y position within the atlas.
+   * @param[in] width The width of the data to upload.
+   * @param[in] height The height of the data to upload.
+   * @param[in] blob The blob of data to upload.
+   */
+  void TexSubImage( unsigned int offsetX,
+                    unsigned int offsetY,
+                    unsigned int width,
+                    unsigned int height,
+                    VectorBlob* blob );
+
+private:
+
+  unsigned int mTextureWidth;
+  unsigned int mTextureHeight;
+
+  unsigned int mItemWidth;
+  unsigned int mItemHeightQuantum;
+
+  unsigned int mCursorX;
+  unsigned int mCursorY;
+
+  BufferImage mAtlasTexture;
+
+  TextureSet mTextureSet;
+
+  struct Key
+  {
+    unsigned int fontId;
+    unsigned int glyphIndex;
+    unsigned int cacheIndex;
+  };
+
+  struct Item
+  {
+    BlobCoordinate coords[4];
+  };
+
+  std::vector< Key >  mItemLookup;
+  std::vector< Item > mItemCache;
+
+  bool mIsFull;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VECTOR_BLOB_ATLAS_H
diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp
new file mode 100755 (executable)
index 0000000..3046f45
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/rendering/view-model.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/line-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+ViewModel::ViewModel( const ModelInterface* const model )
+: mModel( model ),
+  mElidedGlyphs(),
+  mElidedLayout(),
+  mIsTextElided( false )
+{
+}
+
+ViewModel::~ViewModel()
+{
+}
+
+const Size& ViewModel::GetControlSize() const
+{
+  return mModel->GetControlSize();
+}
+
+const Size& ViewModel::GetLayoutSize() const
+{
+  return mModel->GetLayoutSize();
+}
+
+const Vector2& ViewModel::GetScrollPosition() const
+{
+  return mModel->GetScrollPosition();
+}
+
+HorizontalAlignment::Type ViewModel::GetHorizontalAlignment() const
+{
+  return mModel->GetHorizontalAlignment();
+}
+
+VerticalAlignment::Type ViewModel::GetVerticalAlignment() const
+{
+  return mModel->GetVerticalAlignment();
+}
+
+DevelText::VerticalLineAlignment::Type ViewModel::GetVerticalLineAlignment() const
+{
+  return mModel->GetVerticalLineAlignment();
+}
+
+bool ViewModel::IsTextElideEnabled() const
+{
+  return mModel->IsTextElideEnabled();
+}
+
+Length ViewModel::GetNumberOfLines() const
+{
+  return mModel->GetNumberOfLines();
+}
+
+const LineRun* const ViewModel::GetLines() const
+{
+  return mModel->GetLines();
+}
+
+Length ViewModel::GetNumberOfScripts() const
+{
+  return mModel->GetNumberOfScripts();
+}
+
+const ScriptRun* const ViewModel::GetScriptRuns() const
+{
+  return mModel->GetScriptRuns();
+}
+
+Length ViewModel::GetNumberOfGlyphs() const
+{
+  if( mIsTextElided && mModel->IsTextElideEnabled() )
+  {
+     return mElidedGlyphs.Count();
+  }
+  else
+  {
+    return mModel->GetNumberOfGlyphs();
+  }
+
+  return 0u;
+}
+
+const GlyphInfo* const ViewModel::GetGlyphs() const
+{
+  if( mIsTextElided && mModel->IsTextElideEnabled() )
+  {
+    return mElidedGlyphs.Begin();
+  }
+  else
+  {
+    return mModel->GetGlyphs();
+  }
+
+  return NULL;
+}
+
+const Vector2* const ViewModel::GetLayout() const
+{
+  if( mIsTextElided && mModel->IsTextElideEnabled() )
+  {
+    return mElidedLayout.Begin();
+  }
+  else
+  {
+    return mModel->GetLayout();
+  }
+
+  return NULL;
+}
+
+const Vector4* const ViewModel::GetColors() const
+{
+  return mModel->GetColors();
+}
+
+const ColorIndex* const ViewModel::GetColorIndices() const
+{
+  return mModel->GetColorIndices();
+}
+
+const Vector4* const ViewModel::GetBackgroundColors() const
+{
+  return mModel->GetBackgroundColors();
+}
+
+const ColorIndex* const ViewModel::GetBackgroundColorIndices() const
+{
+  return mModel->GetBackgroundColorIndices();
+}
+
+const Vector4& ViewModel::GetDefaultColor() const
+{
+  return mModel->GetDefaultColor();
+}
+
+const Vector2& ViewModel::GetShadowOffset() const
+{
+  return mModel->GetShadowOffset();
+}
+
+const Vector4& ViewModel::GetShadowColor() const
+{
+  return mModel->GetShadowColor();
+}
+
+const float& ViewModel::GetShadowBlurRadius() const
+{
+  return mModel->GetShadowBlurRadius();
+}
+
+const Vector4& ViewModel::GetUnderlineColor() const
+{
+  return mModel->GetUnderlineColor();
+}
+
+bool ViewModel::IsUnderlineEnabled() const
+{
+  return mModel->IsUnderlineEnabled();
+}
+
+float ViewModel::GetUnderlineHeight() const
+{
+  return mModel->GetUnderlineHeight();
+}
+
+Length ViewModel::GetNumberOfUnderlineRuns() const
+{
+  return mModel->GetNumberOfUnderlineRuns();
+}
+
+void ViewModel::GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const
+{
+  mModel->GetUnderlineRuns( underlineRuns, index, numberOfRuns );
+}
+
+const Vector4& ViewModel::GetOutlineColor() const
+{
+  return mModel->GetOutlineColor();
+}
+
+uint16_t ViewModel::GetOutlineWidth() const
+{
+  return mModel->GetOutlineWidth();
+}
+
+const Vector4& ViewModel::GetBackgroundColor() const
+{
+  return mModel->GetBackgroundColor();
+}
+
+bool ViewModel::IsBackgroundEnabled() const
+{
+  return mModel->IsBackgroundEnabled();
+}
+
+void ViewModel::ElideGlyphs()
+{
+  mIsTextElided = false;
+
+  if( mModel->IsTextElideEnabled() )
+  {
+    const Length numberOfLines = mModel->GetNumberOfLines();
+    if( 0u != numberOfLines )
+    {
+      const LineRun* const lines = mModel->GetLines();
+
+      const LineRun& lastLine = *( lines + ( numberOfLines - 1u ) );
+      const Length numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+
+      if( lastLine.ellipsis && ( 0u != numberOfLaidOutGlyphs ) )
+      {
+        mIsTextElided = true;
+        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+        const GlyphInfo* const glyphs = mModel->GetGlyphs();
+        const Vector2* const positions = mModel->GetLayout();
+
+        // Copy the glyphs to be elided.
+        mElidedGlyphs.Resize( numberOfLaidOutGlyphs );
+        mElidedLayout.Resize( numberOfLaidOutGlyphs );
+
+        GlyphInfo* elidedGlyphsBuffer = mElidedGlyphs.Begin();
+        Vector2* elidedPositionsBuffer = mElidedLayout.Begin();
+
+        memcpy( elidedGlyphsBuffer, glyphs, numberOfLaidOutGlyphs * sizeof( GlyphInfo ) );
+        memcpy( elidedPositionsBuffer, positions, numberOfLaidOutGlyphs * sizeof( Vector2 ) );
+
+        const Size& controlSize = mModel->GetControlSize();
+
+        if( ( 1u == numberOfLines ) &&
+            ( lastLine.ascender - lastLine.descender > controlSize.height ) )
+        {
+          // Get the first glyph which is going to be replaced and the ellipsis glyph.
+          GlyphInfo& glyphToRemove = *elidedGlyphsBuffer;
+          const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) );
+
+          // Change the 'x' and 'y' position of the ellipsis glyph.
+          Vector2& position = *elidedPositionsBuffer;
+
+          position.x = ellipsisGlyph.xBearing;
+          position.y = -lastLine.ascender + controlSize.height - ellipsisGlyph.yBearing;
+
+          // Replace the glyph by the ellipsis glyph and resize the buffers.
+          glyphToRemove = ellipsisGlyph;
+
+          mElidedGlyphs.Resize( 1u );
+          mElidedLayout.Resize( 1u );
+
+          return;
+        }
+
+        // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
+        float firstPenX = 0.f; // Used if rtl text is elided.
+        float penY = 0.f;
+        bool firstPenSet = false;
+
+        // Add the ellipsis glyph.
+        bool inserted = false;
+        float removedGlypsWidth = 0.f;
+        Length numberOfRemovedGlyphs = 0u;
+        GlyphIndex index = numberOfLaidOutGlyphs - 1u;
+
+        // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
+        while( !inserted )
+        {
+          const GlyphInfo& glyphToRemove = *( elidedGlyphsBuffer + index );
+
+          if( 0u != glyphToRemove.fontId )
+          {
+            // i.e. The font id of the glyph shaped from the '\n' character is zero.
+
+            // Need to reshape the glyph as the font may be different in size.
+            const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) );
+
+            if( !firstPenSet || EqualsZero( glyphToRemove.advance ) )
+            {
+              const Vector2& position = *( elidedPositionsBuffer + index );
+
+              // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+              penY = position.y + glyphToRemove.yBearing;
+
+              // Calculates the first penX which will be used if rtl text is elided.
+              firstPenX = position.x - glyphToRemove.xBearing;
+              if( firstPenX < -ellipsisGlyph.xBearing )
+              {
+                // Avoids to exceed the bounding box when rtl text is elided.
+                firstPenX = -ellipsisGlyph.xBearing;
+              }
+
+              removedGlypsWidth = -ellipsisGlyph.xBearing;
+
+              if( !EqualsZero( firstPenX ) )
+              {
+                firstPenSet = true;
+              }
+            }
+
+            removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+
+            // Calculate the width of the ellipsis glyph and check if it fits.
+            const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+
+            if( ellipsisGlyphWidth < removedGlypsWidth )
+            {
+              GlyphInfo& glyphInfo = *( elidedGlyphsBuffer + index );
+              Vector2& position = *( elidedPositionsBuffer + index );
+              position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
+
+              // Replace the glyph by the ellipsis glyph.
+              glyphInfo = ellipsisGlyph;
+
+              // Change the 'x' and 'y' position of the ellipsis glyph.
+              if( position.x > firstPenX )
+              {
+                position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+              }
+
+              position.x += ellipsisGlyph.xBearing;
+              position.y = penY - ellipsisGlyph.yBearing;
+
+              inserted = true;
+            }
+          }
+
+          if( !inserted )
+          {
+            if( index > 0u )
+            {
+              --index;
+            }
+            else
+            {
+              // No space for the ellipsis.
+              inserted = true;
+            }
+            ++numberOfRemovedGlyphs;
+          }
+        } // while( !inserted )
+
+          // 'Removes' all the glyphs after the ellipsis glyph.
+        const Length numberOfGlyphs = numberOfLaidOutGlyphs - numberOfRemovedGlyphs;
+        mElidedGlyphs.Resize( numberOfGlyphs );
+        mElidedLayout.Resize( numberOfGlyphs );
+      }
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/rendering/view-model.h b/dali-toolkit/internal/text/rendering/view-model.h
new file mode 100755 (executable)
index 0000000..fe77f67
--- /dev/null
@@ -0,0 +1,239 @@
+#ifndef DALI_TOOLKIT_TEXT_VIEW_MODEL_H
+#define DALI_TOOLKIT_TEXT_VIEW_MODEL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/internal/text/text-model-interface.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Responsible of creating and store temporary modifications of the text model.
+ * i.e. The elide of text.
+ */
+class ViewModel : public ModelInterface
+{
+public:
+  /**
+   * @brief Constructor.
+   *
+   * Keeps the pointer to the text's model. It initializes all the members of the class to their defaults.
+   *
+   * @param[in] model Pointer to the text's model interface.
+   */
+  ViewModel( const ModelInterface* const model );
+
+  /**
+   * @brief Virtual destructor.
+   *
+   * It's a default destructor.
+   */
+  virtual ~ViewModel();
+
+  /**
+   * @copydoc ModelInterface::GetControlSize()
+   */
+  virtual const Size& GetControlSize() const;
+
+  /**
+   * @copydoc ModelInterface::GetLayoutSize()
+   */
+  virtual const Size& GetLayoutSize() const;
+
+  /**
+   * @copydoc ModelInterface::GetScrollPosition()
+   */
+  virtual const Vector2& GetScrollPosition() const;
+
+  /**
+   * @copydoc ModelInterface::GetHorizontalAlignment()
+   */
+  virtual Text::HorizontalAlignment::Type GetHorizontalAlignment() const;
+
+  /**
+   * @copydoc ModelInterface::GetVerticalAlignment()
+   */
+  virtual Text::VerticalAlignment::Type GetVerticalAlignment() const;
+
+  /**
+ * @copydoc ModelInterface::GetVerticalLineAlignment()
+ */
+  virtual DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const;
+
+  /**
+   * @copydoc ModelInterface::IsTextElideEnabled()
+   */
+  virtual bool IsTextElideEnabled() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfLines()
+   */
+  virtual Length GetNumberOfLines() const;
+
+  /**
+   * @copydoc ModelInterface::GetLines()
+   */
+  virtual const LineRun* const GetLines() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfScripts()
+   */
+  virtual Length GetNumberOfScripts() const;
+
+  /**
+   * @copydoc ModelInterface::GetScriptRuns()
+   */
+  virtual const ScriptRun* const GetScriptRuns() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfGlyphs()
+   */
+  virtual Length GetNumberOfGlyphs() const;
+
+  /**
+   * @copydoc ModelInterface::GetGlyphs()
+   */
+  virtual const GlyphInfo* const GetGlyphs() const;
+
+  /**
+   * @copydoc ModelInterface::GetLayout()
+   */
+  virtual const Vector2* const GetLayout() const;
+
+  /**
+   * @copydoc ModelInterface::GetColors()
+   */
+  virtual const Vector4* const GetColors() const;
+
+  /**
+   * @copydoc ModelInterface::GetColorIndices()
+   */
+  virtual const ColorIndex* const GetColorIndices() const;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const;
+
+  /**
+   * @copydoc ModelInterface::GetDefaultColor()
+   */
+  virtual const Vector4& GetDefaultColor() const;
+
+  /**
+   * @copydoc ModelInterface::GetShadowOffset()
+   */
+  virtual const Vector2& GetShadowOffset() const;
+
+  /**
+   * @copydoc ModelInterface::GetShadowColor()
+   */
+  virtual const Vector4& GetShadowColor() const;
+
+  /**
+   * @copydoc ModelInterface::GetShadowBlurRadius()
+   */
+  virtual const float& GetShadowBlurRadius() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @copydoc ModelInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineHeight()
+   */
+  virtual float GetUnderlineHeight() const;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfUnderlineRuns()
+   */
+  virtual Length GetNumberOfUnderlineRuns() const;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineRuns()
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const;
+
+  /**
+   * @copydoc ModelInterface::GetOutlineColor()
+   */
+  virtual const Vector4& GetOutlineColor() const;
+
+  /**
+   * @copydoc ModelInterface::GetOutlineWidth()
+   */
+  virtual uint16_t GetOutlineWidth() const;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColor()
+   */
+  virtual const Vector4& GetBackgroundColor() const;
+
+  /**
+   * @copydoc ModelInterface::IsBackgroundEnabled()
+   */
+  virtual bool IsBackgroundEnabled() const;
+
+/**
+   * @brief Does the text elide.
+   *
+   * It stores a copy of the visible glyphs and removes as many glyphs as needed
+   * from the last visible line to add the ellipsis glyph.
+   *
+   * It stores as well a copy of the positions for each visible glyph.
+   */
+  void ElideGlyphs();
+
+private:
+  const ModelInterface* const mModel;            ///< Pointer to the text's model.
+  Vector<GlyphInfo>           mElidedGlyphs;     ///< Stores the glyphs of the elided text.
+  Vector<Vector2>             mElidedLayout;     ///< Stores the positions of each glyph of the elided text.
+  bool                        mIsTextElided : 1; ///< Whether the text has been elided.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VIEW_MODEL_H
diff --git a/dali-toolkit/internal/text/script-run.h b/dali-toolkit/internal/text/script-run.h
new file mode 100755 (executable)
index 0000000..ce0698f
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef DALI_TOOLKIT_TEXT_SCRIPT_RUN_H
+#define DALI_TOOLKIT_TEXT_SCRIPT_RUN_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Run of characters with the same script.
+ */
+struct ScriptRun
+{
+  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+  Script       script;       ///< Script of the run.
+  bool         isRightToLeft; ///< Whether is right to left direction
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SCRIPT_RUN_H
diff --git a/dali-toolkit/internal/text/segmentation.cpp b/dali-toolkit/internal/text/segmentation.cpp
new file mode 100644 (file)
index 0000000..61afef1
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/segmentation.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/segmentation.h>
+#ifdef DEBUG_ENABLED
+#include <string>
+#include <dali/integration-api/debug.h>
+#endif
+
+// INTERNAL INCLUDES
+#ifdef DEBUG_ENABLED
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#endif
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_SEGMENTATION");
+#endif
+
+} // namespace
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void SetLineBreakInfo( const Vector<Character>& text,
+                       CharacterIndex startIndex,
+                       Length numberOfCharacters,
+                       Vector<LineBreakInfo>& lineBreakInfo )
+{
+  const Length totalNumberOfCharacters = text.Count();
+
+  if( 0u == totalNumberOfCharacters )
+  {
+    // Nothing to do if there are no characters.
+    return;
+  }
+
+  // Retrieve the line break info.
+  lineBreakInfo.Resize( totalNumberOfCharacters );
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  LineBreakInfo* lineBreakInfoBuffer = NULL;
+  Vector<LineBreakInfo> newLineBreakInfo;
+
+  if( updateCurrentBuffer )
+  {
+    newLineBreakInfo.Resize( numberOfCharacters );
+    lineBreakInfoBuffer = newLineBreakInfo.Begin();
+  }
+  else
+  {
+    lineBreakInfoBuffer = lineBreakInfo.Begin();
+  }
+
+  // Retrieve the line break info.
+  TextAbstraction::Segmentation::Get().GetLineBreakPositions( text.Begin() + startIndex,
+                                                              numberOfCharacters,
+                                                              lineBreakInfoBuffer );
+
+  // If the line break info is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    lineBreakInfo.Insert( lineBreakInfo.Begin() + startIndex,
+                          newLineBreakInfo.Begin(),
+                          newLineBreakInfo.End() );
+    lineBreakInfo.Resize( totalNumberOfCharacters );
+  }
+
+#ifdef DEBUG_ENABLED
+  if( gLogFilter->IsEnabledFor(Debug::Verbose) )
+  {
+    std::string utf8;
+    Utf32ToUtf8( text.Begin(), numberOfCharacters, utf8 );
+
+    std::string info;
+    info.reserve( numberOfCharacters );
+    for( unsigned int i=0; i<lineBreakInfo.Count(); ++i )
+    {
+      info.push_back( static_cast<char>('0' + lineBreakInfo[i]) );
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SetLineBreakInfo Characters: %s\n", utf8.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SetLineBreakInfo Break info: %s\n", info.c_str() );
+  }
+#endif
+}
+
+void SetWordBreakInfo( const Vector<Character>& text,
+                       CharacterIndex startIndex,
+                       Length numberOfCharacters,
+                       Vector<WordBreakInfo>& wordBreakInfo )
+{
+  const Length totalNumberOfCharacters = text.Count();
+
+  if( 0u == totalNumberOfCharacters )
+  {
+    // Nothing to do if there are no characters.
+    return;
+  }
+
+  // Resize the vector.
+  wordBreakInfo.Resize( totalNumberOfCharacters );
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  WordBreakInfo* wordBreakInfoBuffer = NULL;
+  Vector<WordBreakInfo> newWordBreakInfo;
+
+  if( updateCurrentBuffer )
+  {
+    newWordBreakInfo.Resize( numberOfCharacters );
+    wordBreakInfoBuffer = newWordBreakInfo.Begin();
+  }
+  else
+  {
+    wordBreakInfoBuffer = wordBreakInfo.Begin();
+  }
+
+  // Retrieve the word break info.
+  TextAbstraction::Segmentation::Get().GetWordBreakPositions( text.Begin() + startIndex,
+                                                              numberOfCharacters,
+                                                              wordBreakInfoBuffer );
+
+  // If the word break info is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    wordBreakInfo.Insert( wordBreakInfo.Begin() + startIndex,
+                          newWordBreakInfo.Begin(),
+                          newWordBreakInfo.End() );
+    wordBreakInfo.Resize( totalNumberOfCharacters );
+  }
+
+#ifdef DEBUG_ENABLED
+  if( gLogFilter->IsEnabledFor(Debug::Verbose) )
+  {
+    std::string utf8;
+    Utf32ToUtf8( text.Begin(), totalNumberOfCharacters, utf8 );
+
+    std::string info;
+    info.reserve( totalNumberOfCharacters );
+    for( unsigned int i=0; i<wordBreakInfo.Count(); ++i )
+    {
+      info.push_back( static_cast<char>('0' + wordBreakInfo[i]) );
+    }
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SetWordBreakInfo Characters: %s\n", utf8.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SetWordBreakInfo Break info: %s\n", info.c_str() );
+  }
+#endif
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/segmentation.h b/dali-toolkit/internal/text/segmentation.h
new file mode 100644 (file)
index 0000000..a60865a
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_TOOLKIT_TEXT_SEGMENTATION_H
+#define DALI_TOOLKIT_TEXT_SEGMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+
+/**
+ * Sets line break info.
+ *
+ * Possible values for LineBreakInfo are:
+ *
+ *  - 0 is a LINE_MUST_BREAK.  Text must be broken into a new line.
+ *  - 1 is a LINE_ALLOW_BREAK. Is possible to break the text into a new line.
+ *  - 2 is a LINE_NO_BREAK.    Text can't be broken into a new line.
+ *
+ * @param[in] text Vector of UTF-32 characters.
+ * @param[in] startIndex The character from where the break info is set.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[out] lineBreakInfo The line break info
+ */
+void SetLineBreakInfo( const Vector<Character>& text,
+                       CharacterIndex startIndex,
+                       Length numberOfCharacters,
+                       Vector<LineBreakInfo>& lineBreakInfo );
+
+/**
+ * Sets word break info.
+ *
+ * - 0 is a WORD_BREAK.    Text can be broken into a new word.
+ * - 1 is a WORD_NO_BREAK. Text can't be broken into a new word.
+ *
+ * @param[in] text Vector of UTF-32 characters.
+ * @param[in] startIndex The character from where the break info is set.
+ * @param[in] numberOfCharacters The number of characters.
+ * @param[out] wordBreakInfo The word break info.
+ */
+void SetWordBreakInfo( const Vector<Character>& text,
+                       CharacterIndex startIndex,
+                       Length numberOfCharacters,
+                       Vector<WordBreakInfo>& wordBreakInfo );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SEGMENTATION_H
diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp
new file mode 100644 (file)
index 0000000..593e1e5
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/shaper.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+CharacterIndex min( CharacterIndex index0,
+                    CharacterIndex index1 )
+{
+  return ( index0 < index1 ) ? index0 : index1;
+}
+
+void ShapeText( const Vector<Character>& text,
+                const Vector<LineBreakInfo>& lineBreakInfo,
+                const Vector<ScriptRun>& scripts,
+                const Vector<FontRun>& fonts,
+                CharacterIndex startCharacterIndex,
+                GlyphIndex startGlyphIndex,
+                Length numberOfCharacters,
+                Vector<GlyphInfo>& glyphs,
+                Vector<CharacterIndex>& glyphToCharacterMap,
+                Vector<Length>& charactersPerGlyph,
+                Vector<GlyphIndex>& newParagraphGlyphs )
+{
+  if( 0u == numberOfCharacters )
+  {
+    // Nothing to do if there are no characters.
+    return;
+  }
+
+#ifdef DEBUG_ENABLED
+  const Length numberOfFontRuns = fonts.Count();
+  const Length numberOfScriptRuns = scripts.Count();
+  const Length totalNumberOfCharacters = text.Count();
+#endif
+
+  DALI_ASSERT_DEBUG( ( 0u != numberOfFontRuns ) &&
+                     ( totalNumberOfCharacters == fonts[numberOfFontRuns - 1u].characterRun.characterIndex + fonts[numberOfFontRuns - 1u].characterRun.numberOfCharacters ) &&
+                     "Toolkit::Text::ShapeText. All characters must have a font set." );
+
+  DALI_ASSERT_DEBUG( ( 0u != numberOfScriptRuns ) &&
+                     ( totalNumberOfCharacters == scripts[numberOfScriptRuns - 1u].characterRun.characterIndex + scripts[numberOfScriptRuns - 1u].characterRun.numberOfCharacters ) &&
+                     "Toolkit::Text::ShapeText. All characters must have a script set." );
+
+  // The text needs to be split in chunks of consecutive characters.
+  // Each chunk must contain characters with the same font id and script set.
+  // A chunk of consecutive characters must not contain a LINE_MUST_BREAK, if there is one a new chunk has to be created.
+
+  TextAbstraction::Shaping shaping = TextAbstraction::Shaping::Get();
+
+  // To shape the text a font and an script is needed.
+
+  // Get the font run containing the startCharacterIndex character.
+  Vector<FontRun>::ConstIterator fontRunIt = fonts.Begin();
+  for( Vector<FontRun>::ConstIterator endIt = fonts.End(); fontRunIt < endIt; ++fontRunIt )
+  {
+    const FontRun& run = *fontRunIt;
+    if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found.
+      break;
+    }
+  }
+
+  // Get the script run containing the startCharacterIndex character.
+  Vector<ScriptRun>::ConstIterator scriptRunIt = scripts.Begin();
+  for( Vector<ScriptRun>::ConstIterator endIt = scripts.End(); scriptRunIt < endIt; ++scriptRunIt )
+  {
+    const ScriptRun& run = *scriptRunIt;
+    if( startCharacterIndex < run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+    {
+      // Found.
+      break;
+    }
+  }
+
+  // Index to the the next one to be shaped. Is pointing the character after the last one it was shaped.
+  CharacterIndex previousIndex = 0u;
+
+  // The current font id and script used to shape the text.
+  FontId currentFontId = 0u;
+  Script currentScript = TextAbstraction::UNKNOWN;
+
+  // Reserve some space to allocate the glyphs and the glyph to character map.
+  // There is no way to know the number of glyphs before shaping the text.
+  // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters.
+
+  GlyphInfo glyphInfo;
+  glyphInfo.isItalicRequired = false;
+  glyphInfo.isBoldRequired = false;
+
+  const Length currentNumberOfGlyphs = glyphs.Count();
+  const Length numberOfGlyphsReserved = static_cast<Length>( numberOfCharacters * 1.3f );
+  glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved, glyphInfo );
+  glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved );
+
+  // The actual number of glyphs.
+  Length totalNumberOfGlyphs = currentNumberOfGlyphs;
+  // The number of new glyphs.
+  Length numberOfNewGlyphs = 0u;
+
+  const Character* const textBuffer = text.Begin();
+  const LineBreakInfo* const lineBreakInfoBuffer = lineBreakInfo.Begin();
+  CharacterIndex* glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+
+  Length glyphIndex = startGlyphIndex;
+
+  // Traverse the characters and shape the text.
+  const CharacterIndex lastCharacter = startCharacterIndex + numberOfCharacters;
+  for( previousIndex = startCharacterIndex; previousIndex < lastCharacter; )
+  {
+    // Get the font id and the script.
+    const FontRun& fontRun = *fontRunIt;
+    const ScriptRun& scriptRun = *scriptRunIt;
+
+    currentFontId = fontRun.fontId;
+    currentScript = scriptRun.script;
+    const bool isItalicRequired = fontRun.isItalicRequired;
+    const bool isBoldRequired = fontRun.isBoldRequired;
+
+    // Get the min index to the last character of both runs.
+    CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters,
+                                       scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters );
+
+    // Check if there is a line must break.
+    bool mustBreak = false;
+
+    // Check if the current index is a new paragraph character.
+    // A new paragraph character is going to be shaped in order to not to mess the conversion tables.
+    // However, the metrics need to be changed in order to not to draw a square.
+    bool isNewParagraph = false;
+
+    for( CharacterIndex index = previousIndex; index < currentIndex; ++index )
+    {
+      mustBreak = TextAbstraction::LINE_MUST_BREAK == *( lineBreakInfoBuffer + index );
+      if( mustBreak )
+      {
+        isNewParagraph = TextAbstraction::IsNewParagraph( *( textBuffer + index ) );
+        currentIndex = index + 1u;
+        break;
+      }
+    }
+
+    // Shape the text for the current chunk.
+    const Length numberOfGlyphs = shaping.Shape( textBuffer + previousIndex,
+                                                 ( currentIndex - previousIndex ), // The number of characters to shape.
+                                                 currentFontId,
+                                                 currentScript );
+
+    // Retrieve the glyphs and the glyph to character conversion map.
+    Vector<GlyphInfo> tmpGlyphs;
+    Vector<CharacterIndex> tmpGlyphToCharacterMap;
+
+    GlyphInfo glyphInfo;
+    glyphInfo.isItalicRequired = isItalicRequired;
+    glyphInfo.isBoldRequired = isBoldRequired;
+
+    tmpGlyphs.Resize( numberOfGlyphs, glyphInfo );
+    tmpGlyphToCharacterMap.Resize( numberOfGlyphs );
+    shaping.GetGlyphs( tmpGlyphs.Begin(),
+                       tmpGlyphToCharacterMap.Begin() );
+
+    // Update the new indices of the glyph to character map.
+    if( 0u != totalNumberOfGlyphs )
+    {
+      for( Vector<CharacterIndex>::Iterator it = tmpGlyphToCharacterMap.Begin(),
+             endIt = tmpGlyphToCharacterMap.End();
+           it != endIt;
+           ++it )
+      {
+        *it += previousIndex;
+      }
+    }
+
+    totalNumberOfGlyphs += numberOfGlyphs;
+    numberOfNewGlyphs += numberOfGlyphs;
+
+    glyphs.Insert( glyphs.Begin() + glyphIndex, tmpGlyphs.Begin(), tmpGlyphs.End() );
+    glyphToCharacterMap.Insert( glyphToCharacterMap.Begin() + glyphIndex, tmpGlyphToCharacterMap.Begin(), tmpGlyphToCharacterMap.End() );
+    glyphIndex += numberOfGlyphs;
+
+    // Set the buffer pointers again.
+    glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+
+    if( isNewParagraph )
+    {
+      // Add the index of the new paragraph glyph to a vector.
+      // Their metrics will be updated in a following step.
+      newParagraphGlyphs.PushBack( glyphIndex - 1u );
+    }
+
+    // Update the iterators to get the next font or script run.
+    if( currentIndex == fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters )
+    {
+      ++fontRunIt;
+    }
+    if( currentIndex == scriptRun.characterRun.characterIndex + scriptRun.characterRun.numberOfCharacters )
+    {
+      ++scriptRunIt;
+    }
+
+    // Update the previous index.
+    previousIndex = currentIndex;
+  }
+
+  // Update indices.
+  for( Length index = startGlyphIndex + numberOfNewGlyphs; index < totalNumberOfGlyphs; ++index )
+  {
+    CharacterIndex& characterIndex = *( glyphToCharacterMapBuffer + index );
+    characterIndex += numberOfCharacters;
+  }
+
+  // Add the number of characters per glyph.
+  charactersPerGlyph.Reserve( totalNumberOfGlyphs );
+  Length* charactersPerGlyphBuffer = charactersPerGlyph.Begin();
+
+  const GlyphIndex lastGlyph = startGlyphIndex + numberOfNewGlyphs;
+  previousIndex = startCharacterIndex;
+  for( Length index = startGlyphIndex + 1u; index < lastGlyph; ++index )
+  {
+    const CharacterIndex characterIndex = *( glyphToCharacterMapBuffer + index );
+
+    charactersPerGlyph.Insert( charactersPerGlyphBuffer + index - 1u, characterIndex - previousIndex );
+
+    previousIndex = characterIndex;
+  }
+  charactersPerGlyph.Insert( charactersPerGlyphBuffer + lastGlyph - 1u, numberOfCharacters + startCharacterIndex - previousIndex );
+
+  // Resize the vectors to set the right number of items.
+  glyphs.Resize( totalNumberOfGlyphs );
+  glyphToCharacterMap.Resize( totalNumberOfGlyphs );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/shaper.h b/dali-toolkit/internal/text/shaper.h
new file mode 100644 (file)
index 0000000..b38b0a0
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_TOOLKIT_TEXT_SHAPER_H
+#define DALI_TOOLKIT_TEXT_SHAPER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+class VisualModel;
+
+/**
+ * Shapes the whole text.
+ *
+ * @param[in] text Vector of UTF-32 characters.
+ * @param[in] lineBreakInfo The line break info.
+ * @param[in] scripts Vector containing the script runs for the whole text.
+ * @param[in] fonts Vector with validated fonts.
+ * @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] glyphs Vector of glyphs in the visual order.
+ * @param[out] glyphToCharacterMap Vector containing the first character in the logical model that each glyph relates to.
+ * @param[out] charactersPerGlyph Vector containing the number of characters per glyph.
+ * @param[out] newParagraphGlyphs Vector containing the indices to the new paragraph glyphs.
+ */
+void ShapeText( const Vector<Character>& text,
+                const Vector<LineBreakInfo>& lineBreakInfo,
+                const Vector<ScriptRun>& scripts,
+                const Vector<FontRun>& fonts,
+                CharacterIndex startCharacterIndex,
+                GlyphIndex startGlyphIndex,
+                Length numberOfCharacters,
+                Vector<GlyphInfo>& glyphs,
+                Vector<CharacterIndex>& glyphToCharacterMap,
+                Vector<Length>& charactersPerGlyph,
+                Vector<GlyphIndex>& newParagraphGlyphs );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SHAPER_H
diff --git a/dali-toolkit/internal/text/text-control-interface.h b/dali-toolkit/internal/text/text-control-interface.h
new file mode 100644 (file)
index 0000000..ce5af88
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_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 Text
+{
+
+/**
+ * @brief An interface that the Text::Controller uses to request a text relayout.
+ */
+class ControlInterface
+{
+public:
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~ControlInterface()
+  {}
+
+  /**
+   * @brief Called to request a text relayout.
+   */
+  virtual void RequestTextRelayout() = 0;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H
diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp
new file mode 100755 (executable)
index 0000000..8f4de65
--- /dev/null
@@ -0,0 +1,3395 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/text/text-controller-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/integration-api/debug.h>
+#include <limits>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/segmentation.h>
+#include <dali-toolkit/internal/text/shaper.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+
+using namespace Dali;
+
+namespace
+{
+
+/**
+ * @brief Struct used to calculate the selection box.
+ */
+struct SelectionBoxInfo
+{
+  float lineOffset;
+  float lineHeight;
+  float minX;
+  float maxX;
+};
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+const float MIN_FLOAT = std::numeric_limits<float>::min();
+const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
+
+#define MAKE_SHADER(A)#A
+
+const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
+attribute mediump vec2    aPosition;
+attribute mediump vec4    aColor;
+varying   mediump vec4    vColor;
+uniform   highp mat4      uMvpMatrix;
+
+void main()
+{
+  mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+  gl_Position = uMvpMatrix * position;
+  vColor = aColor;
+}
+);
+
+const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
+varying mediump vec4      vColor;
+uniform lowp    vec4      uColor;
+
+void main()
+{
+  gl_FragColor = vColor * uColor;
+}
+);
+
+struct BackgroundVertex
+{
+  Vector2 mPosition;        ///< Vertex posiiton
+  Vector4 mColor;           ///< Vertex color
+};
+
+struct BackgroundMesh
+{
+  Vector< BackgroundVertex > mVertices;    ///< container of vertices
+  Vector< unsigned short > mIndices;       ///< container of indices
+};
+
+const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
+: mDecorator( decorator ),
+  mInputMethodContext( inputMethodContext ),
+  mPlaceholderFont( NULL ),
+  mPlaceholderTextActive(),
+  mPlaceholderTextInactive(),
+  mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
+  mEventQueue(),
+  mInputStyleChangedQueue(),
+  mPreviousState( INACTIVE ),
+  mState( INACTIVE ),
+  mPrimaryCursorPosition( 0u ),
+  mLeftSelectionPosition( 0u ),
+  mRightSelectionPosition( 0u ),
+  mPreEditStartPosition( 0u ),
+  mPreEditLength( 0u ),
+  mCursorHookPositionX( 0.f ),
+  mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
+  mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
+  mIsShowingPlaceholderText( false ),
+  mPreEditFlag( false ),
+  mDecoratorUpdated( false ),
+  mCursorBlinkEnabled( true ),
+  mGrabHandleEnabled( true ),
+  mGrabHandlePopupEnabled( true ),
+  mSelectionEnabled( true ),
+  mUpdateCursorHookPosition( false ),
+  mUpdateCursorPosition( false ),
+  mUpdateGrabHandlePosition( false ),
+  mUpdateLeftSelectionPosition( false ),
+  mUpdateRightSelectionPosition( false ),
+  mIsLeftHandleSelected( false ),
+  mIsRightHandleSelected( false ),
+  mUpdateHighlightBox( false ),
+  mScrollAfterUpdatePosition( false ),
+  mScrollAfterDelete( false ),
+  mAllTextSelected( false ),
+  mUpdateInputStyle( false ),
+  mPasswordInput( false ),
+  mCheckScrollAmount( false ),
+  mIsPlaceholderPixelSize( false ),
+  mIsPlaceholderElideEnabled( false ),
+  mPlaceholderEllipsisFlag( false ),
+  mShiftSelectionFlag( true ),
+  mUpdateAlignment( false )
+{
+}
+
+EventData::~EventData()
+{}
+
+bool Controller::Impl::ProcessInputEvents()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
+    return false;
+  }
+
+  if( mEventData->mDecorator )
+  {
+    for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
+         iter != mEventData->mEventQueue.end();
+         ++iter )
+    {
+      switch( iter->type )
+      {
+        case Event::CURSOR_KEY_EVENT:
+        {
+          OnCursorKeyEvent( *iter );
+          break;
+        }
+        case Event::TAP_EVENT:
+        {
+          OnTapEvent( *iter );
+          break;
+        }
+        case Event::LONG_PRESS_EVENT:
+        {
+          OnLongPressEvent( *iter );
+          break;
+        }
+        case Event::PAN_EVENT:
+        {
+          OnPanEvent( *iter );
+          break;
+        }
+        case Event::GRAB_HANDLE_EVENT:
+        case Event::LEFT_SELECTION_HANDLE_EVENT:
+        case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
+        {
+          OnHandleEvent( *iter );
+          break;
+        }
+        case Event::SELECT:
+        {
+          OnSelectEvent( *iter );
+          break;
+        }
+        case Event::SELECT_ALL:
+        {
+          OnSelectAllEvent();
+          break;
+        }
+      }
+    }
+  }
+
+  if( mEventData->mUpdateCursorPosition ||
+      mEventData->mUpdateHighlightBox )
+  {
+    NotifyInputMethodContext();
+  }
+
+  // The cursor must also be repositioned after inserts into the model
+  if( mEventData->mUpdateCursorPosition )
+  {
+    // Updates the cursor position and scrolls the text to make it visible.
+    CursorInfo cursorInfo;
+    // Calculate the cursor position from the new cursor index.
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
+
+    if( mEventData->mUpdateCursorHookPosition )
+    {
+      // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
+      mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
+      mEventData->mUpdateCursorHookPosition = false;
+    }
+
+    // Scroll first the text after delete ...
+    if( mEventData->mScrollAfterDelete )
+    {
+      ScrollTextToMatchCursor( cursorInfo );
+    }
+
+    // ... then, text can be scrolled to make the cursor visible.
+    if( mEventData->mScrollAfterUpdatePosition )
+    {
+      const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
+      ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
+    }
+    mEventData->mScrollAfterUpdatePosition = false;
+    mEventData->mScrollAfterDelete = false;
+
+    UpdateCursorPosition( cursorInfo );
+
+    mEventData->mDecoratorUpdated = true;
+    mEventData->mUpdateCursorPosition = false;
+    mEventData->mUpdateGrabHandlePosition = false;
+  }
+  else
+  {
+    CursorInfo leftHandleInfo;
+    CursorInfo rightHandleInfo;
+
+    if( mEventData->mUpdateHighlightBox )
+    {
+      GetCursorPosition( mEventData->mLeftSelectionPosition,
+                         leftHandleInfo );
+
+      GetCursorPosition( mEventData->mRightSelectionPosition,
+                         rightHandleInfo );
+
+      if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
+      {
+        if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
+        {
+          CursorInfo& infoLeft = leftHandleInfo;
+
+          const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
+
+          CursorInfo& infoRight = rightHandleInfo;
+
+          const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
+        }
+        else
+        {
+          CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
+
+          const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
+        }
+      }
+    }
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
+                             leftHandleInfo );
+
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateLeftSelectionPosition = false;
+    }
+
+    if( mEventData->mUpdateRightSelectionPosition )
+    {
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
+                             rightHandleInfo );
+
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateRightSelectionPosition = false;
+    }
+
+    if( mEventData->mUpdateHighlightBox )
+    {
+      RepositionSelectionHandles();
+
+      mEventData->mUpdateLeftSelectionPosition = false;
+      mEventData->mUpdateRightSelectionPosition = false;
+      mEventData->mUpdateHighlightBox = false;
+      mEventData->mIsLeftHandleSelected = false;
+      mEventData->mIsRightHandleSelected = false;
+    }
+
+    mEventData->mScrollAfterUpdatePosition = false;
+  }
+
+  if( mEventData->mUpdateInputStyle )
+  {
+    // Keep a copy of the current input style.
+    InputStyle currentInputStyle;
+    currentInputStyle.Copy( mEventData->mInputStyle );
+
+    // Set the default style first.
+    RetrieveDefaultInputStyle( mEventData->mInputStyle );
+
+    // Get the character index from the cursor index.
+    const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
+
+    // Retrieve the style from the style runs stored in the logical model.
+    mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
+
+    // Compare if the input style has changed.
+    const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
+
+    if( hasInputStyleChanged )
+    {
+      const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
+      // Queue the input style changed signal.
+      mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
+    }
+
+    mEventData->mUpdateInputStyle = false;
+  }
+
+  mEventData->mEventQueue.clear();
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
+
+  const bool decoratorUpdated = mEventData->mDecoratorUpdated;
+  mEventData->mDecoratorUpdated = false;
+
+  return decoratorUpdated;
+}
+
+void Controller::Impl::NotifyInputMethodContext()
+{
+  if( mEventData && mEventData->mInputMethodContext )
+  {
+    CharacterIndex cursorPosition = GetLogicalCursorPosition();
+
+    const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
+
+    // Update the cursor position by removing the initial white spaces.
+    if( cursorPosition < numberOfWhiteSpaces )
+    {
+      cursorPosition = 0u;
+    }
+    else
+    {
+      cursorPosition -= numberOfWhiteSpaces;
+    }
+
+    mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
+    mEventData->mInputMethodContext.NotifyCursorPosition();
+  }
+}
+
+void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
+{
+  if ( mEventData && mEventData->mInputMethodContext )
+  {
+    Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
+    mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
+  }
+}
+
+CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
+{
+  CharacterIndex cursorPosition = 0u;
+
+  if( mEventData )
+  {
+    if( ( EventData::SELECTING == mEventData->mState ) ||
+        ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
+    {
+      cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
+    }
+    else
+    {
+      cursorPosition = mEventData->mPrimaryCursorPosition;
+    }
+  }
+
+  return cursorPosition;
+}
+
+Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
+{
+  Length numberOfWhiteSpaces = 0u;
+
+  // Get the buffer to the text.
+  Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
+
+  const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
+  for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
+  {
+    if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
+    {
+      break;
+    }
+  }
+
+  return numberOfWhiteSpaces;
+}
+
+void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
+{
+  // Get the total number of characters.
+  Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
+
+  // Retrieve the text.
+  if( 0u != numberOfCharacters )
+  {
+    Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
+  }
+}
+
+void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
+{
+  mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mTextUpdateInfo.mStartGlyphIndex = 0u;
+  mTextUpdateInfo.mStartLineIndex = 0u;
+  numberOfCharacters = 0u;
+
+  const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
+  if( 0u == numberOfParagraphs )
+  {
+    mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    numberOfCharacters = 0u;
+
+    mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+    // Nothing else to do if there are no paragraphs.
+    return;
+  }
+
+  // Find the paragraphs to be updated.
+  Vector<ParagraphRunIndex> paragraphsToBeUpdated;
+  if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
+  {
+    // Text is being added at the end of the current text.
+    if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
+    {
+      // Text is being added in a new paragraph after the last character of the text.
+      mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+      numberOfCharacters = 0u;
+      mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+      mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
+      mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
+
+      // Nothing else to do;
+      return;
+    }
+
+    paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
+  }
+  else
+  {
+    Length numberOfCharactersToUpdate = 0u;
+    if( mTextUpdateInfo.mFullRelayoutNeeded )
+    {
+      numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
+    }
+    else
+    {
+      numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
+    }
+    mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
+                                           numberOfCharactersToUpdate,
+                                           paragraphsToBeUpdated );
+  }
+
+  if( 0u != paragraphsToBeUpdated.Count() )
+  {
+    const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
+    const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
+    mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
+
+    ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
+    const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
+
+    if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
+        ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
+        ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
+          ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
+    {
+      // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
+      const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
+
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
+    else
+    {
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
+  }
+
+  mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+  mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
+}
+
+void Controller::Impl::ClearFullModelData( OperationsMask operations )
+{
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
+  {
+    mModel->mLogicalModel->mLineBreakInfo.Clear();
+    mModel->mLogicalModel->mParagraphInfo.Clear();
+  }
+
+  if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
+  {
+    mModel->mLogicalModel->mScriptRuns.Clear();
+  }
+
+  if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
+  {
+    mModel->mLogicalModel->mFontRuns.Clear();
+  }
+
+  if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( NO_OPERATION != ( BIDI_INFO & operations ) )
+    {
+      mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+      mModel->mLogicalModel->mCharacterDirections.Clear();
+    }
+
+    if( NO_OPERATION != ( REORDER & operations ) )
+    {
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
+             endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+      mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
+    }
+  }
+
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
+  {
+    mModel->mVisualModel->mGlyphs.Clear();
+    mModel->mVisualModel->mGlyphsToCharacters.Clear();
+    mModel->mVisualModel->mCharactersToGlyph.Clear();
+    mModel->mVisualModel->mCharactersPerGlyph.Clear();
+    mModel->mVisualModel->mGlyphsPerCharacter.Clear();
+    mModel->mVisualModel->mGlyphPositions.Clear();
+  }
+
+  if( NO_OPERATION != ( LAYOUT & operations ) )
+  {
+    mModel->mVisualModel->mLines.Clear();
+  }
+
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    mModel->mVisualModel->mColorIndices.Clear();
+    mModel->mVisualModel->mBackgroundColorIndices.Clear();
+  }
+}
+
+void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
+  {
+    // Clear the line break info.
+    LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
+
+    mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
+                                                 lineBreakInfoBuffer + endIndexPlusOne );
+
+    // Clear the paragraphs.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mModel->mLogicalModel->mParagraphInfo );
+  }
+
+  if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
+  {
+    // Clear the scripts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mModel->mLogicalModel->mScriptRuns );
+  }
+
+  if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
+  {
+    // Clear the fonts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mModel->mLogicalModel->mFontRuns );
+  }
+
+  if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( NO_OPERATION != ( BIDI_INFO & operations ) )
+    {
+      // Clear the bidirectional paragraph info.
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mModel->mLogicalModel->mBidirectionalParagraphInfo );
+
+      // Clear the character's directions.
+      CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
+
+      mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
+                                                         characterDirectionsBuffer + endIndexPlusOne );
+    }
+
+    if( NO_OPERATION != ( REORDER & operations ) )
+    {
+      uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
+      uint32_t endRemoveIndex = startRemoveIndex;
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mModel->mLogicalModel->mBidirectionalLineInfo,
+                          startRemoveIndex,
+                          endRemoveIndex );
+
+      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
+
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
+             endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+
+      mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                           bidirectionalLineInfoBuffer + endRemoveIndex );
+    }
+  }
+}
+
+void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+  const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+
+  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+  GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
+  Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
+
+  const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
+  const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
+  {
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
+           endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfGlyphsRemoved;
+    }
+
+    // Clear the character to glyph conversion table.
+    mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
+                                                    charactersToGlyphBuffer + endIndexPlusOne );
+
+    // Clear the glyphs per character table.
+    mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
+                                                     glyphsPerCharacterBuffer + endIndexPlusOne );
+
+    // Clear the glyphs buffer.
+    GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
+    mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                         glyphsBuffer + endGlyphIndexPlusOne );
+
+    CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
+
+    // Update the glyph to character indices.
+    for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+           endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfCharactersRemoved;
+    }
+
+    // Clear the glyphs to characters buffer.
+    mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                     glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
+
+    // Clear the characters per glyph buffer.
+    Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
+    mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                     charactersPerGlyphBuffer + endGlyphIndexPlusOne );
+
+    // Clear the positions buffer.
+    Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
+    mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                 positionsBuffer + endGlyphIndexPlusOne );
+  }
+
+  if( NO_OPERATION != ( LAYOUT & operations ) )
+  {
+    // Clear the lines.
+    uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
+    uint32_t endRemoveIndex = startRemoveIndex;
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mModel->mVisualModel->mLines,
+                        startRemoveIndex,
+                        endRemoveIndex );
+
+    // Will update the glyph runs.
+    startRemoveIndex = mModel->mVisualModel->mLines.Count();
+    endRemoveIndex = startRemoveIndex;
+    ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                    endGlyphIndexPlusOne - 1u,
+                    mModel->mVisualModel->mLines,
+                    startRemoveIndex,
+                    endRemoveIndex );
+
+    // Set the line index from where to insert the new laid-out lines.
+    mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
+
+    LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
+    mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
+                                        linesBuffer + endRemoveIndex );
+  }
+
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    if( 0u != mModel->mVisualModel->mColorIndices.Count() )
+    {
+      ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
+      mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                 colorIndexBuffer + endGlyphIndexPlusOne );
+    }
+
+    if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
+    {
+      ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
+      mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                           backgroundColorIndexBuffer + endGlyphIndexPlusOne );
+    }
+  }
+}
+
+void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  if( mTextUpdateInfo.mClearAll ||
+      ( ( 0u == startIndex ) &&
+        ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
+  {
+    ClearFullModelData( operations );
+  }
+  else
+  {
+    // Clear the model data related with characters.
+    ClearCharacterModelData( startIndex, endIndex, operations );
+
+    // Clear the model data related with glyphs.
+    ClearGlyphModelData( startIndex, endIndex, operations );
+  }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
+
+  mModel->mVisualModel->ClearCaches();
+}
+
+bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
+
+  // Calculate the operations to be done.
+  const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
+
+  if( NO_OPERATION == operations )
+  {
+    // Nothing to do if no operations are pending and required.
+    return false;
+  }
+
+  Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
+  Vector<Character> displayCharacters;
+  bool useHiddenText = false;
+  if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
+  {
+    mHiddenInput->Substitute( srcCharacters,displayCharacters );
+    useHiddenText = true;
+  }
+
+  Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
+  const Length numberOfCharacters = utf32Characters.Count();
+
+  // Index to the first character of the first paragraph to be updated.
+  CharacterIndex startIndex = 0u;
+  // Number of characters of the paragraphs to be removed.
+  Length paragraphCharacters = 0u;
+
+  CalculateTextUpdateIndices( paragraphCharacters );
+
+  // Check whether the indices for updating the text is valid
+  if ( numberOfCharacters > 0u &&
+       ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
+         mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
+  {
+    std::string currentText;
+    Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
+
+    DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
+    DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
+
+    // Dump mTextUpdateInfo
+    DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
+    DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
+
+    return false;
+  }
+
+  startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
+
+  if( mTextUpdateInfo.mClearAll ||
+      ( 0u != paragraphCharacters ) )
+  {
+    ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
+  }
+
+  mTextUpdateInfo.mClearAll = false;
+
+  // Whether the model is updated.
+  bool updated = false;
+
+  Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
+  const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
+
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
+  {
+    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
+    // calculate the bidirectional info for each 'paragraph'.
+    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
+    // is not shaped together).
+    lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
+
+    SetLineBreakInfo( utf32Characters,
+                      startIndex,
+                      requestedNumberOfCharacters,
+                      lineBreakInfo );
+
+    // Create the paragraph info.
+    mModel->mLogicalModel->CreateParagraphInfo( startIndex,
+                                                requestedNumberOfCharacters );
+    updated = true;
+  }
+
+  const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
+  const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
+
+  Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
+  Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
+
+  if( getScripts || validateFonts )
+  {
+    // Validates the fonts assigned by the application or assigns default ones.
+    // It makes sure all the characters are going to be rendered by the correct font.
+    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+    if( getScripts )
+    {
+      // Retrieves the scripts used in the text.
+      multilanguageSupport.SetScripts( utf32Characters,
+                                       startIndex,
+                                       requestedNumberOfCharacters,
+                                       scripts );
+    }
+
+    if( validateFonts )
+    {
+      // Validate the fonts set through the mark-up string.
+      Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
+
+      // Get the default font's description.
+      TextAbstraction::FontDescription defaultFontDescription;
+      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+
+      if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
+      {
+        // If the placeholder font is set specifically, only placeholder font is changed.
+        defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
+        if( mEventData->mPlaceholderFont->sizeDefined )
+        {
+          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
+        }
+      }
+      else if( NULL != mFontDefaults )
+      {
+        // Set the normal font and the placeholder font.
+        defaultFontDescription = mFontDefaults->mFontDescription;
+
+        if( mTextFitEnabled )
+        {
+          defaultPointSize = mFontDefaults->mFitPointSize * 64u;
+        }
+        else
+        {
+          defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
+        }
+      }
+
+      // Validates the fonts. If there is a character with no assigned font it sets a default one.
+      // After this call, fonts are validated.
+      multilanguageSupport.ValidateFonts( utf32Characters,
+                                          scripts,
+                                          fontDescriptionRuns,
+                                          defaultFontDescription,
+                                          defaultPointSize,
+                                          startIndex,
+                                          requestedNumberOfCharacters,
+                                          validFonts );
+    }
+    updated = true;
+  }
+
+  Vector<Character> mirroredUtf32Characters;
+  bool textMirrored = false;
+  const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
+  if( NO_OPERATION != ( BIDI_INFO & operations ) )
+  {
+    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
+    bidirectionalInfo.Reserve( numberOfParagraphs );
+
+    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+    SetBidirectionalInfo( utf32Characters,
+                          scripts,
+                          lineBreakInfo,
+                          startIndex,
+                          requestedNumberOfCharacters,
+                          bidirectionalInfo,
+                          mModel->mMatchSystemLanguageDirection,
+                          mLayoutDirection );
+
+    if( 0u != bidirectionalInfo.Count() )
+    {
+      // Only set the character directions if there is right to left characters.
+      Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
+      GetCharactersDirection( bidirectionalInfo,
+                              numberOfCharacters,
+                              startIndex,
+                              requestedNumberOfCharacters,
+                              directions );
+
+      // This paragraph has right to left text. Some characters may need to be mirrored.
+      // TODO: consider if the mirrored string can be stored as well.
+
+      textMirrored = GetMirroredText( utf32Characters,
+                                      directions,
+                                      bidirectionalInfo,
+                                      startIndex,
+                                      requestedNumberOfCharacters,
+                                      mirroredUtf32Characters );
+    }
+    else
+    {
+      // There is no right to left characters. Clear the directions vector.
+      mModel->mLogicalModel->mCharacterDirections.Clear();
+    }
+    updated = true;
+  }
+
+  Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
+  Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex> newParagraphGlyphs;
+  newParagraphGlyphs.Reserve( numberOfParagraphs );
+
+  const Length currentNumberOfGlyphs = glyphs.Count();
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
+  {
+    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+    // Shapes the text.
+    ShapeText( textToShape,
+               lineBreakInfo,
+               scripts,
+               validFonts,
+               startIndex,
+               mTextUpdateInfo.mStartGlyphIndex,
+               requestedNumberOfCharacters,
+               glyphs,
+               glyphsToCharactersMap,
+               charactersPerGlyph,
+               newParagraphGlyphs );
+
+    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+    mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    updated = true;
+  }
+
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+  if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
+  {
+    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
+
+    // Update the width and advance of all new paragraph characters.
+    for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
+    {
+      const GlyphIndex index = *it;
+      GlyphInfo& glyph = *( glyphsBuffer + index );
+
+      glyph.xBearing = 0.f;
+      glyph.width = 0.f;
+      glyph.advance = 0.f;
+    }
+    updated = true;
+  }
+
+  if( ( NULL != mEventData ) &&
+      mEventData->mPreEditFlag &&
+      ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
+  {
+    Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
+    mEventData->mInputMethodContext.GetPreeditStyle( attrs );
+    Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
+
+    // Check the type of preedit and run it.
+    for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
+    {
+      Dali::InputMethodContext::PreeditAttributeData attrData = *it;
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
+      type = attrData.preeditType;
+
+      // Check the number of commit characters for the start position.
+      unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
+      Length numberOfIndices = attrData.endIndex - attrData.startIndex;
+
+      switch( type )
+      {
+        case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
+        {
+          // Add the underline for the pre-edit text.
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::REVERSE:
+        {
+          Vector4 textColor = mModel->mVisualModel->GetTextColor();
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = textColor;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
+          Vector<ColorRun>  colorRuns;
+          colorRuns.Resize( 1u );
+          ColorRun& colorRun = *( colorRuns.Begin() );
+          colorRun.color = backgroundColor;
+          colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          colorRun.characterRun.numberOfCharacters = numberOfIndices;
+
+          mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
+        {
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = LIGHT_BLUE;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
+        {
+          // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB4;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
+        {
+          // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB5;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
+        {
+          // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB6;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
+        {
+          // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB7;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::NONE:
+        default:
+        {
+          break;
+        }
+      }
+    }
+    attrs.Clear();
+    updated = true;
+  }
+
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
+                              mModel->mVisualModel->mCharactersToGlyph,
+                              mModel->mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mModel->mVisualModel->mColors,
+                              mModel->mVisualModel->mColorIndices );
+
+    // Set the background color runs in glyphs.
+    SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
+                              mModel->mVisualModel->mCharactersToGlyph,
+                              mModel->mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mModel->mVisualModel->mBackgroundColors,
+                              mModel->mVisualModel->mBackgroundColorIndices );
+
+    updated = true;
+  }
+
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
+
+  // Set the previous number of characters for the next time the text is updated.
+  mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
+
+  return updated;
+}
+
+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.lineSpacing = 0.f;
+
+  inputStyle.underlineProperties.clear();
+  inputStyle.shadowProperties.clear();
+  inputStyle.embossProperties.clear();
+  inputStyle.outlineProperties.clear();
+
+  inputStyle.isFamilyDefined = false;
+  inputStyle.isWeightDefined = false;
+  inputStyle.isWidthDefined = false;
+  inputStyle.isSlantDefined = false;
+  inputStyle.isSizeDefined = false;
+
+  inputStyle.isLineSpacingDefined = false;
+
+  inputStyle.isUnderlineDefined = false;
+  inputStyle.isShadowDefined = false;
+  inputStyle.isEmbossDefined = false;
+  inputStyle.isOutlineDefined = false;
+
+  // Sets the default font's family name, weight, width, slant and size.
+  if( mFontDefaults )
+  {
+    if( mFontDefaults->familyDefined )
+    {
+      inputStyle.familyName = mFontDefaults->mFontDescription.family;
+      inputStyle.isFamilyDefined = true;
+    }
+
+    if( mFontDefaults->weightDefined )
+    {
+      inputStyle.weight = mFontDefaults->mFontDescription.weight;
+      inputStyle.isWeightDefined = true;
+    }
+
+    if( mFontDefaults->widthDefined )
+    {
+      inputStyle.width = mFontDefaults->mFontDescription.width;
+      inputStyle.isWidthDefined = true;
+    }
+
+    if( mFontDefaults->slantDefined )
+    {
+      inputStyle.slant = mFontDefaults->mFontDescription.slant;
+      inputStyle.isSlantDefined = true;
+    }
+
+    if( mFontDefaults->sizeDefined )
+    {
+      inputStyle.size = mFontDefaults->mDefaultPointSize;
+      inputStyle.isSizeDefined = true;
+    }
+  }
+}
+
+float Controller::Impl::GetDefaultFontLineHeight()
+{
+  FontId defaultFontId = 0u;
+  if( NULL == mFontDefaults )
+  {
+    TextAbstraction::FontDescription fontDescription;
+    defaultFontId = mFontClient.GetFontId( fontDescription );
+  }
+  else
+  {
+    defaultFontId = mFontDefaults->GetFontId( mFontClient );
+  }
+
+  Text::FontMetrics fontMetrics;
+  mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
+
+  return( fontMetrics.ascender - fontMetrics.descender );
+}
+
+void Controller::Impl::OnCursorKeyEvent( const Event& event )
+{
+  if( NULL == mEventData || !IsShowingRealText() )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  int keyCode = event.p1.mInt;
+  bool isShiftModifier = event.p2.mBool;
+
+  CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
+
+  if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
+  {
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
+      {
+        mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
+      }
+    }
+  }
+  else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
+  {
+    if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
+    {
+      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
+      {
+        mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
+      }
+    }
+  }
+  else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
+  {
+    // Ignore Shift-Up for text selection for now.
+
+    // Get first the line index of the current cursor position index.
+    CharacterIndex characterIndex = 0u;
+
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
+    }
+
+    const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
+    const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
+
+    // Retrieve the cursor position info.
+    CursorInfo cursorInfo;
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
+
+    // Get the line above.
+    const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
+
+    // Get the next hit 'y' point.
+    const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
+
+    // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+    bool matchedCharacter = false;
+    mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                      mModel->mLogicalModel,
+                                                                      mMetrics,
+                                                                      mEventData->mCursorHookPositionX,
+                                                                      hitPointY,
+                                                                      CharacterHitTest::TAP,
+                                                                      matchedCharacter );
+  }
+  else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier )
+  {
+    // Ignore Shift-Down for text selection for now.
+
+    // Get first the line index of the current cursor position index.
+    CharacterIndex characterIndex = 0u;
+
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
+    }
+
+    const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
+
+    if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
+    {
+      // Retrieve the cursor position info.
+      CursorInfo cursorInfo;
+      GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                         cursorInfo );
+
+      // Get the line below.
+      const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
+
+      // Get the next hit 'y' point.
+      const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
+
+      // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+      bool matchedCharacter = false;
+      mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                        mModel->mLogicalModel,
+                                                                        mMetrics,
+                                                                        mEventData->mCursorHookPositionX,
+                                                                        hitPointY,
+                                                                        CharacterHitTest::TAP,
+                                                                        matchedCharacter );
+    }
+  }
+
+  if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
+  {
+    // Update selection position after moving the cursor
+    mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
+    mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+  }
+
+  if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
+  {
+    // Handle text selection
+    bool selecting = false;
+
+    if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
+    {
+      // Shift-Left/Right to select the text
+      int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
+      if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
+      {
+        mEventData->mRightSelectionPosition += cursorPositionDelta;
+      }
+      selecting = true;
+    }
+    else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
+    {
+      // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
+      selecting = true;
+    }
+
+    if ( selecting )
+    {
+      // Notify the cursor position to the InputMethodContext.
+      if( mEventData->mInputMethodContext )
+      {
+        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mInputMethodContext.NotifyCursorPosition();
+      }
+
+      ChangeState( EventData::SELECTING );
+
+      mEventData->mUpdateLeftSelectionPosition = true;
+      mEventData->mUpdateRightSelectionPosition = true;
+      mEventData->mUpdateGrabHandlePosition = true;
+      mEventData->mUpdateHighlightBox = true;
+
+      // Hide the text selection popup if select the text using keyboard instead of moving grab handles
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+    }
+  }
+  else
+  {
+    // Handle normal cursor move
+    ChangeState( EventData::EDITING );
+    mEventData->mUpdateCursorPosition = true;
+  }
+
+  mEventData->mUpdateInputStyle = true;
+  mEventData->mScrollAfterUpdatePosition = true;
+}
+
+void Controller::Impl::OnTapEvent( const Event& event )
+{
+  if( NULL != mEventData )
+  {
+    const unsigned int tapCount = event.p1.mUint;
+
+    if( 1u == tapCount )
+    {
+      if( IsShowingRealText() )
+      {
+        // Convert from control's coords to text's coords.
+        const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+        const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+        // Keep the tap 'x' position. Used to move the cursor.
+        mEventData->mCursorHookPositionX = xPosition;
+
+        // Whether to touch point hits on a glyph.
+        bool matchedCharacter = false;
+        mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                          mModel->mLogicalModel,
+                                                                          mMetrics,
+                                                                          xPosition,
+                                                                          yPosition,
+                                                                          CharacterHitTest::TAP,
+                                                                          matchedCharacter );
+
+        // When the cursor position is changing, delay cursor blinking
+        mEventData->mDecorator->DelayCursorBlink();
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = 0u;
+      }
+
+      // Update selection position after tapping
+      mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
+      mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+
+      mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateGrabHandlePosition = true;
+      mEventData->mScrollAfterUpdatePosition = true;
+      mEventData->mUpdateInputStyle = true;
+
+      // Notify the cursor position to the InputMethodContext.
+      if( mEventData->mInputMethodContext )
+      {
+        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mInputMethodContext.NotifyCursorPosition();
+      }
+    }
+    else if( 2u == tapCount )
+    {
+      if( mEventData->mSelectionEnabled )
+      {
+        // Convert from control's coords to text's coords.
+        const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+        const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+        // Calculates the logical position from the x,y coords.
+        RepositionSelectionHandles( xPosition,
+                                    yPosition,
+                                    mEventData->mDoubleTapAction );
+      }
+    }
+  }
+}
+
+void Controller::Impl::OnPanEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
+  const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
+
+  if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
+  {
+    // Nothing to do if scrolling is not enabled.
+    return;
+  }
+
+  const int state = event.p1.mInt;
+
+  switch( state )
+  {
+    case Gesture::Started:
+    {
+      // Will remove the cursor, handles or text's popup, ...
+      ChangeState( EventData::TEXT_PANNING );
+      break;
+    }
+    case Gesture::Continuing:
+    {
+      const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
+      const Vector2 currentScroll = mModel->mScrollPosition;
+
+      if( isHorizontalScrollEnabled )
+      {
+        const float displacementX = event.p2.mFloat;
+        mModel->mScrollPosition.x += displacementX;
+
+        ClampHorizontalScroll( layoutSize );
+      }
+
+      if( isVerticalScrollEnabled )
+      {
+        const float displacementY = event.p3.mFloat;
+        mModel->mScrollPosition.y += displacementY;
+
+        ClampVerticalScroll( layoutSize );
+      }
+
+      mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
+      break;
+    }
+    case Gesture::Finished:
+    case Gesture::Cancelled: // FALLTHROUGH
+    {
+      // Will go back to the previous state to show the cursor, handles, the text's popup, ...
+      ChangeState( mEventData->mPreviousState );
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+void Controller::Impl::OnLongPressEvent( const Event& event )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
+
+  if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
+  {
+    ChangeState( EventData::EDITING_WITH_POPUP );
+    mEventData->mDecoratorUpdated = true;
+    mEventData->mUpdateInputStyle = true;
+  }
+  else
+  {
+    if( mEventData->mSelectionEnabled )
+    {
+      // Convert from control's coords to text's coords.
+      const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+      const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+      // Calculates the logical position from the x,y coords.
+      RepositionSelectionHandles( xPosition,
+                                  yPosition,
+                                  mEventData->mLongPressAction );
+    }
+  }
+}
+
+void Controller::Impl::OnHandleEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  const unsigned int state = event.p1.mUint;
+  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
+  const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
+
+  if( HANDLE_PRESSED == state )
+  {
+    // Convert from decorator's coords to text's coords.
+    const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+    const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+    // Need to calculate the handle's new position.
+    bool matchedCharacter = false;
+    const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                          mModel->mLogicalModel,
+                                                                          mMetrics,
+                                                                          xPosition,
+                                                                          yPosition,
+                                                                          CharacterHitTest::SCROLL,
+                                                                          matchedCharacter );
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::GRAB_HANDLE_PANNING );
+
+      if( handleNewPosition != mEventData->mPrimaryCursorPosition )
+      {
+        // Updates the cursor position if the handle's new position is different than the current one.
+        mEventData->mUpdateCursorPosition = true;
+        // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+        mEventData->mPrimaryCursorPosition = handleNewPosition;
+      }
+
+      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
+      {
+        // Updates the highlight box if the handle's new position is different than the current one.
+        mEventData->mUpdateHighlightBox = true;
+        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+        mEventData->mLeftSelectionPosition = handleNewPosition;
+      }
+
+      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+
+      // Will define the order to scroll the text to match the handle position.
+      mEventData->mIsLeftHandleSelected = true;
+      mEventData->mIsRightHandleSelected = false;
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
+      {
+        // Updates the highlight box if the handle's new position is different than the current one.
+        mEventData->mUpdateHighlightBox = true;
+        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+        mEventData->mRightSelectionPosition = handleNewPosition;
+      }
+
+      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+
+      // Will define the order to scroll the text to match the handle position.
+      mEventData->mIsLeftHandleSelected = false;
+      mEventData->mIsRightHandleSelected = true;
+    }
+  } // end ( HANDLE_PRESSED == state )
+  else if( ( HANDLE_RELEASED == state ) ||
+           handleStopScrolling )
+  {
+    CharacterIndex handlePosition = 0u;
+    if( handleStopScrolling || isSmoothHandlePanEnabled )
+    {
+      // Convert from decorator's coords to text's coords.
+      const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+      const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+      bool matchedCharacter = false;
+      handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                    mModel->mLogicalModel,
+                                                    mMetrics,
+                                                    xPosition,
+                                                    yPosition,
+                                                    CharacterHitTest::SCROLL,
+                                                    matchedCharacter );
+    }
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateGrabHandlePosition = true;
+      mEventData->mUpdateInputStyle = true;
+
+      if( !IsClipboardEmpty() )
+      {
+        ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
+      }
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      mEventData->mUpdateHighlightBox = true;
+      mEventData->mUpdateLeftSelectionPosition = true;
+      mEventData->mUpdateRightSelectionPosition = true;
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
+
+        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
+            ( handlePosition != mEventData->mLeftSelectionPosition ) )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      mEventData->mUpdateHighlightBox = true;
+      mEventData->mUpdateRightSelectionPosition = true;
+      mEventData->mUpdateLeftSelectionPosition = true;
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
+        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
+            ( handlePosition != mEventData->mLeftSelectionPosition ) )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+    }
+
+    mEventData->mDecoratorUpdated = true;
+  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
+  else if( HANDLE_SCROLLING == state )
+  {
+    const float xSpeed = event.p2.mFloat;
+    const float ySpeed = event.p3.mFloat;
+    const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
+    const Vector2 currentScrollPosition = mModel->mScrollPosition;
+
+    mModel->mScrollPosition.x += xSpeed;
+    mModel->mScrollPosition.y += ySpeed;
+
+    ClampHorizontalScroll( layoutSize );
+    ClampVerticalScroll( layoutSize );
+
+    bool endOfScroll = false;
+    if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
+    {
+      // Notify the decorator there is no more text to scroll.
+      // The decorator won't send more scroll events.
+      mEventData->mDecorator->NotifyEndOfScroll();
+      // Still need to set the position of the handle.
+      endOfScroll = true;
+    }
+
+    // Set the position of the handle.
+    const bool scrollRightDirection = xSpeed > 0.f;
+    const bool scrollBottomDirection = ySpeed > 0.f;
+    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::GRAB_HANDLE_PANNING );
+
+      // Get the grab handle position in decorator coords.
+      Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+
+      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
+      {
+        // Position the grag handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
+      }
+
+      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
+      {
+        position.x = mEventData->mCursorHookPositionX;
+
+        // Position the grag handle close to either the top or bottom edge.
+        position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
+      }
+
+      // Get the new handle position.
+      // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
+      bool matchedCharacter = false;
+      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                         mModel->mLogicalModel,
+                                                                         mMetrics,
+                                                                         position.x - mModel->mScrollPosition.x,
+                                                                         position.y - mModel->mScrollPosition.y,
+                                                                         CharacterHitTest::SCROLL,
+                                                                         matchedCharacter );
+
+      if( mEventData->mPrimaryCursorPosition != handlePosition )
+      {
+        mEventData->mUpdateCursorPosition = true;
+        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+        mEventData->mScrollAfterUpdatePosition = true;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+      mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
+
+      // Updates the decorator if the soft handle panning is enabled.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+    }
+    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+    {
+      ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+      // Get the selection handle position in decorator coords.
+      Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
+      {
+        // Position the selection handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
+      }
+
+      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
+      {
+        position.x = mEventData->mCursorHookPositionX;
+
+        // Position the grag handle close to either the top or bottom edge.
+        position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
+      }
+
+      // Get the new handle position.
+      // The selection handle's position is in decorator's coords. Need to transform to text's coords.
+      bool matchedCharacter = false;
+      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                         mModel->mLogicalModel,
+                                                                         mMetrics,
+                                                                         position.x - mModel->mScrollPosition.x,
+                                                                         position.y - mModel->mScrollPosition.y,
+                                                                         CharacterHitTest::SCROLL,
+                                                                         matchedCharacter );
+
+      if( leftSelectionHandleEvent )
+      {
+        const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
+
+        if( differentHandles || endOfScroll )
+        {
+          mEventData->mUpdateHighlightBox = true;
+          mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+          mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+      else
+      {
+        const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+        if( differentHandles || endOfScroll )
+        {
+          mEventData->mUpdateHighlightBox = true;
+          mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+          mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+
+      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+      {
+        RepositionSelectionHandles();
+
+        mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
+      }
+    }
+    mEventData->mDecoratorUpdated = true;
+  } // end ( HANDLE_SCROLLING == state )
+}
+
+void Controller::Impl::OnSelectEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled )
+  {
+    // Convert from control's coords to text's coords.
+    const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+    const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+    // Calculates the logical position from the x,y coords.
+    RepositionSelectionHandles( xPosition,
+                                yPosition,
+                                Controller::NoTextTap::HIGHLIGHT );
+  }
+}
+
+void Controller::Impl::OnSelectAllEvent()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
+
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled )
+  {
+    // Calculates the logical position from the start.
+    RepositionSelectionHandles( 0.f - mModel->mScrollPosition.x,
+                                0.f - mModel->mScrollPosition.y,
+                                Controller::NoTextTap::HIGHLIGHT );
+
+    mEventData->mLeftSelectionPosition = 0u;
+    mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
+  }
+}
+
+void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
+{
+  if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
+  {
+    // Nothing to select if handles are in the same place.
+    selectedText.clear();
+    return;
+  }
+
+  const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
+
+  //Get start and end position of selection
+  const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+  const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
+
+  Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
+  const Length numberOfCharacters = utf32Characters.Count();
+
+  // Validate the start and end selection points
+  if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
+  {
+    //Get text as a UTF8 string
+    Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
+
+    if( deleteAfterRetrieval ) // Only delete text if copied successfully
+    {
+      // Keep a copy of the current input style.
+      InputStyle currentInputStyle;
+      currentInputStyle.Copy( mEventData->mInputStyle );
+
+      // Set as input style the style of the first deleted character.
+      mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
+
+      // Compare if the input style has changed.
+      const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
+
+      if( hasInputStyleChanged )
+      {
+        const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
+        // Queue the input style changed signal.
+        mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
+      }
+
+      mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
+
+      // Mark the paragraphs to be updated.
+      if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
+      {
+        mTextUpdateInfo.mCharacterIndex = 0;
+        mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+        mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
+        mTextUpdateInfo.mClearAll = true;
+      }
+      else
+      {
+        mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+        mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      }
+
+      // Delete text between handles
+      Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
+      Vector<Character>::Iterator last  = first + lengthOfSelectedText;
+      utf32Characters.Erase( first, last );
+
+      // Will show the cursor at the first character of the selection.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+    }
+    else
+    {
+      // Will show the cursor at the last character of the selection.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
+    }
+
+    mEventData->mDecoratorUpdated = true;
+  }
+}
+
+void Controller::Impl::ShowClipboard()
+{
+  if( mClipboard )
+  {
+    mClipboard.ShowClipboard();
+  }
+}
+
+void Controller::Impl::HideClipboard()
+{
+  if( mClipboard && mClipboardHideEnabled )
+  {
+    mClipboard.HideClipboard();
+  }
+}
+
+void Controller::Impl::SetClipboardHideEnable(bool enable)
+{
+  mClipboardHideEnabled = enable;
+}
+
+bool Controller::Impl::CopyStringToClipboard( std::string& source )
+{
+  //Send string to clipboard
+  return ( mClipboard && mClipboard.SetItem( source ) );
+}
+
+void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
+{
+  std::string selectedText;
+  RetrieveSelection( selectedText, deleteAfterSending );
+  CopyStringToClipboard( selectedText );
+  ChangeState( EventData::EDITING );
+}
+
+void Controller::Impl::RequestGetTextFromClipboard()
+{
+  if ( mClipboard )
+  {
+    mClipboard.RequestItem();
+  }
+}
+
+void Controller::Impl::RepositionSelectionHandles()
+{
+  CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
+  CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
+
+  if( selectionStart == selectionEnd )
+  {
+    // Nothing to select if handles are in the same place.
+    // So, deactive Highlight box.
+    mEventData->mDecorator->SetHighlightActive( false );
+    return;
+  }
+
+  mEventData->mDecorator->ClearHighlights();
+
+  const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
+  const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
+  const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
+  const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
+  const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
+  const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
+
+  const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
+  const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
+  const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
+
+  // Swap the indices if the start is greater than the end.
+  const bool indicesSwapped = selectionStart > selectionEnd;
+
+  // Tell the decorator to flip the selection handles if needed.
+  mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
+
+  if( indicesSwapped )
+  {
+    std::swap( selectionStart, selectionEnd );
+  }
+
+  // Get the indices to the first and last selected glyphs.
+  const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
+  const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
+  const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
+  const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
+
+  // Get the lines where the glyphs are laid-out.
+  const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
+
+  LineIndex lineIndex = 0u;
+  Length numberOfLines = 0u;
+  mModel->mVisualModel->GetNumberOfLines( glyphStart,
+                                          1u + glyphEnd - glyphStart,
+                                          lineIndex,
+                                          numberOfLines );
+  const LineIndex firstLineIndex = lineIndex;
+
+  // Create the structure to store some selection box info.
+  Vector<SelectionBoxInfo> selectionBoxLinesInfo;
+  selectionBoxLinesInfo.Resize( numberOfLines );
+
+  SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
+  selectionBoxInfo->minX = MAX_FLOAT;
+  selectionBoxInfo->maxX = MIN_FLOAT;
+
+  // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
+  float minHighlightX = std::numeric_limits<float>::max();
+  float maxHighlightX = std::numeric_limits<float>::min();
+  Size highLightSize;
+  Vector2 highLightPosition; // The highlight position in decorator's coords.
+
+  // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
+
+  // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
+  selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
+                                                      firstLineIndex );
+
+  // Transform to decorator's (control) coords.
+  selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
+
+  lineRun += firstLineIndex;
+
+  // The line height is the addition of the line ascender and the line descender.
+  // However, the line descender has a negative value, hence the subtraction.
+  selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
+
+  GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
+
+  // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
+  bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
+
+  // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
+  bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
+
+  // The number of quads of the selection box.
+  const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
+  mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
+
+  // Count the actual number of quads.
+  unsigned int actualNumberOfQuads = 0u;
+  Vector4 quad;
+
+  // Traverse the glyphs.
+  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  {
+    const GlyphInfo& glyph = *( glyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+
+    if( splitStartGlyph )
+    {
+      // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
+      const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
+      }
+
+      // The end point could be in the middle of the ligature.
+      // Calculate the number of characters selected.
+      const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
+
+      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
+      quad.y = selectionBoxInfo->lineOffset;
+      quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
+      quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
+
+      // Store the min and max 'x' for each line.
+      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
+      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
+      ++actualNumberOfQuads;
+
+      splitStartGlyph = false;
+      continue;
+    }
+
+    if( splitEndGlyph && ( index == glyphEnd ) )
+    {
+      // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
+      const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
+      }
+
+      const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
+
+      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
+      quad.y = selectionBoxInfo->lineOffset;
+      quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
+      quad.w = quad.y + selectionBoxInfo->lineHeight;
+
+      // Store the min and max 'x' for each line.
+      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
+      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                            quad );
+      ++actualNumberOfQuads;
+
+      splitEndGlyph = false;
+      continue;
+    }
+
+    quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
+    quad.y = selectionBoxInfo->lineOffset;
+    quad.z = quad.x + glyph.advance;
+    quad.w = quad.y + selectionBoxInfo->lineHeight;
+
+    // Store the min and max 'x' for each line.
+    selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
+    selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
+
+    mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                          quad );
+    ++actualNumberOfQuads;
+
+    // Whether to retrieve the next line.
+    if( index == lastGlyphOfLine )
+    {
+      ++lineIndex;
+      if( lineIndex < firstLineIndex + numberOfLines )
+      {
+        // Retrieve the next line.
+        ++lineRun;
+
+        // Get the last glyph of the new line.
+        lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
+
+        // Keep the offset and height of the current selection box.
+        const float currentLineOffset = selectionBoxInfo->lineOffset;
+        const float currentLineHeight = selectionBoxInfo->lineHeight;
+
+        // Get the selection box info for the next line.
+        ++selectionBoxInfo;
+
+        selectionBoxInfo->minX = MAX_FLOAT;
+        selectionBoxInfo->maxX = MIN_FLOAT;
+
+        // Update the line's vertical offset.
+        selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
+
+        // The line height is the addition of the line ascender and the line descender.
+        // However, the line descender has a negative value, hence the subtraction.
+        selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
+      }
+    }
+  }
+
+  // Traverses all the lines and updates the min and max 'x' positions and the total height.
+  // The final width is calculated after 'boxifying' the selection.
+  for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
+         endIt = selectionBoxLinesInfo.End();
+       it != endIt;
+       ++it )
+  {
+    const SelectionBoxInfo& info = *it;
+
+    // Update the size of the highlighted text.
+    highLightSize.height += info.lineHeight;
+    minHighlightX = std::min( minHighlightX, info.minX );
+    maxHighlightX = std::max( maxHighlightX, info.maxX );
+  }
+
+  // Add extra geometry to 'boxify' the selection.
+
+  if( 1u < numberOfLines )
+  {
+    // Boxify the first line.
+    lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
+    const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
+
+    bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
+    bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
+
+    if( boxifyBegin )
+    {
+      quad.x = 0.f;
+      quad.y = firstSelectionBoxLineInfo.lineOffset;
+      quad.z = firstSelectionBoxLineInfo.minX;
+      quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
+
+      // Boxify at the beginning of the line.
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                            quad );
+      ++actualNumberOfQuads;
+
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
+    }
+
+    if( boxifyEnd )
+    {
+      quad.x = firstSelectionBoxLineInfo.maxX;
+      quad.y = firstSelectionBoxLineInfo.lineOffset;
+      quad.z = mModel->mVisualModel->mControlSize.width;
+      quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
+
+      // Boxify at the end of the line.
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                            quad );
+      ++actualNumberOfQuads;
+
+      // Update the size of the highlighted text.
+      maxHighlightX = mModel->mVisualModel->mControlSize.width;
+    }
+
+    // Boxify the central lines.
+    if( 2u < numberOfLines )
+    {
+      for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
+             endIt = selectionBoxLinesInfo.End() - 1u;
+           it != endIt;
+           ++it )
+      {
+        const SelectionBoxInfo& info = *it;
+
+        quad.x = 0.f;
+        quad.y = info.lineOffset;
+        quad.z = info.minX;
+        quad.w = info.lineOffset + info.lineHeight;
+
+        mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                              quad );
+        ++actualNumberOfQuads;
+
+        quad.x = info.maxX;
+        quad.y = info.lineOffset;
+        quad.z = mModel->mVisualModel->mControlSize.width;
+        quad.w = info.lineOffset + info.lineHeight;
+
+        mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                              quad );
+        ++actualNumberOfQuads;
+      }
+
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
+      maxHighlightX = mModel->mVisualModel->mControlSize.width;
+    }
+
+    // Boxify the last line.
+    lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
+    const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
+
+    boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
+    boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
+
+    if( boxifyBegin )
+    {
+      quad.x = 0.f;
+      quad.y = lastSelectionBoxLineInfo.lineOffset;
+      quad.z = lastSelectionBoxLineInfo.minX;
+      quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
+
+      // Boxify at the beginning of the line.
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                            quad );
+      ++actualNumberOfQuads;
+
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
+    }
+
+    if( boxifyEnd )
+    {
+      quad.x = lastSelectionBoxLineInfo.maxX;
+      quad.y = lastSelectionBoxLineInfo.lineOffset;
+      quad.z = mModel->mVisualModel->mControlSize.width;
+      quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
+
+      // Boxify at the end of the line.
+      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
+                                            quad );
+      ++actualNumberOfQuads;
+
+      // Update the size of the highlighted text.
+      maxHighlightX = mModel->mVisualModel->mControlSize.width;
+    }
+  }
+
+  // Set the actual number of quads.
+  mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
+
+  // Sets the highlight's size and position. In decorator's coords.
+  // The highlight's height has been calculated above (before 'boxifying' the highlight).
+  highLightSize.width = maxHighlightX - minHighlightX;
+
+  highLightPosition.x = minHighlightX;
+  const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
+  highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
+
+  mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
+
+  if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
+  {
+    CursorInfo primaryCursorInfo;
+    GetCursorPosition( mEventData->mLeftSelectionPosition,
+                       primaryCursorInfo );
+
+    const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
+
+    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
+                                         primaryPosition.x,
+                                         primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
+                                         primaryCursorInfo.lineHeight );
+
+    CursorInfo secondaryCursorInfo;
+    GetCursorPosition( mEventData->mRightSelectionPosition,
+                       secondaryCursorInfo );
+
+    const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
+
+    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
+                                         secondaryPosition.x,
+                                         secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
+                                         secondaryCursorInfo.lineHeight );
+  }
+
+  // Set the flag to update the decorator.
+  mEventData->mDecoratorUpdated = true;
+}
+
+void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  if( IsShowingPlaceholderText() )
+  {
+    // Nothing to do if there is the place-holder text.
+    return;
+  }
+
+  const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
+  const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
+  if( ( 0 == numberOfGlyphs ) ||
+      ( 0 == numberOfLines ) )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  // Find which word was selected
+  CharacterIndex selectionStart( 0 );
+  CharacterIndex selectionEnd( 0 );
+  CharacterIndex noTextHitIndex( 0 );
+  const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
+                                                  mModel->mLogicalModel,
+                                                  mMetrics,
+                                                  visualX,
+                                                  visualY,
+                                                  selectionStart,
+                                                  selectionEnd,
+                                                  noTextHitIndex );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
+
+  if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
+  {
+    ChangeState( EventData::SELECTING );
+
+    mEventData->mLeftSelectionPosition = selectionStart;
+    mEventData->mRightSelectionPosition = selectionEnd;
+
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
+    mEventData->mUpdateHighlightBox = true;
+
+    // It may happen an InputMethodContext commit event arrives before the selection event
+    // if the InputMethodContext is in pre-edit state. The commit event will set the
+    // mEventData->mUpdateCursorPosition flag to true. If it's not set back
+    // to false, the highlight box won't be updated.
+    mEventData->mUpdateCursorPosition = false;
+
+    mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
+
+    // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
+    mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+  }
+  else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
+  {
+    // Nothing to select. i.e. a white space, out of bounds
+    ChangeState( EventData::EDITING_WITH_POPUP );
+
+    mEventData->mPrimaryCursorPosition = noTextHitIndex;
+
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mUpdateGrabHandlePosition = true;
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateInputStyle = true;
+  }
+  else if( Controller::NoTextTap::NO_ACTION == action )
+  {
+    // Nothing to select. i.e. a white space, out of bounds
+    mEventData->mPrimaryCursorPosition = noTextHitIndex;
+
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mUpdateGrabHandlePosition = true;
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateInputStyle = true;
+  }
+}
+
+void Controller::Impl::SetPopupButtons()
+{
+  /**
+   *  Sets the Popup buttons to be shown depending on State.
+   *
+   *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
+   *
+   *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
+   */
+
+  TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
+
+  if( EventData::SELECTING == mEventData->mState )
+  {
+    buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+
+    if( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+
+    if( !mEventData->mAllTextSelected )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
+    }
+  }
+  else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
+  {
+    if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
+    }
+
+    if( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+  }
+  else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
+  {
+    if ( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+  }
+
+  mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+}
+
+void Controller::Impl::ChangeState( EventData::State newState )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
+
+  if( mEventData->mState != newState )
+  {
+    mEventData->mPreviousState = mEventData->mState;
+    mEventData->mState = newState;
+
+    switch( mEventData->mState )
+    {
+      case EventData::INACTIVE:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->StopCursorBlink();
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        mEventData->mDecorator->SetPopupActive( false );
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::INTERRUPTED:
+      {
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        mEventData->mDecorator->SetPopupActive( false );
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::SELECTING:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->StopCursorBlink();
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        }
+        mEventData->mDecorator->SetHighlightActive( true );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_POPUP:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
+
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
+        if( mEventData->mSelectionEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHighlightActive( false );
+        }
+        else if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_GRAB_HANDLE:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
+
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::SELECTION_HANDLE_PANNING:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->StopCursorBlink();
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        }
+        mEventData->mDecorator->SetHighlightActive( true );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::GRAB_HANDLE_PANNING:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
+
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_PASTE_POPUP:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
+
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
+
+        if ( mEventData->mGrabHandleEnabled )
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::TEXT_PANNING:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->StopCursorBlink();
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
+            mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHighlightActive( true );
+        }
+
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+    }
+  }
+}
+
+void Controller::Impl::GetCursorPosition( CharacterIndex logical,
+                                          CursorInfo& cursorInfo )
+{
+  if( !IsShowingRealText() )
+  {
+    // Do not want to use the place-holder text to set the cursor position.
+
+    // Use the line's height of the font's family set to set the cursor's size.
+    // If there is no font's family set, use the default font.
+    // Use the current alignment to place the cursor at the beginning, center or end of the box.
+
+    cursorInfo.lineOffset = 0.f;
+    cursorInfo.lineHeight = GetDefaultFontLineHeight();
+    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+
+    bool isRTL = false;
+    if( mModel->mMatchSystemLanguageDirection )
+    {
+      isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
+    }
+
+    switch( mModel->mHorizontalAlignment )
+    {
+      case Text::HorizontalAlignment::BEGIN :
+      {
+        if( isRTL )
+        {
+          cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+        }
+        else
+        {
+          cursorInfo.primaryPosition.x = 0.f;
+        }
+        break;
+      }
+      case Text::HorizontalAlignment::CENTER:
+      {
+        cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
+        break;
+      }
+      case Text::HorizontalAlignment::END:
+      {
+        if( isRTL )
+        {
+          cursorInfo.primaryPosition.x = 0.f;
+        }
+        else
+        {
+          cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+        }
+        break;
+      }
+    }
+
+    // Nothing else to do.
+    return;
+  }
+
+  const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
+  GetCursorPositionParameters parameters;
+  parameters.visualModel = mModel->mVisualModel;
+  parameters.logicalModel = mModel->mLogicalModel;
+  parameters.metrics = mMetrics;
+  parameters.logical = logical;
+  parameters.isMultiline = isMultiLine;
+
+  Text::GetCursorPosition( parameters,
+                           cursorInfo );
+
+  // Adds Outline offset.
+  const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
+  cursorInfo.primaryPosition.x += outlineWidth;
+  cursorInfo.primaryPosition.y += outlineWidth;
+  cursorInfo.secondaryPosition.x += outlineWidth;
+  cursorInfo.secondaryPosition.y += outlineWidth;
+
+  if( isMultiLine )
+  {
+    // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
+
+    // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
+    // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
+
+    if( 0.f > cursorInfo.primaryPosition.x )
+    {
+      cursorInfo.primaryPosition.x = 0.f;
+    }
+
+    const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
+    if( cursorInfo.primaryPosition.x > edgeWidth )
+    {
+      cursorInfo.primaryPosition.x = edgeWidth;
+    }
+  }
+}
+
+CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return 0u;
+  }
+
+  CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
+
+  const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
+
+  GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
+  Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
+
+  if( numberOfCharacters > 1u )
+  {
+    const Script script = mModel->mLogicalModel->GetScript( index );
+    if( HasLigatureMustBreak( script ) )
+    {
+      // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ, ...
+      numberOfCharacters = 1u;
+    }
+  }
+  else
+  {
+    while( 0u == numberOfCharacters )
+    {
+      ++glyphIndex;
+      numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
+    }
+  }
+
+  if( index < mEventData->mPrimaryCursorPosition )
+  {
+    cursorIndex -= numberOfCharacters;
+  }
+  else
+  {
+    cursorIndex += numberOfCharacters;
+  }
+
+  // Will update the cursor hook position.
+  mEventData->mUpdateCursorHookPosition = true;
+
+  return cursorIndex;
+}
+
+void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
+    return;
+  }
+
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
+
+  mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
+
+  // Sets the cursor position.
+  mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.primaryCursorHeight,
+                                       cursorInfo.lineHeight );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
+
+  if( mEventData->mUpdateGrabHandlePosition )
+  {
+    // Sets the grab handle position.
+    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                         cursorPosition.x,
+                                         cursorInfo.lineOffset + mModel->mScrollPosition.y,
+                                         cursorInfo.lineHeight );
+  }
+
+  if( cursorInfo.isSecondaryCursor )
+  {
+    mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                         cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
+                                         cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
+                                         cursorInfo.secondaryCursorHeight,
+                                         cursorInfo.lineHeight );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
+  }
+
+  // Set which cursors are active according the state.
+  if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+  {
+    if( cursorInfo.isSecondaryCursor )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
+    }
+    else
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    }
+  }
+  else
+  {
+    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
+}
+
+void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
+                                              const CursorInfo& cursorInfo )
+{
+  if( ( LEFT_SELECTION_HANDLE != handleType ) &&
+      ( RIGHT_SELECTION_HANDLE != handleType ) )
+  {
+    return;
+  }
+
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
+
+  // Sets the handle's position.
+  mEventData->mDecorator->SetPosition( handleType,
+                                       cursorPosition.x,
+                                       cursorInfo.lineOffset + mModel->mScrollPosition.y,
+                                       cursorInfo.lineHeight );
+
+  // If selection handle at start of the text and other at end of the text then all text is selected.
+  const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+  const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+  mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
+}
+
+void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
+{
+  // Clamp between -space & -alignment offset.
+
+  if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
+  {
+    const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
+    mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
+    mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
+
+    mEventData->mDecoratorUpdated = true;
+  }
+  else
+  {
+    mModel->mScrollPosition.x = 0.f;
+  }
+}
+
+void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
+{
+  if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
+  {
+    // Nothing to do if the text is single line.
+    return;
+  }
+
+  // Clamp between -space & 0.
+  if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
+  {
+    const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
+    mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
+    mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
+
+    mEventData->mDecoratorUpdated = true;
+  }
+  else
+  {
+    mModel->mScrollPosition.y = 0.f;
+  }
+}
+
+void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
+{
+  const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
+
+  // position is in actor's coords.
+  const float positionEndX = position.x + cursorWidth;
+  const float positionEndY = position.y + lineHeight;
+
+  // Transform the position to decorator coords.
+  const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
+  const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
+
+  const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
+  const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
+
+  if( decoratorPositionBeginX < 0.f )
+  {
+    mModel->mScrollPosition.x = -position.x;
+  }
+  else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
+  {
+    mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
+  }
+
+  if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
+  {
+    if( decoratorPositionBeginY < 0.f )
+    {
+      mModel->mScrollPosition.y = -position.y;
+    }
+    else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
+    {
+      mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+    }
+  }
+}
+
+void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
+{
+  // Get the current cursor position in decorator coords.
+  const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+  const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
+
+
+
+  // Calculate the offset to match the cursor position before the character was deleted.
+  mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
+
+  //If text control has more than two lines and current line index is not last, calculate scrollpositionY
+  if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
+  {
+    const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
+    mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
+  }
+
+
+  ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
+  ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
+
+  // Makes the new cursor position visible if needed.
+  ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
+}
+
+void Controller::Impl::RequestRelayout()
+{
+  if( NULL != mControlInterface )
+  {
+    mControlInterface->RequestTextRelayout();
+  }
+}
+
+Actor Controller::Impl::CreateBackgroundActor()
+{
+  // NOTE: Currently we only support background color for one line left-to-right text,
+  //       so the following calculation is based on one line left-to-right text only!
+
+  Actor actor;
+
+  Length numberOfGlyphs = mView.GetNumberOfGlyphs();
+  if( numberOfGlyphs > 0u )
+  {
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize( numberOfGlyphs );
+
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
+
+    // Get the line where the glyphs are laid-out.
+    const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
+    float alignmentOffset = lineRun->alignmentOffset;
+    numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
+                                      positions.Begin(),
+                                      alignmentOffset,
+                                      0u,
+                                      numberOfGlyphs );
+
+    glyphs.Resize( numberOfGlyphs );
+    positions.Resize( numberOfGlyphs );
+
+    const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+    const Vector2* const positionsBuffer = positions.Begin();
+
+    BackgroundMesh mesh;
+    mesh.mVertices.Reserve( 4u * glyphs.Size() );
+    mesh.mIndices.Reserve( 6u * glyphs.Size() );
+
+    const Vector2 textSize = mView.GetLayoutSize();
+
+    const float offsetX = textSize.width * 0.5f;
+    const float offsetY = textSize.height * 0.5f;
+
+    const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
+    const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
+    const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
+
+    Vector4 quad;
+    uint32_t numberOfQuads = 0u;
+
+    for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
+    {
+      const GlyphInfo& glyph = *( glyphsBuffer + i );
+
+      // Get the background color of the character.
+      // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
+      const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
+      const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? defaultBackgroundColor : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
+
+      // Only create quads for glyphs with a background color
+      if ( backgroundColor != Color::TRANSPARENT )
+      {
+        const Vector2 position = *( positionsBuffer + i );
+
+        if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
+        {
+          quad.x = position.x;
+          quad.y = 0.0f;
+          quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
+          quad.w = textSize.height;
+        }
+        else if ( i == 0u ) // The first glyph in the whole text
+        {
+          quad.x = position.x;
+          quad.y = 0.0f;
+          quad.z = quad.x - glyph.xBearing + glyph.advance;
+          quad.w = textSize.height;
+        }
+        else if ( i == glyphSize - 1u ) // The last glyph in the whole text
+        {
+          quad.x = position.x - glyph.xBearing;
+          quad.y = 0.0f;
+          quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
+          quad.w = textSize.height;
+        }
+        else // The glyph in the middle of the text
+        {
+          quad.x = position.x - glyph.xBearing;
+          quad.y = 0.0f;
+          quad.z = quad.x + glyph.advance;
+          quad.w = textSize.height;
+        }
+
+        BackgroundVertex vertex;
+
+        // Top left
+        vertex.mPosition.x = quad.x - offsetX;
+        vertex.mPosition.y = quad.y - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Top right
+        vertex.mPosition.x = quad.z - offsetX;
+        vertex.mPosition.y = quad.y - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Bottom left
+        vertex.mPosition.x = quad.x - offsetX;
+        vertex.mPosition.y = quad.w - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Bottom right
+        vertex.mPosition.x = quad.z - offsetX;
+        vertex.mPosition.y = quad.w - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Six indices in counter clockwise winding
+        mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
+
+        numberOfQuads++;
+      }
+    }
+
+    // Only create the background actor if there are glyphs with background color
+    if ( mesh.mVertices.Count() > 0u )
+    {
+      Property::Map quadVertexFormat;
+      quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+      quadVertexFormat[ "aColor" ] = Property::VECTOR4;
+
+      PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
+      quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
+
+      Geometry quadGeometry = Geometry::New();
+      quadGeometry.AddVertexBuffer( quadVertices );
+      quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
+
+      if( !mShaderBackground )
+      {
+        mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
+      }
+
+      Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
+      renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
+      renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
+
+      actor = Actor::New();
+      actor.SetName( "TextBackgroundColorActor" );
+      actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      actor.SetSize( textSize );
+      actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+      actor.AddRenderer( renderer );
+    }
+  }
+
+  return actor;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h
new file mode 100755 (executable)
index 0000000..064d644
--- /dev/null
@@ -0,0 +1,805 @@
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
+
+/*
+ * Copyright (c) 2017 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 <dali/devel-api/adaptor-framework/clipboard.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-model.h>
+#include <dali-toolkit/internal/text/text-view.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+const float DEFAULT_TEXTFIT_MIN = 10.f;
+const float DEFAULT_TEXTFIT_MAX = 100.f;
+const float DEFAULT_TEXTFIT_STEP = 1.f;
+
+//Forward declarations
+struct CursorInfo;
+struct FontDefaults;
+
+struct Event
+{
+  // Used to queue input events until DoRelayout()
+  enum Type
+  {
+    CURSOR_KEY_EVENT,
+    TAP_EVENT,
+    PAN_EVENT,
+    LONG_PRESS_EVENT,
+    GRAB_HANDLE_EVENT,
+    LEFT_SELECTION_HANDLE_EVENT,
+    RIGHT_SELECTION_HANDLE_EVENT,
+    SELECT,
+    SELECT_ALL
+  };
+
+  union Param
+  {
+    int mInt;
+    unsigned int mUint;
+    float mFloat;
+    bool mBool;
+  };
+
+  Event( Type eventType )
+  : type( eventType )
+  {
+    p1.mInt = 0;
+    p2.mInt = 0;
+    p3.mInt = 0;
+  }
+
+  Type type;
+  Param p1;
+  Param p2;
+  Param p3;
+};
+
+struct EventData
+{
+  enum State
+  {
+    INACTIVE,
+    INTERRUPTED,
+    SELECTING,
+    EDITING,
+    EDITING_WITH_POPUP,
+    EDITING_WITH_GRAB_HANDLE,
+    EDITING_WITH_PASTE_POPUP,
+    GRAB_HANDLE_PANNING,
+    SELECTION_HANDLE_PANNING,
+    TEXT_PANNING
+  };
+
+  EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext );
+
+  ~EventData();
+
+  static bool IsEditingState( State stateToCheck )
+  {
+    return ( stateToCheck == EDITING || stateToCheck == EDITING_WITH_POPUP || stateToCheck == EDITING_WITH_GRAB_HANDLE || stateToCheck == EDITING_WITH_PASTE_POPUP );
+  }
+
+  DecoratorPtr       mDecorator;               ///< Pointer to the decorator.
+  InputMethodContext mInputMethodContext;      ///< The Input Method Framework Manager.
+  FontDefaults*      mPlaceholderFont;         ///< The placeholder default font.
+  std::string        mPlaceholderTextActive;   ///< The text to display when the TextField is empty with key-input focus.
+  std::string        mPlaceholderTextInactive; ///< The text to display when the TextField is empty and inactive.
+  Vector4            mPlaceholderTextColor;    ///< The in/active placeholder text color.
+
+  /**
+   * This is used to delay handling events until after the model has been updated.
+   * The number of updates to the model is minimized to improve performance.
+   */
+  std::vector<Event> mEventQueue;              ///< The queue of touch events etc.
+
+  Vector<InputStyle::Mask> mInputStyleChangedQueue; ///< Queue of changes in the input style. Used to emit the signal in the iddle callback.
+
+  InputStyle         mInputStyle;              ///< The style to be set to the new inputed text.
+
+  State              mPreviousState;           ///< Stores the current state before it's updated with the new one.
+  State              mState;                   ///< Selection mode, edit mode etc.
+
+  CharacterIndex     mPrimaryCursorPosition;   ///< Index into logical model for primary cursor.
+  CharacterIndex     mLeftSelectionPosition;   ///< Index into logical model for left selection handle.
+  CharacterIndex     mRightSelectionPosition;  ///< Index into logical model for right selection handle.
+
+  CharacterIndex     mPreEditStartPosition;    ///< Used to remove the pre-edit text if necessary.
+  Length             mPreEditLength;           ///< Used to remove the pre-edit text if necessary.
+
+  float              mCursorHookPositionX;     ///< Used to move the cursor with the keys or when scrolling the text vertically with the handles.
+
+  Controller::NoTextTap::Action mDoubleTapAction; ///< Action to be done when there is a double tap on top of 'no text'
+  Controller::NoTextTap::Action mLongPressAction; ///< Action to be done when there is a long press on top of 'no text'
+
+  bool mIsShowingPlaceholderText        : 1;   ///< True if the place-holder text is being displayed.
+  bool mPreEditFlag                     : 1;   ///< True if the model contains text in pre-edit state.
+  bool mDecoratorUpdated                : 1;   ///< True if the decorator was updated during event processing.
+  bool mCursorBlinkEnabled              : 1;   ///< True if cursor should blink when active.
+  bool mGrabHandleEnabled               : 1;   ///< True if grab handle is enabled.
+  bool mGrabHandlePopupEnabled          : 1;   ///< True if the grab handle popu-up should be shown.
+  bool mSelectionEnabled                : 1;   ///< True if selection handles, highlight etc. are enabled.
+  bool mUpdateCursorHookPosition        : 1;   ///< True if the cursor hook position must be updated. Used to move the cursor with the keys 'up' and 'down'.
+  bool mUpdateCursorPosition            : 1;   ///< True if the visual position of the cursor must be recalculated.
+  bool mUpdateGrabHandlePosition        : 1;   ///< True if the visual position of the grab handle must be recalculated.
+  bool mUpdateLeftSelectionPosition     : 1;   ///< True if the visual position of the left selection handle must be recalculated.
+  bool mUpdateRightSelectionPosition    : 1;   ///< True if the visual position of the right selection handle must be recalculated.
+  bool mIsLeftHandleSelected            : 1;   ///< Whether is the left handle the one which is selected.
+  bool mIsRightHandleSelected           : 1;   ///< Whether is the right handle the one which is selected.
+  bool mUpdateHighlightBox              : 1;   ///< True if the text selection high light box must be updated.
+  bool mScrollAfterUpdatePosition       : 1;   ///< Whether to scroll after the cursor position is updated.
+  bool mScrollAfterDelete               : 1;   ///< Whether to scroll after delete characters.
+  bool mAllTextSelected                 : 1;   ///< True if the selection handles are selecting all the text.
+  bool mUpdateInputStyle                : 1;   ///< Whether to update the input style after moving the cursor.
+  bool mPasswordInput                   : 1;   ///< True if password input is enabled.
+  bool mCheckScrollAmount               : 1;   ///< Whether to check scrolled amount after updating the position
+  bool mIsPlaceholderPixelSize          : 1;   ///< True if the placeholder font size is set as pixel size.
+  bool mIsPlaceholderElideEnabled       : 1;   ///< True if the placeholder text's elide is enabled.
+  bool mPlaceholderEllipsisFlag         : 1;   ///< True if the text controller sets the placeholder ellipsis.
+  bool mShiftSelectionFlag              : 1;   ///< True if the text selection using Shift key is enabled.
+  bool mUpdateAlignment                 : 1;   ///< True if the whole text needs to be full aligned..
+};
+
+struct ModifyEvent
+{
+  enum Type
+  {
+    TEXT_REPLACED,    ///< The entire text was replaced
+    TEXT_INSERTED,    ///< Insert characters at the current cursor position
+    TEXT_DELETED      ///< Characters were deleted
+  };
+
+  Type type;
+};
+
+struct FontDefaults
+{
+  FontDefaults()
+  : mFontDescription(),
+    mDefaultPointSize( 0.f ),
+    mFitPointSize( 0.f ),
+    mFontId( 0u ),
+    familyDefined( false ),
+    weightDefined( false ),
+    widthDefined( false ),
+    slantDefined( false ),
+    sizeDefined( false )
+  {
+    // Initially use the default platform font
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+    fontClient.GetDefaultPlatformFontDescription( mFontDescription );
+  }
+
+  FontId GetFontId( TextAbstraction::FontClient& fontClient )
+  {
+    if( !mFontId )
+    {
+      const PointSize26Dot6 pointSize = static_cast<PointSize26Dot6>( mDefaultPointSize * 64.f );
+      mFontId = fontClient.GetFontId( mFontDescription, pointSize );
+    }
+
+    return mFontId;
+  }
+
+  TextAbstraction::FontDescription mFontDescription;  ///< The default font's description.
+  float                            mDefaultPointSize; ///< The default font's point size.
+  float                            mFitPointSize; ///< The fit font's point size.
+  FontId                           mFontId;           ///< The font's id of the default font.
+  bool familyDefined:1; ///< Whether the default font's family name is defined.
+  bool weightDefined:1; ///< Whether the default font's weight is defined.
+  bool  widthDefined:1; ///< Whether the default font's width is defined.
+  bool  slantDefined:1; ///< Whether the default font's slant is defined.
+  bool   sizeDefined:1; ///< Whether the default font's point size is defined.
+};
+
+/**
+ * @brief Stores indices used to update the text.
+ * Stores the character index where the text is updated and the number of characters removed and added.
+ * Stores as well indices to the first and the last paragraphs to be updated.
+ */
+struct TextUpdateInfo
+{
+  TextUpdateInfo()
+  : mCharacterIndex( 0u ),
+    mNumberOfCharactersToRemove( 0u ),
+    mNumberOfCharactersToAdd( 0u ),
+    mPreviousNumberOfCharacters( 0u ),
+    mParagraphCharacterIndex( 0u ),
+    mRequestedNumberOfCharacters( 0u ),
+    mStartGlyphIndex( 0u ),
+    mStartLineIndex( 0u ),
+    mEstimatedNumberOfLines( 0u ),
+    mClearAll( true ),
+    mFullRelayoutNeeded( true ),
+    mIsLastCharacterNewParagraph( false )
+  {}
+
+  ~TextUpdateInfo()
+  {}
+
+  CharacterIndex    mCharacterIndex;                ///< Index to the first character to be updated.
+  Length            mNumberOfCharactersToRemove;    ///< The number of characters to be removed.
+  Length            mNumberOfCharactersToAdd;       ///< The number of characters to be added.
+  Length            mPreviousNumberOfCharacters;    ///< The number of characters before the text update.
+
+  CharacterIndex    mParagraphCharacterIndex;       ///< Index of the first character of the first paragraph to be updated.
+  Length            mRequestedNumberOfCharacters;   ///< The requested number of characters.
+  GlyphIndex        mStartGlyphIndex;
+  LineIndex         mStartLineIndex;
+  Length            mEstimatedNumberOfLines;         ///< The estimated number of lines. Used to avoid reallocations when layouting.
+
+  bool              mClearAll:1;                    ///< Whether the whole text is cleared. i.e. when the text is reset.
+  bool              mFullRelayoutNeeded:1;          ///< Whether a full re-layout is needed. i.e. when a new size is set to the text control.
+  bool              mIsLastCharacterNewParagraph:1; ///< Whether the last character is a new paragraph character.
+
+  void Clear()
+  {
+    // Clear all info except the mPreviousNumberOfCharacters member.
+    mCharacterIndex = static_cast<CharacterIndex>( -1 );
+    mNumberOfCharactersToRemove = 0u;
+    mNumberOfCharactersToAdd = 0u;
+    mParagraphCharacterIndex = 0u;
+    mRequestedNumberOfCharacters = 0u;
+    mStartGlyphIndex = 0u;
+    mStartLineIndex = 0u;
+    mEstimatedNumberOfLines = 0u;
+    mClearAll = false;
+    mFullRelayoutNeeded = false;
+    mIsLastCharacterNewParagraph = false;
+  }
+};
+
+struct UnderlineDefaults
+{
+  std::string properties;
+  // TODO: complete with underline parameters.
+};
+
+struct ShadowDefaults
+{
+  std::string properties;
+  // TODO: complete with shadow parameters.
+};
+
+struct EmbossDefaults
+{
+  std::string properties;
+  // TODO: complete with emboss parameters.
+};
+
+struct OutlineDefaults
+{
+  std::string properties;
+  // TODO: complete with outline parameters.
+};
+
+struct Controller::Impl
+{
+  Impl( ControlInterface* controlInterface,
+        EditableControlInterface* editableControlInterface )
+  : mControlInterface( controlInterface ),
+    mEditableControlInterface( editableControlInterface ),
+    mModel(),
+    mFontDefaults( NULL ),
+    mUnderlineDefaults( NULL ),
+    mShadowDefaults( NULL ),
+    mEmbossDefaults( NULL ),
+    mOutlineDefaults( NULL ),
+    mEventData( NULL ),
+    mFontClient(),
+    mClipboard(),
+    mView(),
+    mMetrics(),
+    mModifyEvents(),
+    mTextColor( Color::BLACK ),
+    mTextUpdateInfo(),
+    mOperationsPending( NO_OPERATION ),
+    mMaximumNumberOfCharacters( 50u ),
+    mHiddenInput( NULL ),
+    mRecalculateNaturalSize( true ),
+    mMarkupProcessorEnabled( false ),
+    mClipboardHideEnabled( true ),
+    mIsAutoScrollEnabled( false ),
+    mUpdateTextDirection( true ),
+    mIsTextDirectionRTL( false ),
+    mUnderlineSetByString( false ),
+    mShadowSetByString( false ),
+    mOutlineSetByString( false ),
+    mFontStyleSetByString( false ),
+    mShouldClearFocusOnEscape( true ),
+    mLayoutDirection( LayoutDirection::LEFT_TO_RIGHT ),
+    mTextFitMinSize( DEFAULT_TEXTFIT_MIN ),
+    mTextFitMaxSize( DEFAULT_TEXTFIT_MAX ),
+    mTextFitStepSize( DEFAULT_TEXTFIT_STEP ),
+    mTextFitEnabled( false )
+  {
+    mModel = Model::New();
+
+    mFontClient = TextAbstraction::FontClient::Get();
+    mClipboard = Clipboard::Get();
+
+    mView.SetVisualModel( mModel->mVisualModel );
+
+    // Use this to access FontClient i.e. to get down-scaled Emoji metrics.
+    mMetrics = Metrics::New( mFontClient );
+    mLayoutEngine.SetMetrics( mMetrics );
+
+    // Set the text properties to default
+    mModel->mVisualModel->SetUnderlineEnabled( false );
+    mModel->mVisualModel->SetUnderlineHeight( 0.0f );
+
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      bool temp;
+      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
+      if( config["clearFocusOnEscape"].Get( temp ) )
+      {
+        mShouldClearFocusOnEscape = temp;
+      }
+    }
+  }
+
+  ~Impl()
+  {
+    delete mHiddenInput;
+
+    delete mFontDefaults;
+    delete mUnderlineDefaults;
+    delete mShadowDefaults;
+    delete mEmbossDefaults;
+    delete mOutlineDefaults;
+    delete mEventData;
+  }
+
+  // Text Controller Implementation.
+
+  /**
+   * @copydoc Text::Controller::RequestRelayout()
+   */
+  void RequestRelayout();
+
+  /**
+   * @brief Request a relayout using the ControlInterface.
+   */
+  void QueueModifyEvent( ModifyEvent::Type type )
+  {
+    if( ModifyEvent::TEXT_REPLACED == type)
+    {
+      // Cancel previously queued inserts etc.
+      mModifyEvents.Clear();
+    }
+
+    ModifyEvent event;
+    event.type = type;
+    mModifyEvents.PushBack( event );
+
+    // The event will be processed during relayout
+    RequestRelayout();
+  }
+
+  /**
+   * @brief Helper to move the cursor, grab handle etc.
+   */
+  bool ProcessInputEvents();
+
+  /**
+   * @brief Helper to check whether any place-holder text is available.
+   */
+  bool IsPlaceholderAvailable() const
+  {
+    return ( mEventData &&
+             ( !mEventData->mPlaceholderTextInactive.empty() ||
+               !mEventData->mPlaceholderTextActive.empty() )
+           );
+  }
+
+  bool IsShowingPlaceholderText() const
+  {
+    return ( mEventData && mEventData->mIsShowingPlaceholderText );
+  }
+
+  /**
+   * @brief Helper to check whether active place-holder text is available.
+   */
+  bool IsFocusedPlaceholderAvailable() const
+  {
+    return ( mEventData && !mEventData->mPlaceholderTextActive.empty() );
+  }
+
+  bool IsShowingRealText() const
+  {
+    return ( !IsShowingPlaceholderText() &&
+             0u != mModel->mLogicalModel->mText.Count() );
+  }
+
+  /**
+   * @brief Called when placeholder-text is hidden
+   */
+  void PlaceholderCleared()
+  {
+    if( mEventData )
+    {
+      mEventData->mIsShowingPlaceholderText = false;
+
+      // Remove mPlaceholderTextColor
+      mModel->mVisualModel->SetTextColor( mTextColor );
+    }
+  }
+
+  void ClearPreEditFlag()
+  {
+    if( mEventData )
+    {
+      mEventData->mPreEditFlag = false;
+      mEventData->mPreEditStartPosition = 0;
+      mEventData->mPreEditLength = 0;
+    }
+  }
+
+  void ResetInputMethodContext()
+  {
+    if( mEventData )
+    {
+      // Reset incase we are in a pre-edit state.
+      if( mEventData->mInputMethodContext )
+      {
+        mEventData->mInputMethodContext.Reset(); // Will trigger a message ( commit, get surrounding )
+      }
+
+      ClearPreEditFlag();
+    }
+  }
+
+  /**
+   * @brief Helper to notify InputMethodContext with surrounding text & cursor changes.
+   */
+  void NotifyInputMethodContext();
+
+  /**
+   * @brief Helper to notify InputMethodContext with multi line status.
+   */
+  void NotifyInputMethodContextMultiLineStatus();
+
+  /**
+   * @brief Retrieve the current cursor position.
+   *
+   * @return The cursor position.
+   */
+  CharacterIndex GetLogicalCursorPosition() const;
+
+  /**
+   * @brief Retrieves the number of consecutive white spaces starting from the given @p index.
+   *
+   * @param[in] index The character index from where to count the number of consecutive white spaces.
+   *
+   * @return The number of consecutive white spaces.
+   */
+  Length GetNumberOfWhiteSpaces( CharacterIndex index ) const;
+
+  /**
+   * @brief Retrieve any text previously set starting from the given @p index.
+   *
+   * @param[in] index The character index from where to retrieve the text.
+   * @param[out] text A string of UTF-8 characters.
+   *
+   * @see Dali::Toolkit::Text::Controller::GetText()
+   */
+  void GetText( CharacterIndex index, std::string& text ) const;
+
+  bool IsClipboardEmpty()
+  {
+    bool result( mClipboard && mClipboard.NumberOfItems() );
+    return !result; // If NumberOfItems greater than 0, return false
+  }
+
+  bool IsClipboardVisible()
+  {
+    bool result( mClipboard && mClipboard.IsVisible() );
+    return result;
+  }
+
+  /**
+   * @brief Calculates the start character index of the first paragraph to be updated and
+   * the end character index of the last paragraph to be updated.
+   *
+   * @param[out] numberOfCharacters The number of characters to be updated.
+   */
+  void CalculateTextUpdateIndices( Length& numberOfCharacters );
+
+  /**
+   * @brief Helper to clear completely the parts of the model specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   */
+  void ClearFullModelData( OperationsMask operations );
+
+  /**
+   * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
+   * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations.
+   *
+   * @note It never clears the text stored in utf32.
+   * @note Character indices are transformed to glyph indices.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
+   * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
+   *
+   * @note It never clears the text stored in utf32.
+   *
+   * @param[in] startIndex Index to the first character to be cleared.
+   * @param[in] endIndex Index to the last character to be cleared.
+   * @param[in] operations The operations required.
+   */
+  void ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
+
+  /**
+   * @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
+   * with a given @p operationsRequired parameter. The operations required are
+   * matched with the operations pending to perform the minimum number of operations.
+   *
+   * @param[in] operationsRequired The operations required.
+   *
+   * @return @e true if the model has been modified.
+   */
+  bool UpdateModel( OperationsMask operationsRequired );
+
+  /**
+   * @brief Retreieves the default style.
+   *
+   * @param[out] inputStyle The default style.
+   */
+  void RetrieveDefaultInputStyle( InputStyle& inputStyle );
+
+  /**
+   * @brief Retrieve the line height of the default font.
+   */
+  float GetDefaultFontLineHeight();
+
+  void OnCursorKeyEvent( const Event& event );
+
+  void OnTapEvent( const Event& event );
+
+  void OnPanEvent( const Event& event );
+
+  void OnLongPressEvent( const Event& event );
+
+  void OnHandleEvent( const Event& event );
+
+  void OnSelectEvent( const Event& event );
+
+  void OnSelectAllEvent();
+
+  /**
+   * @brief Retrieves the selected text. It removes the text if the @p deleteAfterRetrieval parameter is @e true.
+   *
+   * @param[out] selectedText The selected text encoded in utf8.
+   * @param[in] deleteAfterRetrieval Whether the text should be deleted after retrieval.
+   */
+  void RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval );
+
+  void ShowClipboard();
+
+  void HideClipboard();
+
+  void SetClipboardHideEnable(bool enable);
+
+  bool CopyStringToClipboard( std::string& source );
+
+  void SendSelectionToClipboard( bool deleteAfterSending );
+
+  void RequestGetTextFromClipboard();
+
+  void RepositionSelectionHandles();
+  void RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action );
+
+  void SetPopupButtons();
+
+  void ChangeState( EventData::State newState );
+
+  /**
+   * @brief Calculates the cursor's position for a given character index in the logical order.
+   *
+   * It retrieves as well the line's height and the cursor's height and
+   * if there is a valid alternative cursor, its position and height.
+   *
+   * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+   * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
+   */
+  void GetCursorPosition( CharacterIndex logical,
+                          CursorInfo& cursorInfo );
+
+  /**
+   * @brief Calculates the new cursor index.
+   *
+   * It takes into account that in some scripts multiple characters can form a glyph and all of them
+   * need to be jumped with one key event.
+   *
+   * @param[in] index The initial new index.
+   *
+   * @return The new cursor index.
+   */
+  CharacterIndex CalculateNewCursorIndex( CharacterIndex index ) const;
+
+  /**
+   * @brief Updates the cursor position.
+   *
+   * Sets the cursor's position into the decorator. It transforms the cursor's position into decorator's coords.
+   * It sets the position of the secondary cursor if it's a valid one.
+   * Sets which cursors are active.
+   *
+   * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+   *
+   */
+  void UpdateCursorPosition( const CursorInfo& cursorInfo );
+
+  /**
+   * @brief Updates the position of the given selection handle. It transforms the handle's position into decorator's coords.
+   *
+   * @param[in] handleType One of the selection handles.
+   * @param[in] cursorInfo Contains the selection handle position in Actor's coords.
+   */
+  void UpdateSelectionHandle( HandleType handleType,
+                              const CursorInfo& cursorInfo );
+
+  /**
+   * @biref Clamps the horizontal scrolling to get the control always filled with text.
+   *
+   * @param[in] layoutSize The size of the laid out text.
+   */
+  void ClampHorizontalScroll( const Vector2& layoutSize );
+
+  /**
+   * @biref Clamps the vertical scrolling to get the control always filled with text.
+   *
+   * @param[in] layoutSize The size of the laid out text.
+   */
+  void ClampVerticalScroll( const Vector2& layoutSize );
+
+  /**
+   * @brief Scrolls the text to make a position visible.
+   *
+   * @pre mEventData must not be NULL. (there is a text-input or selection capabilities).
+   *
+   * @param[in] position A position in text coords.
+   * @param[in] lineHeight The line height for the given position.
+   *
+   * This method is called after inserting text, moving the cursor with the grab handle or the keypad,
+   * or moving the selection handles.
+   */
+  void ScrollToMakePositionVisible( const Vector2& position, float lineHeight );
+
+  /**
+   * @brief Scrolls the text to make the cursor visible.
+   *
+   * This method is called after deleting text.
+   */
+  void ScrollTextToMatchCursor( const CursorInfo& cursorInfo );
+
+  /**
+   * @brief Create an actor that renders the text background color
+   *
+   * @return the created actor or an empty handle if no background color needs to be rendered.
+   */
+  Actor CreateBackgroundActor();
+
+public:
+
+  /**
+   * @brief Gets implementation from the controller handle.
+   * @param controller The text controller
+   * @return The implementation of the Controller
+   */
+  static Impl& GetImplementation( Text::Controller& controller )
+  {
+    return *controller.mImpl;
+  }
+
+private:
+  // Declared private and left undefined to avoid copies.
+  Impl( const Impl& );
+  // Declared private and left undefined to avoid copies.
+  Impl& operator=( const Impl& );
+
+public:
+
+  ControlInterface* mControlInterface;     ///< Reference to the text controller.
+  EditableControlInterface* mEditableControlInterface; ///< Reference to the editable text controller.
+  ModelPtr mModel;                         ///< Pointer to the text's model.
+  FontDefaults* mFontDefaults;             ///< Avoid allocating this when the user does not specify a font.
+  UnderlineDefaults* mUnderlineDefaults;   ///< Avoid allocating this when the user does not specify underline parameters.
+  ShadowDefaults* mShadowDefaults;         ///< Avoid allocating this when the user does not specify shadow parameters.
+  EmbossDefaults* mEmbossDefaults;         ///< Avoid allocating this when the user does not specify emboss parameters.
+  OutlineDefaults* mOutlineDefaults;       ///< Avoid allocating this when the user does not specify outline parameters.
+  EventData* mEventData;                   ///< Avoid allocating everything for text input until EnableTextInput().
+  TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
+  Clipboard mClipboard;                    ///< Handle to the system clipboard
+  View mView;                              ///< The view interface to the rendering back-end.
+  MetricsPtr mMetrics;                     ///< A wrapper around FontClient used to get metrics & potentially down-scaled Emoji metrics.
+  Layout::Engine mLayoutEngine;            ///< The layout engine.
+  Vector<ModifyEvent> mModifyEvents;       ///< Temporary stores the text set until the next relayout.
+  Vector4 mTextColor;                      ///< The regular text color
+  TextUpdateInfo mTextUpdateInfo;          ///< Info of the characters updated.
+  OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
+  Length mMaximumNumberOfCharacters;       ///< Maximum number of characters that can be inserted.
+  HiddenText* mHiddenInput;                ///< Avoid allocating this when the user does not specify hidden input mode.
+  Vector2 mTextFitContentSize;             ///< Size of Text fit content
+
+  bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
+  bool mMarkupProcessorEnabled:1;          ///< Whether the mark-up procesor is enabled.
+  bool mClipboardHideEnabled:1;            ///< Whether the ClipboardHide function work or not
+  bool mIsAutoScrollEnabled:1;             ///< Whether auto text scrolling is enabled.
+  bool mUpdateTextDirection:1;             ///< Whether the text direction needs to be updated.
+  CharacterDirection mIsTextDirectionRTL:1;  ///< Whether the text direction is right to left or not
+
+  bool mUnderlineSetByString:1;            ///< Set when underline is set by string (legacy) instead of map
+  bool mShadowSetByString:1;               ///< Set when shadow is set by string (legacy) instead of map
+  bool mOutlineSetByString:1;              ///< Set when outline is set by string (legacy) instead of map
+  bool mFontStyleSetByString:1;            ///< Set when font style is set by string (legacy) instead of map
+  bool mShouldClearFocusOnEscape:1;        ///< Whether text control should clear key input focus
+  LayoutDirection::Type mLayoutDirection;  ///< Current system language direction
+
+  Shader mShaderBackground;                ///< The shader for text background.
+
+  float mTextFitMinSize;                   ///< Minimum Font Size for text fit. Default 10
+  float mTextFitMaxSize;                   ///< Maximum Font Size for text fit. Default 100
+  float mTextFitStepSize;                  ///< Step Size for font intervalse. Default 1
+  bool  mTextFitEnabled : 1;               ///< Whether the text's fit is enabled.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp
new file mode 100755 (executable)
index 0000000..0407147
--- /dev/null
@@ -0,0 +1,4342 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/text-controller.h>
+
+// EXTERNAL INCLUDES
+#include <limits>
+#include <cmath>
+#include <memory.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
+#include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/markup-processor.h>
+#include <dali-toolkit/internal/text/multi-language-support.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+
+const std::string EMPTY_STRING("");
+
+const std::string KEY_C_NAME = "c";
+const std::string KEY_V_NAME = "v";
+const std::string KEY_X_NAME = "x";
+
+const char * const PLACEHOLDER_TEXT = "text";
+const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
+const char * const PLACEHOLDER_COLOR = "color";
+const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily";
+const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
+const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
+const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
+const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
+const unsigned int MAX_TEXT_LENGTH = 1024u * 32u;
+
+float ConvertToEven( float value )
+{
+  int intValue(static_cast<int>( value ));
+  return static_cast<float>( intValue + ( intValue & 1 ) );
+}
+
+int ConvertPixelToPint( float pixel )
+{
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+  return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Adds a new font description run for the selected text.
+ *
+ * The new font parameters are added after the call to this method.
+ *
+ * @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,
+                                                 CharacterIndex& startOfSelectedText,
+                                                 Length& lengthOfSelectedText )
+{
+  const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
+
+  // Get start and end position of selection
+  startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
+  lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
+
+  // Add the font run.
+  const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
+  logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
+
+  FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
+
+  fontDescriptionRun.characterRun.characterIndex = startOfSelectedText;
+  fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+  // Recalculate the selection highlight as the metrics may have changed.
+  eventData->mUpdateLeftSelectionPosition = true;
+  eventData->mUpdateRightSelectionPosition = true;
+  eventData->mUpdateHighlightBox = true;
+
+  return fontDescriptionRun;
+}
+
+// public : Constructor.
+
+ControllerPtr Controller::New()
+{
+  return ControllerPtr( new Controller() );
+}
+
+ControllerPtr Controller::New( ControlInterface* controlInterface )
+{
+  return ControllerPtr( new Controller( controlInterface ) );
+}
+
+ControllerPtr Controller::New( ControlInterface* controlInterface,
+                               EditableControlInterface* editableControlInterface )
+{
+  return ControllerPtr( new Controller( controlInterface,
+                                        editableControlInterface ) );
+}
+
+// public : Configure the text controller.
+
+void Controller::EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
+{
+  if( !decorator )
+  {
+    delete mImpl->mEventData;
+    mImpl->mEventData = NULL;
+
+    // Nothing else to do.
+    return;
+  }
+
+  if( NULL == mImpl->mEventData )
+  {
+    mImpl->mEventData = new EventData( decorator, inputMethodContext );
+  }
+}
+
+void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
+{
+  // Metrics for bitmap & vector based glyphs are different
+  mImpl->mMetrics->SetGlyphType( glyphType );
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+void Controller::SetMarkupProcessorEnabled( bool enable )
+{
+  if( enable != mImpl->mMarkupProcessorEnabled )
+  {
+    //If Text was already set, call the SetText again for enabling or disabling markup
+    mImpl->mMarkupProcessorEnabled = enable;
+    std::string text;
+    GetText( text );
+    SetText( text );
+  }
+}
+
+bool Controller::IsMarkupProcessorEnabled() const
+{
+  return mImpl->mMarkupProcessorEnabled;
+}
+
+void Controller::SetAutoScrollEnabled( bool enable )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)?"true":"false", this );
+
+  if( mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX )
+  {
+    if( enable )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               LAYOUT                    |
+                                                               ALIGN                     |
+                                                               UPDATE_LAYOUT_SIZE        |
+                                                               UPDATE_DIRECTION          |
+                                                               REORDER );
+
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               LAYOUT                    |
+                                                               ALIGN                     |
+                                                               UPDATE_LAYOUT_SIZE        |
+                                                               REORDER );
+    }
+
+    mImpl->mIsAutoScrollEnabled = enable;
+    mImpl->RequestRelayout();
+  }
+  else
+  {
+    DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n" );
+    mImpl->mIsAutoScrollEnabled = false;
+  }
+}
+
+bool Controller::IsAutoScrollEnabled() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled?"true":"false" );
+
+  return mImpl->mIsAutoScrollEnabled;
+}
+
+CharacterDirection Controller::GetAutoScrollDirection() const
+{
+  return mImpl->mIsTextDirectionRTL;
+}
+
+float Controller::GetAutoScrollLineAlignment() const
+{
+  float offset = 0.f;
+
+  if( mImpl->mModel->mVisualModel &&
+      ( 0u != mImpl->mModel->mVisualModel->mLines.Count() ) )
+  {
+    offset = ( *mImpl->mModel->mVisualModel->mLines.Begin() ).alignmentOffset;
+  }
+
+  return offset;
+}
+
+void Controller::SetHorizontalScrollEnabled( bool enable )
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled( enable );
+  }
+}
+bool Controller::IsHorizontalScrollEnabled() const
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
+  }
+
+  return false;
+}
+
+void Controller::SetVerticalScrollEnabled( bool enable )
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    if( mImpl->mEventData->mDecorator )
+    {
+      mImpl->mEventData->mDecorator->SetVerticalScrollEnabled( enable );
+    }
+  }
+}
+
+bool Controller::IsVerticalScrollEnabled() const
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
+  }
+
+  return false;
+}
+
+void Controller::SetSmoothHandlePanEnabled( bool enable )
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled( enable );
+  }
+}
+
+bool Controller::IsSmoothHandlePanEnabled() const
+{
+  if( ( NULL != mImpl->mEventData ) &&
+      mImpl->mEventData->mDecorator )
+  {
+    return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
+  }
+
+  return false;
+}
+
+void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
+{
+  mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH );
+}
+
+int Controller::GetMaximumNumberOfCharacters()
+{
+  return mImpl->mMaximumNumberOfCharacters;
+}
+
+void Controller::SetEnableCursorBlink( bool enable )
+{
+  DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mCursorBlinkEnabled = enable;
+
+    if( !enable &&
+        mImpl->mEventData->mDecorator )
+    {
+      mImpl->mEventData->mDecorator->StopCursorBlink();
+    }
+  }
+}
+
+bool Controller::GetEnableCursorBlink() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mCursorBlinkEnabled;
+  }
+
+  return false;
+}
+
+void Controller::SetMultiLineEnabled( bool enable )
+{
+  const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
+
+  if( layout != mImpl->mLayoutEngine.GetLayout() )
+  {
+    // Set the layout type.
+    mImpl->mLayoutEngine.SetLayout( layout );
+
+    // Set the flags to redo the layout operations
+    const OperationsMask layoutOperations =  static_cast<OperationsMask>( LAYOUT             |
+                                                                          UPDATE_LAYOUT_SIZE |
+                                                                          ALIGN              |
+                                                                          REORDER );
+
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
+
+    // Need to recalculate natural size
+    mImpl->mRecalculateNaturalSize = true;
+
+    mImpl->RequestRelayout();
+  }
+}
+
+bool Controller::IsMultiLineEnabled() const
+{
+  return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
+}
+
+void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignment )
+{
+  if( alignment != mImpl->mModel->mHorizontalAlignment )
+  {
+    // Set the alignment.
+    mImpl->mModel->mHorizontalAlignment = alignment;
+
+    // Set the flag to redo the alignment operation.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
+
+    if( mImpl->mEventData )
+    {
+      mImpl->mEventData->mUpdateAlignment = true;
+
+      // Update the cursor if it's in editing mode
+      if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+      {
+        mImpl->ChangeState( EventData::EDITING );
+        mImpl->mEventData->mUpdateCursorPosition = true;
+      }
+    }
+
+    mImpl->RequestRelayout();
+  }
+}
+
+Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
+{
+  return mImpl->mModel->mHorizontalAlignment;
+}
+
+void Controller::SetVerticalAlignment( VerticalAlignment::Type alignment )
+{
+  if( alignment != mImpl->mModel->mVerticalAlignment )
+  {
+    // Set the alignment.
+    mImpl->mModel->mVerticalAlignment = alignment;
+
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
+
+    mImpl->RequestRelayout();
+  }
+}
+
+VerticalAlignment::Type Controller::GetVerticalAlignment() const
+{
+  return mImpl->mModel->mVerticalAlignment;
+}
+
+bool Controller::IsIgnoreSpacesAfterText() const
+{
+  return mImpl->mModel->mIgnoreSpacesAfterText;
+}
+
+void Controller::SetIgnoreSpacesAfterText( bool ignore )
+{
+  mImpl->mModel->mIgnoreSpacesAfterText = ignore;
+}
+
+bool Controller::IsMatchSystemLanguageDirection() const
+{
+  return mImpl->mModel->mMatchSystemLanguageDirection;
+}
+
+void Controller::SetMatchSystemLanguageDirection( bool match )
+{
+  mImpl->mModel->mMatchSystemLanguageDirection = match;
+}
+
+void Controller::SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection )
+{
+  mImpl->mLayoutDirection = layoutDirection;
+}
+
+bool Controller::IsShowingRealText() const
+{
+  return mImpl->IsShowingRealText();
+}
+
+
+void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
+{
+  if( lineWrapMode != mImpl->mModel->mLineWrapMode )
+  {
+    // Set the text wrap mode.
+    mImpl->mModel->mLineWrapMode = lineWrapMode;
+
+
+    // Update Text layout for applying wrap mode
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             ALIGN                     |
+                                                             LAYOUT                    |
+                                                             UPDATE_LAYOUT_SIZE        |
+                                                             REORDER                   );
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // Request relayout
+    mImpl->RequestRelayout();
+  }
+}
+
+Text::LineWrap::Mode Controller::GetLineWrapMode() const
+{
+  return mImpl->mModel->mLineWrapMode;
+}
+
+void Controller::SetTextElideEnabled( bool enabled )
+{
+  mImpl->mModel->mElideEnabled = enabled;
+}
+
+bool Controller::IsTextElideEnabled() const
+{
+  return mImpl->mModel->mElideEnabled;
+}
+
+void Controller::SetTextFitEnabled(bool enabled)
+{
+  mImpl->mTextFitEnabled = enabled;
+}
+
+bool Controller::IsTextFitEnabled() const
+{
+  return mImpl->mTextFitEnabled;
+}
+
+void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMinSize = minSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMinSize() const
+{
+  return mImpl->mTextFitMinSize;
+}
+
+void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMaxSize = maxSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMaxSize() const
+{
+  return mImpl->mTextFitMaxSize;
+}
+
+void Controller::SetTextFitStepSize( float step, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitStepSize = step;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitStepSize = ConvertPixelToPint( step );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitStepSize() const
+{
+  return mImpl->mTextFitStepSize;
+}
+
+void Controller::SetTextFitContentSize(Vector2 size)
+{
+  mImpl->mTextFitContentSize = size;
+}
+
+Vector2 Controller::GetTextFitContentSize() const
+{
+  return mImpl->mTextFitContentSize;
+}
+
+void Controller::SetPlaceholderTextElideEnabled( bool enabled )
+{
+  mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
+  mImpl->mEventData->mPlaceholderEllipsisFlag = true;
+
+  // Update placeholder if there is no text
+  if( mImpl->IsShowingPlaceholderText() ||
+      ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
+  {
+    ShowPlaceholderText();
+  }
+}
+
+bool Controller::IsPlaceholderTextElideEnabled() const
+{
+  return mImpl->mEventData->mIsPlaceholderElideEnabled;
+}
+
+void Controller::SetSelectionEnabled( bool enabled )
+{
+  mImpl->mEventData->mSelectionEnabled = enabled;
+}
+
+bool Controller::IsSelectionEnabled() const
+{
+  return mImpl->mEventData->mSelectionEnabled;
+}
+
+void Controller::SetShiftSelectionEnabled( bool enabled )
+{
+  mImpl->mEventData->mShiftSelectionFlag = enabled;
+}
+
+bool Controller::IsShiftSelectionEnabled() const
+{
+  return mImpl->mEventData->mShiftSelectionFlag;
+}
+
+void Controller::SetGrabHandleEnabled( bool enabled )
+{
+  mImpl->mEventData->mGrabHandleEnabled = enabled;
+}
+
+bool Controller::IsGrabHandleEnabled() const
+{
+  return mImpl->mEventData->mGrabHandleEnabled;
+}
+
+void Controller::SetGrabHandlePopupEnabled(bool enabled)
+{
+  mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
+}
+
+bool Controller::IsGrabHandlePopupEnabled() const
+{
+  return mImpl->mEventData->mGrabHandlePopupEnabled;
+}
+
+// public : Update
+
+void Controller::SetText( const std::string& text )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
+
+  // Reset keyboard as text changed
+  mImpl->ResetInputMethodContext();
+
+  // Remove the previously set text and style.
+  ResetText();
+
+  // Remove the style.
+  ClearStyleData();
+
+  CharacterIndex lastCursorIndex = 0u;
+
+  if( NULL != mImpl->mEventData )
+  {
+    // If popup shown then hide it by switching to Editing state
+    if( ( EventData::SELECTING == mImpl->mEventData->mState )          ||
+        ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
+        ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) ||
+        ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
+    {
+      mImpl->ChangeState( EventData::EDITING );
+    }
+  }
+
+  if( !text.empty() )
+  {
+    mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
+
+    MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
+                                         mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
+                                         mImpl->mModel->mLogicalModel->mEmbeddedItems );
+
+    Length textSize = 0u;
+    const uint8_t* utf8 = NULL;
+    if( mImpl->mMarkupProcessorEnabled )
+    {
+      ProcessMarkupString( text, markupProcessData );
+      textSize = markupProcessData.markupProcessedText.size();
+
+      // This is a bit horrible but std::string returns a (signed) char*
+      utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
+    }
+    else
+    {
+      textSize = text.size();
+
+      // This is a bit horrible but std::string returns a (signed) char*
+      utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+    }
+
+    // Limit the text size. If the text size is too large, crash or deadlock will occur.
+    if( textSize > MAX_TEXT_LENGTH )
+    {
+      DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize );
+      textSize = MAX_TEXT_LENGTH;
+    }
+
+    //  Convert text into UTF-32
+    Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
+    utf32Characters.Resize( textSize );
+
+    // Transform a text array encoded in utf8 into an array encoded in utf32.
+    // It returns the actual number of characters.
+    Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
+    utf32Characters.Resize( characterCount );
+
+    DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() );
+
+    // The characters to be added.
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // To reset the cursor position
+    lastCursorIndex = characterCount;
+
+    // Update the rest of the model during size negotiation
+    mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
+
+    // The natural size needs to be re-calculated.
+    mImpl->mRecalculateNaturalSize = true;
+
+    // The text direction needs to be updated.
+    mImpl->mUpdateTextDirection = true;
+
+    // Apply modifications to the model
+    mImpl->mOperationsPending = ALL_OPERATIONS;
+  }
+  else
+  {
+    ShowPlaceholderText();
+  }
+
+  // Resets the cursor position.
+  ResetCursorPosition( lastCursorIndex );
+
+  // Scrolls the text to make the cursor visible.
+  ResetScrollPosition();
+
+  mImpl->RequestRelayout();
+
+  if( NULL != mImpl->mEventData )
+  {
+    // Cancel previously queued events
+    mImpl->mEventData->mEventQueue.clear();
+  }
+
+  // Do this last since it provides callbacks into application code.
+  if( NULL != mImpl->mEditableControlInterface )
+  {
+    mImpl->mEditableControlInterface->TextChanged();
+  }
+}
+
+void Controller::GetText( std::string& text ) const
+{
+  if( !mImpl->IsShowingPlaceholderText() )
+  {
+    // Retrieves the text string.
+    mImpl->GetText( 0u, text );
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this );
+  }
+}
+
+void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( PLACEHOLDER_TYPE_INACTIVE == type )
+    {
+      mImpl->mEventData->mPlaceholderTextInactive = text;
+    }
+    else
+    {
+      mImpl->mEventData->mPlaceholderTextActive = text;
+    }
+
+    // Update placeholder if there is no text
+    if( mImpl->IsShowingPlaceholderText() ||
+        ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) )
+    {
+      ShowPlaceholderText();
+    }
+  }
+}
+
+void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( PLACEHOLDER_TYPE_INACTIVE == type )
+    {
+      text = mImpl->mEventData->mPlaceholderTextInactive;
+    }
+    else
+    {
+      text = mImpl->mEventData->mPlaceholderTextActive;
+    }
+  }
+}
+
+void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
+
+  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() );
+    mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
+
+    ClearFontData();
+
+    mImpl->RequestRelayout();
+  }
+}
+
+// public : Default style & Input style
+
+void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
+{
+  if( NULL == mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults = new FontDefaults();
+  }
+
+  mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
+  mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+const std::string& Controller::GetDefaultFontFamily() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->mFontDescription.family;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( NULL == mImpl->mEventData->mPlaceholderFont )
+    {
+      mImpl->mEventData->mPlaceholderFont = new FontDefaults();
+    }
+
+    mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
+    DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
+    mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
+
+    mImpl->RequestRelayout();
+  }
+}
+
+const std::string& Controller::GetPlaceholderFontFamily() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetDefaultFontWeight( FontWeight weight )
+{
+  if( NULL == mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults = new FontDefaults();
+  }
+
+  mImpl->mFontDefaults->mFontDescription.weight = weight;
+  mImpl->mFontDefaults->weightDefined = true;
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontWeightDefined() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->weightDefined;
+  }
+
+  return false;
+}
+
+FontWeight Controller::GetDefaultFontWeight() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->mFontDescription.weight;
+  }
+
+  return TextAbstraction::FontWeight::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontWeight( FontWeight weight )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( NULL == mImpl->mEventData->mPlaceholderFont )
+    {
+      mImpl->mEventData->mPlaceholderFont = new FontDefaults();
+    }
+
+    mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
+    mImpl->mEventData->mPlaceholderFont->weightDefined = true;
+
+    mImpl->RequestRelayout();
+  }
+}
+
+bool Controller::IsPlaceholderTextFontWeightDefined() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->weightDefined;
+  }
+  return false;
+}
+
+FontWeight Controller::GetPlaceholderTextFontWeight() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
+  }
+
+  return TextAbstraction::FontWeight::NORMAL;
+}
+
+void Controller::SetDefaultFontWidth( FontWidth width )
+{
+  if( NULL == mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults = new FontDefaults();
+  }
+
+  mImpl->mFontDefaults->mFontDescription.width = width;
+  mImpl->mFontDefaults->widthDefined = true;
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontWidthDefined() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->widthDefined;
+  }
+
+  return false;
+}
+
+FontWidth Controller::GetDefaultFontWidth() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->mFontDescription.width;
+  }
+
+  return TextAbstraction::FontWidth::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontWidth( FontWidth width )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( NULL == mImpl->mEventData->mPlaceholderFont )
+    {
+      mImpl->mEventData->mPlaceholderFont = new FontDefaults();
+    }
+
+    mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
+    mImpl->mEventData->mPlaceholderFont->widthDefined = true;
+
+    mImpl->RequestRelayout();
+  }
+}
+
+bool Controller::IsPlaceholderTextFontWidthDefined() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->widthDefined;
+  }
+  return false;
+}
+
+FontWidth Controller::GetPlaceholderTextFontWidth() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
+  }
+
+  return TextAbstraction::FontWidth::NORMAL;
+}
+
+void Controller::SetDefaultFontSlant( FontSlant slant )
+{
+  if( NULL == mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults = new FontDefaults();
+  }
+
+  mImpl->mFontDefaults->mFontDescription.slant = slant;
+  mImpl->mFontDefaults->slantDefined = true;
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsDefaultFontSlantDefined() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->slantDefined;
+  }
+  return false;
+}
+
+FontSlant Controller::GetDefaultFontSlant() const
+{
+  if( NULL != mImpl->mFontDefaults )
+  {
+    return mImpl->mFontDefaults->mFontDescription.slant;
+  }
+
+  return TextAbstraction::FontSlant::NORMAL;
+}
+
+void Controller::SetPlaceholderTextFontSlant( FontSlant slant )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( NULL == mImpl->mEventData->mPlaceholderFont )
+    {
+      mImpl->mEventData->mPlaceholderFont = new FontDefaults();
+    }
+
+    mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
+    mImpl->mEventData->mPlaceholderFont->slantDefined = true;
+
+    mImpl->RequestRelayout();
+  }
+}
+
+bool Controller::IsPlaceholderTextFontSlantDefined() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->slantDefined;
+  }
+  return false;
+}
+
+FontSlant Controller::GetPlaceholderTextFontSlant() const
+{
+  if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) )
+  {
+    return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
+  }
+
+  return TextAbstraction::FontSlant::NORMAL;
+}
+
+void Controller::SetDefaultFontSize( float fontSize, FontSizeType type )
+{
+  if( NULL == mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults = new FontDefaults();
+  }
+
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mFontDefaults->mDefaultPointSize = fontSize;
+      mImpl->mFontDefaults->sizeDefined = true;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      // Point size = Pixel size * 72.f / DPI
+      unsigned int horizontalDpi = 0u;
+      unsigned int verticalDpi = 0u;
+      TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+      fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+      mImpl->mFontDefaults->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
+      mImpl->mFontDefaults->sizeDefined = true;
+      break;
+    }
+  }
+
+  // Clear the font-specific data
+  ClearFontData();
+
+  mImpl->RequestRelayout();
+}
+
+float Controller::GetDefaultFontSize( FontSizeType type ) const
+{
+  float value = 0.0f;
+  if( NULL != mImpl->mFontDefaults )
+  {
+    switch( type )
+    {
+      case POINT_SIZE:
+      {
+        value = mImpl->mFontDefaults->mDefaultPointSize;
+        break;
+      }
+      case PIXEL_SIZE:
+      {
+        // Pixel size = Point size * DPI / 72.f
+        unsigned int horizontalDpi = 0u;
+        unsigned int verticalDpi = 0u;
+        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+        fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+        value = mImpl->mFontDefaults->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
+        break;
+      }
+    }
+    return value;
+  }
+
+  return value;
+}
+
+void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( NULL == mImpl->mEventData->mPlaceholderFont )
+    {
+      mImpl->mEventData->mPlaceholderFont = new FontDefaults();
+    }
+
+    switch( type )
+    {
+      case POINT_SIZE:
+      {
+        mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
+        mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
+        mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
+        break;
+      }
+      case PIXEL_SIZE:
+      {
+        // Point size = Pixel size * 72.f / DPI
+        unsigned int horizontalDpi = 0u;
+        unsigned int verticalDpi = 0u;
+        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+        fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+        mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi );
+        mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
+        mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
+        break;
+      }
+    }
+
+    mImpl->RequestRelayout();
+  }
+}
+
+float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const
+{
+  float value = 0.0f;
+  if( NULL != mImpl->mEventData )
+  {
+    switch( type )
+    {
+      case POINT_SIZE:
+      {
+        if( NULL != mImpl->mEventData->mPlaceholderFont )
+        {
+          value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
+        }
+        else
+        {
+          // If the placeholder text font size is not set, then return the default font size.
+          value = GetDefaultFontSize( POINT_SIZE );
+        }
+        break;
+      }
+      case PIXEL_SIZE:
+      {
+        if( NULL != mImpl->mEventData->mPlaceholderFont )
+        {
+          // Pixel size = Point size * DPI / 72.f
+          unsigned int horizontalDpi = 0u;
+          unsigned int verticalDpi = 0u;
+          TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+          fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+          value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
+        }
+        else
+        {
+          // If the placeholder text font size is not set, then return the default font size.
+          value = GetDefaultFontSize( PIXEL_SIZE );
+        }
+        break;
+      }
+    }
+    return value;
+  }
+
+  return value;
+}
+
+void Controller::SetDefaultColor( const Vector4& color )
+{
+  mImpl->mTextColor = color;
+
+  if( !mImpl->IsShowingPlaceholderText() )
+  {
+    mImpl->mModel->mVisualModel->SetTextColor( color );
+
+    mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+
+    mImpl->RequestRelayout();
+  }
+}
+
+const Vector4& Controller::GetDefaultColor() const
+{
+  return mImpl->mTextColor;
+}
+
+void Controller::SetPlaceholderTextColor( const Vector4& textColor )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mPlaceholderTextColor = textColor;
+  }
+
+  if( mImpl->IsShowingPlaceholderText() )
+  {
+    mImpl->mModel->mVisualModel->SetTextColor( textColor );
+    mImpl->RequestRelayout();
+  }
+}
+
+const Vector4& Controller::GetPlaceholderTextColor() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mPlaceholderTextColor;
+  }
+
+  return Color::BLACK;
+}
+
+void Controller::SetShadowOffset( const Vector2& shadowOffset )
+{
+  mImpl->mModel->mVisualModel->SetShadowOffset( shadowOffset );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector2& Controller::GetShadowOffset() const
+{
+  return mImpl->mModel->mVisualModel->GetShadowOffset();
+}
+
+void Controller::SetShadowColor( const Vector4& shadowColor )
+{
+  mImpl->mModel->mVisualModel->SetShadowColor( shadowColor );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetShadowColor() const
+{
+  return mImpl->mModel->mVisualModel->GetShadowColor();
+}
+
+void Controller::SetShadowBlurRadius( const float& shadowBlurRadius )
+{
+  if ( fabsf( GetShadowBlurRadius() - shadowBlurRadius ) > Math::MACHINE_EPSILON_1 )
+  {
+    mImpl->mModel->mVisualModel->SetShadowBlurRadius( shadowBlurRadius );
+
+    mImpl->RequestRelayout();
+  }
+}
+
+const float& Controller::GetShadowBlurRadius() const
+{
+  return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
+}
+
+void Controller::SetUnderlineColor( const Vector4& color )
+{
+  mImpl->mModel->mVisualModel->SetUnderlineColor( color );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetUnderlineColor() const
+{
+  return mImpl->mModel->mVisualModel->GetUnderlineColor();
+}
+
+void Controller::SetUnderlineEnabled( bool enabled )
+{
+  mImpl->mModel->mVisualModel->SetUnderlineEnabled( enabled );
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+  return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
+}
+
+void Controller::SetUnderlineHeight( float height )
+{
+  mImpl->mModel->mVisualModel->SetUnderlineHeight( height );
+
+  mImpl->RequestRelayout();
+}
+
+float Controller::GetUnderlineHeight() const
+{
+  return mImpl->mModel->mVisualModel->GetUnderlineHeight();
+}
+
+void Controller::SetOutlineColor( const Vector4& color )
+{
+  mImpl->mModel->mVisualModel->SetOutlineColor( color );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetOutlineColor() const
+{
+  return mImpl->mModel->mVisualModel->GetOutlineColor();
+}
+
+void Controller::SetOutlineWidth( uint16_t width )
+{
+  mImpl->mModel->mVisualModel->SetOutlineWidth( width );
+
+  mImpl->RequestRelayout();
+}
+
+uint16_t Controller::GetOutlineWidth() const
+{
+  return mImpl->mModel->mVisualModel->GetOutlineWidth();
+}
+
+void Controller::SetBackgroundColor( const Vector4& color )
+{
+  mImpl->mModel->mVisualModel->SetBackgroundColor( color );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetBackgroundColor() const
+{
+  return mImpl->mModel->mVisualModel->GetBackgroundColor();
+}
+
+void Controller::SetBackgroundEnabled( bool enabled )
+{
+  mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled );
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsBackgroundEnabled() const
+{
+  return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
+}
+
+void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
+{
+  if( NULL == mImpl->mEmbossDefaults )
+  {
+    mImpl->mEmbossDefaults = new EmbossDefaults();
+  }
+
+  mImpl->mEmbossDefaults->properties = embossProperties;
+}
+
+const std::string& Controller::GetDefaultEmbossProperties() const
+{
+  if( NULL != mImpl->mEmbossDefaults )
+  {
+    return mImpl->mEmbossDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
+{
+  if( NULL == mImpl->mOutlineDefaults )
+  {
+    mImpl->mOutlineDefaults = new OutlineDefaults();
+  }
+
+  mImpl->mOutlineDefaults->properties = outlineProperties;
+}
+
+const std::string& Controller::GetDefaultOutlineProperties() const
+{
+  if( NULL != mImpl->mOutlineDefaults )
+  {
+    return mImpl->mOutlineDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
+bool Controller::SetDefaultLineSpacing( float lineSpacing )
+{
+  if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
+  {
+    mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
+    mImpl->mRecalculateNaturalSize = true;
+    return true;
+  }
+  return false;
+}
+
+float Controller::GetDefaultLineSpacing() const
+{
+  return mImpl->mLayoutEngine.GetDefaultLineSpacing();
+}
+
+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 || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
+
+      // Get start and end position of selection
+      const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
+      const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
+
+      // Add the color run.
+      const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
+      mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
+
+      ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
+      colorRun.color = color;
+      colorRun.characterRun.characterIndex = startOfSelectedText;
+      colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+      // 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;
+    }
+  }
+}
+
+const Vector4& Controller::GetInputColor() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.textColor;
+  }
+
+  // Return the default text's color if there is no EventData.
+  return mImpl->mTextColor;
+
+}
+
+void Controller::SetInputFontFamily( const std::string& fontFamily )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.familyName = fontFamily;
+    mImpl->mEventData->mInputStyle.isFamilyDefined = true;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
+      FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+                                                                            mImpl->mModel->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
+
+      fontDescriptionRun.familyLength = fontFamily.size();
+      fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+      memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+      fontDescriptionRun.familyDefined = true;
+
+      // 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 = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_LAYOUT_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;
+      mImpl->mEventData->mUpdateHighlightBox = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+}
+
+const std::string& Controller::GetInputFontFamily() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.familyName;
+  }
+
+  // Return the default font's family if there is no EventData.
+  return GetDefaultFontFamily();
+}
+
+void Controller::SetInputFontWeight( FontWeight weight )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.weight = weight;
+    mImpl->mEventData->mInputStyle.isWeightDefined = true;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
+      FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+                                                                            mImpl->mModel->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
+
+      fontDescriptionRun.weight = weight;
+      fontDescriptionRun.weightDefined = true;
+
+      // Request to relayout.
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_LAYOUT_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;
+      mImpl->mEventData->mUpdateHighlightBox = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+}
+
+bool Controller::IsInputFontWeightDefined() const
+{
+  bool defined = false;
+
+  if( NULL != mImpl->mEventData )
+  {
+    defined = mImpl->mEventData->mInputStyle.isWeightDefined;
+  }
+
+  return defined;
+}
+
+FontWeight Controller::GetInputFontWeight() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.weight;
+  }
+
+  return GetDefaultFontWeight();
+}
+
+void Controller::SetInputFontWidth( FontWidth width )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.width = width;
+    mImpl->mEventData->mInputStyle.isWidthDefined = true;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
+      FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+                                                                            mImpl->mModel->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
+
+      fontDescriptionRun.width = width;
+      fontDescriptionRun.widthDefined = true;
+
+      // Request to relayout.
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_LAYOUT_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;
+      mImpl->mEventData->mUpdateHighlightBox = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+}
+
+bool Controller::IsInputFontWidthDefined() const
+{
+  bool defined = false;
+
+  if( NULL != mImpl->mEventData )
+  {
+    defined = mImpl->mEventData->mInputStyle.isWidthDefined;
+  }
+
+  return defined;
+}
+
+FontWidth Controller::GetInputFontWidth() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.width;
+  }
+
+  return GetDefaultFontWidth();
+}
+
+void Controller::SetInputFontSlant( FontSlant slant )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.slant = slant;
+    mImpl->mEventData->mInputStyle.isSlantDefined = true;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
+      FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+                                                                            mImpl->mModel->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
+
+      fontDescriptionRun.slant = slant;
+      fontDescriptionRun.slantDefined = true;
+
+      // Request to relayout.
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_LAYOUT_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;
+      mImpl->mEventData->mUpdateHighlightBox = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+}
+
+bool Controller::IsInputFontSlantDefined() const
+{
+  bool defined = false;
+
+  if( NULL != mImpl->mEventData )
+  {
+    defined = mImpl->mEventData->mInputStyle.isSlantDefined;
+  }
+
+  return defined;
+}
+
+FontSlant Controller::GetInputFontSlant() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.slant;
+  }
+
+  return GetDefaultFontSlant();
+}
+
+void Controller::SetInputFontPointSize( float size )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.size = size;
+    mImpl->mEventData->mInputStyle.isSizeDefined = true;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
+      FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+                                                                            mImpl->mModel->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
+
+      fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
+      fontDescriptionRun.sizeDefined = true;
+
+      // Request to relayout.
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_LAYOUT_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;
+      mImpl->mEventData->mUpdateHighlightBox = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+}
+
+float Controller::GetInputFontPointSize() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.size;
+  }
+
+  // Return the default font's point size if there is no EventData.
+  return GetDefaultFontSize( Text::Controller::POINT_SIZE );
+}
+
+void Controller::SetInputLineSpacing( float lineSpacing )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
+    mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
+  }
+}
+
+float Controller::GetInputLineSpacing() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.lineSpacing;
+  }
+
+  return 0.f;
+}
+
+void Controller::SetInputShadowProperties( const std::string& shadowProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
+  }
+}
+
+const std::string& Controller::GetInputShadowProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.shadowProperties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
+  }
+}
+
+const std::string& Controller::GetInputUnderlineProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.underlineProperties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetInputEmbossProperties( const std::string& embossProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
+  }
+}
+
+const std::string& Controller::GetInputEmbossProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.embossProperties;
+  }
+
+  return GetDefaultEmbossProperties();
+}
+
+void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
+  }
+}
+
+const std::string& Controller::GetInputOutlineProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.outlineProperties;
+  }
+
+  return GetDefaultOutlineProperties();
+}
+
+void Controller::SetInputModePassword( bool passwordInput )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mPasswordInput = passwordInput;
+  }
+}
+
+bool Controller::IsInputModePassword()
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mPasswordInput;
+  }
+  return false;
+}
+
+void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mDoubleTapAction = action;
+  }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
+{
+  NoTextTap::Action action = NoTextTap::NO_ACTION;
+
+  if( NULL != mImpl->mEventData )
+  {
+    action = mImpl->mEventData->mDoubleTapAction;
+  }
+
+  return action;
+}
+
+void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mLongPressAction = action;
+  }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
+{
+  NoTextTap::Action action = NoTextTap::NO_ACTION;
+
+  if( NULL != mImpl->mEventData )
+  {
+    action = mImpl->mEventData->mLongPressAction;
+  }
+
+  return action;
+}
+
+bool Controller::IsUnderlineSetByString()
+{
+  return mImpl->mUnderlineSetByString;
+}
+
+void Controller::UnderlineSetByString( bool setByString )
+{
+  mImpl->mUnderlineSetByString = setByString;
+}
+
+bool Controller::IsShadowSetByString()
+{
+  return mImpl->mShadowSetByString;
+}
+
+void Controller::ShadowSetByString( bool setByString )
+{
+  mImpl->mShadowSetByString = setByString;
+}
+
+bool Controller::IsOutlineSetByString()
+{
+  return mImpl->mOutlineSetByString;
+}
+
+void Controller::OutlineSetByString( bool setByString )
+{
+  mImpl->mOutlineSetByString = setByString;
+}
+
+bool Controller::IsFontStyleSetByString()
+{
+  return mImpl->mFontStyleSetByString;
+}
+
+void Controller::FontStyleSetByString( bool setByString )
+{
+  mImpl->mFontStyleSetByString = setByString;
+}
+
+// public : Queries & retrieves.
+
+Layout::Engine& Controller::GetLayoutEngine()
+{
+  return mImpl->mLayoutEngine;
+}
+
+View& Controller::GetView()
+{
+  return mImpl->mView;
+}
+
+Vector3 Controller::GetNaturalSize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
+  Vector3 naturalSize;
+
+  // Make sure the model is up-to-date before layouting
+  ProcessModifyEvents();
+
+  if( mImpl->mRecalculateNaturalSize )
+  {
+    // Operations that can be done only once until the text changes.
+    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
+                                                                           GET_SCRIPTS       |
+                                                                           VALIDATE_FONTS    |
+                                                                           GET_LINE_BREAKS   |
+                                                                           BIDI_INFO         |
+                                                                           SHAPE_TEXT        |
+                                                                           GET_GLYPH_METRICS );
+
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // Make sure the model is up-to-date before layouting
+    mImpl->UpdateModel( onlyOnceOperations );
+
+    // Layout the text for the new width.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT | REORDER );
+
+    // Store the actual control's size to restore later.
+    const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
+
+    DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
+                static_cast<OperationsMask>( onlyOnceOperations |
+                                             LAYOUT | REORDER ),
+                naturalSize.GetVectorXY() );
+
+    // Do not do again the only once operations.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+    // Do the size related operations again.
+    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
+                                                                        ALIGN  |
+                                                                        REORDER );
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+
+    // Stores the natural size to avoid recalculate it again
+    // unless the text/style changes.
+    mImpl->mModel->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
+
+    mImpl->mRecalculateNaturalSize = false;
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+    mImpl->mTextUpdateInfo.mClearAll = true;
+
+    // Restore the actual control's size.
+    mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
+  }
+  else
+  {
+    naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
+  }
+
+  naturalSize.x = ConvertToEven( naturalSize.x );
+  naturalSize.y = ConvertToEven( naturalSize.y );
+
+  return naturalSize;
+}
+
+bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
+{
+  Size textSize;
+  mImpl->mFontDefaults->mFitPointSize = pointSize;
+  mImpl->mFontDefaults->sizeDefined = true;
+  ClearFontData();
+
+  // Operations that can be done only once until the text changes.
+  const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
+                                                                              GET_SCRIPTS |
+                                                                           VALIDATE_FONTS |
+                                                                          GET_LINE_BREAKS |
+                                                                                BIDI_INFO |
+                                                                                SHAPE_TEXT|
+                                                                         GET_GLYPH_METRICS );
+
+  mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+  // Make sure the model is up-to-date before layouting
+  mImpl->UpdateModel( onlyOnceOperations );
+
+  DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
+              static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
+              textSize);
+
+  // Clear the update info. This info will be set the next time the text is updated.
+  mImpl->mTextUpdateInfo.Clear();
+  mImpl->mTextUpdateInfo.mClearAll = true;
+
+  if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
+  {
+    return false;
+  }
+  return true;
+}
+
+void Controller::FitPointSizeforLayout( Size layoutSize )
+{
+  const OperationsMask operations  = mImpl->mOperationsPending;
+  if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize )
+  {
+    bool actualellipsis = mImpl->mModel->mElideEnabled;
+    float minPointSize = mImpl->mTextFitMinSize;
+    float maxPointSize = mImpl->mTextFitMaxSize;
+    float pointInterval = mImpl->mTextFitStepSize;
+
+    mImpl->mModel->mElideEnabled = false;
+    Vector<float> pointSizeArray;
+
+    // check zero value
+    if( pointInterval < 1.f )
+    {
+      mImpl->mTextFitStepSize = pointInterval = 1.0f;
+    }
+
+    pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
+
+    for( float i = minPointSize; i < maxPointSize; i += pointInterval )
+    {
+      pointSizeArray.PushBack( i );
+    }
+
+    pointSizeArray.PushBack( maxPointSize );
+
+    int bestSizeIndex = 0;
+    int min = bestSizeIndex + 1;
+    int max = pointSizeArray.Size() - 1;
+    while( min <= max )
+    {
+      int destI = ( min + max ) / 2;
+
+      if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
+      {
+        bestSizeIndex = min;
+        min = destI + 1;
+      }
+      else
+      {
+        max = destI - 1;
+        bestSizeIndex = max;
+      }
+    }
+
+    mImpl->mModel->mElideEnabled = actualellipsis;
+    mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+    mImpl->mFontDefaults->sizeDefined = true;
+    ClearFontData();
+  }
+}
+
+float Controller::GetHeightForWidth( float width )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
+  // Make sure the model is up-to-date before layouting
+  ProcessModifyEvents();
+
+  Size layoutSize;
+  if( fabsf( width - mImpl->mModel->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 ||
+                                                         mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
+                                                         mImpl->mTextUpdateInfo.mClearAll            )
+  {
+    // Operations that can be done only once until the text changes.
+    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
+                                                                           GET_SCRIPTS       |
+                                                                           VALIDATE_FONTS    |
+                                                                           GET_LINE_BREAKS   |
+                                                                           BIDI_INFO         |
+                                                                           SHAPE_TEXT        |
+                                                                           GET_GLYPH_METRICS );
+
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // Make sure the model is up-to-date before layouting
+    mImpl->UpdateModel( onlyOnceOperations );
+
+
+    // Layout the text for the new width.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+
+    // Store the actual control's width.
+    const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
+
+    DoRelayout( Size( width, MAX_FLOAT ),
+                static_cast<OperationsMask>( onlyOnceOperations |
+                                             LAYOUT ),
+                layoutSize );
+
+    // Do not do again the only once operations.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+    // Do the size related operations again.
+    const OperationsMask sizeOperations =  static_cast<OperationsMask>( LAYOUT |
+                                                                        ALIGN  |
+                                                                        REORDER );
+
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+    mImpl->mTextUpdateInfo.mClearAll = true;
+
+    // Restore the actual control's width.
+    mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
+  }
+  else
+  {
+    layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
+  }
+
+  return layoutSize.height;
+}
+
+int Controller::GetLineCount( float width )
+{
+  GetHeightForWidth( width );
+  int numberofLines = mImpl->mModel->GetNumberOfLines();
+  return numberofLines;
+}
+
+const ModelInterface* const Controller::GetTextModel() const
+{
+  return mImpl->mModel.Get();
+}
+
+float Controller::GetScrollAmountByUserInput()
+{
+  float scrollAmount = 0.0f;
+
+  if (NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
+  {
+    scrollAmount = mImpl->mModel->mScrollPosition.y -  mImpl->mModel->mScrollPositionLast.y;
+    mImpl->mEventData->mCheckScrollAmount = false;
+  }
+  return scrollAmount;
+}
+
+bool Controller::GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight )
+{
+  const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
+  bool isScrolled;
+
+  controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
+  layoutHeight = layout.height;
+  scrollPosition = mImpl->mModel->mScrollPosition.y;
+  isScrolled = !Equals( mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1 );
+  return isScrolled;
+}
+
+void Controller::SetHiddenInputOption(const Property::Map& options )
+{
+  if( NULL == mImpl->mHiddenInput )
+  {
+    mImpl->mHiddenInput = new HiddenText( this );
+  }
+  mImpl->mHiddenInput->SetProperties(options);
+}
+
+void Controller::GetHiddenInputOption(Property::Map& options )
+{
+  if( NULL != mImpl->mHiddenInput )
+  {
+    mImpl->mHiddenInput->GetProperties(options);
+  }
+}
+
+void Controller::SetPlaceholderProperty( const Property::Map& map )
+{
+  const Property::Map::SizeType count = map.Count();
+
+  for( Property::Map::SizeType position = 0; position < count; ++position )
+  {
+    KeyValuePair keyValue = map.GetKeyValue( position );
+    Property::Key& key = keyValue.first;
+    Property::Value& value = keyValue.second;
+
+    if( key == Toolkit::Text::PlaceHolder::Property::TEXT  || key == PLACEHOLDER_TEXT )
+    {
+      std::string text = "";
+      value.Get( text );
+      SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text );
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
+    {
+      std::string text = "";
+      value.Get( text );
+      SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text );
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
+    {
+      Vector4 textColor;
+      value.Get( textColor );
+      if( GetPlaceholderTextColor() != textColor )
+      {
+        SetPlaceholderTextColor( textColor );
+      }
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
+    {
+      std::string fontFamily = "";
+      value.Get( fontFamily );
+      SetPlaceholderFontFamily( fontFamily );
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
+    {
+      SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER );
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
+    {
+      float pointSize;
+      value.Get( pointSize );
+      if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
+      {
+        SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE );
+      }
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
+    {
+      float pixelSize;
+      value.Get( pixelSize );
+      if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) )
+      {
+        SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE );
+      }
+    }
+    else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
+    {
+      bool ellipsis;
+      value.Get( ellipsis );
+      SetPlaceholderTextElideEnabled( ellipsis );
+    }
+  }
+}
+
+void Controller::GetPlaceholderProperty( Property::Map& map )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    if( !mImpl->mEventData->mPlaceholderTextActive.empty() )
+    {
+      map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive;
+    }
+    if( !mImpl->mEventData->mPlaceholderTextInactive.empty() )
+    {
+      map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive;
+    }
+
+    map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor;
+    map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily();
+
+    Property::Value fontStyleMapGet;
+    GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
+    map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
+
+    // Choose font size : POINT_SIZE or PIXEL_SIZE
+    if( !mImpl->mEventData->mIsPlaceholderPixelSize )
+    {
+      map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE );
+    }
+    else
+    {
+      map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE );
+    }
+
+    if( mImpl->mEventData->mPlaceholderEllipsisFlag )
+    {
+      map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled();
+    }
+  }
+}
+
+Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
+{
+  // Make sure the model is up-to-date before layouting
+  ProcessModifyEvents();
+
+  if ( mImpl->mUpdateTextDirection )
+  {
+    // Operations that can be done only once until the text changes.
+    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
+                                                                           GET_SCRIPTS       |
+                                                                           VALIDATE_FONTS    |
+                                                                           GET_LINE_BREAKS   |
+                                                                           BIDI_INFO         |
+                                                                           SHAPE_TEXT        |
+                                                                           GET_GLYPH_METRICS );
+
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // Make sure the model is up-to-date before layouting
+    mImpl->UpdateModel( onlyOnceOperations );
+
+    Vector3 naturalSize;
+    DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
+                static_cast<OperationsMask>( onlyOnceOperations |
+                                             LAYOUT | REORDER | UPDATE_DIRECTION ),
+                naturalSize.GetVectorXY() );
+
+    // Do not do again the only once operations.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
+    // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+
+    mImpl->mUpdateTextDirection = false;
+  }
+
+  return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
+}
+
+Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
+{
+  return mImpl->mModel->GetVerticalLineAlignment();
+}
+
+void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment )
+{
+  mImpl->mModel->mVerticalLineAlignment = alignment;
+}
+
+// public : Relayout.
+
+Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
+
+  UpdateTextType updateTextType = NONE_UPDATED;
+
+  if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
+  {
+    if( 0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count() )
+    {
+      mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
+      updateTextType = MODEL_UPDATED;
+    }
+
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.Clear();
+
+    // Not worth to relayout if width or height is equal to zero.
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
+
+    return updateTextType;
+  }
+
+  // Whether a new size has been set.
+  const bool newSize = ( size != mImpl->mModel->mVisualModel->mControlSize );
+
+  if( newSize )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height );
+
+    if( ( 0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd ) &&
+        ( 0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) &&
+        ( ( mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000 ) || ( mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000 ) ) )
+    {
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
+    }
+
+    // Layout operations that need to be done if the size changes.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             LAYOUT                    |
+                                                             ALIGN                     |
+                                                             UPDATE_LAYOUT_SIZE        |
+                                                             REORDER );
+    // Set the update info to relayout the whole text.
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+
+    // Store the size used to layout the text.
+    mImpl->mModel->mVisualModel->mControlSize = size;
+  }
+
+  // Whether there are modify events.
+  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 );
+  }
+
+  // Set the update info to elide the text.
+  if( mImpl->mModel->mElideEnabled ||
+      ( ( NULL != mImpl->mEventData ) && mImpl->mEventData->mIsPlaceholderElideEnabled ) )
+  {
+    // Update Text layout for applying elided
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             ALIGN                     |
+                                                             LAYOUT                    |
+                                                             UPDATE_LAYOUT_SIZE        |
+                                                             REORDER );
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+  }
+
+  if( mImpl->mModel->mMatchSystemLanguageDirection  && mImpl->mLayoutDirection != layoutDirection )
+  {
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.mClearAll = true;
+    // Apply modifications to the model
+    // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             GET_GLYPH_METRICS         |
+                                                             SHAPE_TEXT                |
+                                                             UPDATE_DIRECTION          |
+                                                             LAYOUT                    |
+                                                             BIDI_INFO                 |
+                                                             REORDER );
+    mImpl->mLayoutDirection = layoutDirection;
+  }
+
+  // Make sure the model is up-to-date before layouting.
+  ProcessModifyEvents();
+  bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
+
+  // Layout the text.
+  Size layoutSize;
+  updated = DoRelayout( size,
+                        mImpl->mOperationsPending,
+                        layoutSize ) || updated;
+
+
+  if( updated )
+  {
+    updateTextType = MODEL_UPDATED;
+  }
+
+  // Do not re-do any operation until something changes.
+  mImpl->mOperationsPending = NO_OPERATION;
+  mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
+
+  // Whether the text control is editable
+  const bool isEditable = NULL != mImpl->mEventData;
+
+  // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
+  Vector2 offset;
+  if( newSize && isEditable )
+  {
+    offset = mImpl->mModel->mScrollPosition;
+  }
+
+  if( !isEditable || !IsMultiLineEnabled() )
+  {
+    // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
+    CalculateVerticalOffset( size );
+  }
+
+  if( isEditable )
+  {
+    if( newSize )
+    {
+      // If there is a new size, the scroll position needs to be clamped.
+      mImpl->ClampHorizontalScroll( layoutSize );
+
+      // Update the decorator's positions is needed if there is a new size.
+      mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mModel->mScrollPosition - offset );
+    }
+
+    // Move the cursor, grab handle etc.
+    if( mImpl->ProcessInputEvents() )
+    {
+      updateTextType = static_cast<UpdateTextType>( updateTextType | DECORATOR_UPDATED );
+    }
+  }
+
+  // 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 updateTextType;
+}
+
+void Controller::RequestRelayout()
+{
+  mImpl->RequestRelayout();
+}
+
+// public : Input style change signals.
+
+bool Controller::IsInputStyleChangedSignalsQueueEmpty()
+{
+  return ( NULL == mImpl->mEventData ) || ( 0u == mImpl->mEventData->mInputStyleChangedQueue.Count() );
+}
+
+void Controller::ProcessInputStyleChangedSignals()
+{
+  if( NULL == mImpl->mEventData )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  for( Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
+         endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
+       it != endIt;
+       ++it )
+  {
+    const InputStyle::Mask mask = *it;
+
+    if( NULL != mImpl->mEditableControlInterface )
+    {
+      // Emit the input style changed signal.
+      mImpl->mEditableControlInterface->InputStyleChanged( mask );
+    }
+  }
+
+  mImpl->mEventData->mInputStyleChangedQueue.Clear();
+}
+
+// public : Text-input Event Queuing.
+
+void Controller::KeyboardFocusGainEvent()
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    if( ( EventData::INACTIVE == mImpl->mEventData->mState ) ||
+        ( EventData::INTERRUPTED == mImpl->mEventData->mState ) )
+    {
+      mImpl->ChangeState( EventData::EDITING );
+      mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
+      mImpl->mEventData->mUpdateInputStyle = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+    mImpl->NotifyInputMethodContextMultiLineStatus();
+    if( mImpl->IsShowingPlaceholderText() )
+    {
+      // Show alternative placeholder-text when editing
+      ShowPlaceholderText();
+    }
+
+    mImpl->RequestRelayout();
+  }
+}
+
+void Controller::KeyboardFocusLostEvent()
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    if( EventData::INTERRUPTED != mImpl->mEventData->mState )
+    {
+      mImpl->ChangeState( EventData::INACTIVE );
+
+      if( !mImpl->IsShowingRealText() )
+      {
+        // Revert to regular placeholder-text when not editing
+        ShowPlaceholderText();
+      }
+    }
+  }
+  mImpl->RequestRelayout();
+}
+
+bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" );
+
+  bool textChanged = false;
+  bool relayoutNeeded = false;
+
+  if( ( NULL != mImpl->mEventData ) &&
+      ( keyEvent.state == KeyEvent::Down ) )
+  {
+    int keyCode = keyEvent.keyCode;
+    const std::string& keyString = keyEvent.keyPressed;
+    const std::string keyName = keyEvent.keyPressedName;
+
+    const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() );
+
+    // Pre-process to separate modifying events from non-modifying input events.
+    if( isNullKey )
+    {
+      // In some platforms arrive key events with no key code.
+      // Do nothing.
+      return false;
+    }
+    else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode  || Dali::DALI_KEY_SEARCH == keyCode )
+    {
+      // Do nothing
+      return false;
+    }
+    else if( ( Dali::DALI_KEY_CURSOR_LEFT  == keyCode ) ||
+             ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) ||
+             ( Dali::DALI_KEY_CURSOR_UP    == keyCode ) ||
+             ( Dali::DALI_KEY_CURSOR_DOWN  == keyCode ) )
+    {
+      // If don't have any text, do nothing.
+      if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters )
+      {
+        return false;
+      }
+
+      uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition;
+      uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+      uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition );
+      uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
+
+      // Logic to determine whether this text control will lose focus or not.
+      if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) ||
+          ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
+          ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
+          ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
+          ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
+          ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
+      {
+        // Release the active highlight.
+        if( mImpl->mEventData->mState == EventData::SELECTING )
+        {
+          mImpl->ChangeState( EventData::EDITING );
+
+          // Update selection position.
+          mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+          mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+          mImpl->mEventData->mUpdateCursorPosition = true;
+          mImpl->RequestRelayout();
+        }
+        return false;
+      }
+
+      mImpl->mEventData->mCheckScrollAmount = true;
+      Event event( Event::CURSOR_KEY_EVENT );
+      event.p1.mInt = keyCode;
+      event.p2.mBool = keyEvent.IsShiftModifier();
+      mImpl->mEventData->mEventQueue.push_back( event );
+
+      // Will request for relayout.
+      relayoutNeeded = true;
+    }
+    else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode )
+    {
+      // Left or Right Control key event is received before Ctrl-C/V/X key event is received
+      // If not handle it here, any selected text will be deleted
+
+      // Do nothing
+      return false;
+    }
+    else if ( keyEvent.IsCtrlModifier() )
+    {
+      bool consumed = false;
+      if (keyName == KEY_C_NAME)
+      {
+        // Ctrl-C to copy the selected text
+        TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY );
+        consumed = true;
+      }
+      else if (keyName == KEY_V_NAME)
+      {
+        // Ctrl-V to paste the copied text
+        TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE );
+        consumed = true;
+      }
+      else if (keyName == KEY_X_NAME)
+      {
+        // Ctrl-X to cut the selected text
+        TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT );
+        consumed = true;
+      }
+      return consumed;
+    }
+    else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) ||
+             ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) )
+    {
+      textChanged = DeleteEvent( keyCode );
+
+      // Will request for relayout.
+      relayoutNeeded = true;
+    }
+    else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) ||
+             IsKey( keyEvent, Dali::DALI_KEY_MENU ) ||
+             IsKey( keyEvent, Dali::DALI_KEY_HOME ) )
+    {
+      // Power key/Menu/Home key behaviour does not allow edit mode to resume.
+      mImpl->ChangeState( EventData::INACTIVE );
+
+      // Will request for relayout.
+      relayoutNeeded = true;
+
+      // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
+    }
+    else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) )
+    {
+      // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled
+      // and a character is typed after the type of a upper case latin character.
+
+      // Do nothing.
+      return false;
+    }
+    else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) )
+    {
+      // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
+      // Do nothing.
+      return false;
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
+
+      if( !keyString.empty() )
+      {
+        // InputMethodContext is no longer handling key-events
+        mImpl->ClearPreEditFlag();
+
+        InsertText( keyString, COMMIT );
+
+        textChanged = true;
+
+        // Will request for relayout.
+        relayoutNeeded = true;
+      }
+
+    }
+
+    if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
+         ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
+         ( !isNullKey ) &&
+         ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
+         ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) &&
+         ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
+         ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
+    {
+      // Should not change the state if the key is the shift send by the InputMethodContext.
+      // Otherwise, when the state is SELECTING the text controller can't send the right
+      // surrounding info to the InputMethodContext.
+      mImpl->ChangeState( EventData::EDITING );
+
+      // Will request for relayout.
+      relayoutNeeded = true;
+    }
+
+    if( relayoutNeeded )
+    {
+      mImpl->RequestRelayout();
+    }
+  }
+
+  if( textChanged &&
+      ( NULL != mImpl->mEditableControlInterface ) )
+  {
+    // Do this last since it provides callbacks into application code
+    mImpl->mEditableControlInterface->TextChanged();
+  }
+
+  return true;
+}
+
+void Controller::TapEvent( unsigned int tapCount, float x, float y )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState );
+    EventData::State state( mImpl->mEventData->mState );
+    bool relayoutNeeded( false );   // to avoid unnecessary relayouts when tapping an empty text-field
+
+    if( mImpl->IsClipboardVisible() )
+    {
+      if( EventData::INACTIVE == state || EventData::EDITING == state)
+      {
+        mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
+      }
+      relayoutNeeded = true;
+    }
+    else if( 1u == tapCount )
+    {
+      if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state )
+      {
+        mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
+      }
+
+      if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) )
+      {
+        mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );
+        relayoutNeeded = true;
+      }
+      else
+      {
+        if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() )
+        {
+          // Hide placeholder text
+          ResetText();
+        }
+
+        if( EventData::INACTIVE == state )
+        {
+          mImpl->ChangeState( EventData::EDITING );
+        }
+        else if( !mImpl->IsClipboardEmpty() )
+        {
+          mImpl->ChangeState( EventData::EDITING_WITH_POPUP );
+        }
+        relayoutNeeded = true;
+      }
+    }
+    else if( 2u == tapCount )
+    {
+      if( mImpl->mEventData->mSelectionEnabled &&
+          mImpl->IsShowingRealText() )
+      {
+        relayoutNeeded = true;
+        mImpl->mEventData->mIsLeftHandleSelected = true;
+        mImpl->mEventData->mIsRightHandleSelected = true;
+      }
+    }
+
+    // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
+    if( relayoutNeeded )
+    {
+      Event event( Event::TAP_EVENT );
+      event.p1.mUint = tapCount;
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+
+      mImpl->RequestRelayout();
+    }
+  }
+
+  // Reset keyboard as tap event has occurred.
+  mImpl->ResetInputMethodContext();
+}
+
+void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    Event event( Event::PAN_EVENT );
+    event.p1.mInt = state;
+    event.p2.mFloat = displacement.x;
+    event.p3.mFloat = displacement.y;
+    mImpl->mEventData->mEventQueue.push_back( event );
+
+    mImpl->RequestRelayout();
+  }
+}
+
+void Controller::LongPressEvent( Gesture::State state, float x, float y  )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" );
+
+  if( ( state == Gesture::Started ) &&
+      ( NULL != mImpl->mEventData ) )
+  {
+    // The 1st long-press on inactive text-field is treated as tap
+    if( EventData::INACTIVE == mImpl->mEventData->mState )
+    {
+      mImpl->ChangeState( EventData::EDITING );
+
+      Event event( Event::TAP_EVENT );
+      event.p1.mUint = 1;
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+
+      mImpl->RequestRelayout();
+    }
+    else if( !mImpl->IsShowingRealText() )
+    {
+      Event event( Event::LONG_PRESS_EVENT );
+      event.p1.mInt = state;
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+      mImpl->RequestRelayout();
+    }
+    else if( !mImpl->IsClipboardVisible() )
+    {
+      // Reset the InputMethodContext to commit the pre-edit before selecting the text.
+      mImpl->ResetInputMethodContext();
+
+      Event event( Event::LONG_PRESS_EVENT );
+      event.p1.mInt = state;
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+      mImpl->RequestRelayout();
+
+      mImpl->mEventData->mIsLeftHandleSelected = true;
+      mImpl->mEventData->mIsRightHandleSelected = true;
+    }
+  }
+}
+
+void Controller::SelectEvent( float x, float y, bool selectAll )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    if( selectAll )
+    {
+      Event event( Event::SELECT_ALL );
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+    else
+    {
+      Event event( Event::SELECT );
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+
+    mImpl->mEventData->mCheckScrollAmount = true;
+    mImpl->mEventData->mIsLeftHandleSelected = true;
+    mImpl->mEventData->mIsRightHandleSelected = true;
+    mImpl->RequestRelayout();
+  }
+}
+
+InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
+{
+  // Whether the text needs to be relaid-out.
+  bool requestRelayout = false;
+
+  // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
+  bool retrieveText = false;
+  bool retrieveCursor = false;
+
+  switch( inputMethodContextEvent.eventName )
+  {
+    case InputMethodContext::COMMIT:
+    {
+      InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT );
+      requestRelayout = true;
+      retrieveCursor = true;
+      break;
+    }
+    case InputMethodContext::PRE_EDIT:
+    {
+      InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT );
+      requestRelayout = true;
+      retrieveCursor = true;
+      break;
+    }
+    case InputMethodContext::DELETE_SURROUNDING:
+    {
+      const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset,
+                                           inputMethodContextEvent.numberOfChars,
+                                           DONT_UPDATE_INPUT_STYLE );
+
+      if( textDeleted )
+      {
+        if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
+            !mImpl->IsPlaceholderAvailable() )
+        {
+          mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+        }
+        else
+        {
+          ShowPlaceholderText();
+        }
+        mImpl->mEventData->mUpdateCursorPosition = true;
+        mImpl->mEventData->mScrollAfterDelete = true;
+
+        requestRelayout = true;
+      }
+      break;
+    }
+    case InputMethodContext::GET_SURROUNDING:
+    {
+      retrieveText = true;
+      retrieveCursor = true;
+      break;
+    }
+    case InputMethodContext::PRIVATE_COMMAND:
+    {
+      // PRIVATECOMMAND event is just for getting the private command message
+      retrieveText = true;
+      retrieveCursor = true;
+      break;
+    }
+    case InputMethodContext::VOID:
+    {
+      // do nothing
+      break;
+    }
+  } // end switch
+
+  if( requestRelayout )
+  {
+    mImpl->mOperationsPending = ALL_OPERATIONS;
+    mImpl->RequestRelayout();
+  }
+
+  std::string text;
+  CharacterIndex cursorPosition = 0u;
+  Length numberOfWhiteSpaces = 0u;
+
+  if( retrieveCursor )
+  {
+    numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
+
+    cursorPosition = mImpl->GetLogicalCursorPosition();
+
+    if( cursorPosition < numberOfWhiteSpaces )
+    {
+      cursorPosition = 0u;
+    }
+    else
+    {
+      cursorPosition -= numberOfWhiteSpaces;
+    }
+  }
+
+  if( retrieveText )
+  {
+    if( !mImpl->IsShowingPlaceholderText() )
+    {
+      // Retrieves the normal text string.
+      mImpl->GetText( numberOfWhiteSpaces, text );
+    }
+    else
+    {
+      // When the current text is Placeholder Text, the surrounding text should be empty string.
+      // It means DALi should send empty string ("") to IME.
+      text = "";
+    }
+  }
+
+  InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
+
+  if( requestRelayout &&
+      ( NULL != mImpl->mEditableControlInterface ) )
+  {
+    // Do this last since it provides callbacks into application code
+    mImpl->mEditableControlInterface->TextChanged();
+  }
+
+  return callbackData;
+}
+
+void Controller::PasteClipboardItemEvent()
+{
+  // Retrieve the clipboard contents first
+  ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() );
+  std::string stringToPaste( notifier.GetContent() );
+
+  // Commit the current pre-edit text; the contents of the clipboard should be appended
+  mImpl->ResetInputMethodContext();
+
+  // Temporary disable hiding clipboard
+  mImpl->SetClipboardHideEnable( false );
+
+  // Paste
+  PasteText( stringToPaste );
+
+  mImpl->SetClipboardHideEnable( true );
+}
+
+// protected : Inherit from Text::Decorator::ControllerInterface.
+
+void Controller::GetTargetSize( Vector2& targetSize )
+{
+  targetSize = mImpl->mModel->mVisualModel->mControlSize;
+}
+
+void Controller::AddDecoration( Actor& actor, bool needsClipping )
+{
+  if( NULL != mImpl->mEditableControlInterface )
+  {
+    mImpl->mEditableControlInterface->AddDecoration( actor, needsClipping );
+  }
+}
+
+void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y )
+{
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    switch( handleType )
+    {
+      case GRAB_HANDLE:
+      {
+        Event event( Event::GRAB_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case LEFT_SELECTION_HANDLE:
+      {
+        Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case RIGHT_SELECTION_HANDLE:
+      {
+        Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case LEFT_SELECTION_HANDLE_MARKER:
+      case RIGHT_SELECTION_HANDLE_MARKER:
+      {
+        // Markers do not move the handles.
+        break;
+      }
+      case HANDLE_TYPE_COUNT:
+      {
+        DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
+      }
+    }
+
+    mImpl->RequestRelayout();
+  }
+}
+
+// protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
+
+void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
+{
+  if( NULL == mImpl->mEventData )
+  {
+    return;
+  }
+
+  switch( button )
+  {
+    case Toolkit::TextSelectionPopup::CUT:
+    {
+      mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
+      mImpl->mOperationsPending = ALL_OPERATIONS;
+
+      if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
+          !mImpl->IsPlaceholderAvailable() )
+      {
+        mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+      }
+      else
+      {
+        ShowPlaceholderText();
+      }
+
+      mImpl->mEventData->mUpdateCursorPosition = true;
+      mImpl->mEventData->mScrollAfterDelete = true;
+
+      mImpl->RequestRelayout();
+
+      if( NULL != mImpl->mEditableControlInterface )
+      {
+        mImpl->mEditableControlInterface->TextChanged();
+      }
+      break;
+    }
+    case Toolkit::TextSelectionPopup::COPY:
+    {
+      mImpl->SendSelectionToClipboard( false ); // Text not modified
+
+      mImpl->mEventData->mUpdateCursorPosition = true;
+
+      mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup
+      break;
+    }
+    case Toolkit::TextSelectionPopup::PASTE:
+    {
+      mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item
+      break;
+    }
+    case Toolkit::TextSelectionPopup::SELECT:
+    {
+      const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+      if( mImpl->mEventData->mSelectionEnabled )
+      {
+        // Creates a SELECT event.
+        SelectEvent( currentCursorPosition.x, currentCursorPosition.y, false );
+      }
+      break;
+    }
+    case Toolkit::TextSelectionPopup::SELECT_ALL:
+    {
+      // Creates a SELECT_ALL event
+      SelectEvent( 0.f, 0.f, true );
+      break;
+    }
+    case Toolkit::TextSelectionPopup::CLIPBOARD:
+    {
+      mImpl->ShowClipboard();
+      break;
+    }
+    case Toolkit::TextSelectionPopup::NONE:
+    {
+      // Nothing to do.
+      break;
+    }
+  }
+}
+
+void Controller::DisplayTimeExpired()
+{
+  mImpl->mEventData->mUpdateCursorPosition = true;
+  // Apply modifications to the model
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+
+  mImpl->RequestRelayout();
+}
+
+// private : Update.
+
+void Controller::InsertText( const std::string& text, Controller::InsertType type )
+{
+  bool removedPrevious = false;
+  bool removedSelected = false;
+  bool maxLengthReached = false;
+
+  DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" )
+
+  if( NULL == mImpl->mEventData )
+  {
+    return;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n",
+                 this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"),
+                 mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
+
+  // TODO: At the moment the underline runs are only for pre-edit.
+  mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
+
+  // Remove the previous InputMethodContext pre-edit.
+  if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
+  {
+    removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
+                                  mImpl->mEventData->mPreEditLength,
+                                  DONT_UPDATE_INPUT_STYLE );
+
+    mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
+    mImpl->mEventData->mPreEditLength = 0u;
+  }
+  else
+  {
+    // Remove the previous Selection.
+    removedSelected = RemoveSelectedText();
+
+  }
+
+  Vector<Character> utf32Characters;
+  Length characterCount = 0u;
+
+  if( !text.empty() )
+  {
+    //  Convert text into UTF-32
+    utf32Characters.Resize( text.size() );
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+
+    // Transform a text array encoded in utf8 into an array encoded in utf32.
+    // It returns the actual number of characters.
+    characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
+    utf32Characters.Resize( characterCount );
+
+    DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() );
+  }
+
+  if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded
+  {
+    // The placeholder text is no longer needed
+    if( mImpl->IsShowingPlaceholderText() )
+    {
+      ResetText();
+    }
+
+    mImpl->ChangeState( EventData::EDITING );
+
+    // Handle the InputMethodContext (predicitive text) state changes
+    if( COMMIT == type )
+    {
+      // InputMethodContext is no longer handling key-events
+      mImpl->ClearPreEditFlag();
+    }
+    else // PRE_EDIT
+    {
+      if( !mImpl->mEventData->mPreEditFlag )
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" );
+
+        // Record the start of the pre-edit text
+        mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
+      }
+
+      mImpl->mEventData->mPreEditLength = utf32Characters.Count();
+      mImpl->mEventData->mPreEditFlag = true;
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength );
+    }
+
+    const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
+
+    // Restrict new text to fit within Maximum characters setting.
+    Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
+    maxLengthReached = ( characterCount > maxSizeOfNewText );
+
+    // The cursor position.
+    CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
+
+    // Update the text's style.
+
+    // Updates the text style runs by adding characters.
+    mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
+
+    // Get the character index from the cursor index.
+    const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
+
+    // Retrieve the text's style for the given index.
+    InputStyle style;
+    mImpl->RetrieveDefaultInputStyle( style );
+    mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
+
+    // Whether to add a new text color run.
+    const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
+
+    // Whether to add a new font run.
+    const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
+    const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
+    const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
+    const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
+    const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
+
+    // Add style runs.
+    if( addColorRun )
+    {
+      const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
+      mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
+
+      ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
+      colorRun.color = mImpl->mEventData->mInputStyle.textColor;
+      colorRun.characterRun.characterIndex = cursorIndex;
+      colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
+    }
+
+    if( addFontNameRun   ||
+        addFontWeightRun ||
+        addFontWidthRun  ||
+        addFontSlantRun  ||
+        addFontSizeRun )
+    {
+      const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
+      mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u );
+
+      FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns );
+
+      if( addFontNameRun )
+      {
+        fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
+        fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+        memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength );
+        fontDescriptionRun.familyDefined = true;
+
+        // The memory allocated for the font family name is freed when the font description is removed from the logical model.
+      }
+
+      if( addFontWeightRun )
+      {
+        fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
+        fontDescriptionRun.weightDefined = true;
+      }
+
+      if( addFontWidthRun )
+      {
+        fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
+        fontDescriptionRun.widthDefined = true;
+      }
+
+      if( addFontSlantRun )
+      {
+        fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
+        fontDescriptionRun.slantDefined = true;
+      }
+
+      if( addFontSizeRun )
+      {
+        fontDescriptionRun.size = static_cast<PointSize26Dot6>( mImpl->mEventData->mInputStyle.size * 64.f );
+        fontDescriptionRun.sizeDefined = true;
+      }
+
+      fontDescriptionRun.characterRun.characterIndex = cursorIndex;
+      fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
+    }
+
+    // Insert at current cursor position.
+    Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
+
+    if( cursorIndex < numberOfCharactersInModel )
+    {
+      modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
+    }
+    else
+    {
+      modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
+    }
+
+    // Mark the first paragraph to be updated.
+    if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
+    {
+      mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
+      mImpl->mTextUpdateInfo.mClearAll = true;
+    }
+    else
+    {
+      mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
+    }
+
+    // Update the cursor index.
+    cursorIndex += maxSizeOfNewText;
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
+  }
+
+  if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) &&
+      mImpl->IsPlaceholderAvailable() )
+  {
+    // Show place-holder if empty after removing the pre-edit text
+    ShowPlaceholderText();
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    mImpl->ClearPreEditFlag();
+  }
+  else if( removedPrevious ||
+           removedSelected ||
+           ( 0 != utf32Characters.Count() ) )
+  {
+    // Queue an inserted event
+    mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
+
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    if( removedSelected )
+    {
+      mImpl->mEventData->mScrollAfterDelete = true;
+    }
+    else
+    {
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
+  }
+
+  if( maxLengthReached )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
+
+    mImpl->ResetInputMethodContext();
+
+    if( NULL != mImpl->mEditableControlInterface )
+    {
+      // Do this last since it provides callbacks into application code
+      mImpl->mEditableControlInterface->MaxLengthReached();
+    }
+  }
+}
+
+void Controller::PasteText( const std::string& stringToPaste )
+{
+  InsertText( stringToPaste, Text::Controller::COMMIT );
+  mImpl->ChangeState( EventData::EDITING );
+  mImpl->RequestRelayout();
+
+  if( NULL != mImpl->mEditableControlInterface )
+  {
+    // Do this last since it provides callbacks into application code
+    mImpl->mEditableControlInterface->TextChanged();
+  }
+}
+
+bool Controller::RemoveText( int cursorOffset,
+                             int numberOfCharacters,
+                             UpdateInputStyleType type )
+{
+  bool removed = false;
+
+  if( NULL == mImpl->mEventData )
+  {
+    return removed;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n",
+                 this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters );
+
+  if( !mImpl->IsShowingPlaceholderText() )
+  {
+    // Delete at current cursor position
+    Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
+    CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
+
+    CharacterIndex cursorIndex = 0;
+
+    // Validate the cursor position & number of characters
+    if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 )
+    {
+      cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
+    }
+
+    if( ( cursorIndex + numberOfCharacters ) > currentText.Count() )
+    {
+      numberOfCharacters = currentText.Count() - cursorIndex;
+    }
+
+    if( mImpl->mEventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
+        ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) )
+    {
+      // Mark the paragraphs to be updated.
+      if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
+      {
+        mImpl->mTextUpdateInfo.mCharacterIndex = 0;
+        mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+        mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
+        mImpl->mTextUpdateInfo.mClearAll = true;
+      }
+      else
+      {
+        mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex );
+        mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
+      }
+
+      // Update the input style and remove the text's style before removing the text.
+
+      if( UPDATE_INPUT_STYLE == type )
+      {
+        // Keep a copy of the current input style.
+        InputStyle currentInputStyle;
+        currentInputStyle.Copy( mImpl->mEventData->mInputStyle );
+
+        // Set first the default input style.
+        mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
+
+        // Update the input style.
+        mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
+
+        // Compare if the input style has changed.
+        const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle );
+
+        if( hasInputStyleChanged )
+        {
+          const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle );
+          // Queue the input style changed signal.
+          mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
+        }
+      }
+
+      // If the number of current text and the number of characters to be deleted are same,
+      // it means all texts should be removed and all Preedit variables should be initialized.
+      if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) )
+      {
+        mImpl->ClearPreEditFlag();
+      }
+
+      // Updates the text style runs by removing characters. Runs with no characters are removed.
+      mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
+
+      // Remove the characters.
+      Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
+      Vector<Character>::Iterator last  = first + numberOfCharacters;
+
+      currentText.Erase( first, last );
+
+      // Cursor position retreat
+      oldCursorIndex = cursorIndex;
+
+      mImpl->mEventData->mScrollAfterDelete = true;
+
+      if( EventData::INACTIVE == mImpl->mEventData->mState )
+      {
+        mImpl->ChangeState( EventData::EDITING );
+      }
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
+      removed = true;
+    }
+  }
+
+  return removed;
+}
+
+bool Controller::RemoveSelectedText()
+{
+  bool textRemoved( false );
+
+  if( EventData::SELECTING == mImpl->mEventData->mState )
+  {
+    std::string removedString;
+    mImpl->RetrieveSelection( removedString, true );
+
+    if( !removedString.empty() )
+    {
+      textRemoved = true;
+      mImpl->ChangeState( EventData::EDITING );
+    }
+  }
+
+  return textRemoved;
+}
+
+// private : Relayout.
+
+bool Controller::DoRelayout( const Size& size,
+                             OperationsMask operationsRequired,
+                             Size& layoutSize )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height );
+  bool viewUpdated( false );
+
+  // Calculate the operations to be done.
+  const OperationsMask operations = static_cast<OperationsMask>( mImpl->mOperationsPending & operationsRequired );
+
+  const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
+  const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
+
+  // Get the current layout size.
+  layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
+
+  if( NO_OPERATION != ( LAYOUT & operations ) )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
+
+    // Some vectors with data needed to layout and reorder may be void
+    // after the first time the text has been laid out.
+    // Fill the vectors again.
+
+    // Calculate the number of glyphs to layout.
+    const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
+    const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
+    const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
+
+    const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
+    const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
+
+    // Make sure the index is not out of bound
+    if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
+         requestedNumberOfCharacters > charactersToGlyph.Count() ||
+         ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
+    {
+      std::string currentText;
+      GetText( currentText );
+
+      DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
+      DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
+      DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
+
+      return false;
+    }
+
+    const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
+    const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
+
+    if( 0u == totalNumberOfGlyphs )
+    {
+      if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
+      {
+        mImpl->mModel->mVisualModel->SetLayoutSize( Size::ZERO );
+      }
+
+      // Nothing else to do if there is no glyphs.
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n" );
+      return true;
+    }
+
+    // Set the layout parameters.
+    Layout::Parameters layoutParameters( size,
+                                         mImpl->mModel);
+
+    // Resize the vector of positions to have the same size than the vector of glyphs.
+    Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
+    glyphPositions.Resize( totalNumberOfGlyphs );
+
+    // Whether the last character is a new paragraph character.
+    const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
+    mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph =  TextAbstraction::IsNewParagraph( *( textBuffer + ( mImpl->mModel->mLogicalModel->mText.Count() - 1u ) ) );
+    layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
+
+    // The initial glyph and the number of glyphs to layout.
+    layoutParameters.startGlyphIndex = startGlyphIndex;
+    layoutParameters.numberOfGlyphs = numberOfGlyphs;
+    layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
+    layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
+
+    // Update the ellipsis
+    bool elideTextEnabled = mImpl->mModel->mElideEnabled;
+
+    if( NULL != mImpl->mEventData )
+    {
+      if( mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText() )
+      {
+        elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
+      }
+      else if( EventData::INACTIVE != mImpl->mEventData->mState )
+      {
+        // Disable ellipsis when editing
+        elideTextEnabled = false;
+      }
+
+      // Reset the scroll position in inactive state
+      if( elideTextEnabled && ( mImpl->mEventData->mState == EventData::INACTIVE ) )
+      {
+        ResetScrollPosition();
+      }
+    }
+
+    // Update the visual model.
+    bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
+    Size newLayoutSize;
+    viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
+                                                   newLayoutSize,
+                                                   elideTextEnabled,
+                                                   isAutoScrollEnabled );
+    mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
+
+    viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
+
+    if( viewUpdated )
+    {
+      layoutSize = newLayoutSize;
+
+      if( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
+      {
+        mImpl->mIsTextDirectionRTL = false;
+      }
+
+      if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && !mImpl->mModel->mVisualModel->mLines.Empty() )
+      {
+        mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
+      }
+
+      // Sets the layout size.
+      if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
+      {
+        mImpl->mModel->mVisualModel->SetLayoutSize( layoutSize );
+      }
+    } // view updated
+  }
+
+  if( NO_OPERATION != ( ALIGN & operations ) )
+  {
+    // The laid-out lines.
+    Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
+
+    CharacterIndex alignStartIndex = startIndex;
+    Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+
+    // the whole text needs to be full aligned.
+    // If you do not do a full aligned, only the last line of the multiline input is aligned.
+    if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
+    {
+      alignStartIndex = 0u;
+      alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+      mImpl->mEventData->mUpdateAlignment = false;
+    }
+
+    // Need to align with the control's size as the text may contain lines
+    // starting either with left to right text or right to left.
+    mImpl->mLayoutEngine.Align( size,
+                                alignStartIndex,
+                                alignRequestedNumberOfCharacters,
+                                mImpl->mModel->mHorizontalAlignment,
+                                lines,
+                                mImpl->mModel->mAlignmentOffset,
+                                mImpl->mLayoutDirection,
+                                mImpl->mModel->mMatchSystemLanguageDirection );
+
+    viewUpdated = true;
+  }
+#if defined(DEBUG_ENABLED)
+  std::string currentText;
+  GetText( currentText );
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL)?"true":"false",  currentText.c_str() );
+#endif
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
+  return viewUpdated;
+}
+
+void Controller::CalculateVerticalOffset( const Size& controlSize )
+{
+  Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
+
+  if( fabsf( layoutSize.height ) < Math::MACHINE_EPSILON_1000 )
+  {
+    // Get the line height of the default font.
+    layoutSize.height = mImpl->GetDefaultFontLineHeight();
+  }
+
+  switch( mImpl->mModel->mVerticalAlignment )
+  {
+    case VerticalAlignment::TOP:
+    {
+      mImpl->mModel->mScrollPosition.y = 0.f;
+      break;
+    }
+    case VerticalAlignment::CENTER:
+    {
+      mImpl->mModel->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
+      break;
+    }
+    case VerticalAlignment::BOTTOM:
+    {
+      mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
+      break;
+    }
+  }
+}
+
+// private : Events.
+
+void Controller::ProcessModifyEvents()
+{
+  Vector<ModifyEvent>& events = mImpl->mModifyEvents;
+
+  if( 0u == events.Count() )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  for( Vector<ModifyEvent>::ConstIterator it = events.Begin(),
+         endIt = events.End();
+       it != endIt;
+       ++it )
+  {
+    const ModifyEvent& event = *it;
+
+    if( ModifyEvent::TEXT_REPLACED == event.type )
+    {
+      // A (single) replace event should come first, otherwise we wasted time processing NOOP events
+      DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" );
+
+      TextReplacedEvent();
+    }
+    else if( ModifyEvent::TEXT_INSERTED == event.type )
+    {
+      TextInsertedEvent();
+    }
+    else if( ModifyEvent::TEXT_DELETED == event.type )
+    {
+      // Placeholder-text cannot be deleted
+      if( !mImpl->IsShowingPlaceholderText() )
+      {
+        TextDeletedEvent();
+      }
+    }
+  }
+
+  if( NULL != mImpl->mEventData )
+  {
+    // When the text is being modified, delay cursor blinking
+    mImpl->mEventData->mDecorator->DelayCursorBlink();
+
+    // Update selection position after modifying the text
+    mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+    mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+  }
+
+  // Discard temporary text
+  events.Clear();
+}
+
+void Controller::TextReplacedEvent()
+{
+  // The natural size needs to be re-calculated.
+  mImpl->mRecalculateNaturalSize = true;
+
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
+  // Apply modifications to the model
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::TextInsertedEvent()
+{
+  DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" );
+
+  if( NULL == mImpl->mEventData )
+  {
+    return;
+  }
+
+  mImpl->mEventData->mCheckScrollAmount = true;
+
+  // The natural size needs to be re-calculated.
+  mImpl->mRecalculateNaturalSize = true;
+
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
+  // Apply modifications to the model; TODO - Optimize this
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::TextDeletedEvent()
+{
+  DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" );
+
+  if( NULL == mImpl->mEventData )
+  {
+    return;
+  }
+
+  mImpl->mEventData->mCheckScrollAmount = true;
+
+  // The natural size needs to be re-calculated.
+  mImpl->mRecalculateNaturalSize = true;
+
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
+  // Apply modifications to the model; TODO - Optimize this
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+bool Controller::DeleteEvent( int keyCode )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
+
+  bool removed = false;
+
+  if( NULL == mImpl->mEventData )
+  {
+    return removed;
+  }
+
+  // InputMethodContext is no longer handling key-events
+  mImpl->ClearPreEditFlag();
+
+  if( EventData::SELECTING == mImpl->mEventData->mState )
+  {
+    removed = RemoveSelectedText();
+  }
+  else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) )
+  {
+    // Remove the character before the current cursor position
+    removed = RemoveText( -1,
+                          1,
+                          UPDATE_INPUT_STYLE );
+  }
+  else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE )
+  {
+    // Remove the character after the current cursor position
+    removed = RemoveText( 0,
+                          1,
+                          UPDATE_INPUT_STYLE );
+  }
+
+  if( removed )
+  {
+    if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) ||
+        !mImpl->IsPlaceholderAvailable() )
+    {
+      mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED );
+    }
+    else
+    {
+      ShowPlaceholderText();
+    }
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    mImpl->mEventData->mScrollAfterDelete = true;
+  }
+
+  return removed;
+}
+
+// private : Helpers.
+
+void Controller::ResetText()
+{
+  // Reset buffers.
+  mImpl->mModel->mLogicalModel->mText.Clear();
+
+  // Reset the embedded images buffer.
+  mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
+
+  // We have cleared everything including the placeholder-text
+  mImpl->PlaceholderCleared();
+
+  mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
+
+  // Clear any previous text.
+  mImpl->mTextUpdateInfo.mClearAll = true;
+
+  // The natural size needs to be re-calculated.
+  mImpl->mRecalculateNaturalSize = true;
+
+  // The text direction needs to be updated.
+  mImpl->mUpdateTextDirection = true;
+
+  // Apply modifications to the model
+  mImpl->mOperationsPending = ALL_OPERATIONS;
+}
+
+void Controller::ShowPlaceholderText()
+{
+  if( mImpl->IsPlaceholderAvailable() )
+  {
+    DALI_ASSERT_DEBUG( mImpl->mEventData && "No placeholder text available" );
+
+    if( NULL == mImpl->mEventData )
+    {
+      return;
+    }
+
+    mImpl->mEventData->mIsShowingPlaceholderText = true;
+
+    // Disable handles when showing place-holder text
+    mImpl->mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+    mImpl->mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+    mImpl->mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+
+    const char* text( NULL );
+    size_t size( 0 );
+
+    // TODO - Switch Placeholder text when changing state
+    if( ( EventData::INACTIVE != mImpl->mEventData->mState ) &&
+        ( 0u != mImpl->mEventData->mPlaceholderTextActive.c_str() ) )
+    {
+      text = mImpl->mEventData->mPlaceholderTextActive.c_str();
+      size = mImpl->mEventData->mPlaceholderTextActive.size();
+    }
+    else
+    {
+      text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
+      size = mImpl->mEventData->mPlaceholderTextInactive.size();
+    }
+
+    mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+
+    // Reset model for showing placeholder.
+    mImpl->mModel->mLogicalModel->mText.Clear();
+    mImpl->mModel->mVisualModel->SetTextColor( mImpl->mEventData->mPlaceholderTextColor );
+
+    // Convert text into UTF-32
+    Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
+    utf32Characters.Resize( size );
+
+    // This is a bit horrible but std::string returns a (signed) char*
+    const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
+
+    // Transform a text array encoded in utf8 into an array encoded in utf32.
+    // It returns the actual number of characters.
+    const Length characterCount = Utf8ToUtf32( utf8, size, utf32Characters.Begin() );
+    utf32Characters.Resize( characterCount );
+
+    // The characters to be added.
+    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
+
+    // Reset the cursor position
+    mImpl->mEventData->mPrimaryCursorPosition = 0;
+
+    // The natural size needs to be re-calculated.
+    mImpl->mRecalculateNaturalSize = true;
+
+    // The text direction needs to be updated.
+    mImpl->mUpdateTextDirection = true;
+
+    // Apply modifications to the model
+    mImpl->mOperationsPending = ALL_OPERATIONS;
+
+    // Update the rest of the model during size negotiation
+    mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
+  }
+}
+
+void Controller::ClearFontData()
+{
+  if( mImpl->mFontDefaults )
+  {
+    mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
+  }
+
+  // Set flags to update the model.
+  mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->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                |
+                                                           BIDI_INFO                 |
+                                                           GET_GLYPH_METRICS         |
+                                                           LAYOUT                    |
+                                                           UPDATE_LAYOUT_SIZE        |
+                                                           REORDER                   |
+                                                           ALIGN );
+}
+
+void Controller::ClearStyleData()
+{
+  mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+  mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
+}
+
+void Controller::ResetCursorPosition( CharacterIndex cursorIndex )
+{
+  // Reset the cursor position
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
+
+    // Update the cursor if it's in editing mode.
+    if( EventData::IsEditingState( mImpl->mEventData->mState )  )
+    {
+      mImpl->mEventData->mUpdateCursorPosition = true;
+    }
+  }
+}
+
+void Controller::ResetScrollPosition()
+{
+  if( NULL != mImpl->mEventData )
+  {
+    // Reset the scroll position.
+    mImpl->mModel->mScrollPosition = Vector2::ZERO;
+    mImpl->mEventData->mScrollAfterUpdatePosition = true;
+  }
+}
+
+void Controller::SetControlInterface( ControlInterface* controlInterface )
+{
+  mImpl->mControlInterface = controlInterface;
+}
+
+bool Controller::ShouldClearFocusOnEscape() const
+{
+  return mImpl->mShouldClearFocusOnEscape;
+}
+
+Actor Controller::CreateBackgroundActor()
+{
+  return mImpl->CreateBackgroundActor();
+}
+
+// private : Private contructors & copy operator.
+
+Controller::Controller()
+: mImpl( NULL )
+{
+  mImpl = new Controller::Impl( NULL, NULL );
+}
+
+Controller::Controller( ControlInterface* controlInterface )
+{
+  mImpl = new Controller::Impl( controlInterface, NULL );
+}
+
+Controller::Controller( ControlInterface* controlInterface,
+                        EditableControlInterface* editableControlInterface )
+{
+  mImpl = new Controller::Impl( controlInterface,
+                                editableControlInterface );
+}
+
+// The copy constructor and operator are left unimplemented.
+
+// protected : Destructor.
+
+Controller::~Controller()
+{
+  delete mImpl;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h
new file mode 100755 (executable)
index 0000000..82a7a15
--- /dev/null
@@ -0,0 +1,1698 @@
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/public-api/events/gesture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-selection-popup-callback-interface.h>
+#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/text/decorator/text-decorator.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine.h>
+#include <dali-toolkit/internal/text/hidden-text.h>
+#include <dali-toolkit/internal/text/text-model-interface.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class Controller;
+class ControlInterface;
+class EditableControlInterface;
+class View;
+class RenderingController;
+
+typedef IntrusivePtr<Controller> ControllerPtr;
+
+/**
+ * @brief A Text Controller is used by UI Controls which display text.
+ *
+ * It manipulates the Logical & Visual text models on behalf of the UI Controls.
+ * It provides a view of the text that can be used by rendering back-ends.
+ *
+ * For selectable/editable UI controls, the controller handles input events from the UI control
+ * and decorations (grab handles etc) via the Decorator::ControllerInterface interface.
+ *
+ * The text selection popup button callbacks are as well handled via the TextSelectionPopupCallbackInterface interface.
+ */
+class Controller : public RefObject, public Decorator::ControllerInterface, public TextSelectionPopupCallbackInterface, public HiddenText::Observer
+{
+public: // Enumerated types.
+
+  /**
+   * @brief Text related operations to be done in the relayout process.
+   */
+  enum OperationsMask
+  {
+    NO_OPERATION       = 0x0000,
+    CONVERT_TO_UTF32   = 0x0001,
+    GET_SCRIPTS        = 0x0002,
+    VALIDATE_FONTS     = 0x0004,
+    GET_LINE_BREAKS    = 0x0008,
+    BIDI_INFO          = 0x0010,
+    SHAPE_TEXT         = 0x0020,
+    GET_GLYPH_METRICS  = 0x0040,
+    LAYOUT             = 0x0080,
+    UPDATE_LAYOUT_SIZE = 0x0100,
+    REORDER            = 0x0200,
+    ALIGN              = 0x0400,
+    COLOR              = 0x0800,
+    UPDATE_DIRECTION   = 0x1000,
+    ALL_OPERATIONS     = 0xFFFF
+  };
+
+  /**
+   * @brief Used to distinguish between regular key events and InputMethodContext events
+   */
+  enum InsertType
+  {
+    COMMIT,
+    PRE_EDIT
+  };
+
+  /**
+   * @brief Used to specify whether to update the input style.
+   */
+  enum UpdateInputStyleType
+  {
+    UPDATE_INPUT_STYLE,
+    DONT_UPDATE_INPUT_STYLE
+  };
+
+  /**
+   * @brief Used to specify what has been updated after the Relayout() method has been called.
+   */
+  enum UpdateTextType
+  {
+    NONE_UPDATED      = 0x0, ///< Nothing has been updated.
+    MODEL_UPDATED     = 0x1, ///< The text's model has been updated.
+    DECORATOR_UPDATED = 0x2  ///< The decoration has been updated.
+  };
+
+  /**
+   * @brief Different placeholder-text can be shown when the control is active/inactive.
+   */
+  enum PlaceholderType
+  {
+    PLACEHOLDER_TYPE_ACTIVE,
+    PLACEHOLDER_TYPE_INACTIVE,
+  };
+
+  /**
+   * @brief Enumeration for Font Size Type.
+   */
+  enum FontSizeType
+  {
+    POINT_SIZE,   // The size of font in points.
+    PIXEL_SIZE    // The size of font in pixels.
+  };
+
+  struct NoTextTap
+  {
+    enum Action
+    {
+      NO_ACTION,           ///< Does no action if there is a tap on top of an area with no text.
+      HIGHLIGHT,           ///< Highlights the nearest text (at the beginning or end of the text) and shows the text's selection popup.
+      SHOW_SELECTION_POPUP ///< Shows the text's selection popup.
+    };
+  };
+
+  struct TextFitInfo
+  {
+    enum Property
+    {
+      TEXT_FIT_ENABLE,
+      TEXT_FIT_MIN_SIZE,
+      TEXT_FIT_MAX_SIZE,
+      TEXT_FIT_STEP_SIZE,
+      TEXT_FIT_FONT_SIZE_TYPE
+    };
+  };
+
+public: // Constructor.
+
+  /**
+   * @brief Create a new instance of a Controller.
+   *
+   * @return A pointer to a new Controller.
+   */
+  static ControllerPtr New();
+
+  /**
+   * @brief Create a new instance of a Controller.
+   *
+   * @param[in] controlInterface The control's interface.
+   *
+   * @return A pointer to a new Controller.
+   */
+  static ControllerPtr New( ControlInterface* controlInterface );
+
+  /**
+   * @brief Create a new instance of a Controller.
+   *
+   * @param[in] controlInterface The control's interface.
+   * @param[in] editableControlInterface The editable control's interface.
+   *
+   * @return A pointer to a new Controller.
+   */
+  static ControllerPtr New( ControlInterface* controlInterface,
+                            EditableControlInterface* editableControlInterface );
+
+public: // Configure the text controller.
+
+  /**
+   * @brief Called to enable text input.
+   *
+   * @note Selectable or editable controls should call this once after Controller::New().
+   * @param[in] decorator Used to create cursor, selection handle decorations etc.
+   * @param[in] inputMethodContext Used to manager ime.
+   */
+  void EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext );
+
+  /**
+   * @brief Used to switch between bitmap & vector based glyphs
+   *
+   * @param[in] glyphType The type of glyph; note that metrics for bitmap & vector based glyphs are different.
+   */
+  void SetGlyphType( TextAbstraction::GlyphType glyphType );
+
+  /**
+   * @brief Enables/disables the mark-up processor.
+   *
+   * By default is disabled.
+   *
+   * @param[in] enable Whether to enable the mark-up processor.
+   */
+  void SetMarkupProcessorEnabled( bool enable );
+
+  /**
+   * @brief Retrieves whether the mark-up processor is enabled.
+   *
+   * By default is disabled.
+   *
+   * @return @e true if the mark-up processor is enabled, otherwise returns @e false.
+   */
+  bool IsMarkupProcessorEnabled() const;
+
+  /**
+   * @brief Enables/disables the auto text scrolling
+   *
+   * By default is disabled.
+   *
+   * @param[in] enable Whether to enable the auto scrolling
+   */
+  void SetAutoScrollEnabled( bool enable );
+
+  /**
+   * @brief Retrieves whether auto text scrolling is enabled.
+   *
+   * By default is disabled.
+   *
+   * @return @e true if auto scrolling is enabled, otherwise returns @e false.
+   */
+  bool IsAutoScrollEnabled() const;
+
+  /**
+   * @brief Get direction of the text from the first line of text,
+   * @return bool rtl (right to left) is true
+   */
+  CharacterDirection GetAutoScrollDirection() const;
+
+  /**
+   * @brief Get the alignment offset of the first line of text.
+   *
+   * @return The alignment offset.
+   */
+  float GetAutoScrollLineAlignment() const;
+
+  /**
+   * @brief Enables the horizontal scrolling.
+   *
+   * @param[in] enable Whether to enable the horizontal scrolling.
+   */
+  void SetHorizontalScrollEnabled( bool enable );
+
+  /**
+   * @brief Retrieves whether the horizontal scrolling is enabled.
+   *
+   * @return @e true if the horizontal scrolling is enabled, otherwise it returns @e false.
+   */
+  bool IsHorizontalScrollEnabled() const;
+
+  /**
+   * @brief Enables the vertical scrolling.
+   *
+   * @param[in] enable Whether to enable the vertical scrolling.
+   */
+  void SetVerticalScrollEnabled( bool enable );
+
+  /**
+   * @brief Retrieves whether the verticall scrolling is enabled.
+   *
+   * @return @e true if the vertical scrolling is enabled, otherwise it returns @e false.
+   */
+  bool IsVerticalScrollEnabled() const;
+
+  /**
+   * @brief Enables the smooth handle panning.
+   *
+   * @param[in] enable Whether to enable the smooth handle panning.
+   */
+  void SetSmoothHandlePanEnabled( bool enable );
+
+  /**
+   * @brief Retrieves whether the smooth handle panning is enabled.
+   *
+   * @return @e true if the smooth handle panning is enabled.
+   */
+  bool IsSmoothHandlePanEnabled() const;
+
+  /**
+   * @brief Sets the maximum number of characters that can be inserted into the TextModel
+   *
+   * @param[in] maxCharacters maximum number of characters to be accepted
+   */
+  void SetMaximumNumberOfCharacters( Length maxCharacters );
+
+  /**
+   * @brief Sets the maximum number of characters that can be inserted into the TextModel
+   *
+   * @param[in] maxCharacters maximum number of characters to be accepted
+   */
+  int GetMaximumNumberOfCharacters();
+
+  /**
+   * @brief Called to enable/disable cursor blink.
+   *
+   * @note Only editable controls should calls this.
+   * @param[in] enabled Whether the cursor should blink or not.
+   */
+  void SetEnableCursorBlink( bool enable );
+
+  /**
+   * @brief Query whether cursor blink is enabled.
+   *
+   * @return Whether the cursor should blink or not.
+   */
+  bool GetEnableCursorBlink() const;
+
+  /**
+   * @brief Whether to enable the multi-line layout.
+   *
+   * @param[in] enable \e true enables the multi-line (by default)
+   */
+  void SetMultiLineEnabled( bool enable );
+
+  /**
+   * @return Whether the multi-line layout is enabled.
+   */
+  bool IsMultiLineEnabled() const;
+
+  /**
+   * @brief Sets the text's horizontal alignment.
+   *
+   * @param[in] alignment The horizontal alignment.
+   */
+  void SetHorizontalAlignment( HorizontalAlignment::Type alignment );
+
+  /**
+   * @copydoc ModelInterface::GetHorizontalAlignment()
+   */
+  HorizontalAlignment::Type GetHorizontalAlignment() const;
+
+  /**
+   * @brief Sets the text's vertical alignment.
+   *
+   * @param[in] alignment The vertical alignment.
+   */
+  void SetVerticalAlignment( VerticalAlignment::Type alignment );
+
+  /**
+   * @copydoc ModelInterface::GetVerticalAlignment()
+   */
+  VerticalAlignment::Type GetVerticalAlignment() const;
+
+  /**
+   * @brief Sets the text's wrap mode
+   * @param[in] text wrap mode The unit of wrapping
+   */
+  void SetLineWrapMode( Text::LineWrap::Mode textWarpMode );
+
+  /**
+   * @brief Retrieve text wrap mode previously set.
+   * @return text wrap mode
+   */
+  Text::LineWrap::Mode GetLineWrapMode() const;
+
+  /**
+   * @brief Enable or disable the text elide.
+   *
+   * @param[in] enabled Whether to enable the text elide.
+   */
+  void SetTextElideEnabled( bool enabled );
+
+  /**
+   * @copydoc ModelInterface::IsTextElideEnabled()
+   */
+  bool IsTextElideEnabled() const;
+
+  /**
+   * @brief Enable or disable the text fit.
+   *
+   * @param[in] enabled Whether to enable the text fit.
+   */
+  void SetTextFitEnabled(bool enabled);
+
+  /**
+   * @brief Whether the text fit is enabled or not.
+   *
+   * @return True if the text fit is enabled
+   */
+  bool IsTextFitEnabled() const;
+
+  /**
+   * @brief Sets minimum size valid for text fit.
+   *
+   * @param[in] minimum size value.
+   * @param[in] type The font size type is point size or pixel size
+   */
+  void SetTextFitMinSize( float pointSize, FontSizeType type );
+
+  /**
+   * @brief Retrieves the minimum point size valid for text fit.
+   *
+   * @return The minimum point size valid for text fit
+   */
+  float GetTextFitMinSize() const;
+
+  /**
+   * @brief Sets maximum size valid for text fit.
+   *
+   * @param[in] maximum size value.
+   * @param[in] type The font size type is point size or pixel size
+   */
+  void SetTextFitMaxSize( float pointSize, FontSizeType type );
+
+  /**
+   * @brief Retrieves the maximum point size valid for text fit.
+   *
+   * @return The maximum point size valid for text fit
+   */
+  float GetTextFitMaxSize() const;
+
+  /**
+   * @brief Sets step size for font increase valid for text fit.
+   *
+   * @param[in] step size value.
+   * @param[in] type The font size type is point size or pixel size
+   */
+  void SetTextFitStepSize( float step, FontSizeType type );
+
+  /**
+   * @brief Retrieves the step point size valid for text fit.
+   *
+   * @return The step point size valid for text fit
+   */
+  float GetTextFitStepSize() const;
+
+  /**
+   * @brief Sets content size valid for text fit.
+   *
+   * @param[in] Content size value.
+   */
+  void SetTextFitContentSize(Vector2 size);
+
+  /**
+   * @brief Retrieves the content size valid for text fit.
+   *
+   * @return The content size valid for text fit
+   */
+  Vector2 GetTextFitContentSize() const;
+
+  /**
+   * @brief Enable or disable the placeholder text elide.
+   * @param enabled Whether to enable the placeholder text elide.
+   */
+  void SetPlaceholderTextElideEnabled( bool enabled );
+
+  /**
+   * @brief Whether the placeholder text elide property is enabled.
+   * @return True if the placeholder text elide property is enabled, false otherwise.
+   */
+  bool IsPlaceholderTextElideEnabled() const;
+
+  /**
+   * @brief Enable or disable the text selection.
+   * @param[in] enabled Whether to enable the text selection.
+   */
+  void SetSelectionEnabled( bool enabled );
+
+  /**
+   * @brief Whether the text selection is enabled or not.
+   * @return True if the text selection is enabled
+   */
+  bool IsSelectionEnabled() const;
+
+  /**
+   * @brief Enable or disable the text selection using Shift key.
+   * @param enabled Whether to enable the text selection using Shift key
+   */
+  void SetShiftSelectionEnabled( bool enabled );
+
+  /**
+   * @brief Whether the text selection using Shift key is enabled or not.
+   * @return True if the text selection using Shift key is enabled
+   */
+  bool IsShiftSelectionEnabled() const;
+
+  /**
+   * @brief Enable or disable the grab handles for text selection.
+   *
+   * @param[in] enabled Whether to enable the grab handles
+   */
+  void SetGrabHandleEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the grab handles are enabled.
+   *
+   * @return True if the grab handles are enabled
+   */
+  bool IsGrabHandleEnabled() const;
+
+  /**
+   * @brief Enable or disable the grab handles for text selection.
+   *
+   * @param[in] enabled Whether to enable the grab handles
+   */
+  void SetGrabHandlePopupEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the grab handles are enabled.
+   *
+   * @return True if the grab handles are enabled
+   */
+  bool IsGrabHandlePopupEnabled() const;
+
+  /**
+   * @brief Sets input type to password
+   *
+   * @note The string is displayed hidden character
+   *
+   * @param[in] passwordInput True if password input is enabled.
+   */
+  void SetInputModePassword( bool passwordInput );
+
+  /**
+   * @brief Returns whether the input mode type is set as password.
+   *
+   * @return True if input mode type is password
+   */
+  bool IsInputModePassword();
+
+  /**
+   * @brief Sets the action when there is a double tap event on top of a text area with no text.
+   *
+   * @param[in] action The action to do.
+   */
+  void SetNoTextDoubleTapAction( NoTextTap::Action action );
+
+  /**
+   * @brief Retrieves the action when there is a double tap event on top of a text area with no text.
+   *
+   * @return The action to do.
+   */
+  NoTextTap::Action GetNoTextDoubleTapAction() const;
+
+  /**
+   * @briefSets the action when there is a long press event on top of a text area with no text.
+   *
+   * @param[in] action The action to do.
+   */
+  void SetNoTextLongPressAction( NoTextTap::Action action );
+
+  /**
+   * @brief Retrieves the action when there is a long press event on top of a text area with no text.
+   *
+   * @return The action to do.
+   */
+  NoTextTap::Action GetNoTextLongPressAction() const;
+
+  /**
+   * @brief Query if Underline settings were provided by string or map
+   * @return bool true if set by string
+   */
+  bool IsUnderlineSetByString();
+
+  /**
+   * Set method underline setting were set by
+   * @param[in] bool, true if set by string
+   */
+  void UnderlineSetByString( bool setByString );
+
+  /**
+   * @brief Query if shadow settings were provided by string or map
+   * @return bool true if set by string
+   */
+  bool IsShadowSetByString();
+
+  /**
+   * Set method shadow setting were set by
+   * @param[in] bool, true if set by string
+   */
+  void ShadowSetByString( bool setByString );
+
+  /**
+   * @brief Query if outline settings were provided by string or map
+   * @return bool true if set by string
+   */
+  bool IsOutlineSetByString();
+
+  /**
+   * Set method outline setting were set by
+   * @param[in] bool, true if set by string
+   */
+  void OutlineSetByString( bool setByString );
+
+  /**
+   * @brief Query if font style settings were provided by string or map
+   * @return bool true if set by string
+   */
+  bool IsFontStyleSetByString();
+
+  /**
+   * Set method font style setting were set by
+   * @param[in] bool, true if set by string
+   */
+  void FontStyleSetByString( bool setByString );
+
+public: // Update.
+
+  /**
+   * @brief Replaces any text previously set.
+   *
+   * @note This will be converted into UTF-32 when stored in the text model.
+   * @param[in] text A string of UTF-8 characters.
+   */
+  void SetText( const std::string& text );
+
+  /**
+   * @brief Retrieve any text previously set.
+   *
+   * @param[out] text A string of UTF-8 characters.
+   */
+  void GetText( std::string& text ) const;
+
+  /**
+   * @brief Replaces any placeholder text previously set.
+   *
+   * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
+   * @param[in] text A string of UTF-8 characters.
+   */
+  void SetPlaceholderText( PlaceholderType type, const std::string& text );
+
+  /**
+   * @brief Retrieve any placeholder text previously set.
+   *
+   * @param[in] type Different placeholder-text can be shown when the control is active/inactive.
+   * @param[out] A string of UTF-8 characters.
+   */
+  void GetPlaceholderText( PlaceholderType type, std::string& text ) const;
+
+  /**
+   * @ brief Update the text after a font change
+   * @param[in] newDefaultFont The new font to change to
+   */
+  void UpdateAfterFontChange( const std::string& newDefaultFont );
+
+public: // Default style & Input style
+
+  /**
+   * @brief Set the default font family.
+   *
+   * @param[in] defaultFontFamily The default font family.
+   */
+  void SetDefaultFontFamily( const std::string& defaultFontFamily );
+
+  /**
+   * @brief Retrieve the default font family.
+   *
+   * @return The default font family.
+   */
+  const std::string& GetDefaultFontFamily() const;
+
+  /**
+   * @brief Sets the placeholder text font family.
+   * @param[in] placeholderTextFontFamily The placeholder text font family.
+   */
+  void SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily );
+
+  /**
+   * @brief Retrieves the placeholder text font family.
+   *
+   * @return The placeholder text font family
+   */
+  const std::string& GetPlaceholderFontFamily() const;
+
+  /**
+   * @brief Sets the default font weight.
+   *
+   * @param[in] weight The font weight.
+   */
+  void SetDefaultFontWeight( FontWeight weight );
+
+  /**
+   * @brief Whether the font's weight has been defined.
+   */
+  bool IsDefaultFontWeightDefined() const;
+
+  /**
+   * @brief Retrieves the default font weight.
+   *
+   * @return The default font weight.
+   */
+  FontWeight GetDefaultFontWeight() const;
+
+  /**
+   * @brief Sets the placeholder text font weight.
+   *
+   * @param[in] weight The font weight
+   */
+  void SetPlaceholderTextFontWeight( FontWeight weight );
+
+  /**
+   * @brief Whether the font's weight has been defined.
+   *
+   * @return True if the placeholder text font weight is defined
+   */
+  bool IsPlaceholderTextFontWeightDefined() const;
+
+  /**
+   * @brief Retrieves the placeholder text font weight.
+   *
+   * @return The placeholder text font weight
+   */
+  FontWeight GetPlaceholderTextFontWeight() const;
+
+  /**
+   * @brief Sets the default font width.
+   *
+   * @param[in] width The font width.
+   */
+  void SetDefaultFontWidth( FontWidth width );
+
+  /**
+   * @brief Whether the font's width has been defined.
+   */
+  bool IsDefaultFontWidthDefined() const;
+
+  /**
+   * @brief Retrieves the default font width.
+   *
+   * @return The default font width.
+   */
+  FontWidth GetDefaultFontWidth() const;
+
+  /**
+   * @brief Sets the placeholder text font width.
+   *
+   * @param[in] width The font width
+   */
+  void SetPlaceholderTextFontWidth( FontWidth width );
+
+  /**
+   * @brief Whether the font's width has been defined.
+   *
+   * @return True if the placeholder text font width is defined
+   */
+  bool IsPlaceholderTextFontWidthDefined() const;
+
+  /**
+   * @brief Retrieves the placeholder text font width.
+   *
+   * @return The placeholder text font width
+   */
+  FontWidth GetPlaceholderTextFontWidth() const;
+
+  /**
+   * @brief Sets the default font slant.
+   *
+   * @param[in] slant The font slant.
+   */
+  void SetDefaultFontSlant( FontSlant slant );
+
+  /**
+   * @brief Whether the font's slant has been defined.
+   */
+  bool IsDefaultFontSlantDefined() const;
+
+  /**
+   * @brief Retrieves the default font slant.
+   *
+   * @return The default font slant.
+   */
+  FontSlant GetDefaultFontSlant() const;
+
+  /**
+   * @brief Sets the placeholder text font slant.
+   *
+   * @param[in] slant The font slant
+   */
+  void SetPlaceholderTextFontSlant( FontSlant slant );
+
+  /**
+   * @brief Whether the font's slant has been defined.
+   *
+   * @return True if the placeholder text font slant is defined
+   */
+  bool IsPlaceholderTextFontSlantDefined() const;
+
+  /**
+   * @brief Retrieves the placeholder text font slant.
+   *
+   * @return The placeholder text font slant
+   */
+  FontSlant GetPlaceholderTextFontSlant() const;
+
+  /**
+   * @brief Set the default font size.
+   *
+   * @param[in] fontSize The default font size
+   * @param[in] type The font size type is point size or pixel size
+   */
+  void SetDefaultFontSize( float fontSize, FontSizeType type );
+
+  /**
+   * @brief Retrieve the default point size.
+   *
+   * @param[in] type The font size type
+   * @return The default point size.
+   */
+  float GetDefaultFontSize( FontSizeType type ) const;
+
+  /**
+   * @brief Sets the Placeholder text font size.
+   * @param[in] fontSize The placeholder text font size
+   * @param[in] type The font size type is point size or pixel size
+   */
+  void SetPlaceholderTextFontSize( float fontSize, FontSizeType type );
+
+  /**
+   * @brief Retrieves the Placeholder text font size.
+   * @param[in] type The font size type
+   * @return The placeholder font size
+   */
+  float GetPlaceholderTextFontSize( FontSizeType type ) const;
+
+  /**
+   * @brief Sets the text's default color.
+   *
+   * @param color The default color.
+   */
+  void SetDefaultColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the text's default color.
+   *
+   * @return The default color.
+   */
+  const Vector4& GetDefaultColor() const;
+
+  /**
+   * @brief Set the text color
+   *
+   * @param textColor The text color
+   */
+  void SetPlaceholderTextColor( const Vector4& textColor );
+
+  /**
+   * @brief Retrieve the text color
+   *
+   * @return The text color
+   */
+  const Vector4& GetPlaceholderTextColor() const;
+
+  /**
+   * @brief Set the shadow offset.
+   *
+   * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
+   */
+  void SetShadowOffset( const Vector2& shadowOffset );
+
+  /**
+   * @brief Retrieve the shadow offset.
+   *
+   * @return The shadow offset.
+   */
+  const Vector2& GetShadowOffset() const;
+
+  /**
+   * @brief Set the shadow color.
+   *
+   * @param[in] shadowColor The shadow color.
+   */
+  void SetShadowColor( const Vector4& shadowColor );
+
+  /**
+   * @brief Retrieve the shadow color.
+   *
+   * @return The shadow color.
+   */
+  const Vector4& GetShadowColor() const;
+
+  /**
+   * @brief Set the shadow blur radius.
+   *
+   * @param[in] shadowBlurRadius The shadow blur radius, 0,0 indicates no blur.
+   */
+  void SetShadowBlurRadius( const float& shadowBlurRadius );
+
+  /**
+   * @brief Retrieve the shadow blur radius.
+   *
+   * @return The shadow blur radius.
+   */
+  const float& GetShadowBlurRadius() const;
+
+  /**
+   * @brief Set the underline color.
+   *
+   * @param[in] color color of underline.
+   */
+  void SetUnderlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieve the underline color.
+   *
+   * @return The underline color.
+   */
+  const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @brief Set the underline enabled flag.
+   *
+   * @param[in] enabled The underline enabled flag.
+   */
+  void SetUnderlineEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the text is underlined or not.
+   *
+   * @return The underline state.
+   */
+  bool IsUnderlineEnabled() const;
+
+  /**
+   * @brief Set the override used for underline height, 0 indicates height will be supplied by font metrics
+   *
+   * @param[in] height The height in pixels of the underline
+   */
+  void SetUnderlineHeight( float height );
+
+  /**
+   * @brief Retrieves the override height of an underline, 0 indicates height is supplied by font metrics
+   *
+   * @return The height of the underline, or 0 if height is not overrided.
+   */
+  float GetUnderlineHeight() const;
+
+  /**
+   * @brief Set the outline color.
+   *
+   * @param[in] color color of outline.
+   */
+  void SetOutlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieve the outline color.
+   *
+   * @return The outline color.
+   */
+  const Vector4& GetOutlineColor() const;
+
+  /**
+   * @brief Set the outline width
+   *
+   * @param[in] width The width in pixels of the outline, 0 indicates no outline
+   */
+  void SetOutlineWidth( uint16_t width );
+
+  /**
+   * @brief Retrieves the width of an outline
+   *
+   * @return The width of the outline.
+   */
+  uint16_t GetOutlineWidth() const;
+
+  /**
+   * @brief Set the background color.
+   *
+   * @param[in] color color of background.
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+   * @brief Retrieve the background color.
+   *
+   * @return The background color.
+   */
+  const Vector4& GetBackgroundColor() const;
+
+  /**
+   * @brief Set the background enabled flag.
+   *
+   * @param[in] enabled The background enabled flag.
+   */
+  void SetBackgroundEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether to enable text background or not.
+   *
+   * @return Whether text background is enabled.
+   */
+  bool IsBackgroundEnabled() const;
+
+  /**
+   * @brief Sets the emboss's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] embossProperties The emboss's properties string.
+   */
+  void SetDefaultEmbossProperties( const std::string& embossProperties );
+
+  /**
+   * @brief Retrieves the emboss's properties string.
+   *
+   * @return The emboss's properties string.
+   */
+  const std::string& GetDefaultEmbossProperties() const;
+
+  /**
+   * @brief Sets the outline's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] outlineProperties The outline's properties string.
+   */
+  void SetDefaultOutlineProperties( const std::string& outlineProperties );
+
+  /**
+   * @brief Retrieves the outline's properties string.
+   *
+   * @return The outline's properties string.
+   */
+  const std::string& GetDefaultOutlineProperties() const;
+
+  /**
+   * @brief Sets the default line spacing.
+   *
+   * @param[in] lineSpacing The line spacing.
+   *
+   * @return True if lineSpacing has been updated, false otherwise
+   */
+  bool SetDefaultLineSpacing( float lineSpacing );
+
+  /**
+   * @brief Retrieves the default line spacing.
+   *
+   * @return The line spacing.
+   */
+  float GetDefaultLineSpacing() const;
+
+  /**
+   * @brief Sets the input text's color.
+   *
+   * @param[in] color The input text's color.
+   */
+  void SetInputColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the input text's color.
+   *
+   * @return The input text's color.
+   */
+  const Vector4& GetInputColor() const;
+
+  /**
+   * @brief Sets the input text's font family name.
+   *
+   * @param[in] fontFamily The text's font family name.
+   */
+  void SetInputFontFamily( const std::string& fontFamily );
+
+  /**
+   * @brief Retrieves the input text's font family name.
+   *
+   * @return The input text's font family name.
+   */
+  const std::string& GetInputFontFamily() const;
+
+  /**
+   * @brief Sets the input font's weight.
+   *
+   * @param[in] weight The input font's weight.
+   */
+  void SetInputFontWeight( FontWeight weight );
+
+  /**
+   * @return Whether the font's weight has been defined.
+   */
+  bool IsInputFontWeightDefined() const;
+
+  /**
+   * @brief Retrieves the input font's weight.
+   *
+   * @return The input font's weight.
+   */
+  FontWeight GetInputFontWeight() const;
+
+  /**
+   * @brief Sets the input font's width.
+   *
+   * @param[in] width The input font's width.
+   */
+  void SetInputFontWidth( FontWidth width );
+
+  /**
+   * @return Whether the font's width has been defined.
+   */
+  bool IsInputFontWidthDefined() const;
+
+  /**
+   * @brief Retrieves the input font's width.
+   *
+   * @return The input font's width.
+   */
+  FontWidth GetInputFontWidth() const;
+
+  /**
+   * @brief Sets the input font's slant.
+   *
+   * @param[in] slant The input font's slant.
+   */
+  void SetInputFontSlant( FontSlant slant );
+
+  /**
+   * @return Whether the font's slant has been defined.
+   */
+  bool IsInputFontSlantDefined() const;
+
+  /**
+   * @brief Retrieves the input font's slant.
+   *
+   * @return The input font's slant.
+   */
+  FontSlant GetInputFontSlant() const;
+
+  /**
+   * @brief Sets the input font's point size.
+   *
+   * @param[in] size The input font's point size.
+   */
+  void SetInputFontPointSize( float size );
+
+  /**
+   * @brief Retrieves the input font's point size.
+   *
+   * @return The input font's point size.
+   */
+  float GetInputFontPointSize() const;
+
+  /**
+   * @brief Sets the input line spacing.
+   *
+   * @param[in] lineSpacing The line spacing.
+   */
+  void SetInputLineSpacing( float lineSpacing );
+
+  /**
+   * @brief Retrieves the input line spacing.
+   *
+   * @return The line spacing.
+   */
+  float GetInputLineSpacing() const;
+
+  /**
+   * @brief Sets the input shadow's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] shadowProperties The shadow's properties string.
+   */
+  void SetInputShadowProperties( const std::string& shadowProperties );
+
+  /**
+   * @brief Retrieves the input shadow's properties string.
+   *
+   * @return The shadow's properties string.
+   */
+  const std::string& GetInputShadowProperties() const;
+
+  /**
+   * @brief Sets the input underline's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] underlineProperties The underline's properties string.
+   */
+  void SetInputUnderlineProperties( const std::string& underlineProperties );
+
+  /**
+   * @brief Retrieves the input underline's properties string.
+   *
+   * @return The underline's properties string.
+   */
+  const std::string& GetInputUnderlineProperties() const;
+
+  /**
+   * @brief Sets the input emboss's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] embossProperties The emboss's properties string.
+   */
+  void SetInputEmbossProperties( const std::string& embossProperties );
+
+  /**
+   * @brief Retrieves the input emboss's properties string.
+   *
+   * @return The emboss's properties string.
+   */
+  const std::string& GetInputEmbossProperties() const;
+
+  /**
+   * @brief Sets input the outline's properties string.
+   *
+   * @note The string is stored to be recovered.
+   *
+   * @param[in] outlineProperties The outline's properties string.
+   */
+  void SetInputOutlineProperties( const std::string& outlineProperties );
+
+  /**
+   * @brief Retrieves the input outline's properties string.
+   *
+   * @return The outline's properties string.
+   */
+  const std::string& GetInputOutlineProperties() const;
+
+  /**
+   * @brief Set the control's interface.
+   *
+   * @param[in] controlInterface The control's interface.
+   */
+  void SetControlInterface( ControlInterface* controlInterface );
+
+public: // Queries & retrieves.
+
+  /**
+   * @brief Return the layout engine.
+   *
+   * @return A reference to the layout engine.
+   */
+  Layout::Engine& GetLayoutEngine();
+
+  /**
+   * @brief Return a view of the text.
+   *
+   * @return A reference to the view.
+   */
+  View& GetView();
+
+  /**
+   * @copydoc Control::GetNaturalSize()
+   */
+  Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc Control::GetHeightForWidth()
+   */
+  float GetHeightForWidth( float width );
+
+  /**
+   * @brief Calculates the point size for text for given layout()
+   */
+  void FitPointSizeforLayout( Size layoutSize );
+
+  /**
+   * @brief Checks if the point size fits within the layout size.
+   *
+   * @return Whether the point size fits within the layout size.
+   */
+  bool CheckForTextFit( float pointSize, Size& layoutSize );
+
+  /**
+   * @brief Retrieves the text's number of lines for a given width.
+   * @param[in] width The width of the text's area.
+   * @ return The number of lines.
+   */
+  int GetLineCount( float width );
+
+  /**
+   * @brief Retrieves the text's model.
+   *
+   * @return A pointer to the text's model.
+   */
+  const ModelInterface* const GetTextModel() const;
+
+  /**
+   * @brief Used to get scrolled distance by user input
+   *
+   * @return Distance from last scroll offset to new scroll offset
+   */
+  float GetScrollAmountByUserInput();
+
+  /**
+   * @brief Get latest scroll amount, control size and layout size
+   *
+   * This method is used to get information of control's scroll
+   * @param[out] scrollPosition The current scrolled position
+   * @param[out] controlHeight The size of a UI control
+   * @param[out] layoutHeight The size of a bounding box to layout text within.
+   *
+   * @return Whether the text scroll position is changed or not after last update.
+   */
+  bool GetTextScrollInfo( float& scrollPosition, float& controlHeight, float& layoutHeight );
+
+  /**
+   * @brief Used to set the hidden input option
+   */
+  void SetHiddenInputOption( const Property::Map& options );
+
+  /**
+   * @brief Used to get the hidden input option
+   */
+  void GetHiddenInputOption( Property::Map& options );
+
+  /**
+   * @brief Sets the Placeholder Properties.
+   *
+   * @param[in] map The placeholder property map
+   */
+  void SetPlaceholderProperty( const Property::Map& map );
+
+  /**
+   * @brief Retrieves the Placeholder Property map.
+   *
+   * @param[out] map The property map
+   */
+  void GetPlaceholderProperty( Property::Map& map );
+
+  /**
+   * @brief Checks text direction.
+   * @return The text direction.
+   */
+  Toolkit::DevelText::TextDirection::Type GetTextDirection();
+
+  /**
+   * @brief Retrieves vertical line alignment
+   * @return The vertical line alignment
+   */
+  Toolkit::DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const;
+
+  /**
+   * @brief Sets vertical line alignment
+   * @param[in] alignment The vertical line alignment for the text
+   */
+  void SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment );
+
+  /**
+   * @brief Retrieves ignoreSpaceAfterText value from model
+   * @return The value of ignoreSpaceAfterText
+   */
+  bool IsIgnoreSpacesAfterText() const;
+
+  /**
+   * @brief Sets ignoreSpaceAfterText value to model
+   * @param[in] ignore The value of ignoreSpacesAfterText for the text
+   */
+  void SetIgnoreSpacesAfterText( bool ignore );
+
+  /**
+   * @brief Retrieves matchSystemLanguageDirection value from model
+   * @return The value of matchSystemLanguageDirection
+   */
+  bool IsMatchSystemLanguageDirection() const;
+
+  /**
+   * @brief Sets matchSystemLanguageDirection value to model
+   * @param[in] match The value of matchSystemLanguageDirection for the text
+   */
+  void SetMatchSystemLanguageDirection( bool match );
+
+  /**
+   * @brief Sets layoutDirection value
+   * @param[in] layoutDirection The value of system language direction
+   */
+  void SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection );
+
+  /**
+   * @brief Retrieves if showing real text or not.
+   * @return The value of showing real text.
+   */
+  bool IsShowingRealText() const;
+
+public: // Relayout.
+
+  /**
+   * @brief Triggers a relayout which updates View (if necessary).
+   *
+   * @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation.
+   * @param[in] size A the size of a bounding box to layout text within.
+   * @param[in] layoutDirection The direction of the system language.
+   *
+   * @return Whether the text model or decorations were updated.
+   */
+  UpdateTextType Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection = Dali::LayoutDirection::LEFT_TO_RIGHT );
+
+  /**
+   * @brief Request a relayout using the ControlInterface.
+   */
+  void RequestRelayout();
+
+public: // Input style change signals.
+
+  /**
+   * @return Whether the queue of input style changed signals is empty.
+   */
+  bool IsInputStyleChangedSignalsQueueEmpty();
+
+  /**
+   * @brief Process all pending input style changed signals.
+   *
+   * Calls the Text::ControlInterface::InputStyleChanged() method which is overriden by the
+   * text controls. Text controls may send signals to state the input style has changed.
+   */
+  void ProcessInputStyleChangedSignals();
+
+public: // Text-input Event Queuing.
+
+  /**
+   * @brief Called by editable UI controls when keyboard focus is gained.
+   */
+  void KeyboardFocusGainEvent();
+
+  /**
+   * @brief Called by editable UI controls when focus is lost.
+   */
+  void KeyboardFocusLostEvent();
+
+  /**
+   * @brief Called by editable UI controls when key events are received.
+   *
+   * @param[in] event The key event.
+   * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
+   */
+  bool KeyEvent( const Dali::KeyEvent& event );
+
+  /**
+   * @brief Called by editable UI controls when a tap gesture occurs.
+   * @param[in] tapCount The number of taps.
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   */
+  void TapEvent( unsigned int tapCount, float x, float y );
+
+  /**
+   * @brief Called by editable UI controls when a pan gesture occurs.
+   *
+   * @param[in] state The state of the gesture.
+   * @param[in] displacement This distance panned since the last pan gesture.
+   */
+  void PanEvent( Gesture::State state, const Vector2& displacement );
+
+  /**
+   * @brief Called by editable UI controls when a long press gesture occurs.
+   *
+   * @param[in] state The state of the gesture.
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   */
+  void LongPressEvent( Gesture::State state, float x, float y );
+
+  /**
+   * @brief Creates a selection event.
+   *
+   * It could be called from the TapEvent (double tap) or when the text selection popup's sellect all button is pressed.
+   *
+   * @param[in] x The x position relative to the top-left of the parent control.
+   * @param[in] y The y position relative to the top-left of the parent control.
+   * @param[in] selectAll Whether the whole text is selected.
+   */
+  void SelectEvent( float x, float y, bool selectAll );
+
+  /**
+   * @brief Event received from input method context
+   *
+   * @param[in] inputMethodContext The input method context.
+   * @param[in] inputMethodContextEvent The event received.
+   * @return A data struture indicating if update is needed, cursor position and current text.
+   */
+  InputMethodContext::CallbackData OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent );
+
+  /**
+   * @brief Event from Clipboard notifying an Item has been selected for pasting
+   */
+  void PasteClipboardItemEvent();
+
+  /**
+   * @brief Return true when text control should clear key input focus when escape key is pressed.
+   *
+   * @return Whether text control should clear key input focus or not when escape key is pressed.
+   */
+  bool ShouldClearFocusOnEscape() const;
+
+  /**
+   * @brief Create an actor that renders the text background color
+   *
+   * @return the created actor or an empty handle if no background color needs to be rendered.
+   */
+  Actor CreateBackgroundActor();
+
+protected: // Inherit from Text::Decorator::ControllerInterface.
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::GetTargetSize()
+   */
+  virtual void GetTargetSize( Vector2& targetSize );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::AddDecoration()
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::Decorator::ControllerInterface::DecorationEvent()
+   */
+  virtual void DecorationEvent( HandleType handle, HandleState state, float x, float y );
+
+protected: // Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
+
+  /**
+   * @copydoc Dali::Toolkit::TextSelectionPopup::TextPopupButtonCallbackInterface::TextPopupButtonTouched()
+   */
+  virtual void TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button );
+
+protected: // Inherit from HiddenText.
+
+  /**
+   * @brief Invoked from HiddenText when showing time of the last character was expired
+   */
+  virtual void DisplayTimeExpired();
+
+private: // Update.
+
+  /**
+   * @brief Called by editable UI controls when key events are received.
+   *
+   * @param[in] text The text to insert.
+   * @param[in] type Used to distinguish between regular key events and InputMethodContext events.
+   */
+  void InsertText( const std::string& text, InsertType type );
+
+  /**
+   * @brief Paste given string into Text model
+   * @param[in] stringToPaste this string will be inserted into the text model
+   */
+  void PasteText( const std::string& stringToPaste );
+
+  /**
+   * @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,
+                   UpdateInputStyleType type  );
+
+  /**
+   * @brief Checks if text is selected and if so removes it.
+   * @return true if text was removed
+   */
+  bool RemoveSelectedText();
+
+private: // Relayout.
+
+  /**
+   * @brief Lays-out the text.
+   *
+   * GetNaturalSize(), GetHeightForWidth() and Relayout() calls this method.
+   *
+   * @param[in] size A the size of a bounding box to layout text within.
+   * @param[in] operations The layout operations which need to be done.
+   * @param[out] layoutSize The size of the laid-out text.
+   */
+  bool DoRelayout( const Size& size,
+                   OperationsMask operations,
+                   Size& layoutSize );
+
+  /**
+   * @brief Calulates the vertical offset to align the text inside the bounding box.
+   *
+   * @param[in] size The size of the bounding box.
+   */
+  void CalculateVerticalOffset( const Size& size );
+
+private: // Events.
+
+  /**
+   * @brief Process queued events which modify the model.
+   */
+  void ProcessModifyEvents();
+
+  /**
+   * @brief Used to process an event queued from SetText()
+   */
+  void TextReplacedEvent();
+
+  /**
+   * @brief Used to process an event queued from key events etc.
+   */
+  void TextInsertedEvent();
+
+  /**
+   * @brief Used to process an event queued from backspace key etc.
+   */
+  void TextDeletedEvent();
+
+  /**
+   * @brief Helper to KeyEvent() to handle the backspace or delete key case.
+   *
+   * @param[in] keyCode The keycode for the key pressed
+   * @return True if a character was deleted.
+   */
+  bool DeleteEvent( int keyCode );
+
+private: // Helpers.
+
+  /**
+   * @brief Used to remove the text included the placeholder text.
+   */
+  void ResetText();
+
+  /**
+   * @brief Helper to show the place holder text..
+   */
+  void ShowPlaceholderText();
+
+  /**
+   * @brief Helper to clear font-specific data (only).
+   */
+  void ClearFontData();
+
+  /**
+   * @brief Helper to clear text's style data.
+   */
+  void ClearStyleData();
+
+  /**
+   * @brief Used to reset the cursor position after setting a new text.
+   *
+   * @param[in] cursorIndex Where to place the cursor.
+   */
+  void ResetCursorPosition( CharacterIndex cursorIndex );
+
+  /**
+   * @brief Used to reset the scroll position after setting a new text.
+   */
+  void ResetScrollPosition();
+
+private: // Private contructors & copy operator.
+
+  /**
+   * @brief Private constructor.
+   */
+  Controller();
+
+  /**
+   * @brief Private constructor.
+   */
+  Controller( ControlInterface* controlInterface );
+
+  /**
+   * @brief Private constructor.
+   */
+  Controller( ControlInterface* controlInterface,
+              EditableControlInterface* editableControlInterface );
+
+  // Undefined
+  Controller( const Controller& handle );
+
+  // Undefined
+  Controller& operator=( const Controller& handle );
+
+protected: // Destructor.
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Controller();
+
+public:
+
+  struct Impl; ///< Made public for testing purposes
+
+private:
+
+  Impl* mImpl;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_H
diff --git a/dali-toolkit/internal/text/text-definitions.h b/dali-toolkit/internal/text/text-definitions.h
new file mode 100755 (executable)
index 0000000..6ea207b
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DALI_TEXT_ABSTRACTION_TEXT_TYPE_DEFINITIONS_H
+#define DALI_TEXT_ABSTRACTION_TEXT_TYPE_DEFINITIONS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/devel-api/text-abstraction/font-list.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>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+typedef TextAbstraction::FontId             FontId;             ///< The unique identifier for a font face (generated by FontClient).
+typedef TextAbstraction::FontWidth::Type    FontWidth;          ///< The font's width.
+typedef TextAbstraction::FontWeight::Type   FontWeight;         ///< The font's weight.
+typedef TextAbstraction::FontSlant::Type    FontSlant;          ///< The font's slant.
+typedef TextAbstraction::FontMetrics        FontMetrics;        ///< The metrics for a Font expressed in 26.6 fractional pixel format.
+typedef TextAbstraction::PointSize26Dot6    PointSize26Dot6;    ///< The point size in 26.6 fractional points.
+typedef TextAbstraction::FaceIndex          FaceIndex;          ///< Used with fonts which allow several font faces.
+typedef TextAbstraction::GlyphIndex         GlyphIndex;         ///< Uniquely identifies a glyph within a particular font.
+typedef TextAbstraction::Character          Character;          ///< A UTF-32 representation of a character.
+typedef TextAbstraction::GlyphInfo          GlyphInfo;          ///< The information describing a glyph (font ID, index, metrics).
+typedef TextAbstraction::CharacterIndex     CharacterIndex;     ///< An index into an array of characters.
+typedef TextAbstraction::Length             Length;             ///< The length of an array.
+typedef TextAbstraction::BidiInfoIndex      BidiInfoIndex;      ///< Index to the bidirectional info for a paragraph.
+typedef TextAbstraction::Script             Script;             ///< The character's script.
+typedef TextAbstraction::LineBreakInfo      LineBreakInfo;      ///< Line break info (must break, allow break, no break). Possible values are: @e LINE_MUST_BREAK, @e LINE_ALLOW_BREAK and @e LINE_NO_BREAK (in the TextAbstraction namespace).
+typedef TextAbstraction::WordBreakInfo      WordBreakInfo;      ///< Word break info (break, no break). Possible values are: @e WORD_BREAK and @e WORD_NO_BREAK (in the TextAbstraction namespace).
+typedef TextAbstraction::CharacterDirection CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
+typedef TextAbstraction::ColorBlendingMode  ColorBlendingMode;  ///< Defines how a color is blended.
+typedef TextAbstraction::ColorIndex         ColorIndex;         ///< An index into an array of colors.
+
+typedef uint32_t                         GlyphIndex;                ///< An index into an array of glyphs.
+typedef uint32_t                         ScriptRunIndex;            ///< An index into an array of script runs.
+typedef uint32_t                         FontRunIndex;              ///< An index into an array of font runs.
+typedef uint32_t                         UnderlineRunIndex;         ///< An index into an array of underline runs.
+typedef uint32_t                         BidirectionalRunIndex;     ///< An index into an array of bidirectional info.
+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.
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_TEXT_TYPE_DEFINITIONS_H
diff --git a/dali-toolkit/internal/text/text-editable-control-interface.h b/dali-toolkit/internal/text/text-editable-control-interface.h
new file mode 100644 (file)
index 0000000..e54704c
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef DALI_TOOLKIT_TEXT_EDITABLE_CONTROL_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_EDITABLE_CONTROL_INTERFACE_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
+
+namespace Dali
+{
+
+class Actor;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief An interface that the Text::Controller uses to notify about text changes and add decoration to the text control.
+ */
+class EditableControlInterface
+{
+public:
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~EditableControlInterface()
+  {}
+
+  /**
+   * @brief Called to signal that text has been inserted or deleted.
+   */
+  virtual void TextChanged() = 0;
+
+  /**
+   * @brief Called when the number of characters to be inserted exceeds the maximum limit
+   */
+  virtual void MaxLengthReached() = 0;
+
+  /**
+   * @brief Called to signal that input style has been changed.
+   *
+   * @param[in] inputStyleMask Mask with the bits of the input style that has changed.
+   */
+  virtual void InputStyleChanged( InputStyle::Mask inputStyleMask ) = 0;
+
+  /**
+   * @brief Add a decoration.
+   *
+   * @param[in] decoration The actor displaying a decoration.
+   * @param[in] needsClipping Whether the actor needs clipping.
+   */
+  virtual void AddDecoration( Actor& actor, bool needsClipping ) = 0;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_EDITABLE_CONTROL_INTERFACE_H
diff --git a/dali-toolkit/internal/text/text-effects-style.cpp b/dali-toolkit/internal/text/text-effects-style.cpp
new file mode 100755 (executable)
index 0000000..d5f8ff1
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/text-effects-style.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/property-string-parser.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string COLOR_KEY( "color" );
+const std::string OFFSET_KEY( "offset" );
+const std::string BLUR_RADIUS_KEY( "blurRadius" );
+const std::string WIDTH_KEY( "width" );
+const std::string HEIGHT_KEY( "height" );
+const std::string ENABLE_KEY( "enable" );
+const std::string TRUE_TOKEN( "true" );
+const std::string FALSE_TOKEN( "false" );
+}
+
+bool ParseShadowProperties( const Property::Map& shadowPropertiesMap,
+                            bool& colorDefined,
+                            Vector4& color,
+                            bool& offsetDefined,
+                            Vector2& offset,
+                            bool& blurRadiusDefined,
+                            float& blurRadius )
+{
+  const unsigned int numberOfItems = shadowPropertiesMap.Count();
+
+  // Parses and applies the style.
+  for( unsigned int index = 0u; index < numberOfItems; ++index )
+  {
+    const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue( index );
+
+    if( ( DevelText::Shadow::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
+    {
+      /// Color key.
+      colorDefined = true;
+
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string colorStr = valueGet.second.Get<std::string>();
+        Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
+      }
+      else
+      {
+        color = valueGet.second.Get<Vector4>();
+      }
+    }
+    else if( ( DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey ) || ( OFFSET_KEY == valueGet.first.stringKey ) )
+    {
+      /// Offset key.
+      offsetDefined = true;
+
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string offsetStr = valueGet.second.Get<std::string>();
+        StringToVector2( offsetStr.c_str(), offsetStr.size(), offset );
+      }
+      else
+      {
+        offset = valueGet.second.Get<Vector2>();
+      }
+    }
+    else if( ( DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey ) || ( BLUR_RADIUS_KEY == valueGet.first.stringKey ) )
+    {
+      /// Blur radius key.
+      blurRadiusDefined = true;
+
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string blurRadiusStr = valueGet.second.Get<std::string>();
+        blurRadius = StringToFloat( blurRadiusStr.c_str() );
+      }
+      else
+      {
+        blurRadius = valueGet.second.Get<float>();
+      }
+    }
+  }
+
+  return 0u == numberOfItems;
+}
+
+bool ParseUnderlineProperties( const Property::Map& underlinePropertiesMap,
+                               bool& enabled,
+                               bool& colorDefined,
+                               Vector4& color,
+                               bool& heightDefined,
+                               float& height )
+{
+  const unsigned int numberOfItems = underlinePropertiesMap.Count();
+
+  // Parses and applies the style.
+  for( unsigned int index = 0u; index < numberOfItems; ++index )
+  {
+    const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
+
+    if( ( DevelText::Underline::Property::ENABLE == valueGet.first.indexKey ) || ( ENABLE_KEY == valueGet.first.stringKey ) )
+    {
+      /// Enable key.
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string enableStr = valueGet.second.Get<std::string>();
+        enabled = Text::TokenComparison( TRUE_TOKEN, enableStr.c_str(), enableStr.size() );
+      }
+      else
+      {
+        enabled = valueGet.second.Get<bool>();
+      }
+    }
+    else if( ( DevelText::Underline::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
+    {
+      /// Color key.
+      colorDefined = true;
+
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string colorStr = valueGet.second.Get<std::string>();
+        Text::ColorStringToVector4( colorStr.c_str(), colorStr.size(), color );
+      }
+      else
+      {
+        color = valueGet.second.Get<Vector4>();
+      }
+    }
+    else if( ( DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey ) || ( HEIGHT_KEY == valueGet.first.stringKey ) )
+    {
+      /// Height key.
+      heightDefined = true;
+
+      if( valueGet.second.GetType() == Dali::Property::STRING )
+      {
+        const std::string heightStr = valueGet.second.Get<std::string>();
+        height = StringToFloat( heightStr.c_str() );
+      }
+      else
+      {
+        height = valueGet.second.Get<float>();
+      }
+    }
+  }
+
+  return 0u == numberOfItems;
+}
+
+bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap,
+                               bool& colorDefined,
+                               Vector4& color,
+                               bool& widthDefined,
+                               uint16_t& width )
+{
+  const unsigned int numberOfItems = underlinePropertiesMap.Count();
+
+  // Parses and applies the style.
+  for( unsigned int index = 0u; index < numberOfItems; ++index )
+  {
+    const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue( index );
+
+    if( ( DevelText::Outline::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
+    {
+      /// Color key.
+      colorDefined = true;
+      color = valueGet.second.Get<Vector4>();
+    }
+    else if( ( DevelText::Outline::Property::WIDTH == valueGet.first.indexKey ) || ( WIDTH_KEY == valueGet.first.stringKey ) )
+    {
+      /// Width key.
+      widthDefined = true;
+      width = static_cast<uint16_t>( valueGet.second.Get<float>() );
+    }
+  }
+
+  return 0u == numberOfItems;
+}
+
+bool ParseBackgroundProperties( const Property::Map& backgroundProperties,
+                                bool& enabled,
+                                bool& colorDefined,
+                                Vector4& color )
+{
+  const unsigned int numberOfItems = backgroundProperties.Count();
+
+  // Parses and applies the style.
+  for( unsigned int index = 0u; index < numberOfItems; ++index )
+  {
+    const KeyValuePair& valueGet = backgroundProperties.GetKeyValue( index );
+
+    if( ( DevelText::Background::Property::ENABLE == valueGet.first.indexKey ) || ( ENABLE_KEY == valueGet.first.stringKey ) )
+    {
+      /// Enable key.
+      enabled = valueGet.second.Get<bool>();
+    }
+    else if( ( DevelText::Background::Property::COLOR == valueGet.first.indexKey ) || ( COLOR_KEY == valueGet.first.stringKey ) )
+    {
+      /// Color key.
+      colorDefined = true;
+      color = valueGet.second.Get<Vector4>();
+    }
+  }
+
+  return 0u == numberOfItems;
+}
+
+bool SetUnderlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
+{
+  bool update = false;
+
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+        bool enabled = false;
+        bool colorDefined = false;
+        Vector4 color;
+        bool heightDefined = false;
+        float height = 0.f;
+
+        bool empty = true;
+
+        if ( propertiesMap.Empty() )
+        {
+          // Map empty so check if a string provided
+          const std::string propertyString = value.Get<std::string>();
+
+          if ( !propertyString.empty() )
+          {
+            Property::Map parsedStringMap;
+            Text::ParsePropertyString( propertyString, parsedStringMap );
+
+            empty = ParseUnderlineProperties( parsedStringMap,
+                                              enabled,
+                                              colorDefined,
+                                              color,
+                                              heightDefined,
+                                              height );
+
+            controller->UnderlineSetByString( !empty );
+          }
+        }
+        else
+        {
+           empty = ParseUnderlineProperties( propertiesMap,
+                                             enabled,
+                                             colorDefined,
+                                             color,
+                                             heightDefined,
+                                             height );
+
+           controller->UnderlineSetByString( false );
+        }
+
+        if( !empty )
+        {
+          if( enabled != controller->IsUnderlineEnabled() )
+          {
+            controller->SetUnderlineEnabled( enabled );
+            update = true;
+          }
+
+          // Sets the default underline values.
+          if( colorDefined && ( controller->GetUnderlineColor() != color ) )
+          {
+            controller->SetUnderlineColor( color );
+            update = true;
+          }
+
+          if( heightDefined && ( fabsf( controller->GetUnderlineHeight() - height ) > Math::MACHINE_EPSILON_1000 ) )
+          {
+            controller->SetUnderlineHeight( height );
+            update = true;
+          }
+        }
+        else
+        {
+          // Disable underline.
+          if( controller->IsUnderlineEnabled() )
+          {
+            controller->SetUnderlineEnabled( false );
+            update = true;
+          }
+        }
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        const std::string& underlineProperties = value.Get<std::string>();
+
+        controller->SetInputUnderlineProperties( underlineProperties );
+        break;
+      }
+    } // switch
+  } // if( controller )
+
+  return update;
+}
+
+void GetUnderlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
+{
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const bool enabled = controller->IsUnderlineEnabled();
+        const Vector4& color = controller->GetUnderlineColor();
+        const float height = controller->GetUnderlineHeight();
+
+        if ( controller->IsUnderlineSetByString() )
+        {
+          std::string underlineProperties = "{\"enable\":";
+          const std::string enabledStr = enabled ? "true" : "false";
+          underlineProperties += "\"" + enabledStr + "\",";
+
+          std::string colorStr;
+          Vector4ToColorString( color, colorStr );
+          underlineProperties += "\"color\":\"" + colorStr + "\",";
+
+          std::string heightStr;
+          FloatToString( height, heightStr );
+          underlineProperties += "\"height\":\"" + heightStr + "\"}";
+
+          value = underlineProperties;
+        }
+        else
+        {
+          Property::Map map;
+
+          map.Insert( ENABLE_KEY, enabled );
+          map.Insert( COLOR_KEY, color );
+          map.Insert( HEIGHT_KEY, height );
+
+          value = map;
+        }
+
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        value = controller->GetInputUnderlineProperties();
+        break;
+      }
+    }
+  }
+}
+
+bool SetShadowProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
+{
+  bool update = false;
+
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+        bool colorDefined = false;
+        Vector4 color;
+        bool offsetDefined = false;
+        Vector2 offset;
+        bool blurRadiusDefined = false;
+        float blurRadius;
+
+        bool empty = true;
+
+        if ( propertiesMap.Empty() )
+        {
+           // Map empty so check if a string provided
+           const std::string propertyString = value.Get<std::string>();
+
+           Property::Map parsedStringMap;
+           Text::ParsePropertyString( propertyString, parsedStringMap );
+
+           empty = ParseShadowProperties( parsedStringMap,
+                                          colorDefined,
+                                          color,
+                                          offsetDefined,
+                                          offset,
+                                          blurRadiusDefined,
+                                          blurRadius );
+
+           controller->ShadowSetByString( !empty );
+
+        }
+        else
+        {
+          empty = ParseShadowProperties( propertiesMap,
+                                         colorDefined,
+                                         color,
+                                         offsetDefined,
+                                         offset,
+                                         blurRadiusDefined,
+                                         blurRadius );
+
+          controller->ShadowSetByString( false );
+        }
+
+        if( !empty )
+        {
+          // Sets the default shadow values.
+          if( colorDefined && ( controller->GetShadowColor() != color ) )
+          {
+            controller->SetShadowColor( color );
+            update = true;
+          }
+
+          if( offsetDefined && ( controller->GetShadowOffset() != offset ) )
+          {
+            controller->SetShadowOffset( offset );
+            update = true;
+          }
+
+          if( blurRadiusDefined && ( controller->GetShadowBlurRadius() != blurRadius ) )
+          {
+            controller->SetShadowBlurRadius( blurRadius );
+            update = true;
+          }
+        }
+        else
+        {
+          // Disable shadow.
+          if( Vector2::ZERO != controller->GetShadowOffset() )
+          {
+            controller->SetShadowOffset( Vector2::ZERO );
+          }
+        }
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        const std::string& shadowString = value.Get<std::string>();
+
+        controller->SetInputShadowProperties( shadowString );
+        break;
+      }
+    } // switch
+  } // if( controller )
+
+  return update;
+}
+
+void GetShadowProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
+{
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const Vector4& color = controller->GetShadowColor();
+        const Vector2& offset = controller->GetShadowOffset();
+        const float& blurRadius = controller->GetShadowBlurRadius();
+
+        if ( controller->IsShadowSetByString() )
+        {
+          std::string shadowProperties = "{";
+
+          std::string colorStr;
+          Vector4ToColorString( color, colorStr );
+          shadowProperties += "\"color\":\"" + colorStr + "\",";
+
+          std::string offsetStr;
+          Vector2ToString( offset, offsetStr );
+          shadowProperties += "\"offset\":\"" + offsetStr + "\",";
+
+          std::string blurRadiusStr;
+          FloatToString( blurRadius, blurRadiusStr );
+          shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
+
+          value = shadowProperties;
+        }
+        else
+        {
+          Property::Map map;
+
+          map.Insert( COLOR_KEY, color );
+          map.Insert( OFFSET_KEY, offset );
+          map.Insert( BLUR_RADIUS_KEY, blurRadius );
+
+          value = map;
+        }
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        value = controller->GetInputShadowProperties();
+        break;
+      }
+    }
+  }
+}
+
+bool SetEmbossProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
+{
+  bool update = false;
+
+  if( controller )
+  {
+    const std::string properties = value.Get< std::string >();
+
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
+        controller->SetDefaultEmbossProperties( properties );
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
+        controller->SetInputEmbossProperties( properties );
+        break;
+      }
+    }
+  }
+
+  return update;
+}
+
+void GetEmbossProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
+{
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        value = controller->GetDefaultEmbossProperties();
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        value = controller->GetInputEmbossProperties();
+        break;
+      }
+    }
+  }
+}
+
+bool SetOutlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
+{
+  bool update = false;
+
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+        bool colorDefined = false;
+        Vector4 color;
+        bool widthDefined = false;
+        uint16_t width = 0u;
+
+        bool empty = true;
+
+        if ( propertiesMap.Empty() )
+        {
+           // Map empty so check if a string provided
+           // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
+           const std::string propertyString = value.Get<std::string>();
+
+           // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
+           controller->SetDefaultOutlineProperties( propertyString );
+
+           controller->OutlineSetByString( true );
+        }
+        else
+        {
+           empty = ParseOutlineProperties( propertiesMap,
+                                           colorDefined,
+                                           color,
+                                           widthDefined,
+                                           width );
+
+           controller->OutlineSetByString( false );
+        }
+
+        if( !empty )
+        {
+          // Sets the default outline values.
+          if( colorDefined && ( controller->GetOutlineColor() != color ) )
+          {
+            controller->SetOutlineColor( color );
+            update = true;
+          }
+
+          if( widthDefined && ( controller->GetOutlineWidth() != width ) )
+          {
+            controller->SetOutlineWidth( width );
+            update = true;
+          }
+        }
+        else
+        {
+          // Disable outline
+          if( 0u != controller->GetOutlineWidth() )
+          {
+            controller->SetOutlineWidth( 0u );
+            update = true;
+          }
+        }
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        const std::string& outlineProperties = value.Get<std::string>();
+
+        controller->SetInputOutlineProperties( outlineProperties );
+        break;
+      }
+    } // switch
+  } // if( controller )
+
+  return update;
+}
+
+void GetOutlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
+{
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        if ( controller->IsOutlineSetByString() )
+        {
+          value = controller->GetDefaultOutlineProperties();
+          break;
+        }
+        else
+        {
+          const Vector4& color = controller->GetOutlineColor();
+          const uint16_t width = controller->GetOutlineWidth();
+
+          Property::Map map;
+          map.Insert( COLOR_KEY, color );
+          map.Insert( WIDTH_KEY, static_cast<int>( width ) );
+
+          value = map;
+
+          break;
+        }
+      }
+      case EffectStyle::INPUT:
+      {
+        value = controller->GetInputOutlineProperties();
+        break;
+      }
+    }
+  }
+}
+
+bool SetBackgroundProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type )
+{
+  bool update = false;
+
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const Property::Map& propertiesMap = value.Get<Property::Map>();
+
+        bool enabled = false;
+        bool colorDefined = false;
+        Vector4 color;
+
+        bool empty = true;
+
+        if ( !propertiesMap.Empty() )
+        {
+           empty = ParseBackgroundProperties( propertiesMap,
+                                              enabled,
+                                              colorDefined,
+                                              color );
+        }
+
+        if( !empty )
+        {
+          if( enabled != controller->IsBackgroundEnabled() )
+          {
+            controller->SetBackgroundEnabled( enabled );
+            update = true;
+          }
+
+          if( colorDefined && ( controller->GetBackgroundColor() != color ) )
+          {
+            controller->SetBackgroundColor( color );
+            update = true;
+          }
+        }
+        else
+        {
+          // Disable background.
+          if( controller->IsBackgroundEnabled() )
+          {
+            controller->SetBackgroundEnabled( false );
+            update = true;
+          }
+        }
+        break;
+      }
+      case EffectStyle::INPUT:
+      {
+        // Text background is not supported while inputting yet
+        break;
+      }
+    } // switch
+  } // if( controller )
+
+  return update;
+}
+
+void GetBackgroundProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type )
+{
+  if( controller )
+  {
+    switch( type )
+    {
+      case EffectStyle::DEFAULT:
+      {
+        const bool enabled = controller->IsBackgroundEnabled();
+        const Vector4& color = controller->GetBackgroundColor();
+
+        Property::Map map;
+        map.Insert( ENABLE_KEY, enabled );
+        map.Insert( COLOR_KEY, color );
+
+        value = map;
+
+        break;
+
+      }
+      case EffectStyle::INPUT:
+      {
+        // Text background is not supported while inputting yet
+        break;
+      }
+    }
+  }
+}
+
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-effects-style.h b/dali-toolkit/internal/text/text-effects-style.h
new file mode 100755 (executable)
index 0000000..a64d26f
--- /dev/null
@@ -0,0 +1,209 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_EFFECTS_STYLE_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_EFFECTS_STYLE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace EffectStyle
+{
+  enum Type
+  {
+    DEFAULT, ///< The default text effect style.
+    INPUT    ///< The input text effect style.
+  };
+};
+
+/**
+ * @brief Parses the shadow properties.
+ *
+ * @param[in] shadowProperties The map with the shadow properties.
+ * @param[out] colorDefined Whether the shadow's color is defined.
+ * @param[out] color The shadow's color.
+ * @param[out] offsetDefined Whether the shadow's offset is defined.
+ * @param[out] offset The shadow's offset.
+ */
+bool ParseShadowProperties( const Property::Map& shadowProperties,
+                            bool& colorDefined,
+                            Vector4& color,
+                            bool& offsetDefined,
+                            Vector2& offset );
+
+/**
+ * @brief Parses the underline properties.
+ *
+ * @param[in] underlineProperties The map with the underline properties.
+ * @param[out] enabled Whether the underline is enabled.
+ * @param[out] colorDefined Whether the underline's color is defined.
+ * @param[out] color The underline's color.
+ * @param[out] heightDefined Whether the underline's height is defined.
+ * @param[out] height The underline's height.
+ */
+bool ParseUnderlineProperties( const Property::Map& underlineProperties,
+                               bool& enabled,
+                               bool& colorDefined,
+                               Vector4& color,
+                               bool& heightDefined,
+                               float& height );
+
+/**
+ * @brief Parses the outline properties.
+ *
+ * @param[in] outlineProperties The map with the outline properties.
+ * @param[out] colorDefined Whether the outline's color is defined.
+ * @param[out] color The outline's color.
+ * @param[out] widthDefined Whether the outline's width is defined.
+ * @param[out] width The outline's width.
+ */
+bool ParseOutlineProperties( const Property::Map& outlineProperties,
+                               bool& colorDefined,
+                               Vector4& color,
+                               bool& widthDefined,
+                               unsigned int& width );
+
+
+/**
+ * @brief Parses the background properties.
+ *
+ * @param[in] backgroundProperties The map with the background properties.
+ * @param[out] enabled Whether the background is enabled.
+ * @param[out] colorDefined Whether the background color is defined.
+ * @param[out] color The background color.
+ */
+bool ParseBackgroundProperties( const Property::Map& backgroundProperties,
+                                bool& enabled,
+                                bool& colorDefined,
+                                Vector4& color );
+
+/**
+ * @brief Sets the underline properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The values of the underline's properties.
+ * @param[in] type Whether the property is for the default underline or the input underline.
+ *
+ * @return Whether the underline properties have been updated.
+ */
+bool SetUnderlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Retrieves the underline's properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the underline's properties.
+ * @param[in] type Whether the property is for the default underline or the input underline.
+ */
+void GetUnderlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Sets the shadow properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The values of the shadow's style.
+ * @param[in] type Whether the property is for the default shadow's style or the input shadow's style.
+ *
+ * @return Whether the shadow properties have been updated.
+ */
+bool SetShadowProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Retrieves the shadow's properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the shadow's properties.
+ * @param[in] type Whether the property is for the default shadow or the input shadow.
+ */
+void GetShadowProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Sets the emboss properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The values of the emboss's properties.
+ * @param[in] type Whether the property is for the default emboss or the input emboss.
+ *
+ * @return Whether the emboss properties have been updated.
+ */
+bool SetEmbossProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Retrieves the emboss's properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the emboss's properties.
+ * @param[in] type Whether the property is for the default emboss or the input emboss.
+ */
+void GetEmbossProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Sets the outline properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The values of the outline's properties.
+ * @param[in] type Whether the property is for the default outline or the input outline.
+ *
+ * @return Whether the outline properties have been updated.
+ */
+bool SetOutlineProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Retrieves the outline's properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the outline's properties.
+ * @param[in] type Whether the property is for the default outline or the input outline.
+ */
+void GetOutlineProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Sets the background properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The values of the background's properties.
+ * @param[in] type Whether the property is for the default background or the input background.
+ *
+ * @return Whether the background properties have been updated.
+ */
+bool SetBackgroundProperties( ControllerPtr controller, const Property::Value& value, EffectStyle::Type type );
+
+/**
+ * @brief Retrieves the background's properties.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the underline's properties.
+ * @param[in] type Whether the property is for the default background or the input background.
+ */
+void GetBackgroundProperties( ControllerPtr controller, Property::Value& value, EffectStyle::Type type );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_EFFECTS_STYLE_H
diff --git a/dali-toolkit/internal/text/text-enumerations-impl.cpp b/dali-toolkit/internal/text/text-enumerations-impl.cpp
new file mode 100644 (file)
index 0000000..ce1c503
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/text/text-enumerations-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/scripting/enum-helper.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+DALI_ENUM_TO_STRING_TABLE_BEGIN( HORIZONTAL_ALIGNMENT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::HorizontalAlignment, BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::HorizontalAlignment, CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::HorizontalAlignment, END )
+DALI_ENUM_TO_STRING_TABLE_END( HORIZONTAL_ALIGNMENT_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( VERTICAL_ALIGNMENT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::VerticalAlignment, TOP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::VerticalAlignment, CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::VerticalAlignment, BOTTOM )
+DALI_ENUM_TO_STRING_TABLE_END( VERTICAL_ALIGNMENT_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( LINE_WRAP_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::LineWrap, WORD )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Text::LineWrap, CHARACTER )
+DALI_ENUM_TO_STRING_TABLE_END( LINE_WRAP_MODE )
+} // namespace
+
+bool GetHorizontalAlignmentEnumeration( const Property::Value& propertyValue, Toolkit::Text::HorizontalAlignment::Type& alignment )
+{
+  return Scripting::GetEnumerationProperty( propertyValue, HORIZONTAL_ALIGNMENT_TYPE_TABLE, HORIZONTAL_ALIGNMENT_TYPE_TABLE_COUNT, alignment );
+}
+
+bool GetVerticalAlignmentEnumeration( const Property::Value& propertyValue, Toolkit::Text::VerticalAlignment::Type& alignment )
+{
+  return Scripting::GetEnumerationProperty( propertyValue, VERTICAL_ALIGNMENT_TYPE_TABLE, VERTICAL_ALIGNMENT_TYPE_TABLE_COUNT, alignment );
+}
+
+bool GetLineWrapModeEnumeration( const Property::Value& propertyValue, Toolkit::Text::LineWrap::Mode& lineWrapMode )
+{
+  return Scripting::GetEnumerationProperty( propertyValue, LINE_WRAP_MODE_TABLE, LINE_WRAP_MODE_TABLE_COUNT, lineWrapMode );
+}
+
+const char* GetHorizontalAlignmentString( const Toolkit::Text::HorizontalAlignment::Type& alignment )
+{
+  return Scripting::GetLinearEnumerationName< Toolkit::Text::HorizontalAlignment::Type >( alignment,
+                                                                                          HORIZONTAL_ALIGNMENT_TYPE_TABLE,
+                                                                                          HORIZONTAL_ALIGNMENT_TYPE_TABLE_COUNT );
+}
+
+const char* GetVerticalAlignmentString( const Toolkit::Text::VerticalAlignment::Type& alignment )
+{
+  return Scripting::GetLinearEnumerationName< Toolkit::Text::VerticalAlignment::Type >( alignment,
+                                                                                        VERTICAL_ALIGNMENT_TYPE_TABLE,
+                                                                                        VERTICAL_ALIGNMENT_TYPE_TABLE_COUNT );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-enumerations-impl.h b/dali-toolkit/internal/text/text-enumerations-impl.h
new file mode 100644 (file)
index 0000000..53e4fc1
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef DALI_TOOLKIT_TEXT_ENUMERATION_IMPL_H
+#define DALI_TOOLKIT_TEXT_ENUMERATION_IMPL_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/object/property-value.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Get the alignment from the provided property value.
+ * @param[in] propertyValue The source value (which can be a Property::INTEGER or Property::STRING type)
+ * @param[out] alignment The resulting alignment from the given source
+ * @return true if the resulting alignment has been updated
+ */
+bool GetHorizontalAlignmentEnumeration( const Property::Value& propertyValue, Toolkit::Text::HorizontalAlignment::Type& alignment );
+
+/**
+ * @brief Get the alignment from the provided property value.
+ * @param[in] propertyValue The source value (which can be a Property::INTEGER or Property::STRING type)
+ * @param[out] alignment The resulting alignment from the given source
+ * @return true if the resulting alignment has been updated
+ */
+bool GetVerticalAlignmentEnumeration( const Property::Value& propertyValue, Toolkit::Text::VerticalAlignment::Type& alignment );
+
+/**
+ * @brief Get the line-wrap-mode from the provided property value.
+ * @param[in] propertyValue The source value (which can be a Property::INTEGER or Property::STRING type)
+ * @param[out] alignment The resulting lineWrapMode from the given source
+ * @return true if the resulting lineWrapMode has been updated
+ */
+bool GetLineWrapModeEnumeration( const Property::Value& propertyValue, Toolkit::Text::LineWrap::Mode& lineWrapMode );
+
+/**
+ * @brief Get the alignment string from the provided alignment string.
+ * @param[in] alignment the Text::Horizontal enum source
+ * @return the string equivalent
+ */
+const char* GetHorizontalAlignmentString( const Toolkit::Text::HorizontalAlignment::Type& alignment );
+
+/**
+ * @brief Get the alignment string from the provided alignment string.
+ * @param[in] alignment the Text::VerticalAlignment enum source
+ * @return the string equivalent
+ */
+const char* GetVerticalAlignmentString( const Toolkit::Text::VerticalAlignment::Type& alignment );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ENUMERATION_IMPL_H
diff --git a/dali-toolkit/internal/text/text-font-style.cpp b/dali-toolkit/internal/text/text-font-style.cpp
new file mode 100644 (file)
index 0000000..927f277
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/text-font-style.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/property-string-parser.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string STYLE_KEY( "style" );
+const std::string WEIGHT_KEY( "weight" );
+const std::string WIDTH_KEY( "width" );
+const std::string SLANT_KEY( "slant" );
+const std::string FAMILY_KEY( "family" );
+const std::string TYPE_KEY( "type" );
+
+const std::string SYSTEM_TOKEN( "system" );
+
+} // namespace
+
+void SetFontFamilyProperty( ControllerPtr controller, const Property::Value& value )
+{
+  if( controller )
+  {
+    const std::string fontFamilyValue = value.Get<std::string>();
+
+    if( fontFamilyValue.empty() )
+    {
+      // Resets the default's font family name.
+      controller->SetDefaultFontFamily( "" );
+      return;
+    }
+
+    Property::Map map;
+    ParsePropertyString( fontFamilyValue, map );
+
+    if( map.Empty() )
+    {
+      // There is no map. The font has been passed as a font's family name with no format.
+      controller->SetDefaultFontFamily( fontFamilyValue );
+    }
+    else
+    {
+      /// Family key
+      Property::Value* familyValue = map.Find( FAMILY_KEY );
+
+      std::string fontFamilyName;
+      if( NULL != familyValue )
+      {
+        fontFamilyName = familyValue->Get<std::string>();
+      }
+
+      /// Type key
+      Property::Value* typeValue = map.Find( TYPE_KEY );
+
+      std::string typeStr;
+      if( NULL != typeValue )
+      {
+        typeStr = typeValue->Get<std::string>();
+      }
+
+      if( TokenComparison( SYSTEM_TOKEN, typeStr.c_str(), typeStr.size() ) )
+      {
+        controller->UpdateAfterFontChange( fontFamilyName );
+      }
+      else
+      {
+        controller->SetDefaultFontFamily( fontFamilyName );
+      }
+    }
+  }
+}
+
+void SetFontStyleProperty( ControllerPtr controller, const Property::Value& value, FontStyle::Type type )
+{
+  if( controller )
+  {
+    Property::Map map;
+    if( Property::STRING == value.GetType() )
+    {
+      const std::string& fontStyleProperties = value.Get<std::string>();
+
+      ParsePropertyString( fontStyleProperties, map );
+      controller->FontStyleSetByString( true );
+
+    }
+    else
+    {
+      map = value.Get<Property::Map>();
+      controller->FontStyleSetByString( false );
+    }
+
+    if( !map.Empty() )
+    {
+      /// Weight key
+      Property::Value* weightValue = map.Find( WEIGHT_KEY );
+
+      FontWeight weight = TextAbstraction::FontWeight::NONE;
+      const bool weightDefined = weightValue != NULL;
+      if( weightDefined )
+      {
+        const std::string weightStr = weightValue->Get<std::string>();
+
+        Scripting::GetEnumeration< FontWeight >( weightStr.c_str(),
+                                                 FONT_WEIGHT_STRING_TABLE,
+                                                 FONT_WEIGHT_STRING_TABLE_COUNT,
+                                                 weight );
+      }
+
+      /// Width key
+      Property::Value* widthValue = map.Find( WIDTH_KEY );
+
+      FontWidth width = TextAbstraction::FontWidth::NONE;
+      const bool widthDefined = widthValue != NULL;
+      if( widthDefined )
+      {
+        const std::string widthStr = widthValue->Get<std::string>();
+
+        Scripting::GetEnumeration< FontWidth >( widthStr.c_str(),
+                                                FONT_WIDTH_STRING_TABLE,
+                                                FONT_WIDTH_STRING_TABLE_COUNT,
+                                                width );
+      }
+
+      /// Slant key
+      Property::Value* slantValue = map.Find( SLANT_KEY );
+
+      FontSlant slant = TextAbstraction::FontSlant::NONE;
+      const bool slantDefined = slantValue != NULL;
+      if( slantDefined )
+      {
+        const std::string slantStr = slantValue->Get<std::string>();
+
+        Scripting::GetEnumeration< FontSlant >( slantStr.c_str(),
+                                                FONT_SLANT_STRING_TABLE,
+                                                FONT_SLANT_STRING_TABLE_COUNT,
+                                                slant );
+      }
+
+      switch( type )
+      {
+        case FontStyle::DEFAULT:
+        {
+          // Sets the default font's style values.
+          if( !weightDefined ||
+              ( weightDefined && ( controller->GetDefaultFontWeight() != weight ) ) )
+          {
+            controller->SetDefaultFontWeight( weight );
+          }
+
+          if( !widthDefined ||
+              ( widthDefined && ( controller->GetDefaultFontWidth() != width ) ) )
+          {
+            controller->SetDefaultFontWidth( width );
+          }
+
+          if( !slantDefined ||
+              ( slantDefined && ( controller->GetDefaultFontSlant() != slant ) ) )
+          {
+            controller->SetDefaultFontSlant( slant );
+          }
+          break;
+        }
+        case FontStyle::INPUT:
+        {
+          // Sets the input font's style values.
+          if( !weightDefined ||
+              ( weightDefined && ( controller->GetInputFontWeight() != weight ) ) )
+          {
+            controller->SetInputFontWeight( weight );
+          }
+
+          if( !widthDefined ||
+              ( widthDefined && ( controller->GetInputFontWidth() != width ) ) )
+          {
+            controller->SetInputFontWidth( width );
+          }
+
+          if( !slantDefined ||
+              ( slantDefined && ( controller->GetInputFontSlant() != slant ) ) )
+          {
+            controller->SetInputFontSlant( slant );
+          }
+          break;
+        }
+        case FontStyle::PLACEHOLDER:
+        {
+          // Sets the placeholder text font's style values.
+          if( !weightDefined ||
+              ( weightDefined && ( controller->GetPlaceholderTextFontWeight() != weight ) ) )
+          {
+            controller->SetPlaceholderTextFontWeight( weight );
+          }
+
+          if( !widthDefined ||
+              ( widthDefined && ( controller->GetPlaceholderTextFontWidth() != width ) ) )
+          {
+            controller->SetPlaceholderTextFontWidth( width );
+          }
+
+          if( !slantDefined ||
+              ( slantDefined && ( controller->GetPlaceholderTextFontSlant() != slant ) ) )
+          {
+            controller->SetPlaceholderTextFontSlant( slant );
+          }
+          break;
+        }
+      } // switch
+    } // map not empty
+    else
+    {
+      switch( type )
+      {
+        case FontStyle::DEFAULT:
+        {
+          controller->SetDefaultFontWeight( TextAbstraction::FontWeight::NONE );
+          controller->SetDefaultFontWidth( TextAbstraction::FontWidth::NONE );
+          controller->SetDefaultFontSlant( TextAbstraction::FontSlant::NONE );
+          break;
+        }
+        case FontStyle::INPUT:
+        {
+          controller->SetInputFontWeight( TextAbstraction::FontWeight::NONE );
+          controller->SetInputFontWidth( TextAbstraction::FontWidth::NONE );
+          controller->SetInputFontSlant( TextAbstraction::FontSlant::NONE );
+          break;
+        }
+        case FontStyle::PLACEHOLDER:
+        {
+          controller->SetPlaceholderTextFontWeight( TextAbstraction::FontWeight::NONE );
+          controller->SetPlaceholderTextFontWidth( TextAbstraction::FontWidth::NONE );
+          controller->SetPlaceholderTextFontSlant( TextAbstraction::FontSlant::NONE );
+          break;
+        }
+      } // switch
+    } // map.Empty()
+  } // controller
+}
+
+void GetFontStyleProperty( ControllerPtr controller, Property::Value& value, FontStyle::Type type )
+{
+  if( controller )
+  {
+    const bool isSetbyString = controller->IsFontStyleSetByString();
+
+    bool weightDefined = false;
+    bool widthDefined = false;
+    bool slantDefined = false;
+    FontWeight weight = TextAbstraction::FontWeight::NONE;
+    FontWidth width = TextAbstraction::FontWidth::NONE;
+    FontSlant slant = TextAbstraction::FontSlant::NONE;
+
+    switch( type )
+    {
+      case FontStyle::DEFAULT:
+      {
+        weightDefined = controller->IsDefaultFontWeightDefined();
+        widthDefined = controller->IsDefaultFontWidthDefined();
+        slantDefined = controller->IsDefaultFontSlantDefined();
+
+        if( weightDefined )
+        {
+          weight = controller->GetDefaultFontWeight();
+        }
+
+        if( widthDefined )
+        {
+          width = controller->GetDefaultFontWidth();
+        }
+
+        if( slantDefined )
+        {
+          slant = controller->GetDefaultFontSlant();
+        }
+        break;
+      }
+      case FontStyle::INPUT:
+      {
+        weightDefined = controller->IsInputFontWeightDefined();
+        widthDefined = controller->IsInputFontWidthDefined();
+        slantDefined = controller->IsInputFontSlantDefined();
+
+        if( weightDefined )
+        {
+          weight = controller->GetInputFontWeight();
+        }
+
+        if( widthDefined )
+        {
+          width = controller->GetInputFontWidth();
+        }
+
+        if( slantDefined )
+        {
+          slant = controller->GetInputFontSlant();
+        }
+        break;
+      }
+      case FontStyle::PLACEHOLDER:
+      {
+        // The type is FontStyle::PLACEHOLDER
+        weightDefined = controller->IsPlaceholderTextFontWeightDefined();
+        widthDefined = controller->IsPlaceholderTextFontWidthDefined();
+        slantDefined = controller->IsPlaceholderTextFontSlantDefined();
+
+        if( weightDefined )
+        {
+          weight = controller->GetPlaceholderTextFontWeight();
+        }
+
+        if( widthDefined )
+        {
+          width = controller->GetPlaceholderTextFontWidth();
+        }
+
+        if( slantDefined )
+        {
+          slant = controller->GetPlaceholderTextFontSlant();
+        }
+        break;
+      }
+    }
+
+    if( !isSetbyString )
+    {
+      Property::Map map;
+
+      if( weightDefined )
+      {
+        if( TextAbstraction::FontWeight::NONE != weight )
+        {
+          const std::string weightStr( GetEnumerationName( weight,
+                                                          FONT_WEIGHT_STRING_TABLE,
+                                                          FONT_WEIGHT_STRING_TABLE_COUNT ) );
+
+          map.Insert( WEIGHT_KEY, weightStr );
+        }
+      }
+
+      if( widthDefined )
+      {
+        if( TextAbstraction::FontWidth::NONE != width )
+        {
+          const std::string widthStr( GetEnumerationName( width,
+                                                          FONT_WIDTH_STRING_TABLE,
+                                                          FONT_WIDTH_STRING_TABLE_COUNT ) );
+
+          map.Insert( WIDTH_KEY, widthStr );
+        }
+      }
+
+      if( slantDefined )
+      {
+        if( TextAbstraction::FontSlant::NONE != slant )
+        {
+          const std::string slantStr( GetEnumerationName( slant,
+                                                          FONT_SLANT_STRING_TABLE,
+                                                          FONT_SLANT_STRING_TABLE_COUNT ) );
+
+          map.Insert( SLANT_KEY, slantStr );
+        }
+      }
+
+      value = map;
+    } // SetbyMAP
+    else
+    {
+      std::string fontStyleProperties = "{";
+
+      if( weightDefined )
+      {
+        if( TextAbstraction::FontWeight::NONE != weight )
+        {
+          const std::string weightStr( GetEnumerationName( weight,
+                                                          FONT_WEIGHT_STRING_TABLE,
+                                                          FONT_WEIGHT_STRING_TABLE_COUNT ) );
+
+          fontStyleProperties += "\"weight\":\"" + weightStr + "\",";
+        }
+      }
+
+      if( widthDefined )
+      {
+        if( TextAbstraction::FontWidth::NONE != width )
+        {
+          const std::string widthStr( GetEnumerationName( width,
+                                                          FONT_WIDTH_STRING_TABLE,
+                                                          FONT_WIDTH_STRING_TABLE_COUNT ) );
+          fontStyleProperties += "\"width\":\"" + widthStr + "\",";
+        }
+      }
+
+      if( slantDefined )
+      {
+        if( TextAbstraction::FontSlant::NONE != slant )
+        {
+          const std::string slantStr( GetEnumerationName( slant,
+                                                          FONT_SLANT_STRING_TABLE,
+                                                          FONT_SLANT_STRING_TABLE_COUNT ) );
+
+          fontStyleProperties += "\"slant\":\"" + slantStr + "\"";
+        }
+      }
+
+      // If last character is comma, it will be removed.
+      if((*fontStyleProperties.rbegin()) == ',' )
+      {
+        fontStyleProperties = fontStyleProperties.substr( 0, fontStyleProperties.size()-1 );
+      }
+      fontStyleProperties += "}";
+
+      value = fontStyleProperties;
+    } // SetbyString
+  }// controller
+}
+
+FontWeight StringToWeight( const char* const weightStr )
+{
+  FontWeight weight = TextAbstraction::FontWeight::NORMAL;
+  Scripting::GetEnumeration<FontWeight>( weightStr,
+                                         FONT_WEIGHT_STRING_TABLE,
+                                         FONT_WEIGHT_STRING_TABLE_COUNT,
+                                         weight );
+
+  return weight;
+}
+
+FontWidth StringToWidth( const char* const widthStr )
+{
+  FontWidth width = TextAbstraction::FontWidth::NORMAL;
+  Scripting::GetEnumeration<FontWidth>( widthStr,
+                                        FONT_WIDTH_STRING_TABLE,
+                                        FONT_WIDTH_STRING_TABLE_COUNT,
+                                        width );
+
+  return width;
+}
+
+FontSlant StringToSlant( const char* const slantStr )
+{
+  FontSlant slant = TextAbstraction::FontSlant::NORMAL;
+  Scripting::GetEnumeration<FontSlant>( slantStr,
+                                        FONT_SLANT_STRING_TABLE,
+                                        FONT_SLANT_STRING_TABLE_COUNT,
+                                        slant );
+
+  return slant;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-font-style.h b/dali-toolkit/internal/text/text-font-style.h
new file mode 100644 (file)
index 0000000..e53d754
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_FONT_STYLE_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_FONT_STYLE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+const Scripting::StringEnum FONT_WEIGHT_STRING_TABLE[] =
+{
+  { "thin", TextAbstraction::FontWeight::THIN },
+  { "ultraLight", TextAbstraction::FontWeight::ULTRA_LIGHT },
+  { "extraLight", TextAbstraction::FontWeight::EXTRA_LIGHT },
+  { "light", TextAbstraction::FontWeight::LIGHT },
+  { "demiLight", TextAbstraction::FontWeight::DEMI_LIGHT },
+  { "semiLight", TextAbstraction::FontWeight::SEMI_LIGHT },
+  { "book", TextAbstraction::FontWeight::BOOK },
+  { "normal", TextAbstraction::FontWeight::NORMAL },
+  { "regular", TextAbstraction::FontWeight::REGULAR },
+  { "medium", TextAbstraction::FontWeight::MEDIUM },
+  { "demiBold", TextAbstraction::FontWeight::DEMI_BOLD },
+  { "semiBold", TextAbstraction::FontWeight::SEMI_BOLD },
+  { "bold", TextAbstraction::FontWeight::BOLD },
+  { "ultraBold", TextAbstraction::FontWeight::ULTRA_BOLD },
+  { "extraBold", TextAbstraction::FontWeight::EXTRA_BOLD },
+  { "black", TextAbstraction::FontWeight::BLACK },
+  { "heavy", TextAbstraction::FontWeight::HEAVY },
+  { "extraBlack", TextAbstraction::FontWeight::EXTRA_BLACK }
+};
+const unsigned int FONT_WEIGHT_STRING_TABLE_COUNT = sizeof( FONT_WEIGHT_STRING_TABLE ) / sizeof( FONT_WEIGHT_STRING_TABLE[0] );
+
+const Scripting::StringEnum FONT_WIDTH_STRING_TABLE[] =
+{
+  { "ultraCondensed", TextAbstraction::FontWidth::ULTRA_CONDENSED },
+  { "extraCondensed", TextAbstraction::FontWidth::EXTRA_CONDENSED },
+  { "condensed", TextAbstraction::FontWidth::CONDENSED },
+  { "semiCondensed", TextAbstraction::FontWidth::SEMI_CONDENSED },
+  { "normal", TextAbstraction::FontWidth::NORMAL },
+  { "semiExpanded", TextAbstraction::FontWidth::SEMI_EXPANDED },
+  { "expanded", TextAbstraction::FontWidth::EXPANDED },
+  { "extraExpanded", TextAbstraction::FontWidth::EXTRA_EXPANDED },
+  { "ultraExpanded", TextAbstraction::FontWidth::ULTRA_EXPANDED },
+};
+const unsigned int FONT_WIDTH_STRING_TABLE_COUNT = sizeof( FONT_WIDTH_STRING_TABLE ) / sizeof( FONT_WIDTH_STRING_TABLE[0] );
+
+const Scripting::StringEnum FONT_SLANT_STRING_TABLE[] =
+{
+  { "normal", TextAbstraction::FontSlant::NORMAL },
+  { "roman", TextAbstraction::FontSlant::ROMAN },
+  { "italic", TextAbstraction::FontSlant::ITALIC },
+  { "oblique", TextAbstraction::FontSlant::OBLIQUE }
+};
+const unsigned int FONT_SLANT_STRING_TABLE_COUNT = sizeof( FONT_SLANT_STRING_TABLE ) / sizeof( FONT_SLANT_STRING_TABLE[0] );
+
+namespace FontStyle
+{
+  enum Type
+  {
+    DEFAULT,      ///< The default font's style.
+    INPUT,        ///< The input font's style.
+    PLACEHOLDER   ///< The placeholder text font's style.
+  };
+};
+
+/**
+ * @brief Sets the font family property.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The value of the font's family.
+ */
+void SetFontFamilyProperty( ControllerPtr controller, const Property::Value& value );
+
+/**
+ * @brief Sets the font's style property.
+ *
+ * @param[in] controller The text's controller.
+ * @param[in] value The value of the font's style.
+ * @param[in] type Whether the property is for the default font's style, the input font's style or the placeholder font's style.
+ *
+ */
+void SetFontStyleProperty( ControllerPtr controller, const Property::Value& value, FontStyle::Type type );
+
+/**
+ * @brief Retrieves the font's style property.
+ *
+ * @param[in] controller The text's controller.
+ * @param[out] value The value of the font's style.
+ * @param[in] type Whether the property is for the default font's style, the input font's style or the placeholder font's style.
+ */
+void GetFontStyleProperty( ControllerPtr controller, Property::Value& value, FontStyle::Type type );
+
+/**
+ * @brief Converts a weight string into @e FontWeight.
+ *
+ * @param[in] weightStr The weight string. Must end with '\0'.
+ *
+ * @return The @e FontWeight value corresponding to the string.
+ */
+FontWeight StringToWeight( const char* const weightStr );
+
+/**
+ * @brief Converts a width string into @e FontWidth.
+ *
+ * @param[in] widthStr The width string. Must end with '\0'.
+ *
+ * @return The @e FontWidth value corresponding to the string.
+ */
+FontWidth StringToWidth( const char* const widthStr );
+
+/**
+ * @brief Converts a slant string into @e FontSlant.
+ *
+ * @param[in] slantStr The slant string. Must end with '\0'.
+ *
+ * @return The @e FontSlant value corresponding to the string.
+ */
+FontSlant StringToSlant( const char* const slantStr );
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXT_FONT_STYLE_H
diff --git a/dali-toolkit/internal/text/text-io.cpp b/dali-toolkit/internal/text/text-io.cpp
new file mode 100644 (file)
index 0000000..279e1aa
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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 <dali-toolkit/internal/text/text-io.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/script.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+std::ostream& operator<< (std::ostream& o, const Vector<Character>& text)
+{
+  o << std::hex;
+
+  for( unsigned int i=0; i<text.Count(); ++i )
+  {
+    o << text[i];
+    if( i+1 < text.Count() )
+    {
+      o << " ";
+    }
+  }
+
+  return o << std::dec;
+}
+
+std::ostream& operator<< (std::ostream& o, const Vector<ScriptRun>& scriptRun)
+{
+  for( unsigned int i=0; i<scriptRun.Count(); ++i )
+  {
+    // e.g. Print "0->9: LATIN" for a ten character run staring from beginning of the model
+    o << scriptRun[i].characterRun.characterIndex << "->" << (scriptRun[i].characterRun.characterIndex + scriptRun[i].characterRun.numberOfCharacters ) << ": ";
+    o << TextAbstraction::ScriptName[scriptRun[i].script];
+
+    if( i+1 < scriptRun.Count() )
+    {
+      o << ", ";
+    }
+  }
+
+  return o << std::dec;
+}
+
+std::ostream& operator<< (std::ostream& o, const Vector<FontRun>& fontRun)
+{
+  TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+  for( unsigned int i=0; i<fontRun.Count(); ++i )
+  {
+    // e.g. Print "0->9: ID:1 TizenSansKorean style:Regular size:10.0" for a ten character run staring from beginning of the model
+    o << fontRun[i].characterRun.characterIndex << "->" << (fontRun[i].characterRun.characterIndex + fontRun[i].characterRun.numberOfCharacters ) << ": ";
+
+    FontId id = fontRun[i].fontId;
+    TextAbstraction::FontDescription fontDescription;
+    fontClient.GetDescription( id, fontDescription );
+    o << "ID:" << id << ", " << fontDescription.family << " width: " << fontDescription.width << " weight: " << fontDescription.weight << " slant: " << fontDescription.slant <<  " size:" << (fontClient.GetPointSize(id) / 64);
+
+    if( i+1 < fontRun.Count() )
+    {
+      o << ", ";
+    }
+  }
+
+  return o << std::dec;
+}
+
+std::ostream& operator<< (std::ostream& o, const Vector<LineRun>& lineRuns)
+{
+  for( unsigned int i=0; i<lineRuns.Count(); ++i )
+  {
+    // e.g. Print "Line 0 Glyphs: 0->9 Characters: 0->9 (10)" for a ten character run staring from beginning of the model
+    o << "Line " << i << " Glyphs: " << lineRuns[i].glyphRun.glyphIndex << "->" << (lineRuns[i].glyphRun.glyphIndex + lineRuns[i].glyphRun.numberOfGlyphs );
+    o << " Characters: " << lineRuns[i].characterRun.characterIndex << "->" << (lineRuns[i].characterRun.characterIndex + lineRuns[i].characterRun.numberOfCharacters );
+    o << " Width: " << lineRuns[i].width;
+    o << " Ascender: " << lineRuns[i].ascender;
+    o << " Descender: " << lineRuns[i].descender;
+
+    if( i+1 < lineRuns.Count() )
+    {
+      o << ", ";
+    }
+  }
+
+  return o << std::dec;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-io.h b/dali-toolkit/internal/text/text-io.h
new file mode 100644 (file)
index 0000000..6c6d3c5
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_TEXT_ABSTRACTION_TEXT_IO_H
+#define DALI_TEXT_ABSTRACTION_TEXT_IO_H
+
+/*
+ * Copyright (c) 2019 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 <iosfwd>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/font-run.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Print a vector of characters.
+ *
+ * @param [in] o The output stream operator.
+ * @param [in] text The text to print.
+ * @return The output stream operator.
+ */
+std::ostream& operator<< (std::ostream& o, const Vector<Character>& text);
+
+/**
+ * @brief Print a vector of script runs.
+ *
+ * @param [in] o The output stream operator.
+ * @param [in] scriptRuns The script runs to print.
+ * @return The output stream operator.
+ */
+std::ostream& operator<< (std::ostream& o, const Vector<ScriptRun>& scriptRuns);
+
+/**
+ * @brief Print a vector of font runs.
+ *
+ * @param [in] o The output stream operator.
+ * @param [in] fontRuns The font runs to print.
+ * @return The output stream operator.
+ */
+std::ostream& operator<< (std::ostream& o, const Vector<FontRun>& fontRuns);
+
+/**
+ * @brief Print a vector of line runs.
+ *
+ * @param [in] o The output stream operator.
+ * @param [in] lineRuns The line runs to print.
+ * @return The output stream operator.
+ */
+std::ostream& operator<< (std::ostream& o, const Vector<LineRun>& lineRuns);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_TEXT_IO_H
diff --git a/dali-toolkit/internal/text/text-model-interface.h b/dali-toolkit/internal/text/text-model-interface.h
new file mode 100755 (executable)
index 0000000..812ba7c
--- /dev/null
@@ -0,0 +1,279 @@
+#ifndef DALI_TOOLKIT_TEXT_MODEL_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_MODEL_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/script-run.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Interface class used to retrieve the text's model from the text-controller.
+ */
+class ModelInterface
+{
+public:
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~ModelInterface()
+  {}
+
+  /**
+   * @brief Retrives the control's size.
+   *
+   * @return The control's size.
+   */
+  virtual const Size& GetControlSize() const = 0;
+
+  /**
+   * @brief Retrives the layout's size.
+   *
+   * @return The layout's size.
+   */
+  virtual const Size& GetLayoutSize() const = 0;
+
+  /**
+   * @brief Retrieves the text's scroll position.
+   *
+   * @return The scroll position.
+   */
+  virtual const Vector2& GetScrollPosition() const = 0;
+
+  /**
+   * @brief Retrieves the text's horizontal alignment.
+   *
+   * @return The horizontal alignment.
+   */
+  virtual HorizontalAlignment::Type GetHorizontalAlignment() const = 0;
+
+  /**
+   * @brief Retrieves the text's vertical alignment.
+   *
+   * @return The vertical alignment.
+   */
+  virtual VerticalAlignment::Type GetVerticalAlignment() const = 0;
+
+  /**
+   * @brief Retrieves the text's vertical line alignment.
+   *
+   * @return The vertical line alignment.
+   */
+  virtual DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const = 0;
+
+  /**
+   * @brief Whether the text elide property is enabled.
+   *
+   * @return @e true if the text elide property is enabled, @e false otherwise.
+   */
+  virtual bool IsTextElideEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the number of laid-out lines.
+   *
+   * @return The number of laid-out lines.
+   */
+  virtual Length GetNumberOfLines() const = 0;
+
+  /**
+   * @brief Retrieves the laid-out lines.
+   *
+   * @return A pointer to the vector with the laid-out lines.
+   */
+  virtual const LineRun* const GetLines() const = 0;
+
+  /**
+   * @brief Retrieves the number of script runs.
+   *
+   * @return The number of script runs.
+   */
+  virtual Length GetNumberOfScripts() const = 0;
+
+  /**
+   * @brief Retrieves the script runs.
+   *
+   * @return A pointer to the vector with the runs of characters with the same script..
+   */
+  virtual const ScriptRun* const GetScriptRuns() const = 0;
+
+  /**
+   * @brief Retrieves the number of laid-out glyphs.
+   *
+   * @return The number of laid-out glyphs.
+   */
+  virtual Length GetNumberOfGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the laid-out glyphs.
+   *
+   * @return A pointer to the vector with the laid-out glyphs.
+   */
+  virtual const GlyphInfo* const GetGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves the text layout.
+   *
+   * @return A pointer to the vector with the positions for each glyph.
+   */
+  virtual const Vector2* const GetLayout() 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 vector of background colors.
+   *
+   * @return Pointer to the vector of background colors.
+   */
+  virtual const Vector4* const GetBackgroundColors() const = 0;
+
+  /**
+   * @brief Retrieves the vector of indices to the vector of background colors.
+   *
+   * @return Pointer to a vector which stores for each glyph the index to the vector of background colors.
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
+
+  /**
+   * @brief Retrieves the text's default color.
+   *
+   * @return The default color.
+   */
+  virtual const Vector4& GetDefaultColor() const = 0;
+
+  /**
+   * @brief Retrieves the shadow offset, 0 indicates no shadow.
+   *
+   * @return The shadow offset.
+   */
+  virtual const Vector2& GetShadowOffset() const = 0;
+
+  /**
+   * @brief Retrieves the shadow color.
+   *
+   * @return The shadow color.
+   */
+  virtual const Vector4& GetShadowColor() const = 0;
+
+  /**
+   * @brief Retrieve the shadow blur radius.
+   *
+   * @return The shadow blur radius.
+   */
+  virtual const float& GetShadowBlurRadius() const = 0;
+
+  /**
+   * @brief Retrieves the underline color.
+   *
+   * @return The underline color.
+   */
+  virtual const Vector4& GetUnderlineColor() const = 0;
+
+  /**
+   * @brief Returns whether underline is enabled or not.
+   *
+   * @return The underline state.
+   */
+  virtual bool IsUnderlineEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the underline height override
+   *
+   * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
+   */
+  virtual float GetUnderlineHeight() const = 0;
+
+  /**
+   * @brief Retrieves the number of underline runs.
+   *
+   * @return The number of underline runs.
+   */
+  virtual Length GetNumberOfUnderlineRuns() const = 0;
+
+  /**
+   * @brief Retrieves the underline runs.
+   *
+   * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+   * @param[in] index Index of the first underline run to be copied.
+   * @param[in] numberOfRuns Number of underline runs to be copied.
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const = 0;
+
+  /**
+   * @brief Retrieve the outline color.
+   *
+   * @return The outline color.
+   */
+  virtual const Vector4& GetOutlineColor() const = 0;
+
+  /**
+   * @brief Retrieves the width of an outline
+   *
+   * @return The width of the outline.
+   */
+  virtual uint16_t GetOutlineWidth() const = 0;
+
+  /**
+   * @brief Retrieves the background color.
+   *
+   * @return The background color.
+   */
+  virtual const Vector4& GetBackgroundColor() const = 0;
+
+  /**
+   * @brief Returns whether background is enabled or not.
+   *
+   * @return The background state.
+   */
+  virtual bool IsBackgroundEnabled() const = 0;
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MODEL_INTERFACE_H
diff --git a/dali-toolkit/internal/text/text-model.cpp b/dali-toolkit/internal/text/text-model.cpp
new file mode 100755 (executable)
index 0000000..c1767d8
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/text/text-model.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+ModelPtr Model::New()
+{
+  return ModelPtr( new Model() );
+}
+
+const Size& Model::GetControlSize() const
+{
+  return mVisualModel->mControlSize;
+}
+
+const Size& Model::GetLayoutSize() const
+{
+  return mVisualModel->GetLayoutSize();
+}
+
+const Vector2& Model::GetScrollPosition() const
+{
+  return mScrollPosition;
+}
+
+HorizontalAlignment::Type Model::GetHorizontalAlignment() const
+{
+  return mHorizontalAlignment;
+}
+
+VerticalAlignment::Type Model::GetVerticalAlignment() const
+{
+  return mVerticalAlignment;
+}
+
+DevelText::VerticalLineAlignment::Type Model::GetVerticalLineAlignment() const
+{
+  return mVerticalLineAlignment;
+}
+
+bool Model::IsTextElideEnabled() const
+{
+  return mElideEnabled;
+}
+
+Length Model::GetNumberOfLines() const
+{
+  return mVisualModel->mLines.Count();
+}
+
+const LineRun* const Model::GetLines() const
+{
+  return mVisualModel->mLines.Begin();
+}
+
+Length Model::GetNumberOfScripts() const
+{
+  return mLogicalModel->mScriptRuns.Count();
+}
+
+const ScriptRun* const Model::GetScriptRuns() const
+{
+  return mLogicalModel->mScriptRuns.Begin();
+}
+
+Length Model::GetNumberOfGlyphs() const
+{
+  return mVisualModel->mGlyphs.Count();
+}
+
+const GlyphInfo* const Model::GetGlyphs() const
+{
+  return mVisualModel->mGlyphs.Begin();
+}
+
+const Vector2* const Model::GetLayout() const
+{
+  return mVisualModel->mGlyphPositions.Begin();
+}
+
+const Vector4* const Model::GetColors() const
+{
+  return mVisualModel->mColors.Begin();
+}
+
+const ColorIndex* const Model::GetColorIndices() const
+{
+  return mVisualModel->mColorIndices.Begin();
+}
+
+const Vector4* const Model::GetBackgroundColors() const
+{
+  return mVisualModel->mBackgroundColors.Begin();
+}
+
+const ColorIndex* const Model::GetBackgroundColorIndices() const
+{
+  return mVisualModel->mBackgroundColorIndices.Begin();
+}
+
+const Vector4& Model::GetDefaultColor() const
+{
+  return mVisualModel->mTextColor;
+}
+
+const Vector2& Model::GetShadowOffset() const
+{
+  return mVisualModel->mShadowOffset;
+}
+
+const Vector4& Model::GetShadowColor() const
+{
+  return mVisualModel->mShadowColor;
+}
+
+const float& Model::GetShadowBlurRadius() const
+{
+  return mVisualModel->mShadowBlurRadius;
+}
+
+const Vector4& Model::GetUnderlineColor() const
+{
+  return mVisualModel->GetUnderlineColor();
+}
+
+bool Model::IsUnderlineEnabled() const
+{
+  return mVisualModel->IsUnderlineEnabled();
+}
+
+float Model::GetUnderlineHeight() const
+{
+  return mVisualModel->GetUnderlineHeight();
+}
+
+Length Model::GetNumberOfUnderlineRuns() const
+{
+  return mVisualModel->GetNumberOfUnderlineRuns();
+}
+
+void Model::GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const
+{
+  mVisualModel->GetUnderlineRuns( underlineRuns, index, numberOfRuns );
+}
+
+const Vector4& Model::GetOutlineColor() const
+{
+  return mVisualModel->GetOutlineColor();
+}
+
+uint16_t Model::GetOutlineWidth() const
+{
+  return mVisualModel->GetOutlineWidth();
+}
+
+const Vector4& Model::GetBackgroundColor() const
+{
+  return mVisualModel->GetBackgroundColor();
+}
+
+bool Model::IsBackgroundEnabled() const
+{
+  return mVisualModel->IsBackgroundEnabled();
+}
+
+Model::Model()
+: mLogicalModel(),
+  mVisualModel(),
+  mScrollPosition(),
+  mScrollPositionLast(),
+  mHorizontalAlignment( Text::HorizontalAlignment::BEGIN ),
+  mVerticalAlignment( Text::VerticalAlignment::TOP ),
+  mVerticalLineAlignment( DevelText::VerticalLineAlignment::TOP ),
+  mLineWrapMode( Text::LineWrap::WORD ),
+  mAlignmentOffset( 0.0f ),
+  mElideEnabled( false ),
+  mIgnoreSpacesAfterText( true ),
+  mMatchSystemLanguageDirection( false )
+{
+  mLogicalModel = LogicalModel::New();
+  mVisualModel = VisualModel::New();
+}
+
+Model::~Model()
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-model.h b/dali-toolkit/internal/text/text-model.h
new file mode 100755 (executable)
index 0000000..5edb294
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef DALI_TOOLKIT_TEXT_MODEL_H
+#define DALI_TOOLKIT_TEXT_MODEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/internal/text/logical-model-impl.h>
+#include <dali-toolkit/internal/text/text-model-interface.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+// Forward declarations.
+class Model;
+
+typedef IntrusivePtr<Model> ModelPtr;
+
+/**
+ * @brief Implementation class used to retrieve the text's model from the text-controller.
+ */
+class Model : public RefObject, public ModelInterface
+{
+
+public: // Constructor.
+
+  /**
+   * @brief Create a new instance of a text Model.
+   *
+   * @return A pointer to a new text Model.
+   */
+  static ModelPtr New();
+
+public:
+
+  /**
+   * @copydoc ModelInterface::GetControlSize()
+   */
+  virtual const Size& GetControlSize() const override;
+
+  /**
+   * @copydoc ModelInterface::GetLayoutSize()
+   */
+  virtual const Size& GetLayoutSize() const override;
+
+  /**
+   * @copydoc ModelInterface::GetScrollPosition()
+   */
+  virtual const Vector2& GetScrollPosition() const override;
+
+  /**
+   * @copydoc ModelInterface::GetHorizontalAlignment()
+   */
+  virtual HorizontalAlignment::Type GetHorizontalAlignment() const override;
+
+  /**
+   * @copydoc ModelInterface::GetVerticalAlignment()
+   */
+  virtual VerticalAlignment::Type GetVerticalAlignment() const override;
+
+  /**
+   * @copydoc ModelInterface::GetVerticalLineAlignment()
+   */
+  virtual DevelText::VerticalLineAlignment::Type GetVerticalLineAlignment() const override;
+
+  /**
+   * @copydoc ModelInterface::IsTextElideEnabled()
+   */
+  virtual bool IsTextElideEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfLines()
+   */
+  virtual Length GetNumberOfLines() const override;
+
+  /**
+   * @copydoc ModelInterface::GetLines()
+   */
+  virtual const LineRun* const GetLines() const override;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfScripts()
+   */
+  virtual Length GetNumberOfScripts() const override;
+
+  /**
+   * @copydoc ModelInterface::GetScriptRuns()
+   */
+  virtual const ScriptRun* const GetScriptRuns() const override;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfGlyphs()
+   */
+  virtual Length GetNumberOfGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetGlyphs()
+   */
+  virtual const GlyphInfo* const GetGlyphs() const override;
+
+  /**
+   * @copydoc ModelInterface::GetLayout()
+   */
+  virtual const Vector2* const GetLayout() const override;
+
+  /**
+   * @copydoc ModelInterface::GetColors()
+   */
+  virtual const Vector4* const GetColors() const override;
+
+  /**
+   * @copydoc ModelInterface::GetColorIndices()
+   */
+  virtual const ColorIndex* const GetColorIndices() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const override;
+
+  /**
+   * @copydoc ModelInterface::GetDefaultColor()
+   */
+  virtual const Vector4& GetDefaultColor() const override;
+
+  /**
+   * @copydoc ModelInterface::GetShadowOffset()
+   */
+  virtual const Vector2& GetShadowOffset() const override;
+
+  /**
+   * @copydoc ModelInterface::GetShadowColor()
+   */
+  virtual const Vector4& GetShadowColor() const override;
+
+  /**
+   * @copydoc ModelInterface::GetShadowBlurRadius()
+   */
+  virtual const float& GetShadowBlurRadius() const override;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const override;
+
+  /**
+   * @copydoc ModelInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const override;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineHeight()
+   */
+  virtual float GetUnderlineHeight() const override;
+
+  /**
+   * @copydoc ModelInterface::GetNumberOfUnderlineRuns()
+   */
+  virtual Length GetNumberOfUnderlineRuns() const override;
+
+  /**
+   * @copydoc ModelInterface::GetUnderlineRuns()
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns ) const override;
+
+  /**
+   * @copydoc ModelInterface::GetOutlineColor()
+   */
+  virtual const Vector4& GetOutlineColor() const override;
+
+  /**
+   * @copydoc ModelInterface::GetOutlineWidth()
+   */
+  virtual uint16_t GetOutlineWidth() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColor()
+   */
+  virtual const Vector4& GetBackgroundColor() const override;
+
+  /**
+   * @copydoc ModelInterface::IsBackgroundEnabled()
+   */
+  virtual bool IsBackgroundEnabled() const override;
+
+private: // Private contructors & copy operator.
+
+  /**
+   * @brief Private constructor.
+   */
+  Model();
+
+  // Undefined.
+  Model( const Model& handle );
+
+  // Undefined.
+  Model& operator=( const Model& handle );
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Model();
+
+public:
+  LogicalModelPtr             mLogicalModel;        ///< Pointer to the logical model.
+  VisualModelPtr              mVisualModel;         ///< Pointer to the visual model.
+  /**
+   * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
+   * Typically this will have a negative value with scrolling occurs.
+   */
+  Vector2                                   mScrollPosition;          ///< The text is offset by this position when scrolling.
+  Vector2                                   mScrollPositionLast;      ///< The last offset value of mScrollPosition
+  HorizontalAlignment::Type                 mHorizontalAlignment;     ///< The layout's horizontal alignment.
+  VerticalAlignment::Type                   mVerticalAlignment;       ///< The layout's vertical alignment.
+  DevelText::VerticalLineAlignment::Type    mVerticalLineAlignment;   ///< The layout's vertical line alignment.
+  Text::LineWrap::Mode                      mLineWrapMode;            ///< The text wrap mode
+  float                                     mAlignmentOffset;         ///< The alignment offset.
+  bool                                      mElideEnabled:1;          ///< Whether the text's elide is enabled.
+  bool                                      mIgnoreSpacesAfterText:1; ///< Whether ignoring spaces after text or not. Default is true.
+  bool                                      mMatchSystemLanguageDirection:1; ///< Whether match align for system language direction or not. Default is false.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MODEL_H
diff --git a/dali-toolkit/internal/text/text-run-container.h b/dali-toolkit/internal/text/text-run-container.h
new file mode 100644 (file)
index 0000000..3b54d5c
--- /dev/null
@@ -0,0 +1,356 @@
+#ifndef DALI_TOOLKIT_TEXT_RUN_CONTAINER_H
+#define DALI_TOOLKIT_TEXT_RUN_CONTAINER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Clears the runs starting from the given character index.
+ *
+ * @param[in] startIndex The starting character index used to remove runs.
+ * @param[in] endIndex The ending character index used to remove runs.
+ * @param[in,out] runs The text's runs.
+ * @param[out] startRemoveIndex The index to the first run to be removed.
+ * @param[out] endRemoveIndex The index to the last run to be removed.
+ */
+template< typename T >
+void ClearCharacterRuns( CharacterIndex startIndex,
+                         CharacterIndex endIndex,
+                         Vector<T>& runs,
+                         uint32_t& startRemoveIndex,
+                         uint32_t& endRemoveIndex )
+{
+  T* runsBuffer = runs.Begin();
+  T* run = runsBuffer;
+
+  const Length length = runs.Count();
+  Length index = 0u;
+  for( index = 0u; index < length; ++index )
+  {
+    if( ( run->characterRun.characterIndex <= endIndex ) &&
+        ( startIndex < run->characterRun.characterIndex + run->characterRun.numberOfCharacters ) )
+    {
+      // Run found.
+
+      // Set the index to the first run to be removed.
+      startRemoveIndex = index;
+      break;
+    }
+
+    ++run;
+  }
+
+  run = ( runsBuffer + startRemoveIndex );
+  for( index = startRemoveIndex; index < length; ++index )
+  {
+    if( ( run->characterRun.characterIndex > endIndex ) ||
+        ( startIndex >= run->characterRun.characterIndex + run->characterRun.numberOfCharacters ) )
+    {
+      // Run found. Nothing else to do.
+      break;
+    }
+    ++run;
+  }
+  endRemoveIndex = index;
+
+  // The number of characters to remove.
+  const Length numberOfCharactersRemoved = 1u + endIndex - startIndex;
+
+  // Update the character index of the next runs.
+  run = runsBuffer;
+  for( Length index = 0u; index < length; ++index )
+  {
+    if( run->characterRun.characterIndex > startIndex )
+    {
+      run->characterRun.characterIndex -= numberOfCharactersRemoved;
+    }
+
+    ++run;
+  }
+}
+
+/**
+ * @brief Clears the runs starting from the given character index.
+ *
+ * @param[in] startIndex The starting character index used to remove runs.
+ * @param[in] endIndex The ending character index used to remove runs.
+ * @param[in,out] runs The text's runs.
+ */
+template< typename T >
+void ClearCharacterRuns( CharacterIndex startIndex,
+                         CharacterIndex endIndex,
+                         Vector<T>& runs )
+{
+  uint32_t startRemoveIndex = runs.Count();
+  uint32_t endRemoveIndex = startRemoveIndex;
+  ClearCharacterRuns( startIndex,
+                      endIndex,
+                      runs,
+                      startRemoveIndex,
+                      endRemoveIndex );
+
+  // Remove all remaining runs.
+  T* runBuffer = runs.Begin();
+  runs.Erase( runBuffer + startRemoveIndex, runBuffer + endRemoveIndex );
+}
+
+/**
+ * @brief Updates the number of characters and the character index of the text's style runs.
+ *
+ * If the @p numberOfCharacters is a negative value, it means the number of characters that are removed starting from the @p index.
+ *
+ * It deletes runs if all their characters are removed.
+ *
+ * @param[in] index Index to the first character updated.
+ * @param[in] numberOfCharacters The number of characters to be updated.
+ * @param[in] totalNumberOfCharacters Total number of characters of the text.
+ * @param[in,out] runs The text's style runs.
+ * @param[out] removedRuns The text's style removed runs.
+ */
+template< typename T >
+void UpdateCharacterRuns( CharacterIndex index,
+                          int numberOfCharacters,
+                          Length totalNumberOfCharacters,
+                          Vector<T>& runs,
+                          Vector<T>& removedRuns )
+{
+  if( 0 > numberOfCharacters )
+  {
+    // Remove characters.
+    const Length numberOfRemovedCharacters = -numberOfCharacters;
+
+    if( ( 0u == index ) && ( numberOfRemovedCharacters == totalNumberOfCharacters ) )
+    {
+      // Set the removed runs.
+      removedRuns = runs;
+
+      // All characters are removed.
+      runs.Clear();
+
+      // Nothing else to do.
+      return;
+    }
+
+    const VectorBase::SizeType size = runs.Count();
+    // Temporary vector used to remove runs.
+    Vector<T> tempRuns;
+    // Reserve some space for the temporary vector.
+    tempRuns.Reserve( size );
+    removedRuns.Reserve( size );
+
+    // Whether any run has to be removed.
+    bool runsRemoved = false;
+
+    // Index to the last character added/removed.
+    const CharacterIndex lastIndex = index + numberOfRemovedCharacters - 1u;
+
+    // Update the style runs
+    for( typename Vector<T>::Iterator it = runs.Begin(),
+           endIt = runs.End();
+         it != endIt;
+         ++it )
+    {
+      T& run = *it;
+
+      const CharacterIndex lastRunIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+
+      if( lastRunIndex < index )
+      {
+        // The style run is not affected by the removed text.
+        tempRuns.PushBack( run );
+        continue;
+      }
+
+      if( ( index <= run.characterRun.characterIndex ) &&
+          ( lastIndex >= lastRunIndex ) )
+      {
+        // Add the removed run into the vector.
+        removedRuns.PushBack( run );
+
+        // All the characters are removed.
+        runsRemoved = true;
+      }
+      else
+      {
+        if( lastIndex < run.characterRun.characterIndex )
+        {
+          // Just move the character index.
+          run.characterRun.characterIndex -= numberOfRemovedCharacters;
+        }
+        else
+        {
+          if( run.characterRun.characterIndex < index )
+          {
+            // Remove characters starting from a character within the run.
+            run.characterRun.numberOfCharacters -= std::min( numberOfRemovedCharacters, 1u + lastRunIndex - index );
+          }
+          else
+          {
+            // Remove characters starting from a character located before the first index of the run.
+            run.characterRun.numberOfCharacters -= 1u + lastIndex - run.characterRun.characterIndex;
+            run.characterRun.characterIndex = index;
+          }
+        }
+
+        tempRuns.PushBack( run );
+      }
+    }
+
+    // Copy the temporary vector if there are runs removed.
+    if( runsRemoved )
+    {
+      runs = tempRuns;
+    }
+  }
+  else
+  {
+    // Add characters.
+
+    // Update the style runs
+    for( typename Vector<T>::Iterator it = runs.Begin(),
+           endIt = runs.End();
+         it != endIt;
+         ++it )
+    {
+      T& run = *it;
+
+      // Update the number of characters of the style run.
+
+      if( ( 0u == index ) && ( 0u == run.characterRun.characterIndex ) )
+      {
+        run.characterRun.numberOfCharacters += numberOfCharacters;
+      }
+      else if( index <= run.characterRun.characterIndex )
+      {
+        run.characterRun.characterIndex += numberOfCharacters;
+      }
+      else if( index <= run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+      {
+        run.characterRun.numberOfCharacters += numberOfCharacters;
+      }
+    }
+  }
+}
+
+/**
+ * @brief Clears the runs starting from the given glyph index.
+ *
+ * @param[in] startIndex The starting glyph index used to remove runs.
+ * @param[in] endIndex The ending glyph index used to remove runs.
+ * @param[in,out] runs The text's runs.
+ * @param[out] startRemoveIndex The index to the first run to be removed.
+ * @param[out] endRemoveIndex The index to the last run to be removed.
+ */
+template< typename T >
+void ClearGlyphRuns( GlyphIndex startIndex,
+                     GlyphIndex endIndex,
+                     Vector<T>& runs,
+                     uint32_t& startRemoveIndex,
+                     uint32_t& endRemoveIndex )
+{
+  T* runsBuffer = runs.Begin();
+  T* run = runsBuffer;
+
+  const Length length = runs.Count();
+  Length index = 0u;
+  for( index = 0u; index < length; ++index )
+  {
+    if( ( run->glyphRun.glyphIndex <= endIndex ) &&
+        ( startIndex < run->glyphRun.glyphIndex + run->glyphRun.numberOfGlyphs ) )
+    {
+      // Run found.
+
+      // Set the index to the first run to be removed.
+      startRemoveIndex = index;
+      break;
+    }
+    ++run;
+  }
+
+  run = ( runsBuffer + startRemoveIndex );
+  for( index = startRemoveIndex; index < length; ++index )
+  {
+    if( ( run->glyphRun.glyphIndex > endIndex ) ||
+        ( startIndex >= run->glyphRun.glyphIndex + run->glyphRun.numberOfGlyphs ) )
+    {
+      // Run found. Nothing else to do.
+      break;
+    }
+
+    ++run;
+  }
+  endRemoveIndex = index;
+
+  // The number of glyphs to remove.
+  const Length numberOfGlyphsRemoved = 1u + endIndex - startIndex;
+
+  // Update the glyph index of the next runs.
+  run = runsBuffer;
+  for( Length index = 0u; index < length; ++index )
+  {
+
+    if( run->glyphRun.glyphIndex > startIndex )
+    {
+      run->glyphRun.glyphIndex -= numberOfGlyphsRemoved;
+    }
+  }
+}
+
+/**
+ * @brief Clears the runs starting from the given glyph index.
+ *
+ * @param[in] startIndex The starting glyph index used to remove runs.
+ * @param[in] endIndex The ending glyph index used to remove runs.
+ * @param[in,out] runs The text's runs.
+ */
+template< typename T >
+void ClearGlyphRuns( GlyphIndex startIndex,
+                     GlyphIndex endIndex,
+                     Vector<T>& runs )
+{
+  uint32_t startRemoveIndex = runs.Count();
+  uint32_t endRemoveIndex = startRemoveIndex;
+  ClearGlyphRuns( startIndex,
+                  endIndex,
+                  runs,
+                  startRemoveIndex,
+                  endRemoveIndex );
+
+  // Remove all remaining runs.
+  T* runBuffer = runs.Begin();
+  runs.Erase( runBuffer + startRemoveIndex, runBuffer + endRemoveIndex );
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_RUN_CONTAINER_H
diff --git a/dali-toolkit/internal/text/text-scroller-interface.h b/dali-toolkit/internal/text/text-scroller-interface.h
new file mode 100644 (file)
index 0000000..9cecc36
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef DALI_TOOLKIT_TEXT_SCROLLER_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_SCROLLER_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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
+{
+
+class Actor;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief An interface used by the text-controls which implement auto-scrolling
+ */
+class ScrollerInterface
+{
+public:
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~ScrollerInterface()
+  {}
+
+  /**
+   * @brief Called when the scrolling finishes
+   */
+  virtual void ScrollingFinished() = 0;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SCROLLER_INTERFACE_H
diff --git a/dali-toolkit/internal/text/text-scroller.cpp b/dali-toolkit/internal/text/text-scroller.cpp
new file mode 100644 (file)
index 0000000..6ad85d4
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/text/text-scroller.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/stage.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-scroller-interface.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+
+#if defined ( DEBUG_ENABLED )
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_SCROLLING");
+#endif
+
+const int MINIMUM_SCROLL_SPEED = 1; // Speed should be set by Property system.
+
+const char* VERTEX_SHADER_SCROLL = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying highp vec2 vTexCoord;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump float uDelta;\n
+  uniform mediump vec2 uTextureSize;\n
+  uniform mediump float uGap;\n
+  uniform mediump float uHorizontalAlign;\n
+  uniform mediump float uVerticalAlign;\n
+  \n
+  uniform highp   mat4 uMvpMatrix;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  void main()\n
+  {\n
+    mediump vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );\n
+    mediump vec2 visualSize = mix( uSize.xy * size, size, offsetSizeMode.zw );\n
+    \n
+    vTexCoord.x = ( uDelta + uHorizontalAlign * ( uTextureSize.x - visualSize.x - uGap ) + floor( aPosition.x * visualSize.x ) + 0.5 - uGap * 0.5 ) / uTextureSize.x + 0.5;\n
+    vTexCoord.y = ( uVerticalAlign * ( uTextureSize.y - visualSize.y ) + floor( aPosition.y * visualSize.y ) + 0.5 ) / ( uTextureSize.y ) + 0.5;\n
+    \n
+    mediump vec4 vertexPosition = vec4( floor( ( aPosition + anchorPoint ) * visualSize + ( visualOffset + origin ) * uSize.xy ), 0.0, 1.0 );\n
+    \n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying highp vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    if ( vTexCoord.y > 1.0 )\n
+      discard;\n
+    \n
+    mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
+    \n
+    gl_FragColor = textTexture * uColor * vec4( mixColor, 1.0 );
+  }\n
+);
+
+/**
+ * @brief How the text should be aligned horizontally when scrolling the text.
+ *
+ * -0.5f aligns the text to the left, 0.0f aligns the text to the center, 0.5f aligns the text to the right.
+ * The final alignment depends on two factors:
+ *   1) The alignment value of the text label (Use Text::HorizontalAlignment enumerations).
+ *   2) The text direction, i.e. whether it's LTR or RTL (0 = LTR, 1 = RTL).
+ */
+const float HORIZONTAL_ALIGNMENT_TABLE[ Text::HorizontalAlignment::END+1 ][ 2 ] =
+{
+  // HorizontalAlignment::BEGIN
+  {
+    -0.5f, // LTR
+    0.5f   // RTL
+  },
+
+  // HorizontalAlignment::CENTER
+  {
+    0.0f,  // LTR
+    0.0f   // RTL
+  },
+
+  // HorizontalAlignment::END
+  {
+    0.5f,  // LTR
+    -0.5f  // RTL
+  }
+};
+
+/**
+ * @brief How the text should be aligned vertically when scrolling the text.
+ *
+ * -0.5f aligns the text to the top, 0.0f aligns the text to the center, 0.5f aligns the text to the bottom.
+ * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
+ */
+const float VERTICAL_ALIGNMENT_TABLE[ Text::VerticalAlignment::BOTTOM+1 ] =
+{
+  -0.5f, // VerticalAlignment::TOP
+  0.0f,  // VerticalAlignment::CENTER
+  0.5f   // VerticalAlignment::BOTTOM
+};
+
+} // namespace
+
+namespace Text
+{
+
+TextScrollerPtr TextScroller::New( ScrollerInterface& scrollerInterface )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::New\n" );
+
+  TextScrollerPtr textScroller( new TextScroller( scrollerInterface) );
+  return textScroller;
+}
+
+void TextScroller::SetGap( int gap )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetGap gap[%d]\n", gap );
+  mWrapGap = static_cast<float>(gap);
+}
+
+int TextScroller::GetGap() const
+{
+  return static_cast<int>(mWrapGap);
+}
+
+void TextScroller::SetSpeed( int scrollSpeed )
+{
+  mScrollSpeed = std::max( MINIMUM_SCROLL_SPEED, scrollSpeed );
+}
+
+int TextScroller::GetSpeed() const
+{
+  return mScrollSpeed;
+}
+
+void TextScroller::SetLoopCount( int loopCount )
+{
+  if ( loopCount >= 0 )
+  {
+    mLoopCount = loopCount;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetLoopCount [%d] Status[%s]\n", mLoopCount, (loopCount)?"looping":"stop" );
+}
+
+int TextScroller::GetLoopCount() const
+{
+  return mLoopCount;
+}
+
+void TextScroller::SetLoopDelay( float delay )
+{
+  mLoopDelay = delay;
+}
+
+float TextScroller::GetLoopDelay() const
+{
+  return mLoopDelay;
+}
+
+void TextScroller::SetStopMode( TextLabel::AutoScrollStopMode::Type stopMode )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetAutoScrollStopMode [%s]\n",(stopMode == TextLabel::AutoScrollStopMode::IMMEDIATE)?"IMMEDIATE":"FINISH_LOOP" );
+  mStopMode = stopMode;
+}
+
+void TextScroller::StopScrolling()
+{
+  if ( mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING )
+  {
+    switch( mStopMode )
+    {
+      case TextLabel::AutoScrollStopMode::IMMEDIATE:
+      {
+        mScrollAnimation.Stop();
+        mScrollerInterface.ScrollingFinished();
+        break;
+      }
+      case TextLabel::AutoScrollStopMode::FINISH_LOOP:
+      {
+        mScrollAnimation.SetLoopCount( 1 ); // As animation already playing this allows the current animation to finish instead of trying to stop mid-way
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Undifined AutoScrollStopMode\n" );
+      }
+    }
+  }
+  else
+  {
+    mScrollerInterface.ScrollingFinished();
+  }
+}
+
+TextLabel::AutoScrollStopMode::Type TextScroller::GetStopMode() const
+{
+  return mStopMode;
+}
+
+TextScroller::TextScroller( ScrollerInterface& scrollerInterface )
+: mScrollerInterface( scrollerInterface ),
+  mScrollDeltaIndex( Property::INVALID_INDEX ),
+  mScrollSpeed( MINIMUM_SCROLL_SPEED ),
+  mLoopCount( 1 ),
+  mLoopDelay( 0.0f ),
+  mWrapGap( 0.0f ),
+  mStopMode( TextLabel::AutoScrollStopMode::FINISH_LOOP )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller Default Constructor\n" );
+}
+
+TextScroller::~TextScroller()
+{
+}
+
+void TextScroller::SetParameters( Actor scrollingTextActor, Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textureSize, const float wrapGap, CharacterDirection direction, HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters controlSize[%f,%f] textureSize[%f,%f] direction[%d]\n",
+                 controlSize.x, controlSize.y, textureSize.x, textureSize.y, direction );
+
+  mRenderer = renderer;
+
+  float animationProgress = 0.0f;
+  int   remainedLoop = mLoopCount;
+  if ( mScrollAnimation )
+  {
+    if( mScrollAnimation.GetState() == Animation::PLAYING )
+    {
+      animationProgress = mScrollAnimation.GetCurrentProgress();
+
+      if( mLoopCount > 0 ) // If not a ininity loop, then calculate remained loop
+      {
+        remainedLoop = mLoopCount - ( mScrollAnimation.GetCurrentLoop() );
+        remainedLoop = ( remainedLoop <= 0 ? 1 : remainedLoop );
+      }
+    }
+    mScrollAnimation.Clear();
+
+    // Reset to the original shader and texture before scrolling
+    mRenderer.SetShader(mShader);
+    mRenderer.SetTextures( mTextureSet );
+  }
+
+  mShader = mRenderer.GetShader();
+  mTextureSet = mRenderer.GetTextures();
+
+  // Set the shader and texture for scrolling
+  Shader shader = Shader::New( VERTEX_SHADER_SCROLL, FRAGMENT_SHADER, Shader::Hint::NONE );
+  mRenderer.SetShader( shader );
+  mRenderer.SetTextures( textureSet );
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters wrapGap[%f]\n", wrapGap );
+
+  float horizontalAlign;
+
+  if( textureSize.x > controlSize.x )
+  {
+    // if Text is elided, scroll should start at the begin of text.
+    horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[HorizontalAlignment::BEGIN][ direction ];
+  }
+  else
+  {
+    horizontalAlign = HORIZONTAL_ALIGNMENT_TABLE[ horizontalAlignment ][ direction ];
+  }
+
+  const float verticalAlign = VERTICAL_ALIGNMENT_TABLE[ verticalAlignment ];
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::SetParameters horizontalAlign[%f], verticalAlign[%f]\n", horizontalAlign, verticalAlign );
+
+  shader.RegisterProperty( "uTextureSize", textureSize );
+  shader.RegisterProperty( "uHorizontalAlign", horizontalAlign );
+  shader.RegisterProperty( "uVerticalAlign", verticalAlign );
+  shader.RegisterProperty( "uGap", wrapGap );
+  mScrollDeltaIndex = shader.RegisterProperty( "uDelta", 0.0f );
+
+  float scrollAmount = std::max( textureSize.width, controlSize.width );
+  float scrollDuration =  scrollAmount / mScrollSpeed;
+
+  if ( direction  )
+  {
+     scrollAmount = -scrollAmount; // reverse direction of scrolling
+  }
+
+  StartScrolling( scrollingTextActor, scrollAmount, scrollDuration, remainedLoop );
+  mScrollAnimation.SetCurrentProgress(animationProgress);
+}
+
+void TextScroller::AutoScrollAnimationFinished( Dali::Animation& animation )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::AutoScrollAnimationFinished\n" );
+  mScrollerInterface.ScrollingFinished();
+
+  // Revert to the original shader and texture after scrolling
+  mRenderer.SetShader(mShader);
+  if ( mTextureSet )
+  {
+    mRenderer.SetTextures( mTextureSet );
+  }
+}
+
+void TextScroller::StartScrolling( Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextScroller::StartScrolling scrollAmount[%f] scrollDuration[%f], loop[%d] speed[%d]\n", scrollAmount, scrollDuration, loopCount, mScrollSpeed );
+
+  Shader shader = mRenderer.GetShader();
+  mScrollAnimation = Animation::New( scrollDuration );
+  mScrollAnimation.AnimateTo( Property( shader, mScrollDeltaIndex ), scrollAmount, TimePeriod( mLoopDelay, scrollDuration ) );
+  mScrollAnimation.SetEndAction( Animation::Discard );
+  mScrollAnimation.SetLoopCount( loopCount );
+  mScrollAnimation.FinishedSignal().Connect( this, &TextScroller::AutoScrollAnimationFinished );
+  mScrollAnimation.Play();
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-scroller.h b/dali-toolkit/internal/text/text-scroller.h
new file mode 100644 (file)
index 0000000..16e350a
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef DALI_TOOLKIT_TEXT_SCROLLER_H
+#define DALI_TOOLKIT_TEXT_SCROLLER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class TextScroller;
+class ScrollerInterface;
+
+typedef IntrusivePtr<TextScroller> TextScrollerPtr;
+
+/**
+ * @brief A helper class for scrolling text
+ */
+class TextScroller : public RefObject, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Text Scrolling helper, used to automatically scroll text, SetParameters should be called before scrolling is needed.
+   * CleanUp removes the Scrolling actors from stage whilst keeping the Scroller object alive and preserving Speed, Gap and Loop count.
+   *
+   * @param[in] scrollerInterface scroller interface
+   */
+  static TextScrollerPtr New( ScrollerInterface& scrollerInterface );
+
+  /**
+   * @brief Set parameters relating to source required for scrolling
+   *
+   * @param[in] scrollingTextActor actor containing the text to be scrolled
+   * @param[in] renderer renderer to render the text
+   * @param[in] textureSet texture of the text to be scrolled
+   * @param[in] controlSize size of the control to scroll within
+   * @param[in] textureSize size of the texture
+   * @param[in] wrapGap The gap before scrolling wraps
+   * @param[in] direction text direction true for right to left text
+   * @param[in] horizontalAlignment horizontal alignment of the text
+   * @param[in] verticalAlignment vertical alignment of the text
+   */
+  void SetParameters( Actor scrollingTextActor, Dali::Renderer renderer, TextureSet textureSet, const Size& controlSize, const Size& textureSize, const float wrapGap, CharacterDirection direction, HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment );
+
+  /**
+   * @brief Set the gap distance to elapse before the text wraps around
+   * @param[in] gap distance to elapse
+   */
+  void SetGap( int gap );
+
+  /**
+   * @brief Get the distance before scrolling wraps
+   * @return gap distance to elapse
+   */
+  int GetGap() const;
+
+  /**
+   * @brief Set speed the text should scroll
+   * @param[in] scrollSpeed pixels per second
+   */
+  void SetSpeed( int scrollSpeed );
+
+  /**
+   * @brief Get the speed of text scrolling
+   * @return speed in pixels per second
+   */
+  int GetSpeed() const;
+
+  /**
+   * @brief Set the number of times the text scrolling should loop, can stop current scrolling by passing in 0;
+   * @param[in] loopCount number of times the scrolled text should loop, 0 to stop scrolling
+   */
+  void SetLoopCount( int loopCount );
+
+  /**
+   * @brief Get the number of loops
+   * @return int number of loops
+   */
+  int GetLoopCount() const;
+
+  /**
+   * @brief Set the delay time of scroll animation loop
+   * @param[in] float delay time seconds of loops
+   */
+  void SetLoopDelay( float delay );
+
+  /**
+   * @brief Get the delay time of scroll
+   * @return float delay time seconds of loops
+   */
+  float GetLoopDelay() const;
+
+  /**
+   * @brief Set the mode of scrolling stop
+   * @param[in] stopMode type when text scrolling is stoped.
+   */
+  void SetStopMode( TextLabel::AutoScrollStopMode::Type stopMode );
+
+  /**
+   * @brief Stop the auto scrolling.
+   */
+  void StopScrolling();
+
+  /**
+   * @brief Get the mode of scrolling stop
+   * @return stopMode type when text scrolling is stoped.
+   */
+  TextLabel::AutoScrollStopMode::Type GetStopMode() const;
+
+private: // Implementation
+
+  /**
+   * Constructor
+   */
+  TextScroller( ScrollerInterface& scrollerInterface );
+
+  /**
+   * Destructor
+   */
+  ~TextScroller();
+
+  // Undefined
+  TextScroller( const TextScroller& handle );
+
+  // Undefined
+  TextScroller& operator=( const TextScroller& handle );
+
+  /**
+   * @brief Callback for end of animation
+   * @param[in] animation Animation handle
+   */
+  void AutoScrollAnimationFinished( Dali::Animation& animation );
+
+  /**
+   * @brief variables required to set up scrolling animation
+   * @param[in] scrollingTextActor actor that shows scrolling text
+   * @param[in] scrollAmount distance to animate text for the given duration
+   * @param[in] scrollDuration duration of aninmation
+   * @param[in] loopCount number of times to loop the scrolling text
+   */
+  void StartScrolling( Actor scrollingTextActor, float scrollAmount, float scrollDuration, int loopCount );
+
+private:
+
+  ScrollerInterface& mScrollerInterface;        // Interface implemented by control that requires scrolling
+  Property::Index    mScrollDeltaIndex;         // Property used by shader to represent distance to scroll
+  Animation          mScrollAnimation;          // Animation used to update the mScrollDeltaIndex
+  Dali::Renderer     mRenderer;                 // Renderer used to render the text
+  Shader             mShader;                   // Shader originally used by the renderer while not scrolling
+  TextureSet         mTextureSet;               // Texture originally used by the renderer while not scrolling
+
+  int   mScrollSpeed;                                   ///< Speed which text should automatically scroll at
+  int   mLoopCount;                                     ///< Number of time the text should scroll
+  float mLoopDelay;                                     ///< Time delay of loop start
+  float mWrapGap;                                       ///< Gap before text wraps around when scrolling
+  TextLabel::AutoScrollStopMode::Type  mStopMode;       ///< Stop mode of scrolling text, when loop count is 0.
+
+}; // TextScroller class
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_SCROLLER_H
+
diff --git a/dali-toolkit/internal/text/text-vertical-scroller.cpp b/dali-toolkit/internal/text/text-vertical-scroller.cpp
new file mode 100644 (file)
index 0000000..b9d6606
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/text/text-vertical-scroller.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace
+{
+
+const float DEFAULT_VERTICAL_SCROLL_DURATION(0.15f);     ///< Duration to complete scroll animation
+
+} // namespace
+
+namespace Text
+{
+
+TextVerticalScrollerPtr TextVerticalScroller::New()
+{
+  TextVerticalScrollerPtr textScroller( new TextVerticalScroller() );
+  return textScroller;
+}
+
+TextVerticalScroller::TextVerticalScroller()
+: mDuration( DEFAULT_VERTICAL_SCROLL_DURATION ),
+  mScrollTo( 0.0f )
+{
+}
+
+TextVerticalScroller::~TextVerticalScroller()
+{
+}
+
+void TextVerticalScroller::CheckStartAnimation( Actor& sourceActor, float x, float y, float scrollAmount )
+{
+  if ( Equals( scrollAmount, 0.0f, Math::MACHINE_EPSILON_1 ) )
+  {
+    // scroll animation isn't required, set position only
+    if( mScrollAnimation && mScrollAnimation.GetState() == Animation::PLAYING )
+    {
+      mScrollAnimation.Clear();
+    }
+    sourceActor.SetPosition( x, y );
+    return;
+  }
+  float toY = y + scrollAmount;
+  // Either actor or scroll area is changed, so restart animation
+  if( mScrollAnimation )
+  {
+    mScrollAnimation.Clear();
+  }
+  else
+  {
+    // Create animation at first
+    mScrollAnimation = Animation::New( mDuration );
+  }
+  mScrollingActor = sourceActor;
+  mScrollTo = toY;
+
+  // Set animation attribute
+  sourceActor.SetPosition( x, y );
+  mScrollAnimation.AnimateTo( Property(sourceActor, Actor::Property::POSITION_Y), mScrollTo, AlphaFunction::EASE_OUT_SINE );
+  mScrollAnimation.Play();
+}
+
+void TextVerticalScroller::SetDuration( float duration )
+{
+  mDuration = duration;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-vertical-scroller.h b/dali-toolkit/internal/text/text-vertical-scroller.h
new file mode 100644 (file)
index 0000000..f6a005a
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_TOOLKIT_TEXT_VERTICAL_SCROLLER_H
+#define DALI_TOOLKIT_TEXT_VERTICAL_SCROLLER_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/actors/actor.h>
+#include <dali/public-api/animation/animation.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class TextVerticalScroller;
+
+typedef IntrusivePtr<TextVerticalScroller> TextVerticalScrollerPtr;
+
+/**
+ * @brief A helper class for scrolling text vertically
+ */
+class TextVerticalScroller : public RefObject, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Text Scrolling helper, used to automatically scroll text, StartScroll should be called when scrolling is needed.
+   *
+   */
+  static TextVerticalScrollerPtr New();
+
+  /**
+   * @brief variables required to set up scrolling animation
+   * @param[in] sourceActor actor to be animated
+   * @param[in] x The new x position
+   * @param[in] y The new y position
+   * @param[in] scrollAmount The distance to destination y position for actor to be animated
+   */
+  void CheckStartAnimation( Actor& sourceActor, float x, float y, float scrollAmount );
+
+  /**
+   * @brief Set duration the text should scroll
+   * @param[in] duration The duration in seconds
+   */
+  void SetDuration( float duration );
+
+private: // Implementation
+  /**
+   * Constructor
+   */
+  TextVerticalScroller();
+
+  /**
+   * @brief Virtual Destructor.
+   */
+  virtual ~TextVerticalScroller();
+
+private:
+
+  Animation          mScrollAnimation;          // Animation used to update the actor's position
+  Actor              mScrollingActor;           // The actor being animated
+  float              mDuration;                 // The duration of text scrolling
+  float              mScrollTo;                 // The destination y position
+}; // TextVerticalScroller class
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VERTICAL_SCROLLER_H
diff --git a/dali-toolkit/internal/text/text-view-interface.cpp b/dali-toolkit/internal/text/text-view-interface.cpp
new file mode 100644 (file)
index 0000000..54d1589
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 <dali-toolkit/internal/text/text-view-interface.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+ViewInterface::ViewInterface()
+{
+}
+
+ViewInterface::~ViewInterface()
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h
new file mode 100755 (executable)
index 0000000..4aad47b
--- /dev/null
@@ -0,0 +1,212 @@
+#ifndef DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H
+#define DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+namespace Dali
+{
+
+struct Vector2;
+struct Vector4;
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct GlyphRun;
+
+/**
+ * @brief Abstract interface to provide the information necessary to display text.
+ *
+ * This includes:
+ * - The font & glyph IDs needed to get bitmaps etc. from TextAbstraction
+ * - The visual position of each glyph within the layout
+ * - A window into the text layout e.g. which page of a document to view
+ */
+class ViewInterface
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  ViewInterface();
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~ViewInterface();
+
+  /**
+   * @brief Retrieves the target size of the UI control.
+   *
+   * @return The control's size.
+   */
+  virtual const Vector2& GetControlSize() const = 0;
+
+  /**
+   * @brief Retrieves the text's layout size.
+   *
+   * @return The text's size. Note that this may be larger than the control size,
+   * in the case where text is scrolling/clipped.
+   */
+  virtual const Vector2& GetLayoutSize() const = 0;
+
+  /**
+   * Retrieves the number of glyphs.
+   *
+   * @return The number of glyphs.
+   */
+  virtual Length GetNumberOfGlyphs() const = 0;
+
+  /**
+   * @brief Retrieves glyphs and positions in the given buffers.
+   *
+   * @note The size of the @p glyphs and @p glyphPositions buffers need to be big enough to copy the @p numberOfGlyphs glyphs and positions.
+   * @note The returned number of glyphs may be less than @p numberOfGlyphs if a line has ellipsis.
+   *
+   * @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] minLineOffset The minimum line offset.
+   * @param[in] glyphIndex Index to the first glyph.
+   * @param[in] numberOfGlyphs Number of glyphs to be copied.
+   *
+   * @return The number of glyphs.
+   */
+  virtual Length GetGlyphs( GlyphInfo* glyphs,
+                            Vector2* glyphPositions,
+                            float& minLineOffset,
+                            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 vector of background colors.
+   *
+   * @return Pointer to the vector of background colors.
+   */
+  virtual const Vector4* const GetBackgroundColors() const = 0;
+
+  /**
+   * @brief Retrieves the vector of indices to the vector of background colors.
+   *
+   * @return Pointer to a vector which stores for each glyph the index to the vector of background colors.
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
+
+  /**
+   * @brief Retrieves the text color
+   *
+   * @return The text color
+   */
+  virtual const Vector4& GetTextColor() const = 0;
+
+  /**
+   * @brief Retrieves the shadow offset, 0 indicates no shadow.
+   *
+   * @return The shadow offset.
+   */
+  virtual const Vector2& GetShadowOffset() const = 0;
+
+  /**
+   * @brief Retrieves the shadow color.
+   *
+   * @return The shadow color.
+   */
+  virtual const Vector4& GetShadowColor() const = 0;
+
+  /**
+   * @brief Retrieves the underline color.
+   *
+   * @return The underline color.
+   */
+  virtual const Vector4& GetUnderlineColor() const = 0;
+
+  /**
+   * @brief Returns whether underline is enabled or not.
+   *
+   * @return The underline state.
+   */
+  virtual bool IsUnderlineEnabled() const = 0;
+
+  /**
+   * @brief Retrieves the underline height override
+   *
+   * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height
+   */
+  virtual float GetUnderlineHeight() const = 0;
+
+  /**
+   * @brief Retrieves the number of underline runs.
+   *
+   * @return The number of underline runs.
+   */
+  virtual Length GetNumberOfUnderlineRuns() const = 0;
+
+  /**
+   * @brief Retrieves the underline runs.
+   *
+   * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+   * @param[in] index Index of the first underline run to be copied.
+   * @param[in] numberOfRuns Number of underline runs to be copied.
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns,
+                                 UnderlineRunIndex index,
+                                 Length numberOfRuns ) const = 0;
+
+  /**
+   * @brief Retrieve the outline color.
+   *
+   * @return The outline color.
+   */
+  virtual const Vector4& GetOutlineColor() const = 0;
+
+  /**
+   * @brief Retrieves the width of an outline
+   *
+   * @return The width of the outline.
+   */
+  virtual uint16_t GetOutlineWidth() const = 0;
+
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H
diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp
new file mode 100755 (executable)
index 0000000..9d9f991
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/text-view.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector2.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct View::Impl
+{
+  VisualModelPtr mVisualModel;
+  TextAbstraction::FontClient mFontClient; ///< Handle to the font client.
+};
+
+View::View()
+: mImpl( NULL )
+{
+  mImpl = new View::Impl();
+
+  mImpl->mFontClient = TextAbstraction::FontClient::Get();
+}
+
+View::~View()
+{
+  delete mImpl;
+}
+
+void View::SetVisualModel( VisualModelPtr visualModel )
+{
+  mImpl->mVisualModel = visualModel;
+}
+
+const Vector2& View::GetControlSize() const
+{
+  if ( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mControlSize;
+  }
+
+  return Vector2::ZERO;
+}
+
+const Vector2& View::GetLayoutSize() const
+{
+  if ( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetLayoutSize();
+  }
+
+  return Vector2::ZERO;
+}
+
+Length View::GetNumberOfGlyphs() const
+{
+  if( mImpl->mVisualModel )
+  {
+    const VisualModel& model = *mImpl->mVisualModel;
+
+    const Length glyphCount = model.mGlyphs.Count();
+    const Length positionCount = model.mGlyphPositions.Count();
+
+    DALI_ASSERT_DEBUG( positionCount <= glyphCount && "Invalid glyph positions in Model" );
+
+    return (positionCount < glyphCount) ? positionCount : glyphCount;
+  }
+
+  return 0;
+}
+
+Length View::GetGlyphs( GlyphInfo* glyphs,
+                        Vector2* glyphPositions,
+                        float& minLineOffset,
+                        GlyphIndex glyphIndex,
+                        Length numberOfGlyphs ) const
+{
+  Length numberOfLaidOutGlyphs = 0u;
+
+  if( mImpl->mVisualModel )
+  {
+    // If ellipsis is enabled, the number of glyphs the layout engine has laid out may be less than 'numberOfGlyphs'.
+    // Check the last laid out line to know if the layout engine elided some text.
+
+    const Length numberOfLines = mImpl->mVisualModel->mLines.Count();
+    if( numberOfLines > 0u )
+    {
+      const LineRun& lastLine = *( mImpl->mVisualModel->mLines.Begin() + ( numberOfLines - 1u ) );
+
+      // If ellipsis is enabled, calculate the number of laid out glyphs.
+      // Otherwise use the given number of glyphs.
+      if( lastLine.ellipsis )
+      {
+        numberOfLaidOutGlyphs = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+      }
+      else
+      {
+        numberOfLaidOutGlyphs = numberOfGlyphs;
+      }
+
+      if( 0u < numberOfLaidOutGlyphs )
+      {
+        // Retrieve from the visual model the glyphs and positions.
+        mImpl->mVisualModel->GetGlyphs( glyphs,
+                                        glyphIndex,
+                                        numberOfLaidOutGlyphs );
+
+        mImpl->mVisualModel->GetGlyphPositions( glyphPositions,
+                                                glyphIndex,
+                                                numberOfLaidOutGlyphs );
+
+        // 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;
+        Length numberOfLines = 0u;
+        mImpl->mVisualModel->GetNumberOfLines( glyphIndex,
+                                               numberOfLaidOutGlyphs,
+                                               firstLine,
+                                               numberOfLines );
+
+        Vector<LineRun> lines;
+        lines.Resize( numberOfLines );
+        LineRun* lineBuffer = lines.Begin();
+
+        mImpl->mVisualModel->GetLinesOfGlyphRange( lineBuffer,
+                                                   glyphIndex,
+                                                   numberOfLaidOutGlyphs );
+
+        // Get the first line for the given glyph range.
+        LineIndex lineIndex = firstLine;
+        LineRun* line = lineBuffer + lineIndex;
+
+        // Index of the last glyph of the line.
+        GlyphIndex lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
+
+        // Add the alignment offset to the glyph's position.
+
+        minLineOffset = line->alignmentOffset;
+        float penY = line->ascender;
+        for( Length index = 0u; index < numberOfLaidOutGlyphs; ++index )
+        {
+          Vector2& position =  *( glyphPositions + index );
+          position.x += line->alignmentOffset;
+          position.y += penY;
+
+          if( lastGlyphIndexOfLine == index )
+          {
+            penY += -line->descender;
+
+            // Get the next line.
+            ++lineIndex;
+
+            if( lineIndex < numberOfLines )
+            {
+              line = lineBuffer + lineIndex;
+              minLineOffset = std::min( minLineOffset, line->alignmentOffset );
+
+              lastGlyphIndexOfLine = line->glyphRun.glyphIndex + line->glyphRun.numberOfGlyphs - 1u;
+
+              penY += line->ascender;
+            }
+          }
+        }
+
+        if( 1u == numberOfLaidOutGlyphs )
+        {
+          // not a point try to do ellipsis with only one laid out character.
+          return numberOfLaidOutGlyphs;
+        }
+
+        if( lastLine.ellipsis )
+        {
+          if( ( 1u == numberOfLines ) &&
+              ( lastLine.ascender - lastLine.descender > mImpl->mVisualModel->mControlSize.height ) )
+          {
+            // Get the first glyph which is going to be replaced and the ellipsis glyph.
+            GlyphInfo& glyphInfo = *glyphs;
+            const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphInfo.fontId ) );
+
+            // Change the 'x' and 'y' position of the ellipsis glyph.
+            Vector2& position = *glyphPositions;
+            position.x = ellipsisGlyph.xBearing;
+            position.y = mImpl->mVisualModel->mControlSize.height - ellipsisGlyph.yBearing;
+
+            // Replace the glyph by the ellipsis glyph.
+            glyphInfo = ellipsisGlyph;
+
+             return 1u;
+          }
+
+          // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed.
+          float firstPenX = 0.f; // Used if rtl text is elided.
+          float penY = 0.f;
+          bool firstPenSet = false;
+
+          // Add the ellipsis glyph.
+          bool inserted = false;
+          float removedGlypsWidth = 0.f;
+          Length numberOfRemovedGlyphs = 0u;
+          GlyphIndex index = numberOfLaidOutGlyphs - 1u;
+
+          // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed.
+          while( !inserted )
+          {
+            const GlyphInfo& glyphToRemove = *( glyphs + index );
+
+            if( 0u != glyphToRemove.fontId )
+            {
+              // i.e. The font id of the glyph shaped from the '\n' character is zero.
+
+              // Need to reshape the glyph as the font may be different in size.
+              const GlyphInfo& ellipsisGlyph = mImpl->mFontClient.GetEllipsisGlyph( mImpl->mFontClient.GetPointSize( glyphToRemove.fontId ) );
+
+              if( !firstPenSet )
+              {
+                const Vector2& position = *( glyphPositions + index );
+
+                // Calculates the penY of the current line. It will be used to position the ellipsis glyph.
+                penY = position.y + glyphToRemove.yBearing;
+
+                // Calculates the first penX which will be used if rtl text is elided.
+                firstPenX = position.x - glyphToRemove.xBearing;
+                if( firstPenX < -ellipsisGlyph.xBearing )
+                {
+                  // Avoids to exceed the bounding box when rtl text is elided.
+                  firstPenX = -ellipsisGlyph.xBearing;
+                }
+
+                removedGlypsWidth = -ellipsisGlyph.xBearing;
+
+                firstPenSet = true;
+              }
+
+              removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) );
+
+              // Calculate the width of the ellipsis glyph and check if it fits.
+              const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
+              if( ellipsisGlyphWidth < removedGlypsWidth )
+              {
+                GlyphInfo& glyphInfo = *( glyphs + index );
+                Vector2& position = *( glyphPositions + index );
+                position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f;
+
+                // Replace the glyph by the ellipsis glyph.
+                glyphInfo = ellipsisGlyph;
+
+                // Change the 'x' and 'y' position of the ellipsis glyph.
+
+                if( position.x > firstPenX )
+                {
+                  position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+                }
+
+                position.x += ellipsisGlyph.xBearing;
+                position.y = penY - ellipsisGlyph.yBearing;
+
+                inserted = true;
+              }
+            }
+
+            if( !inserted )
+            {
+              if( index > 0u )
+              {
+                --index;
+              }
+              else
+              {
+                // No space for the ellipsis.
+                inserted = true;
+              }
+              ++numberOfRemovedGlyphs;
+            }
+          }
+
+          // 'Removes' all the glyphs after the ellipsis glyph.
+          numberOfLaidOutGlyphs -= numberOfRemovedGlyphs;
+        }
+      }
+    }
+  }
+
+  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* const View::GetBackgroundColors() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mBackgroundColors.Begin();
+  }
+
+  return nullptr;
+}
+
+const ColorIndex* const View::GetBackgroundColorIndices() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mBackgroundColorIndices.Begin();
+  }
+
+  return nullptr;
+}
+
+const Vector4& View::GetTextColor() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetTextColor();
+  }
+  return Vector4::ZERO;
+}
+
+const Vector2& View::GetShadowOffset() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetShadowOffset();
+  }
+  return Vector2::ZERO;
+}
+
+const Vector4& View::GetShadowColor() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetShadowColor();
+  }
+  return Vector4::ZERO;
+}
+
+const Vector4& View::GetUnderlineColor() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetUnderlineColor();
+  }
+  return Vector4::ZERO;
+}
+
+bool View::IsUnderlineEnabled() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->IsUnderlineEnabled();
+  }
+  return false;
+}
+
+float View::GetUnderlineHeight() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetUnderlineHeight();
+  }
+  return 0.0f;
+}
+
+Length View::GetNumberOfUnderlineRuns() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetNumberOfUnderlineRuns();
+  }
+
+  return 0u;
+}
+
+void View::GetUnderlineRuns( GlyphRun* underlineRuns,
+                             UnderlineRunIndex index,
+                             Length numberOfRuns ) const
+{
+  if( mImpl->mVisualModel )
+  {
+    mImpl->mVisualModel->GetUnderlineRuns( underlineRuns,
+                                           index,
+                                           numberOfRuns );
+  }
+}
+
+const Vector4& View::GetOutlineColor() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetOutlineColor();
+  }
+  return Vector4::ZERO;
+}
+
+uint16_t View::GetOutlineWidth() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->GetOutlineWidth();
+  }
+  return 0u;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h
new file mode 100755 (executable)
index 0000000..91b7867
--- /dev/null
@@ -0,0 +1,173 @@
+#ifndef DALI_TOOLKIT_TEXT_VIEW_H
+#define DALI_TOOLKIT_TEXT_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-view-interface.h>
+#include <dali-toolkit/internal/text/visual-model-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief View provides an interface between the Text layout engine and rendering back-end.
+ */
+class View : public ViewInterface
+{
+public:
+
+  /**
+   * @brief Create a new instance of a View.
+   */
+  View();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~View();
+
+  /**
+   * @brief Set the visual model.
+   *
+   * @param[in] visualModel The visual model used by the View.
+   */
+  void SetVisualModel( VisualModelPtr visualModel );
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetControlSize()
+   */
+  virtual const Vector2& GetControlSize() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetLayoutSize()
+   */
+  virtual const Vector2& GetLayoutSize() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetNumberOfGlyphs()
+   */
+  virtual Length GetNumberOfGlyphs() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetGlyphs()
+   */
+  virtual Length GetGlyphs( GlyphInfo* glyphs,
+                            Vector2* glyphPositions,
+                            float& minLineOffset,
+                            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::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetTextColor()
+   */
+  virtual const Vector4& GetTextColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetShadowOffset()
+   */
+  virtual const Vector2& GetShadowOffset() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetShadowColor()
+   */
+  virtual const Vector4& GetShadowColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight()
+   */
+  virtual float GetUnderlineHeight() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetNumberOfUnderlineRuns()
+   */
+  virtual Length GetNumberOfUnderlineRuns() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineRuns()
+   */
+  virtual void GetUnderlineRuns( GlyphRun* underlineRuns,
+                                 UnderlineRunIndex index,
+                                 Length numberOfRuns ) const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineColor()
+   */
+  virtual const Vector4& GetOutlineColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineWidth()
+   */
+  virtual uint16_t GetOutlineWidth() const;
+
+private:
+
+  // Undefined
+  View( const View& handle );
+
+  // Undefined
+  View& operator=( const View& handle );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VIEW_H
diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp
new file mode 100755 (executable)
index 0000000..6a06e58
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/text/visual-model-impl.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+VisualModelPtr VisualModel::New()
+{
+  return VisualModelPtr( new VisualModel() );
+}
+
+void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex,
+                                               GlyphIndex startGlyphIndex,
+                                               Length numberOfCharacters )
+{
+  if( 0u == numberOfCharacters )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u );
+
+  // Get the total number of characters.
+  const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  Vector<GlyphIndex> newCharactersToGlyph;
+  GlyphIndex* charactersToGlyphBuffer = NULL;
+
+  // 1) Reserve some space for the glyph indices to avoid reallocations.
+  if( updateCurrentBuffer )
+  {
+    newCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = newCharactersToGlyph.Begin();
+  }
+  else
+  {
+    mCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex;
+  }
+
+  const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
+
+  // 2) Traverse the glyphs and set the glyph indices per character.
+
+  // Index to the glyph.
+  GlyphIndex glyphIndex = startGlyphIndex;
+  CharacterIndex characterIndex = startIndex;
+  const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
+  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex,
+         endIt = mCharactersPerGlyph.End();
+       ( it != endIt ) && ( characterIndex < lastCharacterIndexPlusOne );
+       ++it )
+  {
+    const Length numberOfCharactersPerGlyph = *it;
+
+    Length numberOfGlyphs = 0u;
+    // Set the glyph indices.
+    for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
+    {
+      *charactersToGlyphBuffer = glyphIndex;
+      numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex );
+      ++charactersToGlyphBuffer;
+    }
+    glyphIndex += numberOfGlyphs;
+  }
+
+  // If the character to glyph buffer is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    // Update the indices.
+    const Length numberOfGlyphs = glyphIndex - startGlyphIndex;
+    for( Vector<Length>::Iterator it = mCharactersToGlyph.Begin() + startIndex,
+           endIt = mCharactersToGlyph.End();
+         it != endIt;
+         ++it )
+    {
+      *it += numberOfGlyphs;
+    }
+
+    mCharactersToGlyph.Insert( mCharactersToGlyph.Begin() + startIndex,
+                               newCharactersToGlyph.Begin(),
+                               newCharactersToGlyph.End() );
+
+  }
+}
+
+void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+                                                 GlyphIndex startGlyphIndex,
+                                                 Length numberOfCharacters )
+{
+  if( 0u == numberOfCharacters )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  // Get the total number of characters.
+  const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  Vector<Length> newGlyphsPerCharacter;
+  Length* glyphsPerCharacterBuffer = NULL;
+
+  // 1) Reserve some space for the glyphs per character to avoid reallocations.
+  if( updateCurrentBuffer )
+  {
+    newGlyphsPerCharacter.Resize( numberOfCharacters );
+    glyphsPerCharacterBuffer = newGlyphsPerCharacter.Begin();
+  }
+  else
+  {
+    mGlyphsPerCharacter.Resize( numberOfCharacters );
+    glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin() + startIndex;
+  }
+
+  // 2) Traverse the glyphs and set the number of glyphs per character.
+
+  Length traversedCharacters = 0;
+
+  // The number of 'characters per glyph' equal to zero.
+  Length zeroCharactersPerGlyph = 0u;
+
+  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + startGlyphIndex,
+         endIt = mCharactersPerGlyph.End();
+       ( it != endIt ) && ( traversedCharacters < numberOfCharacters );
+       ++it )
+  {
+    const Length numberOfCharactersPerGlyph = *it;
+    traversedCharacters += numberOfCharactersPerGlyph;
+
+    // Set the glyphs per character.
+    if( 0u == numberOfCharactersPerGlyph )
+    {
+      ++zeroCharactersPerGlyph;
+    }
+    else
+    {
+      const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u );
+      for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter; ++zeroIndex )
+      {
+        *glyphsPerCharacterBuffer = 0u;
+
+        // Point to the next position in the buffer.
+        ++glyphsPerCharacterBuffer;
+      }
+
+      *glyphsPerCharacterBuffer = zeroCharactersPerGlyph + 1u;
+
+      zeroCharactersPerGlyph = 0u;
+
+      // Point to the next position in the buffer.
+      ++glyphsPerCharacterBuffer;
+    }
+  }
+
+  // If the glyphs per character buffer is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    mGlyphsPerCharacter.Insert( mGlyphsPerCharacter.Begin() + startIndex,
+                                newGlyphsPerCharacter.Begin(),
+                                newGlyphsPerCharacter.End() );
+  }
+}
+
+void VisualModel::GetGlyphs( GlyphInfo* glyphs,
+                             GlyphIndex glyphIndex,
+                             Length numberOfGlyphs ) const
+{
+  memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
+}
+
+void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
+                                     GlyphIndex glyphIndex,
+                                     Length numberOfGlyphs ) const
+{
+  memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
+}
+
+void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
+                                    Length numberOfGlyphs,
+                                    LineIndex& firstLine,
+                                    Length& numberOfLines ) const
+{
+  // Initialize the number of lines and the first line.
+  firstLine = 0u;
+  numberOfLines = 0u;
+  bool firstLineFound = false;
+
+  const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
+
+  // Traverse the lines and count those lines within the range of glyphs.
+  for( Vector<LineRun>::ConstIterator it = mLines.Begin(),
+         endIt = mLines.End();
+       it != endIt;
+       ++it )
+  {
+    const LineRun& line = *it;
+
+    if( ( line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex ) &&
+        ( lastGlyphIndex > line.glyphRun.glyphIndex ) )
+    {
+      firstLineFound = true;
+      ++numberOfLines;
+    }
+    else if( lastGlyphIndex <= line.glyphRun.glyphIndex )
+    {
+      // nothing else to do.
+      break;
+    }
+
+    if( !firstLineFound )
+    {
+      ++firstLine;
+    }
+  }
+}
+
+void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
+                                        GlyphIndex glyphIndex,
+                                        Length numberOfGlyphs ) const
+{
+  LineIndex firstLine = 0u;
+  Length numberOfLines = 0u;
+
+  GetNumberOfLines( glyphIndex,
+                    numberOfGlyphs,
+                    firstLine,
+                    numberOfLines );
+
+  memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
+}
+
+LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
+{
+  // 1) Check line is empty or not.
+  if( mLines.Empty() )
+  {
+    return 0u;
+  }
+
+  // 2) Check in the cached line.
+  const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
+  if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
+      ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
+  {
+    return mCachedLineIndex;
+  }
+
+  // 3) Is not in the cached line. Check in the other lines.
+  LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
+
+  for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
+         endIt = mLines.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const LineRun& lineRun = *it;
+
+    if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
+    {
+      mCachedLineIndex = index;
+      break;
+    }
+  }
+
+  return index;
+}
+
+void VisualModel::GetUnderlineRuns( GlyphRun* underlineRuns,
+                                    UnderlineRunIndex index,
+                                    Length numberOfRuns ) const
+{
+  memcpy( underlineRuns,
+          mUnderlineRuns.Begin() + index,
+          numberOfRuns * sizeof( GlyphRun ) );
+}
+
+void VisualModel::SetNaturalSize( const Vector2& size  )
+{
+  mNaturalSize = size;
+}
+
+const Vector2& VisualModel::GetNaturalSize() const
+{
+  return mNaturalSize;
+}
+
+void VisualModel::SetLayoutSize( const Vector2& size )
+{
+  mLayoutSize = size;
+}
+
+const Vector2& VisualModel::GetLayoutSize() const
+{
+  return mLayoutSize;
+}
+
+void VisualModel::SetTextColor( const Vector4& textColor )
+{
+  mTextColor = textColor;
+
+  if ( !mUnderlineColorSet )
+  {
+    mUnderlineColor = textColor;
+  }
+}
+
+void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
+{
+  mShadowOffset = shadowOffset;
+}
+
+void VisualModel::SetShadowColor( const Vector4& shadowColor )
+{
+  mShadowColor = shadowColor;
+}
+
+void VisualModel::SetShadowBlurRadius( const float& shadowBlurRadius )
+{
+  mShadowBlurRadius = shadowBlurRadius;
+}
+
+void VisualModel::SetUnderlineColor( const Vector4& color )
+{
+  mUnderlineColor = color;
+  mUnderlineColorSet = true;
+}
+
+void VisualModel::SetOutlineColor( const Vector4& color )
+{
+  mOutlineColor = color;
+}
+
+void VisualModel::SetUnderlineEnabled( bool enabled )
+{
+  mUnderlineEnabled = enabled;
+}
+
+void VisualModel::SetUnderlineHeight( float height )
+{
+  mUnderlineHeight = height;
+}
+
+void VisualModel::SetOutlineWidth( uint16_t width )
+{
+  mOutlineWidth = width;
+}
+
+void VisualModel::SetBackgroundColor( const Vector4& color )
+{
+  mBackgroundColor = color;
+}
+
+void VisualModel::SetBackgroundEnabled( bool enabled )
+{
+  mBackgroundEnabled = enabled;
+}
+
+const Vector4& VisualModel::GetTextColor() const
+{
+  return mTextColor;
+}
+
+const Vector2& VisualModel::GetShadowOffset() const
+{
+  return mShadowOffset;
+}
+
+const Vector4& VisualModel::GetShadowColor() const
+{
+  return mShadowColor;
+}
+
+const float& VisualModel::GetShadowBlurRadius() const
+{
+  return mShadowBlurRadius;
+}
+
+const Vector4& VisualModel::GetUnderlineColor() const
+{
+  return mUnderlineColor;
+}
+
+const Vector4& VisualModel::GetOutlineColor() const
+{
+  return mOutlineColor;
+}
+
+bool VisualModel::IsUnderlineEnabled() const
+{
+  return mUnderlineEnabled;
+}
+
+float VisualModel::GetUnderlineHeight() const
+{
+  return mUnderlineHeight;
+}
+
+uint16_t VisualModel::GetOutlineWidth() const
+{
+  return mOutlineWidth;
+}
+
+const Vector4& VisualModel::GetBackgroundColor() const
+{
+  return mBackgroundColor;
+}
+
+bool VisualModel::IsBackgroundEnabled() const
+{
+  return mBackgroundEnabled;
+}
+
+Length VisualModel::GetNumberOfUnderlineRuns() const
+{
+  return mUnderlineRuns.Count();
+}
+
+void VisualModel::ClearCaches()
+{
+  mCachedLineIndex = 0u;
+}
+
+VisualModel::~VisualModel()
+{
+}
+
+VisualModel::VisualModel()
+: mGlyphs(),
+  mGlyphsToCharacters(),
+  mCharactersToGlyph(),
+  mCharactersPerGlyph(),
+  mGlyphsPerCharacter(),
+  mGlyphPositions(),
+  mLines(),
+  mTextColor( Color::BLACK ),
+  mShadowColor( Color::BLACK ),
+  mUnderlineColor( Color::BLACK ),
+  mOutlineColor( Color::WHITE ),
+  mBackgroundColor( Color::TRANSPARENT ),
+  mControlSize(),
+  mShadowOffset(),
+  mUnderlineHeight( 0.0f ),
+  mShadowBlurRadius( 0.0f ),
+  mOutlineWidth( 0u ),
+  mNaturalSize(),
+  mLayoutSize(),
+  mCachedLineIndex( 0u ),
+  mUnderlineEnabled( false ),
+  mUnderlineColorSet( false ),
+  mBackgroundEnabled( false )
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h
new file mode 100755 (executable)
index 0000000..853e946
--- /dev/null
@@ -0,0 +1,427 @@
+#ifndef DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H
+#define DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/color-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class VisualModel;
+typedef IntrusivePtr<VisualModel> VisualModelPtr;
+
+/**
+ * @brief A visual text model contains layout specific information.
+ *
+ * This includes:
+ * - A series of glyphs in visual order i.e. after the bidirectional reordering.
+ * - The position of each glyph within a 2D bounding box.
+ */
+class VisualModel : public RefObject
+{
+public:
+
+  /**
+   * @brief Create a new instance of a VisualModel.
+   *
+   * @return A pointer to a new VisualModel.
+   */
+  static VisualModelPtr New();
+
+  // Glyph interface.
+
+  /**
+   * @brief Creates the character to glyph conversion table.
+   *
+   * @pre The glyphs per character table needs to be created first.
+   *
+   * @param[in] startIndex The character from where the conversion table is created.
+   * @param[in] startGlyphIndex The glyph from where the conversion table is created.
+   * @param[in] numberOfCharacters The number of characters.
+   */
+  void CreateCharacterToGlyphTable( CharacterIndex startIndex,
+                                    GlyphIndex startGlyphIndex,
+                                    Length numberOfCharacters );
+
+  /**
+   * @brief Creates an array containing the number of glyphs per character.
+   *
+   * @param[in] startIndex The character from where the table is created.
+   * @param[in] startGlyphIndex The glyph from where the conversion table is created.
+   * @param[in] numberOfCharacters The number of characters.
+   */
+  void CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+                                      GlyphIndex startGlyphIndex,
+                                      Length numberOfCharacters );
+
+  /**
+   * @brief Retrieves glyphs in the given buffer.
+   *
+   * The size of the @p glyphs buffer needs to be big enough to copy the @p numberOfGlyphs.
+   * @param[out] glyphs Pointer to a buffer where the glyphs are copied.
+   * @param[in] glyphIndex Index to the first glyph.
+   * @param[in] numberOfGlyphs Number of glyphs to be copied.
+   */
+  void GetGlyphs( GlyphInfo* glyphs,
+                  GlyphIndex glyphIndex,
+                  Length numberOfGlyphs ) const;
+
+  // Position interface
+
+  /**
+   * @brief Retrieves the glyph positions.
+   *
+   * @pre The size of the @p positions buffer needs to be big enough to copy the @p numberOfGlyphs positions.
+   * @param[out] glyphPositions Pointer to a buffer where the glyph positions are copied.
+   * @param[in] glyphIndex Index to the first glyph position.
+   * @param[in] numberOfGlyphs The number of positions to be copied.
+   */
+  void GetGlyphPositions( Vector2* glyphPositions,
+                          GlyphIndex glyphIndex,
+                          Length numberOfGlyphs ) const;
+
+  // Line interface.
+
+  /**
+   * @brief Retrieves the number of lines and the index to the first line where the given range of glyphs is laid out.
+   *
+   * @param[in] glyphIndex Index to the first glyph.
+   * @param[in] numberOfGlyphs The number of glyph.
+   * @param[out] firstLine Index to the line containing the glyph index.
+   * @param[out] numberOfLines The number of lines.
+   */
+  void GetNumberOfLines( GlyphIndex glyphIndex,
+                         Length numberOfGlyphs,
+                         LineIndex& firstLine,
+                         Length& numberOfLines ) const;
+
+  /**
+   * @brief Retrieves the lines where the given range of glyphs is laid out.
+   *
+   * The size of the @p lines buffer needs to be big enough to copy the @p numberOfLines.
+   *
+   * @param[out] lines Pointer to a buffer where the lines are copied.
+   * @param[in] glyphIndex Index to the first glyphs of the range.
+   * @param[in] numberOfGlyphs Number of glyphs in the range.
+   */
+  void GetLinesOfGlyphRange( LineRun* lines,
+                             GlyphIndex glyphIndex,
+                             Length numberOfGlyphs ) const;
+
+  /**
+   * @brief Retrieves the line index where the character is laid-out.
+   *
+   * @param[in] characterIndex The character's index.
+   *
+   * @return The line index.
+   */
+  LineIndex GetLineOfCharacter( CharacterIndex characterIndex );
+
+  // Underline runs
+
+  /**
+   * @brief Retrieves the underline runs.
+   *
+   * @param[out] underlineRuns Pointer to a buffer where the underline runs are copied.
+   * @param[in] index Index of the first underline run to be copied.
+   * @param[in] numberOfRuns Number of underline runs to be copied.
+   */
+  void GetUnderlineRuns( GlyphRun* underlineRuns,
+                         UnderlineRunIndex index,
+                         Length numberOfRuns ) const;
+
+  // Size interface
+
+  /**
+   * @brief Sets the natural size.
+   *
+   * @param[in] size The text's natural size.
+   */
+  void SetNaturalSize( const Vector2& size  );
+
+  /**
+   * @brief Retrieves the natural size.
+   *
+   * @return The text's natural size.
+   */
+  const Vector2& GetNaturalSize() const;
+
+  /**
+   * @brief Sets the text's layout size.
+   *
+   * @param[in] size The text's size.
+   */
+  void SetLayoutSize( const Vector2& size );
+
+  /**
+   * @brief Retrieves the text's layout size.
+   *
+   * @return The text's size.
+   */
+  const Vector2& GetLayoutSize() const;
+
+  /**
+   * @brief Set the text's color
+   *
+   * @param[in] textColor The text's color
+   */
+  void SetTextColor( const Vector4& textColor );
+
+  /**
+   * @brief Retrieve the text's color
+   *
+   * @return The text's color
+   */
+  const Vector4& GetTextColor() const;
+
+  /**
+   * @brief Sets the text's shadow offset.
+   *
+   * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
+   */
+  void SetShadowOffset( const Vector2& shadowOffset );
+
+  /**
+   * @brief Retrieves the text's shadow offset.
+   *
+   * @return The text's shadow offset, 0,0 indicates no shadow.
+   */
+  const Vector2& GetShadowOffset() const;
+
+  /**
+   * @brief Sets the text's shadow color.
+   *
+   * @param[in] shadowColor The shadow color.
+   */
+  void SetShadowColor( const Vector4& shadowColor );
+
+  /**
+   * @brief Retrieves the text's shadow color.
+   *
+   * @return The text's shadow color.
+   */
+  const Vector4& GetShadowColor() const;
+
+  /**
+   * @brief Set the shadow blur radius.
+   *
+   * @param[in] shadowBlurRadius The shadow blur radius, 0,0 indicates no blur.
+   */
+  void SetShadowBlurRadius( const float& shadowBlurRadius );
+
+  /**
+   * @brief Retrieve the shadow blur radius.
+   *
+   * @return The shadow blur radius.
+   */
+  const float& GetShadowBlurRadius() const;
+
+  /**
+   * @brief Sets the text's underline color.
+   *
+   * @param[in] color The text's underline color.
+   */
+  void SetUnderlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the text's underline color.
+   *
+   * @return The text's underline color.
+   */
+  const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @brief Sets the text underline flag.
+   *
+   * @param[in] enabled true if underlined.
+   */
+  void SetUnderlineEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the text is underlined or not.
+   *
+   * @return underline state.
+   */
+  bool IsUnderlineEnabled() const;
+
+  /**
+   * @brief Clear the caches.
+   */
+  void ClearCaches();
+
+  /**
+   * @brief Set the override used for underline height, 0 indicates height will be come from font metrics
+   *
+   * @param[in] height The height in pixels of the underline
+   */
+  void SetUnderlineHeight( float height );
+
+  /**
+   * @brief Retrieves the underline height override
+   *
+   * @return Returns the override height for an underline, 0 indicates that font metrics will determine the height
+   */
+  float GetUnderlineHeight() const;
+
+  /**
+   * @brief Retrieves the number of underline runs.
+   *
+   * @return The number of underline runs.
+   */
+  Length GetNumberOfUnderlineRuns() const;
+
+  /**
+   * @brief Set the outline color.
+   *
+   * @param[in] color color of outline.
+   */
+  void SetOutlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieve the outline color.
+   *
+   * @return The outline color.
+   */
+  const Vector4& GetOutlineColor() const;
+
+  /**
+   * @brief Set the outline width
+   *
+   * @param[in] width The width in pixels of the outline, 0 indicates no outline
+   */
+  void SetOutlineWidth( uint16_t width );
+
+  /**
+   * @brief Retrieves the width of an outline
+   *
+   * @return The width of the outline.
+   */
+  uint16_t GetOutlineWidth() const;
+
+  /**
+   * @brief Sets the text's background color.
+   *
+   * @param[in] color The text's background color.
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the text's background color.
+   *
+   * @return The text's background color.
+   */
+  const Vector4& GetBackgroundColor() const;
+
+  /**
+   * @brief Sets whether the text has a background or not.
+   *
+   * @param[in] enabled true if the text has a background.
+   */
+  void SetBackgroundEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the text has a background or not.
+   *
+   * @return whether the text has a background or not.
+   */
+  bool IsBackgroundEnabled() const;
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~VisualModel();
+
+private:
+
+  /**
+   * @brief Private constructor.
+   */
+  VisualModel();
+
+  // Undefined
+  VisualModel( const VisualModel& handle );
+
+  // Undefined
+  VisualModel& operator=( const VisualModel& handle );
+
+public:
+
+  Vector<GlyphInfo>      mGlyphs;               ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+  Vector<CharacterIndex> mGlyphsToCharacters;   ///< For each glyph, the index of the first character.
+  Vector<GlyphIndex>     mCharactersToGlyph;    ///< For each character, the index of the first glyph.
+  Vector<Length>         mCharactersPerGlyph;   ///< For each glyph, the number of characters that form the glyph.
+  Vector<Length>         mGlyphsPerCharacter;   ///< For each character, the number of glyphs that are shaped.
+  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<Vector4>        mColors;               ///< Colors of the glyphs.
+  Vector<ColorIndex>     mColorIndices;         ///< Indices to the vector of colors for each glyphs.
+  Vector<Vector4>        mBackgroundColors;     ///< Background colors of the glyphs.
+  Vector<ColorIndex>     mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
+
+  Vector4                mTextColor;            ///< The text color
+  Vector4                mShadowColor;          ///< Color of drop shadow
+  Vector4                mUnderlineColor;       ///< Color of underline
+  Vector4                mOutlineColor;         ///< Color of outline
+  Vector4                mBackgroundColor;      ///< Color of text background
+  Size                   mControlSize;          ///< The size of the UI control.
+  Vector2                mShadowOffset;         ///< Offset for drop shadow, 0 indicates no shadow
+  float                  mUnderlineHeight;      ///< Fixed height for underline to override font metrics.
+  float                  mShadowBlurRadius;     ///< Blur radius of shadow, 0 indicates no blur.
+  uint16_t               mOutlineWidth;         ///< Width of outline.
+
+private:
+
+  Size                   mNaturalSize;        ///< Size of the text with no line wrapping.
+  Size                   mLayoutSize;         ///< Size of the laid-out text considering the layout properties set.
+
+  // Caches to increase performance in some consecutive operations.
+  LineIndex mCachedLineIndex; ///< Used to increase performance in consecutive calls to GetLineOfGlyph() or GetLineOfCharacter() with consecutive glyphs or characters.
+
+public:
+
+  bool                   mUnderlineEnabled:1;   ///< Underline enabled flag
+  bool                   mUnderlineColorSet:1;  ///< Has the underline color been explicitly set?
+  bool                   mBackgroundEnabled:1;   ///< Background enabled flag
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H
diff --git a/dali-toolkit/internal/text/xhtml-entities.cpp b/dali-toolkit/internal/text/xhtml-entities.cpp
new file mode 100755 (executable)
index 0000000..3ee7215
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2017 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 <cstring> // for strlen()
+
+// FILE HEADER
+#include "xhtml-entities.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+/**
+ * Implementation of the XHTML Entity matching
+ */
+struct XHTMLEntityLookup
+{
+    const char* const entityName;  // XHTML Named Entity string
+    const char* const entityCode;  // Corresponding UTF-8
+};
+
+/* table of html name entities supported in DALi
+ *
+ * these are stored as pair with Named entity as Key and
+ * its utf 8 as value
+ */
+const XHTMLEntityLookup XHTMLEntityLookupTable[] =
+  {
+  { "&quot;\0"    ,"\x22\0" },
+  { "&amp;\0"     ,"\x26\0" },
+  { "&apos;\0"    ,"\x27\0" },
+  { "&lt;\0"      ,"\x3c\0" },
+  { "&gt;\0"      ,"\x3e\0" },
+  { "&nbsp;\0"    ,"\xc2\xa0\0" },
+  { "&iexcl;\0"   ,"\xc2\xa1\0" },
+  { "&cent;\0"    ,"\xc2\xa2\0" },
+  { "&pound;\0"   ,"\xc2\xa3\0" },
+  { "&curren;\0"  ,"\xc2\xa4\0" },
+  { "&yen;\0"     ,"\xc2\xa5\0" },
+  { "&brvbar;\0"  ,"\xc2\xa6\0" },
+  { "&sect;\0"    ,"\xc2\xa7\0" },
+  { "&uml;\0"     ,"\xc2\xa8\0" },
+  { "&copy;\0"    ,"\xc2\xa9\0" },
+  { "&ordf;\0"    ,"\xc2\xaa\0" },
+  { "&laquo;\0"   ,"\xc2\xab\0" },
+  { "&not;\0"     ,"\xc2\xac\0" },
+  { "&shy;\0"     ,"\xc2\xad\0" },
+  { "&reg;\0"     ,"\xc2\xae\0" },
+  { "&macr;\0"    ,"\xc2\xaf\0" },
+  { "&deg;\0"     ,"\xc2\xb0\0" },
+  { "&plusmn;\0"  ,"\xc2\xb1\0" },
+  { "&sup2;\0"    ,"\xc2\xb2\0" },
+  { "&sup3;\0"    ,"\xc2\xb3\0" },
+  { "&acute;\0"   ,"\xc2\xb4\0" },
+  { "&micro;\0"   ,"\xc2\xb5\0" },
+  { "&para;\0"    ,"\xc2\xb6\0" },
+  { "&middot;\0"  ,"\xc2\xb7\0" },
+  { "&cedil;\0"   ,"\xc2\xb8\0" },
+  { "&sup1;\0"    ,"\xc2\xb9\0" },
+  { "&ordm;\0"    ,"\xc2\xba\0" },
+  { "&raquo;\0"   ,"\xc2\xbb\0" },
+  { "&frac14;\0"  ,"\xc2\xbc\0" },
+  { "&frac12;\0"  ,"\xc2\xbd\0" },
+  { "&frac34;\0"  ,"\xc2\xbe\0" },
+  { "&iquest;\0"  ,"\xc2\xbf\0" },
+  { "&Agrave;\0"  ,"\xc3\x80\0" },
+  { "&Aacute;\0"  ,"\xc3\x81\0" },
+  { "&Acirc;\0"   ,"\xc3\x82\0" },
+  { "&Atilde;\0"  ,"\xc3\x83\0" },
+  { "&Auml;\0"    ,"\xc3\x84\0" },
+  { "&Aring;\0"   ,"\xc3\x85\0" },
+  { "&AElig;\0"   ,"\xc3\x86\0" },
+  { "&Ccedil;\0"  ,"\xc3\x87\0" },
+  { "&Egrave;\0"  ,"\xc3\x88\0" },
+  { "&Eacute;\0"  ,"\xc3\x89\0" },
+  { "&Ecirc;\0"   ,"\xc3\x8a\0" },
+  { "&Euml;\0"    ,"\xc3\x8b\0" },
+  { "&Igrave;\0"  ,"\xc3\x8c\0" },
+  { "&Iacute;\0"  ,"\xc3\x8d\0" },
+  { "&Icirc;\0"   ,"\xc3\x8e\0" },
+  { "&Iuml;\0"    ,"\xc3\x8f\0" },
+  { "&ETH;\0"     ,"\xc3\x90\0" },
+  { "&Ntilde;\0"  ,"\xc3\x91\0" },
+  { "&Ograve;\0"  ,"\xc3\x92\0" },
+  { "&Oacute;\0"  ,"\xc3\x93\0" },
+  { "&Ocirc;\0"   ,"\xc3\x94\0" },
+  { "&Otilde;\0"  ,"\xc3\x95\0" },
+  { "&Ouml;\0"    ,"\xc3\x96\0" },
+  { "&times;\0"   ,"\xc3\x97\0" },
+  { "&Oslash;\0"  ,"\xc3\x98\0" },
+  { "&Ugrave;\0"  ,"\xc3\x99\0" },
+  { "&Uacute;\0"  ,"\xc3\x9a\0" },
+  { "&Ucirc;\0"   ,"\xc3\x9b\0" },
+  { "&Uuml;\0"    ,"\xc3\x9c\0" },
+  { "&Yacute;\0"  ,"\xc3\x9d\0" },
+  { "&THORN;\0"   ,"\xc3\x9e\0" },
+  { "&szlig;\0"   ,"\xc3\x9f\0" },
+  { "&agrave;\0"  ,"\xc3\xa0\0" },
+  { "&aacute;\0"  ,"\xc3\xa1\0" },
+  { "&acirc;\0"   ,"\xc3\xa2\0" },
+  { "&atilde;\0"  ,"\xc3\xa3\0" },
+  { "&auml;\0"    ,"\xc3\xa4\0" },
+  { "&aring;\0"   ,"\xc3\xa5\0" },
+  { "&aelig;\0"   ,"\xc3\xa6\0" },
+  { "&ccedil;\0"  ,"\xc3\xa7\0" },
+  { "&egrave;\0"  ,"\xc3\xa8\0" },
+  { "&eacute;\0"  ,"\xc3\xa9\0" },
+  { "&ecirc;\0"   ,"\xc3\xaa\0" },
+  { "&euml;\0"    ,"\xc3\xab\0" },
+  { "&igrave;\0"  ,"\xc3\xac\0" },
+  { "&iacute;\0"  ,"\xc3\xad\0" },
+  { "&icirc;\0"   ,"\xc3\xae\0" },
+  { "&iuml;\0"    ,"\xc3\xaf\0" },
+  { "&eth;\0"     ,"\xc3\xb0\0" },
+  { "&ntilde;\0"  ,"\xc3\xb1\0" },
+  { "&ograve;\0"  ,"\xc3\xb2\0" },
+  { "&oacute;\0"  ,"\xc3\xb3\0" },
+  { "&ocirc;\0"   ,"\xc3\xb4\0" },
+  { "&otilde;\0"  ,"\xc3\xb5\0" },
+  { "&ouml;\0"    ,"\xc3\xb6\0" },
+  { "&divide;\0"  ,"\xc3\xb7\0" },
+  { "&oslash;\0"  ,"\xc3\xb8\0" },
+  { "&ugrave;\0"  ,"\xc3\xb9\0" },
+  { "&uacute;\0"  ,"\xc3\xba\0" },
+  { "&ucirc;\0"   ,"\xc3\xbb\0" },
+  { "&uuml;\0"    ,"\xc3\xbc\0" },
+  { "&yacute;\0"  ,"\xc3\xbd\0" },
+  { "&thorn;\0"   ,"\xc3\xbe\0" },
+  { "&yuml;\0"    ,"\xc3\xbf\0" },
+  { "&OElig;\0"   ,"\xc5\x92\0" },
+  { "&oelig;\0"   ,"\xc5\x93\0" },
+  { "&Scaron;\0"  ,"\xc5\xa0\0" },
+  { "&scaron;\0"  ,"\xc5\xa1\0" },
+  { "&Yuml;\0"    ,"\xc5\xb8\0" },
+  { "&fnof;\0"    ,"\xc6\x92\0" },
+  { "&circ;\0"    ,"\xcb\x86\0" },
+  { "&tilde;\0"   ,"\xcb\x9c\0" },
+  { "&Alpha;\0"   ,"\xce\x91\0" },
+  { "&Beta;\0"    ,"\xce\x92\0" },
+  { "&Gamma;\0"   ,"\xce\x93\0" },
+  { "&Delta;\0"   ,"\xce\x94\0" },
+  { "&Epsilon;\0" ,"\xce\x95\0" },
+  { "&Zeta;\0"    ,"\xce\x96\0" },
+  { "&Eta;\0"     ,"\xce\x97\0" },
+  { "&Theta;\0"   ,"\xce\x98\0" },
+  { "&Iota;\0"    ,"\xce\x99\0" },
+  { "&Kappa;\0"   ,"\xce\x9a\0" },
+  { "&Lambda;\0"  ,"\xce\x9b\0" },
+  { "&Mu;\0"      ,"\xce\x9c\0" },
+  { "&Nu;\0"      ,"\xce\x9d\0" },
+  { "&Xi;\0"      ,"\xce\x9e\0" },
+  { "&Omicron;\0" ,"\xce\x9f\0" },
+  { "&Pi;\0"      ,"\xce\xa0\0" },
+  { "&Rho;\0"     ,"\xce\xa1\0" },
+  { "&Sigma;\0"   ,"\xce\xa3\0" },
+  { "&Tau;\0"     ,"\xce\xa4\0" },
+  { "&Upsilon;\0" ,"\xce\xa5\0" },
+  { "&Phi;\0"     ,"\xce\xa6\0" },
+  { "&Chi;\0"     ,"\xce\xa7\0" },
+  { "&Psi;\0"     ,"\xce\xa8\0" },
+  { "&Omega;\0"   ,"\xce\xa9\0" },
+  { "&alpha;\0"   ,"\xce\xb1\0" },
+  { "&beta;\0"    ,"\xce\xb2\0" },
+  { "&gamma;\0"   ,"\xce\xb3\0" },
+  { "&delta;\0"   ,"\xce\xb4\0" },
+  { "&epsilon;\0" ,"\xce\xb5\0" },
+  { "&zeta;\0"    ,"\xce\xb6\0" },
+  { "&eta;\0"     ,"\xce\xb7\0" },
+  { "&theta;\0"   ,"\xce\xb8\0" },
+  { "&iota;\0"    ,"\xce\xb9\0" },
+  { "&kappa;\0"   ,"\xce\xba\0" },
+  { "&lambda;\0"  ,"\xce\xbb\0" },
+  { "&mu;\0"      ,"\xce\xbc\0" },
+  { "&nu;\0"      ,"\xce\xbd\0" },
+  { "&xi;\0"      ,"\xce\xbe\0" },
+  { "&omicron;\0" ,"\xce\xbf\0" },
+  { "&pi;\0"      ,"\xcf\x80\0" },
+  { "&rho;\0"     ,"\xcf\x81\0" },
+  { "&sigmaf;\0"  ,"\xcf\x82\0" },
+  { "&sigma;\0"   ,"\xcf\x83\0" },
+  { "&tau;\0"     ,"\xcf\x84\0" },
+  { "&upsilon;\0" ,"\xcf\x85\0" },
+  { "&phi;\0"     ,"\xcf\x86\0" },
+  { "&chi;\0"     ,"\xcf\x87\0" },
+  { "&psi;\0"     ,"\xcf\x88\0" },
+  { "&omega;\0"   ,"\xcf\x89\0" },
+  { "&thetasym;\0","\xcf\x91\0" },
+  { "&upsih;\0"   ,"\xcf\x92\0" },
+  { "&piv;\0"     ,"\xcf\x96\0" },
+  { "&ensp;\0"    ,"\xe2\x80\x82\0" },
+  { "&emsp;\0"    ,"\xe2\x80\x83\0" },
+  { "&thinsp;\0"  ,"\xe2\x80\x89\0" },
+  { "&zwnj;\0"    ,"\xe2\x80\x8c\0" },
+  { "&zwj;\0"     ,"\xe2\x80\x8d\0" },
+  { "&lrm;\0"     ,"\xe2\x80\x8e\0" },
+  { "&rlm;\0"     ,"\xe2\x80\x8f\0" },
+  { "&ndash;\0"   ,"\xe2\x80\x93\0" },
+  { "&mdash;\0"   ,"\xe2\x80\x94\0" },
+  { "&lsquo;\0"   ,"\xe2\x80\x98\0" },
+  { "&rsquo;\0"   ,"\xe2\x80\x99\0" },
+  { "&sbquo;\0"   ,"\xe2\x80\x9a\0" },
+  { "&ldquo;\0"   ,"\xe2\x80\x9c\0" },
+  { "&rdquo;\0"   ,"\xe2\x80\x9d\0" },
+  { "&bdquo;\0"   ,"\xe2\x80\x9e\0" },
+  { "&dagger;\0"  ,"\xe2\x80\xa0\0" },
+  { "&Dagger;\0"  ,"\xe2\x80\xa1\0" },
+  { "&bull;\0"    ,"\xe2\x80\xa2\0" },
+  { "&hellip;\0"  ,"\xe2\x80\xa6\0" },
+  { "&permil;\0"  ,"\xe2\x80\xb0\0" },
+  { "&prime;\0"   ,"\xe2\x80\xb2\0" },
+  { "&Prime;\0"   ,"\xe2\x80\xb3\0" },
+  { "&lsaquo;\0"  ,"\xe2\x80\xb9\0" },
+  { "&rsaquo;\0"  ,"\xe2\x80\xba\0" },
+  { "&oline;\0"   ,"\xe2\x80\xbe\0" },
+  { "&frasl;\0"   ,"\xe2\x81\x84\0" },
+  { "&euro;\0"    ,"\xe2\x82\xac\0" },
+  { "&image;\0"   ,"\xe2\x84\x91\0" },
+  { "&weierp;\0"  ,"\xe2\x84\x98\0" },
+  { "&real;\0"    ,"\xe2\x84\x9c\0" },
+  { "&trade;\0"   ,"\xe2\x84\xa2\0" },
+  { "&alefsym;\0" ,"\xe2\x84\xb5\0" },
+  { "&larr;\0"    ,"\xe2\x86\x90\0" },
+  { "&uarr;\0"    ,"\xe2\x86\x91\0" },
+  { "&rarr;\0"    ,"\xe2\x86\x92\0" },
+  { "&darr;\0"    ,"\xe2\x86\x93\0" },
+  { "&harr;\0"    ,"\xe2\x86\x94\0" },
+  { "&crarr;\0"   ,"\xe2\x86\xb5\0" },
+  { "&lArr;\0"    ,"\xe2\x87\x90\0" },
+  { "&uArr;\0"    ,"\xe2\x87\x91\0" },
+  { "&rArr;\0"    ,"\xe2\x87\x92\0" },
+  { "&dArr;\0"    ,"\xe2\x87\x93\0" },
+  { "&hArr;\0"    ,"\xe2\x87\x94\0" },
+  { "&forall;\0"  ,"\xe2\x88\x80\0" },
+  { "&part;\0"    ,"\xe2\x88\x82\0" },
+  { "&exist;\0"   ,"\xe2\x88\x83\0" },
+  { "&empty;\0"   ,"\xe2\x88\x85\0" },
+  { "&nabla;\0"   ,"\xe2\x88\x87\0" },
+  { "&isin;\0"    ,"\xe2\x88\x88\0" },
+  { "&notin;\0"   ,"\xe2\x88\x89\0" },
+  { "&ni;\0"      ,"\xe2\x88\x8b\0" },
+  { "&prod;\0"    ,"\xe2\x88\x8f\0" },
+  { "&sum;\0"     ,"\xe2\x88\x91\0" },
+  { "&minus;\0"   ,"\xe2\x88\x92\0" },
+  { "&lowast;\0"  ,"\xe2\x88\x97\0" },
+  { "&radic;\0"   ,"\xe2\x88\x9a\0" },
+  { "&prop;\0"    ,"\xe2\x88\x9d\0" },
+  { "&infin;\0"   ,"\xe2\x88\x9e\0" },
+  { "&ang;\0"     ,"\xe2\x88\xa0\0" },
+  { "&and;\0"     ,"\xe2\x88\xa7\0" },
+  { "&or;\0"      ,"\xe2\x88\xa8\0" },
+  { "&cap;\0"     ,"\xe2\x88\xa9\0" },
+  { "&cup;\0"     ,"\xe2\x88\xaa\0" },
+  { "&int;\0"     ,"\xe2\x88\xab\0" },
+  { "&there4;\0"  ,"\xe2\x88\xb4\0" },
+  { "&sim;\0"     ,"\xe2\x88\xbc\0" },
+  { "&cong;\0"    ,"\xe2\x89\x85\0" },
+  { "&asymp;\0"   ,"\xe2\x89\x88\0" },
+  { "&ne;\0"      ,"\xe2\x89\xa0\0" },
+  { "&equiv;\0"   ,"\xe2\x89\xa1\0" },
+  { "&le;\0"      ,"\xe2\x89\xa4\0" },
+  { "&ge;\0"      ,"\xe2\x89\xa5\0" },
+  { "&sub;\0"     ,"\xe2\x8a\x82\0" },
+  { "&sup;\0"     ,"\xe2\x8a\x83\0" },
+  { "&nsub;\0"    ,"\xe2\x8a\x84\0" },
+  { "&sube;\0"    ,"\xe2\x8a\x86\0" },
+  { "&supe;\0"    ,"\xe2\x8a\x87\0" },
+  { "&oplus;\0"   ,"\xe2\x8a\x95\0" },
+  { "&otimes;\0"  ,"\xe2\x8a\x97\0" },
+  { "&perp;\0"    ,"\xe2\x8a\xa5\0" },
+  { "&sdot;\0"    ,"\xe2\x8b\x85\0" },
+  { "&lceil;\0"   ,"\xe2\x8c\x88\0" },
+  { "&rceil;\0"   ,"\xe2\x8c\x89\0" },
+  { "&lfloor;\0"  ,"\xe2\x8c\x8a\0" },
+  { "&rfloor;\0"  ,"\xe2\x8c\x8b\0" },
+  { "&loz;\0"     ,"\xe2\x97\x8a\0" },
+  { "&spades;\0"  ,"\xe2\x99\xa0\0" },
+  { "&clubs;\0"   ,"\xe2\x99\xa3\0" },
+  { "&hearts;\0"  ,"\xe2\x99\xa5\0" },
+  { "&diams;\0"   ,"\xe2\x99\xa6\0" },
+  { "&lang;\0"    ,"\xe2\x9f\xa8\0" },
+  { "&rang;\0"    ,"\xe2\x9f\xa9\0" }
+};
+
+const std::size_t XHTMLENTITY_LOOKUP_COUNT = (sizeof( XHTMLEntityLookupTable))/ (sizeof(XHTMLEntityLookup));
+
+} // unnamed namespace
+
+const char* const  NamedEntityToUtf8( const char* const markupText, unsigned int len )
+{
+  // finding if given XHTML named entity is supported or not
+  for( size_t i = 0; i < XHTMLENTITY_LOOKUP_COUNT ; ++i )
+  {
+    unsigned int entityLen = strlen(XHTMLEntityLookupTable[i].entityName);
+    if( len == entityLen )
+    {
+      if( strncmp( markupText, XHTMLEntityLookupTable[i].entityName, len )  == 0 )  // if named Entity found in table
+        {
+          return XHTMLEntityLookupTable[i].entityCode;
+        }
+    }
+  }
+  return NULL;
+}
+
+} // namespace  Text
+
+} // namespace  Toolkit
+
+} // namespace  Dali
diff --git a/dali-toolkit/internal/text/xhtml-entities.h b/dali-toolkit/internal/text/xhtml-entities.h
new file mode 100755 (executable)
index 0000000..c09d5cd
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DALI_TOOLKIT_TEXT_XHTML_ENTITIES_H
+#define DALI_TOOLKIT_TEXT_XHTML_ENTITIES_H
+
+/*
+ * Copyright (c) 2017 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 Text
+{
+/**
+ * @brief Retrieves UTF8 entity code for corresponding XHTML named Entity.
+ *
+ * @param[in] markupText The XHTML named entity.
+ * @param[int] len Length of markupText.
+ *
+ * @return pointer to UTF8 entity code if namedEntity found in table otherwise NULL
+ */
+const char* const NamedEntityToUtf8( const char* const markupText, unsigned int len );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_XHTML_ENTITIES_H
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.cpp b/dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.cpp
new file mode 100644 (file)
index 0000000..3026d9c
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "cube-transition-cross-effect-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+CubeTransitionCrossEffect::CubeTransitionCrossEffect( unsigned int numRows, unsigned int numColumns )
+: CubeTransitionEffect( numRows, numColumns ),
+  mDisplacementSpreadFactor( 0.008f )
+{
+}
+
+Toolkit::CubeTransitionCrossEffect CubeTransitionCrossEffect::New(unsigned int numRows, unsigned int numColumns )
+{
+  // Create the implementation
+  IntrusivePtr< CubeTransitionCrossEffect > internalCubeTransEffect = new CubeTransitionCrossEffect( numRows, numColumns );
+
+  // Pass ownership to CustomActor handle
+  Toolkit::CubeTransitionCrossEffect cubeTransEffect( *internalCubeTransEffect );
+
+  //Initialization
+  internalCubeTransEffect->Initialize();
+
+  return cubeTransEffect;
+}
+
+void CubeTransitionCrossEffect::OnInitialize()
+{
+  unsigned int idx;
+  for( unsigned int y = 0; y < mRows; y++ )
+  {
+    for( unsigned int x = y % 2; x < mColumns; x += 2 )
+    {
+      idx = y * mColumns + x;
+      SetTargetTop( idx );
+    }
+    for( unsigned int x = ( y + 1 ) % 2; x < mColumns; x += 2 )
+    {
+      idx = y * mColumns + x;
+      SetTargetRight( idx );
+    }
+  }
+}
+
+void CubeTransitionCrossEffect::OnStartTransition( Vector2 panPosition, Vector2 panDisplacement )
+{
+  float angle = Math::PI_2;
+  unsigned int idx;
+
+  if( panDisplacement.x < 0 )
+  {
+    for( unsigned int y = 0; y < mRows; y++ )
+    {
+      for( unsigned int x = y % 2; x < mColumns; x += 2 )
+      {
+        idx = y * mColumns + x;
+        SetTargetTop( idx );
+      }
+      for( unsigned int x = ( y + 1 ) % 2; x < mColumns; x += 2 )
+      {
+        idx = y * mColumns + x;
+        SetTargetRight( idx );
+      }
+    }
+  }
+  else
+  {
+    angle = -angle;
+
+    for( unsigned int y = 0; y < mRows; y++ )
+    {
+      for( unsigned int x = y % 2; x < mColumns; x += 2 )
+      {
+        idx = y * mColumns + x;
+        SetTargetBottom( idx );
+      }
+      for( unsigned int x = ( y + 1 ) % 2; x < mColumns; x += 2 )
+      {
+        idx = y * mColumns + x;
+        SetTargetLeft( idx );
+      }
+    }
+  }
+
+  const Vector2 halfSize = Self().GetCurrentSize().GetVectorXY() * 0.5f;
+  //the centre to "explode" the tiles outwards from
+  Vector3 centre( halfSize.x, halfSize.y, -1.0f / mDisplacementSpreadFactor );
+
+  for( unsigned int y = 0; y < mRows; y++ )
+  {
+    for( unsigned int x = y%2; x < mColumns; x=x+2) // rotate vertically
+    {
+      idx = y*mColumns + x;
+      SetupAnimation( idx, x, y, -angle, Vector3::XAXIS, centre );
+    }
+    for( unsigned int x = (y+1)%2; x < mColumns; x=x+2) // rotate horizontally
+    {
+      idx = y*mColumns + x;
+      SetupAnimation( idx, x, y, angle, Vector3::YAXIS, centre );
+    }
+  }
+
+  mAnimation.Play();
+  mIsAnimating = true;
+}
+
+void CubeTransitionCrossEffect::SetupAnimation( unsigned int actorIndex, unsigned int x, unsigned int y, float angle, const Vector3 axis, const Vector3& displacementCentre )
+{
+  const Vector2 size = Self().GetCurrentSize().GetVectorXY();
+  Vector2 halfSize = size * 0.5f;
+
+  //the position of the centre of the front face tile
+  Vector3 position( halfSize.x * (2.0f * x + 1.0f) / mColumns, halfSize.y * (2.0f * y + 1.0f ) / mRows, 0.0f );
+
+  Vector3 direction = position - displacementCentre;
+  float length = direction.Length();
+  direction.Normalize();
+
+  float deltaLength = mCubeDisplacement / direction.z; //the length along the direction vector such that the projected direction onto the z axis is equal to mCubeDisplacement
+
+  Vector3 newPosition = ( direction * (length + deltaLength ) ) + displacementCentre;
+  Vector3 newLocalPosition = newPosition - position;
+
+  mAnimation.AnimateTo( Property( mBoxes[ actorIndex ], Actor::Property::ORIENTATION ), Quaternion( Radian( -angle ), axis ), AlphaFunction::EASE_IN_OUT_SINE );
+  mAnimation.AnimateTo( Property( mBoxes[ actorIndex ], Actor::Property::POSITION ), newLocalPosition, AlphaFunction::BOUNCE );
+
+  mAnimation.AnimateTo( Property( mCurrentTiles[ actorIndex ], Actor::Property::COLOR ), HALF_BRIGHTNESS, AlphaFunction::EASE_OUT );
+  mAnimation.AnimateTo( Property( mTargetTiles[ actorIndex ], Actor::Property::COLOR ), FULL_BRIGHTNESS, AlphaFunction::EASE_IN );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.h b/dali-toolkit/internal/transition-effects/cube-transition-cross-effect-impl.h
new file mode 100644 (file)
index 0000000..d9ce90f
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_CROSS_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_CROSS_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-cross-effect.h>
+#include <dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class CubeTransitionCrossEffect;
+
+namespace Internal
+{
+
+class CubeTransitionEffect;
+
+class CubeTransitionCrossEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * @copydoc Toolkit::CubeTransitionCrossEffect::New
+   */
+  static Toolkit::CubeTransitionCrossEffect New( unsigned int numRows, unsigned int numColumns );
+
+protected:
+
+   /**
+    * @copydoc Toolkit::Internal::CubeTransitionEffect::OnInitialize
+    */
+   virtual void OnInitialize();
+
+   /**
+    * @copydoc Toolkit::Internal::CubeTransitionEffect::OnStartTransition
+    */
+   virtual void OnStartTransition( Vector2 panPosition, Vector2 panDisplacement );
+
+private:
+
+   /**
+    * @brief Construct a new CubeTransitionCrossEffect object
+    *
+    * @param[in] numRows How many rows of cubes
+    * @param[in] numColumns How many columns of cubes
+    */
+   CubeTransitionCrossEffect( unsigned int numRows, unsigned int numColumns );
+
+   /**
+    * @brief Set up animation to an Actor
+    * This will also displace the cubes in the z direction by mCubeDisplacement and spread them apart on the xy plane
+    * given by the closeness of displacementCentre to the XY plane at 0.
+    *
+    * @param[in] actorIndex The index of the cube in the cube array
+    * @param[in] angle The angle of the rotation animation
+    * @param[in] the centre to "explode" the tiles outwards from
+    */
+   void SetupAnimation( unsigned int actorIndex, unsigned int x, unsigned int y, float angle, const Vector3 axis, const Vector3& displacementCentre );
+
+private:
+
+   /**
+    * The factor that determines how spread apart from each other the cubes will go
+    * when they are displaced during the transition animation.
+    * The larger the value the more the spread apart the cubes will be.
+    * it should be in the range (0.0, +infinity)
+    */
+   float  mDisplacementSpreadFactor;
+
+}; //class CubeTransitionCrossEffect
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::CubeTransitionCrossEffect& GetImpl( Dali::Toolkit::CubeTransitionCrossEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< Internal::CubeTransitionCrossEffect& >( handle );
+}
+
+inline const Internal::CubeTransitionCrossEffect& GetImpl( const Dali::Toolkit::CubeTransitionCrossEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  const Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< const Internal::CubeTransitionCrossEffect& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_CROSS_EFFECT_H
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-effect-impl.cpp b/dali-toolkit/internal/transition-effects/cube-transition-effect-impl.cpp
new file mode 100644 (file)
index 0000000..460ea31
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2017 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 "cube-transition-effect-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN( Toolkit::CubeTransitionEffect, Dali::BaseHandle, NULL );
+
+DALI_SIGNAL_REGISTRATION( Toolkit, CubeTransitionEffect, "transitionCompleted",  SIGNAL_TRANSITION_COMPLETED )
+
+DALI_TYPE_REGISTRATION_END()
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec4 uTextureRect;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = aPosition + vec2(0.5);\n
+    vTexCoord = mix(uTextureRect.xy, uTextureRect.zw, vTexCoord);\n
+
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec4 uSamplerRect;
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+  }\n
+);
+
+Actor CreateTile( const Vector4& samplerRect )
+{
+ Actor tile = Actor::New();
+  tile.SetAnchorPoint( AnchorPoint::CENTER );
+  tile.RegisterProperty( "uTextureRect", samplerRect );
+  return tile;
+}
+
+}
+
+const Vector4 CubeTransitionEffect::FULL_BRIGHTNESS( 1.0f, 1.0f, 1.0f, 1.0f );
+const Vector4 CubeTransitionEffect::HALF_BRIGHTNESS( 0.5f, 0.5f, 0.5f, 1.0f );
+
+CubeTransitionEffect::CubeTransitionEffect( unsigned int rows, unsigned int columns )
+: Control( ControlBehaviour( DISABLE_STYLE_CHANGE_SIGNALS ) ),
+  mRows( rows ),
+  mColumns( columns ),
+  mIsAnimating( false ),
+  mIsPaused( false ),
+  mAnimationDuration( 1.f ),
+  mCubeDisplacement( 0.f )
+{
+}
+
+CubeTransitionEffect::~CubeTransitionEffect()
+{
+}
+
+void CubeTransitionEffect::SetTargetRight( unsigned int idx )
+{
+  mBoxType[ idx ] = RIGHT;
+
+  mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
+
+  mTargetTiles[ idx ].SetParentOrigin( Vector3( 1.f, 0.5f, 0.5f) );
+  mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::YAXIS );
+}
+
+void CubeTransitionEffect::SetTargetLeft( unsigned int idx )
+{
+  mBoxType[ idx ] = LEFT;
+
+  mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
+
+  mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.f, 0.5f, 0.5f) );
+  mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::YAXIS );
+}
+
+void CubeTransitionEffect::SetTargetBottom( unsigned int idx )
+{
+  mBoxType[ idx ] = BOTTOM;
+
+  mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
+
+  mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 0.f, 0.5f) );
+  mTargetTiles[ idx ].SetOrientation( Degree( 90.f ), Vector3::XAXIS );
+}
+
+void CubeTransitionEffect::SetTargetTop( unsigned int idx )
+{
+  mBoxType[ idx ] = TOP;
+
+  mBoxes[ idx ].SetProperty(Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
+
+  mTargetTiles[ idx ].SetParentOrigin( Vector3( 0.5f, 1.f, 0.5f) );
+  mTargetTiles[ idx ].SetOrientation( Degree( -90.f ), Vector3::XAXIS );
+}
+
+void CubeTransitionEffect::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  mTileSize = Vector2( size.x / mColumns, size.y / mRows );
+
+  mBoxRoot.SetProperty( Actor::Property::SIZE_WIDTH, size.x );
+  mBoxRoot.SetProperty( Actor::Property::SIZE_HEIGHT, size.y );
+  mBoxRoot.SetProperty( Actor::Property::SIZE_DEPTH, 1.0f );
+
+  for( size_t i = 0; i < mBoxes.size(); ++i )
+  {
+    mBoxes[ i ].SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
+    mBoxes[ i ].SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
+
+    switch( mBoxType[i] )
+    {
+      case LEFT:
+      case RIGHT:
+      {
+        mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.x * 0.5f );
+        mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.x );
+        break;
+      }
+      case BOTTOM:
+      case TOP:
+      {
+        mBoxes[ i ].SetProperty( Actor::Property::PARENT_ORIGIN_Z, 1.0f - mTileSize.y * 0.5f );
+        mBoxes[ i ].SetProperty( Actor::Property::SIZE_DEPTH, mTileSize.y );
+        break;
+      }
+    }
+  }
+
+  for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
+  {
+    it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
+    it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
+  }
+  for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
+  {
+    it->SetProperty( Actor::Property::SIZE_WIDTH, mTileSize.x );
+    it->SetProperty( Actor::Property::SIZE_HEIGHT, mTileSize.y );
+  }
+}
+
+void CubeTransitionEffect::Initialize()
+{
+  Self().RegisterProperty( "uTextureRect", Vector4( 0.0f, 0.0f, 1.0f, 1.0f ) );
+
+  mBoxType.Resize(mColumns * mRows);
+
+  //create the box parents
+  mBoxRoot = Actor::New();
+  mBoxRoot.SetParentOrigin( ParentOrigin::CENTER );
+  mBoxRoot.SetAnchorPoint( AnchorPoint::CENTER );
+
+  mCurrentTiles.clear();
+  mTargetTiles.clear();
+
+  mCurrentTiles.reserve( mColumns * mRows );
+  mTargetTiles.reserve( mColumns * mRows );
+
+  Vector2 gridSizeInv( 1.0f / mColumns, 1.0f / mRows );
+  Vector3 offset( 0.5f * gridSizeInv.x, 0.5f * gridSizeInv.y, 0.0f );
+
+  Vector3 anchor;
+  for( unsigned int y = 0; y < mRows; ++y, anchor.y += 1.0f / mRows )
+  {
+    anchor.x = 0.0f;
+    for( unsigned int x = 0; x <mColumns; ++x, anchor.x += 1.0f / mColumns )
+    {
+      Vector4 textureRect( anchor.x, anchor.y, anchor.x + gridSizeInv.x, anchor.y + gridSizeInv.y );
+
+      Actor currentTile = CreateTile( textureRect );
+      currentTile.SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
+      currentTile.SetParentOrigin( ParentOrigin::CENTER );
+      mCurrentTiles.push_back( currentTile );
+
+      Actor targetTile = CreateTile( textureRect );
+      targetTile.SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
+      mTargetTiles.push_back( targetTile );
+
+      Actor box = Actor::New();
+      box.SetParentOrigin( anchor + offset );
+      box.SetAnchorPoint( AnchorPoint::CENTER );
+
+      box.Add( currentTile );
+      box.Add( targetTile );
+
+      mBoxRoot.Add( box );
+
+      mBoxes.push_back( box );
+    }
+  }
+
+  OnInitialize();
+}
+
+void CubeTransitionEffect::OnStageConnection( int depth )
+{
+  Geometry geometry = VisualFactoryCache::CreateQuadGeometry();
+  Shader shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+
+  TextureSet textureSet = TextureSet::New();
+
+  if( mCurrentTexture )
+  {
+    textureSet.SetTexture( 0u, mCurrentTexture );
+  }
+  mCurrentRenderer = Renderer::New( geometry, shader );
+  mCurrentRenderer.SetTextures( textureSet );
+
+  mCurrentRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, depth );
+  Self().AddRenderer( mCurrentRenderer );
+
+  Control::OnStageConnection( depth );
+}
+
+void CubeTransitionEffect::OnStageDisconnection()
+{
+  if( mCurrentRenderer )
+  {
+    Self().RemoveRenderer( mCurrentRenderer );
+
+    for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
+    {
+      it->RemoveRenderer( mCurrentRenderer );
+    }
+    mCurrentRenderer.Reset();
+  }
+
+  if( mTargetRenderer )
+  {
+    for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
+    {
+      it->RemoveRenderer( mTargetRenderer );
+    }
+    mTargetRenderer.Reset();
+  }
+
+  Control::OnStageDisconnection();
+}
+
+void CubeTransitionEffect::SetTransitionDuration( float duration )
+{
+  mAnimationDuration = duration;
+}
+
+float CubeTransitionEffect::GetTransitionDuration( ) const
+{
+  return mAnimationDuration;
+}
+
+void CubeTransitionEffect::SetCubeDisplacement( float displacement )
+{
+  mCubeDisplacement = displacement;
+}
+
+float CubeTransitionEffect::GetCubeDisplacement() const
+{
+  return mCubeDisplacement;
+}
+
+bool CubeTransitionEffect::IsTransitioning()
+{
+  return mIsAnimating;
+}
+
+void CubeTransitionEffect::SetCurrentTexture( Texture texture )
+{
+  mCurrentTexture = texture;
+
+  if( mCurrentRenderer )
+  {
+    TextureSet textureSet = mCurrentRenderer.GetTextures();
+    textureSet.SetTexture( 0u, mCurrentTexture);
+  }
+}
+
+void CubeTransitionEffect::SetTargetTexture( Texture texture )
+{
+  mTargetTexture = texture;
+
+  if( mTargetRenderer )
+  {
+    TextureSet textureSet = mTargetRenderer.GetTextures();
+    textureSet.SetTexture( 0u, mTargetTexture );
+  }
+}
+
+void CubeTransitionEffect::StartTransition( bool toNextImage )
+{
+  Vector3 size = Self().GetCurrentSize();
+  if( toNextImage )
+  {
+    StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( -10.f, 0.f ) );
+  }
+  else
+  {
+    StartTransition( Vector2(size.x* 0.5f, size.y*0.5f), Vector2( 10.f, 0.f ));
+  }
+}
+
+void CubeTransitionEffect::StartTransition( Vector2 panPosition, Vector2 panDisplacement )
+{
+  if( !mCurrentRenderer )
+  {
+    DALI_LOG_ERROR( "Trying to transition a cube transition without an image set\n" );
+    return;
+  }
+
+  //create the target renderer
+  TextureSet textureSet = TextureSet::New();
+  if( mTargetTexture )
+  {
+    textureSet.SetTexture( 0u, mTargetTexture );
+  }
+  Geometry geometry = mCurrentRenderer.GetGeometry();
+  Shader shader( mCurrentRenderer.GetShader() );
+  mTargetRenderer = Renderer::New( geometry, shader );
+  mTargetRenderer.SetTextures( textureSet );
+
+  int depthIndex = mCurrentRenderer.GetProperty<int>(Renderer::Property::DEPTH_INDEX);
+  mTargetRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, depthIndex );
+
+  for( size_t i = 0; i < mBoxes.size(); ++i )
+  {
+    mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
+  }
+
+  for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
+  {
+    it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
+    it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
+    it->AddRenderer( mCurrentRenderer );
+  }
+  for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
+  {
+    it->AddRenderer( mTargetRenderer );
+  }
+
+  Self().RemoveRenderer( mCurrentRenderer );
+  Self().Add( mBoxRoot );
+
+  if(mAnimation)
+  {
+    mAnimation.Clear();
+    mAnimation.Reset();
+  }
+
+  mAnimation = Animation::New( mAnimationDuration );
+  mAnimation.FinishedSignal().Connect( this, &CubeTransitionEffect::OnTransitionFinished );
+
+  OnStartTransition( panPosition, panDisplacement );
+}
+
+void CubeTransitionEffect::PauseTransition()
+{
+  if( mIsAnimating && !mIsPaused )
+  {
+    mAnimation.Pause();
+    mIsPaused = true;
+  }
+}
+
+void CubeTransitionEffect::ResumeTransition()
+{
+  if( mIsAnimating && mIsPaused)
+  {
+    mAnimation.Play();
+    mIsPaused = false;
+  }
+}
+
+void CubeTransitionEffect::StopTransition()
+{
+  ResetToInitialState();
+}
+
+void CubeTransitionEffect::ResetToInitialState()
+{
+  mAnimation.Clear();
+  mAnimation.Reset();
+  mIsAnimating = false;
+
+  Self().Remove( mBoxRoot );
+
+  for( size_t i = 0; i < mBoxes.size(); ++i )
+  {
+    mBoxes[ i ].SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
+  }
+
+  for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
+  {
+    it->SetParentOrigin( Vector3( 0.5f, 0.5f, 1.0f) );
+    it->SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian( 0.0f ), Vector3::XAXIS ) );
+    it->SetProperty( Actor::Property::COLOR, FULL_BRIGHTNESS );
+  }
+  if( mCurrentRenderer )
+  {
+    for( ActorArray::iterator it = mCurrentTiles.begin(); it != mCurrentTiles.end(); ++it )
+    {
+      it->RemoveRenderer( mCurrentRenderer );
+    }
+    Self().AddRenderer( mCurrentRenderer );
+  }
+
+  for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
+  {
+    it->SetProperty( Actor::Property::COLOR, HALF_BRIGHTNESS );
+  }
+  if( mTargetRenderer )
+  {
+    for( ActorArray::iterator it = mTargetTiles.begin(); it != mTargetTiles.end(); ++it )
+    {
+      it->RemoveRenderer( mTargetRenderer );
+    }
+  }
+}
+
+void CubeTransitionEffect::OnTransitionFinished(Animation& source)
+{
+
+  std::swap( mCurrentTiles, mTargetTiles );
+  std::swap( mCurrentRenderer, mTargetRenderer );
+  std::swap( mCurrentTexture, mTargetTexture );
+
+  ResetToInitialState();
+
+  //Emit signal
+  Toolkit::CubeTransitionEffect handle( GetOwner() );
+  mTransitionCompletedSignal.Emit( handle, mCurrentTexture );
+}
+
+Toolkit::CubeTransitionEffect::TransitionCompletedSignalType& CubeTransitionEffect::TransitionCompletedSignal()
+{
+  return mTransitionCompletedSignal;
+}
+
+bool CubeTransitionEffect::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  Dali::BaseHandle handle( object );
+
+  bool connected( true );
+  Toolkit::CubeTransitionEffect cubeTransitionEffect = Toolkit::CubeTransitionEffect::DownCast( handle );
+
+  if( 0 == strcmp( signalName.c_str(), SIGNAL_TRANSITION_COMPLETED ) )
+  {
+    cubeTransitionEffect.TransitionCompletedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h b/dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h
new file mode 100644 (file)
index 0000000..5eda6b2
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_EFFECT_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-effect.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class CubeTransitionEffect;
+
+namespace Internal
+{
+
+/**
+ * CubeTransitionEffect implementation class
+ */
+class CubeTransitionEffect : public Control
+{
+
+public:
+
+  /**
+   * Destructor
+   */
+  ~CubeTransitionEffect();
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::SetTransitionDuration
+   */
+  void SetTransitionDuration( float duration );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::GetTransitionDuration
+   */
+  float GetTransitionDuration() const;
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::SetCubeDisplacement
+   */
+  void SetCubeDisplacement( float displacement );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::GetCubeDisplacement
+   */
+  float GetCubeDisplacement() const;
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::IsTransitioning
+   */
+  bool IsTransitioning();
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::SetCurrentTexture
+   */
+  void SetCurrentTexture( Texture texture );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::SetTargetTexture
+   */
+  void SetTargetTexture( Texture texture );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::StartTransition(bool)
+   */
+  void StartTransition( bool toNextImage = true );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::StartTransition(Vector2, Vector2)
+   */
+  void StartTransition( Vector2 panPosition, Vector2 panDisplacement );
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::PauseTransition()
+   */
+  void PauseTransition();
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::ResumeTransition()
+   */
+  void ResumeTransition();
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::StopTransition()
+   */
+  void StopTransition();
+
+public: //Signal
+
+  /**
+   * @copydoc Toolkit::CubeTransitionEffect::TransitionCompletedSignal()
+   */
+  Toolkit::CubeTransitionEffect::TransitionCompletedSignalType& TransitionCompletedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+protected:
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   */
+  virtual void OnStageDisconnection();
+
+protected:
+
+  /**
+   * Construct a new CubeTransitionEffect object
+   * Called in the constructor of subclasses
+   * @param[in] numRows How many rows of cubes
+   * @param[in] numColumns How many columns of cubes
+   */
+  CubeTransitionEffect( unsigned int numRows, unsigned int numColumns );
+
+  /**
+   * Initialization steps: creating a layer, two groups of tiles,
+   * and one group of actors (cubes) serving as parents of every two tiles (one from each image).
+   */
+  void Initialize();
+
+
+protected:
+  void SetTargetLeft( unsigned int idx );
+  void SetTargetRight( unsigned int idx );
+  void SetTargetTop( unsigned int idx );
+  void SetTargetBottom( unsigned int idx );
+
+private:
+
+  /**
+   * Callback function of transition animation finished
+   * Hide transition layer, show current image, and set isAnimating flag to false
+   * @param[in] source The cube transition animation
+   */
+  void OnTransitionFinished(Animation& source);
+
+  /**
+   * This method is called after the CubeTransitionEffect has been initialized.  Derived classes should do
+   * any second phase initialization by overriding this method.
+   */
+  virtual void OnInitialize() { }
+
+  /**
+   * This method is called after the a new transition is activated.
+   * Derived classes should do any specialized transition process by overriding this method.
+   * @param[in] panPosition The press down position of panGesture
+   * @param[in] panDisplacement The displacement vector of panGesture
+   */
+  virtual void OnStartTransition( Vector2 panPosition, Vector2 panDisplacement ) {}
+
+  /**
+   * This method is called when the transition is forced stop in the middle of animation.
+   * Derived classed should set the rotation status of the cubes to the same as the final state when the animation is finished completely.
+   * So that the next transition would be started correctly.
+   */
+  virtual void OnStopTransition() {}
+
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  void ResetToInitialState();
+
+
+protected:
+  typedef std::vector< Actor > ActorArray;
+  enum FACE { TOP, BOTTOM, LEFT, RIGHT };
+
+  ActorArray                 mBoxes;
+  Vector< FACE >             mBoxType;
+  ActorArray                 mCurrentTiles;
+  ActorArray                 mTargetTiles;
+
+  Actor                      mBoxRoot;
+
+  unsigned int               mRows;
+  unsigned int               mColumns;
+
+  Renderer                   mCurrentRenderer;
+  Renderer                   mTargetRenderer;
+
+  Texture                    mCurrentTexture;
+  Texture                    mTargetTexture;
+
+  Animation                  mAnimation;
+
+  Vector2                    mTileSize;
+
+  bool                       mIsAnimating;
+  bool                       mIsPaused;
+
+  float                      mAnimationDuration;
+  float                      mCubeDisplacement;
+
+  static const Vector4       FULL_BRIGHTNESS;
+  static const Vector4       HALF_BRIGHTNESS;
+
+private:
+
+  Toolkit::CubeTransitionEffect::TransitionCompletedSignalType mTransitionCompletedSignal;
+
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::CubeTransitionEffect& GetImpl(Dali::Toolkit::CubeTransitionEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast<Internal::CubeTransitionEffect&>(handle);
+}
+
+inline const Internal::CubeTransitionEffect& GetImpl(const Dali::Toolkit::CubeTransitionEffect& obj)
+{
+  DALI_ASSERT_ALWAYS(obj);
+
+  const Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast<const Internal::CubeTransitionEffect&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_EFFECT_H
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.cpp b/dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.cpp
new file mode 100644 (file)
index 0000000..8cd84be
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "cube-transition-fold-effect-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+CubeTransitionFoldEffect::CubeTransitionFoldEffect( unsigned int numRows, unsigned int numColumns )
+: CubeTransitionEffect( numRows, numColumns )
+{
+}
+
+Toolkit::CubeTransitionFoldEffect CubeTransitionFoldEffect::New(unsigned int numRows, unsigned int numColumns )
+{
+  // Create the implementation
+  IntrusivePtr< CubeTransitionFoldEffect > internalCubeTransEffect = new CubeTransitionFoldEffect( numRows, numColumns );
+
+  // Pass ownership to CustomActor handle
+  Toolkit::CubeTransitionFoldEffect cubeTransEffect( *internalCubeTransEffect );
+
+  //Initialization
+  internalCubeTransEffect->Initialize();
+
+  return cubeTransEffect;
+}
+
+void CubeTransitionFoldEffect::OnInitialize()
+{
+  unsigned int idx;
+  for( unsigned int y = 0; y < mRows; y++ )
+  {
+    idx = y*mColumns;
+    for( unsigned int x = y%2; x < mColumns; x=x+2)
+    {
+      SetTargetLeft( idx + x );
+    }
+    for( unsigned int x = (y+1)%2; x < mColumns; x=x+2)
+    {
+      SetTargetRight( idx + x );
+    }
+  }
+}
+
+void CubeTransitionFoldEffect::OnStartTransition( Vector2 panPosition, Vector2 panDisplacement )
+{
+  float angle = Math::PI_2;
+
+  unsigned int idx;
+  if( panDisplacement.x < 0 )
+  {
+    for( unsigned int y = 0; y < mRows; y++ )
+    {
+      idx = y*mColumns;
+      for( unsigned int x = y%2; x < mColumns; x=x+2)
+      {
+        SetTargetLeft( idx + x );
+      }
+      for( unsigned int x = (y+1)%2; x < mColumns; x=x+2)
+      {
+        SetTargetRight( idx + x );
+      }
+    }
+  }
+  else
+  {
+    angle = -angle;
+
+    for( unsigned int y = 0; y < mRows; y++ )
+    {
+      idx = y*mColumns;
+      for( unsigned int x = y%2; x < mColumns; x=x+2)
+      {
+        SetTargetRight( idx + x );
+      }
+      for( unsigned int x = (y+1)%2; x < mColumns; x=x+2)
+      {
+        SetTargetLeft( idx + x );
+      }
+    }
+  }
+
+  for( unsigned int y = 0; y < mRows; y++ )
+  {
+    idx = y*mColumns;
+    for( unsigned int x = y%2; x < mColumns; x=x+2)
+    {
+      SetupAnimation( idx + x, x, angle );
+    }
+    for( unsigned int x = (y+1)%2; x < mColumns; x=x+2)
+    {
+      SetupAnimation( idx + x, x, -angle );
+    }
+  }
+
+  mAnimation.Play();
+  mIsAnimating = true;
+}
+
+void CubeTransitionFoldEffect::SetupAnimation( unsigned int actorIndex, unsigned int x, float angle )
+{
+  //rotate and translate the cube such that the edges remain in constant contact
+  //calculate the maximum distance the cube has to move when it the box has rotated 45 degrees
+  //ie distance from of centre of square to a vertex is given by:
+  //  distance = width / sqrt(2)
+  //therefore the delta distance the cube should move is given by:
+  //  delta_distance = ( width / 2 ) - distance
+  //re-arranging we get:
+  //  delta_distance = ( width / 2 ) * ( sqrt(2) - 1 )
+  //accumulating over the length of the row we get:
+  //  delta_distance_at_x = x * delta_distance;
+
+  float delta = (float)x * mTileSize.x * ( 1.4142f - 1.0f );
+
+  Vector3 position( mBoxes[ actorIndex ].GetCurrentPosition() );
+  mAnimation.AnimateTo( Property( mBoxes[ actorIndex ], Actor::Property::ORIENTATION ), Quaternion( Radian( angle ), Vector3::YAXIS ), AlphaFunction::LINEAR );
+  mAnimation.AnimateTo( Property( mBoxes[ actorIndex ], Actor::Property::POSITION_X ), position.x + delta, AlphaFunction::BOUNCE );
+
+  mAnimation.AnimateTo( Property( mCurrentTiles[ actorIndex ], Actor::Property::COLOR ), HALF_BRIGHTNESS, AlphaFunction::EASE_OUT );
+  mAnimation.AnimateTo( Property( mTargetTiles[ actorIndex ], Actor::Property::COLOR ), FULL_BRIGHTNESS, AlphaFunction::EASE_IN );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.h b/dali-toolkit/internal/transition-effects/cube-transition-fold-effect-impl.h
new file mode 100644 (file)
index 0000000..40f28bf
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_FOLD_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_FOLD_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-fold-effect.h>
+#include <dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class CubeTransitionFoldEffect;
+
+namespace Internal
+{
+
+class CubeTransitionEffect;
+
+class CubeTransitionFoldEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * @copydoc Toolkit::CubeTransitionFoldEffect::New
+   */
+  static Toolkit::CubeTransitionFoldEffect New( unsigned int numRows, unsigned int numColumns );
+
+protected:
+
+   /**
+    * @copydoc Toolkit::CubeTransitionEffect::OnInitialize
+    */
+   virtual void OnInitialize();
+
+   /**
+    * @copydoc Toolkit::CubeTransitionEffect::OnStartTransition
+    */
+   virtual void OnStartTransition( Vector2 panPosition, Vector2 panDisplacement );
+
+private:
+
+   /**
+    * Construct a new CubeTransitionFoldEffect object
+    * @param[in] numRows How many rows of cubes
+    * @param[in] numColumns How many columns of cubes
+    */
+   CubeTransitionFoldEffect( unsigned int numRows, unsigned int numColumns );
+
+   /**
+    * Set up animation to an Actor
+    * @param[in] actorIndex The index of the cube in the cube array
+    * @param[in] angle The angle of the rotation animation
+    */
+   void SetupAnimation( unsigned int actorIndex, unsigned int x, float angle );
+
+}; //class CubeTransitionFoldEffect
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::CubeTransitionFoldEffect& GetImpl( Dali::Toolkit::CubeTransitionFoldEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< Internal::CubeTransitionFoldEffect& >( handle );
+}
+
+inline const Internal::CubeTransitionFoldEffect& GetImpl( const Dali::Toolkit::CubeTransitionFoldEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  const Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< const Internal::CubeTransitionFoldEffect& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_FOLD_EFFECT_H
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.cpp b/dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.cpp
new file mode 100644 (file)
index 0000000..525a61e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "cube-transition-wave-effect-impl.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+CubeTransitionWaveEffect::CubeTransitionWaveEffect( unsigned int numRows, unsigned int numColumns )
+: CubeTransitionEffect( numRows, numColumns ),
+  mSaddleAA( 1.f ),
+  mSaddleBB( 1.f ),
+  mSaddleB( 1.f )
+{
+}
+
+Toolkit::CubeTransitionWaveEffect CubeTransitionWaveEffect::New(unsigned int numRows, unsigned int numColumns )
+{
+  // Create the implementation
+  IntrusivePtr< CubeTransitionWaveEffect > internalCubeTransEffect = new CubeTransitionWaveEffect( numRows, numColumns );
+
+  // Pass ownership to CustomActor handle
+  Toolkit::CubeTransitionWaveEffect cubeTransEffect( *internalCubeTransEffect );
+
+  //Initialization
+  internalCubeTransEffect->Initialize();
+
+  return cubeTransEffect;
+}
+
+void CubeTransitionWaveEffect::OnInitialize()
+{
+  for( unsigned int idx = 0; idx < mTargetTiles.size(); idx++ )
+  {
+    SetTargetRight( idx );
+  }
+}
+
+void CubeTransitionWaveEffect::OnStartTransition( Vector2 panPosition, Vector2 panDisplacement )
+{
+  bool forward = panDisplacement.x < 0.0;
+  CalculateSaddleSurfaceParameters( panPosition, forward ? panDisplacement : -panDisplacement );
+
+  float angle = Math::PI_2;
+
+  unsigned int idx;
+  if( forward )
+  {
+    for( idx = 0; idx < mTargetTiles.size(); idx++ )
+    {
+      SetTargetRight( idx );
+    }
+  }
+  else
+  {
+    angle = -angle;
+    for( idx = 0; idx < mTargetTiles.size(); idx++ )
+    {
+      SetTargetLeft( idx );
+    }
+  }
+
+  float thirdAnimationDuration = mAnimationDuration / 3.f;
+
+  for( unsigned int y = 0; y < mRows; y++ )
+  {
+    idx = y * mColumns;
+    for( unsigned int x = 0; x < mColumns; x++, idx++)
+    {
+      // the delay value is within 0.f ~ 2.f*thirdAnimationDuration
+      float delay = thirdAnimationDuration * CalculateDelay( x * mTileSize.width, y * mTileSize.height, forward );
+
+      mAnimation.AnimateTo( Property( mBoxes[ idx ], Actor::Property::ORIENTATION ), Quaternion( Radian( -angle ), Vector3::YAXIS ),
+                            AlphaFunction::EASE_OUT_SINE, TimePeriod( delay, thirdAnimationDuration ) );
+      mAnimation.AnimateBy( Property( mBoxes[idx], Actor::Property::POSITION ), Vector3( 0.f, 0.f, -mCubeDisplacement ),
+                         AlphaFunction::BOUNCE, TimePeriod( delay, thirdAnimationDuration ) );
+
+      mAnimation.AnimateTo( Property( mCurrentTiles[ idx ], Actor::Property::COLOR ), HALF_BRIGHTNESS,
+                          AlphaFunction::EASE_OUT, TimePeriod( delay, thirdAnimationDuration ) );
+      mAnimation.AnimateTo( Property( mTargetTiles[ idx ], Actor::Property::COLOR ), FULL_BRIGHTNESS,
+                          AlphaFunction::EASE_IN, TimePeriod( delay, thirdAnimationDuration ) );
+    }
+  }
+
+  mAnimation.Play();
+  mIsAnimating = true;
+}
+
+void  CubeTransitionWaveEffect::CalculateSaddleSurfaceParameters( Vector2 position, Vector2 displacement )
+{
+  const Vector2 size = Self().GetCurrentSize().GetVectorXY();
+  // the line passes through 'position' and has the direction of 'displacement'
+  float coefA, coefB, coefC; //line equation: Ax+By+C=0;
+  coefA = displacement.y;
+  coefB = -displacement.x;
+  coefC = -displacement.y*position.x + displacement.x*position.y;
+
+  float inversedAABB = 1.f / (coefA*coefA+coefB*coefB);
+  float inversedSqrtAABB = sqrtf(inversedAABB);
+  float saddleA;
+
+  if(displacement.y > 0)
+  {
+    //distance from (0,0) to the line
+    float distanceTopLeft =  fabsf(coefC) * inversedSqrtAABB;
+    //distance from (viewAreaSize.x, viewAreaSize.y) to the line
+    float distanceBottomRight = fabsf(coefA*size.x+coefB*size.y+coefC) * inversedSqrtAABB;
+    saddleA = std::max( distanceTopLeft, distanceBottomRight );
+
+    //foot of a perpendicular: (viewAreaSize.x,0) to the line
+    float footX1 = ( coefB*coefB*size.x - coefA*coefC) * inversedAABB;
+    float footY1 = (-coefA*coefB*size.x - coefB*coefC) * inversedAABB;
+    //foot of a perpendicular: (0,viewAreaSize.y) to the line
+    float footX2 = (-coefA*coefB*size.y - coefA*coefC) * inversedAABB;
+    float footY2 = ( coefA*coefA*size.y - coefB*coefC) * inversedAABB;
+    mSaddleBB = (footX1-footX2)*(footX1-footX2) + (footY1-footY2)*(footY1-footY2);
+    mTranslation = Vector2(-footX2,-footY2);
+  }
+  else
+  {
+    //distance from(viewAreaSize.x,0) to the line
+    float distanceTopRight = fabsf(coefA*size.x+coefC) * inversedSqrtAABB;
+    //distance from(0,viewAreaSize.y) to the line
+    float distanceBottomLeft = fabsf(coefB*size.y+coefC) * inversedSqrtAABB;
+    saddleA = std::max( distanceTopRight, distanceBottomLeft );
+    //foot of a perpendicular: (0,0) to the line
+    float footX3 = (-coefA*coefC) * inversedAABB;
+    float footY3 = (-coefB*coefC) * inversedAABB;
+    //foot of a perpendicular: (viewAreaSize.x,viewAreaSize.y) to the line
+    float footX4 = ( coefB*coefB*size.x - coefA*coefB*size.y - coefA*coefC) * inversedAABB;
+    float footY4 = (-coefA*coefB*size.x + coefA*coefA*size.y - coefB*coefC) * inversedAABB;
+    mSaddleBB = (footX3-footX4)*(footX3-footX4) + (footY3-footY4)*(footY3-footY4);
+    mTranslation = Vector2(-footX3, -footY3);
+  }
+
+  mSaddleB = sqrtf(mSaddleBB);
+  //prevent high curve shape
+  if(mSaddleB > 2.f * saddleA)
+  {
+    saddleA = mSaddleB * 0.5f;
+  }
+  else if(mSaddleB < saddleA)
+  {
+    mSaddleB = saddleA;
+    mSaddleBB = mSaddleB*mSaddleB;
+  }
+  mSaddleAA = saddleA*saddleA;
+  mRotation = Vector2(-displacement.x, displacement.y);
+  mRotation.Normalize();
+}
+
+float CubeTransitionWaveEffect::CalculateDelay( float x, float y, bool forward )
+{
+  float tx = x + mTranslation.x;
+  float ty = y + mTranslation.y;
+  float valueX = mRotation.x * tx - mRotation.y * ty;
+  float valueY = mRotation.y * tx + mRotation.x * ty;
+  if( !forward ) // to previous image
+  {
+    valueX = mSaddleB - valueX;
+  }
+  //the return value is a float number between 0.f and 2.f
+  return (1.f + valueY*valueY / mSaddleAA - valueX*valueX / mSaddleBB);
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.h b/dali-toolkit/internal/transition-effects/cube-transition-wave-effect-impl.h
new file mode 100644 (file)
index 0000000..ff968d3
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_WAVE_EFFECT_H
+#define DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_WAVE_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/transition-effects/cube-transition-wave-effect.h>
+#include <dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class CubeTransitionWaveEffect;
+
+namespace Internal
+{
+
+class CubeTransitionEffect;
+
+class CubeTransitionWaveEffect : public CubeTransitionEffect
+{
+
+public:
+
+  /**
+   * @copydoc Toolkit::CubeTransitionWaveEffect::New
+   */
+  static Toolkit::CubeTransitionWaveEffect New(unsigned int numRows, unsigned int numColumns );
+
+protected:
+
+  /**
+   * @copydoc Toolkit::Internal::CubeTransitionEffect::OnInitialize
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @copydoc Toolkit::Internal::CubeTransitionEffect::OnStartTransition
+   */
+  virtual void OnStartTransition( Vector2 panPosition, Vector2 panDisplacement );
+
+private:
+
+  /**
+   * Construct a new CubeTransitionWaveEffect object
+   * @param[in] numRows How many rows of cubes
+   * @param[in] numColumns How many columns of cubes
+   */
+  CubeTransitionWaveEffect( unsigned int numRows, unsigned int numColumns );
+
+  /**
+   * The Saddle surface (Hyperbolic paraboloid)function is used to calculate the delay of rotating animation for each cube
+   * This function calculates the Hyperbolic paraboloid parameters,
+   * and the translation and rotation params for mapping the current stage coordinate to the function defining coordinate system
+   * @param[in] position The press down position of panGesture
+   * @param[in] displacement The displacement vector of panGesture
+   */
+  void CalculateSaddleSurfaceParameters( Vector2 position, Vector2 displacement);
+
+  /**
+   * Calculate the delay of the animation for each cube
+   * @param[in] x The X coordinate of the cube
+   * @param[in] y The Y coordinate of the cube
+   * @return The delay time of the animation
+   */
+  float CalculateDelay( float x, float y, bool forward );
+
+private:
+
+  //saddle surface(Hyperbolic paraboloid)function, used to calculate the delay time of each cube
+  //z = 1.0 + y*y/a/a - x*x/b/b
+  //with our selection of parameters(a and b), this value for any cube is between 0.0 and 2.0
+  float                      mSaddleAA; //a*a
+  float                      mSaddleBB; //b*b
+  float                      mSaddleB;  //b
+  Vector2                    mTranslation;
+  Vector2                    mRotation;
+
+}; // class CubeTransitionWaveEffect
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::CubeTransitionWaveEffect& GetImpl( Dali::Toolkit::CubeTransitionWaveEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< Internal::CubeTransitionWaveEffect& >( handle );
+}
+
+inline const Internal::CubeTransitionWaveEffect& GetImpl( const Dali::Toolkit::CubeTransitionWaveEffect& obj )
+{
+  DALI_ASSERT_ALWAYS( obj );
+
+  const Dali::RefObject& handle = obj.GetImplementation();
+
+  return static_cast< const Internal::CubeTransitionWaveEffect& >( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_CUBE_TRANSITION_WAVE_EFFECT_H
diff --git a/dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.cpp b/dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.cpp
new file mode 100755 (executable)
index 0000000..d4e2f6e
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+DALI_ENUM_TO_STRING_TABLE_BEGIN( GRADIENT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::GradientType, LINEAR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::GradientType, RADIAL )
+DALI_ENUM_TO_STRING_TABLE_END( GRADIENT_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( UNIT_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::UnitType, OBJECT_BOUNDING_BOX )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::UnitType, USER_SPACE )
+DALI_ENUM_TO_STRING_TABLE_END( UNIT_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::SpreadType, REFLECT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::SpreadType, REPEAT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::SpreadType, CLAMP )
+DALI_ENUM_TO_STRING_TABLE_END( SPREAD_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( DIRECTION_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType, FORWARD )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType, BACKWARD )
+DALI_ENUM_TO_STRING_TABLE_END( DIRECTION_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( MOTION_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType, LOOP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType, MIRROR )
+DALI_ENUM_TO_STRING_TABLE_END( MOTION_TYPE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( EASING_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType, LINEAR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType, IN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType, OUT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType, IN_OUT )
+DALI_ENUM_TO_STRING_TABLE_END( EASING_TYPE )
+
+// Default values of each properties
+const Toolkit::DevelAnimatedGradientVisual::GradientType::Type DEFAULT_GRADIENT_TYPE = Toolkit::DevelAnimatedGradientVisual::GradientType::LINEAR;
+const Toolkit::DevelAnimatedGradientVisual::UnitType::Type     DEFAULT_UNIT_TYPE     = Toolkit::DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX;
+const Toolkit::DevelAnimatedGradientVisual::SpreadType::Type   DEFAULT_SPREAD_TYPE   = Toolkit::DevelAnimatedGradientVisual::SpreadType::REFLECT;
+
+const float DEFAULT_START_POSITION[] = { -0.5f, 0.0f };
+const float DEFAULT_START_COLOR[]    = { 143.0f/255.0f, 170.0f/255.0f, 220.0f/255.0f, 255.0f/255.0f };
+const float DEFAULT_END_POSITION[]   = { 0.5f, 0.0f };
+const float DEFAULT_END_COLOR[]      = { 255.0f/255.0f, 163.0f/255.0f, 163.0f/255.0f, 255.0f/255.0f };
+const float DEFAULT_ROTATE_CENTER[]  = { 0.0f, 0.0f };
+const float DEFAULT_ROTATE_AMOUNT    = 0.0f;
+
+const float DEFAULT_ANIMATION_START_VALUE  = 0.0f;
+const float DEFAULT_ANIMATION_TARGET_VALUE = 0.0f;
+const float DEFAULT_ANIMATION_DURATION     = 3.0f;
+const float DEFAULT_ANIMATION_DELAY        = 0.0f;
+const int   DEFAULT_ANIMATION_REPEAT       = 0;
+const float DEFAULT_ANIMATION_REPEAT_DELAY = 0.0f;
+
+const Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::Type DEFAULT_ANIMATION_DIRECTION_TYPE = Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::FORWARD;
+const Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::Type    DEFAULT_ANIMATION_MOTION_TYPE    = Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::LOOP;
+const Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::Type    DEFAULT_ANIMATION_EASING_TYPE    = Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::LINEAR;
+
+const char* const BASIC_VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;
+  uniform highp   mat4 uMvpMatrix;
+  uniform mediump vec3 uSize;
+
+  uniform mediump vec2 start_point;
+  uniform mediump vec2 end_point;
+  uniform mediump vec2 rotate_center;
+  uniform mediump float rotate_angle;
+
+  varying mediump vec2 vTexCoord;
+  varying mediump vec2 vStart;
+  varying mediump vec2 vEnd;
+
+  vec2 rotate(vec2 x, vec2 c, float a)
+  {
+    vec2 d = x - c;
+    vec2 r = vec2(d.x * cos(a) - d.y * sin(a), d.x * sin(a) + d.y * cos(a));
+
+\n  #ifdef UNIT_TYPE_BOUNDING_BOX \n return r + c;             \n #endif \n /* UnitType::OBJECT_BOUNDING_BOX */
+\n  #ifdef UNIT_TYPE_USER         \n return (r + c) / uSize.x; \n #endif \n /* UnitType::USER_SPACE          */
+  }
+
+  //Visual size and offset
+  uniform mediump vec2 offset;
+  uniform mediump vec2 size;
+  uniform mediump vec4 offsetSizeMode;
+  uniform mediump vec2 origin;
+  uniform mediump vec2 anchorPoint;
+
+  vec4 ComputeVertexPosition()
+  {
+    vec2 visualSize = mix( uSize.xy*size, size, offsetSizeMode.zw );
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy );
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );
+  }
+
+  void main()
+  {
+    vStart = rotate( start_point, rotate_center, rotate_angle );
+    vEnd = rotate( end_point, rotate_center, rotate_angle );
+    gl_Position = uMvpMatrix * ComputeVertexPosition();
+
+\n  #ifdef UNIT_TYPE_BOUNDING_BOX \n vTexCoord = vec2(aPosition.x, -aPosition.y);                     \n #endif \n /* UnitType::OBJECT_BOUNDING_BOX */
+\n  #ifdef UNIT_TYPE_USER         \n vTexCoord = vec2(aPosition.x, -aPosition.y * uSize.y / uSize.x); \n #endif \n /* UnitType::USER_SPACE          */
+  }
+);
+
+const char* const BASIC_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;
+
+  uniform mediump vec4 start_color;
+  uniform mediump vec4 end_color;
+  uniform mediump float gradient_offset;
+
+  varying mediump vec2 vTexCoord;
+  varying mediump vec2 vStart;
+  varying mediump vec2 vEnd;
+
+  float get_position(vec2 x, vec2 s, vec2 e)
+  {
+    vec2 df = e - s;
+    vec2 dx = x - s;
+
+\n  #ifdef GRADIENT_TYPE_LINEAR \n return dot(dx,df)/dot(df,df);       \n #endif \n /* GradientType::LINEAR */
+\n  #ifdef GRADIENT_TYPE_RADIAL \n return sqrt(dot(dx,dx)/dot(df,df)); \n #endif \n /* GradientType::RADIAL */
+  }
+  float recalculate(float r)
+  {
+\n  #ifdef SPREAD_TYPE_REFLECT \n return 1.0 - abs(mod(r, 2.0) - 1.0); \n #endif \n /* SpreadType::REFLECT */
+\n  #ifdef SPREAD_TYPE_REPEAT  \n return fract(r);                     \n #endif \n /* SpreadType::REPEAT  */
+\n  #ifdef SPREAD_TYPE_CLAMP   \n return clamp(r, 0.0, 1.0);           \n #endif \n /* SpreadType::CLAMP   */
+  }
+
+  void main()
+  {
+    float r = get_position( vTexCoord, vStart, vEnd );
+    r = recalculate( r + gradient_offset );
+    vec4 color = mix( start_color, end_color, r );
+    gl_FragColor = color;
+  }
+);
+
+Property::Value GetStartValue( const Property::Map& map, Property::Index index, const char* const name )
+{
+  // Get start value of animation parameter
+  Property::Value* res = map.Find( index, name );
+  if( res )
+  {
+    Property::Map* s_map = res->GetMap();
+    if( s_map )
+    {
+      res = s_map->Find( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::START, START_VALUE_NAME );
+      DALI_ASSERT_ALWAYS( res && "Start value is not setup in Property::Map" );
+    }
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS( !"Start value is not setup even default" );
+  }
+  return *res;
+}
+
+VisualFactoryCache::ShaderType GetShaderType( Toolkit::DevelAnimatedGradientVisual::GradientType::Type grad, Toolkit::DevelAnimatedGradientVisual::UnitType::Type unit, Toolkit::DevelAnimatedGradientVisual::SpreadType::Type spread )
+{
+  return static_cast<VisualFactoryCache::ShaderType>(
+    VisualFactoryCache::ANIMATED_GRADIENT_SHADER_LINEAR_BOUNDING_REFLECT +
+    static_cast<unsigned int>( grad ) * 6 + // 6 is the number of UnitType * SpreadType
+    static_cast<unsigned int>( unit ) * 3 + // 3 is the number of SpreadType.
+    static_cast<unsigned int>( spread )
+  );
+}
+
+} // unnamed namespace
+
+AnimatedGradientVisualPtr AnimatedGradientVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  AnimatedGradientVisualPtr animatedGradientVisualPtr( new AnimatedGradientVisual( factoryCache ) );
+  animatedGradientVisualPtr->SetProperties( properties );
+  return animatedGradientVisualPtr;
+}
+
+AnimatedGradientVisual::AnimatedGradientVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL )
+{
+  SetupDefaultValue();
+}
+
+AnimatedGradientVisual::~AnimatedGradientVisual()
+{
+
+}
+
+void AnimatedGradientVisual::SetupDefaultValue()
+{
+  mGradientType = DEFAULT_GRADIENT_TYPE;
+  mUnitType     = DEFAULT_UNIT_TYPE;
+  mSpreadType   = DEFAULT_SPREAD_TYPE;
+
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::START_POSITION] = Vector2( DEFAULT_START_POSITION );
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::START_COLOR]    = Vector4( DEFAULT_START_COLOR );
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::END_POSITION]   = Vector2( DEFAULT_END_POSITION );
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::END_COLOR]      = Vector4( DEFAULT_END_COLOR );
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_CENTER]  = Vector2( DEFAULT_ROTATE_CENTER );
+  mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT]  = DEFAULT_ROTATE_AMOUNT;
+  // Default Offset value is very special. unlimited animation from 0.0f to 2.0f
+  {
+    Property::Map map;
+    map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::START, 0.0f );
+    map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET, 2.0f );
+    map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT, -1 );
+
+    mValueMap[Toolkit::DevelAnimatedGradientVisual::Property::OFFSET] = map;
+  }
+}
+
+void AnimatedGradientVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  //GRADIENT_TYPE
+  Property::Value* gradientTypeValue = propertyMap.Find( Toolkit::DevelAnimatedGradientVisual::Property::GRADIENT_TYPE, GRADIENT_TYPE_NAME );
+  Toolkit::DevelAnimatedGradientVisual::GradientType::Type gradientType = mGradientType;
+  if( gradientTypeValue )
+  {
+    Scripting::GetEnumerationProperty( *gradientTypeValue, GRADIENT_TYPE_TABLE, GRADIENT_TYPE_TABLE_COUNT, gradientType );
+  }
+
+  //UNIT_TYPE
+  Property::Value* unitTypeValue = propertyMap.Find( Toolkit::DevelAnimatedGradientVisual::Property::UNIT_TYPE, UNIT_TYPE_NAME );
+  Toolkit::DevelAnimatedGradientVisual::UnitType::Type unitType = mUnitType;
+  if( unitTypeValue )
+  {
+    Scripting::GetEnumerationProperty( *unitTypeValue, UNIT_TYPE_TABLE, UNIT_TYPE_TABLE_COUNT, unitType );
+  }
+
+  //SPREAD_TYPE
+  Property::Value* spreadTypeValue = propertyMap.Find( Toolkit::DevelAnimatedGradientVisual::Property::SPREAD_TYPE, SPREAD_TYPE_NAME );
+  Toolkit::DevelAnimatedGradientVisual::SpreadType::Type spreadType = mSpreadType;
+  if( spreadTypeValue )
+  {
+    Scripting::GetEnumerationProperty( *spreadTypeValue, SPREAD_TYPE_TABLE, SPREAD_TYPE_TABLE_COUNT, spreadType );
+  }
+
+  mGradientType = gradientType;
+  mUnitType = unitType;
+  mSpreadType = spreadType;
+
+  SetupGradientAnimationData(propertyMap);
+}
+
+void AnimatedGradientVisual::SetupGradientAnimationData( const Property::Map& propertyMap )
+{
+  mGradientAnimationDataList.Clear(); // Clear Transition Information. All animation will deleted safely
+
+  static Property::Map propertyNameMap;
+  static Property::Map propertyUniformNameMap;
+  if( propertyNameMap.Empty() )
+  {
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::START_POSITION] = START_POSITION_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::START_COLOR   ] = START_COLOR_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::END_POSITION  ] = END_POSITION_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::END_COLOR     ] = END_COLOR_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_CENTER ] = ROTATE_CENTER_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT ] = ROTATE_AMOUNT_NAME;
+    propertyNameMap[Toolkit::DevelAnimatedGradientVisual::Property::OFFSET        ] = OFFSET_NAME;
+  }
+  if( propertyUniformNameMap.Empty() )
+  {
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::START_POSITION] = UNIFORM_START_POINT_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::START_COLOR   ] = UNIFORM_START_COLOR_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::END_POSITION  ] = UNIFORM_END_POINT_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::END_COLOR     ] = UNIFORM_END_COLOR_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_CENTER ] = UNIFORM_ROTATE_CENTER_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT ] = UNIFORM_ROTATE_ANGLE_NAME;
+    propertyUniformNameMap[Toolkit::DevelAnimatedGradientVisual::Property::OFFSET        ] = UNIFORM_OFFSET_NAME;
+  }
+
+  Property::Map::SizeType map_index_end = propertyNameMap.Count();
+  for( Property::Map::SizeType map_index = 0; map_index < map_index_end; map_index++ )
+  {
+    KeyValuePair property_pair = propertyNameMap.GetKeyValue( map_index );
+    KeyValuePair uniform_pair = propertyUniformNameMap.GetKeyValue( map_index );
+    Property::Index index = property_pair.first.indexKey;
+    const std::string property_name = property_pair.second.Get< std::string >();
+    const std::string uniform_name = uniform_pair.second.Get< std::string >();
+
+    Property::Map map;
+    Property::Value default_value = mValueMap[index];
+
+    map["target"] = "background";
+    map["property"] = uniform_name;
+
+    Property::Value *value = propertyMap.Find( index, property_name );
+    if( !value )
+    {
+      value = &default_value;
+    }
+    else
+    {
+      // Update value list
+      mValueMap[index] = (*value);
+    }
+
+    int loop_count = 0;
+    float delay = 0.0f;
+    bool forward = true;
+    bool auto_mirror = false;
+    std::string ease_str = "LINEAR";
+    Property::Map *map_value = value->GetMap();
+    if( map_value )
+    {
+      auto getValueFromMap = [ &map_value ]( const Property::Index& index, const std::string& name, Property::Value& res ) -> void
+      {
+        Property::Value *sub_value = map_value->Find( index, name );
+        if( sub_value )
+        {
+          res = *sub_value;
+        }
+      };
+
+      Property::Value value_start        = DEFAULT_ANIMATION_START_VALUE;
+      Property::Value value_target       = DEFAULT_ANIMATION_TARGET_VALUE;
+      Property::Value value_duration     = DEFAULT_ANIMATION_DURATION;
+      Property::Value value_delay        = DEFAULT_ANIMATION_DELAY;
+      Property::Value value_repeat       = DEFAULT_ANIMATION_REPEAT;
+      Property::Value value_repeat_delay = DEFAULT_ANIMATION_REPEAT_DELAY;
+
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::START       , START_VALUE_NAME   , value_start );
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET      , TARGET_VALUE_NAME  , value_target );
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION    , DURATION_NAME      , value_duration );
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY       , DELAY_NAME         , value_delay );
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT      , REPEAT_NAME        , value_repeat );
+      getValueFromMap( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY, REPEAT_DELAY_NAME  , value_repeat_delay );
+
+      Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::Type direction_type = DEFAULT_ANIMATION_DIRECTION_TYPE;
+      Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::Type    motion_type    = DEFAULT_ANIMATION_MOTION_TYPE;
+      Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::Type    easing_type    = DEFAULT_ANIMATION_EASING_TYPE;
+
+      Property::Value *direction_sub_value = map_value->Find( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION, DIRECTION_TYPE_NAME );
+      if( direction_sub_value )
+      {
+        Scripting::GetEnumerationProperty( *direction_sub_value, DIRECTION_TYPE_TABLE, DIRECTION_TYPE_TABLE_COUNT, direction_type );
+      }
+      Property::Value *motion_sub_value = map_value->Find( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE, MOTION_TYPE_NAME );
+      if( motion_sub_value )
+      {
+        Scripting::GetEnumerationProperty( *motion_sub_value   , MOTION_TYPE_TABLE   , MOTION_TYPE_TABLE_COUNT   , motion_type );
+      }
+      Property::Value *easing_sub_value = map_value->Find( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE, EASING_TYPE_NAME );
+      if( easing_sub_value )
+      {
+        Scripting::GetEnumerationProperty( *easing_sub_value   , EASING_TYPE_TABLE   , EASING_TYPE_TABLE_COUNT   , easing_type );
+      }
+
+      forward = ( direction_type == Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::FORWARD );
+      delay = value_delay.Get< float >();
+      loop_count = value_repeat.Get< int >();
+      auto_mirror = ( motion_type == Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::MIRROR );
+
+      switch( easing_type )
+      {
+        case Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::LINEAR:
+        {
+          ease_str = "LINEAR";
+          break;
+        }
+        case Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN:
+        {
+          ease_str = "EASE_IN_SQUARE";
+          break;
+        }
+        case Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::OUT:
+        {
+          ease_str = "EASE_OUT_SQUARE";
+          break;
+        }
+        case Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN_OUT:
+        {
+          ease_str = "EASE_IN_OUT";
+          break;
+        }
+      }
+
+      map["initialValue"] = forward ? value_start : value_target;
+      map["targetValue"] = forward ? value_target : value_start;
+      if( loop_count != 0 )
+      {
+        map["animator"] = Property::Map()
+                          .Add( "alphaFunction", ease_str )
+                          .Add( "timePeriod", Property::Map()
+                                             .Add( "delay", value_repeat_delay.Get< float >() )
+                                             .Add( "duration", value_duration.Get< float >() ) );
+      }
+    }
+    else
+    {
+      map["initialValue"] = *value;
+      map["targetValue"] = *value;
+    }
+
+    AnimatedGradientVisual::GradientAnimationData *animData = new AnimatedGradientVisual::GradientAnimationData();
+    animData->transition = Toolkit::TransitionData::New( map );
+    animData->index = index;
+    animData->loop_count = loop_count;
+    animData->delay = delay;
+    animData->forward = forward;
+    animData->auto_mirror = auto_mirror;
+    mGradientAnimationDataList.PushBack( animData );
+  }
+}
+
+void AnimatedGradientVisual::SetupAnimation()
+{
+  for( auto&& elem : mGradientAnimationDataList )
+  {
+    Toolkit::TransitionData& transition = elem->transition;
+    Animation& animation = elem->animation;
+    int loop_count = elem->loop_count;
+    bool auto_mirror = elem->auto_mirror;
+    bool without_animation = ( loop_count == 0 );
+
+    const Internal::TransitionData& transitionData = Toolkit::GetImplementation( transition );
+    for( auto iter = transitionData.Begin(); iter != transitionData.End(); iter++ )
+    {
+      TransitionData::Animator *animator = (*iter);
+      AnimateProperty( animation, *animator );
+    }
+    if( animation && !without_animation )
+    {
+      if( loop_count < 0 )
+      {
+        animation.SetLooping( true );
+      }
+      else if( loop_count > 0 )
+      {
+        animation.SetLoopCount( loop_count );
+      }
+      if( auto_mirror )
+      {
+        animation.SetLoopingMode( Animation::LoopingMode::AUTO_REVERSE );
+      }
+    }
+  }
+}
+
+void AnimatedGradientVisual::PlayAnimation()
+{
+  for( auto&& elem : mGradientAnimationDataList )
+  {
+    Animation& animation = elem->animation;
+    if( animation )
+    {
+      float delay = elem->delay;
+      if( delay > 0.0f )
+      {
+        animation.PlayAfter( delay );
+      }
+      else if( delay < 0.0f )
+      {
+        float progress = -delay / animation.GetDuration(); // (duration + repeat_duration)
+        if(progress >= 1.0f)
+        {
+          int cur_loop = animation.GetLoopCount();
+          int decrease_loop = floor( progress ) + 1;
+          while( decrease_loop > progress )
+          {
+            decrease_loop--;
+          }
+          progress -= decrease_loop;
+          if( cur_loop == 0 )
+          {
+            animation.PlayFrom( progress );
+          }
+          else
+          {
+            cur_loop -= decrease_loop;
+            if( cur_loop > 0 )
+            {
+              animation.SetLoopCount( cur_loop );
+              animation.PlayFrom( progress );
+            }
+            else
+            {
+              // animation done. make this animation finished safely.
+              animation.SetLoopCount( 1 );
+              animation.PlayFrom( 1.0f );
+            }
+          }
+        }
+        else
+        {
+          animation.PlayFrom( progress );
+        }
+      }
+      else
+      {
+        animation.Play();
+      }
+    }
+  }
+}
+
+void AnimatedGradientVisual::StopAnimation()
+{
+  for( auto&& elem : mGradientAnimationDataList )
+  {
+    Animation& animation = elem->animation;
+    if( animation )
+    {
+      animation.Stop();
+    }
+  }
+}
+
+void AnimatedGradientVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void AnimatedGradientVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+  actor.AddRenderer( mImpl->mRenderer );
+  SetupAnimation();
+  PlayAnimation();
+
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void AnimatedGradientVisual::DoSetOffStage( Actor& actor )
+{
+  DALI_ASSERT_DEBUG( (bool)mImpl->mRenderer && "There should always be a renderer whilst on stage");
+
+  StopAnimation();
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+}
+
+void AnimatedGradientVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_GRADIENT );
+
+  //Create non-animated properties
+  map.Insert( Toolkit::DevelAnimatedGradientVisual::Property::GRADIENT_TYPE, static_cast<int>(mGradientType) );
+  map.Insert( Toolkit::DevelAnimatedGradientVisual::Property::UNIT_TYPE    , static_cast<int>(mUnitType) );
+  map.Insert( Toolkit::DevelAnimatedGradientVisual::Property::SPREAD_TYPE  , static_cast<int>(mSpreadType) );
+
+  //Create animated properties. Get from transition for more realistic test. Not from animation cause Animation may not setuped
+  for( auto&& elem : mGradientAnimationDataList )
+  {
+    Toolkit::TransitionData& transition = elem->transition;
+    Property::Index index = elem->index;
+    int loop_count = elem->loop_count;
+    float delay = elem->delay;
+    bool forward = elem->forward;
+    bool auto_mirror = elem->auto_mirror;
+
+    const Internal::TransitionData& transitionData = Toolkit::GetImplementation( transition );
+    for( auto iter = transitionData.Begin(); iter != transitionData.End(); iter++ )
+    {
+      TransitionData::Animator *animator = (*iter);
+      if( animator->animate )
+      {
+        //with animation
+        Property::Map animation_map;
+        Property::Value value_start = forward ? animator->initialValue : animator->targetValue;
+        Property::Value value_target = forward ? animator->targetValue : animator->initialValue;
+        Property::Value value_direction;
+        Property::Value value_duration = Property::Value( animator->timePeriodDuration );
+        Property::Value value_delay = Property::Value( delay );
+        Property::Value value_repeat = Property::Value( loop_count );
+        Property::Value value_repeat_delay = Property::Value( animator->timePeriodDelay );
+        Property::Value value_motion_type;
+        Property::Value value_easing_type;
+
+        if( forward )
+        {
+          value_direction = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::FORWARD );
+        }
+        else
+        {
+          value_direction = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::DirectionType::BACKWARD );
+        }
+        if( auto_mirror )
+        {
+          value_motion_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::MIRROR );
+        }
+        else
+        {
+          value_motion_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::MotionType::LOOP );
+        }
+        switch( animator->alphaFunction.GetBuiltinFunction() )
+        {
+          case Dali::AlphaFunction::LINEAR:
+          {
+            value_easing_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::LINEAR );
+            break;
+          }
+          case Dali::AlphaFunction::EASE_IN_SQUARE:
+          {
+            value_easing_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN );
+            break;
+          }
+          case Dali::AlphaFunction::EASE_OUT_SQUARE:
+          {
+            value_easing_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::OUT );
+            break;
+          }
+          case Dali::AlphaFunction::EASE_IN_OUT:
+          {
+            value_easing_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::IN_OUT );
+            break;
+          }
+          default:
+          {
+            value_easing_type = Property::Value( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::EasingType::LINEAR );
+          }
+        }
+
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::START       , value_start );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::TARGET      , value_target );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DIRECTION   , value_direction );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DURATION    , value_duration );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::DELAY       , value_delay );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT      , value_repeat );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::REPEAT_DELAY, value_repeat_delay );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::MOTION_TYPE , value_motion_type );
+        animation_map.Insert( Toolkit::DevelAnimatedGradientVisual::AnimationParameter::Property::EASING_TYPE , value_easing_type );
+
+        map.Insert( index, animation_map );
+      }
+      else
+      {
+        //without animation
+        map.Insert( index, animator->targetValue );
+      }
+    }
+  }
+}
+
+void AnimatedGradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+
+}
+
+Shader AnimatedGradientVisual::CreateShader()
+{
+  Shader shader;
+
+  std::string tagUnit;
+  std::string tagGrad;
+  std::string tagSpread;
+  switch( mUnitType )
+  {
+    case Toolkit::DevelAnimatedGradientVisual::UnitType::OBJECT_BOUNDING_BOX:
+    {
+      tagUnit = "UNIT_TYPE_BOUNDING_BOX";
+      break;
+    }
+    case Toolkit::DevelAnimatedGradientVisual::UnitType::USER_SPACE:
+    {
+      tagUnit = "UNIT_TYPE_USER";
+      break;
+    }
+  }
+  switch( mGradientType )
+  {
+    case Toolkit::DevelAnimatedGradientVisual::GradientType::LINEAR:
+    {
+      tagGrad = "GRADIENT_TYPE_LINEAR";
+      break;
+    }
+    case Toolkit::DevelAnimatedGradientVisual::GradientType::RADIAL:
+    {
+      tagGrad = "GRADIENT_TYPE_RADIAL";
+      break;
+    }
+  }
+  switch( mSpreadType )
+  {
+    case Toolkit::DevelAnimatedGradientVisual::SpreadType::REFLECT:
+    {
+      tagSpread = "SPREAD_TYPE_REFLECT";
+      break;
+    }
+    case Toolkit::DevelAnimatedGradientVisual::SpreadType::REPEAT:
+    {
+      tagSpread = "SPREAD_TYPE_REPEAT";
+      break;
+    }
+    case Toolkit::DevelAnimatedGradientVisual::SpreadType::CLAMP:
+    {
+      tagSpread = "SPREAD_TYPE_CLAMP";
+      break;
+    }
+  }
+
+  std::string vert;
+  std::string frag;
+
+  vert = "#define " + tagUnit + "\n"
+       + BASIC_VERTEX_SHADER;
+  frag = "#define " + tagGrad + "\n"
+       + "#define " + tagSpread + "\n"
+       + BASIC_FRAGMENT_SHADER;
+
+  shader = Shader::New( vert, frag );
+  return shader;
+}
+
+void AnimatedGradientVisual::InitializeRenderer()
+{
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+  VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, mUnitType, mSpreadType );
+  Shader shader = mFactoryCache.GetShader( shaderType );
+  if( !shader )
+  {
+    shader = CreateShader();
+    mFactoryCache.SaveShader( shaderType, shader );
+  }
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  mImpl->mRenderer.RegisterProperty( UNIFORM_START_POINT_NAME  , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::START_POSITION, START_POSITION_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_START_COLOR_NAME  , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::START_COLOR   , START_COLOR_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_END_POINT_NAME    , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::END_POSITION  , END_POSITION_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_END_COLOR_NAME    , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::END_COLOR     , END_COLOR_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_ROTATE_CENTER_NAME, GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_CENTER , ROTATE_CENTER_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_ROTATE_ANGLE_NAME , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::ROTATE_AMOUNT , ROTATE_AMOUNT_NAME ) );
+  mImpl->mRenderer.RegisterProperty( UNIFORM_OFFSET_NAME       , GetStartValue( mValueMap, Toolkit::DevelAnimatedGradientVisual::Property::OFFSET        , OFFSET_NAME ) );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+}//namespace Internal
+
+}//namespace Toolkit
+
+}//namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h b/dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h
new file mode 100755 (executable)
index 0000000..28e820a
--- /dev/null
@@ -0,0 +1,281 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_GRADIENT_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_ANIMATED_GRADIENT_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali-toolkit/devel-api/visuals/animated-gradient-visual-properties-devel.h>
+
+//INTERNAL INCLUDES
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class AnimatedGradientVisual;
+typedef IntrusivePtr< AnimatedGradientVisual > AnimatedGradientVisualPtr;
+
+/**
+ * This visual which renders smooth transition of colors to the control's quad.
+ * There are two types of properties: non-animated property and animated property
+ *
+ * The following properties are non-animated property.
+ *
+ * | %Property Name | Type         | Default                   |
+ * |----------------|--------------|---------------------------|
+ * | gradientType   | GradientType | Linear                    |
+ * | unitType       | UnitType     | Object bounding box       |
+ * | spreadType     | SpreadType   | Reflect                   |
+ *
+ * The following properties are animated property.
+ *
+ * | %Property Name | Type                                     | Default                         |
+ * |----------------|------------------------------------------|---------------------------------|
+ * | startPosition  | Vector2 or AnimationParameter< Vector2 > | (-0.5, 0)                       |
+ * | startColor     | Vector4 or AnimationParameter< Vector4 > | (143., 170., 220., 255.) / 255. |
+ * | endPosition    | Vector2 or AnimationParameter< Vector2 > | (0.5, 0)                        |
+ * | endColor       | Vector4 or AnimationParameter< Vector4 > | (255., 163., 163., 255.) / 255. |
+ * | rotateCenter   | Vector2 or AnimationParameter< Vector2 > | (0.0, 0.0)                      |
+ * | rotateAmount   | Float   or AnimationParameter< Float >   | 0.0                             |
+ * | offset         | Float   or AnimationParameter< Float >   | (explain details below)         |
+ *
+ * Each animated property can contain follow AnimationParameter
+ *
+ * | %AnimationParameter<T>::Propery Name | Type          | Default  |
+ * |--------------------------------------|---------------|----------|
+ * | start                                | T             | Zero     |
+ * | target                               | T             | Zero     |
+ * | direction                            | DirectionType | Forward  |
+ * | duration                             | Float         | 3.0      |
+ * | delay                                | Float         | 0.0      |
+ * | repeat                               | Integer       | 0        |
+ * | repeat_delay                         | Float         | 0.0      |
+ * | motion_type                          | MotionType    | Loop     |
+ * | easing_type                          | EasingType    | Linear   |
+ *
+ * T is animated property value's type. If property type is AnimationParameter< Vector2 >, start and target type is Vector2.
+ *
+ *
+ * gradientType decide the form of gradient
+ * unitType decide the coordinate of all positions
+ * spreadType decide how to make color where gradient_point is not 0 ~ 1
+ * visualSize decide this visual's size hardly. only use when unitType is SCREEN
+ *
+ * startPoint and startColor decide position and color where gradient_point = 0. if gradientType is RADIAL, here is center of circle.
+ * endPoint and endColor  decide position and color where gradient_point = 1.
+ * rotateCenter and rotateAmount are same job as its name
+ * rotateAmount is radian value
+ *
+ * offset is main feature of this visual.
+ * Image the points which has same gradient_point values. If gradientType is LINEAR, this form is line. If gradientTYPE IS RADIAL, this form is circle.
+ * without think about offset value, gradient_point = t color will be like this
+ *
+ *  color(t) = startColor * (1-t) + endColor * t (0 <= t <= 1)
+ *
+ * so color be smooth changed when gradient_point change smooth.
+ * offset value change the color of gradient_point = t like this
+ *
+ *  realColor(t) = color(t + offset)
+ *
+ * so If offset value increas (or decrease) gradient looks like "Flowing" effect
+ * default offset value is an unlimited simple loop animation from 0 to 2. duration is 3.0 second
+ *
+ * GradientType has two types : LINEAR / RADIAL
+ *  LINEAR draw gradient linear form
+ *  RADIAL draw gradietn circle form
+ * UnitType has two types : OBJECT_BOUNDING_BOX / USER_SPACE
+ *  OBJECT_BOUNDING_BOX use normalized coordinate, relate by Actor bounding box. bottom-left ~ top-right : (-0.5,-0.5) ~ (0.5, 0.5)
+ *  USER_SPACE use coordinate, relate by Actor Size. bottom-left ~ top-right : (ActorSize * -0.5) ~ (ActorSize * 0.5)
+ * SpreadType has three types : REFLECT / REPEAT / CLAMP
+ *  REFLECT use mirror warping
+ *  REPEAT use repeat warping
+ *  CLAMP use clamp warping
+ *
+ * DirectionType has two types : FORWARD / BACKWARD
+ *  FORWARD animate value from start to target
+ *  BACKWARD animate value from target to start
+ * MotionType has two types : LOOP / MIRROR
+ *  LOOP animate loopingmode restart
+ *  MIRROR animate loopingmode auto_reverse
+ * EasingType has four types : LINEAR / IN / OUT / IN_OUT
+ *  LINEAR easing animation linear
+ *  IN easing in (slow start -> fast finish)
+ *  OUT easing out (fast start -> slow finish)
+ *  IN_OUT easing in and out (slow start -> slow finish)
+ */
+class AnimatedGradientVisual : public Visual::Base
+{
+public:
+
+  /**
+   * Animation informations what this visual using
+   */
+  struct GradientAnimationData
+  {
+   GradientAnimationData()
+    : index( Property::INVALID_INDEX ),
+      loop_count( 0 ),
+      delay( 0.0f ),
+      forward( false ),
+      auto_mirror( false )
+    {
+    }
+
+    Toolkit::TransitionData transition;
+    Animation animation;
+    Property::Index index;
+    int loop_count;   ///< if < 0, loop unlimited. else, loop loop_count times.
+    float delay;      ///< delay time. if > 0, wait 'delay' seconds. else, play animation at '-delay' seconds.
+    bool forward;     ///< True if AnimationParameter::DirectionType::Type is FORWARD
+    bool auto_mirror; ///< True if AnimationParameter::LoopType::Type is MIRROR
+  };
+
+  using GradientAnimationDataList =  Dali::OwnerContainer< GradientAnimationData* >;
+
+public:
+
+  /**
+   * @brief Create a new animated gradient visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual
+   */
+  static AnimatedGradientVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+private: //from Visual
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  AnimatedGradientVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unrefecence()
+   */
+  virtual ~AnimatedGradientVisual();
+
+protected: //from Visual
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+private:
+
+  /**
+   * @brief Initialize the default value of properies.
+   */
+  void SetupDefaultValue();
+
+  /**
+   * @brief Initialize the rendere with the geometry from the cache, and shader which made by CreateShader()
+   */
+  void InitializeRenderer();
+
+  /**
+   * @brief Make animations with GradientAnimationData
+   */
+  void SetupAnimation();
+
+  /**
+  * @brief Play animations
+  */
+  void PlayAnimation();
+
+  /**
+  * @brief Stop animations
+  */
+  void StopAnimation();
+
+  /**
+   * @brief Clear all previous GradientAnimationData and Setup new GradientAnimationData information which made by animated properties
+   *
+   * param[in] propertyMap A Property::Map come from DoSetProperties
+   */
+  void SetupGradientAnimationData( const Property::Map& propertyMap );
+
+  /**
+   * @brief Create new shader
+   *
+   * return A Shader which made by non-animated properties
+   */
+  Shader CreateShader();
+
+  // Undefined
+  AnimatedGradientVisual( const AnimatedGradientVisual& gradientRenderer );
+
+  // Undefined
+  AnimatedGradientVisual& operator=( const AnimatedGradientVisual& gradientRenderer );
+
+private:
+  GradientAnimationDataList mGradientAnimationDataList;
+  Property::Map mValueMap;
+
+  Dali::Toolkit::DevelAnimatedGradientVisual::GradientType::Type mGradientType;
+  Dali::Toolkit::DevelAnimatedGradientVisual::UnitType::Type mUnitType;
+  Dali::Toolkit::DevelAnimatedGradientVisual::SpreadType::Type mSpreadType;
+};
+
+}//namespace Internal
+
+}//namespace Toolkit
+
+}//namespace Dali
+
+#endif
diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
new file mode 100755 (executable)
index 0000000..a0ebe45
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2020 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 "animated-image-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
+#include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
+#include <dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+// stop behavior
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STOP_BEHAVIOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME )
+DALI_ENUM_TO_STRING_TABLE_END( STOP_BEHAVIOR )
+
+// wrap modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT )
+DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE )
+
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+constexpr auto LOOP_FOREVER = -1;
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+#endif
+}
+
+
+/**
+ * Multi-image  Flow of execution
+ *
+ *   | New
+ *   |   DoSetProperties()
+ *   |   LoadFirstBatch()
+ *   |     new cache
+ *   |       cache->LoadBatch()
+ *   |
+ *   | DoSetOnStage()
+ *   |   PrepareTextureSet()
+ *   |     cache->FirstFrame()
+ *   |   CreateRenderer()    (Doesn't become ready until first frame loads)
+ *   |   StartFirstFrame()
+ *   |
+ *   | FrameReady(textureSet)
+ *   |   start first frame:
+ *   |     actor.AddRenderer
+ *   |     start timer
+ *   |   mRenderer.SetTextures(textureSet)
+ *   |
+ *   | Timer ticks
+ *   |   DisplayNextFrame()
+ *   |     if front frame is ready,
+ *   |       mRenderer.SetTextures( front frame's texture )
+ *   |     else
+ *   |       mWaitingForTexture=true
+ *   |     cache->LoadBatch()
+ *   |
+ *   | FrameReady(textureSet)
+ *   |   mRenderer.SetTextures(textureSet)
+ *   V
+ *  Time
+ */
+
+AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
+{
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache, shaderFactory ) );
+  visual->InitializeGif( imageUrl );
+  visual->SetProperties( properties );
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
+  return visual;
+}
+
+AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties )
+{
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache, shaderFactory ) );
+  visual->mImageUrls = new ImageCache::UrlList();
+  visual->mImageUrls->reserve( imageUrls.Count() );
+
+  for( unsigned int i=0; i < imageUrls.Count(); ++i)
+  {
+    ImageCache::UrlStore urlStore;
+    urlStore.mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    urlStore.mUrl = imageUrls[i].Get<std::string>();
+    visual->mImageUrls->push_back( urlStore );
+  }
+  visual->mFrameCount = imageUrls.Count();
+  visual->SetProperties( properties );
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
+  return visual;
+}
+
+AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
+{
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache, shaderFactory ) );
+  visual->InitializeGif( imageUrl );
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
+  return visual;
+}
+
+void AnimatedImageVisual::InitializeGif( const VisualUrl& imageUrl )
+{
+  mImageUrl = imageUrl;
+  mGifLoading = GifLoading::New( imageUrl.GetUrl(), imageUrl.IsLocalResource() );
+  mFrameCount = mGifLoading->GetImageCount();
+  mGifLoading->LoadFrameDelays( mFrameDelayContainer );
+}
+
+AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory )
+: Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
+  mFrameDelayTimer(),
+  mPlacementActor(),
+  mImageVisualShaderFactory( shaderFactory ),
+  mPixelArea( FULL_TEXTURE_RECT ),
+  mImageUrl(),
+  mGifLoading( nullptr ),
+  mCurrentFrameIndex( 0 ),
+  mImageUrls( NULL ),
+  mImageCache( NULL ),
+  mCacheSize( 1 ),
+  mBatchSize( 1 ),
+  mFrameDelay( 100 ),
+  mLoopCount( LOOP_FOREVER ),
+  mCurrentLoopIndex( 0 ),
+  mUrlIndex( 0 ),
+  mFrameCount( 0 ),
+  mImageSize(),
+  mWrapModeU( WrapMode::DEFAULT ),
+  mWrapModeV( WrapMode::DEFAULT ),
+  mActionStatus( DevelAnimatedImageVisual::Action::PLAY ),
+  mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
+  mStartFirstFrame(false),
+  mIsJumpTo( false )
+{}
+
+AnimatedImageVisual::~AnimatedImageVisual()
+{
+  delete mImageCache;
+  delete mImageUrls;
+}
+
+void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( mImageSize.GetWidth() == 0 &&  mImageSize.GetHeight() == 0)
+  {
+    if( mImageUrl.IsValid() )
+    {
+      mImageSize = mGifLoading->GetImageSize();
+    }
+    else if( mImageUrls && mImageUrls->size() > 0 )
+    {
+      mImageSize = Dali::GetClosestImageSize( (*mImageUrls)[0].mUrl );
+    }
+  }
+
+  naturalSize.width = mImageSize.GetWidth();
+  naturalSize.height = mImageSize.GetHeight();
+}
+
+void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE );
+
+  if( mImageUrl.IsValid() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
+  }
+  if( mImageUrls != NULL && ! mImageUrls->empty() )
+  {
+    Property::Array urls;
+    for( unsigned int i=0; i<mImageUrls->size(); ++i)
+    {
+      urls.Add( (*mImageUrls)[i].mUrl );
+    }
+    Property::Value value( const_cast<Property::Array&>(urls) );
+    map.Insert( Toolkit::ImageVisual::Property::URL, value );
+  }
+
+  map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
+
+  map.Insert( Toolkit::ImageVisual::Property::BATCH_SIZE, static_cast<int>(mBatchSize) );
+  map.Insert( Toolkit::ImageVisual::Property::CACHE_SIZE, static_cast<int>(mCacheSize) );
+  map.Insert( Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast<int>(mFrameDelay) );
+  map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast<int>(mLoopCount) );
+
+  map.Insert( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior );
+}
+
+void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void AnimatedImageVisual::OnDoAction( const Dali::Property::Index actionId, const Dali::Property::Value& attributes )
+{
+  // Check if action is valid for this visual type and perform action if possible
+
+  switch ( actionId )
+  {
+    case DevelAnimatedImageVisual::Action::PAUSE:
+    {
+      // Pause will be executed on next timer tick
+      mActionStatus = DevelAnimatedImageVisual::Action::PAUSE;
+      break;
+    }
+    case DevelAnimatedImageVisual::Action::PLAY:
+    {
+      if( IsOnStage() && mActionStatus != DevelAnimatedImageVisual::Action::PLAY )
+      {
+        mFrameDelayTimer.Start();
+      }
+      mActionStatus = DevelAnimatedImageVisual::Action::PLAY;
+      break;
+    }
+    case DevelAnimatedImageVisual::Action::STOP:
+    {
+      // STOP reset functionality will actually be done in a future change
+      // Stop will be executed on next timer tick
+      mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+      if( IsOnStage() )
+      {
+        DisplayNextFrame();
+      }
+      break;
+    }
+    case DevelAnimatedImageVisual::Action::JUMP_TO:
+    {
+      int32_t frameNumber;
+      if( attributes.Get( frameNumber ) )
+      {
+        if( frameNumber < 0 || frameNumber >= static_cast<int32_t>( mFrameCount ) )
+        {
+          DALI_LOG_ERROR( "Invalid frame index used.\n" );
+        }
+        else
+        {
+          mIsJumpTo = true;
+          mCurrentFrameIndex = frameNumber;
+          if( IsOnStage() )
+          {
+            DisplayNextFrame();
+          }
+        }
+      }
+      break;
+    }
+  }
+}
+
+void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // url[s] already passed in from constructor
+
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else
+    {
+      if( keyValue.first == PIXEL_AREA_UNIFORM_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_WRAP_MODE_U )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_WRAP_MODE_V )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second );
+      }
+      else if( keyValue.first == BATCH_SIZE_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::BATCH_SIZE, keyValue.second );
+      }
+      else if( keyValue.first == CACHE_SIZE_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::CACHE_SIZE, keyValue.second );
+      }
+      else if( keyValue.first == FRAME_DELAY_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::FRAME_DELAY, keyValue.second );
+      }
+      else if( keyValue.first == LOOP_COUNT_NAME )
+      {
+        DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
+      }
+      else if( keyValue.first == STOP_BEHAVIOR_NAME )
+      {
+         DoSetProperty( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second );
+      }
+    }
+  }
+}
+
+void AnimatedImageVisual::DoSetProperty( Property::Index index,
+                                         const Property::Value& value )
+{
+  switch(index)
+  {
+    case Toolkit::ImageVisual::Property::PIXEL_AREA:
+    {
+      value.Get( mPixelArea );
+      break;
+    }
+    case Toolkit::ImageVisual::Property::WRAP_MODE_U:
+    {
+      int wrapMode = 0;
+      if(Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode ))
+      {
+        mWrapModeU = Dali::WrapMode::Type(wrapMode);
+      }
+      else
+      {
+        mWrapModeU = Dali::WrapMode::Type::DEFAULT;
+      }
+      break;
+    }
+    case Toolkit::ImageVisual::Property::WRAP_MODE_V:
+    {
+      int wrapMode = 0;
+      if(Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode ))
+      {
+        mWrapModeV = Dali::WrapMode::Type(wrapMode);
+      }
+      else
+      {
+        mWrapModeV = Dali::WrapMode::Type::DEFAULT;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::BATCH_SIZE:
+    {
+      int batchSize;
+      if( value.Get( batchSize ) )
+      {
+        mBatchSize = batchSize;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::CACHE_SIZE:
+    {
+      int cacheSize;
+      if( value.Get( cacheSize ) )
+      {
+        mCacheSize = cacheSize;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::FRAME_DELAY:
+    {
+      int frameDelay;
+      if( value.Get( frameDelay ) )
+      {
+        mFrameDelay = frameDelay;
+      }
+      break;
+    }
+
+    case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
+    {
+      int loopCount;
+      if( value.Get( loopCount ) )
+      {
+        mLoopCount = loopCount;
+      }
+      break;
+    }
+
+    case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR:
+    {
+      int32_t stopBehavior = mStopBehavior;
+      if( Scripting::GetEnumerationProperty( value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior ) )
+      {
+        mStopBehavior = DevelImageVisual::StopBehavior::Type( stopBehavior );
+      }
+      break;
+    }
+  }
+}
+
+void AnimatedImageVisual::DoSetOnStage( Actor& actor )
+{
+  mPlacementActor = actor;
+  TextureSet textureSet = PrepareTextureSet();
+  CreateRenderer(); // Always create a renderer when on stage
+
+  if( textureSet ) // if the image loading is successful
+  {
+    StartFirstFrame( textureSet );
+  }
+  else
+  {
+    mStartFirstFrame = true;
+  }
+}
+
+void AnimatedImageVisual::DoSetOffStage( Actor& actor )
+{
+  DALI_ASSERT_DEBUG( (bool)mImpl->mRenderer && "There should always be a renderer whilst on stage");
+
+  if( mFrameDelayTimer )
+  {
+    mFrameDelayTimer.Stop();
+    mFrameDelayTimer.Reset();
+  }
+
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+  mPlacementActor.Reset();
+}
+
+void AnimatedImageVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void AnimatedImageVisual::CreateRenderer()
+{
+  bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+  bool atlasing = false;
+  Shader shader = mImageVisualShaderFactory.GetShader( mFactoryCache, atlasing, defaultWrapMode, IsRoundedCornerRequired() );
+
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  if( !defaultWrapMode ) // custom wrap mode
+  {
+    Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
+    wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
+    mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
+  }
+
+  if( mPixelArea != FULL_TEXTURE_RECT )
+  {
+    mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
+  }
+
+  mCurrentFrameIndex = 0;
+}
+
+void AnimatedImageVisual::LoadFirstBatch()
+{
+  // Ensure the batch size and cache size are no bigger than the number of URLs,
+  // and that the cache is at least as big as the batch size.
+  uint16_t numUrls = 0;
+  uint16_t batchSize = 1;
+  uint16_t cacheSize = 1;
+
+  if( mImageUrls )
+  {
+    numUrls = mImageUrls->size();
+  }
+  else
+  {
+    numUrls = mFrameCount;
+  }
+
+  batchSize = std::min( mBatchSize, numUrls );
+  cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()  batchSize:%d  cacheSize:%d\n", batchSize, cacheSize);
+
+  mUrlIndex = 0;
+  TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+  if( mGifLoading != nullptr )
+  {
+    mImageCache = new RollingGifImageCache( textureManager, *mGifLoading, mFrameCount, *this, cacheSize, batchSize );
+  }
+  else if( mImageUrls )
+  {
+    if( batchSize > 0 && cacheSize > 0 )
+    {
+      if( cacheSize < numUrls )
+      {
+        mImageCache = new RollingImageCache( textureManager, *mImageUrls, *this, cacheSize, batchSize );
+      }
+      else
+      {
+        mImageCache = new FixedImageCache( textureManager, *mImageUrls, *this, batchSize );
+      }
+    }
+    else
+    {
+      mImageCache = new RollingImageCache( textureManager, *mImageUrls, *this, 1, 1 );
+    }
+  }
+
+  if (!mImageCache)
+  {
+    DALI_LOG_ERROR("mImageCache is null\n");
+  }
+}
+
+void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
+{
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::StartFirstFrame()\n");
+
+  mStartFirstFrame = false;
+  if(mImpl->mRenderer)
+  {
+    mImpl->mRenderer.SetTextures( textureSet );
+  }
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+    mPlacementActor.Reset();
+  }
+
+  mCurrentFrameIndex = 0;
+
+  if( mFrameCount > 1 )
+  {
+    int frameDelay = mFrameDelay; // from URL array
+    if( mFrameDelayContainer.Count() > 0 ) // from GIF
+    {
+      frameDelay = mFrameDelayContainer[0];
+    }
+
+    mFrameDelayTimer = Timer::New( frameDelay );
+    mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
+    mFrameDelayTimer.Start();
+  }
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::READY)\n");
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+TextureSet AnimatedImageVisual::PrepareTextureSet()
+{
+  TextureSet textureSet;
+  if (mImageCache)
+    textureSet = mImageCache->FirstFrame();
+  if( textureSet )
+  {
+    SetImageSize( textureSet );
+  }
+  else
+  {
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::FAILED)\n");
+    ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
+  }
+
+  return textureSet;
+}
+
+void AnimatedImageVisual::SetImageSize( TextureSet& textureSet )
+{
+  if( textureSet )
+  {
+    Texture texture = textureSet.GetTexture( 0 );
+    if( texture )
+    {
+      mImageSize.SetWidth( texture.GetWidth() );
+      mImageSize.SetHeight( texture.GetHeight() );
+    }
+  }
+}
+
+void AnimatedImageVisual::FrameReady( TextureSet textureSet )
+{
+  SetImageSize( textureSet );
+
+  if( mStartFirstFrame )
+  {
+    StartFirstFrame( textureSet );
+  }
+  else
+  {
+    if(mImpl->mRenderer)
+    {
+      mImpl->mRenderer.SetTextures( textureSet );
+    }
+  }
+}
+
+bool AnimatedImageVisual::DisplayNextFrame()
+{
+  if( mIsJumpTo )
+  {
+    mIsJumpTo = false;
+  }
+  else if( mActionStatus == DevelAnimatedImageVisual::Action::PAUSE )
+  {
+    return false;
+  }
+  else if( mActionStatus == DevelAnimatedImageVisual::Action::STOP )
+  {
+    mCurrentLoopIndex = 0;
+    if( mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME )
+    {
+      mCurrentFrameIndex = 0;
+    }
+    else if( mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME )
+    {
+      mCurrentFrameIndex = mFrameCount - 1;
+    }
+    else
+    {
+      return false; // Do not draw already rendered scene twice.
+    }
+  }
+  else
+  {
+    if( mFrameCount > 1 )
+    {
+      // Wrap the frame index
+      bool finished = false;
+      ++mCurrentFrameIndex;
+      if( mCurrentFrameIndex >= mFrameCount )
+      {
+        ++mCurrentLoopIndex;
+        finished = true;
+      }
+
+      if( mLoopCount < 0 || mCurrentLoopIndex < mLoopCount)
+      {
+        if( finished )
+        {
+          mCurrentFrameIndex = 0; // Back to the first frame
+        }
+      }
+      else
+      {
+        // This will stop timer
+        mActionStatus = DevelAnimatedImageVisual::Action::STOP;
+        return DisplayNextFrame();
+      }
+    }
+
+    if( mFrameDelayContainer.Count() > 0 )
+    {
+      unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
+
+      if( mFrameDelayTimer.GetInterval() != delay )
+      {
+        mFrameDelayTimer.SetInterval( delay );
+      }
+    }
+  }
+
+  DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, mCurrentFrameIndex);
+
+  TextureSet textureSet;
+  if( mImageCache )
+  {
+    textureSet = mImageCache->Frame( mCurrentFrameIndex );
+    if( textureSet )
+    {
+      SetImageSize( textureSet );
+      mImpl->mRenderer.SetTextures( textureSet );
+    }
+  }
+
+  return ( mActionStatus == DevelAnimatedImageVisual::Action::PLAY ) ? true : false;
+}
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
new file mode 100755 (executable)
index 0000000..0d21f97
--- /dev/null
@@ -0,0 +1,278 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
+
+/*
+ * Copyright (c) 2020 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ImageVisualShaderFactory;
+class AnimatedImageVisual;
+typedef IntrusivePtr< AnimatedImageVisual > AnimatedImageVisualPtr;
+
+/**
+ * The visual which renders an animated image
+ *
+ * One of the following properties is mandatory
+ *
+ * | %Property Name     | Type              |
+ * |------------------- |-------------------|
+ * | url                | STRING            |
+ * | urls               | ARRAY of STRING   |
+ *
+ * The remaining properties are optional
+ * | pixelArea          | VECTOR4           |
+ * | wrapModeU          | INTEGER OR STRING |
+ * | wrapModeV          | INTEGER OR STRING |
+ * | cacheSize          | INTEGER           |
+ * | batchSize          | INTEGER           |
+ * | frameDelay         | INTEGER           |
+ *
+ * pixelArea is a rectangular area.
+ * In its Vector4 value, the first two elements indicate the top-left position of the area,
+ * and the last two elements are the area width and height respectively.
+ * If not specified, the default value is [0.0, 0.0, 1.0, 1.0], i.e. the entire area of the image.
+ *
+ * wrapModeU and wrapModeV separately decide how the texture should be sampled when the u and v coordinate exceeds the range of 0.0 to 1.0.
+ * Its value should be one of the following wrap mode:
+ *   "DEFAULT"
+ *   "CLAMP_TO_EDGE"
+ *   "REPEAT"
+ *   "MIRRORED_REPEAT"
+ *
+ * cacheSize is used with multiple images - it determines how many images are kept pre-loaded
+ * batchSize is used with multiple images - it determines how many images to load on each frame
+ * frameDelay is used with multiple images - it is the number of milliseconds between each frame
+ */
+
+class AnimatedImageVisual : public Visual::Base,
+                            public ConnectionTracker,
+                            public ImageCache::FrameReadyObserver
+{
+
+public:
+
+  /**
+   * @brief Create the animated image Visual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to gif resource to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties );
+
+  /**
+   * @brief Create the animated image Visual using image URLs.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrls A Property::Array containing the URLs to the image resources
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties );
+
+  /**
+   * @brief Create the animated image visual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to animated image resource to use
+   */
+  static AnimatedImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::OnDoAction
+   */
+  void OnDoAction( const Dali::Property::Index actionName, const Dali::Property::Value& attributes ) override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   */
+  AnimatedImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~AnimatedImageVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+  /**
+   * Creates the renderer for the animated image
+   */
+  void CreateRenderer();
+
+  /**
+   * Starts the Load of the first batch of URLs
+   */
+  void LoadFirstBatch();
+
+  /**
+   * Adds the texture set to the renderer, and the renderer to the
+   * placement actor, and starts the frame timer
+   * @param[in] textureSet The texture set to apply
+   */
+  void StartFirstFrame( TextureSet& textureSet );
+
+  /**
+   * Prepares the texture set for displaying
+   */
+  TextureSet PrepareTextureSet();
+
+  /**
+   * Set the image size from the texture set
+   * @param[in] textureSet The texture set to get the size from
+   */
+  void SetImageSize( TextureSet& textureSet );
+
+  /**
+   * Called when the next frame is ready.
+   * @param[in] textureSet the texture set to apply
+   */
+  void FrameReady( TextureSet textureSet );
+
+  /**
+   * Display the next frame. It is called when the mFrameDelayTimer ticks.
+   * Returns true to ensure the timer continues running.
+   */
+  bool DisplayNextFrame();
+
+  /**
+   * Initialize the gif variables.
+   * @param[in] imageUrl The url of the animated gif
+   */
+  void InitializeGif( const VisualUrl& imageUrl );
+
+  // Undefined
+  AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual );
+
+  // Undefined
+  AnimatedImageVisual& operator=( const AnimatedImageVisual& animatedImageVisual );
+
+private:
+
+  Timer mFrameDelayTimer;
+  WeakHandle<Actor> mPlacementActor;
+  ImageVisualShaderFactory& mImageVisualShaderFactory;
+
+  // Variables for GIF player
+  Dali::Vector<uint32_t> mFrameDelayContainer;
+  Vector4 mPixelArea;
+  VisualUrl mImageUrl;
+  std::unique_ptr<Dali::GifLoading> mGifLoading; // Only needed for animated gifs
+  uint32_t mCurrentFrameIndex; // Frame index into textureRects
+
+  // Variables for Multi-Image player
+  ImageCache::UrlList* mImageUrls;
+  ImageCache* mImageCache;
+  uint16_t mCacheSize;
+  uint16_t mBatchSize;
+  uint16_t mFrameDelay;
+  int16_t mLoopCount;
+  int16_t mCurrentLoopIndex;
+  uint16_t mUrlIndex;
+
+  // Shared variables
+  uint32_t mFrameCount; // Number of frames
+  ImageDimensions mImageSize;
+
+  Dali::WrapMode::Type mWrapModeU:3;
+  Dali::WrapMode::Type mWrapModeV:3;
+  DevelAnimatedImageVisual::Action::Type mActionStatus:3;
+  DevelImageVisual::StopBehavior::Type   mStopBehavior:2;
+  bool mStartFirstFrame:1;
+  bool mIsJumpTo:1;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+#endif /* DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
new file mode 100644 (file)
index 0000000..d71ee94
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+namespace
+{
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+} // namespace
+
+FixedImageCache::FixedImageCache(
+  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
+  unsigned int batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
+  mFront(0u)
+{
+  mReadyFlags.reserve( mImageUrls.size() );
+  LoadBatch();
+}
+
+FixedImageCache::~FixedImageCache()
+{
+  if( mTextureManagerAlive )
+  {
+    for( std::size_t i = 0; i < mImageUrls.size() ; ++i )
+    {
+      mTextureManager.Remove( mImageUrls[i].mTextureId, this );
+    }
+  }
+}
+
+TextureSet FixedImageCache::Frame( uint32_t frameIndex )
+{
+  while( frameIndex > mFront )
+  {
+    NextFrame();
+  }
+  mFront = frameIndex;
+
+  TextureSet textureSet;
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
+  {
+    mWaitingForReadyFrame = true;
+  }
+
+  return textureSet;
+}
+
+TextureSet FixedImageCache::FirstFrame()
+{
+  TextureSet textureSet = GetFrontTextureSet();
+
+  if( ! textureSet )
+  {
+    mWaitingForReadyFrame = true;
+  }
+
+  return textureSet;
+}
+
+TextureSet FixedImageCache::NextFrame()
+{
+  TextureSet textureSet;
+  ++mFront;
+  mFront %= mImageUrls.size();
+
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
+  {
+    mWaitingForReadyFrame = true;
+  }
+  LoadBatch();
+
+  return textureSet;
+}
+
+bool FixedImageCache::IsFrontReady() const
+{
+  return ( mReadyFlags.size() > 0 && mReadyFlags[mFront] == true );
+}
+
+void FixedImageCache::LoadBatch()
+{
+  // Try and load up to mBatchSize images, until the cache is filled.
+  // Once the cache is filled, mUrlIndex exceeds mImageUrls size and
+  // no more images are loaded.
+  bool frontFrameReady = IsFrontReady();
+
+  for( unsigned int i=0; i< mBatchSize && mUrlIndex < mImageUrls.size(); ++i )
+  {
+    std::string& url = mImageUrls[ mUrlIndex ].mUrl;
+
+    mReadyFlags.push_back(false);
+
+    // Note, if the image is already loaded, then UploadComplete will get called
+    // from within this method. This means it won't yet have a texture id, so we
+    // need to account for this inside the UploadComplete method using mRequestingLoad.
+    mRequestingLoad = true;
+
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+    Dali::ImageDimensions textureRectSize;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect, textureRectSize,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
+
+    if( loadingStatus == false )  // not loading, means it's already ready.
+    {
+      SetImageFrameReady( mImageUrls[ mUrlIndex ].mTextureId );
+    }
+    mRequestingLoad = false;
+    ++mUrlIndex;
+  }
+
+  CheckFrontFrame( frontFrameReady );
+}
+
+void FixedImageCache::SetImageFrameReady( TextureManager::TextureId textureId )
+{
+  for( std::size_t i = 0; i < mImageUrls.size() ; ++i )
+  {
+    if( mImageUrls[i].mTextureId == textureId )
+    {
+      mReadyFlags[i] = true;
+      break;
+    }
+  }
+}
+
+TextureSet FixedImageCache::GetFrontTextureSet() const
+{
+  return mTextureManager.GetTextureSet( mImageUrls[mFront].mTextureId );
+}
+
+void FixedImageCache::CheckFrontFrame( bool wasReady )
+{
+  if( mWaitingForReadyFrame && wasReady == false && IsFrontReady() )
+  {
+    mWaitingForReadyFrame = false;
+    mObserver.FrameReady( GetFrontTextureSet() );
+  }
+}
+
+void FixedImageCache::UploadComplete(
+  bool           loadSuccess,
+  int32_t        textureId,
+  TextureSet     textureSet,
+  bool           useAtlasing,
+  const Vector4& atlasRect,
+  bool           preMultiplied)
+{
+  bool frontFrameReady = IsFrontReady();
+
+  if( ! mRequestingLoad )
+  {
+    SetImageFrameReady( textureId );
+
+    CheckFrontFrame( frontFrameReady );
+  }
+  else
+  {
+    // UploadComplete has been called from within RequestLoad. TextureManager must
+    // therefore already have the texture cached, so make the texture ready.
+    // (Use the last texture, as the texture id hasn't been assigned yet)
+    mReadyFlags.back() = true;
+  }
+}
+
+void FixedImageCache::LoadComplete(
+  bool loadSuccess,
+  Devel::PixelBuffer pixelBuffer,
+  const VisualUrl& url,
+  bool preMultiplied )
+{
+  // LoadComplete is called if this TextureUploadObserver requested to load
+  // an image that will be returned as a type of PixelBuffer by using a method
+  // TextureManager::LoadPixelBuffer.
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
new file mode 100644 (file)
index 0000000..d884e28
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_TOOLKIT_INTERNAL_FIXED_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_FIXED_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class FixedImageCache : public ImageCache, public TextureUploadObserver
+{
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] urlList List of urls to cache
+   * @param[in] observer FrameReady observer
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes. The cache is as large as the number of urls.
+   */
+  FixedImageCache( TextureManager&                 textureManager,
+                   UrlList&                        urlList,
+                   ImageCache::FrameReadyObserver& observer,
+                   unsigned int                    batchSize );
+
+  virtual ~FixedImageCache();
+
+  /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet Frame( uint32_t frameIndex ) override;
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet FirstFrame() override;
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  TextureSet NextFrame() override;
+
+private:
+  /**
+   * @return true if the front frame is ready
+   */
+  bool IsFrontReady() const;
+
+  /**
+   * Load the next batch of images
+   */
+  void LoadBatch();
+
+  /**
+   * Find the matching image frame, and set it to ready
+   */
+  void SetImageFrameReady( TextureManager::TextureId textureId );
+
+  /**
+   * Get the texture set of the front frame.
+   * @return the texture set
+   */
+  TextureSet GetFrontTextureSet() const;
+
+  /**
+   * Check if the front frame has become ready - if so, inform observer
+   * @param[in] wasReady Readiness before call.
+   */
+  void CheckFrontFrame( bool wasReady );
+
+protected:
+  void UploadComplete(
+    bool           loadSuccess,
+    int32_t        textureId,
+    TextureSet     textureSet,
+    bool           useAtlasing,
+    const Vector4& atlasRect,
+    bool           premultiplied ) override;
+
+  void LoadComplete(
+    bool loadSuccess,
+    Devel::PixelBuffer pixelBuffer,
+    const VisualUrl& url,
+    bool preMultiplied ) override;
+
+private:
+  std::vector<UrlStore>& mImageUrls;
+  std::vector<bool> mReadyFlags;
+  unsigned int      mFront;
+};
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_FIXED_IMAGE_CACHE_H
diff --git a/dali-toolkit/internal/visuals/animated-image/image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/image-cache.cpp
new file mode 100644 (file)
index 0000000..78ca796
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 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 "image-cache.h"
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+ImageCache::ImageCache( TextureManager&                 textureManager,
+                        ImageCache::FrameReadyObserver& observer,
+                        unsigned int                    batchSize )
+: mTextureManager( textureManager ),
+  mObserver( observer ),
+  mBatchSize( batchSize ),
+  mUrlIndex(0u),
+  mWaitingForReadyFrame(false),
+  mRequestingLoad(false),
+  mTextureManagerAlive(true)
+{
+  mTextureManager.AddObserver( *this );
+}
+
+ImageCache::~ImageCache()
+{
+  if( mTextureManagerAlive )
+  {
+    mTextureManager.RemoveObserver( *this );
+  }
+}
+
+void ImageCache::TextureManagerDestroyed()
+{
+  mTextureManagerAlive = false;
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/image-cache.h b/dali-toolkit/internal/visuals/animated-image/image-cache.h
new file mode 100644 (file)
index 0000000..7354992
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/texture-upload-observer.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class ImageCache : public TextureManager::LifecycleObserver
+{
+public:
+  /**
+   * Observer class to inform when the next image is ready
+   */
+  class FrameReadyObserver
+  {
+  public:
+    /**
+     * Informs observer when the next texture set is ready to display
+     * @param[in] textureSet The ready texture set
+     */
+    virtual void FrameReady( TextureSet textureSet ) = 0;
+  };
+
+  struct UrlStore
+  {
+    TextureManager::TextureId mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    std::string mUrl;
+  };
+
+  /**
+   * List of URLs
+   */
+  typedef std::vector<UrlStore> UrlList;
+
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] urlList List of urls to cache
+   * @param[in] observer FrameReady observer
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes. The cache is as large as the number of urls.
+   */
+  ImageCache( TextureManager&                 textureManager,
+              ImageCache::FrameReadyObserver& observer,
+              unsigned int                    batchSize );
+
+  virtual ~ImageCache();
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  virtual TextureSet FirstFrame() = 0;
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  virtual TextureSet NextFrame() = 0;
+
+  /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  virtual TextureSet Frame( uint32_t frameIndex ) = 0;
+
+private:
+
+  /**
+   * Called before the texture manager is destroyed.
+   */
+  void TextureManagerDestroyed() final;
+
+protected:
+  TextureManager&        mTextureManager;
+  FrameReadyObserver&    mObserver;
+  unsigned int           mBatchSize;
+  unsigned int           mUrlIndex;
+  bool                   mWaitingForReadyFrame:1;
+  bool                   mRequestingLoad:1;
+  bool                   mTextureManagerAlive:1;
+};
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp
new file mode 100644 (file)
index 0000000..04f0f1d
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2020 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 "rolling-gif-image-cache.h"
+
+// EXTERNAL HEADERS
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+
+#define LOG_CACHE                                                       \
+  {                                                                     \
+    std::ostringstream oss;                                             \
+    oss<<"Size:"<<mQueue.Count()<<" [ ";                                \
+    for(std::size_t _i=0; _i<mQueue.Count(); ++_i)                      \
+    {                                                                   \
+      oss<<_i<<                                                         \
+        "={ frm#: " << mQueue[_i].mFrameNumber <<                        \
+           " tex: " << mImageUrls[mQueue[_i].mFrameNumber].mTextureId<<"}, ";  \
+    }                                                                   \
+    oss<<" ]"<<std::endl;                                               \
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"%s",oss.str().c_str()); \
+  }
+
+#else
+  #define LOG_CACHE
+#endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+RollingGifImageCache::RollingGifImageCache(
+  TextureManager& textureManager, GifLoading& gifLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer,
+  uint16_t cacheSize, uint16_t batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+  mGifLoading( gifLoading ),
+  mFrameCount( frameCount ),
+  mFrameIndex( 0 ),
+  mCacheSize( cacheSize ),
+  mQueue( cacheSize )
+{
+  mImageUrls.resize( mFrameCount );
+  LoadBatch();
+}
+
+RollingGifImageCache::~RollingGifImageCache()
+{
+  if( mTextureManagerAlive )
+  {
+    while( !mQueue.IsEmpty() )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+    }
+  }
+}
+
+TextureSet RollingGifImageCache::Frame( uint32_t frameIndex )
+{
+  // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
+  if( mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID )
+  {
+    mFrameIndex = frameIndex;
+    while( !mQueue.IsEmpty() )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+      mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    }
+    LoadBatch();
+  }
+  // If the frame is already loaded, remove previous frames of the frame in the queue
+  // and load new frames amount of removed frames.
+  else
+  {
+    bool popExist = false;
+    while( !mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+      mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+      popExist = true;
+    }
+    if( popExist )
+    {
+      mFrameIndex = ( mQueue.Back().mFrameNumber + 1 ) % mFrameCount;
+      LoadBatch();
+    }
+  }
+
+  return GetFrontTextureSet();
+}
+
+TextureSet RollingGifImageCache::FirstFrame()
+{
+  return Frame( 0u );
+}
+
+TextureSet RollingGifImageCache::NextFrame()
+{
+  ImageFrame imageFrame = mQueue.PopFront();
+  Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+  mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+
+  LoadBatch();
+
+  return GetFrontTextureSet();
+}
+
+bool RollingGifImageCache::IsFrontReady() const
+{
+  return ( !mQueue.IsEmpty() );
+}
+
+void RollingGifImageCache::LoadBatch()
+{
+  // Try and load up to mBatchSize images, until the cache is filled.
+  // Once the cache is filled, as frames progress, the old frame is
+  // removed, and another frame is loaded
+
+  std::vector<Dali::PixelData> pixelDataList;
+
+  // Get the smallest number of frames we need to load
+  int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() );
+  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d  batchSize:%d\n", mFrameIndex, batchSize );
+
+  if( mGifLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) )
+  {
+    unsigned int pixelDataListCount = pixelDataList.size();
+
+    for( unsigned int i = 0; i < pixelDataListCount && !mQueue.IsFull(); ++i )
+    {
+      ImageFrame imageFrame;
+
+      // create the texture for uploading the pixel data
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                      pixelDataList[i].GetPixelFormat(),
+                                      pixelDataList[i].GetWidth(),
+                                      pixelDataList[i].GetHeight() );
+
+      texture.Upload( pixelDataList[i] );
+
+      mImageUrls[ mUrlIndex ].mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
+      imageFrame.mFrameNumber = mUrlIndex;
+
+      ++mUrlIndex;
+      mUrlIndex %= mImageUrls.size();
+
+      mQueue.PushBack( imageFrame );
+
+      bool synchronousLoading = false;
+      bool atlasingStatus = false;
+      bool loadingStatus = false;
+      TextureManager::MaskingDataPointer maskInfo = nullptr;
+      AtlasUploadObserver* atlasObserver = nullptr;
+      ImageAtlasManagerPtr imageAtlasManager = nullptr;
+      Vector4 textureRect;
+      Dali::ImageDimensions textureRectSize;
+      auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+      mTextureManager.LoadTexture(
+        mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+        SamplingMode::BOX_THEN_LINEAR, maskInfo,
+        synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect, textureRectSize,
+        atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+        Dali::WrapMode::Type::DEFAULT, NULL,
+        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply );
+    }
+
+    mFrameIndex += batchSize;
+    mFrameIndex %= mFrameCount;
+  }
+
+  LOG_CACHE;
+}
+
+TextureSet RollingGifImageCache::GetFrontTextureSet() const
+{
+  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[ 0 ].mFrameNumber );
+
+  TextureManager::TextureId textureId = GetCachedTextureId( 0 );
+  return mTextureManager.GetTextureSet( textureId );
+}
+
+TextureManager::TextureId RollingGifImageCache::GetCachedTextureId( int index ) const
+{
+  return mImageUrls[ mQueue[ index ].mFrameNumber ].mTextureId;
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h
new file mode 100644 (file)
index 0000000..91a1210
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2020 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 <dali/devel-api/adaptor-framework/gif-loading.h>
+#include <dali/devel-api/common/circular-queue.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Class to manage a rolling cache of GIF images, where the cache size
+ * is smaller than the total number of images.
+ *
+ * Frames are always ready, so the observer.FrameReady callback is never triggered;
+ * the FirstFrame and NextFrame APIs will always return a texture.
+ */
+class RollingGifImageCache : public ImageCache
+{
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] gifLoader The loaded gif image
+   * @param[in] frameCount The number of frames in the gif
+   * @param[in] observer FrameReady observer
+   * @param[in] cacheSize The size of the cache
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes.
+   */
+  RollingGifImageCache( TextureManager&                 textureManager,
+                        GifLoading&                     gifLoader,
+                        uint32_t                        frameCount,
+                        ImageCache::FrameReadyObserver& observer,
+                        uint16_t                        cacheSize,
+                        uint16_t                        batchSize );
+
+  /**
+   * Destructor
+   */
+  virtual ~RollingGifImageCache();
+
+  /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet Frame( uint32_t frameIndex ) override;
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet FirstFrame() override;
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  TextureSet NextFrame() override;
+
+private:
+  /**
+   * @return true if the front frame is ready
+   */
+  bool IsFrontReady() const;
+
+  /**
+   * Load the next batch of images
+   */
+  void LoadBatch();
+
+  /**
+   * Get the texture set of the front frame.
+   * @return the texture set
+   */
+  TextureSet GetFrontTextureSet() const;
+
+  /**
+   * Get the texture id of the given index
+   */
+  TextureManager::TextureId GetCachedTextureId( int index ) const;
+
+private:
+  /**
+   * Secondary class to hold readiness and index into url
+   */
+  struct ImageFrame
+  {
+    unsigned int mFrameNumber = 0u;
+  };
+
+  GifLoading&               mGifLoading;
+  uint32_t                  mFrameCount;
+  int                       mFrameIndex;
+  std::vector<UrlStore>     mImageUrls;
+  uint16_t                  mCacheSize;
+  CircularQueue<ImageFrame> mQueue;
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
new file mode 100644 (file)
index 0000000..21f81b7
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL HEADERS
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+
+#define LOG_CACHE                                                       \
+  {                                                                     \
+    std::ostringstream oss;                                             \
+    oss<<"Size:"<<mQueue.Count()<<" [ ";                                \
+    for(std::size_t _i=0; _i<mQueue.Count(); ++_i)                      \
+    {                                                                   \
+      oss<<_i<<                                                         \
+        "={ tex:"<<mImageUrls[mQueue[_i].mUrlIndex].mTextureId<<        \
+        " urlId:"<<mQueue[_i].mUrlIndex<<                               \
+        " rdy:"<<(mQueue[_i].mReady?"T":"F")<< "}, ";                   \
+    }                                                                   \
+    oss<<" ]"<<std::endl;                                               \
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"%s",oss.str().c_str()); \
+  }
+
+#else
+  #define LOG_CACHE
+#endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+RollingImageCache::RollingImageCache(
+  TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
+  uint16_t cacheSize, uint16_t batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
+  mQueue( cacheSize )
+{
+  LoadBatch();
+}
+
+RollingImageCache::~RollingImageCache()
+{
+  if( mTextureManagerAlive )
+  {
+    while( !mQueue.IsEmpty() )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
+    }
+  }
+}
+
+TextureSet RollingImageCache::Frame( uint32_t frameIndex )
+{
+  // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures.
+  if( mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID )
+  {
+    mUrlIndex = frameIndex;
+    while( !mQueue.IsEmpty() )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
+      mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+    }
+    LoadBatch();
+  }
+  // If the frame is already loaded, remove previous frames of the frame in the queue
+  // and load new frames amount of removed frames.
+  else
+  {
+    bool popExist = false;
+    while( !mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex )
+    {
+      ImageFrame imageFrame = mQueue.PopFront();
+      mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
+      mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+      popExist = true;
+    }
+    if( popExist )
+    {
+      mUrlIndex = ( mQueue.Back().mUrlIndex + 1 ) % mImageUrls.size();
+      LoadBatch();
+    }
+  }
+
+  TextureSet textureSet;
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
+  {
+    mWaitingForReadyFrame = true;
+  }
+
+  return textureSet;
+}
+
+TextureSet RollingImageCache::FirstFrame()
+{
+  return Frame( 0u );
+}
+
+TextureSet RollingImageCache::NextFrame()
+{
+  TextureSet textureSet;
+
+  ImageFrame imageFrame = mQueue.PopFront();
+  mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this );
+  mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID;
+
+  LoadBatch();
+
+  if( IsFrontReady() == true )
+  {
+    textureSet = GetFrontTextureSet();
+  }
+  else
+  {
+    mWaitingForReadyFrame = true;
+  }
+
+  return textureSet;
+}
+
+bool RollingImageCache::IsFrontReady() const
+{
+  return ( !mQueue.IsEmpty() && mQueue.Front().mReady );
+}
+
+void RollingImageCache::LoadBatch()
+{
+  // Try and load up to mBatchSize images, until the cache is filled.
+  // Once the cache is filled, as frames progress, the old frame is
+  // cleared, but not erased, and another image is loaded
+  bool frontFrameReady = IsFrontReady();
+
+  for( unsigned int i=0; i< mBatchSize && !mQueue.IsFull(); ++i )
+  {
+    ImageFrame imageFrame;
+
+    std::string& url = mImageUrls[ mUrlIndex ].mUrl;
+    imageFrame.mUrlIndex = mUrlIndex;
+    imageFrame.mReady = false;
+
+    ++mUrlIndex;
+    mUrlIndex %= mImageUrls.size();
+
+    mQueue.PushBack( imageFrame );
+
+    // Note, if the image is already loaded, then UploadComplete will get called
+    // from within this method. This means it won't yet have a texture id, so we
+    // need to account for this inside the UploadComplete method using mRequestingLoad.
+    mRequestingLoad = true;
+
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+    Dali::ImageDimensions textureRectSize;
+    auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ imageFrame.mUrlIndex ].mTextureId, textureRect, textureRectSize,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED,
+      preMultiply );
+
+    mRequestingLoad = false;
+  }
+
+  CheckFrontFrame( frontFrameReady );
+}
+
+void RollingImageCache::SetImageFrameReady( TextureManager::TextureId textureId )
+{
+  for( std::size_t i = 0; i < mQueue.Count() ; ++i )
+  {
+    if( GetCachedTextureId(i) == textureId )
+    {
+      mQueue[i].mReady = true;
+      break;
+    }
+  }
+}
+
+TextureSet RollingImageCache::GetFrontTextureSet() const
+{
+  TextureManager::TextureId textureId = GetCachedTextureId( 0 );
+  return mTextureManager.GetTextureSet( textureId );
+}
+
+TextureManager::TextureId RollingImageCache::GetCachedTextureId( int index ) const
+{
+  return mImageUrls[ mQueue[ index ].mUrlIndex ].mTextureId;
+}
+
+void RollingImageCache::CheckFrontFrame( bool wasReady )
+{
+  if( mWaitingForReadyFrame && wasReady == false && IsFrontReady() )
+  {
+    mWaitingForReadyFrame = false;
+    mObserver.FrameReady( GetFrontTextureSet() );
+  }
+}
+
+void RollingImageCache::UploadComplete(
+  bool           loadSuccess,
+  int32_t        textureId,
+  TextureSet     textureSet,
+  bool           useAtlasing,
+  const Vector4& atlasRect,
+  bool           preMultiplied )
+{
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::UploadComplete(textureId:%d) start\n", textureId);
+  LOG_CACHE;
+
+  bool frontFrameReady = IsFrontReady();
+
+  if( ! mRequestingLoad )
+  {
+    SetImageFrameReady( textureId );
+
+    CheckFrontFrame( frontFrameReady );
+  }
+  else
+  {
+    // UploadComplete has been called from within RequestLoad. TextureManager must
+    // therefore already have the texture cached, so make the texture ready.
+    // (Use the last texture, as the texture id hasn't been assigned yet)
+    mQueue.Back().mReady = true;
+  }
+
+  LOG_CACHE;
+}
+
+void RollingImageCache::LoadComplete(
+  bool loadSuccess,
+  Devel::PixelBuffer pixelBuffer,
+  const VisualUrl& url,
+  bool preMultiplied )
+{
+  // LoadComplete is called if this TextureUploadObserver requested to load
+  // an image that will be returned as a type of PixelBuffer by using a method
+  // TextureManager::LoadPixelBuffer.
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
new file mode 100644 (file)
index 0000000..47a5155
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ROLLING_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_ROLLING_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2020 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 <dali/devel-api/common/circular-queue.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Class to manage a rolling cache of images, where the cache size
+ * is smaller than the total number of images.
+ */
+class RollingImageCache : public ImageCache, public TextureUploadObserver
+{
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] urlList List of urls to cache
+   * @param[in] observer FrameReady observer
+   * @param[in] cacheSize The size of the cache
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes.
+   */
+  RollingImageCache( TextureManager&                 textureManager,
+                     UrlList&                        urlList,
+                     ImageCache::FrameReadyObserver& observer,
+                     uint16_t                        cacheSize,
+                     uint16_t                        batchSize );
+
+  /**
+   * Destructor
+   */
+  virtual ~RollingImageCache();
+
+  /**
+   * Get the Nth frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet Frame( uint32_t frameIndex ) override;
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  TextureSet FirstFrame() override;
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  TextureSet NextFrame() override;
+
+private:
+  /**
+   * @return true if the front frame is ready
+   */
+  bool IsFrontReady() const;
+
+  /**
+   * Load the next batch of images
+   */
+  void LoadBatch();
+
+  /**
+   * Find the matching image frame, and set it to ready
+   */
+  void SetImageFrameReady( TextureManager::TextureId textureId );
+
+  /**
+   * Get the texture set of the front frame.
+   * @return the texture set
+   */
+  TextureSet GetFrontTextureSet() const;
+
+  /**
+   * Get the texture id of the given index
+   */
+  TextureManager::TextureId GetCachedTextureId( int index ) const;
+
+  /**
+   * Check if the front frame has become ready - if so, inform observer
+   * @param[in] wasReady Readiness before call.
+   */
+  void CheckFrontFrame( bool wasReady );
+
+protected:
+  void UploadComplete(
+    bool           loadSuccess,
+    int32_t        textureId,
+    TextureSet     textureSet,
+    bool           useAtlasing,
+    const Vector4& atlasRect,
+    bool           preMultiplied ) override;
+
+  void LoadComplete(
+    bool loadSuccess,
+    Devel::PixelBuffer pixelBuffer,
+    const VisualUrl& url,
+    bool preMultiplied ) override;
+
+private:
+  /**
+   * Secondary class to hold readiness and index into url
+   */
+  struct ImageFrame
+  {
+    unsigned int mUrlIndex = 0u;
+    bool mReady = false;
+  };
+
+  std::vector<UrlStore>& mImageUrls;
+  CircularQueue<ImageFrame> mQueue;
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp b/dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
new file mode 100644 (file)
index 0000000..9b3fb7e
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-signals-devel.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+constexpr auto LOOP_FOREVER = -1;
+
+const Dali::Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
+
+// Flags for re-sending data to the rasterize thread
+enum Flags
+{
+  RESEND_PLAY_RANGE    = 1 << 0,
+  RESEND_LOOP_COUNT    = 1 << 1,
+  RESEND_STOP_BEHAVIOR = 1 << 2,
+  RESEND_LOOPING_MODE  = 1 << 3
+};
+
+// stop behavior
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STOP_BEHAVIOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME )
+DALI_ENUM_TO_STRING_TABLE_END( STOP_BEHAVIOR )
+
+// looping mode
+DALI_ENUM_TO_STRING_TABLE_BEGIN( LOOPING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::LoopingMode, RESTART )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::LoopingMode, AUTO_REVERSE )
+DALI_ENUM_TO_STRING_TABLE_END( LOOPING_MODE )
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
+#endif
+
+} // unnamed namespace
+
+AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
+{
+  AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
+  visual->SetProperties( properties );
+
+  return visual;
+}
+
+AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
+{
+  AnimatedVectorImageVisualPtr visual( new AnimatedVectorImageVisual( factoryCache, shaderFactory, imageUrl ) );
+
+  return visual;
+}
+
+AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mUrl( imageUrl ),
+  mVectorAnimationTask( new VectorAnimationTask( factoryCache, imageUrl.GetUrl() ) ),
+  mImageVisualShaderFactory( shaderFactory ),
+  mVisualSize(),
+  mVisualScale( Vector2::ONE ),
+  mPlayRange(),
+  mPlacementActor(),
+  mLoopCount( LOOP_FOREVER ),
+  mResendFlag( 0 ),
+  mActionStatus( DevelAnimatedVectorImageVisual::Action::STOP ),
+  mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
+  mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
+  mRendererAdded( false )
+{
+  // the rasterized image is with pre-multiplied alpha format
+  mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+
+  mVectorAnimationTask->UploadCompletedSignal().Connect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
+  mVectorAnimationTask->SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
+}
+
+AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
+{
+  // Finalize animation task in the main thread
+  mVectorAnimationTask->Finalize();
+}
+
+void AnimatedVectorImageVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( mVisualSize != Vector2::ZERO )
+  {
+    naturalSize = mVisualSize;
+  }
+  else
+  {
+    uint32_t width, height;
+    mVectorAnimationTask->GetDefaultSize( width, height );
+    naturalSize.x = width;
+    naturalSize.y = height;
+  }
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::GetNaturalSize: w = %f, h = %f [%p]\n", naturalSize.width, naturalSize.height, this );
+}
+
+void AnimatedVectorImageVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE );
+  if( mUrl.IsValid() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::URL, mUrl.GetUrl() );
+  }
+  map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, mLoopCount );
+
+  uint32_t startFrame, endFrame;
+  mVectorAnimationTask->GetPlayRange( startFrame, endFrame );
+
+  Property::Array playRange;
+  playRange.PushBack( static_cast< int32_t >( startFrame ) );
+  playRange.PushBack( static_cast< int32_t >( endFrame ) );
+  map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, playRange );
+
+  map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int32_t >( mVectorAnimationTask->GetPlayState() ) );
+  map.Insert( Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, static_cast< int32_t >( mVectorAnimationTask->GetCurrentFrameNumber() ) );
+  map.Insert( Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast< int32_t >( mVectorAnimationTask->GetTotalFrameNumber() ) );
+
+  map.Insert( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior );
+  map.Insert( Toolkit::DevelImageVisual::Property::LOOPING_MODE, mLoopingMode );
+
+  Property::Map layerInfo;
+  mVectorAnimationTask->GetLayerInfo( layerInfo );
+  map.Insert( Toolkit::DevelImageVisual::Property::CONTENT_INFO, layerInfo );
+}
+
+void AnimatedVectorImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void AnimatedVectorImageVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // url already passed in from constructor
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else
+    {
+       if( keyValue.first == LOOP_COUNT_NAME )
+       {
+          DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second );
+       }
+       else if( keyValue.first == PLAY_RANGE_NAME )
+       {
+          DoSetProperty( Toolkit::DevelImageVisual::Property::PLAY_RANGE, keyValue.second );
+       }
+       else if( keyValue.first == STOP_BEHAVIOR_NAME )
+       {
+          DoSetProperty( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second );
+       }
+       else if( keyValue.first == LOOPING_MODE_NAME )
+       {
+          DoSetProperty( Toolkit::DevelImageVisual::Property::LOOPING_MODE, keyValue.second );
+       }
+    }
+  }
+}
+
+void AnimatedVectorImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
+{
+  switch(index)
+  {
+    case Toolkit::DevelImageVisual::Property::LOOP_COUNT:
+    {
+      int32_t loopCount;
+      if( value.Get( loopCount ) )
+      {
+        mLoopCount = loopCount;
+        mResendFlag |= RESEND_LOOP_COUNT;
+      }
+      break;
+    }
+    case Toolkit::DevelImageVisual::Property::PLAY_RANGE:
+    {
+      Property::Array* array = value.GetArray();
+      if( array )
+      {
+        mPlayRange = *array;
+        mResendFlag |= RESEND_PLAY_RANGE;
+      }
+      break;
+    }
+    case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR:
+    {
+      int32_t stopBehavior = mStopBehavior;
+      if( Scripting::GetEnumerationProperty( value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior ) )
+      {
+        mStopBehavior = DevelImageVisual::StopBehavior::Type( stopBehavior );
+        mResendFlag |= RESEND_STOP_BEHAVIOR;
+      }
+      break;
+    }
+    case Toolkit::DevelImageVisual::Property::LOOPING_MODE:
+    {
+      int32_t loopingMode = mLoopingMode;
+      if( Scripting::GetEnumerationProperty( value, LOOPING_MODE_TABLE, LOOPING_MODE_TABLE_COUNT, loopingMode ) )
+      {
+        mLoopingMode = DevelImageVisual::LoopingMode::Type( loopingMode );
+        mResendFlag |= RESEND_LOOPING_MODE;
+      }
+      break;
+    }
+  }
+}
+
+void AnimatedVectorImageVisual::DoSetOnStage( Actor& actor )
+{
+  Shader shader;
+
+  if( mImpl->mCustomShader )
+  {
+    shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
+                          mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
+                          mImpl->mCustomShader->mHints );
+
+    shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+  }
+  else
+  {
+    shader = mImageVisualShaderFactory.GetShader( mFactoryCache, false, true, false );
+  }
+
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  TextureSet textureSet = TextureSet::New();
+  mImpl->mRenderer.SetTextures( textureSet );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
+
+  // Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
+  mPlacementActor = actor;
+
+  mVectorAnimationTask->SetRenderer( mImpl->mRenderer );
+
+  // Add property notification for scaling & size
+  mScaleNotification = actor.AddPropertyNotification( Actor::Property::WORLD_SCALE, StepCondition( 0.1f, 1.0f ) );
+  mScaleNotification.NotifySignal().Connect( this, &AnimatedVectorImageVisual::OnScaleNotification );
+
+  mSizeNotification = actor.AddPropertyNotification( Actor::Property::SIZE, StepCondition( 3.0f ) );
+  mSizeNotification.NotifySignal().Connect( this, &AnimatedVectorImageVisual::OnSizeNotification );
+
+  DevelActor::VisibilityChangedSignal( actor ).Connect( this, &AnimatedVectorImageVisual::OnControlVisibilityChanged );
+
+  Window window = DevelWindow::Get( actor );
+  if( window )
+  {
+    DevelWindow::VisibilityChangedSignal( window ).Connect( this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged );
+  }
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::DoSetOnStage [%p]\n", this );
+}
+
+void AnimatedVectorImageVisual::DoSetOffStage( Actor& actor )
+{
+  StopAnimation();
+
+  if( mImpl->mRenderer )
+  {
+    actor.RemoveRenderer( mImpl->mRenderer );
+    mImpl->mRenderer.Reset();
+
+    mRendererAdded = false;
+  }
+
+  // Remove property notification
+  actor.RemovePropertyNotification( mScaleNotification );
+  actor.RemovePropertyNotification( mSizeNotification );
+
+  DevelActor::VisibilityChangedSignal( actor ).Disconnect( this, &AnimatedVectorImageVisual::OnControlVisibilityChanged );
+
+  Window window = DevelWindow::Get( actor );
+  if( window )
+  {
+    DevelWindow::VisibilityChangedSignal( window ).Disconnect( this, &AnimatedVectorImageVisual::OnWindowVisibilityChanged );
+  }
+
+  mPlacementActor.Reset();
+
+  // Reset the visual size to zero so that when adding the actor back to stage the rasterization is forced
+  mVisualSize = Vector2::ZERO;
+  mVisualScale = Vector2::ONE;
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::DoSetOffStage [%p]\n", this );
+}
+
+void AnimatedVectorImageVisual::OnSetTransform()
+{
+  Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
+
+  if( IsOnStage() && visualSize != mVisualSize )
+  {
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnSetTransform: width = %f, height = %f [%p]\n", visualSize.width, visualSize.height, this );
+
+    mVisualSize = visualSize;
+
+    SetVectorImageSize();
+
+    SendAnimationData();
+
+    if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
+    {
+      mVectorAnimationTask->PlayAnimation();
+
+      mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
+    }
+    else
+    {
+      // Render one frame
+      mVectorAnimationTask->RenderFrame();
+    }
+  }
+}
+
+void AnimatedVectorImageVisual::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
+{
+  // Check if action is valid for this visual type and perform action if possible
+  switch( actionId )
+  {
+    case DevelAnimatedVectorImageVisual::Action::PLAY:
+    {
+      if( IsOnStage() && mVisualSize != Vector2::ZERO )
+      {
+        mVectorAnimationTask->PlayAnimation();
+
+        mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
+      }
+      mActionStatus = DevelAnimatedVectorImageVisual::Action::PLAY;
+      break;
+    }
+    case DevelAnimatedVectorImageVisual::Action::PAUSE:
+    {
+      mVectorAnimationTask->PauseAnimation();
+
+      if( mImpl->mRenderer )
+      {
+        mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
+      }
+
+      mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
+      break;
+    }
+    case DevelAnimatedVectorImageVisual::Action::STOP:
+    {
+      if( mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::STOPPED )
+      {
+        mVectorAnimationTask->StopAnimation();
+      }
+
+      if( mImpl->mRenderer )
+      {
+        mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
+      }
+
+      mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
+      break;
+    }
+    case DevelAnimatedVectorImageVisual::Action::JUMP_TO:
+    {
+      int32_t frameNumber;
+      if( attributes.Get( frameNumber ) )
+      {
+        mVectorAnimationTask->SetCurrentFrameNumber( frameNumber );
+
+        if( IsOnStage() && mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::PLAYING )
+        {
+          mVectorAnimationTask->RenderFrame();
+          Stage::GetCurrent().KeepRendering( 0.0f );    // Trigger rendering
+        }
+      }
+      break;
+    }
+    case DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY:
+    {
+      Property::Map* map = attributes.GetMap();
+      if( map )
+      {
+        DoSetProperties( *map );
+
+        SendAnimationData();
+      }
+      break;
+    }
+  }
+}
+
+void AnimatedVectorImageVisual::OnUploadCompleted()
+{
+  // If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor && !mRendererAdded )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+    mRendererAdded = true;
+
+    ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnUploadCompleted: Renderer is added [%p]\n", this );
+  }
+}
+
+void AnimatedVectorImageVisual::OnAnimationFinished()
+{
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnAnimationFinished: action state = %d [%p]\n", mActionStatus, this );
+
+  if( mActionStatus != DevelAnimatedVectorImageVisual::Action::STOP )
+  {
+    mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
+
+    if( mImpl->mEventObserver )
+    {
+      mImpl->mEventObserver->NotifyVisualEvent( *this, DevelAnimatedVectorImageVisual::Signal::ANIMATION_FINISHED );
+    }
+  }
+
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
+  }
+}
+
+void AnimatedVectorImageVisual::SendAnimationData()
+{
+  if( mResendFlag )
+  {
+    bool isPlaying = false;
+    if( mVectorAnimationTask->GetPlayState() == DevelImageVisual::PlayState::PLAYING )
+    {
+      mVectorAnimationTask->PauseAnimation();
+      isPlaying = true;
+    }
+
+    if( mResendFlag & RESEND_LOOP_COUNT )
+    {
+      mVectorAnimationTask->SetLoopCount( mLoopCount );
+    }
+
+    if( mResendFlag & RESEND_PLAY_RANGE )
+    {
+      mVectorAnimationTask->SetPlayRange( mPlayRange );
+    }
+
+    if( mResendFlag & RESEND_STOP_BEHAVIOR )
+    {
+      mVectorAnimationTask->SetStopBehavior( mStopBehavior );
+    }
+
+    if( mResendFlag & RESEND_LOOPING_MODE )
+    {
+      mVectorAnimationTask->SetLoopingMode( mLoopingMode );
+    }
+
+    if( IsOnStage() )
+    {
+      if( isPlaying )
+      {
+        mVectorAnimationTask->PlayAnimation();
+      }
+      else
+      {
+        mVectorAnimationTask->RenderFrame();
+        Stage::GetCurrent().KeepRendering( 0.0f );
+      }
+    }
+
+    mResendFlag = 0;
+  }
+}
+
+void AnimatedVectorImageVisual::SetVectorImageSize()
+{
+  uint32_t width = static_cast< uint32_t >( mVisualSize.width * mVisualScale.width );
+  uint32_t height = static_cast< uint32_t >( mVisualSize.height * mVisualScale.height );
+
+  mVectorAnimationTask->SetSize( width, height );
+
+  if( IsOnStage() && mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::PLAYING )
+  {
+    mVectorAnimationTask->RenderFrame();
+    Stage::GetCurrent().KeepRendering( 0.0f );    // Trigger rendering
+  }
+}
+
+void AnimatedVectorImageVisual::StopAnimation()
+{
+  if( mActionStatus != DevelAnimatedVectorImageVisual::Action::STOP )
+  {
+    mVectorAnimationTask->StopAnimation();
+
+    mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
+
+    if( mImpl->mRenderer )
+    {
+      mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED );
+    }
+  }
+}
+
+void AnimatedVectorImageVisual::OnScaleNotification( PropertyNotification& source )
+{
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor )
+  {
+    Vector3 scale = actor.GetProperty< Vector3 >( Actor::Property::WORLD_SCALE );
+    mVisualScale.width = scale.width;
+    mVisualScale.height = scale.height;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnScaleNotification: scale = %f, %f [%p]\n", mVisualScale.width, mVisualScale.height, this );
+
+    SetVectorImageSize();
+  }
+}
+
+void AnimatedVectorImageVisual::OnSizeNotification( PropertyNotification& source )
+{
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor )
+  {
+    Vector3 size = actor.GetCurrentSize();
+    mVisualSize.width = size.width;
+    mVisualSize.height = size.height;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnSizeNotification: size = %f, %f [%p]\n", mVisualSize.width, mVisualSize.height, this );
+
+    SetVectorImageSize();
+  }
+}
+
+void AnimatedVectorImageVisual::OnControlVisibilityChanged( Actor actor, bool visible, DevelActor::VisibilityChange::Type type )
+{
+  if( !visible )
+  {
+    StopAnimation();
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnControlVisibilityChanged: invisibile. Pause animation [%p]\n", this );
+  }
+}
+
+void AnimatedVectorImageVisual::OnWindowVisibilityChanged( Window window, bool visible )
+{
+  if( !visible )
+  {
+    StopAnimation();
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "AnimatedVectorImageVisual::OnWindowVisibilityChanged: invisibile. Pause animation [%p]\n", this );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h b/dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h
new file mode 100644 (file)
index 0000000..8aaed9c
--- /dev/null
@@ -0,0 +1,225 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ANIMATED_VECTOR_IMAGE_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_ANIMATED_VECTOR_IMAGE_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/weak-handle.h>
+#include <dali/public-api/object/property-notification.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/public-api/adaptor-framework/window.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ImageVisualShaderFactory;
+class AnimatedVectorImageVisual;
+using AnimatedVectorImageVisualPtr = IntrusivePtr< AnimatedVectorImageVisual >;
+
+/**
+ * The visual which renders an animated vector image using VectorAnimationRenderer.
+ * VectorAnimationRenderer renders the animation image and this visuall controls the images.
+ *
+ * The following property is essential
+ *
+ * | %Property Name           | Type             |
+ * |--------------------------|------------------|
+ * | url                      | STRING           |
+ *
+ */
+class AnimatedVectorImageVisual: public Visual::Base, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Create the AnimatedVectorImageVisual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to an animated vector image to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static AnimatedVectorImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties );
+
+  /**
+   * @brief Create the AnimatedVectorImageVisual using the image URL.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to an animated vector image to use
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static AnimatedVectorImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to an animated vector image to use
+   */
+  AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~AnimatedVectorImageVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::OnDoAction
+   */
+  void OnDoAction( const Property::Index actionId, const Property::Value& attributes ) override;
+
+private:
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+  /**
+   * @brief Called when the texture upload is completed.
+   */
+  void OnUploadCompleted();
+
+  /**
+   * @brief Event callback from rasterize thread. This is called after the animation is finished.
+   */
+  void OnAnimationFinished();
+
+  /**
+   * @brief Send animation data to the rasterize thread.
+   */
+  void SendAnimationData();
+
+  /**
+   * @brief Set the vector image size.
+   */
+  void SetVectorImageSize();
+
+  /**
+   * @brief Stop the animation.
+   */
+  void StopAnimation();
+
+  /**
+   * @brief Callback when the world scale factor changes.
+   */
+  void OnScaleNotification( PropertyNotification& source );
+
+  /**
+   * @brief Callback when the size changes.
+   */
+  void OnSizeNotification( PropertyNotification& source );
+
+  /**
+   * @brief Callback when the visibility of the actor is changed.
+   */
+  void OnControlVisibilityChanged( Actor actor, bool visible, DevelActor::VisibilityChange::Type type );
+
+  /**
+   * @brief Callback when the visibility of the window is changed.
+   */
+  void OnWindowVisibilityChanged( Window window, bool visible );
+
+  // Undefined
+  AnimatedVectorImageVisual( const AnimatedVectorImageVisual& visual ) = delete;
+
+  // Undefined
+  AnimatedVectorImageVisual& operator=( const AnimatedVectorImageVisual& visual ) = delete;
+
+private:
+  VisualUrl                                    mUrl;
+  VectorAnimationTaskPtr                       mVectorAnimationTask;
+  ImageVisualShaderFactory&                    mImageVisualShaderFactory;
+  PropertyNotification                         mScaleNotification;
+  PropertyNotification                         mSizeNotification;
+  Vector2                                      mVisualSize;
+  Vector2                                      mVisualScale;
+  Property::Array                              mPlayRange;
+  WeakHandle< Actor >                          mPlacementActor;
+  int32_t                                      mLoopCount;
+  uint32_t                                     mResendFlag;
+  DevelAnimatedVectorImageVisual::Action::Type mActionStatus;
+  DevelImageVisual::StopBehavior::Type         mStopBehavior;
+  DevelImageVisual::LoopingMode::Type          mLoopingMode;
+  bool                                         mRendererAdded;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_ANIMATED_VECTOR_IMAGE_VISUAL_H
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
new file mode 100644 (file)
index 0000000..ae66146
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/math/math-utils.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+constexpr auto LOOP_FOREVER = -1;
+constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
+#endif
+
+template< typename T >
+inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
+{
+  ConditionalWait::ScopedLock lock( conditionalWait );
+  if( !updated )
+  {
+    value = newValue;
+    updated = true;
+  }
+}
+
+} // unnamed namespace
+
+VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
+: mUrl( url ),
+  mVectorRenderer(),
+  mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
+  mConditionalWait(),
+  mAnimationFinishedTrigger(),
+  mPlayState( PlayState::STOPPED ),
+  mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
+  mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
+  mNextFrameStartTime(),
+  mFrameDurationNanoSeconds( 0 ),
+  mFrameRate( 60.0f ),
+  mCurrentFrame( 0 ),
+  mTotalFrame( 0 ),
+  mStartFrame( 0 ),
+  mEndFrame( 0 ),
+  mWidth( 0 ),
+  mHeight( 0 ),
+  mLoopCount( LOOP_FOREVER ),
+  mCurrentLoop( 0 ),
+  mResourceReady( false ),
+  mCurrentFrameUpdated( false ),
+  mCurrentLoopUpdated( false ),
+  mForward( true ),
+  mUpdateFrameNumber( false ),
+  mNeedAnimationFinishedTrigger( true )
+{
+  Initialize();
+}
+
+VectorAnimationTask::~VectorAnimationTask()
+{
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
+}
+
+void VectorAnimationTask::Finalize()
+{
+  // Release some objects in the main thread
+  if( mAnimationFinishedTrigger )
+  {
+    mAnimationFinishedTrigger.reset();
+  }
+
+  mVectorRenderer.Finalize();
+}
+
+void VectorAnimationTask::SetRenderer( Renderer renderer )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  mVectorRenderer.SetRenderer( renderer );
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
+}
+
+void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
+{
+  if( mWidth != width || mHeight != height )
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    mVectorRenderer.SetSize( width, height );
+
+    mWidth = width;
+    mHeight = height;
+
+    mResourceReady = false;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
+  }
+}
+
+void VectorAnimationTask::PlayAnimation()
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( mPlayState != PlayState::PLAYING )
+  {
+    mUpdateFrameNumber = false;
+    mPlayState = PlayState::PLAYING;
+
+    mVectorAnimationThread.AddTask( this );
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
+  }
+}
+
+void VectorAnimationTask::StopAnimation()
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
+  {
+    mNeedAnimationFinishedTrigger = false;
+    mPlayState = PlayState::STOPPING;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
+  }
+}
+
+void VectorAnimationTask::PauseAnimation()
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  if( mPlayState == PlayState::PLAYING )
+  {
+    mPlayState = PlayState::PAUSED;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
+  }
+}
+
+void VectorAnimationTask::RenderFrame()
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( !mResourceReady )
+  {
+    mVectorAnimationThread.AddTask( this );
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
+  }
+}
+
+void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  if( callback )
+  {
+    mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
+  }
+}
+
+void VectorAnimationTask::SetLoopCount( int32_t count )
+{
+  if( mLoopCount != count )
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+
+    mLoopCount = count;
+    mCurrentLoop = 0;
+    mCurrentLoopUpdated = true;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
+  }
+}
+
+void VectorAnimationTask::SetPlayRange( Property::Array& playRange )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  bool valid = false;
+  uint32_t startFrame = 0, endFrame = 0;
+  size_t count = playRange.Count();
+
+  if( count >= 2 )
+  {
+    int32_t start = 0, end = 0;
+    if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
+    {
+      startFrame = static_cast< uint32_t >( start );
+      endFrame = static_cast< uint32_t >( end );
+      valid = true;
+    }
+    else
+    {
+      std::string startMarker, endMarker;
+      if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
+      {
+        if( mVectorRenderer )
+        {
+          uint32_t frame;   // We don't use this later
+          if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
+          {
+            valid = true;
+          }
+        }
+      }
+    }
+  }
+  else if( count == 1 )
+  {
+    std::string marker;
+    if( playRange.GetElementAt( 0 ).Get( marker ) )
+    {
+      if( mVectorRenderer )
+      {
+        mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
+        valid = true;
+      }
+    }
+  }
+
+  if( !valid )
+  {
+    DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
+    return;
+  }
+
+  // Make sure the range specified is between 0 and the total frame number
+  if( startFrame < mTotalFrame && endFrame < mTotalFrame )
+  {
+    // If the range is not in order swap values
+    if( startFrame > endFrame )
+    {
+      uint32_t temp = startFrame;
+      startFrame = endFrame;
+      endFrame = temp;
+    }
+
+    if( startFrame != mStartFrame || endFrame != mEndFrame )
+    {
+      mStartFrame = startFrame;
+      mEndFrame = endFrame;
+
+      // If the current frame is out of the range, change the current frame also.
+      if( mStartFrame > mCurrentFrame )
+      {
+        mCurrentFrame = mStartFrame;
+
+        mCurrentFrameUpdated = true;
+        mResourceReady = false;
+      }
+      else if( mEndFrame < mCurrentFrame )
+      {
+        mCurrentFrame = mEndFrame;
+
+        mCurrentFrameUpdated = true;
+        mResourceReady = false;
+      }
+
+      DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
+    return;
+  }
+}
+
+void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
+{
+  startFrame = mStartFrame;
+  endFrame = mEndFrame;
+}
+
+DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
+{
+  DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
+
+  switch( mPlayState )
+  {
+    case PlayState::PLAYING:
+    {
+      state = DevelImageVisual::PlayState::PLAYING;
+      break;
+    }
+    case PlayState::PAUSED:
+    {
+      state = DevelImageVisual::PlayState::PAUSED;
+      break;
+    }
+    case PlayState::STOPPING:
+    case PlayState::STOPPED:
+    {
+      state = DevelImageVisual::PlayState::STOPPED;
+      break;
+    }
+  }
+
+  return state;
+}
+
+void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( mCurrentFrame == frameNumber )
+  {
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
+    return;
+  }
+
+  if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
+  {
+    mCurrentFrame = frameNumber;
+    mCurrentFrameUpdated = true;
+
+    mUpdateFrameNumber = false;
+    mResourceReady = false;
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
+  }
+}
+
+uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
+{
+  return mCurrentFrame;
+}
+
+uint32_t VectorAnimationTask::GetTotalFrameNumber() const
+{
+  return mTotalFrame;
+}
+
+void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+  mVectorRenderer.GetDefaultSize( width, height );
+}
+
+void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  mStopBehavior = stopBehavior;
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
+}
+
+void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  mLoopingMode = loopingMode;
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
+}
+
+void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
+{
+  mVectorRenderer.GetLayerInfo( map );
+}
+
+VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
+{
+  return mVectorRenderer.UploadCompletedSignal();
+}
+
+void VectorAnimationTask::Initialize()
+{
+  mVectorRenderer = VectorAnimationRenderer::New( mUrl );
+
+  mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
+
+  mEndFrame = mTotalFrame - 1;
+
+  mFrameRate = mVectorRenderer.GetFrameRate();
+  mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
+
+  uint32_t width, height;
+  mVectorRenderer.GetDefaultSize( width, height );
+
+  SetSize( width, height );
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
+}
+
+bool VectorAnimationTask::Rasterize()
+{
+  bool stopped = false, needAnimationFinishedTrigger;
+  uint32_t currentFrame, startFrame, endFrame;
+  int32_t loopCount, currentLoopCount;
+  PlayState playState;
+
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+
+    if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
+    {
+      mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
+      Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
+    }
+
+    currentFrame = mCurrentFrame;
+    startFrame = mStartFrame;
+    endFrame = mEndFrame;
+    loopCount = mLoopCount;
+    currentLoopCount = mCurrentLoop;
+    needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
+    playState = mPlayState;
+
+    mResourceReady = true;
+    mCurrentFrameUpdated = false;
+    mCurrentLoopUpdated = false;
+    mUpdateFrameNumber = true;
+    mNeedAnimationFinishedTrigger = true;
+  }
+
+  if( playState == PlayState::STOPPING )
+  {
+    currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
+    ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
+
+    stopped = true;
+  }
+  else if( playState == PlayState::PLAYING )
+  {
+    bool animationFinished = false;
+
+    if( currentFrame >= endFrame )  // last frame
+    {
+      if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
+      {
+        mForward = false;
+      }
+      else
+      {
+        if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
+        {
+          ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
+          mUpdateFrameNumber = false;
+        }
+        else
+        {
+          animationFinished = true;   // end of animation
+        }
+        ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
+      }
+    }
+    else if( currentFrame == startFrame && !mForward )  // first frame
+    {
+      if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
+      {
+        mForward = true;
+      }
+      else
+      {
+        animationFinished = true;   // end of animation
+      }
+      ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
+    }
+
+    if( animationFinished )
+    {
+      if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
+      {
+        stopped = true;
+      }
+      else
+      {
+        mPlayState = PlayState::STOPPING;
+      }
+    }
+  }
+
+  // Rasterize
+  bool renderSuccess = false;
+  if( mVectorRenderer )
+  {
+    renderSuccess = mVectorRenderer.Render( currentFrame );
+    if( !renderSuccess )
+    {
+      DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
+      mUpdateFrameNumber = false;
+    }
+  }
+
+  if( stopped && renderSuccess )
+  {
+    mPlayState = PlayState::STOPPED;
+    mForward = true;
+    mCurrentLoop = 0;
+
+    // Animation is finished
+    if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
+    {
+      mAnimationFinishedTrigger->Trigger();
+    }
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
+  }
+
+  bool keepAnimation = true;
+  if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
+  {
+    keepAnimation = false;
+  }
+
+  return keepAnimation;
+}
+
+uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
+{
+  uint32_t frame = currentFrame;
+
+  switch( mStopBehavior )
+  {
+    case DevelImageVisual::StopBehavior::FIRST_FRAME:
+    {
+      frame = startFrame;
+      break;
+    }
+    case DevelImageVisual::StopBehavior::LAST_FRAME:
+    {
+      if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
+      {
+        frame = startFrame;
+      }
+      else
+      {
+        frame = endFrame;
+      }
+      break;
+    }
+    case DevelImageVisual::StopBehavior::CURRENT_FRAME:
+    {
+      frame = currentFrame;
+      break;
+    }
+  }
+
+  return frame;
+}
+
+std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
+{
+  // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
+  // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
+  // is casted to use the default duration.
+  mNextFrameStartTime =  std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
+      mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
+  auto current = std::chrono::system_clock::now();
+  if( renderNow || mNextFrameStartTime < current )
+  {
+    mNextFrameStartTime = current;
+  }
+  return mNextFrameStartTime;
+}
+
+std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
+{
+  return mNextFrameStartTime;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
new file mode 100644 (file)
index 0000000..f2e3042
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
+#define DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <memory>
+#include <chrono>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class VisualFactoryCache;
+class VectorAnimationThread;
+class VectorAnimationTask;
+typedef IntrusivePtr< VectorAnimationTask > VectorAnimationTaskPtr;
+
+/**
+ * The task of the vector animation.
+ */
+class VectorAnimationTask : public RefObject
+{
+public:
+
+  using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] url The url of the vector animation file
+   */
+  VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url );
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~VectorAnimationTask();
+
+  /**
+   * @brief Finalizes the task.
+   */
+  void Finalize();
+
+  /**
+   * @brief Sets the renderer used to display the result image.
+   *
+   * @param[in] renderer The renderer used to display the result image
+   */
+  void SetRenderer( Renderer renderer );
+
+  /**
+   * @brief Sets the target image size.
+   *
+   * @param[in] width The target image width
+   * @param[in] height The target image height
+   */
+  void SetSize( uint32_t width, uint32_t height );
+
+  /**
+   * @brief Play the vector animation.
+   */
+  void PlayAnimation();
+
+  /**
+   * @brief Stop the vector animation.
+   */
+  void StopAnimation();
+
+  /**
+   * @brief Pause the vector animation.
+   */
+  void PauseAnimation();
+
+  /**
+   * @brief Render one frame. The current frame number will be increased.
+   */
+  void RenderFrame();
+
+  /**
+   * @brief This callback is called after the animation is finished.
+   * @param[in] callback The animation finished callback
+   */
+  void SetAnimationFinishedCallback( EventThreadCallback* callback );
+
+  /**
+   * @brief Enable looping for 'count' repeats. -1 means to repeat forever.
+   * @param[in] count The number of times to loop
+   */
+  void SetLoopCount( int32_t count );
+
+  /**
+   * @brief Set the playing range in frame number.
+   * @param[in] playRange The array to specify minimum and maximum progress.
+   * The animation will play between those values.
+   */
+  void SetPlayRange( Property::Array& playRange );
+
+  /**
+   * @brief Gets the playing range in frame number.
+   * @param[out] startFrame The frame number to specify minimum progress.
+   * @param[out] endFrame The frame number to specify maximum progress.
+   */
+  void GetPlayRange( uint32_t& startFrame, uint32_t& endFrame );
+
+  /**
+   * @brief Get the play state
+   * @return The play state
+   */
+  DevelImageVisual::PlayState::Type GetPlayState() const;
+
+  /**
+   * @brief Sets the current frame number of the animation.
+   * @param[in] frameNumber The new frame number between [0, the maximum frame number] or between the play range if specified.
+   */
+  void SetCurrentFrameNumber( uint32_t frameNumber );
+
+  /**
+   * @brief Retrieves the current frame number of the animation.
+   * @return The current frame number
+   */
+  uint32_t GetCurrentFrameNumber() const;
+
+  /**
+   * @brief Retrieves the total frame number of the animation.
+   * @return The total frame number
+   */
+  uint32_t GetTotalFrameNumber() const;
+
+  /**
+   * @brief Gets the default size of the file,.
+   * @return The default size of the file
+   */
+  void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
+
+  /**
+   * @brief Sets the stop behavior of the animation. This is performed when the animation is stopped.
+   * @param[in] stopBehavior The stop behavior
+   */
+  void SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior );
+
+  /**
+   * @brief Sets the looping mode.
+   * Animation plays forwards and then restarts from the beginning or runs backwards again.
+   * @param[in] loopingMode The looping mode
+   */
+  void SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode );
+
+  /**
+   * @brief Gets the layer information of all the child layers.
+   * @param[out] map The layer information
+   */
+  void GetLayerInfo( Property::Map& map ) const;
+
+  /**
+   * @brief Connect to this signal to be notified when the texture upload is completed.
+   * @return The signal to connect to.
+   */
+  UploadCompletedSignalType& UploadCompletedSignal();
+
+  /**
+   * @brief Rasterizes the current frame.
+   * @return true if the animation is running, false otherwise.
+   */
+  bool Rasterize();
+
+  /**
+   * @brief Calculates the time for the next frame rasterization.
+   * @return The time for the next frame rasterization.
+   */
+  std::chrono::time_point< std::chrono::system_clock > CalculateNextFrameTime( bool renderNow );
+
+  /**
+   * @brief Gets the time for the next frame rasterization.
+   * @return The time for the next frame rasterization.
+   */
+  std::chrono::time_point< std::chrono::system_clock > GetNextFrameTime();
+
+private:
+
+  /**
+   * @brief Initializes the vector renderer.
+   */
+  void Initialize();
+
+  /**
+   * @brief Gets the frame number when the animation is stopped according to the stop behavior.
+   */
+  uint32_t GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame );
+
+  // Undefined
+  VectorAnimationTask( const VectorAnimationTask& task ) = delete;
+
+  // Undefined
+  VectorAnimationTask& operator=( const VectorAnimationTask& task ) = delete;
+
+private:
+
+  enum class PlayState
+  {
+    STOPPING,  ///< The animation is stopping
+    STOPPED,   ///< The animation has stopped
+    PLAYING,   ///< The animation is playing
+    PAUSED     ///< The animation is paused
+  };
+
+  std::string                            mUrl;
+  VectorAnimationRenderer                mVectorRenderer;
+  VectorAnimationThread&                 mVectorAnimationThread;
+  ConditionalWait                        mConditionalWait;
+  std::unique_ptr< EventThreadCallback > mAnimationFinishedTrigger;
+  Vector2                                mPlayRange;
+  PlayState                              mPlayState;
+  DevelImageVisual::StopBehavior::Type   mStopBehavior;
+  DevelImageVisual::LoopingMode::Type    mLoopingMode;
+  std::chrono::time_point< std::chrono::system_clock > mNextFrameStartTime;
+  int64_t                                mFrameDurationNanoSeconds;
+  float                                  mFrameRate;
+  uint32_t                               mCurrentFrame;
+  uint32_t                               mTotalFrame;
+  uint32_t                               mStartFrame;
+  uint32_t                               mEndFrame;
+  uint32_t                               mWidth;
+  uint32_t                               mHeight;
+  int32_t                                mLoopCount;
+  int32_t                                mCurrentLoop;
+  bool                                   mResourceReady;
+  bool                                   mCurrentFrameUpdated;
+  bool                                   mCurrentLoopUpdated;
+  bool                                   mForward;
+  bool                                   mUpdateFrameNumber;
+  bool                                   mNeedAnimationFinishedTrigger;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
new file mode 100644 (file)
index 0000000..8403e6a
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/integration-api/debug.h>
+#include <thread>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+constexpr auto DEFAULT_NUMBER_OF_RASTERIZE_THREADS = size_t{ 4u };
+constexpr auto NUMBER_OF_RASTERIZE_THREADS_ENV = "DALI_VECTOR_RASTERIZE_THREADS";
+
+size_t GetNumberOfThreads( const char* environmentVariable, size_t defaultValue )
+{
+  using Dali::EnvironmentVariable::GetEnvironmentVariable;
+  auto numberString = GetEnvironmentVariable( environmentVariable );
+  auto numberOfThreads = numberString ? std::strtoul( numberString, nullptr, 10 ) : 0;
+  constexpr auto MAX_NUMBER_OF_THREADS = 100u;
+  DALI_ASSERT_DEBUG( numberOfThreads < MAX_NUMBER_OF_THREADS );
+  return ( numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS ) ? numberOfThreads : defaultValue;
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
+#endif
+
+} // unnamed namespace
+
+VectorAnimationThread::VectorAnimationThread()
+: mAnimationTasks(),
+  mCompletedTasks(),
+  mRasterizers( GetNumberOfThreads( NUMBER_OF_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_RASTERIZE_THREADS ), [&]() { return RasterizeHelper( *this ); } ),
+  mSleepThread( MakeCallback( this, &VectorAnimationThread::OnAwakeFromSleep ) ),
+  mConditionalWait(),
+  mNeedToSleep( false ),
+  mDestroyThread( false ),
+  mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
+{
+  mSleepThread.Start();
+}
+
+VectorAnimationThread::~VectorAnimationThread()
+{
+  // Stop the thread
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    mDestroyThread = true;
+    mConditionalWait.Notify( lock );
+  }
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::~VectorAnimationThread: Join [%p]\n", this );
+
+  Join();
+}
+
+void VectorAnimationThread::AddTask( VectorAnimationTaskPtr task )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( mAnimationTasks.end() == std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
+  {
+    auto currentTime = task->CalculateNextFrameTime( true );  // Rasterize as soon as possible
+
+    bool inserted = false;
+    for( auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter )
+    {
+      auto nextTime = (*iter)->GetNextFrameTime();
+      if( nextTime > currentTime )
+      {
+        mAnimationTasks.insert( iter, task );
+        inserted = true;
+        break;
+      }
+    }
+
+    if( !inserted )
+    {
+      mAnimationTasks.push_back( task );
+    }
+
+    // wake up the animation thread
+    mConditionalWait.Notify( lock );
+  }
+}
+
+void VectorAnimationThread::OnTaskCompleted( VectorAnimationTaskPtr task, bool keepAnimation )
+{
+  if( keepAnimation && !mDestroyThread )
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+
+    if( mCompletedTasks.end() == std::find( mCompletedTasks.begin(), mCompletedTasks.end(), task ) )
+    {
+      mCompletedTasks.push_back( task );
+
+      // wake up the animation thread
+      mConditionalWait.Notify( lock );
+    }
+  }
+}
+
+void VectorAnimationThread::OnAwakeFromSleep()
+{
+  if( !mDestroyThread )
+  {
+    mNeedToSleep = false;
+    // wake up the animation thread
+    mConditionalWait.Notify();
+  }
+}
+
+void VectorAnimationThread::Run()
+{
+  SetThreadName( "VectorAnimationThread" );
+  mLogFactory.InstallLogFunction();
+
+  while( !mDestroyThread )
+  {
+    Rasterize();
+  }
+}
+
+void VectorAnimationThread::Rasterize()
+{
+  // Lock while popping task out from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  // conditional wait
+  if( (mAnimationTasks.empty() && mCompletedTasks.empty() ) || mNeedToSleep )
+  {
+    mConditionalWait.Wait( lock );
+  }
+
+  mNeedToSleep = false;
+
+  // Process completed tasks
+  for( auto&& task : mCompletedTasks )
+  {
+    if( mAnimationTasks.end() == std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
+    {
+      // Should use the frame rate of the animation file
+      auto nextFrameTime = task->CalculateNextFrameTime( false );
+
+      bool inserted = false;
+      for( auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter )
+      {
+        auto time = (*iter)->GetNextFrameTime();
+        if( time > nextFrameTime )
+        {
+          mAnimationTasks.insert( iter, task );
+          inserted = true;
+          break;
+        }
+      }
+
+      if( !inserted )
+      {
+        mAnimationTasks.push_back( task );
+      }
+    }
+  }
+  mCompletedTasks.clear();
+
+  // pop out the next task from the queue
+  while( !mAnimationTasks.empty() && !mNeedToSleep )
+  {
+    std::vector< VectorAnimationTaskPtr >::iterator next = mAnimationTasks.begin();
+    VectorAnimationTaskPtr nextTask = *next;
+
+    auto currentTime = std::chrono::system_clock::now();
+    auto nextFrameTime = nextTask->GetNextFrameTime();
+
+#if defined(DEBUG_ENABLED)
+    auto duration = std::chrono::duration_cast< std::chrono::milliseconds >( nextFrameTime - currentTime );
+
+    DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count() );
+#endif
+
+    if( nextFrameTime <= currentTime )
+    {
+      mAnimationTasks.erase( next );
+
+      auto rasterizerHelperIt = mRasterizers.GetNext();
+      DALI_ASSERT_ALWAYS( rasterizerHelperIt != mRasterizers.End() );
+
+      rasterizerHelperIt->Rasterize( nextTask );
+    }
+    else
+    {
+      mNeedToSleep = true;
+      mSleepThread.SleepUntil( nextFrameTime );
+    }
+  }
+}
+
+VectorAnimationThread::RasterizeHelper::RasterizeHelper( VectorAnimationThread& animationThread )
+: RasterizeHelper( std::unique_ptr< VectorRasterizeThread >( new VectorRasterizeThread() ), animationThread )
+{
+}
+
+VectorAnimationThread::RasterizeHelper::RasterizeHelper( RasterizeHelper&& rhs )
+: RasterizeHelper( std::move( rhs.mRasterizer ), rhs.mAnimationThread )
+{
+}
+
+VectorAnimationThread::RasterizeHelper::RasterizeHelper( std::unique_ptr< VectorRasterizeThread > rasterizer, VectorAnimationThread& animationThread )
+: mRasterizer( std::move( rasterizer ) ),
+  mAnimationThread( animationThread )
+{
+  mRasterizer->SetCompletedCallback( MakeCallback( &mAnimationThread, &VectorAnimationThread::OnTaskCompleted ) );
+}
+
+void VectorAnimationThread::RasterizeHelper::Rasterize( VectorAnimationTaskPtr task )
+{
+  if( task )
+  {
+    mRasterizer->AddTask( task );
+  }
+}
+
+VectorAnimationThread::SleepThread::SleepThread( CallbackBase* callback )
+: mConditionalWait(),
+  mAwakeCallback( std::unique_ptr< CallbackBase >( callback ) ),
+  mSleepTimePoint(),
+  mLogFactory( Dali::Adaptor::Get().GetLogFactory() ),
+  mNeedToSleep( false ),
+  mDestroyThread( false )
+{
+}
+
+VectorAnimationThread::SleepThread::~SleepThread()
+{
+  // Stop the thread
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    mDestroyThread = true;
+    mConditionalWait.Notify( lock );
+  }
+
+  Join();
+}
+
+void VectorAnimationThread::SleepThread::SleepUntil( std::chrono::time_point< std::chrono::system_clock > timeToSleepUntil )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  mSleepTimePoint = timeToSleepUntil;
+  mNeedToSleep = true;
+  mConditionalWait.Notify( lock );
+}
+
+void VectorAnimationThread::SleepThread::Run()
+{
+  SetThreadName( "VectorSleepThread" );
+  mLogFactory.InstallLogFunction();
+
+  while( !mDestroyThread )
+  {
+    bool needToSleep;
+    std::chrono::time_point< std::chrono::system_clock > sleepTimePoint;
+
+    {
+      ConditionalWait::ScopedLock lock( mConditionalWait );
+
+      needToSleep = mNeedToSleep;
+      sleepTimePoint = mSleepTimePoint;
+
+      mNeedToSleep = false;
+    }
+
+    if( needToSleep )
+    {
+#if defined(DEBUG_ENABLED)
+      auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( mSleepTimePoint - std::chrono::system_clock::now() );
+
+      DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count() );
+#endif
+
+      std::this_thread::sleep_until( sleepTimePoint );
+
+      if( mAwakeCallback )
+      {
+        CallbackBase::Execute( *mAwakeCallback );
+      }
+    }
+
+    {
+      ConditionalWait::ScopedLock lock( mConditionalWait );
+      if( !mDestroyThread && !mNeedToSleep )
+      {
+        mConditionalWait.Wait( lock );
+      }
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h
new file mode 100755 (executable)
index 0000000..8d3dd64
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
+#define DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * The main animation thread for vector animations
+ */
+class VectorAnimationThread : public Thread
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  VectorAnimationThread();
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~VectorAnimationThread();
+
+  /**
+   * Add a animation task into the vector animation thread, called by main thread.
+   *
+   * @param[in] task The task added to the thread.
+   */
+  void AddTask( VectorAnimationTaskPtr task );
+
+  /**
+   * @brief Called when the rasterization is completed from the rasterize thread.
+   * @param task The completed task
+   */
+  void OnTaskCompleted( VectorAnimationTaskPtr task, bool stopped );
+
+  /**
+   * @brief Called when the sleep thread is awaken.
+   */
+  void OnAwakeFromSleep();
+
+protected:
+
+  /**
+   * @brief The entry function of the animation thread.
+   */
+  void Run() override;
+
+private:
+
+  /**
+   * Rasterizes the tasks.
+   */
+  void Rasterize();
+
+private:
+
+  /**
+   * @brief Helper class to keep the relation between VectorRasterizeThread and corresponding container
+   */
+  class RasterizeHelper : public ConnectionTracker
+  {
+  public:
+    /**
+     * @brief Create an RasterizeHelper.
+     *
+     * @param[in] animationThread Reference to the VectorAnimationThread
+     */
+    RasterizeHelper( VectorAnimationThread& animationThread );
+
+    /**
+     * @brief Rasterizes the task.
+     *
+     * @param[in] task The task to rasterize.
+     */
+    void Rasterize( VectorAnimationTaskPtr task );
+
+  public:
+    RasterizeHelper( const RasterizeHelper& ) = delete;
+    RasterizeHelper& operator=( const RasterizeHelper& ) = delete;
+
+    RasterizeHelper( RasterizeHelper&& rhs );
+    RasterizeHelper& operator=( RasterizeHelper&& rhs ) = delete;
+
+  private:
+
+    /**
+     * @brief Main constructor that used by all other constructors
+     */
+    RasterizeHelper( std::unique_ptr< VectorRasterizeThread > rasterizer, VectorAnimationThread& animationThread );
+
+  private:
+    std::unique_ptr< VectorRasterizeThread > mRasterizer;
+    VectorAnimationThread&                   mAnimationThread;
+  };
+
+  /**
+   * @brief The thread to sleep until the next frame time.
+   */
+  class SleepThread : public Thread
+  {
+  public:
+
+    /**
+     * @brief Constructor.
+     */
+    SleepThread( CallbackBase* callback );
+
+    /**
+     * @brief Destructor.
+     */
+    virtual ~SleepThread();
+
+    /**
+     * @brief Sleeps untile the specified time point.
+     */
+    void SleepUntil( std::chrono::time_point< std::chrono::system_clock > timeToSleepUntil );
+
+  protected:
+
+    /**
+     * @brief The entry function of the animation thread.
+     */
+    void Run() override;
+
+  private:
+
+    SleepThread( const SleepThread& thread ) = delete;
+    SleepThread& operator=( const SleepThread& thread ) = delete;
+
+  private:
+    ConditionalWait                  mConditionalWait;
+    std::unique_ptr< CallbackBase >  mAwakeCallback;
+    std::chrono::time_point< std::chrono::system_clock > mSleepTimePoint;
+    const Dali::LogFactoryInterface& mLogFactory;
+    bool                             mNeedToSleep;
+    bool                             mDestroyThread;
+  };
+
+private:
+
+  // Undefined
+  VectorAnimationThread( const VectorAnimationThread& thread ) = delete;
+
+  // Undefined
+  VectorAnimationThread& operator=( const VectorAnimationThread& thread ) = delete;
+
+private:
+
+  std::vector< VectorAnimationTaskPtr >      mAnimationTasks;
+  std::vector< VectorAnimationTaskPtr >      mCompletedTasks;
+  RoundRobinContainerView< RasterizeHelper > mRasterizers;
+  SleepThread                                mSleepThread;
+  ConditionalWait                            mConditionalWait;
+  bool                                       mNeedToSleep;
+  bool                                       mDestroyThread;
+  const Dali::LogFactoryInterface&           mLogFactory;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // #endif // DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.cpp
new file mode 100644 (file)
index 0000000..08cad31
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/integration-api/debug.h>
+#include <chrono>
+#include <thread>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
+#endif
+
+} // unnamed namespace
+
+VectorRasterizeThread::VectorRasterizeThread()
+: mRasterizeTasks(),
+  mConditionalWait(),
+  mCompletedCallback(),
+  mDestroyThread( false ),
+  mIsThreadStarted( false ),
+  mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
+{
+}
+
+VectorRasterizeThread::~VectorRasterizeThread()
+{
+  // Stop the thread
+  {
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    mDestroyThread = true;
+    mConditionalWait.Notify( lock );
+  }
+
+  DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::~VectorRasterizeThread: Join [%p]\n", this );
+
+  Join();
+}
+
+void VectorRasterizeThread::SetCompletedCallback( CallbackBase* callback )
+{
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  mCompletedCallback = std::unique_ptr< CallbackBase >( callback );
+}
+
+void VectorRasterizeThread::AddTask( VectorAnimationTaskPtr task )
+{
+  // Lock while adding task to the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( !mIsThreadStarted )
+  {
+    Start();
+    mIsThreadStarted = true;
+  }
+
+  if( mRasterizeTasks.end() == std::find( mRasterizeTasks.begin(), mRasterizeTasks.end(), task ) )
+  {
+    mRasterizeTasks.push_back( task );
+
+    // wake up the animation thread
+    mConditionalWait.Notify( lock );
+  }
+}
+
+void VectorRasterizeThread::Run()
+{
+  SetThreadName( "VectorRasterizeThread" );
+  mLogFactory.InstallLogFunction();
+
+  while( !mDestroyThread )
+  {
+    Rasterize();
+  }
+}
+
+void VectorRasterizeThread::Rasterize()
+{
+  VectorAnimationTaskPtr nextTask;
+  {
+    // Lock while popping task out from the queue
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+
+    // conditional wait
+    if( mRasterizeTasks.empty() )
+    {
+      mConditionalWait.Wait( lock );
+    }
+
+    // pop out the next task from the queue
+    if( !mRasterizeTasks.empty() )
+    {
+      std::vector< VectorAnimationTaskPtr >::iterator next = mRasterizeTasks.begin();
+      nextTask = *next;
+      mRasterizeTasks.erase( next );
+    }
+  }
+
+  if( nextTask )
+  {
+    bool keepAnimation = nextTask->Rasterize();
+
+    if( mCompletedCallback )
+    {
+      CallbackBase::Execute( *mCompletedCallback, nextTask, keepAnimation );
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h b/dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h
new file mode 100644 (file)
index 0000000..e24a918
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_TOOLKIT_VECTOR_IMAGE_RASTERIZE_THREAD_H
+#define DALI_TOOLKIT_VECTOR_IMAGE_RASTERIZE_THREAD_H
+
+/*
+ * Copyright (c) 2019 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 <vector>
+#include <memory>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * The worker thread for vector image rasterization.
+ */
+class VectorRasterizeThread : public Thread
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  VectorRasterizeThread();
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~VectorRasterizeThread();
+
+  /**
+   * The callback is called from the rasterize thread after the rasterization is completed.
+   * @param[in] callBack  The function to call.
+   */
+  void SetCompletedCallback( CallbackBase* callback );
+
+  /**
+   * Add a task to rasterize.
+   *
+   * @param[in] task The task to rasterize
+   */
+  void AddTask( VectorAnimationTaskPtr task );
+
+protected:
+
+  /**
+   * @brief The entry function of the worker thread.
+   *        It rasterizes the vector image.
+   */
+  void Run() override;
+
+private:
+
+  /**
+   * Rasterizes the tasks.
+   */
+  void Rasterize();
+
+private:
+
+  // Undefined
+  VectorRasterizeThread( const VectorRasterizeThread& thread ) = delete;
+
+  // Undefined
+  VectorRasterizeThread& operator=( const VectorRasterizeThread& thread ) = delete;
+
+private:
+
+  std::vector< VectorAnimationTaskPtr > mRasterizeTasks;
+  ConditionalWait                       mConditionalWait;
+  std::unique_ptr< CallbackBase >       mCompletedCallback;
+  bool                                  mDestroyThread;  ///< Whether the thread be destroyed
+  bool                                  mIsThreadStarted;
+  const Dali::LogFactoryInterface&      mLogFactory; ///< The log factory
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VECTOR_IMAGE_RASTERIZE_THREAD_H
diff --git a/dali-toolkit/internal/visuals/arc/arc-visual.cpp b/dali-toolkit/internal/visuals/arc/arc-visual.cpp
new file mode 100644 (file)
index 0000000..a1eb02a
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/arc/arc-visual.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// cap
+DALI_ENUM_TO_STRING_TABLE_BEGIN( CAP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelArcVisual::Cap, BUTT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DevelArcVisual::Cap, ROUND )
+DALI_ENUM_TO_STRING_TABLE_END( CAP )
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  varying mediump vec2 vPosition;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    vPosition = aPosition* visualSize;\n
+    return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_BUTT_CAP = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vPosition;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float thickness;\n
+  uniform mediump float radius;\n
+  uniform mediump float startAngle;\n
+  uniform mediump float sweepAngle;\n
+  \n
+  const mediump float M_PI_OVER_2 = 1.57079632679;\n
+  const mediump float M_PI = 3.14159265359;\n
+  const mediump float M_PI_2 = 6.28318530718;\n
+  \n
+  mediump float GetOpacity()\n
+  {\n
+      mediump float start = radians( mod( startAngle, 360.0 ) );\n
+      mediump float angle = mod( atan( vPosition.y, vPosition.x ) + M_PI_OVER_2 - start, M_PI_2 );\n
+      mediump float dist = length( vPosition );\n
+      if( angle <= radians( sweepAngle ) )\n
+      {\n
+        return smoothstep( -1.0, 1.0, thickness / 2.0 - ( abs( dist - radius ) ) );\n
+      }\n
+      mediump float end = radians( mod( startAngle + sweepAngle, 360.0 ) );\n
+      mediump vec2 q0 = vec2( dist * cos( start - M_PI_OVER_2 ), dist * sin( start - M_PI_OVER_2 ) );\n
+      mediump vec2 q1 = vec2( dist * cos( end - M_PI_OVER_2 ), dist * sin( end - M_PI_OVER_2 ) );\n
+      mediump float opacity = 1.0 - smoothstep( 0.0, 2.0, min( length( vPosition - q0 ), length( vPosition - q1 ) ) );\n
+      opacity *= step( 0.0, thickness / 2.0 - abs( dist - radius ) );\n
+      return opacity;\n
+  }\n
+  void main()\n
+  {\n
+    gl_FragColor = vec4( mixColor, 1.0 ) * uColor;\n
+    gl_FragColor.a *= GetOpacity();\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_ROUND_CAP = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vPosition;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float thickness;\n
+  uniform mediump float radius;\n
+  uniform mediump float startAngle;\n
+  uniform mediump float sweepAngle;\n
+  \n
+  const mediump float M_PI_OVER_2 = 1.57079632679;\n
+  const mediump float M_PI_2 = 6.28318530718;\n
+  \n
+  mediump float GetOpacity()\n
+  {\n
+      mediump float start = radians( mod( startAngle, 360.0 ) );\n
+      mediump float angle = mod( atan( vPosition.y, vPosition.x ) + M_PI_OVER_2 - start, M_PI_2 );\n
+      mediump float dist = length( vPosition );\n
+      if( angle <= radians( sweepAngle ) )\n
+      {\n
+        return smoothstep( -1.0, 1.0, thickness / 2.0 - ( abs( dist - radius ) ) );\n
+      }\n
+      mediump float end = radians( mod( startAngle + sweepAngle, 360.0 ) );\n
+      mediump vec2 q0 = vec2( radius * cos( start - M_PI_OVER_2 ), radius * sin( start - M_PI_OVER_2 ) );\n
+      mediump vec2 q1 = vec2( radius * cos( end - M_PI_OVER_2 ), radius * sin( end - M_PI_OVER_2 ) );\n
+      return smoothstep( -1.0, 1.0, thickness / 2.0 - min( length( vPosition - q0 ), length( vPosition - q1 ) ) );\n
+  }\n
+  void main()\n
+  {\n
+    gl_FragColor = vec4( mixColor, 1.0 ) * uColor;\n
+    gl_FragColor.a *= GetOpacity();\n
+  }\n
+);
+
+}
+
+ArcVisualPtr ArcVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  ArcVisualPtr arcVisualPtr( new ArcVisual( factoryCache ) );
+  arcVisualPtr->SetProperties( properties );
+  return arcVisualPtr;
+}
+
+ArcVisual::ArcVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mThickness( 0.0f ),
+  mRadius( 0.0f ),
+  mStartAngle( 0.0f ),
+  mSweepAngle( 360.0f ),
+  mRadiusIndex( Property::INVALID_INDEX ),
+  mCapType( DevelArcVisual::Cap::BUTT )
+{
+}
+
+ArcVisual::~ArcVisual()
+{
+}
+
+void ArcVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  Property::Value* thicknessValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::THICKNESS, THICKNESS_NAME );
+  if( thicknessValue )
+  {
+    if( !thicknessValue->Get( mThickness ) )
+    {
+      DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: THICKNESS property has incorrect type: %d\n", thicknessValue->GetType() );
+    }
+  }
+
+  Property::Value* startAngleValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::START_ANGLE, START_ANGLE_NAME );
+  if( startAngleValue )
+  {
+    if( !startAngleValue->Get( mStartAngle ) )
+    {
+      DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: START_ANGLE property has incorrect type: %d\n", startAngleValue->GetType() );
+    }
+  }
+
+  Property::Value* sweepAngleValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::SWEEP_ANGLE, SWEEP_ANGLE_NAME );
+  if( sweepAngleValue )
+  {
+    if( !sweepAngleValue->Get( mSweepAngle ) )
+    {
+      DALI_LOG_ERROR( "ArcVisual:DoSetProperties:: SWEEP_ANGLE property has incorrect type: %d\n", sweepAngleValue->GetType() );
+    }
+  }
+
+  Property::Value* capValue = propertyMap.Find( Toolkit::DevelArcVisual::Property::CAP, CAP_NAME );
+  if( capValue )
+  {
+    int capType = 0;
+    Scripting::GetEnumerationProperty( *capValue, CAP_TABLE, CAP_TABLE_COUNT, capType );
+    mCapType = Toolkit::DevelArcVisual::Cap::Type( capType );
+  }
+}
+
+void ArcVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Arc Visual generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void ArcVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::DevelVisual::ARC );
+  map.Insert( Toolkit::DevelArcVisual::Property::THICKNESS, mThickness );
+  map.Insert( Toolkit::DevelArcVisual::Property::START_ANGLE, mStartAngle );
+  map.Insert( Toolkit::DevelArcVisual::Property::SWEEP_ANGLE, mSweepAngle );
+  map.Insert( Toolkit::DevelArcVisual::Property::CAP, mCapType );
+}
+
+void ArcVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void ArcVisual::OnSetTransform()
+{
+  Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
+  mRadius = ( std::min( visualSize.width, visualSize.height ) - mThickness ) / 2.0f;
+
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty( mRadiusIndex, mRadius );
+  }
+}
+
+void ArcVisual::InitializeRenderer()
+{
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+  Shader shader;
+  if( mCapType == DevelArcVisual::Cap::BUTT )
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::ARC_BUTT_CAP_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_BUTT_CAP );
+      mFactoryCache.SaveShader( VisualFactoryCache::ARC_BUTT_CAP_SHADER, shader );
+    }
+  }
+  else
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::ARC_ROUND_CAP_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ROUND_CAP );
+      mFactoryCache.SaveShader( VisualFactoryCache::ARC_ROUND_CAP_SHADER, shader );
+    }
+  }
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  mImpl->mRenderer.RegisterProperty( THICKNESS_NAME, mThickness );
+  mImpl->mRenderer.RegisterProperty( START_ANGLE_NAME, mStartAngle );
+  mImpl->mRenderer.RegisterProperty( SWEEP_ANGLE_NAME, mSweepAngle );
+  mImpl->mRenderer.RegisterProperty( CAP_NAME, 0.0f );
+
+  mRadiusIndex = mImpl->mRenderer.RegisterProperty( RADIUS_NAME, mRadius );
+
+  mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/arc/arc-visual.h b/dali-toolkit/internal/visuals/arc/arc-visual.h
new file mode 100644 (file)
index 0000000..e9fa083
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ARC_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_ARC_VISUAL_H
+
+/*
+ * Copyright (c) 2020 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 <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/devel-api/visuals/arc-visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ArcVisual;
+typedef IntrusivePtr< ArcVisual > ArcVisualPtr;
+
+/**
+ * The visual which renders an arc to the control's quad
+ *
+ * The following properties are required for create an ArcVisual
+ *
+ * | %Property Name  | Type        |
+ * |-----------------|-------------|
+ * | THICKNESS       | FLOAT       |
+ * | START_ANGLE     | FLOAT       |
+ * | SWEEP_ANGLE     | FLOAT       |
+ * | CAP             | INTEGER     |
+ */
+class ArcVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new arc visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static ArcVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  ArcVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~ArcVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+private:
+
+  // Undefined
+  ArcVisual( const ArcVisual& arcVisual ) = delete;
+
+  // Undefined
+  ArcVisual& operator=( const ArcVisual& arcVisual ) = delete;
+
+private:
+
+  float mThickness;                    ///< The thickness of the arc.
+  float mRadius;                       ///< The radius of the arc.
+  float mStartAngle;                   ///< The start angle of the arc.
+  float mSweepAngle;                   ///< The sweep angle of the arc.
+  Property::Index mRadiusIndex;        ///< The index of the radius property.
+  DevelArcVisual::Cap::Type mCapType;  ///< The cap type.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_ARC_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/border/border-visual.cpp b/dali-toolkit/internal/visuals/border/border-visual.cpp
new file mode 100644 (file)
index 0000000..c1ba93b
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2018 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 "border-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/object/handle-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/border-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const char * const POSITION_ATTRIBUTE_NAME("aPosition");
+const char * const DRIFT_ATTRIBUTE_NAME("aDrift");
+const char * const INDEX_NAME("indices");
+
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  attribute mediump vec2 aDrift;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump float borderSize;\n
+  \n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec2 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy;\n
+  }\n
+
+  void main()\n
+  {\n
+    vec2 position = ComputeVertexPosition() + aDrift*borderSize;\n
+    gl_Position = uMvpMatrix * vec4(position, 0.0, 1.0);\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec4 borderColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = vec4(mixColor, 1.0)*borderColor*uColor;\n
+  }\n
+);
+
+const char* VERTEX_SHADER_ANTI_ALIASING = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  attribute mediump vec2 aDrift;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump float borderSize;\n
+  varying mediump float vAlpha;\n
+  \n
+  void main()\n
+  {\n
+    vec2 position = aPosition*(uSize.xy+vec2(0.75)) + aDrift*(borderSize+1.5);\n
+    gl_Position = uMvpMatrix * vec4(position, 0.0, 1.0);\n
+    vAlpha = min( abs(aDrift.x), abs(aDrift.y) )*(borderSize+1.5);
+  }\n
+);
+
+const char* FRAGMENT_SHADER_ANTI_ALIASING = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec4 borderColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float borderSize;\n
+  varying mediump float vAlpha;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = vec4(mixColor, 1.0)*borderColor*uColor;\n
+    gl_FragColor.a *= smoothstep(0.0, 1.5, vAlpha)*smoothstep( borderSize+1.5, borderSize, vAlpha );\n
+  }\n
+);
+}
+
+BorderVisualPtr BorderVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  BorderVisualPtr borderVisualPtr( new BorderVisual( factoryCache ) );
+  borderVisualPtr->SetProperties( properties );
+  return borderVisualPtr;
+}
+
+BorderVisual::BorderVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mBorderColor( Color::TRANSPARENT ),
+  mBorderSize( 0.f ),
+  mBorderColorIndex( Property::INVALID_INDEX ),
+  mBorderSizeIndex( Property::INVALID_INDEX ),
+  mAntiAliasing( false )
+{
+}
+
+BorderVisual::~BorderVisual()
+{
+}
+
+void BorderVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else
+    {
+      if( keyValue.first == COLOR_NAME )
+      {
+        DoSetProperty( Toolkit::BorderVisual::Property::COLOR, keyValue.second );
+      }
+      else if( keyValue.first == SIZE_NAME )
+      {
+        DoSetProperty( Toolkit::BorderVisual::Property::SIZE, keyValue.second );
+      }
+      else if( keyValue.first == ANTI_ALIASING )
+      {
+        DoSetProperty( Toolkit::BorderVisual::Property::ANTI_ALIASING, keyValue.second );
+      }
+    }
+  }
+}
+
+void BorderVisual::DoSetProperty( Dali::Property::Index index,
+                                  const Dali::Property::Value& value )
+{
+  switch( index )
+  {
+    case Toolkit::BorderVisual::Property::COLOR:
+    {
+      if( !value.Get( mBorderColor ) )
+      {
+        DALI_LOG_ERROR("BorderVisual: borderColor property has incorrect type\n");
+      }
+      break;
+    }
+    case Toolkit::BorderVisual::Property::SIZE:
+    {
+      if( !value.Get( mBorderSize ) )
+      {
+        DALI_LOG_ERROR("BorderVisual: borderSize property has incorrect type\n");
+      }
+      break;
+    }
+    case Toolkit::BorderVisual::Property::ANTI_ALIASING:
+    {
+      if( !value.Get( mAntiAliasing ) )
+      {
+        DALI_LOG_ERROR("BorderVisual: antiAliasing property has incorrect type\n");
+      }
+      break;
+    }
+  }
+}
+
+void BorderVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  mBorderColorIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::BorderVisual::Property::COLOR, COLOR_NAME, mBorderColor );
+  if( mBorderColor.a < 1.f || mAntiAliasing)
+  {
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  }
+  mBorderSizeIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::BorderVisual::Property::SIZE, SIZE_NAME, mBorderSize );
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Border Visual Generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void BorderVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::BORDER );
+  map.Insert( Toolkit::BorderVisual::Property::COLOR, mBorderColor );
+  map.Insert( Toolkit::BorderVisual::Property::SIZE, mBorderSize );
+  map.Insert( Toolkit::BorderVisual::Property::ANTI_ALIASING, mAntiAliasing );
+}
+
+void BorderVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void BorderVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void BorderVisual::InitializeRenderer()
+{
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::BORDER_GEOMETRY );
+  if( !geometry )
+  {
+    geometry =  CreateBorderGeometry();
+    mFactoryCache.SaveGeometry( VisualFactoryCache::BORDER_GEOMETRY, geometry );
+  }
+
+  Shader shader = GetBorderShader();
+  mImpl->mRenderer = Renderer::New( geometry, shader  );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+Shader BorderVisual::GetBorderShader()
+{
+  Shader shader;
+  if( mAntiAliasing )
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::BORDER_SHADER_ANTI_ALIASING );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER_ANTI_ALIASING, FRAGMENT_SHADER_ANTI_ALIASING );
+      mFactoryCache.SaveShader( VisualFactoryCache::BORDER_SHADER_ANTI_ALIASING, shader );
+    }
+  }
+  else
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::BORDER_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+      mFactoryCache.SaveShader( VisualFactoryCache::BORDER_SHADER, shader );
+    }
+  }
+
+  return shader;
+}
+
+/**
+ * Vertices and triangles of the border geometry:
+ *
+ * vertex position = aPosition*uSize.xy + aDrift*uBorderSize;
+ *
+ * 0--1--2--3
+ * |\ | /| /|
+ * | \|/ |/ |
+ * 4--5--6--7
+ * |\ |  |\ |
+ * | \|  | \|
+ * 8--9--10-11
+ * | /| /|\ |
+ * |/ |/ | \|
+ * 12-13-14-15
+ */
+Geometry BorderVisual::CreateBorderGeometry()
+{
+  const float halfWidth = 0.5f;
+  const float halfHeight = 0.5f;
+  struct BorderVertex { Vector2 position; Vector2 drift;};
+  BorderVertex borderVertexData[16] =
+  {
+      { Vector2(-halfWidth, -halfHeight), Vector2(0.f, 0.f) },
+      { Vector2(-halfWidth, -halfHeight), Vector2(1.f, 0.f) },
+      { Vector2(halfWidth, -halfHeight),  Vector2(-1.f, 0.f) },
+      { Vector2(halfWidth, -halfHeight),  Vector2(0.f, 0.f) },
+
+      { Vector2(-halfWidth, -halfHeight), Vector2(0.f, 1.f) },
+      { Vector2(-halfWidth, -halfHeight), Vector2(1.f, 1.f) },
+      { Vector2(halfWidth, -halfHeight),  Vector2(-1.f, 1.f) },
+      { Vector2(halfWidth, -halfHeight),  Vector2(0.f, 1.f) },
+
+      { Vector2(-halfWidth, halfHeight), Vector2(0.f, -1.f) },
+      { Vector2(-halfWidth, halfHeight), Vector2(1.f, -1.f) },
+      { Vector2(halfWidth, halfHeight),  Vector2(-1.f, -1.f) },
+      { Vector2(halfWidth, halfHeight),  Vector2(0.f, -1.f) },
+
+      { Vector2(-halfWidth, halfHeight), Vector2(0.f, 0.f) },
+      { Vector2(-halfWidth, halfHeight), Vector2(1.f, 0.f) },
+      { Vector2(halfWidth, halfHeight),  Vector2(-1.f, 0.f) },
+      { Vector2(halfWidth, halfHeight),  Vector2(0.f, 0.f) },
+  };
+
+  Property::Map borderVertexFormat;
+  borderVertexFormat[POSITION_ATTRIBUTE_NAME] = Property::VECTOR2;
+  borderVertexFormat[DRIFT_ATTRIBUTE_NAME] = Property::VECTOR2;
+  PropertyBuffer borderVertices = PropertyBuffer::New( borderVertexFormat );
+  borderVertices.SetData( borderVertexData, 16 );
+
+  // Create indices
+  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( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+  geometry.SetType( Geometry::TRIANGLE_STRIP );
+
+  return geometry;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/border/border-visual.h b/dali-toolkit/internal/visuals/border/border-visual.h
new file mode 100644 (file)
index 0000000..c28b041
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef DALI_TOOLKIT_INTERNAL_BORDER_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_BORDER_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class BorderVisual;
+typedef IntrusivePtr< BorderVisual > BorderVisualPtr;
+
+/**
+ * The visual which renders a solid color to the control's quad border fixed to a specified size.
+ *
+ * The following properties are required for create a BorderRender
+ *
+ * | %Property Name  | Type        |
+ * |-----------------|-------------|
+ * | borderColor     | VECTOR4     |
+ * | borderSize      | FLOAT       |
+ * | antiAliasing    | BOOLEAN     |
+ */
+class BorderVisual : public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new border visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static BorderVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  BorderVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~BorderVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  /**
+   * Request the border shader from the factory cache. If fail, create tha shader and add it to cache.
+   * @return The border shader.
+   */
+  Shader GetBorderShader();
+
+  /**
+   * Create the geometry which presents the border.
+   * @return The border geometry
+   */
+  Geometry CreateBorderGeometry();
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+  // Undefined
+  BorderVisual( const BorderVisual& borderRenderer );
+
+  // Undefined
+  BorderVisual& operator=( const BorderVisual& borderRenderer );
+
+private:
+
+  Vector4 mBorderColor;
+  float   mBorderSize;
+
+  Property::Index mBorderColorIndex;
+  Property::Index mBorderSizeIndex;
+
+  bool mAntiAliasing;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_BORDER_VISUAL_H
diff --git a/dali-toolkit/internal/visuals/color/color-visual.cpp b/dali-toolkit/internal/visuals/color/color-visual.cpp
new file mode 100644 (file)
index 0000000..e2a30bd
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2020 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 "color-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/object/handle-devel.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump vec2 extraSize;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = vec4(mixColor, 1.0)*uColor;\n
+  }\n
+);
+
+const char* VERTEX_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec2 extraSize;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump float cornerRadius;\n
+  \n
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    vRectSize = visualSize / 2.0 - cornerRadius;\n
+    vPosition = aPosition* visualSize;\n
+    return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+  \n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+  }\n
+);
+
+//float distance = length( max( abs( position - center ), size ) - size ) - radius;
+const char* FRAGMENT_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float cornerRadius;\n
+  \n
+  void main()\n
+  {\n
+      mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
+      gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
+      gl_FragColor.a *= 1.0 - smoothstep( -1.0, 1.0, dist );\n
+  }\n
+);
+
+const char* VERTEX_SHADER_BLUR_EDGE = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec2 extraSize;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump float blurRadius;\n
+  \n
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize + blurRadius * 2.0;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    vRectSize = visualSize / 2.0;\n
+    vPosition = aPosition* visualSize;\n
+    return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+  \n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_BLUR_EDGE = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float blurRadius;\n
+  \n
+  void main()\n
+  {\n
+      mediump vec2 blur = 1.0 - smoothstep( vRectSize - blurRadius * 2.0, vRectSize, abs( vPosition ) );\n
+      gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
+      gl_FragColor.a *= blur.x * blur.y;\n
+  }\n
+);
+
+}
+
+ColorVisualPtr ColorVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  ColorVisualPtr colorVisualPtr( new ColorVisual( factoryCache ) );
+  colorVisualPtr->SetProperties( properties );
+  return colorVisualPtr;
+}
+
+ColorVisual::ColorVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mBlurRadius( 0.0f ),
+  mRenderIfTransparent( false )
+{
+}
+
+ColorVisual::~ColorVisual()
+{
+}
+
+void ColorVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // By virtue of DoSetProperties being called last, this will override
+  // anything set by Toolkit::Visual::Property::MIX_COLOR
+  Property::Value* colorValue = propertyMap.Find( Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR );
+  if( colorValue )
+  {
+    Vector4 color;
+    if( colorValue->Get( color ) )
+    {
+      Property::Type type = colorValue->GetType();
+      if( type == Property::VECTOR4 )
+      {
+        SetMixColor( color );
+      }
+      else if( type == Property::VECTOR3 )
+      {
+        Vector3 color3(color);
+        SetMixColor( color3 );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR("ColorVisual: mixColor property has incorrect type\n");
+    }
+  }
+
+  Property::Value* renderIfTransparentValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, RENDER_IF_TRANSPARENT_NAME );
+  if( renderIfTransparentValue )
+  {
+    if( ! renderIfTransparentValue->Get( mRenderIfTransparent ) )
+    {
+      DALI_LOG_ERROR( "ColorVisual: renderIfTransparent property has incorrect type: %d\n", renderIfTransparentValue->GetType() );
+    }
+  }
+
+  Property::Value* blurRadiusValue = propertyMap.Find( Toolkit::DevelColorVisual::Property::BLUR_RADIUS, BLUR_RADIUS_NAME );
+  if( blurRadiusValue )
+  {
+    if( !blurRadiusValue->Get( mBlurRadius ) )
+    {
+      DALI_LOG_ERROR( "ColorVisual:DoSetProperties:: BLUR_RADIUS property has incorrect type: %d\n", blurRadiusValue->GetType() );
+    }
+  }
+}
+
+void ColorVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  // Only add the renderer if it's not fully transparent
+  // We cannot avoid creating a renderer as it's used in the base class
+  if( mRenderIfTransparent || mImpl->mMixColor.a > 0.0f )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+  }
+
+  // Color Visual generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void ColorVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::COLOR );
+  map.Insert( Toolkit::ColorVisual::Property::MIX_COLOR, mImpl->mMixColor );
+  map.Insert( Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT, mRenderIfTransparent );
+  map.Insert( Toolkit::DevelColorVisual::Property::BLUR_RADIUS, mBlurRadius );
+}
+
+void ColorVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+
+void ColorVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void ColorVisual::InitializeRenderer()
+{
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+  Shader shader;
+  if( !EqualsZero( mBlurRadius ) )
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER_BLUR_EDGE );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER_BLUR_EDGE, FRAGMENT_SHADER_BLUR_EDGE );
+      mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER_BLUR_EDGE, shader );
+    }
+  }
+  else if( !IsRoundedCornerRequired() )
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+      mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER, shader );
+    }
+  }
+  else
+  {
+    shader = mFactoryCache.GetShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER_ROUNDED_CORNER, FRAGMENT_SHADER_ROUNDED_CORNER );
+      mFactoryCache.SaveShader( VisualFactoryCache::COLOR_SHADER_ROUNDED_CORNER, shader );
+    }
+  }
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  // ColorVisual has it's own index key for mix color - use this instead
+  // of using the new base index to avoid changing existing applications
+  // String keys will get to this property.
+  mImpl->mMixColorIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::ColorVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor) );
+
+  mImpl->mRenderer.RegisterProperty( BLUR_RADIUS_NAME, mBlurRadius );
+
+  if( mImpl->mMixColor.a < 1.f || !EqualsZero( mBlurRadius ) )
+  {
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  }
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/color/color-visual.h b/dali-toolkit/internal/visuals/color/color-visual.h
new file mode 100644 (file)
index 0000000..05c8ba9
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H
+
+/*
+ * Copyright (c) 2020 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 <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ColorVisual;
+typedef IntrusivePtr< ColorVisual > ColorVisualPtr;
+
+/**
+ * The visual which renders a solid color to the control's quad
+ *
+ * The following properties are required for create a ColorRender
+ *
+ * | %Property Name  | Type        |
+ * |-----------------|-------------|
+ * | mixColor        | VECTOR4     |
+ */
+class ColorVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new color visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static ColorVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  ColorVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~ColorVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+private:
+
+  // Undefined
+  ColorVisual( const ColorVisual& colorRenderer );
+
+  // Undefined
+  ColorVisual& operator=( const ColorVisual& colorRenderer );
+
+private:
+
+  float mBlurRadius;         ///< The blur radius
+  bool mRenderIfTransparent; ///< Whether we should render even if the mix-color is transparent.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_COLOR_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp b/dali-toolkit/internal/visuals/gradient/gradient-visual.cpp
new file mode 100644 (file)
index 0000000..53ea041
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2018 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 "gradient-visual.h"
+
+// EXTERNAL INCLUDES
+#include <typeinfo>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/gradient/linear-gradient.h>
+#include <dali-toolkit/internal/visuals/gradient/radial-gradient.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( UNITS )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, OBJECT_BOUNDING_BOX )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::Units, USER_SPACE )
+DALI_ENUM_TO_STRING_TABLE_END( UNITS )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SPREAD_METHOD )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, PAD )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REFLECT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::GradientVisual::SpreadMethod, REPEAT )
+DALI_ENUM_TO_STRING_TABLE_END( SPREAD_METHOD )
+
+// uniform names
+const char * const UNIFORM_ALIGNMENT_MATRIX_NAME( "uAlignmentMatrix" );
+
+// default offset value
+const unsigned int DEFAULT_OFFSET_MINIMUM = 0.0f;
+const unsigned int DEFAULT_OFFSET_MAXIMUM = 1.0f;
+
+VisualFactoryCache::ShaderType GetShaderType( GradientVisual::Type type, Toolkit::GradientVisual::Units::Type units )
+{
+  if( type == GradientVisual::LINEAR )
+  {
+   if( units == Toolkit::GradientVisual::Units::USER_SPACE )
+   {
+     return VisualFactoryCache::GRADIENT_SHADER_LINEAR_USER_SPACE;
+   }
+   return VisualFactoryCache::GRADIENT_SHADER_LINEAR_BOUNDING_BOX;
+  }
+  else if( units == Toolkit::GradientVisual::Units::USER_SPACE )
+  {
+    return VisualFactoryCache::GRADIENT_SHADER_RADIAL_USER_SPACE;
+  }
+
+  return VisualFactoryCache::GRADIENT_SHADER_RADIAL_BOUNDING_BOX;
+}
+
+const char* VERTEX_SHADER[] =
+{
+// vertex shader for gradient units as OBJECT_BOUNDING_BOX
+ DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat3 uAlignmentMatrix;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
+    \n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+  }\n
+),
+
+// vertex shader for gradient units as USER_SPACE
+DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat3 uAlignmentMatrix;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+    \n
+    vTexCoord = (uAlignmentMatrix*vertexPosition.xyw).xy;\n
+  }\n
+)
+};
+
+const char* FRAGMENT_SHADER[] =
+{
+// fragment shader for linear gradient
+DALI_COMPOSE_SHADER(
+  uniform sampler2D sTexture;\n // sampler1D?
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vec2( vTexCoord.y, 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
+  }\n
+),
+
+// fragment shader for radial gradient
+DALI_COMPOSE_SHADER(
+  uniform sampler2D sTexture;\n // sampler1D?
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  varying mediump vec2 vTexCoord;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vec2( length(vTexCoord), 0.5 ) ) * vec4(mixColor, 1.0) * uColor;\n
+  }\n
+)
+};
+
+Dali::WrapMode::Type GetWrapMode( Toolkit::GradientVisual::SpreadMethod::Type spread )
+{
+  switch(spread)
+  {
+    case Toolkit::GradientVisual::SpreadMethod::REPEAT:
+    {
+      return Dali::WrapMode::REPEAT;
+    }
+    case Toolkit::GradientVisual::SpreadMethod::REFLECT:
+    {
+      return Dali::WrapMode::MIRRORED_REPEAT;
+    }
+    case Toolkit::GradientVisual::SpreadMethod::PAD:
+    default:
+    {
+      return Dali::WrapMode::CLAMP_TO_EDGE;
+    }
+  }
+}
+
+} // unnamed namespace
+
+GradientVisualPtr GradientVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  GradientVisualPtr gradientVisualPtr( new GradientVisual( factoryCache ) );
+  gradientVisualPtr->SetProperties( properties );
+  return gradientVisualPtr;
+}
+
+GradientVisual::GradientVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mGradientType( LINEAR ),
+  mIsOpaque( true )
+{
+  mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+}
+
+GradientVisual::~GradientVisual()
+{
+}
+
+void GradientVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  Toolkit::GradientVisual::Units::Type gradientUnits = Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX;
+
+  Property::Value* unitsValue = propertyMap.Find( Toolkit::GradientVisual::Property::UNITS, UNITS_NAME );
+  if( unitsValue )
+  {
+    Scripting::GetEnumerationProperty( *unitsValue, UNITS_TABLE, UNITS_TABLE_COUNT, gradientUnits );
+  }
+
+  mGradientType = LINEAR;
+  if( propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME ) )
+  {
+    mGradientType = RADIAL;
+  }
+
+  if( NewGradient( mGradientType, propertyMap ) )
+  {
+    mGradient->SetGradientUnits( gradientUnits );
+    mGradientTransform = mGradient->GetAlignmentTransform();
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Fail to provide valid properties to create a GradientVisual object\n" );
+  }
+}
+
+void GradientVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void GradientVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Gradient Visual generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void GradientVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::GRADIENT );
+  map.Insert( Toolkit::GradientVisual::Property::UNITS, mGradient->GetGradientUnits() );
+  map.Insert( Toolkit::GradientVisual::Property::SPREAD_METHOD, mGradient->GetSpreadMethod() );
+
+  const Vector<Gradient::GradientStop>& stops( mGradient->GetStops() );
+  Property::Array offsets;
+  Property::Array colors;
+  for( unsigned int i=0; i<stops.Count(); i++ )
+  {
+    offsets.PushBack( stops[i].mOffset );
+    if( EqualsZero(stops[i].mStopColor.a) )
+    {
+      colors.PushBack( Vector4::ZERO );
+    }
+    else
+    {
+      colors.PushBack( Vector4( stops[i].mStopColor.r / stops[i].mStopColor.a,
+                                stops[i].mStopColor.g / stops[i].mStopColor.a,
+                                stops[i].mStopColor.b / stops[i].mStopColor.a,
+                                stops[i].mStopColor.a));
+    }
+  }
+
+  map.Insert( Toolkit::GradientVisual::Property::STOP_OFFSET, offsets );
+  map.Insert( Toolkit::GradientVisual::Property::STOP_COLOR, colors );
+
+  if( &typeid( *mGradient ) == &typeid(LinearGradient) )
+  {
+    LinearGradient* gradient = static_cast<LinearGradient*>( mGradient.Get() );
+    map.Insert( Toolkit::GradientVisual::Property::START_POSITION, gradient->GetStartPosition() );
+    map.Insert( Toolkit::GradientVisual::Property::END_POSITION, gradient->GetEndPosition() );
+  }
+  else // if( &typeid( *mGradient ) == &typeid(RadialGradient) )
+  {
+    RadialGradient* gradient = static_cast<RadialGradient*>( mGradient.Get() );
+    map.Insert( Toolkit::GradientVisual::Property::CENTER, gradient->GetCenter() );
+    map.Insert( Toolkit::GradientVisual::Property::RADIUS, gradient->GetRadius() );
+  }
+}
+
+void GradientVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void GradientVisual::InitializeRenderer()
+{
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+
+  Toolkit::GradientVisual::Units::Type gradientUnits = mGradient->GetGradientUnits();
+  VisualFactoryCache::ShaderType shaderType = GetShaderType( mGradientType, gradientUnits );
+  Shader shader = mFactoryCache.GetShader( shaderType );
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER[gradientUnits], FRAGMENT_SHADER[ mGradientType ] );
+    mFactoryCache.SaveShader( shaderType, shader );
+  }
+
+  //Set up the texture set
+  TextureSet textureSet = TextureSet::New();
+  Dali::Texture lookupTexture = mGradient->GenerateLookupTexture();
+  textureSet.SetTexture( 0u, lookupTexture );
+  Dali::WrapMode::Type wrap = GetWrapMode( mGradient->GetSpreadMethod() );
+  Sampler sampler = Sampler::New();
+  sampler.SetWrapMode(  wrap, wrap  );
+  textureSet.SetSampler( 0u, sampler );
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  mImpl->mRenderer.SetTextures( textureSet );
+
+  // If opaque then no need to have blending
+  if( mIsOpaque )
+  {
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::OFF );
+  }
+
+  mImpl->mRenderer.RegisterProperty( UNIFORM_ALIGNMENT_MATRIX_NAME, mGradientTransform );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+bool GradientVisual::NewGradient(Type gradientType, const Property::Map& propertyMap)
+{
+  if( gradientType == LINEAR )
+  {
+    Property::Value* startPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::START_POSITION, START_POSITION_NAME );
+    Property::Value* endPositionValue = propertyMap.Find( Toolkit::GradientVisual::Property::END_POSITION, END_POSITION_NAME );
+    Vector2 startPosition;
+    Vector2 endPosition;
+
+    if( startPositionValue && startPositionValue->Get(startPosition)
+     && endPositionValue && endPositionValue->Get( endPosition ) )
+    {
+      mGradient = new LinearGradient( startPosition, endPosition );
+    }
+    else
+    {
+      return false;
+    }
+  }
+  else // type==RADIAL
+  {
+    Property::Value* centerValue = propertyMap.Find( Toolkit::GradientVisual::Property::CENTER, CENTER_NAME );
+    Property::Value* radiusValue = propertyMap.Find( Toolkit::GradientVisual::Property::RADIUS, RADIUS_NAME );
+    Vector2 center;
+    float radius;
+    if( centerValue && centerValue->Get(center)
+        && radiusValue && radiusValue->Get(radius) )
+    {
+      mGradient = new RadialGradient( center, radius );
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+  unsigned int numValidStop = 0u;
+  Property::Value* stopOffsetValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_OFFSET, STOP_OFFSET_NAME );
+  Property::Value* stopColorValue = propertyMap.Find( Toolkit::GradientVisual::Property::STOP_COLOR, STOP_COLOR_NAME );
+  if( stopColorValue )
+  {
+    Vector<float> offsetArray;
+    Property::Array* colorArray = stopColorValue->GetArray();
+    if( colorArray )
+    {
+      GetStopOffsets( stopOffsetValue, offsetArray );
+      unsigned int numStop = offsetArray.Count() < colorArray->Count() ?
+                             offsetArray.Count() : colorArray->Count();
+      Vector4 color;
+      for( unsigned int i=0; i<numStop; i++ )
+      {
+        if( (colorArray->GetElementAt(i)).Get(color) )
+        {
+          mGradient->AddStop( offsetArray[i], Vector4(color.r*color.a, color.g*color.a, color.b*color.a, color.a));
+          numValidStop++;
+          if( ! Equals( color.a, 1.0f, Math::MACHINE_EPSILON_1 ) )
+          {
+            mIsOpaque = false;
+          }
+        }
+      }
+    }
+  }
+
+  if( numValidStop < 1u ) // no valid stop
+  {
+    return false;
+  }
+
+  Property::Value* spread = propertyMap.Find( Toolkit::GradientVisual::Property::SPREAD_METHOD, SPREAD_METHOD_NAME );
+  // The default spread method is PAD. Only need to set new spread if it's anything else.
+  if( spread )
+  {
+    Toolkit::GradientVisual::SpreadMethod::Type spreadMethod = Toolkit::GradientVisual::SpreadMethod::PAD;
+    if( Scripting::GetEnumerationProperty( *spread, SPREAD_METHOD_TABLE, SPREAD_METHOD_TABLE_COUNT, spreadMethod ) )
+    {
+      mGradient->SetSpreadMethod( spreadMethod );
+    }
+  }
+
+  return true;
+}
+
+void GradientVisual::GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets)
+{
+
+  if ( value ) // Only check valve type if a valid Property has been passed in
+  {
+    switch ( value->GetType() )
+    {
+      case Property::VECTOR2:
+      {
+        Vector2 offset2;
+        value->Get( offset2 );
+        stopOffsets.PushBack( offset2.x );
+        stopOffsets.PushBack( offset2.y );
+        break;
+      }
+      case Property::VECTOR3:
+      {
+        Vector3 offset3;
+        value->Get( offset3 );
+        stopOffsets.PushBack( offset3.x );
+        stopOffsets.PushBack( offset3.y );
+        stopOffsets.PushBack( offset3.z );
+        break;
+      }
+      case Property::VECTOR4:
+      {
+        Vector4 offset4;
+        value->Get( offset4 );
+        stopOffsets.PushBack( offset4.x );
+        stopOffsets.PushBack( offset4.y );
+        stopOffsets.PushBack( offset4.z );
+        stopOffsets.PushBack( offset4.w );
+        break;
+      }
+      case Property::ARRAY:
+      {
+        Property::Array* offsetArray = value->GetArray();
+        if( offsetArray )
+        {
+          unsigned int numStop = offsetArray->Count();
+          float offset;
+          for( unsigned int i=0; i<numStop; i++ )
+          {
+            if( offsetArray->GetElementAt(i).Get(offset) )
+            {
+              stopOffsets.PushBack( offset );
+            }
+          }
+        }
+        break;
+      }
+      default:
+      {
+        DALI_LOG_WARNING("GetStopOffsets passed unsupported Property Map\n");
+        // Unsupported Type
+      }
+    }
+  }
+
+  if ( stopOffsets.Empty() )
+  {
+    // Set default offset if none set by Property system, need a minimum and maximum
+    stopOffsets.PushBack( DEFAULT_OFFSET_MINIMUM );
+    stopOffsets.PushBack( DEFAULT_OFFSET_MAXIMUM );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/gradient/gradient-visual.h b/dali-toolkit/internal/visuals/gradient/gradient-visual.h
new file mode 100644 (file)
index 0000000..c67ee87
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GRADIENT_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_GRADIENT_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/gradient/gradient.h>
+
+namespace Dali
+{
+class Vector2;
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class Gradient;
+class GradientVisual;
+typedef IntrusivePtr< GradientVisual > GradientVisualPtr;
+
+/**
+ * The visual which renders smooth transition of colors to the control's quad.
+ * It supports two types of gradients: linear and radial.
+ *
+ * The following properties are essential for create a LINEAR GradientRender
+ *
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | startPosition           | VECTOR2          |
+ * | endPosition             | VECTOR2          |
+ * | stopColor               | ARRAY of VECTOR4 |
+ *
+ * The following properties are essential for create a RADIAL GradientRender
+ *
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | center                  | VECTOR2          |
+ * | radius                  | FLOAT            |
+ * | stopColor               | ARRAY of VECTOR4 |
+ *
+ * The following properties are optional for both LINEAR and RADIAL GradientRender.
+ *
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | stopOffset              | ARRAY of FLOAT   |
+ * | units                   | STRING           |
+ * | spreadMethod            | STRING           |
+ *
+ * Valid values for units are 'userSpace' and 'objectBoundingBox'.
+ * Valid values for spreadMethod are 'pad', 'repeat' and 'reflect.'
+ * If not provided, 'objectBoundingBox' is used as default gradient units, and 'pad' is used as default spread method.
+ */
+class GradientVisual: public Visual::Base
+{
+public:
+
+  /**
+   * Types of the gradient
+   */
+  enum Type
+  {
+    LINEAR,
+    RADIAL
+  };
+
+  /**
+   * @brief Create a new gradient visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static GradientVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  GradientVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~GradientVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+private:
+
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  /**
+   * New a gradient object with the given property map.
+   *
+   * @return True if the property map provides valid properties to create a gradient. Otherwise, returns false.
+   */
+  bool NewGradient(Type gradientType, const Property::Map& propertyMap);
+
+  /**
+   * Get the stop-offsets from the property.
+   * The valid property type are ARRAY, VECTOR2, VECTOR3, VECTOR4.
+   *
+   * @param[in] value The property value of stop-offsets
+   * @param[out] stopOffsets The vector contains the stop offset values.
+   */
+  static void GetStopOffsets(const Property::Value* value, Vector<float>& stopOffsets);
+
+  // Undefined
+  GradientVisual( const GradientVisual& gradientVisual );
+
+  // Undefined
+  GradientVisual& operator=( const GradientVisual& gradientVisual );
+
+private:
+
+  Matrix3 mGradientTransform;
+  IntrusivePtr<Gradient> mGradient;
+  Type mGradientType;
+  bool mIsOpaque; ///< Set to false if any of the stop colors are not opaque
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_GRADIENT_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/gradient/gradient.cpp b/dali-toolkit/internal/visuals/gradient/gradient.cpp
new file mode 100644 (file)
index 0000000..2c90e52
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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 "gradient.h"
+
+#include <algorithm>    // std::sort
+#include <dali/public-api/math/vector4.h>
+
+namespace
+{
+// The maximum width of the lookup texture ( it is a 1-dimension texture with the height as 1 )
+const unsigned int MAXIMUM_TEXTURE_RESOLUTION(128u);
+}
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+Gradient::Gradient()
+: mGradientUnits( Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX ),
+  mSpreadMethod( Toolkit::GradientVisual::SpreadMethod::PAD )
+{}
+
+Gradient::~Gradient()
+{}
+
+void Gradient::AddStop( float offset, const Vector4& color )
+{
+  // the offset is clamped to the range [0.0, 1.0]
+  mGradientStops.PushBack( GradientStop( Clamp( offset, 0.f, 1.f ), color) );
+}
+
+const Vector<Gradient::GradientStop>& Gradient::GetStops()
+{
+  return mGradientStops;
+}
+
+void Gradient::SetGradientUnits( Toolkit::GradientVisual::Units::Type gradientUnits )
+{
+  mGradientUnits = gradientUnits;
+}
+
+Toolkit::GradientVisual::Units::Type Gradient::GetGradientUnits() const
+{
+  return mGradientUnits;
+}
+
+void Gradient::SetSpreadMethod( Toolkit::GradientVisual::SpreadMethod::Type spread )
+{
+  mSpreadMethod = spread;
+}
+
+Toolkit::GradientVisual::SpreadMethod::Type Gradient::GetSpreadMethod() const
+{
+  return mSpreadMethod;
+}
+
+const Matrix3& Gradient::GetAlignmentTransform() const
+{
+  return mAlignmentTransform;
+}
+
+/**
+ * Following the SVG gradient.
+ *
+ * Not only the spread method decides the texture wrap mode:
+ *    PAD-->GL_CLAMP_TO_EDGE; REPEAT-->GL_REPEAT; REFLECT-->GL_MIRROR_REPEAT
+ *
+ *  If the stops have not covered the whole zero to one range,
+ *  the REPEAT spread behaves different from the two others in the lookup texture generation.
+ */
+Dali::Texture Gradient::GenerateLookupTexture()
+{
+  std::sort( mGradientStops.Begin(), mGradientStops.End() );
+
+  unsigned int numStops = mGradientStops.Count();
+
+  /**
+   * If the stops have not covered the whole zero to one range,
+   * for PAD and REFLECT, use the color of the first stop to fill the range  [0.0, first stop offset)
+   *                  and use the color of the last stop to fill the range (last stop offset, 1.0]
+   * for REPEAT, mix the two color of the first and last stop to fill the remainder
+   */
+  bool tempFirstStop = false;
+  if( mGradientStops[0].mOffset > 0.f )
+  {
+    tempFirstStop = true;
+    Vector4 firstStopColor( mGradientStops[0].mStopColor ); // If spread method is PAD or REFLECT
+    if( mSpreadMethod == Toolkit::GradientVisual::SpreadMethod::REPEAT )
+    {
+      firstStopColor = ( mGradientStops[0].mStopColor * (1.f-mGradientStops[numStops-1].mOffset)
+                       + mGradientStops[numStops-1].mStopColor  * mGradientStops[0].mOffset )
+                   / ( mGradientStops[0].mOffset+1.f-mGradientStops[numStops-1].mOffset);
+    }
+
+    mGradientStops.Insert( mGradientStops.Begin(), GradientStop(0.f, firstStopColor) );
+    numStops++;
+  }
+
+  bool tempLastStop = false;
+  if( mGradientStops[numStops-1].mOffset < 1.f )
+  {
+    tempLastStop = true;
+    Vector4 lastStopColor( mGradientStops[numStops-1].mStopColor ); // If spread method is PAD or REFLECT
+    if( mSpreadMethod == Toolkit::GradientVisual::SpreadMethod::REPEAT )
+    {
+      lastStopColor = mGradientStops[0].mStopColor;
+    }
+    mGradientStops.PushBack( GradientStop(1.f, lastStopColor) );
+    numStops++;
+  }
+
+  /**
+   * Generate the pixels with the color transit from one stop to next.
+   */
+  unsigned int resolution = EstimateTextureResolution();
+
+  unsigned int bufferSize = resolution * 4u;
+  unsigned char* pixels = new unsigned char[ bufferSize ];
+  PixelData pixelData = PixelData::New( pixels, bufferSize, resolution, 1u, Pixel::RGBA8888, PixelData::DELETE_ARRAY );
+
+  int segmentStart = 0;
+  int segmentEnd = 0;
+  int k = 0;
+  float length = static_cast<float>(resolution);
+  for( unsigned int i=0; i<numStops-1u; i++ )
+  {
+    segmentEnd = floorf(mGradientStops[i+1].mOffset * length + 0.5f);
+    if( segmentEnd == segmentStart )
+    {
+      continue;
+    }
+    float segmentWidth = static_cast<float>(segmentEnd-segmentStart);
+
+    for( int j = segmentStart; j<segmentEnd; j++ )
+    {
+      float ratio = static_cast<float>(j-segmentStart)/(segmentWidth - 1);
+      Vector4 currentColor = mGradientStops[i].mStopColor * (1.f-ratio) + mGradientStops[i+1].mStopColor * ratio;
+      pixels[k*4] = static_cast<unsigned char>( 255.f * Clamp( currentColor.r, 0.f, 1.f ) );
+      pixels[k*4+1] = static_cast<unsigned char>( 255.f * Clamp( currentColor.g, 0.f, 1.f ) );
+      pixels[k*4+2] = static_cast<unsigned char>( 255.f * Clamp( currentColor.b, 0.f, 1.f ) );
+      pixels[k*4+3] = static_cast<unsigned char>( 255.f * Clamp( currentColor.a, 0.f, 1.f ) );
+      k++;
+    }
+    segmentStart = segmentEnd;
+  }
+
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, Pixel::RGBA8888, resolution, 1u );
+  texture.Upload( pixelData );
+
+  // remove the stops added temporarily for generating the pixels, as the spread method might get changed later
+  if( tempLastStop )
+  {
+    mGradientStops.Erase( mGradientStops.Begin()+numStops-1 );
+  }
+  if( tempFirstStop )
+  {
+    mGradientStops.Erase( mGradientStops.Begin());
+  }
+
+  return texture;
+}
+
+unsigned int Gradient::EstimateTextureResolution()
+{
+  float minInterval = 1.0;
+  for( unsigned int i=0, numStops = mGradientStops.Count(); i<numStops-1u; i++ )
+  {
+    float interval = mGradientStops[i+1].mOffset - mGradientStops[i].mOffset;
+    minInterval = interval > minInterval ? minInterval:interval;
+  }
+  // Use at least three pixels for each segment between two stops
+  unsigned int resolution = static_cast<int>(3.f/(minInterval+Math::MACHINE_EPSILON_100)+0.5f);
+  // Clamp the resolution to handle the overlapping stops
+  if( resolution > MAXIMUM_TEXTURE_RESOLUTION )
+  {
+    return MAXIMUM_TEXTURE_RESOLUTION;
+  }
+
+  return resolution;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/gradient/gradient.h b/dali-toolkit/internal/visuals/gradient/gradient.h
new file mode 100644 (file)
index 0000000..d6dd7f4
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef DALI_TOOLKIT_INTERNAL_GRADIENT_H
+#define DALI_TOOLKIT_INTERNAL_GRADIENT_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/math/matrix3.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/gradient-visual-properties.h>
+
+namespace Dali
+{
+
+class Vector4;
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Gradients consist of continuously smooth color transitions along a vector from one color to another,
+ * possibly followed by additional transitions along the same vector to other colors.
+ */
+class Gradient : public RefObject
+{
+public:
+
+  /**
+   * The stop node tells the gradient what color it should be at certain position.
+   */
+  struct GradientStop
+  {
+    GradientStop( float offset, const Vector4& color )
+    : mOffset( offset ), mStopColor( color )
+    {}
+
+    bool operator<(const GradientStop& rhs) const
+    {
+      return mOffset < rhs.mOffset;
+    }
+
+    float   mOffset;     // A value ranging from 0 to 1 to indicate where the gradient stop is placed.
+    Vector4 mStopColor;  // The color to use at this gradient stop
+  };
+
+public:
+
+  /**
+   * Add a gradient stop.
+   *
+   * @param[in] offset The position to place the stop.
+   * @param[in] color  The color to use at this stop.
+   */
+  void AddStop(float offset, const Vector4& color);
+
+  /**
+   * Get the gradient stops.
+   * @return The vector of gradient stops.
+   */
+  const Vector<GradientStop>& GetStops();
+
+  /**
+   * Set the coordinate system used by the gradient attributes.
+   * @param[in] gradientUnits The the attributes are defined using the current user coordinate system or the bounding box of the shape.
+   */
+  void SetGradientUnits( Toolkit::GradientVisual::Units::Type gradientUnits );
+
+  /**
+   * Get the coordinate system used by the gradient attributes.
+   * @return USER_SPACE_ON_USE or OBJECT_BOUNDING_BOX
+   */
+  Toolkit::GradientVisual::Units::Type GetGradientUnits() const;
+
+  /**
+   * Indicates what happens if the gradient starts or ends inside the bounds of the target rectangle.
+   * If not specified, the effect is as if a value of 'pad' were specified
+   *
+   * @param[in] spread The method to fill the remainder of target region which is outside the gradient bounds
+   */
+  void SetSpreadMethod( Toolkit::GradientVisual::SpreadMethod::Type spread );
+
+  /**
+   * Get the filling method for the the remainder of target region which is outside the gradient boun.
+   * @return PAD, REFLECT or REPEAT
+   */
+  Toolkit::GradientVisual::SpreadMethod::Type GetSpreadMethod() const;
+
+  /**
+   * Get the transformation matrix to align the vertices with the gradient line/circle
+   * @ return the aligning transformation matrix
+   */
+  const Matrix3& GetAlignmentTransform() const;
+
+  /**
+   * Generate the lookup texture with the gradient stops.
+   * @return The lookup texture which transit smoothly between stops.
+   */
+  Dali::Texture GenerateLookupTexture();
+
+private:
+
+  /**
+   * Estimate the resolution of the lookup texture.
+   * Note: Only call this function after the gradient stops are sorted in order.
+   */
+  unsigned int EstimateTextureResolution();
+
+protected:
+
+  /**
+   * Construct a new Gradient object
+   * Called in the constructor of subclasses
+   */
+  Gradient();
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Gradient();
+
+  // Undefined
+  Gradient( const Gradient& gradient );
+
+  // Undefined
+  Gradient& operator=( const Gradient& handle );
+
+protected:
+
+  Vector<GradientStop>                        mGradientStops;
+  Matrix3                                     mAlignmentTransform;
+  Toolkit::GradientVisual::Units::Type        mGradientUnits;
+  Toolkit::GradientVisual::SpreadMethod::Type mSpreadMethod;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_GRADIENT_RENDERER_H
diff --git a/dali-toolkit/internal/visuals/gradient/linear-gradient.cpp b/dali-toolkit/internal/visuals/gradient/linear-gradient.cpp
new file mode 100644 (file)
index 0000000..d1453a6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 "linear-gradient.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+LinearGradient::LinearGradient( const Vector2& startPosition, const Vector2& endPosition )
+: Gradient()
+{
+  SetStartAndEndPosition( startPosition, endPosition );
+}
+
+LinearGradient::~LinearGradient()
+{}
+
+void LinearGradient::SetStartAndEndPosition( const Vector2& startPosition, const Vector2& endPosition )
+{
+  mStartPosition = startPosition;
+  mEndPosition = endPosition;
+
+  // Calculate the transform aligning to the gradient line
+  float dx = mEndPosition.x - mStartPosition.x;
+  float dy = mEndPosition.y - mStartPosition.y;
+  Matrix3 alignMatrix( dy, -dx, 0.f, dx, dy, 0.f, mStartPosition.x, mStartPosition.y, 1.f );
+  alignMatrix.Invert();
+
+  mAlignmentTransform = alignMatrix;
+}
+
+const Vector2& LinearGradient::GetStartPosition() const
+{
+  return mStartPosition;
+}
+
+const Vector2& LinearGradient::GetEndPosition() const
+{
+  return mEndPosition;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/gradient/linear-gradient.h b/dali-toolkit/internal/visuals/gradient/linear-gradient.h
new file mode 100644 (file)
index 0000000..187c244
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_TOOLKIT_INTERNAL_LINEAR_GRADIENT_H
+#define DALI_TOOLKIT_INTERNAL_LINEAR_GRADIENT_H
+
+/*
+ * 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 <dali-toolkit/internal/visuals/gradient/gradient.h>
+
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Linear gradients change color evenly along a straight line.
+ * The gradient is defined by an axis (the gradient line) at any specified angles.
+ */
+class LinearGradient : public Gradient
+{
+public:
+
+  /**
+   * Constructor.
+   * @param[in] startPosition The starting point onto which the 0% gradient stops are mapped.
+   * @param[in] endPosition The ending point r onto which the 100% gradient stops are mapped.
+   */
+  LinearGradient( const Vector2& startPosition, const Vector2& endPosition );
+
+  /**
+   * Destructor.
+   */
+  virtual ~LinearGradient();
+
+  /**
+   * Set the starting and ending points of the vector onto which the gradient stops are mapped.
+   * @param[in] startPosition The starting point of the gradient vector.
+   * @param[in] endPosition The ending point of the gradient vector.
+   */
+  void SetStartAndEndPosition( const Vector2& startPosition, const Vector2& endPosition );
+
+  /**
+   * Get the stating point of the gradient vector.
+   * @return The stating point of the gradient vector.
+   */
+  const Vector2& GetStartPosition() const;
+
+  /**
+   * Get the ending point of the gradient vector.
+   * @return The ending point of the gradient vector.
+   */
+  const Vector2& GetEndPosition() const;
+
+private:
+
+  // Undefined
+  LinearGradient( const LinearGradient& gradient );
+
+  // Undefined
+  LinearGradient& operator=( const LinearGradient& handle );
+
+private:
+
+  Vector2 mStartPosition;
+  Vector2 mEndPosition;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_LINEAR_GRADIENT_H */
diff --git a/dali-toolkit/internal/visuals/gradient/radial-gradient.cpp b/dali-toolkit/internal/visuals/gradient/radial-gradient.cpp
new file mode 100644 (file)
index 0000000..e986612
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 "radial-gradient.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+RadialGradient::RadialGradient( const Vector2& center, float radius )
+: Gradient()
+{
+  SetCenterAndRadius( center, radius );
+}
+
+RadialGradient::~RadialGradient()
+{}
+
+void RadialGradient::SetCenterAndRadius( const Vector2& center, float radius )
+{
+  mCenter = center;
+  mRadius = radius;
+
+  // Calculate the transform aligning to the circle
+  Matrix3 alignMatrix( mRadius, 0.f, 0.f, 0.f, mRadius, 0.f, mCenter.x, mCenter.y, 1.f );
+  alignMatrix.Invert();
+
+  mAlignmentTransform = alignMatrix;
+}
+
+const Vector2& RadialGradient::GetCenter() const
+{
+  return mCenter;
+}
+
+float RadialGradient::GetRadius() const
+{
+  return mRadius;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/gradient/radial-gradient.h b/dali-toolkit/internal/visuals/gradient/radial-gradient.h
new file mode 100644 (file)
index 0000000..6e2e35e
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_TOOLKIT_INTERNAL_RADIAL_GRADIENT_H
+#define DALI_TOOLKIT_INTERNAL_RADIAL_GRADIENT_H
+
+/*
+ * 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 <dali-toolkit/internal/visuals/gradient/gradient.h>
+
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * Radial gradients change color circularly.
+ * The color transition starts from the center of the circle and distribute outwardly.
+ */
+class RadialGradient : public Gradient
+{
+public:
+
+  /**
+   * Contructor.
+   * @param[in] center The center of the gradient circle onto which the 0% gradient stop is mapped.
+   * @param[in] radius The radius of the outmost circle onto which the 100% gradient stop is mapped.
+   */
+  RadialGradient( const Vector2& center, float radius );
+
+  /**
+   * Destructor.
+   */
+  virtual ~RadialGradient();
+
+  /**
+   * Set the center and radius of the outermost circle for the radial gradient.
+   * @param[in] center The center of the gradient circle onto which the 0% gradient stop is mapped.
+   * @param[in] radius The radius of the outmost circle onto which the 100% gradient stop is mapped.
+   */
+  void SetCenterAndRadius( const Vector2& center, float radius );
+
+  /**
+   * Get the center of the gradient circle.
+   * @return The center of the gradient circle.
+   */
+  const Vector2& GetCenter() const;
+
+  /**
+   * Get the radius of the outmost gradient circle.
+   * @return The radius of the outmost gradient circle.
+   */
+  float GetRadius() const;
+
+private:
+
+  // Undefined
+  RadialGradient( const RadialGradient& gradient );
+
+  // Undefined
+  RadialGradient& operator=( const RadialGradient& handle );
+
+private:
+
+  Vector2 mCenter;
+  float   mRadius;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_RADIAL_GRADIENT_H */
diff --git a/dali-toolkit/internal/visuals/image-atlas-manager.cpp b/dali-toolkit/internal/visuals/image-atlas-manager.cpp
new file mode 100644 (file)
index 0000000..2e4dfb4
--- /dev/null
@@ -0,0 +1,155 @@
+ /*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "image-atlas-manager.h"
+
+// EXTERNAL HEADER
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const uint32_t DEFAULT_ATLAS_SIZE( 1024u ); // this size can fit 8 by 8 images of average size 128*128
+const uint32_t MAX_ITEM_SIZE( 512u  );
+const uint32_t MAX_ITEM_AREA( MAX_ITEM_SIZE*MAX_ITEM_SIZE  );
+}
+
+ImageAtlasManager::ImageAtlasManager()
+: mBrokenImageUrl( "" )
+{
+}
+
+ImageAtlasManager::~ImageAtlasManager()
+{
+}
+
+TextureSet ImageAtlasManager::Add( Vector4& textureRect,
+                                 const std::string& url,
+                                 ImageDimensions& size,
+                                 FittingMode::Type fittingMode,
+                                 bool orientationCorrection,
+                                 AtlasUploadObserver* atlasUploadObserver )
+{
+  ImageDimensions dimensions = size;
+  ImageDimensions zero;
+  if( size == zero )
+  {
+    dimensions = Dali::GetClosestImageSize( url );
+  }
+
+  // big image, atlasing is not applied
+  if( static_cast<uint32_t>(dimensions.GetWidth()) * static_cast<uint32_t>(dimensions.GetHeight()) > MAX_ITEM_AREA
+      || dimensions.GetWidth()>DEFAULT_ATLAS_SIZE
+      || dimensions.GetHeight()>DEFAULT_ATLAS_SIZE)
+  {
+    return TextureSet();
+  }
+  size = dimensions;
+
+  unsigned int i = 0;
+  for( AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+  {
+    if( (*iter).Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver ) )
+    {
+      return mTextureSetList[i];
+    }
+    i++;
+  }
+
+  CreateNewAtlas();
+  mAtlasList.back().Upload( textureRect, url, size, fittingMode, orientationCorrection, atlasUploadObserver );
+  return mTextureSetList.back();
+}
+
+TextureSet ImageAtlasManager::Add( Vector4& textureRect,
+                                   PixelData pixelData )
+{
+
+  // big buffer, atlasing is not applied
+  if( static_cast<uint32_t>(pixelData.GetWidth()) * static_cast<uint32_t>(pixelData.GetHeight()) > MAX_ITEM_AREA
+      || pixelData.GetWidth()>DEFAULT_ATLAS_SIZE
+      || pixelData.GetHeight()>DEFAULT_ATLAS_SIZE )
+  {
+    return TextureSet();
+  }
+
+  unsigned int i = 0;
+  for( AtlasContainer::iterator iter = mAtlasList.begin(); iter != mAtlasList.end(); ++iter)
+  {
+    if( (*iter).Upload( textureRect, pixelData ) )
+    {
+      return mTextureSetList[i];
+    }
+    i++;
+  }
+
+  CreateNewAtlas();
+  mAtlasList.back().Upload( textureRect, pixelData );
+  return mTextureSetList.back();
+
+}
+
+void ImageAtlasManager::Remove( TextureSet textureSet, const Vector4& textureRect )
+{
+  unsigned int i = 0;
+  for( TextureSetContainer::iterator iter = mTextureSetList.begin(); iter != mTextureSetList.end(); ++iter)
+  {
+    if( (*iter) == textureSet )
+    {
+      mAtlasList[i].Remove(textureRect);
+      return;
+    }
+    i++;
+  }
+}
+
+void ImageAtlasManager::SetBrokenImage( const std::string& brokenImageUrl )
+{
+  if( !brokenImageUrl.empty() )
+  {
+    mBrokenImageUrl = brokenImageUrl;
+  }
+}
+
+void ImageAtlasManager::CreateNewAtlas()
+{
+  Toolkit::ImageAtlas newAtlas = Toolkit::ImageAtlas::New( DEFAULT_ATLAS_SIZE, DEFAULT_ATLAS_SIZE  );
+  if( !mBrokenImageUrl.empty() )
+  {
+    newAtlas.SetBrokenImage( mBrokenImageUrl );
+  }
+  mAtlasList.push_back( newAtlas );
+  TextureSet textureSet = TextureSet::New();
+  textureSet.SetTexture( 0u, newAtlas.GetAtlas() );
+  mTextureSetList.push_back( textureSet );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/image-atlas-manager.h b/dali-toolkit/internal/visuals/image-atlas-manager.h
new file mode 100644 (file)
index 0000000..05ed3a5
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_H
+#define DALI_TOOLKIT_IMAGE_ATLAS_MANAGER_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+class AtlasUploadObserver;
+
+namespace Internal
+{
+
+/**
+ * The manager for automatic image atlasing. Owned by VisualFactory
+ */
+class ImageAtlasManager : public RefObject
+{
+public:
+  typedef std::vector< Toolkit::ImageAtlas > AtlasContainer;
+  typedef std::vector< TextureSet > TextureSetContainer;
+
+public:
+
+  /**
+   * Construtor
+   *
+   */
+  ImageAtlasManager();
+
+  /**
+   * @brief Add an image to the atlas.
+   *
+   * @note To make the atlasing efficient, an valid size should be provided.
+   *       If size is not provided, then the image file will be opened to read the actual size for loading.
+   *
+   * SamplingMode::BOX_THEN_LINEAR is used to sampling pixels from the input image while fitting it to desired size.
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] url The URL of the resource image file to use.
+   * @param [in, out] size The width and height to fit the loaded image to.
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+   * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+   * @param [in] atlasUploadObserver The object to observe the uploading state inside ImageAtlas.
+   * @return The texture set containing the image.
+   */
+  TextureSet Add( Vector4& textureRect,
+                  const std::string& url,
+                  ImageDimensions& size,
+                  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+                  bool orientationCorrection = true,
+                  AtlasUploadObserver* atlasUploadObserver = NULL );
+  /**
+   * @brief Add a pixel buffer to the atlas
+   *
+   * @param [out] textureRect The texture area of the resource image in the atlas.
+   * @param [in] pixelData The pixel data.
+   * @return The texture set containing the image.
+   */
+  TextureSet Add( Vector4& textureRect,
+                  PixelData pixelData );
+
+  /**
+   * Remove the image at the given rectangle from the texture set.
+   *
+   * @param [in] textureSet The texture set containing the atlas image.
+   * @param [in] textureRect The texture area to be removed.
+   */
+  void Remove( TextureSet textureSet, const Vector4& textureRect );
+
+  /**
+   * @brief Set the broken image which is used to replace the image if loading fails.
+   *
+   * @param[in] brokenImageUrl The url of the broken image.
+   */
+  void SetBrokenImage( const std::string& brokenImageUrl );
+
+  /**
+   * @brief Get shader
+   */
+  Shader GetShader() const;
+
+private:
+
+  /**
+   * @brief Create a new atlas.
+   *
+   * This method is called when the newly added image or pixel buffer cannot fit into the current atlas list.
+   */
+  void CreateNewAtlas();
+
+protected:
+
+  /**
+   * Destructor
+   */
+  virtual ~ImageAtlasManager();
+
+  /**
+   * Undefined copy constructor.
+   */
+  ImageAtlasManager(const ImageAtlasManager&);
+
+  /**
+   * Undefined assignment operator.
+   */
+  ImageAtlasManager& operator=(const ImageAtlasManager& rhs);
+
+
+private:
+
+  AtlasContainer    mAtlasList;
+  TextureSetContainer mTextureSetList;
+  std::string       mBrokenImageUrl;
+
+};
+
+} // name Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ATLAS_MANAGER_H
diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp b/dali-toolkit/internal/visuals/image-visual-shader-factory.cpp
new file mode 100644 (file)
index 0000000..7fe979f
--- /dev/null
@@ -0,0 +1,253 @@
+ /*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec4 pixelArea;
+  varying mediump vec2 vTexCoord;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump vec2 extraSize;\n
+\n
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+\n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+    vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_NO_ATLAS = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+  \n
+  void main()\n
+  {\n
+      gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_ATLAS_CLAMP = DALI_COMPOSE_SHADER(
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    uniform mediump vec4 uAtlasRect;\n
+    uniform lowp vec4 uColor;\n
+    uniform lowp vec3 mixColor;\n
+    uniform lowp float preMultipliedAlpha;\n
+    \n
+    void main()\n
+    {\n
+        mediump vec2 texCoord = clamp( mix( uAtlasRect.xy, uAtlasRect.zw, vTexCoord ), uAtlasRect.xy, uAtlasRect.zw );\n
+        gl_FragColor = texture2D( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );\n
+     }\n
+);
+
+const char* FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP = DALI_COMPOSE_SHADER(
+    varying mediump vec2 vTexCoord;\n
+    uniform sampler2D sTexture;\n
+    uniform mediump vec4 uAtlasRect;\n
+    // WrapMode -- 0: CLAMP; 1: REPEAT; 2: REFLECT;
+    uniform lowp vec2 wrapMode;\n
+    uniform lowp vec4 uColor;\n
+    uniform lowp vec3 mixColor;\n
+    uniform lowp float preMultipliedAlpha;\n
+    \n
+    mediump float wrapCoordinate( mediump vec2 range, mediump float coordinate, lowp float wrap )\n
+    {\n
+      mediump float coord;\n
+      if( wrap > 1.5 )\n // REFLECT
+        coord = 1.0-abs(fract(coordinate*0.5)*2.0 - 1.0);\n
+      else \n// warp == 0 or 1
+        coord = mix(coordinate, fract( coordinate ), wrap);\n
+      return clamp( mix(range.x, range.y, coord), range.x, range.y );
+    }\n
+    \n
+    void main()\n
+    {\n
+        mediump vec2 texCoord = vec2( wrapCoordinate( uAtlasRect.xz, vTexCoord.x, wrapMode.x ),
+                                      wrapCoordinate( uAtlasRect.yw, vTexCoord.y, wrapMode.y ) );\n
+        gl_FragColor = texture2D( sTexture, texCoord ) * uColor * vec4( mixColor, 1.0 );\n
+    }\n
+);
+
+const char* VERTEX_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec4 pixelArea;
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  \n
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump float cornerRadius;\n
+  uniform mediump vec2 extraSize;\n
+  \n
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    vRectSize = visualSize / 2.0 - cornerRadius;\n
+    vPosition = aPosition* visualSize;\n
+    return vec4( vPosition + anchorPoint*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+\n
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+    vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
+  }\n
+);
+
+//float distance = length( max( abs( position - center ), size ) - size ) - radius;
+const char* FRAGMENT_SHADER_ROUNDED_CORNER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec2 vPosition;\n
+  varying mediump vec2 vRectSize;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform mediump float cornerRadius;\n
+  \n
+  void main()\n
+  {\n
+      mediump float dist = length( max( abs( vPosition ), vRectSize ) - vRectSize ) - cornerRadius;\n
+      gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );\n
+      gl_FragColor.a *= smoothstep( 1.0, -1.0, dist );\n
+  }\n
+);
+
+} // unnamed namespace
+
+ImageVisualShaderFactory::ImageVisualShaderFactory()
+{
+}
+
+ImageVisualShaderFactory::~ImageVisualShaderFactory()
+{
+}
+
+Shader ImageVisualShaderFactory::GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner )
+{
+  Shader shader;
+  if( atlasing )
+  {
+    if( defaultTextureWrapping )
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_CLAMP );
+        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_DEFAULT_WRAP, shader );
+      }
+    }
+    else
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_ATLAS_VARIOUS_WRAP );
+        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ATLAS_CUSTOM_WRAP, shader );
+      }
+    }
+  }
+  else
+  {
+    if( roundedCorner )
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER_ROUNDED_CORNER, FRAGMENT_SHADER_ROUNDED_CORNER );
+        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER_ROUNDED_CORNER, shader );
+      }
+    }
+    else
+    {
+      shader = factoryCache.GetShader( VisualFactoryCache::IMAGE_SHADER );
+      if( !shader )
+      {
+        shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_NO_ATLAS );
+        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+        factoryCache.SaveShader( VisualFactoryCache::IMAGE_SHADER, shader );
+      }
+    }
+  }
+
+  return shader;
+}
+
+const char* ImageVisualShaderFactory::GetVertexShaderSource()
+{
+  return VERTEX_SHADER;
+}
+
+const char* ImageVisualShaderFactory::GetFragmentShaderSource()
+{
+  return FRAGMENT_SHADER_NO_ATLAS;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/image-visual-shader-factory.h b/dali-toolkit/internal/visuals/image-visual-shader-factory.h
new file mode 100644 (file)
index 0000000..c5344d3
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
+
+/*
+ * Copyright (c) 2018 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+/**
+ * ImageVisualShaderFactory is an object that provides and shares shaders between image visuals
+ */
+class ImageVisualShaderFactory
+{
+public:
+
+public:
+
+  /**
+   * @brief Constructor
+   */
+  ImageVisualShaderFactory();
+
+  /**
+   * @brief Destructor
+   */
+  ~ImageVisualShaderFactory();
+
+  /**
+   * Get the standard image rendering shader.
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] atlasing Whether texture atlasing is applied.
+   * @param[in] defaultTextureWrapping Whether the default texture wrap mode is applied.
+   * @param[in] roundedCorner Whether the rounded corder is applied.
+   */
+  Shader GetShader( VisualFactoryCache& factoryCache, bool atlasing, bool defaultTextureWrapping, bool roundedCorner );
+
+  /**
+   * Request the default vertex shader source.
+   * @return The default vertex shader source.
+   */
+  const char* GetVertexShaderSource();
+
+  /**
+   * Request the default fragment shader source.
+   * @return The default fragment shader source.
+   */
+  const char* GetFragmentShaderSource();
+
+protected:
+
+  /**
+   * Undefined copy constructor.
+   */
+  ImageVisualShaderFactory(const ImageVisualShaderFactory&);
+
+  /**
+   * Undefined assignment operator.
+   */
+  ImageVisualShaderFactory& operator=(const ImageVisualShaderFactory& rhs);
+
+private:
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_SHADER_FACTORY_H
diff --git a/dali-toolkit/internal/visuals/image/image-visual.cpp b/dali-toolkit/internal/visuals/image/image-visual.cpp
new file mode 100644 (file)
index 0000000..c553ced
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/image/image-visual.h>
+
+// EXTERNAL HEADERS
+#include <cstring> // for strlen()
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/images/native-image.h>
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// fitting modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( FITTING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SHRINK_TO_FIT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, SCALE_TO_FILL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_WIDTH )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, FIT_HEIGHT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::FittingMode, DEFAULT )
+DALI_ENUM_TO_STRING_TABLE_END( FITTING_MODE )
+
+// sampling modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SAMPLING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NEAREST )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, LINEAR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_NEAREST )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, BOX_THEN_LINEAR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, NO_FILTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::SamplingMode, DONT_CARE )
+DALI_ENUM_TO_STRING_TABLE_END( SAMPLING_MODE )
+
+// wrap modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, CLAMP_TO_EDGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, REPEAT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, MIRRORED_REPEAT )
+DALI_ENUM_TO_STRING_TABLE_END( WRAP_MODE )
+
+// load policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN( LOAD_POLICY )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::LoadPolicy, IMMEDIATE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::LoadPolicy, ATTACHED )
+DALI_ENUM_TO_STRING_TABLE_END( LOAD_POLICY )
+
+// release policies
+DALI_ENUM_TO_STRING_TABLE_BEGIN( RELEASE_POLICY )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, DETACHED )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, DESTROYED )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::ImageVisual::ReleasePolicy, NEVER )
+DALI_ENUM_TO_STRING_TABLE_END( RELEASE_POLICY )
+
+const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+const char* DEFAULT_SAMPLER_TYPENAME = "sampler2D";
+
+const float PIXEL_ALIGN_ON = 1.0f;
+const float PIXEL_ALIGN_OFF = 0.0f;
+
+Geometry CreateGeometry( VisualFactoryCache& factoryCache, ImageDimensions gridSize )
+{
+  Geometry geometry;
+
+  if( gridSize == ImageDimensions( 1, 1 ) )
+  {
+    geometry = factoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+  }
+  else
+  {
+    geometry = VisualFactoryCache::CreateGridGeometry( gridSize );
+  }
+
+  return geometry;
+}
+
+} // unnamed namespace
+
+ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
+                                 ImageVisualShaderFactory& shaderFactory,
+                                 const VisualUrl& imageUrl,
+                                 const Property::Map& properties,
+                                 ImageDimensions size,
+                                 FittingMode::Type fittingMode,
+                                 Dali::SamplingMode::Type samplingMode )
+{
+  ImageVisualPtr imageVisualPtr( new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode ) );
+  imageVisualPtr->SetProperties( properties );
+  return imageVisualPtr;
+}
+
+ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache,
+                                 ImageVisualShaderFactory& shaderFactory,
+                                 const VisualUrl& imageUrl,
+                                 ImageDimensions size,
+                                 FittingMode::Type fittingMode,
+                                 Dali::SamplingMode::Type samplingMode )
+{
+  return new ImageVisual( factoryCache, shaderFactory, imageUrl, size, fittingMode, samplingMode );
+}
+
+ImageVisualPtr ImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image )
+{
+  return new ImageVisual( factoryCache, shaderFactory, image );
+}
+
+ImageVisual::ImageVisual( VisualFactoryCache& factoryCache,
+                          ImageVisualShaderFactory& shaderFactory,
+                          const VisualUrl& imageUrl,
+                          ImageDimensions size,
+                          FittingMode::Type fittingMode,
+                          Dali::SamplingMode::Type samplingMode )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mImage(),
+  mPixelArea( FULL_TEXTURE_RECT ),
+  mPlacementActor(),
+  mImageUrl( imageUrl ),
+  mMaskingData( ),
+  mDesiredSize( size ),
+  mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mTextures(),
+  mImageVisualShaderFactory( shaderFactory ),
+  mFittingMode( fittingMode ),
+  mSamplingMode( samplingMode ),
+  mWrapModeU( WrapMode::DEFAULT ),
+  mWrapModeV( WrapMode::DEFAULT ),
+  mLoadPolicy( Toolkit::ImageVisual::LoadPolicy::ATTACHED ),
+  mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DETACHED ),
+  mAtlasRect( 0.0f, 0.0f, 0.0f, 0.0f ),
+  mAtlasRectSize( 0, 0 ),
+  mAttemptAtlasing( false ),
+  mLoading( false ),
+  mOrientationCorrection( true )
+{
+  EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() );
+}
+
+ImageVisual::ImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image )
+: Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
+  mImage( image ),
+  mPixelArea( FULL_TEXTURE_RECT ),
+  mPlacementActor(),
+  mImageUrl(),
+  mMaskingData( ),
+  mDesiredSize(),
+  mTextureId( TextureManager::INVALID_TEXTURE_ID ),
+  mTextures(),
+  mImageVisualShaderFactory( shaderFactory ),
+  mFittingMode( FittingMode::DEFAULT ),
+  mSamplingMode( SamplingMode::DEFAULT ),
+  mWrapModeU( WrapMode::DEFAULT ),
+  mWrapModeV( WrapMode::DEFAULT ),
+  mLoadPolicy( Toolkit::ImageVisual::LoadPolicy::ATTACHED ),
+  mReleasePolicy( Toolkit::ImageVisual::ReleasePolicy::DESTROYED ),
+  mAtlasRect( 0.0f, 0.0f, 0.0f, 0.0f ),
+  mAttemptAtlasing( false ),
+  mLoading( false ),
+  mOrientationCorrection( true )
+{
+  // PreMultiplied alpha should be disabled when the Image is used.
+  EnablePreMultipliedAlpha( false );
+}
+
+ImageVisual::~ImageVisual()
+{
+  if( Stage::IsInstalled() )
+  {
+    if( mMaskingData )
+    {
+      // TextureManager could have been deleted before the actor that contains this
+      // ImageVisual is destroyed (e.g. due to stage shutdown). Ensure the stage
+      // is still valid before accessing texture manager.
+      if( mMaskingData->mAlphaMaskId != TextureManager::INVALID_TEXTURE_ID )
+      {
+        TextureManager& textureManager = mFactoryCache.GetTextureManager();
+        textureManager.Remove( mMaskingData->mAlphaMaskId, this );
+      }
+    }
+
+    // ImageVisual destroyed so remove texture unless ReleasePolicy is set to never release
+    if( ( mTextureId != TextureManager::INVALID_TEXTURE_ID  ) && ( mReleasePolicy != Toolkit::ImageVisual::ReleasePolicy::NEVER ) )
+    {
+      RemoveTexture();
+    }
+  }
+}
+
+void ImageVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // Url is already received in constructor
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else
+    {
+      if( keyValue.first == IMAGE_FITTING_MODE )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_SAMPLING_MODE )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_DESIRED_WIDTH )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_DESIRED_HEIGHT )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second );
+      }
+      else if( keyValue.first == PIXEL_AREA_UNIFORM_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::PIXEL_AREA, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_WRAP_MODE_U )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_U, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_WRAP_MODE_V )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::WRAP_MODE_V, keyValue.second );
+      }
+      else if( keyValue.first == SYNCHRONOUS_LOADING )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second );
+      }
+      else if( keyValue.first == IMAGE_ATLASING )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second );
+      }
+      else if( keyValue.first == ALPHA_MASK_URL )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, keyValue.second );
+      }
+      else if( keyValue.first == MASK_CONTENT_SCALE_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, keyValue.second );
+      }
+      else if( keyValue.first == CROP_TO_MASK_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::CROP_TO_MASK, keyValue.second );
+      }
+      else if ( keyValue.first == LOAD_POLICY_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::LOAD_POLICY, keyValue.second );
+      }
+      else if( keyValue.first == RELEASE_POLICY_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::RELEASE_POLICY, keyValue.second );
+      }
+      else if( keyValue.first == ORIENTATION_CORRECTION_NAME )
+      {
+        DoSetProperty( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, keyValue.second );
+      }
+    }
+  }
+  // Load image immediately if LOAD_POLICY requires it
+  if ( mLoadPolicy == Toolkit::ImageVisual::LoadPolicy::IMMEDIATE )
+  {
+    auto attemptAtlasing = AttemptAtlasing();
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
+                 TextureManager::ReloadPolicy::CACHED  );
+  }
+}
+
+void ImageVisual::DoSetProperty( Property::Index index, const Property::Value& value )
+{
+  switch( index )
+  {
+    case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
+    {
+      bool sync = false;
+      if( value.Get( sync ) )
+      {
+        if( sync )
+        {
+          mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+        }
+        else
+        {
+          mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+        }
+      }
+      else
+      {
+        DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
+    {
+      float desiredWidth = 0.0f;
+      if( value.Get( desiredWidth ) )
+      {
+        mDesiredSize.SetWidth( desiredWidth );
+      }
+      else
+      {
+        DALI_LOG_ERROR("ImageVisual: desiredWidth property has incorrect type\n");
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
+    {
+      float desiredHeight = 0.0f;
+      if( value.Get( desiredHeight ) )
+      {
+        mDesiredSize.SetHeight( desiredHeight );
+      }
+      else
+      {
+        DALI_LOG_ERROR("ImageVisual: desiredHeight property has incorrect type\n");
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::FITTING_MODE:
+    {
+      int fittingMode = 0;
+      Scripting::GetEnumerationProperty( value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode );
+      mFittingMode = Dali::FittingMode::Type( fittingMode );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::SAMPLING_MODE:
+    {
+      int samplingMode = 0;
+      Scripting::GetEnumerationProperty( value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode );
+      mSamplingMode = Dali::SamplingMode::Type( samplingMode );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::PIXEL_AREA:
+    {
+      value.Get( mPixelArea );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::WRAP_MODE_U:
+    {
+      int wrapMode = 0;
+      Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
+      mWrapModeU = Dali::WrapMode::Type( wrapMode );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::WRAP_MODE_V:
+    {
+      int wrapMode = 0;
+      Scripting::GetEnumerationProperty( value, WRAP_MODE_TABLE, WRAP_MODE_TABLE_COUNT, wrapMode );
+      mWrapModeV = Dali::WrapMode::Type( wrapMode );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::ATLASING:
+    {
+      value.Get( mAttemptAtlasing );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::ALPHA_MASK_URL:
+    {
+      std::string alphaUrl = "";
+      if( value.Get( alphaUrl ) )
+      {
+        AllocateMaskData();
+        mMaskingData->mAlphaMaskUrl = alphaUrl;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE:
+    {
+      float scale = 1.0f;
+      if( value.Get( scale ) )
+      {
+        AllocateMaskData();
+        mMaskingData->mContentScaleFactor = scale;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::CROP_TO_MASK:
+    {
+      bool crop=false;
+      if( value.Get( crop ) )
+      {
+        AllocateMaskData();
+        mMaskingData->mCropToMask = crop;
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::RELEASE_POLICY:
+    {
+      int releasePolicy = 0;
+      Scripting::GetEnumerationProperty( value, RELEASE_POLICY_TABLE, RELEASE_POLICY_TABLE_COUNT, releasePolicy );
+      mReleasePolicy = Toolkit::ImageVisual::ReleasePolicy::Type( releasePolicy );
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::LOAD_POLICY:
+    {
+      int loadPolicy = 0;
+      Scripting::GetEnumerationProperty( value, LOAD_POLICY_TABLE, LOAD_POLICY_TABLE_COUNT, loadPolicy );
+      mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type( loadPolicy );
+      break;
+    }
+    case Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION:
+    {
+      bool orientationCorrection( mOrientationCorrection );
+      if( value.Get( orientationCorrection ) )
+      {
+        mOrientationCorrection = orientationCorrection;
+      }
+      break;
+    }
+  }
+}
+
+void ImageVisual::AllocateMaskData()
+{
+  if( !mMaskingData )
+  {
+    mMaskingData.reset(new TextureManager::MaskingData());
+  }
+}
+
+void ImageVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if(mImage)
+  {
+    naturalSize.x = mImage.GetWidth();
+    naturalSize.y = mImage.GetHeight();
+    return;
+  }
+  else if( mDesiredSize.GetWidth()>0 && mDesiredSize.GetHeight()>0)
+  {
+    naturalSize.x = mDesiredSize.GetWidth();
+    naturalSize.y = mDesiredSize.GetHeight();
+    return;
+  }
+  else if( mImpl->mRenderer ) // Check if we have a loaded image
+  {
+    if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
+    {
+      naturalSize.x = mAtlasRectSize.GetWidth();
+      naturalSize.y = mAtlasRectSize.GetHeight();
+      return;
+    }
+
+    auto textureSet = mImpl->mRenderer.GetTextures();
+    if( textureSet )
+    {
+      auto texture = textureSet.GetTexture(0);
+      naturalSize.x = texture.GetWidth();
+      naturalSize.y = texture.GetHeight();
+      return;
+    }
+  }
+
+  if( mMaskingData != NULL && mMaskingData->mAlphaMaskUrl.IsValid() &&
+           mMaskingData->mCropToMask )
+  {
+    ImageDimensions dimensions = Dali::GetClosestImageSize( mMaskingData->mAlphaMaskUrl.GetUrl() );
+    if( dimensions != ImageDimensions( 0, 0 ) )
+    {
+      naturalSize.x = dimensions.GetWidth();
+      naturalSize.y = dimensions.GetHeight();
+    }
+    return;
+  }
+  else if( mImageUrl.IsValid() )
+  {
+    if( mImageUrl.GetProtocolType() == VisualUrl::LOCAL )
+    {
+      ImageDimensions dimensions = Dali::GetClosestImageSize( mImageUrl.GetUrl() );
+
+      if( dimensions != ImageDimensions( 0, 0 ) )
+      {
+        naturalSize.x = dimensions.GetWidth();
+        naturalSize.y = dimensions.GetHeight();
+      }
+      else
+      {
+        Image brokenImage = mFactoryCache.GetBrokenVisualImage();
+
+        naturalSize.x = brokenImage.GetWidth();
+        naturalSize.y = brokenImage.GetWidth();
+      }
+      return;
+    }
+  }
+
+  naturalSize = Vector2::ZERO;
+}
+
+void ImageVisual::CreateRenderer( TextureSet& textureSet )
+{
+  Geometry geometry;
+  Shader shader;
+
+  if( !mImpl->mCustomShader )
+  {
+    geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+
+    shader = mImageVisualShaderFactory.GetShader( mFactoryCache,
+                             mImpl->mFlags & Impl::IS_ATLASING_APPLIED,
+                             mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE,
+                             IsRoundedCornerRequired() );
+  }
+  else
+  {
+    geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
+    if( mImpl->mCustomShader->mVertexShader.empty() && mImpl->mCustomShader->mFragmentShader.empty() )
+    {
+      // Use custom hints
+      shader = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), mImageVisualShaderFactory.GetFragmentShaderSource(), mImpl->mCustomShader->mHints );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+    }
+    else
+    {
+      shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
+                            mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
+                            mImpl->mCustomShader->mHints );
+      if( mImpl->mCustomShader->mVertexShader.empty() )
+      {
+        shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      }
+    }
+  }
+
+  // Set pixel align off as default.
+  // ToDo: Pixel align causes issues such as rattling image animation.
+  // We should trun it off until issues are resolved
+  shader.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  if( textureSet )
+  {
+    mImpl->mRenderer.SetTextures( textureSet );
+  }
+  // else still waiting for texture load to finish.
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  EnablePreMultipliedAlpha( IsPreMultipliedAlphaEnabled() );
+}
+
+void ImageVisual::CreateNativeImageRenderer( NativeImage& nativeImage )
+{
+  Geometry geometry;
+  Shader shader;
+
+  std::string fragmentShader;
+  const char* fragmentPreFix = nativeImage.GetCustomFragmentPreFix();
+  const char* customSamplerTypename = nativeImage.GetCustomSamplerTypename();
+
+  if( fragmentPreFix )
+  {
+    fragmentShader = fragmentPreFix;
+    fragmentShader += "\n";
+  }
+
+  if( mImpl->mCustomShader && !mImpl->mCustomShader->mFragmentShader.empty() )
+  {
+    fragmentShader += mImpl->mCustomShader->mFragmentShader;
+  }
+  else
+  {
+    fragmentShader += mImageVisualShaderFactory.GetFragmentShaderSource();
+  }
+
+  if( customSamplerTypename )
+  {
+    fragmentShader.replace( fragmentShader.find( DEFAULT_SAMPLER_TYPENAME ), strlen( DEFAULT_SAMPLER_TYPENAME ), customSamplerTypename );
+  }
+
+  if( !mImpl->mCustomShader )
+  {
+    geometry = CreateGeometry( mFactoryCache, ImageDimensions( 1, 1 ) );
+
+    shader  = Shader::New( mImageVisualShaderFactory.GetVertexShaderSource(), fragmentShader );
+    shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+  }
+  else
+  {
+    geometry = CreateGeometry( mFactoryCache, mImpl->mCustomShader->mGridSize );
+    shader  = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
+                           fragmentShader,
+                           mImpl->mCustomShader->mHints );
+    if( mImpl->mCustomShader->mVertexShader.empty() )
+    {
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+    }
+  }
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+void ImageVisual::LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection,
+                               TextureManager::ReloadPolicy forceReload )
+{
+  TextureManager& textureManager = mFactoryCache.GetTextureManager();
+
+  ImageAtlasManagerPtr atlasManager = nullptr;
+  AtlasUploadObserver* atlasUploadObserver = nullptr;
+  auto textureObserver = this;
+
+  if( atlasing )
+  {
+    atlasManager = mFactoryCache.GetAtlasManager();
+    atlasUploadObserver = this;
+  }
+
+  auto preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader
+    ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+    : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+  textures = textureManager.LoadTexture( mImageUrl, mDesiredSize, mFittingMode, mSamplingMode,
+                                         mMaskingData, IsSynchronousLoadingRequired(), mTextureId,
+                                         atlasRect, mAtlasRectSize, atlasing, mLoading, mWrapModeU,
+                                         mWrapModeV, textureObserver, atlasUploadObserver, atlasManager,
+                                         mOrientationCorrection, forceReload, preMultiplyOnLoad);
+
+  if( textures )
+  {
+    EnablePreMultipliedAlpha( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
+  }
+
+  if( atlasing ) // Flag needs to be set before creating renderer
+  {
+    mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+  }
+  else
+  {
+    mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+  }
+}
+
+bool ImageVisual::AttemptAtlasing()
+{
+  return ( ! mImpl->mCustomShader && mImageUrl.GetProtocolType() == VisualUrl::LOCAL && mAttemptAtlasing );
+}
+
+void ImageVisual::InitializeRenderer()
+{
+  auto attemptAtlasing = AttemptAtlasing();
+  // texture set has to be created first as we need to know if atlasing succeeded or not
+  // when selecting the shader
+
+  if( mTextureId == TextureManager::INVALID_TEXTURE_ID && ! mTextures ) // Only load the texture once
+  {
+    LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
+                 TextureManager::ReloadPolicy::CACHED );
+  }
+
+  CreateRenderer( mTextures );
+  mTextures.Reset(); // Visual should not keep a handle to the texture after this point.
+
+  if( attemptAtlasing ) // the texture is packed inside atlas
+  {
+    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
+
+    bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
+
+    if( !defaultWrapMode ) // custom wrap mode
+    {
+      Vector2 wrapMode(mWrapModeU-WrapMode::CLAMP_TO_EDGE, mWrapModeV-WrapMode::CLAMP_TO_EDGE);
+      wrapMode.Clamp( Vector2::ZERO, Vector2( 2.f, 2.f ) );
+      mImpl->mRenderer.RegisterProperty( WRAP_MODE_UNIFORM_NAME, wrapMode );
+    }
+  }
+}
+
+void ImageVisual::InitializeRenderer( const Image& image )
+{
+  TextureSet textures = TextureSet::New();
+
+  NativeImage nativeImage = NativeImage::DownCast( image );
+  if( nativeImage )
+  {
+    CreateNativeImageRenderer( nativeImage );
+    DALI_ASSERT_DEBUG( textures );
+    mImpl->mRenderer.SetTextures( textures );
+  }
+  else
+  {
+    // reuse existing code for regular images
+    CreateRenderer( textures ); // Textures will be retreived from Image
+  }
+  ApplyImageToSampler( image );
+}
+
+void ImageVisual::DoSetOnStage( Actor& actor )
+{
+  if( mImageUrl.IsValid() )
+  {
+    InitializeRenderer();
+  }
+  else if( mImage )
+  {
+    InitializeRenderer( mImage );
+  }
+
+  if( !mImpl->mRenderer )
+  {
+    return;
+  }
+
+  mPlacementActor = actor;
+  // Search the Actor tree to find if Layer UI behaviour set.
+  Layer layer = actor.GetLayer();
+  if( layer && layer.GetBehavior() == Layer::LAYER_3D )
+  {
+     // Layer 3D set, do not align pixels
+     mImpl->mRenderer.RegisterProperty( PIXEL_ALIGNED_UNIFORM_NAME, PIXEL_ALIGN_OFF );
+  }
+
+  if( mPixelArea != FULL_TEXTURE_RECT )
+  {
+    mImpl->mRenderer.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, mPixelArea );
+  }
+
+  if( mLoading == false )
+  {
+    actor.AddRenderer( mImpl->mRenderer );
+    mPlacementActor.Reset();
+
+    // Image loaded and ready to display
+    ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+  }
+}
+
+void ImageVisual::DoSetOffStage( Actor& actor )
+{
+  // Visual::Base::SetOffStage only calls DoSetOffStage if mRenderer exists (is on onstage)
+
+  // Image release is dependent on the ReleasePolicy, renderer is destroyed.
+  actor.RemoveRenderer( mImpl->mRenderer);
+  if( mReleasePolicy == Toolkit::ImageVisual::ReleasePolicy::DETACHED )
+  {
+    RemoveTexture(); // If INVALID_TEXTURE_ID then removal will be attempted on atlas
+    mImpl->mResourceStatus = Toolkit::Visual::ResourceStatus::PREPARING;
+  }
+
+  if( mImageUrl.IsValid() )
+  {
+    // Legacy support for deprecated Dali::Image
+    mImage.Reset();
+  }
+  mLoading = false;
+  mImpl->mRenderer.Reset();
+  mPlacementActor.Reset();
+}
+
+void ImageVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
+
+  bool sync = IsSynchronousLoadingRequired();
+  map.Insert( SYNCHRONOUS_LOADING, sync );
+  if( mImageUrl.IsValid() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
+  }
+  else if( mImage )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
+
+    ResourceImage resourceImage = ResourceImage::DownCast(mImage);
+    if( resourceImage )
+    {
+      map.Insert( Toolkit::ImageVisual::Property::URL, resourceImage.GetUrl() );
+    }
+  }
+
+  map.Insert( Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode );
+  map.Insert( Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode );
+
+  map.Insert( Toolkit::ImageVisual::Property::PIXEL_AREA, mPixelArea );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_U, mWrapModeU );
+  map.Insert( Toolkit::ImageVisual::Property::WRAP_MODE_V, mWrapModeV );
+
+  map.Insert( Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing );
+
+  if( mMaskingData != NULL )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mMaskingData->mAlphaMaskUrl.GetUrl() );
+    map.Insert( Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskingData->mContentScaleFactor );
+    map.Insert( Toolkit::ImageVisual::Property::CROP_TO_MASK, mMaskingData->mCropToMask );
+  }
+
+  map.Insert( Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy );
+  map.Insert( Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy );
+  map.Insert( Toolkit::ImageVisual::Property::ORIENTATION_CORRECTION, mOrientationCorrection );
+}
+
+void ImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE );
+  if( mImageUrl.IsValid() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth() );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight() );
+  }
+  else if( mImage )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_WIDTH, static_cast<int>(mImage.GetWidth()) );
+    map.Insert( Toolkit::ImageVisual::Property::DESIRED_HEIGHT, static_cast<int>(mImage.GetHeight()) );
+  }
+}
+
+void ImageVisual::OnDoAction( const Dali::Property::Index actionName, const Dali::Property::Value& attributes )
+{
+  // Check if action is valid for this visual type and perform action if possible
+
+  switch ( actionName )
+  {
+    case DevelImageVisual::Action::RELOAD:
+    {
+      auto attemptAtlasing = AttemptAtlasing();
+      LoadTexture( attemptAtlasing, mAtlasRect, mTextures, mOrientationCorrection,
+                   TextureManager::ReloadPolicy::FORCED );
+      break;
+    }
+  }
+}
+
+void ImageVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+bool ImageVisual::IsResourceReady() const
+{
+  return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
+           mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED );
+}
+
+void ImageVisual::ApplyImageToSampler( const Image& image )
+{
+  if( image )
+  {
+    TextureSet textureSet = mImpl->mRenderer.GetTextures();
+    DALI_ASSERT_DEBUG( textureSet ); // texture set should always exist by this time
+
+    TextureSetImage( textureSet, 0u, image );
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
+  }
+}
+
+// From existing atlas manager
+void ImageVisual::UploadCompleted()
+{
+  // Texture has been uploaded. If weak handle is holding a placement actor,
+  // it is the time to add the renderer to actor.
+  Actor actor = mPlacementActor.GetHandle();
+  if( actor )
+  {
+    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
+    actor.AddRenderer( mImpl->mRenderer );
+    // reset the weak handle so that the renderer only get added to actor once
+    mPlacementActor.Reset();
+  }
+  // Image loaded
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+  mLoading = false;
+}
+
+// From Texture Manager
+void ImageVisual::UploadComplete( bool loadingSuccess, int32_t textureId, TextureSet textureSet, bool usingAtlas,
+                                  const Vector4& atlasRectangle, bool preMultiplied )
+{
+  Toolkit::Visual::ResourceStatus resourceStatus;
+  if( mImpl->mRenderer )
+  {
+    if( usingAtlas )
+    {
+      mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mAtlasRect );
+    }
+
+    EnablePreMultipliedAlpha( preMultiplied );
+
+    Actor actor = mPlacementActor.GetHandle();
+    if( actor )
+    {
+      actor.AddRenderer( mImpl->mRenderer );
+      // reset the weak handle so that the renderer only get added to actor once
+      mPlacementActor.Reset();
+    }
+
+    if( loadingSuccess )
+    {
+      Sampler sampler = Sampler::New();
+      sampler.SetWrapMode(  mWrapModeU, mWrapModeV  );
+      textureSet.SetSampler( 0u, sampler );
+      mImpl->mRenderer.SetTextures(textureSet);
+    }
+    else
+    {
+      Image brokenImage = mFactoryCache.GetBrokenVisualImage();
+
+      textureSet = TextureSet::New();
+      mImpl->mRenderer.SetTextures( textureSet );
+
+      ApplyImageToSampler( brokenImage );
+    }
+  }
+
+  // Storing TextureSet needed when renderer staged.
+  if( ! mImpl->mRenderer )
+  {
+    mTextures = textureSet;
+  }
+
+  // Image loaded, set status regardless of staged status.
+  if( loadingSuccess )
+  {
+    resourceStatus = Toolkit::Visual::ResourceStatus::READY;
+  }
+  else
+  {
+    resourceStatus = Toolkit::Visual::ResourceStatus::FAILED;
+  }
+  // Signal to observers ( control ) that resources are ready. Must be all resources.
+  ResourceReady( resourceStatus );
+  mLoading = false;
+}
+
+void ImageVisual::RemoveTexture()
+{
+  if( mTextureId != TextureManager::INVALID_TEXTURE_ID )
+  {
+    mFactoryCache.GetTextureManager().Remove( mTextureId, this );
+    mTextureId = TextureManager::INVALID_TEXTURE_ID;
+  }
+  else
+  {
+    Vector4 atlasRect( 0.f, 0.f, 1.f, 1.f );
+    Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
+    if( index != Property::INVALID_INDEX )
+    {
+      Property::Value atlasRectValue = mImpl->mRenderer.GetProperty( index );
+      atlasRectValue.Get( atlasRect );
+    }
+
+    TextureSet textureSet = mImpl->mRenderer.GetTextures();
+    mImpl->mRenderer.Reset();
+
+    if( index != Property::INVALID_INDEX )
+    {
+      mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/image/image-visual.h b/dali-toolkit/internal/visuals/image/image-visual.h
new file mode 100644 (file)
index 0000000..23dee63
--- /dev/null
@@ -0,0 +1,396 @@
+#ifndef DALI_TOOLKIT_INTERNAL_IMAGE_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_IMAGE_VISUAL_H
+
+/*
+ * Copyright (c) 2020 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 <memory>
+
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/images/image.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/atlas-upload-observer.h>
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+
+namespace Dali
+{
+
+class NativeImage;
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ImageVisualShaderFactory;
+class ImageVisual;
+typedef IntrusivePtr< ImageVisual > ImageVisualPtr;
+
+/**
+ * The visual which renders an image to a quad geometry
+ *
+ * The following properties are optional
+ *
+ * | %Property Name        | Type              |
+ * |-----------------------|-------------------|
+ * | url                   | STRING            |
+ * | alphaMaskUrl          | STRING            |
+ * | fittingMode           | INTEGER OR STRING |
+ * | samplingMode          | INTEGER OR STRING |
+ * | desiredWidth          | INTEGER           |
+ * | desiredHeight         | INTEGER           |
+ * | synchronousLoading    | BOOLEAN           |
+ * | pixelArea             | VECTOR4           |
+ * | wrapModeU             | INTEGER OR STRING |
+ * | wrapModeV             | INTEGER OR STRING |
+ * | loadPolicy            | INTEGER OR STRING |
+ * | releasePolicy         | INTEGER OR STRING |
+ * | orientationCorrection | BOOLEAN           |
+ *
+ * where pixelArea is a rectangular area.
+ * In its Vector4 value, the first two elements indicate the top-left position of the area,
+ * and the last two elements are the area width and height respectively.
+ * If not specified, the default value is [0.0, 0.0, 1.0, 1.0], i.e. the entire area of the image.
+ *
+ * where wrapModeU and wrapModeV separately decide how the texture should be sampled when the u and v coordinate exceeds the range of 0.0 to 1.0.
+ * Its value should be one of the following wrap mode:
+ *   "DEFAULT"
+ *   "CLAMP_TO_EDGE"
+ *   "REPEAT"
+ *   "MIRRORED_REPEAT"
+ *
+ * where imageFittingMode should be one of the following fitting modes:
+ *   "SHRINK_TO_FIT"
+ *   "SCALE_TO_FILL"
+ *   "FIT_WIDTH"
+ *   "FIT_HEIGHT"
+ *   "DEFAULT"
+ *
+ * where imageSamplingMode should be one of the following sampling modes:
+ *   "BOX"
+ *   "NEAREST"
+ *   "LINEAR"
+ *   "BOX_THEN_NEAREST"
+ *   "BOX_THEN_LINEAR"
+ *   "NO_FILTER"
+ *   "DONT_CARE"
+ *   "DEFAULT"
+ *
+ * where loadPolicy should be one of the following image loading modes
+ *   "IMMEDIATE"   // Loads image even if visual not attached to stage yet
+ *   "ATTACHED"    // Only loads image once visual is attached to stage
+ *
+ * where releasePolicy should be one of the following policies for when to cache the image
+ *   "DETACHED"    //  Release image from cache when visual detached from stage
+ *   "DESTROYED"   //  Keep image in cache until the visual is destroyed
+ *   "NEVER"       //  Keep image in cache until application ends.
+ *
+ * If the Visual is in a LayerUI it will pixel align the image, using a Layer3D will disable pixel alignment.
+ * Changing layer behaviour between LayerUI to Layer3D whilst the visual is already staged will not have an effect.
+ */
+class ImageVisual: public Visual::Base, public ConnectionTracker, public AtlasUploadObserver, public TextureUploadObserver
+{
+public:
+
+  /**
+   * @brief Create a new image visual with a URL.
+   *
+   * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL of the image resource to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @param[in] size The width and height to fit the loaded image to.
+   * @param[in] fittingMode The FittingMode of the resource to load
+   * @param[in] samplingMode The SamplingMode of the resource to load
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static ImageVisualPtr New( VisualFactoryCache& factoryCache,
+                             ImageVisualShaderFactory& shaderFactory,
+                             const VisualUrl& imageUrl,
+                             const Property::Map& properties,
+                             ImageDimensions size = ImageDimensions(),
+                             FittingMode::Type fittingMode = FittingMode::DEFAULT,
+                             Dali::SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR );
+
+  /**
+   * @brief Create a new image visual with a URL.
+   *
+   * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL of the image resource to use
+   * @param[in] size The width and height to fit the loaded image to.
+   * @param[in] fittingMode The FittingMode of the resource to load
+   * @param[in] samplingMode The SamplingMode of the resource to load
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static ImageVisualPtr New( VisualFactoryCache& factoryCache,
+                             ImageVisualShaderFactory& shaderFactory,
+                             const VisualUrl& imageUrl,
+                             ImageDimensions size = ImageDimensions(),
+                             FittingMode::Type fittingMode = FittingMode::DEFAULT,
+                             Dali::SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR );
+
+  /**
+   * @brief Create a new image visual with an Image type.
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] image The image to use
+   */
+  static ImageVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::OnDoAction
+   */
+  void OnDoAction( const Dali::Property::Index actionName, const Dali::Property::Value& attributes ) override;
+
+protected:
+
+  /**
+   * @brief Constructor with a URL.
+   *
+   * The visual will load the Image asynchronously when the associated actor is put on stage, and destroy the image when it is off stage
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL of the image resource to use
+   * @param[in] size The width and height to fit the loaded image to.
+   * @param[in] fittingMode The FittingMode of the resource to load
+   * @param[in] samplingMode The SamplingMode of the resource to load
+   */
+  ImageVisual( VisualFactoryCache& factoryCache,
+               ImageVisualShaderFactory& shaderFactory,
+               const VisualUrl& imageUrl,
+               ImageDimensions size,
+               FittingMode::Type fittingMode,
+               Dali::SamplingMode::Type samplingMode );
+
+  /**
+   * @brief Constructor with an Image type.
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] image The image to use
+   */
+  ImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Image& image );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~ImageVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::IsResourceReady
+   */
+  bool IsResourceReady() const override;
+
+public:
+
+  /**
+   * @copydoc AtlasUploadObserver::UploadCompleted
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the loading is finished.
+   */
+  void UploadCompleted() override;
+
+  /**
+   * @copydoc TextureUploadObserver::UploadCompleted
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the loading is finished.
+   */
+  void UploadComplete( bool success, int32_t textureId, TextureSet textureSet,
+                       bool usingAtlas, const Vector4& atlasRectangle, bool preMultiplied ) override;
+
+private:
+
+  /**
+   * @copydoc TextureUploadObserver::LoadComplete
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the PixelBuffer loading is finished.
+   */
+  void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override {}
+
+  /**
+   * Allocate the mask data when a masking property is defined in the property map
+   */
+  void AllocateMaskData();
+
+  /**
+   * @brief Applies the image to the texture set used for this renderer
+   *
+   * @param[in] image The Image to apply to the texture set used for this renderer
+   */
+  void ApplyImageToSampler( const Image& image );
+
+  /**
+   * @brief Load the texture, will try to atlas unless unable or param set to false.
+   * @param[in, out] atlasing flag if the image has been put in a atlas (true), passing false will not atlas even if possible.
+   * @param[out] atlasRect if atlasing is used this the texture area of the image in the atlas.
+   * @param[out] textures resulting texture set from the image loading.
+   * @param[in] orientationCorrection flag determines if orientation correction should be performed
+   * @param[in] forceReload flag determines if the texture should be reloaded from its source or use the cached texture.
+   */
+  void LoadTexture( bool& atlasing, Vector4& atlasRect, TextureSet& textures, bool orientationCorrection, TextureManager::ReloadPolicy forceReload );
+
+  /**
+   * @brief Checks if atlasing should be attempted
+   * @return bool returns true if atlasing can be attempted.
+   */
+  bool AttemptAtlasing();
+
+  /**
+   * @brief Initializes the Dali::Renderer from the image url
+   */
+  void InitializeRenderer();
+
+  /**
+   * @brief Initializes the Dali::Renderer from an image handle
+   *
+   * @param[in] image The image handle to intialize this ImageVisual from
+   */
+  void InitializeRenderer( const Image& image );
+
+  /**
+   * @brief Creates the Dali::Renderer (potentially from the renderer cache), initializing it
+   * @param[in] textures to use
+   */
+  void CreateRenderer( TextureSet& textures );
+
+  /**
+   * @brief Creates the Dali::Renderer for NativeImage with custom sampler type and prefix, initializing it
+   * @param NativeImageRenderer
+   */
+  void CreateNativeImageRenderer( NativeImage& nativeImage );
+
+  /**
+   * Creates the texture set and adds the texture to it
+   * @param[out] textureRect The texture area of the texture in the atlas.
+   * @param[in] url The URL of the image resource to use.
+   * @param[in] synchronousLoading If true, the resource is loaded synchronously, otherwise asynchronously.
+   * @param[in] attemptAtlasing If true will attempt atlasing, otherwise create unique texture
+   * @return the texture set to use
+   */
+  TextureSet CreateTextureSet( Vector4& textureRect, bool synchronousLoading, bool attemptAtlasing );
+
+  /**
+   * Set the value to the uTextureRect uniform
+   * @param[in] textureRect The texture rectangular area.
+   */
+  void SetTextureRectUniform( const Vector4& textureRect  );
+
+  /**
+   * Remove texture with valid TextureId
+   */
+  void RemoveTexture();
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+private:
+
+  Image mImage;
+  Vector4 mPixelArea;
+  WeakHandle<Actor> mPlacementActor;
+  VisualUrl mImageUrl;
+  TextureManager::MaskingDataPointer mMaskingData;
+
+  Dali::ImageDimensions mDesiredSize;
+  TextureManager::TextureId mTextureId;
+  TextureSet mTextures;
+
+  ImageVisualShaderFactory& mImageVisualShaderFactory;
+
+  Dali::FittingMode::Type mFittingMode:3;
+  Dali::SamplingMode::Type mSamplingMode:4;
+  Dali::WrapMode::Type mWrapModeU:3;
+  Dali::WrapMode::Type mWrapModeV:3;
+  Dali::Toolkit::ImageVisual::LoadPolicy::Type mLoadPolicy;
+  Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy;
+  Vector4 mAtlasRect;
+  Dali::ImageDimensions mAtlasRectSize;
+  bool mAttemptAtlasing; ///< If true will attempt atlasing, otherwise create unique texture
+  bool mLoading;  ///< True if the texture is still loading.
+  bool mOrientationCorrection; ///< true if the image will have it's orientation corrected.
+};
+
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_IMAGE_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/mesh/mesh-visual.cpp b/dali-toolkit/internal/visuals/mesh/mesh-visual.cpp
new file mode 100644 (file)
index 0000000..7fbb28e
--- /dev/null
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2018 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 "mesh-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+//INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace
+{
+  /**
+   * @brief Loads a texture from a file
+   * @param[in] imageUrl The url of the file
+   * @param[in] generateMipmaps Indicates whether to generate mipmaps for the texture
+   * @return A texture if loading succeeds, an empty handle otherwise
+   */
+  Texture LoadTexture( const char* imageUrl, bool generateMipmaps )
+  {
+    Texture texture;
+
+    Devel::PixelBuffer pixelBuffer = LoadImageFromFile( imageUrl );
+    if( pixelBuffer )
+    {
+      texture = Texture::New( TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(), pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+      PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+      texture.Upload( pixelData );
+
+      if( generateMipmaps )
+      {
+        texture.GenerateMipmaps();
+      }
+    }
+
+    return texture;
+  }
+}// unnamed namespace
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+//Defines ordering of textures for shaders.
+//All shaders, if including certain texture types, must include them in the same order.
+//Within the texture set for the renderer, textures are ordered in the same manner.
+enum TextureIndex
+{
+  DIFFUSE_INDEX = 0u,
+  NORMAL_INDEX = 1u,
+  GLOSS_INDEX = 2u
+};
+
+
+//Shading mode
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SHADING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::MeshVisual::ShadingMode, TEXTURELESS_WITH_DIFFUSE_LIGHTING )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_SPECULAR_LIGHTING )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::MeshVisual::ShadingMode, TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING )
+DALI_ENUM_TO_STRING_TABLE_END( SHADING_MODE )
+
+//Shader properties
+const char * const OBJECT_MATRIX_UNIFORM_NAME( "uObjectMatrix" );
+const char * const STAGE_OFFSET_UNIFORM_NAME( "uStageOffset" );
+
+//Shaders
+//If a shader requires certain textures, they must be listed in order,
+//as detailed in the TextureIndex enum documentation.
+
+//A basic shader that doesn't use textures at all.
+const char* SIMPLE_VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec3 aNormal;\n
+  varying mediump vec3 vIllumination;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;\n
+  uniform mediump mat4 uViewMatrix;\n
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 lightPosition;\n
+  uniform mediump vec2 uStageOffset;\n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    float scaleFactor = min( visualSize.x, visualSize.y );\n
+    vec3 originFlipY =  vec3(origin.x, -origin.y, 0.0);
+    vec3 anchorPointFlipY = vec3( anchorPoint.x, -anchorPoint.y, 0.0);
+    vec3 offset = vec3( ( offset / uSize.xy ) * offsetSizeMode.xy + offset * (1.0-offsetSizeMode.xy), 0.0) * vec3(1.0,-1.0,1.0);\n
+    return vec4( (aPosition + anchorPointFlipY)*scaleFactor + (offset + originFlipY)*uSize, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    vec4 normalisedVertexPosition = ComputeVertexPosition();\n
+    vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
+    vec3 normal = uNormalMatrix * mat3( uObjectMatrix ) * aNormal;\n
+
+    vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
+    mvLightPosition = uViewMatrix * mvLightPosition;\n
+    vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
+
+    float lightDiffuse = max( dot( vectorToLight, normal ), 0.0 );\n
+    vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
+
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the texture-less shader.
+const char* SIMPLE_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying mediump vec3 vIllumination;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+
+  void main()\n
+  {\n
+    gl_FragColor = vec4( vIllumination.rgb * uColor.rgb, uColor.a ) * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+//Diffuse and specular illumination shader with albedo texture. Texture is index 0.
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec2 aTexCoord;\n
+  attribute highp vec3 aNormal;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vIllumination;\n
+  varying mediump float vSpecular;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;
+  uniform mediump mat4 uViewMatrix;\n
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 lightPosition;\n
+  uniform mediump vec2 uStageOffset;\n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    float scaleFactor = min( visualSize.x, visualSize.y );\n
+    vec3 originFlipY =  vec3(origin.x, -origin.y, 0.0);
+    vec3 anchorPointFlipY = vec3( anchorPoint.x, -anchorPoint.y, 0.0);
+    vec3 offset = vec3( ( offset / uSize.xy ) * offsetSizeMode.xy + offset * (1.0-offsetSizeMode.xy), 0.0) * vec3(1.0,-1.0,1.0);\n
+    return vec4( (aPosition + anchorPointFlipY)*scaleFactor + (offset + originFlipY)*uSize, 1.0 );\n
+  }\n
+
+  void main()
+  {\n
+    vec4 normalisedVertexPosition = ComputeVertexPosition();\n
+    vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    //Illumination in Model-View space - Transform attributes and uniforms\n
+    vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
+    vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );\n
+
+    vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
+    mvLightPosition = uViewMatrix * mvLightPosition;\n
+    vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
+
+    vec3 viewDirection = normalize( -mvVertexPosition.xyz );
+
+    float lightDiffuse = dot( vectorToLight, normal );\n
+    lightDiffuse = max( 0.0,lightDiffuse );\n
+    vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
+
+    vec3 reflectDirection = reflect( -vectorToLight, normal );
+    vSpecular = pow( max( dot( reflectDirection, viewDirection ), 0.0 ), 4.0 );
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the diffuse and specular illumination shader with albedo texture
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vIllumination;\n
+  varying mediump float vSpecular;\n
+  uniform sampler2D sDiffuse;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    vec4 visualMixColor = vec4( mixColor, 1.0 );\n
+    gl_FragColor = vec4( vIllumination.rgb * texture.rgb * uColor.rgb * visualMixColor.rgb + vSpecular * 0.3, texture.a * uColor.a * visualMixColor.a );\n
+  }\n
+);
+
+//Diffuse and specular illumination shader with albedo texture, normal map and gloss map shader.
+//Diffuse (albedo) texture is index 0, normal is 1, gloss is 2. They must be declared in this order.
+const char* NORMAL_MAP_VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute highp vec3 aPosition;\n
+  attribute highp vec2 aTexCoord;\n
+  attribute highp vec3 aNormal;\n
+  attribute highp vec3 aTangent;\n
+  attribute highp vec3 aBiNormal;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vLightDirection;\n
+  varying mediump vec3 vHalfVector;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump mat4 uModelView;
+  uniform mediump mat4 uViewMatrix;\n
+  uniform mediump mat3 uNormalMatrix;
+  uniform mediump mat4 uObjectMatrix;\n
+  uniform mediump vec3 lightPosition;\n
+  uniform mediump vec2 uStageOffset;\n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    float scaleFactor = min( visualSize.x, visualSize.y );\n
+    vec3 originFlipY =  vec3(origin.x, -origin.y, 0.0);
+    vec3 anchorPointFlipY = vec3( anchorPoint.x, -anchorPoint.y, 0.0);
+    vec3 offset = vec3( ( offset / uSize.xy ) * offsetSizeMode.xy + offset * (1.0-offsetSizeMode.xy), 0.0) * vec3(1.0,-1.0,1.0);\n
+    return vec4( (aPosition + anchorPointFlipY)*scaleFactor + (offset + originFlipY)*uSize, 1.0 );\n
+  }\n
+
+  void main()
+  {\n
+    vec4 normalisedVertexPosition = ComputeVertexPosition();\n
+    vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+    vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
+
+    vec3 tangent = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aTangent );
+    vec3 binormal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aBiNormal );
+    vec3 normal = normalize( uNormalMatrix * mat3( uObjectMatrix ) * aNormal );
+
+    vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
+    mvLightPosition = uViewMatrix * mvLightPosition;\n
+    vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
+    vLightDirection.x = dot( vectorToLight, tangent );
+    vLightDirection.y = dot( vectorToLight, binormal );
+    vLightDirection.z = dot( vectorToLight, normal );
+
+    vec3 viewDirection = normalize( -mvVertexPosition.xyz );
+    vec3 halfVector = normalize( viewDirection + vectorToLight );
+    vHalfVector.x = dot( halfVector, tangent );
+    vHalfVector.y = dot( halfVector, binormal );
+    vHalfVector.z = dot( halfVector, normal );
+
+    vTexCoord = aTexCoord;\n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Fragment shader corresponding to the shader that uses all textures (diffuse, normal and gloss maps)
+const char* NORMAL_MAP_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec3 vLightDirection;\n
+  varying mediump vec3 vHalfVector;\n
+  uniform sampler2D sDiffuse;\n
+  uniform sampler2D sNormal;\n
+  uniform sampler2D sGloss;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+
+  void main()\n
+  {\n
+    vec4 texture = texture2D( sDiffuse, vTexCoord );\n
+    vec3 normal = normalize( texture2D( sNormal, vTexCoord ).xyz * 2.0 - 1.0 );\n
+    vec4 glossMap = texture2D( sGloss, vTexCoord );\n
+    vec4 visualMixColor = vec4( mixColor, 1.0 );\n
+
+    float lightDiffuse = max( 0.0, dot( normal, normalize( vLightDirection ) ) );\n
+    lightDiffuse = lightDiffuse * 0.5 + 0.5;\n
+
+    float shininess = pow ( max ( dot ( normalize( vHalfVector ), normal ), 0.0 ), 16.0 )  ;
+
+    gl_FragColor = vec4( texture.rgb * uColor.rgb * visualMixColor.rgb * lightDiffuse + shininess * glossMap.rgb, texture.a * uColor.a * visualMixColor.a );\n
+  }\n
+);
+
+} // unnamed namespace
+
+MeshVisualPtr MeshVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  MeshVisualPtr meshVisualPtr( new MeshVisual( factoryCache ) );
+  meshVisualPtr->SetProperties( properties );
+  return meshVisualPtr;
+}
+
+MeshVisual::MeshVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
+  mShadingMode( Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING ),
+  mUseTexture( true ),
+  mUseMipmapping( true ),
+  mUseSoftNormals( true )
+{
+}
+
+MeshVisual::~MeshVisual()
+{
+}
+
+void MeshVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else
+    {
+      if( keyValue.first == OBJECT_URL_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::OBJECT_URL, keyValue.second );
+      }
+      else if( keyValue.first == MATERIAL_URL_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::MATERIAL_URL, keyValue.second );
+      }
+      else if( keyValue.first == TEXTURES_PATH_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::TEXTURES_PATH, keyValue.second );
+      }
+      else if( keyValue.first == SHADING_MODE_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::SHADING_MODE, keyValue.second );
+      }
+      else if( keyValue.first == USE_MIPMAPPING_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::USE_MIPMAPPING, keyValue.second );
+      }
+      else if( keyValue.first == USE_SOFT_NORMALS_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, keyValue.second );
+      }
+      else if( keyValue.first == LIGHT_POSITION_NAME )
+      {
+        DoSetProperty( Toolkit::MeshVisual::Property::LIGHT_POSITION, keyValue.second );
+      }
+    }
+  }
+
+  if( mMaterialUrl.empty() )
+  {
+    mUseTexture = false;
+  }
+
+  if( mLightPosition == Vector3::ZERO )
+  {
+    // Default behaviour is to place the light directly in front of the object,
+    // at a reasonable distance to light everything on screen.
+    Stage stage = Stage::GetCurrent();
+
+    mLightPosition = Vector3( stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5 );
+  }
+}
+
+void MeshVisual::DoSetProperty( Property::Index index, const Property::Value& value )
+{
+  switch( index )
+  {
+    case Toolkit::MeshVisual::Property::OBJECT_URL:
+    {
+      if( !value.Get( mObjectUrl ) )
+      {
+        DALI_LOG_ERROR("MeshVisual: property objectUrl is the wrong type, use STRING\n");
+      }
+      break;
+    }
+    case Toolkit::MeshVisual::Property::MATERIAL_URL:
+    {
+      if( ! value.Get( mMaterialUrl ) )
+      {
+        DALI_LOG_ERROR("MeshVisual: property materialUrl is the wrong type, use STRING\n");
+      }
+      break;
+    }
+    case Toolkit::MeshVisual::Property::TEXTURES_PATH:
+    {
+      if( ! value.Get( mTexturesPath ) )
+      {
+        mTexturesPath.clear();
+      }
+      break;
+    }
+    case Toolkit::MeshVisual::Property::SHADING_MODE:
+    {
+      Scripting::GetEnumerationProperty( value, SHADING_MODE_TABLE, SHADING_MODE_TABLE_COUNT, mShadingMode );
+      break;
+    }
+    case Toolkit::MeshVisual::Property::USE_MIPMAPPING:
+    {
+      if( !value.Get( mUseMipmapping ) )
+      {
+        DALI_LOG_ERROR("MeshVisual: property useMipmapping is the wrong type, use BOOLEAN\n");
+      }
+      break;
+    }
+    case Toolkit::MeshVisual::Property::USE_SOFT_NORMALS:
+    {
+      if( !value.Get( mUseSoftNormals ) )
+      {
+        DALI_LOG_ERROR("MeshVisual: property useSoftNormals is the wrong type, use BOOLEAN\n");
+      }
+      break;
+    }
+    case Toolkit::MeshVisual::Property::LIGHT_POSITION:
+    {
+      if( !value.Get( mLightPosition ) )
+      {
+        mLightPosition = Vector3::ZERO;
+        DALI_LOG_ERROR("MeshVisual: property lightPosition is the wrong type, use VECTOR3\n");
+      }
+      break;
+    }
+  }
+}
+
+void MeshVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void MeshVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Mesh loaded and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void MeshVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::MESH );
+  map.Insert( Toolkit::MeshVisual::Property::OBJECT_URL, mObjectUrl );
+  map.Insert( Toolkit::MeshVisual::Property::MATERIAL_URL, mMaterialUrl );
+  map.Insert( Toolkit::MeshVisual::Property::TEXTURES_PATH, mTexturesPath );
+  map.Insert( Toolkit::MeshVisual::Property::SHADING_MODE, mShadingMode );
+  map.Insert( Toolkit::MeshVisual::Property::USE_MIPMAPPING, mUseMipmapping );
+  map.Insert( Toolkit::MeshVisual::Property::USE_SOFT_NORMALS, mUseSoftNormals );
+  map.Insert( Toolkit::MeshVisual::Property::LIGHT_POSITION, mLightPosition );
+}
+
+void MeshVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void MeshVisual::InitializeRenderer()
+{
+  //Try to load the geometry from the file.
+  if( !LoadGeometry() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  //If a texture is used by the obj file, load the supplied material file.
+  if( mObjLoader.IsTexturePresent() && !mMaterialUrl.empty() )
+  {
+    if( !LoadMaterial() )
+    {
+      SupplyEmptyGeometry();
+      return;
+    }
+  }
+
+  //Now that the required parts are loaded, create the geometry for the object.
+  if( !CreateGeometry() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  CreateShader();
+
+  //Load the various texture files supplied by the material file.
+  if( !LoadTextures() )
+  {
+    SupplyEmptyGeometry();
+    return;
+  }
+
+  mImpl->mRenderer = Renderer::New( mGeometry, mShader );
+  mImpl->mRenderer.SetTextures( mTextureSet );
+  mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
+  mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+void MeshVisual::SupplyEmptyGeometry()
+{
+  mGeometry = Geometry::New();
+  mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  mImpl->mRenderer = Renderer::New( mGeometry, mShader );
+
+  DALI_LOG_ERROR( "Initialisation error in mesh visual.\n" );
+}
+
+void MeshVisual::UpdateShaderUniforms()
+{
+  Stage stage = Stage::GetCurrent();
+  float width = stage.GetSize().width;
+  float height = stage.GetSize().height;
+
+  Matrix scaleMatrix;
+  scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+
+  mShader.RegisterProperty( STAGE_OFFSET_UNIFORM_NAME, Vector2( width, height ) / 2.0f );
+  mShader.RegisterProperty( LIGHT_POSITION_NAME, mLightPosition );
+  mShader.RegisterProperty( OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix );
+}
+
+void MeshVisual::CreateShader()
+{
+  if( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING )
+  {
+    mShader = Shader::New( NORMAL_MAP_VERTEX_SHADER, NORMAL_MAP_FRAGMENT_SHADER );
+  }
+  else if( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING )
+  {
+    mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+  }
+  else //Textureless
+  {
+    mShader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER );
+  }
+
+  UpdateShaderUniforms();
+}
+
+bool MeshVisual::CreateGeometry()
+{
+  //Determine if we need to use a simpler shader to handle the provided data
+  if( !mUseTexture || !mObjLoader.IsDiffuseMapPresent() )
+  {
+    mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING;
+  }
+  else if( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING && (!mObjLoader.IsNormalMapPresent() || !mObjLoader.IsSpecularMapPresent()) )
+  {
+    mShadingMode = Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING;
+  }
+
+  int objectProperties = 0;
+
+  if( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_SPECULAR_LIGHTING ||
+      mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING )
+  {
+    objectProperties |= ObjLoader::TEXTURE_COORDINATES;
+  }
+
+  if( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING )
+  {
+    objectProperties |= ObjLoader::TANGENTS | ObjLoader::BINORMALS;
+  }
+
+  //Create geometry with attributes required by shader.
+  mGeometry = mObjLoader.CreateGeometry( objectProperties, mUseSoftNormals );
+
+  if( mGeometry )
+  {
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to load geometry in mesh visual.\n" );
+  return false;
+}
+
+bool MeshVisual::LoadGeometry()
+{
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if( FileLoader::ReadFile( mObjectUrl, fileSize, fileContent, FileLoader::TEXT ) )
+  {
+    mObjLoader.ClearArrays();
+    mObjLoader.LoadObject( fileContent.Begin(), fileSize );
+
+    //Get size information from the obj loaded
+    mSceneCenter = mObjLoader.GetCenter();
+    mSceneSize = mObjLoader.GetSize();
+
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to find object to load in mesh visual.\n" );
+  return false;
+}
+
+bool MeshVisual::LoadMaterial()
+{
+  std::streampos fileSize;
+  Dali::Vector<char> fileContent;
+
+  if( FileLoader::ReadFile( mMaterialUrl, fileSize, fileContent, FileLoader::TEXT ) )
+  {
+    //Load data into obj (usable) form
+    mObjLoader.LoadMaterial( fileContent.Begin(), fileSize, mDiffuseTextureUrl, mNormalTextureUrl, mGlossTextureUrl );
+    return true;
+  }
+
+  DALI_LOG_ERROR( "Failed to find texture set to load in mesh visual.\n" );
+  mUseTexture = false;
+  return false;
+}
+
+bool MeshVisual::LoadTextures()
+{
+  mTextureSet = TextureSet::New();
+
+  if( mShadingMode != Toolkit::MeshVisual::ShadingMode::TEXTURELESS_WITH_DIFFUSE_LIGHTING )
+  {
+    Sampler sampler = Sampler::New();
+    if( mUseMipmapping )
+    {
+      sampler.SetFilterMode( FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR_MIPMAP_LINEAR );
+    }
+
+    if( !mDiffuseTextureUrl.empty() )
+    {
+      std::string imageUrl = mTexturesPath + mDiffuseTextureUrl;
+
+      //Load textures
+      Texture diffuseTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
+      if( diffuseTexture )
+      {
+        mTextureSet.SetTexture( DIFFUSE_INDEX, diffuseTexture );
+        mTextureSet.SetSampler( DIFFUSE_INDEX, sampler );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Failed to load diffuse map texture in mesh visual.\n");
+        return false;
+      }
+    }
+
+    if( !mNormalTextureUrl.empty() && ( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING ) )
+    {
+      std::string imageUrl = mTexturesPath + mNormalTextureUrl;
+
+      //Load textures
+      Texture normalTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
+      if( normalTexture )
+      {
+        mTextureSet.SetTexture( NORMAL_INDEX, normalTexture );
+        mTextureSet.SetSampler( NORMAL_INDEX, sampler );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Failed to load normal map texture in mesh visual.\n");
+        return false;
+      }
+    }
+
+    if( !mGlossTextureUrl.empty() && ( mShadingMode == Toolkit::MeshVisual::ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING ) )
+    {
+      std::string imageUrl = mTexturesPath + mGlossTextureUrl;
+
+      //Load textures
+      Texture glossTexture = LoadTexture( imageUrl.c_str(), mUseMipmapping );
+      if( glossTexture )
+      {
+        mTextureSet.SetTexture( GLOSS_INDEX, glossTexture );
+        mTextureSet.SetSampler( GLOSS_INDEX, sampler );
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Failed to load gloss map texture in mesh visual.\n");
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/mesh/mesh-visual.h b/dali-toolkit/internal/visuals/mesh/mesh-visual.h
new file mode 100644 (file)
index 0000000..15099bd
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef DALI_TOOLKIT_INTERNAL_MESH_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_MESH_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <fstream>
+#include <string.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/mesh-visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/controls/model3d-view/obj-loader.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class MeshVisual;
+typedef IntrusivePtr< MeshVisual > MeshVisualPtr;
+
+/**
+ * The visual which renders a 3D object to the control's quad
+ *
+ * The following Property::Map keys are required to create a MeshVisual
+ *
+ * | %Property Name  | Type        | Representing                                                          |
+ * |-----------------|-------------|-----------------------------------------------------------------------|
+ * | objectUrl       | STRING      | A URL to the .obj file                                                |
+ * | materialUrl     | STRING      | A URL to the .mtl file                                                |
+ * | texturesPath    | STRING      | A URL of the path to the texture images                               |
+ * | shadingMode     | STRING      | An enum of shading modes                                              |
+ * | useMipmapping   | BOOLEAN     | If true, use mipmaps for textures. Default true.                      |
+ * | useSoftNormals  | BOOLEAN     | If true, average normals at points for smooth textures. Default true. |
+ * | lightPosition   | VECTOR3     | The position (on stage) of the light                                  |
+ */
+class MeshVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new mesh visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static MeshVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  MeshVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~MeshVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+private:
+
+  /**
+   * @brief Provide an empty geometry for the visual to use.
+   * @details For use in error cases where the initialisation has failed for varying reasons.
+   */
+  void SupplyEmptyGeometry();
+
+  /**
+   * @brief Initialize the visual with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  /**
+   * @brief Create a shader for the object to use.
+   */
+  void CreateShader();
+
+  /**
+   * @brief Update shader related info, uniforms, etc. for the new shader.
+   */
+  void UpdateShaderUniforms();
+
+  /**
+   * @brief Use the object URL stored in the mesh visual to load and create the geometry of the object.
+   * @return Boolean of success of operation.
+   */
+  bool CreateGeometry();
+
+  /**
+   * @brief Use the object URL stored in the visual to load the geometry of the object.
+   * @return Boolean of success of operation.
+   */
+  bool LoadGeometry();
+
+  /**
+   * @brief Use the material URL stored in the mesh visual to load the material of the object.
+   * @return Boolean of success of operation.
+   */
+  bool LoadMaterial();
+
+  /**
+   * @brief Use the image and texture URL components to load the different types of texture.
+   * @return Boolean of success of operation. Returns false if any texture fails to load from a url.
+   */
+  bool LoadTextures();
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+private:
+
+  // Undefined
+  MeshVisual( const MeshVisual& meshVisual );
+
+  // Undefined
+  MeshVisual& operator=( const MeshVisual& meshVisual );
+
+private:
+
+  std::string mObjectUrl;
+  std::string mMaterialUrl;
+
+  std::string mDiffuseTextureUrl;
+  std::string mNormalTextureUrl;
+  std::string mGlossTextureUrl;
+  std::string mTexturesPath;
+
+  Shader mShader;
+  Geometry mGeometry;
+  TextureSet mTextureSet;
+
+  ObjLoader mObjLoader;
+  Vector3 mSceneCenter;
+  Vector3 mSceneSize;
+
+  Vector3 mLightPosition;
+  Toolkit::MeshVisual::ShadingMode::Value mShadingMode;
+
+  bool mUseTexture;
+  bool mUseMipmapping;
+  bool mUseSoftNormals;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_MESH_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/npatch-loader.cpp b/dali-toolkit/internal/visuals/npatch-loader.cpp
new file mode 100644 (file)
index 0000000..6745adf
--- /dev/null
@@ -0,0 +1,403 @@
+ /*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/npatch-loader.h>
+
+// EXTERNAL HEADER
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/common/hash.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace NPatchBuffer
+{
+
+void GetRedOffsetAndMask( Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask )
+{
+  switch( pixelFormat )
+  {
+    case Dali::Pixel::A8:
+    case Dali::Pixel::L8:
+    case Dali::Pixel::LA88:
+    {
+      byteOffset = 0;
+      bitMask = 0;
+      break;
+    }
+    case Dali::Pixel::RGB888:
+    case Dali::Pixel::RGB8888:
+    case Dali::Pixel::RGBA8888:
+    {
+      byteOffset = 0;
+      bitMask = 0xFF;
+      break;
+    }
+    case Dali::Pixel::BGR8888:
+    case Dali::Pixel::BGRA8888:
+    {
+      byteOffset = 2;
+      bitMask = 0xff;
+      break;
+    }
+    case Dali::Pixel::RGB565:
+    {
+      byteOffset = 0;
+      bitMask = 0xf8;
+      break;
+    }
+    case Dali::Pixel::BGR565:
+    {
+      byteOffset = 1;
+      bitMask = 0x1f;
+      break;
+    }
+    case Dali::Pixel::RGBA4444:
+    {
+      byteOffset = 0;
+      bitMask = 0xf0;
+      break;
+    }
+    case Dali::Pixel::BGRA4444:
+    {
+      byteOffset = 1;
+      bitMask = 0xf0;
+      break;
+    }
+    case Dali::Pixel::RGBA5551:
+    {
+      byteOffset = 0;
+      bitMask = 0xf8;
+      break;
+    }
+    case Dali::Pixel::BGRA5551:
+    {
+      byteOffset = 1;
+      bitMask = 0x1e;
+      break;
+    }
+    case Dali::Pixel::INVALID:
+    case Dali::Pixel::COMPRESSED_R11_EAC:
+    case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
+    case Dali::Pixel::COMPRESSED_RG11_EAC:
+    case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
+    case Dali::Pixel::COMPRESSED_RGB8_ETC2:
+    case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
+    case Dali::Pixel::COMPRESSED_RGB8_ETC1:
+    case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
+    case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR:
+    case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+    {
+      DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
+      byteOffset=0;
+      bitMask=0;
+      break;
+    }
+    case Dali::Pixel::RGB16F:
+    case Dali::Pixel::RGB32F:
+    {
+      DALI_LOG_ERROR("Pixel format not compatible.\n");
+      byteOffset=0;
+      bitMask=0;
+      break;
+    }
+  }
+}
+
+Uint16Pair ParseRange( unsigned int& index, unsigned int width, unsigned char*& pixel, unsigned int pixelStride, int testByte, int testBits, int testValue )
+{
+  unsigned int start = 0xFFFF;
+  for( ; index < width; ++index, pixel += pixelStride )
+  {
+    if( ( pixel[ testByte ] & testBits ) == testValue )
+    {
+        start = index;
+        ++index;
+        pixel += pixelStride;
+        break;
+    }
+  }
+
+  unsigned int end = width;
+  for( ; index < width; ++index, pixel += pixelStride )
+  {
+    if( ( pixel[ testByte ] & testBits ) != testValue )
+    {
+        end = index;
+        ++index;
+        pixel += pixelStride;
+        break;
+    }
+  }
+
+  return Uint16Pair( start, end );
+}
+
+void ParseBorders( Devel::PixelBuffer& pixelBuffer, NPatchLoader::Data* data  )
+{
+  data->stretchPixelsX.Clear();
+  data->stretchPixelsY.Clear();
+
+  Pixel::Format pixelFormat = pixelBuffer.GetPixelFormat();
+
+  int alphaByte = 0;
+  int alphaBits = 0;
+  Pixel::GetAlphaOffsetAndMask( pixelFormat, alphaByte, alphaBits );
+
+  int testByte = alphaByte;
+  int testBits = alphaBits;
+  int testValue = alphaBits; // Opaque == stretch
+  if( !alphaBits )
+  {
+    GetRedOffsetAndMask( pixelFormat, testByte, testBits );
+    testValue = 0;           // Black == stretch
+  }
+
+  unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+  unsigned int width = pixelBuffer.GetWidth();
+  unsigned int height = pixelBuffer.GetHeight();
+  unsigned char* srcPixels = pixelBuffer.GetBuffer();
+  unsigned int srcStride = width * bytesPerPixel;
+
+  // TOP
+  unsigned char* top = srcPixels + bytesPerPixel;
+  unsigned int index = 0;
+
+  for( ; index < width - 2; )
+  {
+    Uint16Pair range = ParseRange( index, width - 2, top, bytesPerPixel, testByte, testBits, testValue );
+    if( range.GetX() != 0xFFFF )
+    {
+      data->stretchPixelsX.PushBack( range );
+    }
+  }
+
+  // LEFT
+  unsigned char* left  = srcPixels + srcStride;
+  index = 0;
+  for( ; index < height - 2; )
+  {
+    Uint16Pair range = ParseRange( index, height - 2, left, srcStride, testByte, testBits, testValue );
+    if( range.GetX() != 0xFFFF )
+    {
+      data->stretchPixelsY.PushBack( range );
+    }
+  }
+
+  // If there are no stretch pixels then make the entire image stretchable
+  if( data->stretchPixelsX.Size() == 0 )
+  {
+    data->stretchPixelsX.PushBack( Uint16Pair( 0, width - 2 ) );
+  }
+  if( data->stretchPixelsY.Size() == 0 )
+  {
+    data->stretchPixelsY.PushBack( Uint16Pair( 0, height - 2 ) );
+  }
+}
+
+void SetLoadedNPatchData( NPatchLoader::Data* data, Devel::PixelBuffer& pixelBuffer )
+{
+  if( data->border == Rect< int >( 0, 0, 0, 0 ) )
+  {
+    NPatchBuffer::ParseBorders( pixelBuffer, data );
+
+    // Crop the image
+    pixelBuffer.Crop( 1, 1, pixelBuffer.GetWidth() - 2, pixelBuffer.GetHeight() - 2 );
+  }
+  else
+  {
+    data->stretchPixelsX.PushBack( Uint16Pair( data->border.left, ( (pixelBuffer.GetWidth() >= static_cast< unsigned int >( data->border.right )) ? pixelBuffer.GetWidth() - data->border.right : 0 ) ) );
+    data->stretchPixelsY.PushBack( Uint16Pair( data->border.top, ( (pixelBuffer.GetHeight() >= static_cast< unsigned int >( data->border.bottom )) ? pixelBuffer.GetHeight() - data->border.bottom : 0 ) ) );
+  }
+
+  data->croppedWidth = pixelBuffer.GetWidth();
+  data->croppedHeight = pixelBuffer.GetHeight();
+
+  PixelData pixels = Devel::PixelBuffer::Convert( pixelBuffer ); // takes ownership of buffer
+
+  Texture texture = Texture::New( TextureType::TEXTURE_2D, pixels.GetPixelFormat(), pixels.GetWidth(), pixels.GetHeight() );
+  texture.Upload( pixels );
+
+  data->textureSet = TextureSet::New();
+  data->textureSet.SetTexture( 0u, texture );
+
+  data->loadCompleted = true;
+}
+
+} // namespace NPatchBuffer
+
+NPatchLoader::NPatchLoader()
+{
+}
+
+NPatchLoader::~NPatchLoader()
+{
+}
+
+std::size_t NPatchLoader::Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading )
+{
+  std::size_t hash = CalculateHash( url );
+  OwnerContainer< Data* >::SizeType index = UNINITIALIZED_ID;
+  const OwnerContainer< Data* >::SizeType count = mCache.Count();
+  int cachedIndex = -1;
+  Data* data;
+
+  for( ; index < count; ++index )
+  {
+    if( mCache[ index ]->hash == hash )
+    {
+      // hash match, check url as well in case of hash collision
+      if( mCache[ index ]->url == url )
+      {
+        // Use cached data
+        if( mCache[ index ]->border == border )
+        {
+          if( mCache[ index ]->loadCompleted )
+          {
+            return index + 1u; // valid indices are from 1 onwards
+          }
+          data = mCache[ index ];
+          cachedIndex = index + 1u; // valid indices are from 1 onwards
+          break;
+        }
+        else
+        {
+          if( mCache[ index ]->loadCompleted )
+          {
+            // Same url but border is different - use the existing texture
+            Data* data = new Data();
+            data->hash = hash;
+            data->url = url;
+            data->croppedWidth = mCache[ index ]->croppedWidth;
+            data->croppedHeight = mCache[ index ]->croppedHeight;
+
+            data->textureSet = mCache[ index ]->textureSet;
+
+            StretchRanges stretchRangesX;
+            stretchRangesX.PushBack( Uint16Pair( border.left, ( (data->croppedWidth >= static_cast< unsigned int >( border.right )) ? data->croppedWidth - border.right : 0 ) ) );
+
+            StretchRanges stretchRangesY;
+            stretchRangesY.PushBack( Uint16Pair( border.top, ( (data->croppedHeight >= static_cast< unsigned int >( border.bottom )) ? data->croppedHeight - border.bottom : 0 ) ) );
+
+            data->stretchPixelsX = stretchRangesX;
+            data->stretchPixelsY = stretchRangesY;
+            data->border = border;
+
+            data->loadCompleted = mCache[ index ]->loadCompleted;
+
+            mCache.PushBack( data );
+
+            return mCache.Count(); // valid ids start from 1u
+          }
+        }
+      }
+    }
+  }
+
+  if( cachedIndex == -1 )
+  {
+    data = new Data();
+    data->loadCompleted = false;
+    data->hash = hash;
+    data->url = url;
+    data->border = border;
+
+    mCache.PushBack( data );
+
+    cachedIndex = mCache.Count();
+  }
+
+  auto preMultiplyOnLoading = preMultiplyOnLoad ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD
+                                                : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  Devel::PixelBuffer pixelBuffer = textureManager.LoadPixelBuffer( url, Dali::ImageDimensions(), FittingMode::DEFAULT,
+                                                                   SamplingMode::BOX_THEN_LINEAR, synchronousLoading,
+                                                                   textureObserver, true, preMultiplyOnLoading );
+
+  if( pixelBuffer )
+  {
+    NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer );
+    preMultiplyOnLoad = ( preMultiplyOnLoading == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD ) ? true : false;
+  }
+
+  return cachedIndex;
+}
+
+void NPatchLoader::SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer )
+{
+  Data* data;
+  data = mCache[ id - 1u ];
+
+  if( !data->loadCompleted )
+  {
+    NPatchBuffer::SetLoadedNPatchData( data, pixelBuffer );
+  }
+}
+
+bool NPatchLoader::GetNPatchData( std::size_t id, const Data*& data )
+{
+  if( ( id > UNINITIALIZED_ID )&&( id <= mCache.Count() ) )
+  {
+    data = mCache[ id - 1u ]; // id's start from 1u
+    return true;
+  }
+  data = NULL;
+  return false;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/npatch-loader.h b/dali-toolkit/internal/visuals/npatch-loader.h
new file mode 100644 (file)
index 0000000..6bdc2f9
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_TOOLKIT_NPATCH_LOADER_H
+#define DALI_TOOLKIT_NPATCH_LOADER_H
+
+/*
+ * Copyright (c) 2020 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/public-api/rendering/texture-set.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace NPatchBuffer
+{
+
+void GetRedOffsetAndMask( Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask );
+
+} // namespace NPatchBuffer
+
+/**
+ * The manager for loading Npatch textures.
+ * It caches them internally for better performance; i.e. to avoid loading and
+ * parsing the files over and over.
+ *
+ * Cache is not cleaned during app lifecycle as N patches take considerably
+ * small space and there's not usually a lot of them. Usually N patches are specified in
+ * toolkit default style and there is 1-2 per control that are shared across the whole application.
+ */
+class NPatchLoader
+{
+public:
+
+  typedef Dali::Vector< Uint16Pair > StretchRanges;
+
+  enum
+  {
+    UNINITIALIZED_ID = 0 ///< uninitialised id, use to initialize ids
+  };
+
+  struct Data
+  {
+    Data()
+    : url(),
+      textureSet(),
+      hash( 0 ),
+      croppedWidth( 0 ),
+      croppedHeight( 0 ),
+      border( 0, 0, 0, 0 ),
+      loadCompleted( false )
+    {}
+
+    std::string url;                              ///< Url of the N-Patch
+    TextureSet textureSet;                        ///< Texture containing the cropped image
+    StretchRanges stretchPixelsX;                 ///< X stretch pixels
+    StretchRanges stretchPixelsY;                 ///< Y stretch pixels
+    std::size_t hash;                             ///< Hash code for the Url
+    uint32_t croppedWidth;                        ///< Width of the cropped middle part of N-patch
+    uint32_t croppedHeight;                       ///< Height of the cropped middle part of N-patch
+    Rect< int > border;                           ///< The size of the border
+    bool loadCompleted;                           ///< True if the data loading is completed
+  };
+
+public:
+
+  /**
+   * Constructor
+   */
+  NPatchLoader();
+
+  /**
+   * Destructor, non-virtual as not a base class
+   */
+  ~NPatchLoader();
+
+  /**
+   * @brief Retrieve a texture matching the n-patch url.
+   *
+   * @param [in] textureManager that will be used to loading image
+   * @param [in] textureObserver The NPatchVisual that requested loading.
+   * @param [in] url to retrieve
+   * @param [in] border The border size of the image
+   * @param [in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                   image has no alpha channel
+   * @param [in] synchronousLoading True if the image will be loaded in synchronous time.
+   * @return id of the texture.
+   */
+  std::size_t Load( TextureManager& textureManager, TextureUploadObserver* textureObserver, const std::string& url, const Rect< int >& border, bool& preMultiplyOnLoad, bool synchronousLoading );
+
+  /**
+   * @brief Set loaded PixelBuffer and its information
+   *
+   * @param [in] id cache data id
+   * @param [in] pixelBuffer of loaded image
+   */
+  void SetNPatchData( std::size_t id, Devel::PixelBuffer& pixelBuffer );
+
+  /**
+   * @brief Retrieve N patch data matching to an id
+   * @param [in] id of data
+   * @param [out] data const pointer to the data
+   * @return true if data matching to id was really found
+   */
+  bool GetNPatchData( std::size_t id, const Data*& data );
+
+protected:
+
+  /**
+   * Undefined copy constructor.
+   */
+  NPatchLoader(const NPatchLoader&);
+
+  /**
+   * Undefined assignment operator.
+   */
+  NPatchLoader& operator=(const NPatchLoader& rhs);
+
+private:
+
+  OwnerContainer< Data* > mCache;
+
+};
+
+} // name Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_NPATCH_LOADER_H
diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp b/dali-toolkit/internal/visuals/npatch/npatch-visual.cpp
new file mode 100755 (executable)
index 0000000..873eeca
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 2020 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 "npatch-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec2 vMaskTexCoord;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec2 uNinePatchFactorsX[ FACTOR_SIZE_X ];\n
+  uniform mediump vec2 uNinePatchFactorsY[ FACTOR_SIZE_Y ];\n
+  \n
+
+  // Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+  uniform mediump vec2 extraSize;\n
+
+  void main()\n
+  {\n
+    mediump vec2 fixedFactor  = vec2( uNinePatchFactorsX[ int( ( aPosition.x + 1.0 ) * 0.5 ) ].x, uNinePatchFactorsY[ int( ( aPosition.y + 1.0 ) * 0.5 ) ].x );\n
+    mediump vec2 stretch      = vec2( uNinePatchFactorsX[ int( ( aPosition.x       ) * 0.5 ) ].y, uNinePatchFactorsY[ int( ( aPosition.y       ) * 0.5 ) ].y );\n
+    \n
+    mediump vec2 fixedTotal   = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].x, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].x );\n
+    mediump vec2 stretchTotal = vec2( uNinePatchFactorsX[ FACTOR_SIZE_X - 1 ].y, uNinePatchFactorsY[ FACTOR_SIZE_Y - 1 ].y );\n
+    \n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    \n
+    mediump vec4 gridPosition = vec4( fixedFactor + ( visualSize.xy - fixedTotal ) * stretch / stretchTotal, 0.0, 1.0 );\n
+    mediump vec4 vertexPosition = gridPosition;\n
+    vertexPosition.xy -= visualSize.xy * vec2( 0.5, 0.5 );\n
+    vertexPosition.xy += anchorPoint*visualSize + (visualOffset + origin)*uSize.xy;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+    \n
+    vTexCoord = ( fixedFactor + stretch ) / ( fixedTotal + stretchTotal );\n
+    vMaskTexCoord = gridPosition.xy / visualSize;\n
+    \n
+    gl_Position = vertexPosition;\n
+  }\n
+);
+
+const char* VERTEX_SHADER_3X3 = DALI_COMPOSE_SHADER(
+    attribute mediump vec2 aPosition;\n
+    varying mediump vec2 vTexCoord;\n
+    varying mediump vec2 vMaskTexCoord;\n
+    uniform highp   mat4 uMvpMatrix;\n
+    uniform mediump vec3 uSize;\n
+    uniform mediump vec2 uFixed[ 3 ];\n
+    uniform mediump vec2 uStretchTotal;\n
+    \n
+    //Visual size and offset
+    uniform mediump vec2 offset;\n
+    uniform mediump vec2 size;\n
+    uniform mediump vec4 offsetSizeMode;\n
+    uniform mediump vec2 origin;\n
+    uniform mediump vec2 anchorPoint;\n
+    uniform mediump vec2 extraSize;\n
+    \n
+    void main()\n
+    {\n
+      vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw ) + extraSize;\n
+      vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+      \n
+      mediump vec2 size         = visualSize.xy;\n
+      \n
+      mediump vec2 fixedFactor  = vec2( uFixed[ int( ( aPosition.x + 1.0 ) * 0.5 ) ].x, uFixed[ int( ( aPosition.y  + 1.0 ) * 0.5 ) ].y );\n
+      mediump vec2 stretch      = floor( aPosition * 0.5 );\n
+      mediump vec2 fixedTotal   = uFixed[ 2 ];\n
+      \n
+      mediump vec4 gridPosition = vec4( fixedFactor + ( size - fixedTotal ) * stretch, 0.0, 1.0 );\n
+      mediump vec4 vertexPosition = gridPosition;\n
+      vertexPosition.xy -= size * vec2( 0.5, 0.5 );\n
+      vertexPosition.xy += anchorPoint*size + (visualOffset + origin)*uSize.xy;\n
+      \n
+      vertexPosition = uMvpMatrix * vertexPosition;\n
+      \n
+      vTexCoord = ( fixedFactor + stretch * uStretchTotal ) / ( fixedTotal + uStretchTotal );\n
+      \n
+      vMaskTexCoord = gridPosition.xy / size;\n
+      gl_Position = vertexPosition;\n
+    }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+const char* FRAGMENT_MASK_SHADER = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  varying mediump vec2 vMaskTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sMask;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  uniform lowp float preMultipliedAlpha;\n
+  uniform mediump float auxiliaryImageAlpha;\n
+  \n
+  void main()\n
+  {\n
+      // Where mask image is transparent, all of background image must show through.
+      // where mask image is opaque, only mask should be shown
+      // where mask is translucent, less of background should be shown.
+      // auxiliaryImageAlpha controls how much of mask is visible
+
+      mediump vec4 color = texture2D( sTexture, vTexCoord );\n
+      mediump vec4 mask  = texture2D( sMask, vMaskTexCoord );\n
+
+      mediump vec3 mixedColor = color.rgb * mix( 1.0-mask.a, 1.0, 1.0-auxiliaryImageAlpha)
+                                + mask.rgb*mask.a * auxiliaryImageAlpha;\n
+      gl_FragColor = vec4(mixedColor,1.0) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+/**
+ * @brief Creates the geometry formed from the vertices and indices
+ *
+ * @param[in]  vertices             The vertices to generate the geometry from
+ * @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 short >& indices )
+{
+  Property::Map vertexFormat;
+  vertexFormat[ "aPosition" ] = Property::VECTOR2;
+  PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
+  if( vertices.Size() > 0 )
+  {
+    vertexPropertyBuffer.SetData( &vertices[ 0 ], vertices.Size() );
+  }
+
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexPropertyBuffer );
+  if( indices.Size() > 0 )
+  {
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+  }
+
+
+  return geometry;
+}
+
+/**
+ * @brief Adds the indices to form a quad composed off two triangles where the indices are organised in a grid
+ *
+ * @param[out] indices     The indices to add to
+ * @param[in]  rowIdx      The row index to start the quad
+ * @param[in]  nextRowIdx  The index to the next row
+ */
+void AddQuadIndices( Vector< unsigned short >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
+{
+  indices.PushBack( rowIdx );
+  indices.PushBack( nextRowIdx + 1 );
+  indices.PushBack( rowIdx + 1 );
+
+  indices.PushBack( rowIdx );
+  indices.PushBack( nextRowIdx );
+  indices.PushBack( nextRowIdx + 1 );
+}
+
+void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y )
+{
+  vertices.PushBack( Vector2( x, y ) );
+}
+
+void RegisterStretchProperties( Renderer& renderer, const char * uniformName, const NPatchLoader::StretchRanges& stretchPixels, uint16_t imageExtent)
+{
+  uint16_t prevEnd = 0;
+  uint16_t prevFix = 0;
+  uint16_t prevStretch = 0;
+  unsigned int i = 1;
+  for( NPatchLoader::StretchRanges::ConstIterator it = stretchPixels.Begin(); it != stretchPixels.End(); ++it, ++i )
+  {
+    uint16_t start = it->GetX();
+    uint16_t end = it->GetY();
+
+    uint16_t fix = prevFix + start - prevEnd;
+    uint16_t stretch = prevStretch + end - start;
+
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
+
+    prevEnd = end;
+    prevFix = fix;
+    prevStretch = stretch;
+  }
+
+  {
+    prevFix += imageExtent - prevEnd;
+    std::stringstream uniform;
+    uniform << uniformName << "[" << i << "]";
+    renderer.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
+  }
+}
+
+} //unnamed namespace
+
+/////////////////NPatchVisual////////////////
+
+NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties )
+{
+  NPatchVisualPtr nPatchVisual( new NPatchVisual( factoryCache ) );
+  nPatchVisual->mImageUrl = imageUrl;
+  nPatchVisual->SetProperties( properties );
+
+  return nPatchVisual;
+}
+
+NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl )
+{
+  NPatchVisualPtr nPatchVisual( new NPatchVisual( factoryCache ) );
+  nPatchVisual->mImageUrl = imageUrl;
+
+  return nPatchVisual;
+}
+
+NPatchVisualPtr NPatchVisual::New( VisualFactoryCache& factoryCache, NinePatchImage image )
+{
+  NPatchVisualPtr nPatchVisual( new NPatchVisual( factoryCache ) );
+  VisualUrl visualUrl( image.GetUrl() );
+  nPatchVisual->mImageUrl = visualUrl;
+  return nPatchVisual;
+}
+
+void NPatchVisual::LoadImages()
+{
+  TextureManager& textureManager = mFactoryCache.GetTextureManager();
+  bool synchronousLoading = mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+
+  if( NPatchLoader::UNINITIALIZED_ID == mId && mImageUrl.IsLocalResource() )
+  {
+    bool preMultiplyOnLoad = IsPreMultipliedAlphaEnabled() && !mImpl->mCustomShader ? true : false;
+    mId = mLoader.Load( textureManager, this, mImageUrl.GetUrl(), mBorder, preMultiplyOnLoad, synchronousLoading );
+
+    const NPatchLoader::Data* data;
+    if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted )
+    {
+      EnablePreMultipliedAlpha( preMultiplyOnLoad );
+    }
+  }
+
+  if( !mAuxiliaryPixelBuffer && mAuxiliaryUrl.IsValid() && mAuxiliaryUrl.IsLocalResource() )
+  {
+    // Load the auxiliary image
+    auto preMultiplyOnLoading = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+    mAuxiliaryPixelBuffer = textureManager.LoadPixelBuffer( mAuxiliaryUrl, Dali::ImageDimensions(), FittingMode::DEFAULT,
+                                                            SamplingMode::BOX_THEN_LINEAR, synchronousLoading,
+                                                            this, true, preMultiplyOnLoading );
+  }
+}
+
+void NPatchVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  naturalSize.x = 0u;
+  naturalSize.y = 0u;
+
+  // load now if not already loaded
+  const NPatchLoader::Data* data;
+  if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted )
+  {
+    naturalSize.x = data->croppedWidth;
+    naturalSize.y = data->croppedHeight;
+  }
+  else
+  {
+    if( mImageUrl.IsValid() )
+    {
+      ImageDimensions dimensions = Dali::GetOriginalImageSize( mImageUrl.GetUrl() );
+      if( dimensions != ImageDimensions( 0, 0 ) )
+      {
+        naturalSize.x = dimensions.GetWidth();
+        naturalSize.y = dimensions.GetHeight();
+      }
+    }
+  }
+
+  if( mAuxiliaryPixelBuffer )
+  {
+    naturalSize.x = std::max( naturalSize.x, float(mAuxiliaryPixelBuffer.GetWidth()) );
+    naturalSize.y = std::max( naturalSize.y, float(mAuxiliaryPixelBuffer.GetHeight()) );
+  }
+}
+
+void NPatchVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // URL is already passed in via constructor
+
+  Property::Value* borderOnlyValue = propertyMap.Find( Toolkit::ImageVisual::Property::BORDER_ONLY, BORDER_ONLY );
+  if( borderOnlyValue )
+  {
+    borderOnlyValue->Get( mBorderOnly );
+  }
+
+  Property::Value* borderValue = propertyMap.Find( Toolkit::ImageVisual::Property::BORDER, BORDER );
+  if( borderValue && ! borderValue->Get( mBorder ) ) // If value exists and is rect, just set mBorder
+  {
+    // Not a rect so try vector4
+    Vector4 border;
+    if( borderValue->Get( border ) )
+    {
+      mBorder.left = static_cast< int >( border.x );
+      mBorder.right = static_cast< int >( border.y );
+      mBorder.bottom = static_cast< int >( border.z );
+      mBorder.top = static_cast< int >( border.w );
+    }
+  }
+
+  Property::Value* auxImage = propertyMap.Find( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, AUXILIARY_IMAGE_NAME );
+  if( auxImage )
+  {
+    std::string url;
+    if( auxImage->Get( url ) )
+    {
+      mAuxiliaryUrl = url;
+    }
+  }
+
+  Property::Value* auxImageAlpha = propertyMap.Find( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, AUXILIARY_IMAGE_ALPHA_NAME );
+  if( auxImageAlpha )
+  {
+    auxImageAlpha->Get( mAuxiliaryImageAlpha );
+  }
+
+  Property::Value* synchronousLoading = propertyMap.Find( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, SYNCHRONOUS_LOADING );
+  if( synchronousLoading )
+  {
+    bool sync = false;
+    synchronousLoading->Get( sync );
+    if( sync )
+    {
+      mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+    }
+    else
+    {
+      mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+    }
+  }
+}
+
+void NPatchVisual::DoSetOnStage( Actor& actor )
+{
+  // load when first go on stage
+  LoadImages();
+
+  const NPatchLoader::Data* data;
+  if( mLoader.GetNPatchData( mId, data ) )
+  {
+    Geometry geometry = CreateGeometry();
+    Shader shader = CreateShader();
+
+    mImpl->mRenderer = Renderer::New( geometry, shader );
+
+    mPlacementActor = actor;
+    if( data->loadCompleted )
+    {
+      ApplyTextureAndUniforms();
+      actor.AddRenderer( mImpl->mRenderer );
+      mPlacementActor.Reset();
+
+      // npatch loaded and ready to display
+      ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+    }
+  }
+}
+
+void NPatchVisual::DoSetOffStage( Actor& actor )
+{
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+  mPlacementActor.Reset();
+}
+
+void NPatchVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void NPatchVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::N_PATCH );
+  map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
+  map.Insert( Toolkit::ImageVisual::Property::BORDER_ONLY, mBorderOnly );
+  map.Insert( Toolkit::ImageVisual::Property::BORDER, mBorder );
+
+  if( mAuxiliaryUrl.IsValid() )
+  {
+    map.Insert( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl() );
+    map.Insert( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha );
+  }
+}
+
+void NPatchVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  if( mAuxiliaryUrl.IsValid() )
+  {
+    map.Insert( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE, mAuxiliaryUrl.GetUrl() );
+    map.Insert( Toolkit::DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA, mAuxiliaryImageAlpha );
+  }
+}
+
+NPatchVisual::NPatchVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mPlacementActor(),
+  mLoader( factoryCache.GetNPatchLoader() ),
+  mImageUrl(),
+  mAuxiliaryUrl(),
+  mId( NPatchLoader::UNINITIALIZED_ID ),
+  mBorderOnly( false ),
+  mBorder(),
+  mAuxiliaryImageAlpha( 0.0f )
+{
+  EnablePreMultipliedAlpha( mFactoryCache.GetPreMultiplyOnLoad() );
+}
+
+NPatchVisual::~NPatchVisual()
+{
+}
+
+Geometry NPatchVisual::CreateGeometry()
+{
+  Geometry geometry;
+  const NPatchLoader::Data* data;
+  if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted )
+  {
+    if( data->stretchPixelsX.Size() == 1 && data->stretchPixelsY.Size() == 1 )
+    {
+      if( DALI_UNLIKELY( mBorderOnly ) )
+      {
+        geometry = GetNinePatchGeometry( VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY );
+      }
+      else
+      {
+        geometry = GetNinePatchGeometry( VisualFactoryCache::NINE_PATCH_GEOMETRY );
+      }
+    }
+    else if( data->stretchPixelsX.Size() > 0 || data->stretchPixelsY.Size() > 0)
+    {
+      Uint16Pair gridSize( 2 * data->stretchPixelsX.Size() + 1,  2 * data->stretchPixelsY.Size() + 1 );
+      geometry = !mBorderOnly ? CreateGridGeometry( gridSize ) : CreateBorderGeometry( gridSize );
+    }
+  }
+  else
+  {
+    // no N patch data so use default geometry
+    geometry = GetNinePatchGeometry( VisualFactoryCache::NINE_PATCH_GEOMETRY );
+  }
+  return geometry;
+}
+
+Shader NPatchVisual::CreateShader()
+{
+  Shader shader;
+  const NPatchLoader::Data* data;
+  // 0 is either no data (load failed?) or no stretch regions on image
+  // for both cases we use the default shader
+  NPatchLoader::StretchRanges::SizeType xStretchCount = 0;
+  NPatchLoader::StretchRanges::SizeType yStretchCount = 0;
+
+  auto fragmentShader = mAuxiliaryPixelBuffer ? FRAGMENT_MASK_SHADER
+                                              : FRAGMENT_SHADER;
+  auto shaderType = mAuxiliaryPixelBuffer ? VisualFactoryCache::NINE_PATCH_MASK_SHADER
+                                          : VisualFactoryCache::NINE_PATCH_SHADER;
+
+  // ask loader for the regions
+  if( mLoader.GetNPatchData( mId, data ) )
+  {
+    xStretchCount = data->stretchPixelsX.Count();
+    yStretchCount = data->stretchPixelsY.Count();
+  }
+
+  if( DALI_LIKELY( !mImpl->mCustomShader ) )
+  {
+    if( DALI_LIKELY( ( xStretchCount == 1 && yStretchCount == 1 ) ||
+                     ( xStretchCount == 0 && yStretchCount == 0 ) ) )
+    {
+      shader = mFactoryCache.GetShader( shaderType );
+      if( DALI_UNLIKELY( !shader ) )
+      {
+        shader = Shader::New( VERTEX_SHADER_3X3, fragmentShader );
+        // Only cache vanilla 9 patch shaders
+        mFactoryCache.SaveShader( shaderType, shader );
+      }
+    }
+    else if( xStretchCount > 0 || yStretchCount > 0)
+    {
+      std::stringstream vertexShader;
+      vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
+                   << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
+                   << VERTEX_SHADER;
+
+      shader = Shader::New( vertexShader.str(), fragmentShader );
+    }
+  }
+  else
+  {
+    Dali::Shader::Hint::Value hints = Dali::Shader::Hint::NONE;
+
+    if( !mImpl->mCustomShader->mFragmentShader.empty() )
+    {
+      fragmentShader = mImpl->mCustomShader->mFragmentShader.c_str();
+    }
+    hints = mImpl->mCustomShader->mHints;
+
+    /* Apply Custom Vertex Shader only if image is 9-patch */
+    if( ( xStretchCount == 1 && yStretchCount == 1 ) ||
+        ( xStretchCount == 0 && yStretchCount == 0 ) )
+    {
+      const char* vertexShader = VERTEX_SHADER_3X3;
+
+      if( !mImpl->mCustomShader->mVertexShader.empty() )
+      {
+        vertexShader = mImpl->mCustomShader->mVertexShader.c_str();
+      }
+      shader = Shader::New( vertexShader, fragmentShader, hints );
+    }
+    else if( xStretchCount > 0 || yStretchCount > 0)
+    {
+      std::stringstream vertexShader;
+      vertexShader << "#define FACTOR_SIZE_X " << xStretchCount + 2 << "\n"
+                   << "#define FACTOR_SIZE_Y " << yStretchCount + 2 << "\n"
+                   << VERTEX_SHADER;
+
+      shader = Shader::New( vertexShader.str(), fragmentShader, hints );
+    }
+  }
+
+  return shader;
+}
+
+void NPatchVisual::ApplyTextureAndUniforms()
+{
+  const NPatchLoader::Data* data;
+  TextureSet textureSet;
+
+  if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted )
+  {
+    textureSet = data->textureSet;
+
+    if( data->stretchPixelsX.Size() == 1 && data->stretchPixelsY.Size() == 1 )
+    {
+      //special case for 9 patch
+      Uint16Pair stretchX = data->stretchPixelsX[ 0 ];
+      Uint16Pair stretchY = data->stretchPixelsY[ 0 ];
+
+      uint16_t stretchWidth = ( stretchX.GetY() >= stretchX.GetX() ) ? stretchX.GetY() - stretchX.GetX() : 0;
+      uint16_t stretchHeight = ( stretchY.GetY() >= stretchY.GetX() ) ? stretchY.GetY() - stretchY.GetX() : 0;
+
+      mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
+      mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2( data->croppedWidth - stretchWidth, data->croppedHeight - stretchHeight ) );
+      mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
+    }
+    else
+    {
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
+
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", data->stretchPixelsX, data->croppedWidth );
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", data->stretchPixelsY, data->croppedHeight );
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR("The N patch image '%s' is not a valid N patch image\n", mImageUrl.GetUrl().c_str() );
+    textureSet = TextureSet::New();
+
+    Image croppedImage = mFactoryCache.GetBrokenVisualImage();
+    TextureSetImage( textureSet, 0u, croppedImage );
+    mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO );
+    mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2::ZERO );
+    mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2::ZERO );
+    mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( croppedImage.GetWidth(), croppedImage.GetHeight() ) );
+  }
+
+  if( mAuxiliaryPixelBuffer )
+  {
+    // If the auxiliary image is smaller than the un-stretched NPatch, use CPU resizing to enlarge it to the
+    // same size as the unstretched NPatch. This will give slightly higher quality results than just relying
+    // on GL interpolation alone.
+    if( mAuxiliaryPixelBuffer.GetWidth() < data->croppedWidth &&
+        mAuxiliaryPixelBuffer.GetHeight() < data->croppedHeight )
+    {
+      mAuxiliaryPixelBuffer.Resize( data->croppedWidth, data->croppedHeight );
+    }
+
+    // Note, this resets mAuxiliaryPixelBuffer handle
+    auto auxiliaryPixelData = Devel::PixelBuffer::Convert( mAuxiliaryPixelBuffer );
+
+    auto texture = Texture::New( TextureType::TEXTURE_2D,
+                                 auxiliaryPixelData.GetPixelFormat(), auxiliaryPixelData.GetWidth(),
+                                 auxiliaryPixelData.GetHeight() );
+    texture.Upload( auxiliaryPixelData );
+    textureSet.SetTexture( 1, texture );
+    DevelHandle::RegisterProperty( mImpl->mRenderer, DevelImageVisual::Property::AUXILIARY_IMAGE_ALPHA,
+                                   AUXILIARY_IMAGE_ALPHA_NAME, mAuxiliaryImageAlpha );
+  }
+  mImpl->mRenderer.SetTextures( textureSet );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+Geometry NPatchVisual::GetNinePatchGeometry( VisualFactoryCache::GeometryType subType )
+{
+  Geometry geometry = mFactoryCache.GetGeometry( subType );
+  if( !geometry )
+  {
+    if( DALI_LIKELY( VisualFactoryCache::NINE_PATCH_GEOMETRY == subType ) )
+    {
+      geometry = CreateGridGeometry( Uint16Pair( 3, 3 ) );
+    }
+    else if( VisualFactoryCache::NINE_PATCH_BORDER_GEOMETRY == subType )
+    {
+      geometry = CreateBorderGeometry( Uint16Pair( 3, 3 ) );
+    }
+    mFactoryCache.SaveGeometry( subType, geometry );
+  }
+  return geometry;
+}
+
+Geometry NPatchVisual::CreateGridGeometry( Uint16Pair gridSize )
+{
+  uint16_t gridWidth = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector< Vector2 > vertices;
+  vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
+
+  for( int y = 0; y < gridHeight + 1; ++y )
+  {
+    for( int x = 0; x < gridWidth + 1; ++x )
+    {
+      AddVertex( vertices, x, y );
+    }
+  }
+
+  // Create indices
+  Vector< unsigned short > indices;
+  indices.Reserve( gridWidth * gridHeight * 6 );
+
+  unsigned int rowIdx     = 0;
+  unsigned int nextRowIdx = gridWidth + 1;
+  for( int y = 0; y < gridHeight; ++y, ++nextRowIdx, ++rowIdx )
+  {
+    for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+    {
+      AddQuadIndices( indices, rowIdx, nextRowIdx );
+    }
+  }
+
+  return GenerateGeometry( vertices, indices );
+}
+
+Geometry NPatchVisual::CreateBorderGeometry( Uint16Pair gridSize )
+{
+  uint16_t gridWidth = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector< Vector2 > vertices;
+  vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
+
+  //top
+  int y = 0;
+  for(; y < 2; ++y)
+  {
+    for( int x = 0; x < gridWidth + 1; ++x )
+    {
+      AddVertex( vertices, x, y );
+    }
+  }
+
+  for(; y < gridHeight - 1; ++y)
+  {
+    //left
+    AddVertex( vertices, 0, y );
+    AddVertex( vertices, 1, y );
+
+    //right
+    AddVertex( vertices, gridWidth - 1, y );
+    AddVertex( vertices, gridWidth, y );
+  }
+
+  //bottom
+  for(; y < gridHeight + 1; ++y)
+  {
+    for( int x = 0; x < gridWidth + 1; ++x )
+    {
+      AddVertex( vertices, x, y );
+    }
+  }
+
+  // Create indices
+  Vector< unsigned short > indices;
+  indices.Reserve( gridWidth * gridHeight * 6 );
+
+  //top
+  unsigned int rowIdx     = 0 ;
+  unsigned int nextRowIdx = gridWidth + 1;
+  for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+  {
+    AddQuadIndices( indices, rowIdx, nextRowIdx );
+  }
+
+  if(gridHeight > 2)
+  {
+    rowIdx     = gridWidth + 1;
+    nextRowIdx = ( gridWidth + 1 ) * 2;
+
+    unsigned increment = gridWidth - 1;
+    if(gridHeight > 3)
+    {
+      increment = 2;
+      //second row left
+      AddQuadIndices( indices, rowIdx, nextRowIdx );
+
+      rowIdx     = gridWidth * 2;
+      nextRowIdx = ( gridWidth + 1 ) * 2 + 2;
+      //second row right
+      AddQuadIndices( indices, rowIdx, nextRowIdx );
+
+      //left and right
+      rowIdx     = nextRowIdx - 2;
+      nextRowIdx = rowIdx + 4;
+      for(int y = 2; y < 2*(gridHeight - 3); ++y, rowIdx += 2, nextRowIdx += 2)
+      {
+        AddQuadIndices( indices, rowIdx, nextRowIdx );
+      }
+    }
+
+    //second row left
+    AddQuadIndices( indices, rowIdx, nextRowIdx );
+
+    rowIdx     += increment;
+    nextRowIdx += gridWidth - 1;
+    //second row right
+    AddQuadIndices( indices, rowIdx, nextRowIdx );
+  }
+
+  //bottom
+  rowIdx     = nextRowIdx - gridWidth + 1;
+  nextRowIdx = rowIdx + gridWidth + 1;
+  for( int x = 0; x < gridWidth; ++x, ++nextRowIdx, ++rowIdx )
+  {
+    AddQuadIndices( indices, rowIdx, nextRowIdx );
+  }
+
+  return GenerateGeometry( vertices, indices );
+}
+
+void NPatchVisual::SetResource()
+{
+  const NPatchLoader::Data* data;
+  if( mImpl->mRenderer && mLoader.GetNPatchData( mId, data ) )
+  {
+    Geometry geometry = CreateGeometry();
+    Shader shader = CreateShader();
+
+    mImpl->mRenderer.SetGeometry( geometry );
+    mImpl->mRenderer.SetShader( shader );
+
+    Actor actor = mPlacementActor.GetHandle();
+    if( actor )
+    {
+      ApplyTextureAndUniforms();
+      actor.AddRenderer( mImpl->mRenderer );
+      mPlacementActor.Reset();
+
+      // npatch loaded and ready to display
+      ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+    }
+  }
+}
+
+void NPatchVisual::LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied )
+{
+  if( url.GetUrl() == mAuxiliaryUrl.GetUrl() )
+  {
+    mAuxiliaryPixelBuffer = pixelBuffer;
+    const NPatchLoader::Data* data;
+    if( mLoader.GetNPatchData( mId, data ) && data->loadCompleted )
+    {
+      SetResource();
+    }
+  }
+  else
+  {
+    if( loadSuccess )
+    {
+      mLoader.SetNPatchData( mId, pixelBuffer );
+      EnablePreMultipliedAlpha( preMultiplied );
+    }
+
+    if( mAuxiliaryPixelBuffer || !mAuxiliaryUrl.IsValid() )
+    {
+      SetResource();
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/npatch/npatch-visual.h b/dali-toolkit/internal/visuals/npatch/npatch-visual.h
new file mode 100644 (file)
index 0000000..7816e84
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef DALI_TOOLKIT_INTERNAL_N_PATCH_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_N_PATCH_VISUAL_H
+
+/*
+ * Copyright (c) 2020 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/images/image.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/devel-api/images/nine-patch-image.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/sampler.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class NPatchVisual;
+typedef IntrusivePtr< NPatchVisual > NPatchVisualPtr;
+
+/**
+ * The visual which renders an 9 patch image to the control's quad
+ *
+ * The following properties are optional
+ *
+ * | %Property Name           | Type             |
+ * |--------------------------|------------------|
+ * | url                      | STRING           |
+ * | borderOnly               | BOOLEAN          |
+ * | border                   | RECTANGLE        |
+ * | auxiliaryImage           | STRING           |
+ * | auxiliaryImageAlpha      | FLOAT            |
+ */
+class NPatchVisual: public Visual::Base, public TextureUploadObserver
+{
+public:
+
+  /**
+   * @brief Create an N-patch visual using an image URL.
+   *
+   * The visual will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] imageUrl The URL to 9 patch image resource to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static NPatchVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties );
+
+  /**
+   * @brief Create an N-patch visual using an image URL.
+   *
+   * The visual will load the image synchronously when the associated actor is put on stage, and destroy the image when it is off stage
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] imageUrl The URL to 9 patch image resource to use
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static NPatchVisualPtr New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl );
+
+  /**
+   * @brief Create an N-patch visual with a NinePatchImage resource.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] image The NinePatchImage to use
+   */
+  static NPatchVisualPtr New( VisualFactoryCache& factoryCache, NinePatchImage image );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache Reference to the VisualFactoryCache object
+   */
+  NPatchVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~NPatchVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+
+  /**
+   * Loads the NPatch image and the Auxiliary image if needed
+   */
+  void LoadImages();
+
+  /**
+   * @brief Creates a geometry for this renderer's grid size
+   *
+   * @return Returns the created geometry for this renderer's grid size
+   */
+  Geometry CreateGeometry();
+
+  /**
+   * @brief Creates a shader for this renderer's grid size
+   *
+   * @return Returns the created shader for this renderer's grid size
+   */
+  Shader CreateShader();
+
+  /**
+   * @brief Applies texture and related uniforms
+   */
+  void ApplyTextureAndUniforms();
+
+  /**
+   * Helper method to get the default Nine patch geometry from cache or create and store it there
+   * @param subType to use
+   * @return the geometry
+   */
+  Geometry GetNinePatchGeometry( VisualFactoryCache::GeometryType subType );
+
+  /**
+   * @brief Creates a geometry for the grid size to be used by this visuals' shaders
+   *
+   * @param[in] gridSize The grid size of the solid geometry to create
+   * @return Returns the created geometry for the grid size
+   */
+  Geometry CreateGridGeometry( Uint16Pair gridSize );
+
+  /**
+   * @brief Creates a geometry with the border only for the grid size to be used by this visuals' shaders
+   * e.g. a 5x4 grid would create a geometry that would look like:
+   *
+   *   ---------------------
+   *   |  /|  /|  /|  /|  /|
+   *   |/  |/  |/  |/  |/  |
+   *   ---------------------
+   *   |  /|           |  /|
+   *   |/  |           |/  |
+   *   -----           -----
+   *   |  /|           |  /|
+   *   |/  |           |/  |
+   *   ---------------------
+   *   |  /|  /|  /|  /|  /|
+   *   |/  |/  |/  |/  |/  |
+   *   ---------------------
+   *
+   * @param[in] gridSize The grid size of the solid geometry to create
+   * @return Returns the created geometry for the grid size
+   */
+  Geometry CreateBorderGeometry( Uint16Pair gridSize );
+
+  /**
+   * @brief Creates a renderer by using loaded resource.
+   */
+  void SetResource();
+
+private:
+
+  /**
+   * @copydoc TextureUploadObserver::UploadCompleted
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the loading is finished.
+   */
+  void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing, const Vector4& atlasRect, bool preMultiplied ) override {}
+
+  /**
+   * @copydoc TextureUploadObserver::LoadComplete
+   *
+   * To avoid rendering garbage pixels, renderer should be added to actor after the resources are ready.
+   * This callback is the place to add the renderer as it would be called once the loading is finished.
+   */
+  void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const VisualUrl& url, bool preMultiplied ) override;
+
+private:
+
+  WeakHandle<Actor>  mPlacementActor;       ///< Weakhandle to contain Actor during texture loading
+  NPatchLoader&      mLoader;               ///< reference to N patch loader for fast access
+  VisualUrl          mImageUrl;             ///< The url to the N patch to load
+  VisualUrl          mAuxiliaryUrl;         ///< An auxiliary image that can be displayed on top of the N-Patch
+  std::size_t        mId;                   ///< id of the N patch (from loader/cache)
+  Devel::PixelBuffer mAuxiliaryPixelBuffer; ///< pixel buffer of the auxiliary mask image
+  bool               mBorderOnly;           ///< if only border is desired
+  Rect<int>          mBorder;               ///< The size of the border
+  float              mAuxiliaryImageAlpha;  ///< The alpha value for the auxiliary image only
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_N_PATCH_VISUAL_H
diff --git a/dali-toolkit/internal/visuals/primitive/primitive-visual.cpp b/dali-toolkit/internal/visuals/primitive/primitive-visual.cpp
new file mode 100644 (file)
index 0000000..8b2346c
--- /dev/null
@@ -0,0 +1,1506 @@
+/*
+ * Copyright (c) 2018 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 "primitive-visual.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/common/constants.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+// shapes
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SHAPE_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, SPHERE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CONICAL_FRUSTRUM ) // deprecated
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CONE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CYLINDER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CUBE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, OCTAHEDRON )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, BEVELLED_CUBE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CONICAL_FRUSTUM )
+DALI_ENUM_TO_STRING_TABLE_END( SHAPE_TYPE )
+
+//Primitive property defaults
+const int     DEFAULT_SLICES =              128; ///< For spheres and conics
+const int     DEFAULT_STACKS =              128; ///< For spheres and conics
+const float   DEFAULT_SCALE_TOP_RADIUS =    1.0; ///< For conical frustums
+const float   DEFAULT_SCALE_BOTTOM_RADIUS = 1.5; ///< For cones and conical frustums
+const float   DEFAULT_SCALE_HEIGHT =        3.0; ///< For all conics
+const float   DEFAULT_SCALE_RADIUS =        1.0; ///< For cylinders
+const float   DEFAULT_BEVEL_PERCENTAGE =    0.0; ///< For bevelled cubes
+const float   DEFAULT_BEVEL_SMOOTHNESS =    0.0; ///< For bevelled cubes
+const Vector4 DEFAULT_COLOR =               Vector4( 0.5, 0.5, 0.5, 1.0 ); ///< Grey, for all.
+
+//Property limits
+const int   MIN_SLICES =           3;   ///< Minimum number of slices for spheres and conics
+const int   MIN_STACKS =           2;   ///< Minimum number of stacks for spheres and conics
+const int   MAX_PARTITIONS =       255; ///< Maximum number of slices or stacks for spheres and conics
+const float MIN_BEVEL_PERCENTAGE = 0.0; ///< Minimum bevel percentage for bevelled cubes
+const float MAX_BEVEL_PERCENTAGE = 1.0; ///< Maximum bevel percentage for bevelled cubes
+const float MIN_SMOOTHNESS =       0.0; ///< Minimum bevel smoothness for bevelled cubes
+const float MAX_SMOOTHNESS =       1.0; ///< Maximum bevel smoothness for bevelled cubes
+
+//Specific shape labels.
+const char * const SPHERE_LABEL( "SPHERE" );
+const char * const CONE_LABEL( "CONE" );
+const char * const CONICAL_FRUSTRUM_LABEL( "CONICAL_FRUSTRUM" ); // deprecated
+const char * const CYLINDER_LABEL( "CYLINDER" );
+const char * const CUBE_LABEL( "CUBE" );
+const char * const OCTAHEDRON_LABEL( "OCTAHEDRON" );
+const char * const BEVELLED_CUBE_LABEL( "BEVELLED_CUBE" );
+const char * const CONICAL_FRUSTUM_LABEL( "CONICAL_FRUSTUM" );
+
+//Shader properties
+const char * const OBJECT_MATRIX_UNIFORM_NAME( "uObjectMatrix" );
+const char * const OBJECT_DIMENSIONS_UNIFORM_NAME( "uObjectDimensions" );
+const char * const STAGE_OFFSET_UNIFORM_NAME( "uStageOffset" );
+
+//Vertex properties
+const char * const POSITION( "aPosition");
+const char * const NORMAL( "aNormal" );
+const char * const INDICES( "aIndices" );
+
+//A simple shader that applies diffuse lighting to a mono-coloured object.
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute highp   vec3 aPosition;\n
+  attribute highp   vec2 aTexCoord;\n
+  attribute highp   vec3 aNormal;\n
+  varying   mediump vec3 vIllumination;\n
+  uniform   mediump vec3 uSize;\n
+  uniform   mediump vec3 uObjectDimensions;\n
+  uniform   mediump mat4 uMvpMatrix;\n
+  uniform   mediump mat4 uModelView;\n
+  uniform   mediump mat4 uViewMatrix;\n
+  uniform   mediump mat3 uNormalMatrix;\n
+  uniform   mediump mat4 uObjectMatrix;\n
+  uniform   mediump vec3 lightPosition;\n
+  uniform   mediump vec2 uStageOffset;\n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    float scaleFactor = min( visualSize.x / uObjectDimensions.x, visualSize.y / uObjectDimensions.y );\n
+    vec3 originFlipY =  vec3(origin.x, -origin.y, 0.0);
+    vec3 anchorPointFlipY = vec3( anchorPoint.x, -anchorPoint.y, 0.0);
+    vec3 offset = vec3( ( offset / uSize.xy ) * offsetSizeMode.xy + offset * (1.0-offsetSizeMode.xy), 0.0) * vec3(1.0,-1.0,1.0);\n
+
+    return vec4( (aPosition + anchorPointFlipY)*scaleFactor + (offset + originFlipY)*uSize, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    vec4 normalisedVertexPosition = ComputeVertexPosition();\n
+    vec4 vertexPosition = uObjectMatrix * normalisedVertexPosition;\n
+    vertexPosition = uMvpMatrix * vertexPosition;\n
+
+     //Illumination in Model-View space - Transform attributes and uniforms\n
+     vec4 mvVertexPosition = uModelView * normalisedVertexPosition;\n
+     vec3 normal = uNormalMatrix * mat3( uObjectMatrix ) * aNormal;\n
+
+     vec4 mvLightPosition = vec4( ( lightPosition.xy - uStageOffset ), lightPosition.z, 1.0 );\n
+     mvLightPosition = uViewMatrix * mvLightPosition;\n
+     vec3 vectorToLight = normalize( mvLightPosition.xyz - mvVertexPosition.xyz );\n
+
+     float lightDiffuse = max( dot( vectorToLight, normal ), 0.0 );\n
+     vIllumination = vec3( lightDiffuse * 0.5 + 0.5 );\n
+
+     gl_Position = vertexPosition;\n
+  }\n
+);
+
+//Very simple fragment shader that merely applies the vertex shading to the color at each fragment.
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  precision mediump float;\n
+  varying   mediump vec3  vIllumination;\n
+  uniform   lowp    vec4  uColor;\n
+  uniform   lowp    vec3  mixColor;\n
+  void main()\n
+  {\n
+      vec4 baseColor = vec4(mixColor, 1.0) * uColor;\n
+    gl_FragColor = vec4( vIllumination.rgb * baseColor.rgb, baseColor.a );\n
+  }\n
+);
+
+} // unnamed namespace
+
+PrimitiveVisualPtr PrimitiveVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  PrimitiveVisualPtr primitiveVisualPtr( new PrimitiveVisual( factoryCache ) );
+  primitiveVisualPtr->SetProperties( properties );
+  return primitiveVisualPtr;
+}
+
+PrimitiveVisual::PrimitiveVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
+  mScaleDimensions( Vector3::ONE ),
+  mScaleTopRadius( DEFAULT_SCALE_TOP_RADIUS ),
+  mScaleBottomRadius( DEFAULT_SCALE_BOTTOM_RADIUS ),
+  mScaleHeight( DEFAULT_SCALE_HEIGHT ),
+  mScaleRadius( DEFAULT_SCALE_RADIUS ),
+  mBevelPercentage( DEFAULT_BEVEL_PERCENTAGE ),
+  mBevelSmoothness( DEFAULT_BEVEL_SMOOTHNESS ),
+  mSlices( DEFAULT_SLICES ),
+  mStacks( DEFAULT_STACKS ),
+  mPrimitiveType( Toolkit::PrimitiveVisual::Shape::SPHERE )
+{
+  mImpl->mMixColor = DEFAULT_COLOR;
+}
+
+PrimitiveVisual::~PrimitiveVisual()
+{
+}
+
+void PrimitiveVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  //Find out which shape to renderer.
+  Property::Value* primitiveTypeValue = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SHAPE, PRIMITIVE_SHAPE );
+  if( primitiveTypeValue )
+  {
+    Scripting::GetEnumerationProperty( *primitiveTypeValue, SHAPE_TYPE_TABLE, SHAPE_TYPE_TABLE_COUNT, mPrimitiveType );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Fail to provide shape to the PrimitiveVisual object.\n" );
+  }
+
+  // By virtue of DoSetProperties being called last, this will override
+  // anything set by Toolkit::Visual::Property::MIX_COLOR
+  Property::Value* colorValue = propertyMap.Find( Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR );
+  if( colorValue )
+  {
+    Vector4 color;
+    if( colorValue->Get( color ) )
+    {
+      Property::Type type = colorValue->GetType();
+      if( type == Property::VECTOR4 )
+      {
+        SetMixColor( color );
+      }
+      else if( type == Property::VECTOR3 )
+      {
+        Vector3 color3(color);
+        SetMixColor( color3 );
+      }
+    }
+  }
+
+  Property::Value* slices = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SLICES, SLICES );
+  if( slices )
+  {
+    if( slices->Get( mSlices ) )
+    {
+      //Clamp value.
+      if( mSlices > MAX_PARTITIONS )
+      {
+        mSlices = MAX_PARTITIONS;
+        DALI_LOG_WARNING( "Value for slices clamped.\n" );
+      }
+      else if ( mSlices < MIN_SLICES )
+      {
+        mSlices = MIN_SLICES;
+        DALI_LOG_WARNING( "Value for slices clamped.\n" );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Invalid type for slices in PrimitiveVisual.\n" );
+    }
+  }
+
+  Property::Value* stacks = propertyMap.Find( Toolkit::PrimitiveVisual::Property::STACKS, STACKS );
+  if( stacks )
+  {
+    if( stacks->Get( mStacks ) )
+    {
+      //Clamp value.
+      if( mStacks > MAX_PARTITIONS )
+      {
+        mStacks = MAX_PARTITIONS;
+        DALI_LOG_WARNING( "Value for stacks clamped.\n" );
+      }
+      else if ( mStacks < MIN_STACKS )
+      {
+        mStacks = MIN_STACKS;
+        DALI_LOG_WARNING( "Value for stacks clamped.\n" );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Invalid type for stacks in PrimitiveVisual.\n" );
+    }
+  }
+
+  Property::Value* scaleTop = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, SCALE_TOP_RADIUS );
+  if( scaleTop && !scaleTop->Get( mScaleTopRadius ) )
+  {
+    DALI_LOG_ERROR( "Invalid type for scale top radius in PrimitiveVisual.\n" );
+  }
+
+  Property::Value* scaleBottom = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, SCALE_BOTTOM_RADIUS );
+  if( scaleBottom && !scaleBottom->Get( mScaleBottomRadius ) )
+  {
+    DALI_LOG_ERROR( "Invalid type for scale bottom radius in PrimitiveVisual.\n" );
+  }
+
+  Property::Value* scaleHeight = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, SCALE_HEIGHT );
+  if( scaleHeight && !scaleHeight->Get( mScaleHeight ) )
+  {
+    DALI_LOG_ERROR( "Invalid type for scale height in PrimitiveVisual.\n" );
+  }
+
+  Property::Value* scaleRadius = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, SCALE_RADIUS );
+  if( scaleRadius && !scaleRadius->Get( mScaleRadius ) )
+  {
+    DALI_LOG_ERROR( "Invalid type for scale radius in PrimitiveVisual.\n" );
+  }
+
+  Property::Value* dimensions = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, SCALE_DIMENSIONS );
+  if( dimensions )
+  {
+    if( dimensions->Get( mScaleDimensions ) )
+    {
+      //If any dimension is invalid, set it to a sensible default.
+      if( mScaleDimensions.x <= 0.0 )
+      {
+        mScaleDimensions.x = 1.0;
+        DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
+      }
+      if( mScaleDimensions.y <= 0.0 )
+      {
+        mScaleDimensions.y = 1.0;
+        DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
+      }
+      if( mScaleDimensions.z <= 0.0 )
+      {
+        mScaleDimensions.z = 1.0;
+        DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Invalid type for scale dimensions in PrimitiveVisual.\n" );
+    }
+  }
+
+  Property::Value* bevel = propertyMap.Find( Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, BEVEL_PERCENTAGE );
+  if( bevel )
+  {
+    if( bevel->Get( mBevelPercentage ) )
+    {
+      //Clamp value.
+      if( mBevelPercentage < MIN_BEVEL_PERCENTAGE )
+      {
+        mBevelPercentage = MIN_BEVEL_PERCENTAGE;
+        DALI_LOG_WARNING( "Value for bevel percentage clamped.\n" );
+      }
+      else if( mBevelPercentage > MAX_BEVEL_PERCENTAGE )
+      {
+        mBevelPercentage = MAX_BEVEL_PERCENTAGE;
+        DALI_LOG_WARNING( "Value for bevel percentage clamped.\n" );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Invalid type for bevel percentage in PrimitiveVisual.\n" );
+    }
+  }
+
+  Property::Value* smoothness = propertyMap.Find( Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, BEVEL_SMOOTHNESS );
+  if( smoothness )
+  {
+    if( smoothness->Get( mBevelSmoothness ) )
+    {
+      //Clamp value.
+      if( mBevelSmoothness < MIN_SMOOTHNESS )
+      {
+        mBevelSmoothness = MIN_SMOOTHNESS;
+        DALI_LOG_WARNING( "Value for bevel smoothness clamped.\n" );
+      }
+      else if( mBevelSmoothness > MAX_SMOOTHNESS )
+      {
+        mBevelSmoothness = MAX_SMOOTHNESS;
+        DALI_LOG_WARNING( "Value for bevel smoothness clamped.\n" );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Invalid type for bevel smoothness in PrimitiveVisual.\n" );
+    }
+  }
+
+  //Read in light position.
+  Property::Value* lightPosition = propertyMap.Find( Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, LIGHT_POSITION_UNIFORM_NAME );
+  if( lightPosition )
+  {
+    if( !lightPosition->Get( mLightPosition ) )
+    {
+      DALI_LOG_ERROR( "Invalid value passed for light position in MeshVisual object.\n" );
+      mLightPosition = Vector3::ZERO;
+    }
+  }
+  else
+  {
+    //Default behaviour is to place the light directly in front of the object,
+    // at a reasonable distance to light everything on screen.
+    Stage stage = Stage::GetCurrent();
+
+    mLightPosition = Vector3( stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5 );
+  }
+}
+
+void PrimitiveVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( !mGeometry )
+  {
+    CreateGeometry();
+  }
+
+  naturalSize.x = mObjectDimensions.x;
+  naturalSize.y = mObjectDimensions.y;
+}
+
+void PrimitiveVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Primitive generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void PrimitiveVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::PRIMITIVE );
+  map.Insert( Toolkit::PrimitiveVisual::Property::MIX_COLOR, mImpl->mMixColor );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SHAPE, mPrimitiveType );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SLICES, mSlices );
+  map.Insert( Toolkit::PrimitiveVisual::Property::STACKS, mStacks );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, mScaleTopRadius );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, mScaleBottomRadius );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, mScaleHeight );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, mScaleRadius );
+  map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, mScaleDimensions );
+  map.Insert( Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, mBevelPercentage );
+  map.Insert( Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, mBevelSmoothness );
+  map.Insert( Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, mLightPosition );
+}
+
+void PrimitiveVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void PrimitiveVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+void PrimitiveVisual::InitializeRenderer()
+{
+  if( !mGeometry )
+  {
+    CreateGeometry();
+  }
+
+  if( !mShader )
+  {
+    CreateShader();
+  }
+
+  mImpl->mRenderer = Renderer::New( mGeometry, mShader );
+  mImpl->mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  mImpl->mMixColorIndex = DevelHandle::RegisterProperty( mImpl->mRenderer, Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor) );
+}
+
+void PrimitiveVisual::UpdateShaderUniforms()
+{
+  Stage stage = Stage::GetCurrent();
+  float width = stage.GetSize().width;
+  float height = stage.GetSize().height;
+
+  //Flip model to account for DALi starting with (0, 0) at the top left.
+  Matrix scaleMatrix;
+  scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+
+  mShader.RegisterProperty( STAGE_OFFSET_UNIFORM_NAME, Vector2( width, height ) / 2.0f );
+  mShader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, mLightPosition );
+  mShader.RegisterProperty( OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix );
+  mShader.RegisterProperty( OBJECT_DIMENSIONS_UNIFORM_NAME, mObjectDimensions );
+}
+
+void PrimitiveVisual::CreateShader()
+{
+  mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+  UpdateShaderUniforms();
+}
+
+void PrimitiveVisual::CreateGeometry()
+{
+  Dali::Vector<Vertex> vertices;
+  Dali::Vector<unsigned short> indices;
+
+  switch( mPrimitiveType )
+  {
+    case Toolkit::PrimitiveVisual::Shape::SPHERE:
+    {
+      CreateSphere( vertices, indices, mSlices, mStacks );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::CONE:
+    {
+      //Create a conic with zero top radius.
+      CreateConic( vertices, indices, 0, mScaleBottomRadius, mScaleHeight, mSlices );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTRUM: // deprecated
+    {
+      CreateConic( vertices, indices, mScaleTopRadius, mScaleBottomRadius, mScaleHeight, mSlices );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::CYLINDER:
+    {
+      //Create a conic with equal radii on the top and bottom.
+      CreateConic( vertices, indices, mScaleRadius, mScaleRadius, mScaleHeight, mSlices );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::CUBE:
+    {
+      //Create a cube by creating a bevelled cube with minimum bevel.
+      CreateBevelledCube( vertices, indices, mScaleDimensions, 0.0, 0.0 );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::OCTAHEDRON:
+    {
+      //Create an octahedron by creating a bevelled cube with maximum bevel.
+      CreateBevelledCube( vertices, indices, mScaleDimensions, 1.0, mBevelSmoothness );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::BEVELLED_CUBE:
+    {
+      CreateBevelledCube( vertices, indices, mScaleDimensions, mBevelPercentage, mBevelSmoothness );
+      break;
+    }
+    case Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTUM:
+    {
+      CreateConic( vertices, indices, mScaleTopRadius, mScaleBottomRadius, mScaleHeight, mSlices );
+      break;
+    }
+  }
+
+  mGeometry = Geometry::New();
+
+  //Vertices
+  Property::Map vertexFormat;
+  vertexFormat[POSITION] = Property::VECTOR3;
+  vertexFormat[NORMAL] = Property::VECTOR3;
+  PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat );
+  surfaceVertices.SetData( &vertices[0], vertices.Size() );
+
+  mGeometry.AddVertexBuffer( surfaceVertices );
+
+  //Indices for triangle formulation
+  mGeometry.SetIndexBuffer( &indices[0], indices.Size() );
+}
+
+void PrimitiveVisual::CreateSphere( Vector<Vertex>& vertices, Vector<unsigned short>& indices, int slices, int stacks )
+{
+  ComputeSphereVertices( vertices, slices, stacks );
+  FormSphereTriangles( indices, slices, stacks );
+
+  mObjectDimensions = Vector3::ONE;
+}
+
+void PrimitiveVisual::CreateConic( Vector<Vertex>& vertices, Vector<unsigned short>& indices, float scaleTopRadius,
+                                   float scaleBottomRadius, float scaleHeight, int slices )
+{
+  ComputeConicVertices( vertices, scaleTopRadius, scaleBottomRadius, scaleHeight, slices );
+  FormConicTriangles( indices, scaleTopRadius, scaleBottomRadius, slices );
+
+  //Determine object dimensions, and scale them to be between 0.0 and 1.0.
+  float xDimension = std::max( scaleTopRadius, scaleBottomRadius ) * 2.0f;
+  float yDimension = scaleHeight;
+  float largestDimension = std::max( xDimension, yDimension );
+
+  mObjectDimensions = Vector3( xDimension / largestDimension, yDimension / largestDimension,
+                               xDimension / largestDimension );
+}
+
+void PrimitiveVisual::CreateBevelledCube( Vector<Vertex>& vertices, Vector<unsigned short>& indices,
+                                          Vector3 dimensions, float bevelPercentage, float bevelSmoothness )
+{
+  float maxDimension = std::max( std::max( dimensions.x, dimensions.y ), dimensions.z );
+  dimensions = dimensions / maxDimension;
+
+  if( bevelPercentage <= MIN_BEVEL_PERCENTAGE ) //No bevel, form a cube.
+  {
+    ComputeCubeVertices( vertices, dimensions );
+    FormCubeTriangles( indices );
+  }
+  else if( bevelPercentage >= MAX_BEVEL_PERCENTAGE ) //Max bevel, form an octahedron.
+  {
+    ComputeOctahedronVertices( vertices, dimensions, bevelSmoothness );
+    FormOctahedronTriangles( indices );
+  }
+  else //In between, form a bevelled cube.
+  {
+    ComputeBevelledCubeVertices( vertices, dimensions, bevelPercentage, bevelSmoothness );
+    FormBevelledCubeTriangles( indices );
+  }
+
+  mObjectDimensions = dimensions;
+}
+
+void PrimitiveVisual::ComputeCircleTables( Vector<float>& sinTable, Vector<float>& cosTable, int divisions,
+                                           bool halfCircle )
+{
+  if( divisions < 0 )
+  {
+    return;
+  }
+
+  const float angleDivision = ( halfCircle ? 1.0f : 2.0f ) * Dali::Math::PI / ( float ) divisions;
+
+  sinTable.Resize( divisions );
+  cosTable.Resize( divisions );
+
+  for( int i = 0; i < divisions; i++ )
+  {
+    sinTable[i] = sin( angleDivision * i );
+    cosTable[i] = cos( angleDivision * i );
+  }
+}
+
+void PrimitiveVisual::ComputeSphereVertices( Vector<Vertex>& vertices, int slices, int stacks )
+{
+  //Tables for calculating slices angles and stacks angles, respectively.
+  Vector<float> sinTable1;
+  Vector<float> cosTable1;
+  Vector<float> sinTable2;
+  Vector<float> cosTable2;
+
+  ComputeCircleTables( sinTable1, cosTable1, slices, false );
+  ComputeCircleTables( sinTable2, cosTable2, stacks, true );
+
+  int numVertices = slices * ( stacks - 1 ) + 2;
+  vertices.Resize( numVertices );
+
+  int vertexIndex = 0;  //Track progress through vertices.
+  float x;
+  float y;
+  float z;
+
+  //Top stack.
+  vertices[vertexIndex].position = Vector3( 0.0, 0.5, 0.0 );
+  vertices[vertexIndex].normal =   Vector3( 0.0, 1.0, 0.0 );
+  vertexIndex++;
+
+  //Middle stacks.
+  for( int i = 1; i < stacks; i++ )
+  {
+    for( int j = 0; j < slices; j++, vertexIndex++ )
+    {
+      x = cosTable1[j] * sinTable2[i];
+      y = cosTable2[i];
+      z = sinTable1[j] * sinTable2[i];
+
+      vertices[vertexIndex].position = Vector3( x / 2.0f, y / 2.0f, z / 2.0f );
+      vertices[vertexIndex].normal = Vector3( x, y, z );
+    }
+  }
+
+  //Bottom stack.
+  vertices[vertexIndex].position = Vector3( 0.0, -0.5, 0.0 );
+  vertices[vertexIndex].normal =   Vector3( 0.0, -1.0, 0.0 );
+}
+
+void PrimitiveVisual::FormSphereTriangles( Vector<unsigned short>& indices, int slices, int stacks )
+{
+  if( stacks <= 1 )
+  {
+    //Set indices to placeholder "error" values.
+    //This will display nothing, which is the expected behaviour for this edge case.
+    indices.Resize( 3 );
+    return;
+  }
+
+  int numTriangles = 2 * slices * ( stacks - 1 );
+
+  indices.Resize( 3 * numTriangles );
+
+  int indiceIndex = 0;  //Used to keep track of progress through indices.
+  int previousCycleBeginning = 1;  //Stores the index of the vertex that started the cycle of the previous stack.
+  int currentCycleBeginning = 1 + slices;
+
+  //Top stack. Loop from index 1 to index slices, as not counting the very first vertex.
+  for( int i = 1; i <= slices; i++, indiceIndex += 3 )
+  {
+    indices[indiceIndex] = 0;
+    if( i == slices )
+    {
+      //End, so loop around.
+      indices[indiceIndex + 1] = 1;
+    }
+    else
+    {
+      indices[indiceIndex + 1] = i + 1;
+    }
+    indices[indiceIndex + 2] = i;
+  }
+
+  //Middle Stacks. Want to form triangles between the top and bottom stacks, so loop up to the number of stacks - 2.
+  for( int i = 0; i < stacks - 2; i++, previousCycleBeginning += slices, currentCycleBeginning += slices )
+  {
+    for( int j = 0; j < slices; j++, indiceIndex += 6 )
+    {
+      if( j == slices - 1 )
+      {
+        //End, so loop around.
+        indices[indiceIndex] =     previousCycleBeginning + j;
+        indices[indiceIndex + 1] = previousCycleBeginning;
+        indices[indiceIndex + 2] = currentCycleBeginning + j;
+        indices[indiceIndex + 3] = currentCycleBeginning + j;
+        indices[indiceIndex + 4] = previousCycleBeginning;
+        indices[indiceIndex + 5] = currentCycleBeginning;
+      }
+      else
+      {
+        indices[indiceIndex] =     previousCycleBeginning + j;
+        indices[indiceIndex + 1] = previousCycleBeginning + 1 + j;
+        indices[indiceIndex + 2] = currentCycleBeginning + j;
+        indices[indiceIndex + 3] = currentCycleBeginning + j;
+        indices[indiceIndex + 4] = previousCycleBeginning + 1 + j;
+        indices[indiceIndex + 5] = currentCycleBeginning + 1 + j;
+      }
+    }
+  }
+
+  //Bottom stack. Loop around the last stack from the previous loop, and go up to the penultimate vertex.
+  for( int i = 0; i < slices; i++, indiceIndex += 3 )
+  {
+    indices[indiceIndex] = previousCycleBeginning + slices;
+    indices[indiceIndex + 1] = previousCycleBeginning + i;
+    if( i == slices - 1 )
+    {
+      //End, so loop around.
+      indices[indiceIndex + 2] = previousCycleBeginning;
+    }
+    else
+    {
+      indices[indiceIndex + 2] = previousCycleBeginning + i + 1;
+    }
+  }
+}
+
+void PrimitiveVisual::ComputeConicVertices( Vector<Vertex>& vertices, float scaleTopRadius,
+                                            float scaleBottomRadius, float scaleHeight, int slices )
+{
+  int vertexIndex = 0;  //Track progress through vertices.
+  Vector<float> sinTable;
+  Vector<float> cosTable;
+
+  ComputeCircleTables( sinTable, cosTable, slices, false );
+
+  int numVertices = 2;  //Always will have one at the top and one at the bottom.
+
+  //Add vertices for each circle. Need two per point for different face normals.
+  if( scaleTopRadius > 0.0 )
+  {
+    numVertices += 2 * slices;
+  }
+  if( scaleBottomRadius > 0.0 )
+  {
+    numVertices += 2 * slices;
+  }
+
+  vertices.Resize( numVertices );
+
+
+  //Scale to bounding region of -0.5 to 0.5 (i.e range of 1).
+  float biggestObjectDimension = std::max( std::max( scaleTopRadius * 2.0f, scaleBottomRadius * 2.0f ), scaleHeight );
+  scaleTopRadius = scaleTopRadius / biggestObjectDimension;
+  scaleBottomRadius = scaleBottomRadius / biggestObjectDimension;
+
+  //Dimensions for vertex coordinates. Y is constant, and so can be initialised now.
+  float x;
+  float y = scaleHeight / biggestObjectDimension / 2.0f;
+  float z;
+
+  //Top center.
+  vertices[0].position = Vector3( 0, y, 0 );
+  vertices[0].normal = Vector3( 0, 1, 0 );
+  vertexIndex++;
+
+  //Top circle.
+  if( scaleTopRadius > 0.0 )
+  {
+    //Loop around the circle.
+    for( int i = 0; i < slices; i++, vertexIndex++ )
+    {
+      x = sinTable[i] * scaleTopRadius;
+      z = cosTable[i] * scaleTopRadius;
+
+      //Upward-facing normal.
+      vertices[vertexIndex].position = Vector3( x, y, z );
+      vertices[vertexIndex].normal = Vector3( 0, 1, 0 );
+
+      //Outward-facing normal.
+      vertices[vertexIndex + slices].position = Vector3( x, y, z );
+      vertices[vertexIndex + slices].normal = Vector3( x, 0, z );
+    }
+
+    vertexIndex += slices;
+  }
+
+  //Bottom circle.
+  if( scaleBottomRadius > 0.0 )
+  {
+    //Loop around the circle.
+    for( int i = 0; i < slices; i++, vertexIndex++ )
+    {
+      x = sinTable[i] * scaleBottomRadius;
+      z = cosTable[i] * scaleBottomRadius;
+
+      //Outward-facing normal.
+      vertices[vertexIndex].position = Vector3( x, -y, z );
+      vertices[vertexIndex].normal = Vector3( x, 0, z );
+
+      //Downward-facing normal.
+      vertices[vertexIndex + slices].position = Vector3( x, -y, z );
+      vertices[vertexIndex + slices].normal = Vector3( 0, -1, 0 );
+    }
+
+    vertexIndex += slices;
+  }
+
+  //Bottom center.
+  vertices[vertexIndex].position = Vector3( 0, -y, 0 );
+  vertices[vertexIndex].normal = Vector3( 0, -1, 0 );
+  vertexIndex++;
+}
+
+void PrimitiveVisual::FormConicTriangles( Vector<unsigned short>& indices, float scaleTopRadius,
+                                          float scaleBottomRadius, int slices )
+{
+  int  indiceIndex = 0;  //Track progress through indices.
+  int  numTriangles = 0;
+  bool coneTop = scaleTopRadius <= 0.0;
+  bool coneBottom = scaleBottomRadius <= 0.0;
+
+  if( coneTop && coneBottom )
+  {
+    //Set indices to placeholder "error" values.
+    //This will display nothing, which is the expected behaviour for this edge case.
+    indices.Resize( 3 );
+    return;
+  }
+
+  if( !coneTop )
+  {
+    numTriangles += 2 * slices;
+  }
+  if( !coneBottom )
+  {
+    numTriangles += 2 * slices;
+  }
+
+  indices.Resize( 3 * numTriangles );
+
+  //Switch on the type of conic we have.
+  if( !coneTop && !coneBottom )
+  {
+    //Top circle. Start at index of first outer point and go around.
+    for( int i = 1; i <= slices; i++, indiceIndex += 3 )
+    {
+      indices[indiceIndex] = 0;
+      indices[indiceIndex + 1] = i;
+      if( i == slices )
+      {
+        //End, so loop around.
+        indices[indiceIndex + 2] = 1;
+      }
+      else
+      {
+        indices[indiceIndex + 2] = i + 1;
+      }
+    }
+
+    int topCycleBeginning = slices + 1;
+    int bottomCycleBeginning = topCycleBeginning + slices;
+
+    //Vertical edges.
+    for( int i = 0; i < slices; i++, indiceIndex += 6 )
+    {
+      if( i == slices - 1 )
+      {
+        //End, so loop around.
+        indices[indiceIndex] =     topCycleBeginning + i;
+        indices[indiceIndex + 1] = bottomCycleBeginning + i;
+        indices[indiceIndex + 2] = topCycleBeginning;
+        indices[indiceIndex + 3] = bottomCycleBeginning + i;
+        indices[indiceIndex + 4] = bottomCycleBeginning;
+        indices[indiceIndex + 5] = topCycleBeginning;
+      }
+      else
+      {
+        indices[indiceIndex] =     topCycleBeginning + i;
+        indices[indiceIndex + 1] = bottomCycleBeginning + i;
+        indices[indiceIndex + 2] = topCycleBeginning + 1 + i;
+        indices[indiceIndex + 3] = bottomCycleBeginning + i;
+        indices[indiceIndex + 4] = bottomCycleBeginning + 1 + i;
+        indices[indiceIndex + 5] = topCycleBeginning + 1 + i;
+      }
+    }
+
+    int bottomFaceCycleBeginning = bottomCycleBeginning + slices;
+
+    //Bottom circle.
+    for( int i = 0; i < slices; i++, indiceIndex += 3 )
+    {
+      indices[indiceIndex] = bottomFaceCycleBeginning;
+      if( i == slices - 1 )
+      {
+        //End, so loop around.
+        indices[indiceIndex + 1] = bottomFaceCycleBeginning;
+      }
+      else
+      {
+        indices[indiceIndex + 1] = bottomFaceCycleBeginning + i + 1;
+      }
+      indices[indiceIndex + 2] = bottomFaceCycleBeginning + i;
+    }
+  }
+  else if( !coneTop || !coneBottom )
+  {
+    //Top circle/edges. Start at index of first outer point and go around.
+    for( int i = 1; i <= slices; i++, indiceIndex += 3 )
+    {
+      indices[indiceIndex] = 0;
+      indices[indiceIndex + 1] = i;
+      if( i == slices )
+      {
+        //End, so loop around.
+        indices[indiceIndex + 2] = 1;
+      }
+      else
+      {
+        indices[indiceIndex + 2] = i + 1;
+      }
+    }
+
+    //Bottom circle/edges. Start at index of first outer point and go around.
+    for( int i = 1; i <= slices; i++, indiceIndex += 3 )
+    {
+      indices[indiceIndex] = 2 * slices + 1;
+      if( i == slices )
+      {
+        //End, so loop around.
+        indices[indiceIndex + 1] = slices + 1;
+      }
+      else
+      {
+        indices[indiceIndex + 1] = slices + i + 1;
+      }
+      indices[indiceIndex + 2] = slices + i;
+    }
+  }
+}
+
+void PrimitiveVisual::ComputeCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions )
+{
+  int numVertices = 4 * 6; //Four per face.
+  int vertexIndex = 0; //Tracks progress through vertices.
+  float scaledX = 0.5 * dimensions.x;
+  float scaledY = 0.5 * dimensions.y;
+  float scaledZ = 0.5 * dimensions.z;
+
+  vertices.Resize( numVertices );
+
+  Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
+  positions.Resize(8);
+  Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
+  normals.Resize(6);
+
+  positions[0] = Vector3( -scaledX,  scaledY, -scaledZ );
+  positions[1] = Vector3(  scaledX,  scaledY, -scaledZ );
+  positions[2] = Vector3(  scaledX,  scaledY,  scaledZ );
+  positions[3] = Vector3( -scaledX,  scaledY,  scaledZ );
+  positions[4] = Vector3( -scaledX, -scaledY, -scaledZ );
+  positions[5] = Vector3(  scaledX, -scaledY, -scaledZ );
+  positions[6] = Vector3(  scaledX, -scaledY,  scaledZ );
+  positions[7] = Vector3( -scaledX, -scaledY,  scaledZ );
+
+  normals[0] = Vector3(  0,  1,  0 );
+  normals[1] = Vector3(  0,  0, -1 );
+  normals[2] = Vector3(  1,  0,  0 );
+  normals[3] = Vector3(  0,  0,  1 );
+  normals[4] = Vector3( -1,  0,  0 );
+  normals[5] = Vector3(  0, -1,  0 );
+
+  //Top face, upward normals.
+  for( int i = 0; i < 4; i++, vertexIndex++ )
+  {
+    vertices[vertexIndex].position = positions[i];
+    vertices[vertexIndex].normal = normals[0];
+  }
+
+  //Top face, outward normals.
+  for( int i = 0; i < 4; i++, vertexIndex += 2 )
+  {
+    vertices[vertexIndex].position = positions[i];
+    vertices[vertexIndex].normal = normals[i + 1];
+
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex + 1].position = positions[0];
+    }
+    else
+    {
+      vertices[vertexIndex + 1].position = positions[i + 1];
+    }
+    vertices[vertexIndex + 1].normal = normals[i + 1];
+  }
+
+  //Bottom face, outward normals.
+  for( int i = 0; i < 4; i++, vertexIndex += 2 )
+  {
+    vertices[vertexIndex].position = positions[i + 4];
+    vertices[vertexIndex].normal = normals[i + 1];
+
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex + 1].position = positions[4];
+    }
+    else
+    {
+      vertices[vertexIndex + 1].position = positions[i + 5];
+    }
+    vertices[vertexIndex + 1].normal = normals[i + 1];
+  }
+
+  //Bottom face, downward normals.
+  for( int i = 0; i < 4; i++, vertexIndex++ )
+  {
+    vertices[vertexIndex].position = positions[i + 4];
+    vertices[vertexIndex].normal = normals[5];
+  }
+
+}
+
+void PrimitiveVisual::FormCubeTriangles( Vector<unsigned short>& indices )
+{
+  int numTriangles = 12;
+  int triangleIndex = 0;  //Track progress through indices.
+
+  indices.Resize( 3 * numTriangles );
+
+  //Top face.
+  indices[triangleIndex] =     0;
+  indices[triangleIndex + 1] = 2;
+  indices[triangleIndex + 2] = 1;
+  indices[triangleIndex + 3] = 2;
+  indices[triangleIndex + 4] = 0;
+  indices[triangleIndex + 5] = 3;
+  triangleIndex += 6;
+
+  int topFaceStart = 4;
+  int bottomFaceStart = 12;
+
+  //Side faces.
+  for( int i = 0; i < 8; i += 2, triangleIndex += 6 )
+  {
+    indices[triangleIndex    ] = i + topFaceStart;
+    indices[triangleIndex + 1] = i + topFaceStart + 1;
+    indices[triangleIndex + 2] = i + bottomFaceStart + 1;
+    indices[triangleIndex + 3] = i + topFaceStart;
+    indices[triangleIndex + 4] = i + bottomFaceStart + 1;
+    indices[triangleIndex + 5] = i + bottomFaceStart;
+  }
+
+  //Bottom face.
+  indices[triangleIndex] =     20;
+  indices[triangleIndex + 1] = 21;
+  indices[triangleIndex + 2] = 22;
+  indices[triangleIndex + 3] = 22;
+  indices[triangleIndex + 4] = 23;
+  indices[triangleIndex + 5] = 20;
+}
+
+void PrimitiveVisual::ComputeOctahedronVertices( Vector<Vertex>& vertices, Vector3 dimensions, float smoothness )
+{
+  int numVertices = 3 * 8; //Three per face
+  int vertexIndex = 0; //Tracks progress through vertices.
+  float scaledX = 0.5 * dimensions.x;
+  float scaledY = 0.5 * dimensions.y;
+  float scaledZ = 0.5 * dimensions.z;
+
+  vertices.Resize( numVertices );
+
+  Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
+  positions.Resize(6);
+  Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
+  normals.Resize(8);
+  Vector<Vector3> outerNormals;  //Holds normals that point outwards at each vertex.
+  outerNormals.Resize( 6 );
+
+  positions[0] = Vector3(  0.0,  scaledY,  0.0 );
+  positions[1] = Vector3( -scaledX,  0.0,  0.0 );
+  positions[2] = Vector3(  0.0,  0.0, -scaledZ );
+  positions[3] = Vector3(  scaledX,  0.0,  0.0 );
+  positions[4] = Vector3(  0.0,  0.0,  scaledZ );
+  positions[5] = Vector3(  0.0, -scaledY,  0.0 );
+
+  normals[0] = Vector3( -1,  1, -1 );
+  normals[1] = Vector3(  1,  1, -1 );
+  normals[2] = Vector3(  1,  1,  1 );
+  normals[3] = Vector3( -1,  1,  1 );
+  normals[4] = Vector3( -1, -1, -1 );
+  normals[5] = Vector3(  1, -1, -1 );
+  normals[6] = Vector3(  1, -1,  1 );
+  normals[7] = Vector3( -1, -1,  1 );
+
+  outerNormals[0] = Vector3(  0,  1,  0 );
+  outerNormals[1] = Vector3( -1,  0,  0 );
+  outerNormals[2] = Vector3(  0,  0, -1 );
+  outerNormals[3] = Vector3(  1,  0,  0 );
+  outerNormals[4] = Vector3(  0,  0,  1 );
+  outerNormals[5] = Vector3(  0, -1,  0 );
+
+  //Loop through top faces.
+  for( int i = 0; i < 4; i++, vertexIndex += 3 )
+  {
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex    ].position = positions[0];
+      vertices[vertexIndex    ].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
+      vertices[vertexIndex + 1].position = positions[1];
+      vertices[vertexIndex + 1].normal = outerNormals[1] * smoothness + normals[i] * (1 - smoothness);
+      vertices[vertexIndex + 2].position = positions[i + 1];
+      vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
+    }
+    else
+    {
+      vertices[vertexIndex    ].position = positions[0];
+      vertices[vertexIndex    ].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
+      vertices[vertexIndex + 1].position = positions[i + 2];
+      vertices[vertexIndex + 1].normal = outerNormals[i + 2] * smoothness + normals[i] * (1 - smoothness);
+      vertices[vertexIndex + 2].position = positions[i + 1];
+      vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
+    }
+  }
+
+  //Loop through bottom faces.
+  for( int i = 0; i < 4; i++, vertexIndex += 3 )
+  {
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex    ].position = positions[5];
+      vertices[vertexIndex    ].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
+      vertices[vertexIndex + 1].position = positions[i + 1];
+      vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
+      vertices[vertexIndex + 2].position = positions[1];
+      vertices[vertexIndex + 2].normal = outerNormals[1] * smoothness + normals[i + 4] * (1 - smoothness);
+    }
+    else
+    {
+      vertices[vertexIndex    ].position = positions[5];
+      vertices[vertexIndex    ].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
+      vertices[vertexIndex + 1].position = positions[i + 1];
+      vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
+      vertices[vertexIndex + 2].position = positions[i + 2];
+      vertices[vertexIndex + 2].normal = outerNormals[i + 2] * smoothness + normals[i + 4] * (1 - smoothness);
+    }
+  }
+}
+
+void PrimitiveVisual::FormOctahedronTriangles( Vector<unsigned short>& indices )
+{
+  int numTriangles = 8;
+  int numIndices = numTriangles * 3;
+
+  indices.Resize( numIndices );
+
+  for( unsigned short i = 0; i < numIndices; i++ )
+  {
+    indices[i] = i;
+  }
+}
+
+void PrimitiveVisual::ComputeBevelledCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions,
+                                                   float bevelPercentage, float bevelSmoothness )
+{
+  int numPositions = 24;
+  int numFaces = 26;
+  int numOuterFaces = 6;
+  int numVertices = 6 * 4 + 12 * 4 + 8 * 3; //Six outer faces, 12 slanting rectangles, 8 slanting triangles.
+  int vertexIndex = 0;  //Track progress through vertices.
+  int normalIndex = 0;  //Track progress through normals, as vertices are calculated per face.
+
+  float minDimension = std::min( std::min( dimensions.x, dimensions.y ), dimensions.z );
+  float bevelAmount = 0.5 * std::min( bevelPercentage, minDimension ); //Cap bevel amount if necessary.
+
+  //Distances from centre to outer edge points.
+  float outerX = 0.5 * dimensions.x;
+  float outerY = 0.5 * dimensions.y;
+  float outerZ = 0.5 * dimensions.z;
+
+  //Distances from centre to bevelled points.
+  float bevelX = outerX - bevelAmount;
+  float bevelY = outerY - bevelAmount;
+  float bevelZ = outerZ - bevelAmount;
+
+  Vector<Vector3> positions;  //Holds object points, to be shared between vertexes.
+  positions.Resize( numPositions );
+  Vector<Vector3> normals;  //Holds face normals, to be shared between vertexes.
+  normals.Resize( numFaces );
+  Vector<Vector3> outerNormals;  //Holds normals of the outermost faces specifically.
+  outerNormals.Resize( numOuterFaces );
+  vertices.Resize( numVertices );
+
+  //Topmost face positions.
+  positions[0 ] = Vector3( -bevelX,  outerY, -bevelZ );
+  positions[1 ] = Vector3(  bevelX,  outerY, -bevelZ );
+  positions[2 ] = Vector3(  bevelX,  outerY,  bevelZ );
+  positions[3 ] = Vector3( -bevelX,  outerY,  bevelZ );
+
+  //Second layer positions.
+  positions[4 ] = Vector3( -outerX,  bevelY, -bevelZ );
+  positions[5 ] = Vector3( -bevelX,  bevelY, -outerZ );
+  positions[6 ] = Vector3(  bevelX,  bevelY, -outerZ );
+  positions[7 ] = Vector3(  outerX,  bevelY, -bevelZ );
+  positions[8 ] = Vector3(  outerX,  bevelY,  bevelZ );
+  positions[9 ] = Vector3(  bevelX,  bevelY,  outerZ );
+  positions[10] = Vector3( -bevelX,  bevelY,  outerZ );
+  positions[11] = Vector3( -outerX,  bevelY,  bevelZ );
+
+  //Third layer positions.
+  positions[12] = Vector3( -outerX, -bevelY, -bevelZ );
+  positions[13] = Vector3( -bevelX, -bevelY, -outerZ );
+  positions[14] = Vector3(  bevelX, -bevelY, -outerZ );
+  positions[15] = Vector3(  outerX, -bevelY, -bevelZ );
+  positions[16] = Vector3(  outerX, -bevelY,  bevelZ );
+  positions[17] = Vector3(  bevelX, -bevelY,  outerZ );
+  positions[18] = Vector3( -bevelX, -bevelY,  outerZ );
+  positions[19] = Vector3( -outerX, -bevelY,  bevelZ );
+
+  //Bottom-most face positions.
+  positions[20] = Vector3( -bevelX, -outerY, -bevelZ );
+  positions[21] = Vector3(  bevelX, -outerY, -bevelZ );
+  positions[22] = Vector3(  bevelX, -outerY,  bevelZ );
+  positions[23] = Vector3( -bevelX, -outerY,  bevelZ );
+
+  //Top face normal.
+  normals[0 ] = Vector3(  0,  1,  0 );
+
+  //Top slope normals.
+  normals[1 ] = Vector3( -1,  1, -1 );
+  normals[2 ] = Vector3(  0,  1, -1 );
+  normals[3 ] = Vector3(  1,  1, -1 );
+  normals[4 ] = Vector3(  1,  1,  0 );
+  normals[5 ] = Vector3(  1,  1,  1 );
+  normals[6 ] = Vector3(  0,  1,  1 );
+  normals[7 ] = Vector3( -1,  1,  1 );
+  normals[8 ] = Vector3( -1,  1,  0 );
+
+  //Side normals.
+  normals[9 ] = Vector3( -1,  0, -1 );
+  normals[10] = Vector3(  0,  0, -1 );
+  normals[11] = Vector3(  1,  0, -1 );
+  normals[12] = Vector3(  1,  0,  0 );
+  normals[13] = Vector3(  1,  0,  1 );
+  normals[14] = Vector3(  0,  0,  1 );
+  normals[15] = Vector3( -1,  0,  1 );
+  normals[16] = Vector3( -1,  0,  0 );
+
+  //Bottom slope normals.
+  normals[17] = Vector3( -1, -1, -1 );
+  normals[18] = Vector3(  0, -1, -1 );
+  normals[19] = Vector3(  1, -1, -1 );
+  normals[20] = Vector3(  1, -1,  0 );
+  normals[21] = Vector3(  1, -1,  1 );
+  normals[22] = Vector3(  0, -1,  1 );
+  normals[23] = Vector3( -1, -1,  1 );
+  normals[24] = Vector3( -1, -1,  0 );
+
+  //Bottom face normal.
+  normals[25] = Vector3(  0, -1,  0 );
+
+  //Top, back, right, front, left and bottom faces, respectively.
+  outerNormals[0] = Vector3(  0,  1,  0 );
+  outerNormals[1] = Vector3(  0,  0, -1 );
+  outerNormals[2] = Vector3(  1,  0,  0 );
+  outerNormals[3] = Vector3(  0,  0,  1 );
+  outerNormals[4] = Vector3( -1,  0,  0 );
+  outerNormals[5] = Vector3(  0, -1,  0 );
+
+  //Topmost face vertices.
+  for( int i = 0; i < 4; i++, vertexIndex++ )
+  {
+    vertices[vertexIndex].position = positions[i];
+    vertices[vertexIndex].normal = normals[normalIndex];
+  }
+
+  normalIndex++;
+
+  //Top slope vertices.
+  for( int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2 )
+  {
+    //Triangle part
+    vertices[vertexIndex    ].position = positions[i];
+    vertices[vertexIndex    ].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+    vertices[vertexIndex + 1].position = positions[2 * i + 4];
+    vertices[vertexIndex + 1].normal = outerNormals[( i == 0 ) ? 4 : i] * bevelSmoothness  + normals[normalIndex] * (1 - bevelSmoothness);
+    vertices[vertexIndex + 2].position = positions[2 * i + 5];
+    vertices[vertexIndex + 2].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+
+    //Rectangle part
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex + 3].position = positions[i];
+      vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 4].position = positions[0];
+      vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 5].position = positions[2 * i + 5];
+      vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 6].position = positions[4];
+      vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+    }
+    else
+    {
+      vertices[vertexIndex + 3].position = positions[i];
+      vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 4].position = positions[i + 1];
+      vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 5].position = positions[2 * i + 5];
+      vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 6].position = positions[2 * i + 6];
+      vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+    }
+  }
+
+  int secondCycleBeginning = 4;
+  int thirdCycleBeginning = secondCycleBeginning + 8;
+  int bottomCycleBeginning = thirdCycleBeginning + 8;
+
+  //Side vertices.
+  for( int i = 0; i < 8; i++, vertexIndex += 4, normalIndex++ )
+  {
+    if( i == 7 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
+      vertices[vertexIndex    ].normal = normals[normalIndex];
+      vertices[vertexIndex + 1].position = positions[secondCycleBeginning];
+      vertices[vertexIndex + 1].normal = normals[normalIndex];
+      vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
+      vertices[vertexIndex + 2].normal = normals[normalIndex];
+      vertices[vertexIndex + 3].position = positions[thirdCycleBeginning];
+      vertices[vertexIndex + 3].normal = normals[normalIndex];
+    }
+    else if( (i % 2) == 0 )
+    {
+      //'even' faces are corner ones, and need smoothing.
+      vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
+      vertices[vertexIndex    ].normal = outerNormals[( i == 0 ) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
+      vertices[vertexIndex + 1].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
+      vertices[vertexIndex + 2].normal = outerNormals[( i == 0 ) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
+      vertices[vertexIndex + 3].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+    }
+    else
+    {
+      //'odd' faces are outer ones, and so don't need smoothing.
+      vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
+      vertices[vertexIndex    ].normal = normals[normalIndex];
+      vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
+      vertices[vertexIndex + 1].normal = normals[normalIndex];
+      vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
+      vertices[vertexIndex + 2].normal = normals[normalIndex];
+      vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
+      vertices[vertexIndex + 3].normal = normals[normalIndex];
+    }
+  }
+
+  //Bottom slope vertices.
+  for( int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2 )
+  {
+    //Triangle part
+    vertices[vertexIndex    ].position = positions[thirdCycleBeginning + 2 * i];
+    vertices[vertexIndex    ].normal = outerNormals[( i == 0 ) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+    vertices[vertexIndex + 1].position = positions[thirdCycleBeginning + 2 * i + 1];
+    vertices[vertexIndex + 1].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+    vertices[vertexIndex + 2].position = positions[bottomCycleBeginning + i];
+    vertices[vertexIndex + 2].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
+
+    //Rectangle part
+    if( i == 3 )
+    {
+      //End, so loop around.
+      vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
+      vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 4].position = positions[thirdCycleBeginning];
+      vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
+      vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 6].position = positions[bottomCycleBeginning];
+      vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+    }
+    else
+    {
+      vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
+      vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 4].position = positions[thirdCycleBeginning + 2 * i + 2];
+      vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
+      vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+      vertices[vertexIndex + 6].position = positions[bottomCycleBeginning + i + 1];
+      vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
+    }
+  }
+
+  //Bottom-most face vertices.
+  for( int i = 0; i < 4; i++, vertexIndex++ )
+  {
+    vertices[vertexIndex].position = positions[ bottomCycleBeginning + i];
+    vertices[vertexIndex].normal = normals[normalIndex];
+  }
+
+  normalIndex++;
+}
+
+void PrimitiveVisual::FormBevelledCubeTriangles( Vector<unsigned short>& indices )
+{
+  int numTriangles = 44; //(Going from top to bottom, that's 2 + 12 + 16 + 12 + 2)
+  int indiceIndex = 0;  //Track progress through indices.
+  int vertexIndex = 0;  //Track progress through vertices as they're processed.
+
+  indices.Resize( 3 * numTriangles );
+
+  //Top face.
+  indices[indiceIndex    ] = vertexIndex;
+  indices[indiceIndex + 1] = vertexIndex + 2;
+  indices[indiceIndex + 2] = vertexIndex + 1;
+  indices[indiceIndex + 3] = vertexIndex + 0;
+  indices[indiceIndex + 4] = vertexIndex + 3;
+  indices[indiceIndex + 5] = vertexIndex + 2;
+  indiceIndex += 6;
+  vertexIndex += 4;
+
+  //Top slopes.
+  for( int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7 )
+  {
+    //Triangle part.
+    indices[indiceIndex    ] = vertexIndex;
+    indices[indiceIndex + 1] = vertexIndex + 2;
+    indices[indiceIndex + 2] = vertexIndex + 1;
+
+    //Rectangle part.
+    indices[indiceIndex + 3] = vertexIndex + 3;
+    indices[indiceIndex + 4] = vertexIndex + 4;
+    indices[indiceIndex + 5] = vertexIndex + 5;
+    indices[indiceIndex + 6] = vertexIndex + 4;
+    indices[indiceIndex + 7] = vertexIndex + 6;
+    indices[indiceIndex + 8] = vertexIndex + 5;
+  }
+
+  //Side faces.
+  for( int i = 0; i < 8; i++, indiceIndex += 6, vertexIndex += 4 )
+  {
+    indices[indiceIndex    ] = vertexIndex;
+    indices[indiceIndex + 1] = vertexIndex + 1;
+    indices[indiceIndex + 2] = vertexIndex + 2;
+    indices[indiceIndex + 3] = vertexIndex + 1;
+    indices[indiceIndex + 4] = vertexIndex + 3;
+    indices[indiceIndex + 5] = vertexIndex + 2;
+  }
+
+  //Bottom slopes.
+  for( int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7 )
+  {
+    //Triangle part.
+    indices[indiceIndex    ] = vertexIndex;
+    indices[indiceIndex + 1] = vertexIndex + 1;
+    indices[indiceIndex + 2] = vertexIndex + 2;
+
+    //Rectangle part.
+    indices[indiceIndex + 3] = vertexIndex + 3;
+    indices[indiceIndex + 4] = vertexIndex + 4;
+    indices[indiceIndex + 5] = vertexIndex + 5;
+    indices[indiceIndex + 6] = vertexIndex + 4;
+    indices[indiceIndex + 7] = vertexIndex + 6;
+    indices[indiceIndex + 8] = vertexIndex + 5;
+  }
+
+  //Bottom face.
+  indices[indiceIndex    ] = vertexIndex;
+  indices[indiceIndex + 1] = vertexIndex + 1;
+  indices[indiceIndex + 2] = vertexIndex + 2;
+  indices[indiceIndex + 3] = vertexIndex + 0;
+  indices[indiceIndex + 4] = vertexIndex + 2;
+  indices[indiceIndex + 5] = vertexIndex + 3;
+  indiceIndex += 6;
+  vertexIndex += 4;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/primitive/primitive-visual.h b/dali-toolkit/internal/visuals/primitive/primitive-visual.h
new file mode 100644 (file)
index 0000000..e27239b
--- /dev/null
@@ -0,0 +1,356 @@
+#ifndef DALI_TOOLKIT_INTERNAL_PRIMITIVE_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_PRIMITIVE_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+/*
+ * The geometry creation logic was based off similar methods provided by freeGLUT.
+ * Original copyright and licence information:
+ *
+ * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
+ * Written by Pawel W. Olszta, <olszta@sourceforge.net>
+ * Creation date: Fri Dec 3 1999
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class PrimitiveVisual;
+typedef IntrusivePtr< PrimitiveVisual > PrimitiveVisualPtr;
+
+/**
+ * The visual which renders a simple 3D shape to the control's quad
+ *
+ * Primitives are created with clockwise winding and back-face culling by default.
+ *
+ * The following properties are required to create a PrimitiveRender
+ *
+ * | %Property Name  | Type        |
+ * |-----------------|-------------|
+ * | shape           | STRING      |
+ *
+ * In addition, the following properties can be (optionally) supplied to modify the shape's parameters
+ *
+ * | %Property Name    | Type        | Shapes Affected                          |
+ * |-------------------|-------------|------------------------------------------|
+ * | shapeColor        | VECTOR4     | all                                      |
+ * | slices            | INTEGER     | sphere, cone, conical frustum, cylinder  |
+ * | stacks            | INTEGER     | sphere                                   |
+ * | scaleTopRadius    | FLOAT       | conical frustum                          |
+ * | scaleBottomRadius | FLOAT       | cone, conical frustum                    |
+ * | scaleHeight       | FLOAT       | cone, conical frustum, cylinder          |
+ * | scaleRadius       | FLOAT       | cylinder                                 |
+ * | scaleDimensions   | VECTOR3     | cube, octahedron, bevelled cube          |
+ * | bevelPercentage   | FLOAT       | bevelled cube                            |
+ * | bevelSmoothness   | FLOAT       | bevelled cube                            |
+ *
+ * Note: slices and stacks both have an upper limit of 255.
+ *
+ * Finally, the following can be used to affect the visual's shader
+ *
+ * | %Property Name  | Type        | Representing                            |
+ * |-----------------|-------------|-----------------------------------------|
+ * | lightPosition   | VECTOR3     | The position (on stage) of the light    |
+ */
+class PrimitiveVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new primitive visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static PrimitiveVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  PrimitiveVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~PrimitiveVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+
+  //Simple struct to store the position and normal of a single vertex.
+  struct Vertex
+  {
+    Vertex()
+    {}
+
+    Vertex( const Vector3& position, const Vector3& normal, const Vector2& textureCoord )
+    : position( position ), normal( normal )
+    {}
+
+    Vector3 position;
+    Vector3 normal;
+  };
+
+  /**
+   * @brief Initialize the renderer with the geometry and shader from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  /**
+     * @brief Create a shader for the object to use.
+     */
+  void CreateShader();
+
+  /**
+   * @brief Update shader related info, uniforms, etc. for the new shader.
+   */
+  void UpdateShaderUniforms();
+
+  /**
+   * @brief Create the geometry of the given primitive type.
+   */
+  void CreateGeometry();
+
+  /**
+   * @brief Compute the vertices and the triangles for a sphere.
+   * @param[in, out] vertices The vector of vertices.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   * @param[in] slices The number of slices as you go around the sphere. Affects the smoothness of the surface.
+   * @param[in] stacks The number of stacks as you go down the sphere. Affects the smoothness of the surface.
+   */
+  void CreateSphere( Vector<Vertex>& vertices, Vector<unsigned short>& indices, int slices, int stacks );
+
+  /**
+   * @brief Compute the vertices and the triangles for a conic shape.
+   * @param[in, out] vertices The vector of vertices.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   * @param[in] scaleTopRadius The scale of the radius of the top circle, compared to the other dimensions.
+   * @param[in] scaleBottomRadius The scale of the radius of the bottom circle, compared to the other dimensions.
+   * @param[in] scaleHeight The scale of the height of the object, compared to the other dimensions.
+   * @param[in] slices The number of slices as you go around the conic shape. Affects the smoothness of the surface.
+   */
+  void CreateConic( Vector<Vertex>& vertices, Vector<unsigned short>& indices, float scaleTopRadius,
+                           float scaleBottomRadius, float scaleHeight, int slices );
+
+  /**
+   * @brief Compute the vertices and the triangles for a bevelled cube.
+   * @param[in, out] vertices The vector of vertices.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   * @Param[in] dimensions The dimensions of the object. Scales in the same fashion as a 9-patch image.
+   * @param[in] bevelPercentage The ratio of the outer face widths to the cube's width. Between 0.0 and 1.0.
+   * @param[in] bevelSmoothness The smoothness of the bevelled edges. Between 0.0 and 1.0.
+   */
+  void CreateBevelledCube( Vector<Vertex>& vertices, Vector<unsigned short>& indices, Vector3 dimensions,
+                           float bevelPercentage, float bevelSmoothness );
+
+  /**
+   * @brief Computes look-up tables for sin and cos, over angle divisions of (2 * Pi) / divisions
+   * @param[in, out] sinTable The table of sin values.
+   * @param[in, out] cosTable The table of cos values.
+   * @param[in] divisions Determines the angle coverage of the table. E.g divisions of '4' will have the sin values 0 = sin(0), 1 = sin(Pi/2), 2 = sin(Pi), 3 = sin(3Pi/2)
+   * @Param[in] halfCircle If true, go from 0 to Pi instead of 0 to 2Pi.
+   */
+  void ComputeCircleTables( Vector<float>& sinTable, Vector<float>& cosTable, int divisions, bool halfCircle );
+
+  /**
+   * @brief Compute the vertices for a sphere.
+   * @param[in, out] vertices The vector of vertices.
+   * @param[in] slices The number of slices as you go around the sphere. Affects the smoothness of the surface.
+   * @param[in] stacks The number of stacks as you go down the sphere. Affects the smoothness of the surface.
+   */
+  void ComputeSphereVertices( Vector<Vertex>& vertices, int slices, int stacks );
+
+  /**
+   * @brief Compute the triangles for a sphere.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   * @param[in] slices The number of slices as you go around the sphere. Affects the smoothness of the surface.
+   * @param[in] stacks The number of stacks as you go down the sphere. Affects the smoothness of the surface.
+   */
+  void FormSphereTriangles( Vector<unsigned short>& indices, int slices, int stacks );
+
+  /**
+   * @brief Compute the vertices for a conical.
+   * @param[in, out] vertices The vector of vertices.
+   * @param[in] scaleTopRadius The scale of the radius of the top circle, compared to the other dimensions.
+   * @param[in] scaleBottomRadius The scale of the radius of the bottom circle, compared to the other dimensions.
+   * @param[in] scaleHeight The scale of the height of the object, compared to the other dimensions.
+   * @param[in] slices The number of slices as you go around the conical. Affects the smoothness of the surface.
+   */
+  void ComputeConicVertices( Vector<Vertex>& vertices, float scaleTopRadius, float scaleBottomRadius,
+                                    float scaleHeight, int slices );
+
+  /**
+   * @brief Compute the triangles for a conic.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   * @param[in] coneTop True if the top circle has a radius of zero, i.e. the object is a complete cone.
+   * @param[in] coneBottom True if the bottom circle has a radius of zero, i.e. the object is an inverted complete cone.
+   * @param[in] slices The number of slices as you go around the conic. Affects the smoothness of the surface.
+   */
+  void FormConicTriangles( Vector<unsigned short>& indices, float scaleTopRadius, float scaleBottomRadius,
+                                  int slices );
+
+  /**
+   * @brief Compute the vertices for a cube.
+   * @param[in, out] vertices The vector of vertices.
+   * @Param[in] dimensions The dimensions of the object.
+   */
+  void ComputeCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions );
+
+  /**
+   * @brief Compute the triangles for a cube.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   */
+  void FormCubeTriangles( Vector<unsigned short>& indices );
+
+  /**
+   * @brief Compute the vertices for an octahedron (maximumly bevelled cube).
+   * @param[in, out] vertices The vector of vertices.
+   * @Param[in] dimensions The dimensions of the object.
+   * @Param[in] smoothness Defines how rounded the edges appear under lighting. Between 0.0 and 1.0.
+   */
+  void ComputeOctahedronVertices( Vector<Vertex>& vertices, Vector3 dimensions, float smoothness );
+
+  /**
+   * @brief Compute the triangles for an octahedron.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   */
+  void FormOctahedronTriangles( Vector<unsigned short>& indices );
+
+  /**
+   * @brief Compute the vertices for a bevelled cube.
+   * @param[in, out] vertices The vector of vertices.
+   * @Param[in] dimensions The dimensions of the object. Scales in the same fashion as a 9-patch image.
+   * @param[in] bevelPercentage The ratio of the outer face widths to the cube's width. Between 0.0 and 1.0.
+   * @param[in] bevelSmoothness The smoothness of the bevelled edges. Between 0.0 and 1.0.
+   */
+  void ComputeBevelledCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions, float bevelPercentage,
+                                    float bevelSmoothness );
+
+  /**
+   * @brief Compute the triangles for a bevelled cube.
+   * @param[in, out] indices The vector of triangles, consisting of groups of three vertex indices.
+   */
+  void FormBevelledCubeTriangles( Vector<unsigned short>& indices );
+
+private:
+
+  // Undefined
+  PrimitiveVisual( const PrimitiveVisual& PrimitiveVisual );
+
+  // Undefined
+  PrimitiveVisual& operator=( const PrimitiveVisual& PrimitiveVisual );
+
+private:
+  Shader mShader;
+  Geometry mGeometry;
+
+  Vector3 mObjectDimensions;     //Dimensions of shape, scaled to be between 0.0 and 1.0.
+
+  Vector3 mSceneCenter;
+  Vector3 mSceneSize;
+
+  //Shader properties.
+  Vector3 mLightPosition;
+
+  //Shape properties.
+  Vector3 mScaleDimensions;      ///< Scale of dimensions of bevelled cube and sub-shapes.
+  float   mScaleTopRadius;       ///< Scale of radius of top circle, to use when creating certain objects.
+  float   mScaleBottomRadius;    ///< Scale of radius of bottom circle, to use when creating certain objects.
+  float   mScaleHeight;          ///< Scale of height, to use when creating certain objects.
+  float   mScaleRadius;          ///< Scale of radius, to use when creating certain objects.
+  float   mBevelPercentage;      ///< Used to determine bevel amount when creating certain objects.
+  float   mBevelSmoothness;      ///< Used to determine the smoothness of bevelled edges.
+  int     mSlices;               ///< Number of slices to use when creating certain objects.
+  int     mStacks;               ///< Number of stacks to use when creating certain objects.
+
+  Toolkit::PrimitiveVisual::Shape::Type mPrimitiveType;  //Shape to render, as enum.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_PRIMITIVE_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.cpp
new file mode 100644 (file)
index 0000000..f0dc4a4
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "svg-rasterize-thread.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/third-party/nanosvg/nanosvgrast.h>
+#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const char * const UNITS("px");
+}
+
+RasterizingTask::RasterizingTask( SvgVisual* svgRenderer, NSVGimage* parsedSvg, const VisualUrl& url, float dpi, unsigned int width, unsigned int height)
+: mSvgVisual( svgRenderer ),
+  mParsedSvg( parsedSvg ),
+  mUrl( url ),
+  mDpi( dpi ),
+  mWidth( width ),
+  mHeight( height )
+{
+  mRasterizer = nsvgCreateRasterizer();
+}
+
+RasterizingTask::~RasterizingTask()
+{
+  nsvgDeleteRasterizer( mRasterizer );
+}
+
+void RasterizingTask::Load()
+{
+  if( mParsedSvg != NULL)
+  {
+    return;
+  }
+
+  if( !mUrl.IsLocalResource() )
+  {
+    Dali::Vector<uint8_t> remoteBuffer;
+
+    if( !Dali::FileLoader::DownloadFileSynchronously( mUrl.GetUrl(), remoteBuffer ))
+    {
+      DALI_LOG_ERROR("Failed to download file!\n");
+      return;
+    }
+
+    remoteBuffer.PushBack( '\0' );
+    mParsedSvg = nsvgParse( reinterpret_cast<char*>(remoteBuffer.begin()), UNITS, mDpi );
+  }
+}
+
+void RasterizingTask::Rasterize( )
+{
+  if( mParsedSvg != NULL && mWidth > 0u && mHeight > 0u )
+  {
+    float scaleX = static_cast<float>( mWidth ) /  mParsedSvg->width;
+    float scaleY = static_cast<float>( mHeight ) /  mParsedSvg->height;
+    float scale = scaleX < scaleY ? scaleX : scaleY;
+    unsigned int bufferStride = mWidth*Pixel::GetBytesPerPixel( Pixel::RGBA8888 );
+    unsigned int bufferSize = bufferStride * mHeight;
+
+    unsigned char* buffer = new unsigned char [bufferSize];
+    nsvgRasterize(mRasterizer, mParsedSvg, 0.f,0.f,scale,
+        buffer, mWidth, mHeight,
+        bufferStride );
+
+    mPixelData = Dali::PixelData::New( buffer, bufferSize, mWidth, mHeight, Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY );
+  }
+}
+
+NSVGimage* RasterizingTask::GetParsedImage() const
+{
+  return mParsedSvg;
+}
+
+SvgVisual* RasterizingTask::GetSvgVisual() const
+{
+  return mSvgVisual.Get();
+}
+
+PixelData RasterizingTask::GetPixelData() const
+{
+  return mPixelData;
+}
+
+SvgRasterizeThread::SvgRasterizeThread( EventThreadCallback* trigger )
+: mTrigger( trigger ),
+  mIsThreadWaiting( false )
+{
+}
+
+SvgRasterizeThread::~SvgRasterizeThread()
+{
+  delete mTrigger;
+}
+
+void SvgRasterizeThread::TerminateThread( SvgRasterizeThread*& thread )
+{
+  if( thread )
+  {
+    // add an empty task would stop the thread from conditional wait.
+    thread->AddTask( RasterizingTaskPtr() );
+    // stop the thread
+    thread->Join();
+    // delete the thread
+    delete thread;
+    thread = NULL;
+  }
+}
+
+void SvgRasterizeThread::AddTask( RasterizingTaskPtr task )
+{
+  bool wasEmpty = false;
+
+  {
+    // Lock while adding task to the queue
+    ConditionalWait::ScopedLock lock( mConditionalWait );
+    wasEmpty = mRasterizeTasks.empty();
+    if( !wasEmpty && task != NULL)
+    {
+      // Remove the tasks with the same renderer.
+      // Older task which waiting to rasterize and apply the svg to the same renderer is expired.
+      for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
+      {
+        if( (*it) && (*it)->GetSvgVisual() == task->GetSvgVisual() )
+        {
+          mRasterizeTasks.erase( it );
+          break;
+        }
+      }
+    }
+    mRasterizeTasks.push_back( task );
+  }
+
+  if( wasEmpty)
+  {
+    // wake up the image loading thread
+    mConditionalWait.Notify();
+  }
+}
+
+RasterizingTaskPtr SvgRasterizeThread::NextCompletedTask()
+{
+  // Lock while popping task out from the queue
+  Mutex::ScopedLock lock( mMutex );
+
+  if( mCompletedTasks.empty() )
+  {
+    return RasterizingTaskPtr();
+  }
+
+  std::vector< RasterizingTaskPtr >::iterator next = mCompletedTasks.begin();
+  RasterizingTaskPtr nextTask = *next;
+  mCompletedTasks.erase( next );
+
+  return nextTask;
+}
+
+void SvgRasterizeThread::RemoveTask( SvgVisual* visual )
+{
+  // Lock while remove task from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+  if( !mRasterizeTasks.empty() )
+  {
+    for( std::vector< RasterizingTaskPtr >::iterator it = mRasterizeTasks.begin(), endIt = mRasterizeTasks.end(); it != endIt; ++it )
+    {
+      if( (*it) &&  (*it)->GetSvgVisual() == visual )
+      {
+        mRasterizeTasks.erase( it );
+        break;
+      }
+    }
+  }
+}
+
+void SvgRasterizeThread::DeleteImage( NSVGimage* parsedSvg )
+{
+  // Lock while adding image to the delete queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  if( mIsThreadWaiting ) // no rasterization is ongoing, save to delete
+  {
+    nsvgDelete( parsedSvg );
+  }
+  else // wait to delete until current rasterization completed.
+  {
+    mDeleteSvg.PushBack( parsedSvg );
+  }
+}
+
+RasterizingTaskPtr SvgRasterizeThread::NextTaskToProcess()
+{
+  // Lock while popping task out from the queue
+  ConditionalWait::ScopedLock lock( mConditionalWait );
+
+  // Delete the image here to make sure that it is not used in the nsvgRasterize()
+  if( !mDeleteSvg.Empty() )
+  {
+    for( Vector< NSVGimage* >::Iterator it = mDeleteSvg.Begin(), endIt = mDeleteSvg.End();
+        it != endIt;
+        ++it )
+    {
+      nsvgDelete( *it );
+    }
+    mDeleteSvg.Clear();
+  }
+
+  // conditional wait
+  while( mRasterizeTasks.empty() )
+  {
+    mIsThreadWaiting = true;
+    mConditionalWait.Wait( lock );
+  }
+  mIsThreadWaiting = false;
+
+  // pop out the next task from the queue
+  std::vector< RasterizingTaskPtr >::iterator next = mRasterizeTasks.begin();
+  RasterizingTaskPtr nextTask = *next;
+  mRasterizeTasks.erase( next );
+
+  return nextTask;
+}
+
+void SvgRasterizeThread::AddCompletedTask( RasterizingTaskPtr task )
+{
+  // Lock while adding task to the queue
+  Mutex::ScopedLock lock( mMutex );
+  mCompletedTasks.push_back( task );
+
+  // wake up the main thread
+  mTrigger->Trigger();
+}
+
+void SvgRasterizeThread::Run()
+{
+  SetThreadName( "SVGThread" );
+  while( RasterizingTaskPtr task = NextTaskToProcess() )
+  {
+    task->Load( );
+    task->Rasterize( );
+    AddCompletedTask( task );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h b/dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h
new file mode 100644 (file)
index 0000000..b7bdbfd
--- /dev/null
@@ -0,0 +1,233 @@
+#ifndef DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
+#define DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/devel-api/threading/thread.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+struct NSVGimage;
+struct NSVGrasterizer;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class SvgVisual;
+typedef IntrusivePtr< SvgVisual > SvgVisualPtr;
+class RasterizingTask;
+typedef IntrusivePtr< RasterizingTask > RasterizingTaskPtr;
+
+/**
+ * The svg rasterizing tasks to be processed in the worker thread.
+ *
+ * Life cycle of a rasterizing task is as follows:
+ * 1. Created by SvgVisual in the main thread
+ * 2. Queued in the worked thread waiting to be processed.
+ * 3. If this task gets its turn to do the rasterization, it triggers main thread to apply the rasterized image to material then been deleted in main thread call back
+ *    Or if this task is been removed ( new image/size set to the visual or actor off stage) before its turn to be processed, it then been deleted in the worker thread.
+ */
+class RasterizingTask : public RefObject
+{
+public:
+  /**
+   * Constructor
+   *
+   * @param[in] svgRenderer The renderer which the rasterized image to be applied.
+   * @param[in] parsedSvg The parsed svg for rasterizing.
+   *            Note, after the task is added to the worker thread, the worker thread takes over the ownership.
+   *            When the image is to be deleted, delete it in the worker thread by calling SvgRasterizeThread::DeleteImage( parsedSvg ).
+   * @param[in] url The URL to svg resource to use.
+   * @param[in] width The rasterization width.
+   * @param[in] height The rasterization height.
+   */
+  RasterizingTask( SvgVisual* svgRenderer, NSVGimage* parsedSvg, const VisualUrl& url, float dpi, unsigned int width, unsigned int height );
+
+  /**
+   * Destructor.
+   */
+  ~RasterizingTask();
+
+  /**
+   * Do the rasterization with the mRasterizer.
+   */
+  void Rasterize( );
+
+  /**
+   * Get the svg visual
+   */
+  SvgVisual* GetSvgVisual() const;
+
+  /**
+   * Get the rasterization result.
+   * @return The pixel data with the rasterized pixels.
+   */
+  PixelData GetPixelData() const;
+
+  /**
+   * Get the parsed data.
+   * @return parsed image data.
+   */
+  NSVGimage* GetParsedImage() const;
+
+  /**
+   * Load svg file
+   */
+  void Load();
+
+private:
+  // Undefined
+  RasterizingTask( const RasterizingTask& task );
+
+  // Undefined
+  RasterizingTask& operator=( const RasterizingTask& task );
+
+private:
+  SvgVisualPtr    mSvgVisual;
+  NSVGimage*      mParsedSvg;
+  VisualUrl       mUrl;
+  PixelData       mPixelData;
+  float           mDpi;
+  unsigned int    mWidth;
+  unsigned int    mHeight;
+  NSVGrasterizer* mRasterizer;
+};
+
+/**
+ * The worker thread for SVG rasterization.
+ */
+class SvgRasterizeThread : public Thread
+{
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param[in] trigger The trigger to wake up the main thread.
+   */
+  SvgRasterizeThread( EventThreadCallback* trigger );
+
+  /**
+   * Terminate the svg rasterize thread, join and delete.
+   */
+  static void TerminateThread( SvgRasterizeThread*& thread );
+
+  /**
+   * Add a rasterization task into the waiting queue, called by main thread.
+   *
+   * @param[in] task The task added to the queue.
+   */
+  void AddTask( RasterizingTaskPtr task );
+
+  /**
+   * Pop the next task out from the completed queue, called by main thread.
+   *
+   * @return The next task in the completed queue.
+   */
+  RasterizingTaskPtr NextCompletedTask();
+
+  /**
+   * Remove the task with the given visual from the waiting queue, called by main thread.
+   *
+   * Typically called when the actor is put off stage, so the renderer is not needed anymore.
+   *
+   * @param[in] visual The visual pointer.
+   */
+  void RemoveTask( SvgVisual* visual );
+
+  /**
+   * Delete the parsed SVG image, called by main thread.
+   *
+   * The parsed svg should be delelted in worker thread, as the main thread does not know whether a rasterization of this svg is ongoing.
+   *
+   * @param[in] parsedImage The image to be deleted
+   */
+  void DeleteImage( NSVGimage* parsedSvg );
+
+private:
+
+  /**
+   * Pop the next task out from the queue.
+   *
+   * @return The next task to be processed.
+   */
+  RasterizingTaskPtr NextTaskToProcess();
+
+  /**
+   * Add a task in to the queue
+   *
+   * @param[in] task The task added to the queue.
+   */
+  void AddCompletedTask( RasterizingTaskPtr task );
+
+protected:
+
+  /**
+   * Destructor.
+   */
+  virtual ~SvgRasterizeThread();
+
+
+  /**
+   * The entry function of the worker thread.
+   * It fetches task from the Queue, rasterizes the image and apply to the renderer.
+   */
+  void Run() override;
+
+private:
+
+  // Undefined
+  SvgRasterizeThread( const SvgRasterizeThread& thread );
+
+  // Undefined
+  SvgRasterizeThread& operator=( const SvgRasterizeThread& thread );
+
+private:
+
+  std::vector<RasterizingTaskPtr>  mRasterizeTasks;     //The queue of the tasks waiting to rasterize the SVG image
+  std::vector <RasterizingTaskPtr> mCompletedTasks;     //The queue of the tasks with the SVG rasterization completed
+  Vector<NSVGimage*>               mDeleteSvg;          //The images that the event thread requested to delete
+
+  ConditionalWait            mConditionalWait;
+  Dali::Mutex                mMutex;
+  EventThreadCallback*       mTrigger;
+
+  bool                       mIsThreadWaiting;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SVG_RASTERIZE_THREAD_H
diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.cpp b/dali-toolkit/internal/visuals/svg/svg-visual.cpp
new file mode 100644 (file)
index 0000000..9330bdb
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2020 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 "svg-visual.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/third-party/nanosvg/nanosvg.h>
+#include <dali-toolkit/third-party/nanosvg/nanosvgrast.h>
+#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/stage.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+// property name
+const char * const UNITS("px");
+
+const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+}
+
+SvgVisualPtr SvgVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
+{
+  SvgVisualPtr svgVisual( new SvgVisual( factoryCache, shaderFactory, imageUrl ) );
+  svgVisual->ParseFromUrl( imageUrl );
+  svgVisual->SetProperties( properties );
+
+  return svgVisual;
+}
+
+SvgVisualPtr SvgVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
+{
+  SvgVisualPtr svgVisual( new SvgVisual( factoryCache, shaderFactory, imageUrl ) );
+  svgVisual->ParseFromUrl( imageUrl );
+
+  return svgVisual;
+}
+
+SvgVisual::SvgVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mImageVisualShaderFactory( shaderFactory ),
+  mAtlasRect( FULL_TEXTURE_RECT ),
+  mImageUrl( imageUrl ),
+  mParsedImage( NULL ),
+  mPlacementActor(),
+  mVisualSize(Vector2::ZERO),
+  mAttemptAtlasing( false )
+{
+  // the rasterized image is with pre-multiplied alpha format
+  mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+}
+
+SvgVisual::~SvgVisual()
+{
+  if( mParsedImage )
+  {
+    nsvgDelete( mParsedImage );
+  }
+}
+
+void SvgVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  // url already passed in from constructor
+  for( Property::Map::SizeType iter = 0; iter < propertyMap.Count(); ++iter )
+  {
+    KeyValuePair keyValue = propertyMap.GetKeyValue( iter );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      DoSetProperty( keyValue.first.indexKey, keyValue.second );
+    }
+    else if( keyValue.first == IMAGE_ATLASING )
+    {
+      DoSetProperty( Toolkit::ImageVisual::Property::ATLASING, keyValue.second );
+    }
+    else if( keyValue.first == SYNCHRONOUS_LOADING )
+    {
+      DoSetProperty( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second );
+    }
+  }
+}
+
+void SvgVisual::DoSetProperty( Property::Index index, const Property::Value& value )
+{
+  switch( index )
+  {
+    case Toolkit::ImageVisual::Property::ATLASING:
+    {
+      value.Get( mAttemptAtlasing );
+      break;
+    }
+    case Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING:
+    {
+      bool sync = false;
+      if( value.Get( sync ) )
+      {
+        if( sync )
+        {
+          mImpl->mFlags |= Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+        }
+        else
+        {
+          mImpl->mFlags &= ~Impl::IS_SYNCHRONOUS_RESOURCE_LOADING;
+        }
+      }
+      else
+      {
+        DALI_LOG_ERROR("ImageVisual: synchronousLoading property has incorrect type\n");
+      }
+      break;
+    }
+  }
+}
+
+void SvgVisual::DoSetOnStage( Actor& actor )
+{
+  Shader shader;
+  if( !mImpl->mCustomShader )
+  {
+    shader = mImageVisualShaderFactory.GetShader( mFactoryCache, mAttemptAtlasing, true, false );
+  }
+  else
+  {
+    shader = Shader::New( mImpl->mCustomShader->mVertexShader.empty() ? mImageVisualShaderFactory.GetVertexShaderSource() : mImpl->mCustomShader->mVertexShader,
+                          mImpl->mCustomShader->mFragmentShader.empty() ? mImageVisualShaderFactory.GetFragmentShaderSource() : mImpl->mCustomShader->mFragmentShader,
+                          mImpl->mCustomShader->mHints );
+
+    shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+  }
+
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+  TextureSet textureSet = TextureSet::New();
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  mImpl->mRenderer.SetTextures( textureSet );
+
+  // Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+  // Defer the rasterisation task until we get given a size (by Size Negotiation algorithm)
+
+  // Hold the weak handle of the placement actor and delay the adding of renderer until the svg rasterization is finished.
+  mPlacementActor = actor;
+
+  // SVG visual needs it's size set before it can be rasterized hence set ResourceReady once on stage
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void SvgVisual::DoSetOffStage( Actor& actor )
+{
+  mFactoryCache.GetSVGRasterizationThread()->RemoveTask( this );
+
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+  mPlacementActor.Reset();
+
+  // Reset the visual size to zero so that when adding the actor back to stage the SVG rasterization is forced
+  mVisualSize = Vector2::ZERO;
+}
+
+void SvgVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( mParsedImage )
+  {
+    naturalSize.x = mParsedImage->width;
+    naturalSize.y = mParsedImage->height;
+  }
+  else
+  {
+    naturalSize = Vector2::ZERO;
+  }
+}
+
+void SvgVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::SVG );
+  if( mImageUrl.IsValid() )
+  {
+    map.Insert( Toolkit::ImageVisual::Property::URL, mImageUrl.GetUrl() );
+    map.Insert( Toolkit::ImageVisual::Property::ATLASING, mAttemptAtlasing );
+  }
+}
+
+void SvgVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void SvgVisual::ParseFromUrl( const VisualUrl& imageUrl )
+{
+  mImageUrl = imageUrl;
+  if( mImageUrl.IsLocalResource() )
+  {
+    Vector2 dpi = Stage::GetCurrent().GetDpi();
+    float meanDpi = ( dpi.height + dpi.width ) * 0.5f;
+    Dali::Vector<char> buffer;
+    if ( Dali::FileLoader::ReadFile( mImageUrl.GetUrl(), buffer ) )
+    {
+      buffer.PushBack( '\0' );
+      mParsedImage = nsvgParse( buffer.Begin(), UNITS, meanDpi );
+    }
+  }
+}
+
+void SvgVisual::AddRasterizationTask( const Vector2& size )
+{
+  if( mImpl->mRenderer )
+  {
+    unsigned int width = static_cast<unsigned int>(size.width);
+    unsigned int height = static_cast<unsigned int>( size.height );
+
+    Vector2 dpi = Stage::GetCurrent().GetDpi();
+    float meanDpi = ( dpi.height + dpi.width ) * 0.5f;
+
+    RasterizingTaskPtr newTask = new RasterizingTask( this, mParsedImage, mImageUrl, meanDpi, width, height );
+    if ( IsSynchronousLoadingRequired() )
+    {
+      newTask->Rasterize();
+      ApplyRasterizedImage( newTask->GetParsedImage(), newTask->GetPixelData() );
+    }
+    else
+    {
+      mFactoryCache.GetSVGRasterizationThread()->AddTask( newTask );
+    }
+  }
+}
+
+void SvgVisual::ApplyRasterizedImage( NSVGimage* parsedSvg, PixelData rasterizedPixelData )
+{
+  if( mParsedImage == NULL)
+  {
+    mParsedImage = parsedSvg;
+  }
+
+  if( mParsedImage && IsOnStage() )
+  {
+    TextureSet currentTextureSet = mImpl->mRenderer.GetTextures();
+    if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
+    {
+      mFactoryCache.GetAtlasManager()->Remove( currentTextureSet, mAtlasRect );
+    }
+
+    TextureSet textureSet;
+
+    if( mAttemptAtlasing && !mImpl->mCustomShader )
+    {
+      Vector4 atlasRect;
+      textureSet = mFactoryCache.GetAtlasManager()->Add(atlasRect, rasterizedPixelData );
+      if( textureSet ) // atlasing
+      {
+        if( textureSet != currentTextureSet )
+        {
+          mImpl->mRenderer.SetTextures( textureSet );
+        }
+        mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, atlasRect );
+        mAtlasRect = atlasRect;
+        mImpl->mFlags |= Impl::IS_ATLASING_APPLIED;
+      }
+    }
+
+    if( !textureSet ) // no atlasing - mAttemptAtlasing is false or adding to atlas is failed
+    {
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGBA8888,
+                                      rasterizedPixelData.GetWidth(), rasterizedPixelData.GetHeight() );
+      texture.Upload( rasterizedPixelData );
+      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+
+      if( mAtlasRect == FULL_TEXTURE_RECT )
+      {
+        textureSet = currentTextureSet;
+      }
+      else
+      {
+        textureSet = TextureSet::New();
+        mImpl->mRenderer.SetTextures( textureSet );
+
+        mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, FULL_TEXTURE_RECT );
+        mAtlasRect = FULL_TEXTURE_RECT;
+      }
+
+      if( textureSet )
+      {
+        textureSet.SetTexture( 0, texture );
+      }
+    }
+
+    // Rasterized pixels are uploaded to texture. If weak handle is holding a placement actor, it is the time to add the renderer to actor.
+    Actor actor = mPlacementActor.GetHandle();
+    if( actor )
+    {
+      actor.AddRenderer( mImpl->mRenderer );
+      // reset the weak handle so that the renderer only get added to actor once
+      mPlacementActor.Reset();
+    }
+
+   // Svg loaded and ready to display
+   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+  }
+  else if( !mParsedImage )
+  {
+    ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
+  }
+}
+
+void SvgVisual::OnSetTransform()
+{
+  Vector2 visualSize = mImpl->mTransform.GetVisualSize( mImpl->mControlSize );
+
+  if( IsOnStage() )
+  {
+    if( visualSize != mVisualSize )
+    {
+      AddRasterizationTask( visualSize );
+      mVisualSize = visualSize;
+    }
+  }
+
+  if(mImpl->mRenderer)
+  {
+    mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
+  }
+}
+
+bool SvgVisual::IsResourceReady() const
+{
+  return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY ||
+           mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::FAILED );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/svg/svg-visual.h b/dali-toolkit/internal/visuals/svg/svg-visual.h
new file mode 100644 (file)
index 0000000..81bfb5d
--- /dev/null
@@ -0,0 +1,197 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SVG_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_SVG_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+struct NSVGimage;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class ImageVisualShaderFactory;
+class SvgVisual;
+typedef IntrusivePtr< SvgVisual > SvgVisualPtr;
+
+/**
+ * The visual which renders a svg image
+ *
+ * The following property is essential
+ *
+ * | %Property Name           | Type             |
+ * |--------------------------|------------------|
+ * | url                      | STRING           |
+ *
+ */
+class SvgVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create the SVG Visual using the image URL.
+   *
+   * The visual will parse the SVG image once it is set.
+   * And rasterize it into BufferImage synchronously when the associated actor is put on stage, and destroy the BufferImage when it is off stage
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to svg resource to use
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static SvgVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties );
+
+  /**
+   * @brief Create the SVG Visual using the image URL.
+   *
+   * The visual will parse the SVG image once it is set.
+   * And rasterize it into BufferImage synchronously when the associated actor is put on stage, and destroy the BufferImage when it is off stage
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to svg resource to use
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static SvgVisualPtr New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl );
+
+public:  // from Visual
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] imageUrl The URL to svg resource to use
+   */
+  SvgVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~SvgVisual();
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::IsResourceReady
+   */
+  bool IsResourceReady() const override;
+
+public:
+
+  /**
+   * @bried Apply the rasterized image to the visual.
+   *
+   * @param[in] parsedSvg The data of parsed image.
+   * @param[in] rasterizedPixelData The pixel buffer with the rasterized pixels
+   */
+  void ApplyRasterizedImage( NSVGimage* parsedSvg, PixelData rasterizedPixelData );
+
+private:
+  /**
+    * @brief Parses the SVG Image from the set URL.
+    *
+    * @param[in] imageUrl The URL of the image to parse the SVG from.
+    */
+   void ParseFromUrl( const VisualUrl& imageUrl );
+
+  /**
+   * @bried Rasterize the svg with the given size, and add it to the visual.
+   *
+   * @param[in] size The target size of the SVG rasterization.
+   */
+  void AddRasterizationTask( const Vector2& size );
+
+  /**
+   * Helper method to set individual values by index key.
+   * @param[in] index The index key of the value
+   * @param[in] value The value
+   */
+  void DoSetProperty( Property::Index index, const Property::Value& value );
+
+  // Undefined
+  SvgVisual( const SvgVisual& svgRenderer );
+
+  // Undefined
+  SvgVisual& operator=( const SvgVisual& svgRenderer );
+
+private:
+  ImageVisualShaderFactory& mImageVisualShaderFactory;
+  Vector4                   mAtlasRect;
+  VisualUrl                 mImageUrl;
+  NSVGimage*                mParsedImage;
+  WeakHandle<Actor>         mPlacementActor;
+  Vector2                   mVisualSize;
+  bool                      mAttemptAtlasing;  ///< If true will attempt atlasing, otherwise create unique texture
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_SVG_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp
new file mode 100755 (executable)
index 0000000..e0b16e9
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/visuals/text/text-visual.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/constraints.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// INTERNAL HEADER
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/text-visual-properties-devel.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/text/text-font-style.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/script-run.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
+#include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform highp   mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  uniform mediump vec4 pixelArea;\n
+
+  varying mediump vec2 vTexCoord;\n
+
+  //Visual size and offset
+  uniform mediump vec2 offset;\n
+  uniform mediump vec2 size;\n
+  uniform mediump vec4 offsetSizeMode;\n
+  uniform mediump vec2 origin;\n
+  uniform mediump vec2 anchorPoint;\n
+
+  vec4 ComputeVertexPosition()\n
+  {\n
+    vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+    vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+    return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+  }\n
+
+  void main()\n
+  {\n
+    gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+    vTexCoord = pixelArea.xy+pixelArea.zw*(aPosition + vec2(0.5) );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump float textTexture = texture2D( sTexture, vTexCoord ).r;\n
+
+    // Set the color of the text to what it is animated to.
+    gl_FragColor = uTextColorAnimatable * textTexture * uColor * vec4( mixColor, 1.0 );
+  }\n
+);
+
+const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
+
+    gl_FragColor = textTexture * uColor * vec4( mixColor, 1.0 );
+  }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sStyle;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump float textTexture = texture2D( sTexture, vTexCoord ).r;\n
+    mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
+
+    // Draw the text as overlay above the style
+    gl_FragColor = ( uTextColorAnimatable * textTexture + styleTexture * ( 1.0 - uTextColorAnimatable.a * textTexture ) ) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sStyle;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
+    mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
+
+    // Draw the text as overlay above the style
+    gl_FragColor = ( textTexture + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sMask;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
+    mediump float maskTexture = texture2D( sMask, vTexCoord ).r;\n
+
+    // Set the color of non-transparent pixel in text to what it is animated to.
+    // Markup text with multiple text colors are not animated (but can be supported later on if required).
+    // Emoji color are not animated.
+    mediump float vstep = step( 0.0001, textTexture.a );\n
+    textTexture.rgb = mix( textTexture.rgb, uTextColorAnimatable.rgb, vstep * maskTexture );\n
+
+    // Draw the text as overlay above the style
+    gl_FragColor = textTexture * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI = DALI_COMPOSE_SHADER(
+  varying mediump vec2 vTexCoord;\n
+  uniform sampler2D sTexture;\n
+  uniform sampler2D sStyle;\n
+  uniform sampler2D sMask;\n
+  uniform lowp float uHasMultipleTextColors;\n
+  uniform lowp vec4 uTextColorAnimatable;\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 textTexture = texture2D( sTexture, vTexCoord );\n
+    mediump vec4 styleTexture = texture2D( sStyle, vTexCoord );\n
+    mediump float maskTexture = texture2D( sMask, vTexCoord ).r;\n
+
+    // Set the color of non-transparent pixel in text to what it is animated to.
+    // Markup text with multiple text colors are not animated (but can be supported later on if required).
+    // Emoji color are not animated.
+    mediump float vstep = step( 0.0001, textTexture.a );\n
+    textTexture.rgb = mix( textTexture.rgb, uTextColorAnimatable.rgb, vstep * maskTexture * ( 1.0 - uHasMultipleTextColors ) );\n
+
+    // Draw the text as overlay above the style
+    gl_FragColor = ( textTexture + styleTexture * ( 1.0 - textTexture.a ) ) * uColor * vec4( mixColor, 1.0 );\n
+  }\n
+);
+
+/**
+ * Return Property index for the given string key
+ * param[in] stringKey the string index key
+ * return the key as an index
+ */
+
+Dali::Property::Index StringKeyToIndexKey( const std::string& stringKey )
+{
+  Dali::Property::Index result = Property::INVALID_KEY;
+
+  if( stringKey == VISUAL_TYPE )
+  {
+    result = Toolkit::Visual::Property::TYPE;
+  }
+  else if( stringKey == TEXT_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::TEXT;
+  }
+  else if( stringKey == FONT_FAMILY_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::FONT_FAMILY;
+  }
+  else if( stringKey == FONT_STYLE_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::FONT_STYLE;
+  }
+  else if( stringKey == POINT_SIZE_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::POINT_SIZE;
+  }
+  else if( stringKey == MULTI_LINE_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::MULTI_LINE;
+  }
+  else if( stringKey == HORIZONTAL_ALIGNMENT_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT;
+  }
+  else if( stringKey == VERTICAL_ALIGNMENT_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT;
+  }
+  else if( stringKey == TEXT_COLOR_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::TEXT_COLOR;
+  }
+  else if( stringKey == ENABLE_MARKUP_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::ENABLE_MARKUP;
+  }
+  else if( stringKey == SHADOW_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::SHADOW;
+  }
+  else if( stringKey == UNDERLINE_PROPERTY )
+  {
+    result = Toolkit::TextVisual::Property::UNDERLINE;
+  }
+  else if( stringKey == OUTLINE_PROPERTY )
+  {
+    result = Toolkit::DevelTextVisual::Property::OUTLINE;
+  }
+  else if( stringKey == BACKGROUND_PROPERTY )
+  {
+    result = Toolkit::DevelTextVisual::Property::BACKGROUND;
+  }
+
+  return result;
+}
+
+void TextColorConstraint( Vector4& current, const PropertyInputContainer& inputs )
+{
+  Vector4 color = inputs[0]->GetVector4();
+  current.r = color.r * color.a;
+  current.g = color.g * color.a;
+  current.b = color.b * color.a;
+  current.a = color.a;
+}
+
+void OpacityConstraint( float& current, const PropertyInputContainer& inputs )
+{
+  // Make zero if the alpha value of text color is zero to skip rendering text
+  if( EqualsZero( inputs[0]->GetVector4().a ) )
+  {
+    current = 0.0f;
+  }
+  else
+  {
+    current = 1.0f;
+  }
+}
+
+} // unnamed namespace
+
+TextVisualPtr TextVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  TextVisualPtr TextVisualPtr( new TextVisual( factoryCache ) );
+  TextVisualPtr->SetProperties( properties );
+  return TextVisualPtr;
+}
+
+void TextVisual::ConvertStringKeysToIndexKeys( Property::Map& propertyMap )
+{
+  Property::Map outMap;
+
+  for( Property::Map::SizeType index = 0u, count = propertyMap.Count(); index < count; ++index )
+  {
+    const KeyValuePair& keyValue = propertyMap.GetKeyValue( index );
+
+    Property::Index indexKey = keyValue.first.indexKey;
+
+    if ( keyValue.first.type == Property::Key::STRING )
+    {
+      indexKey = StringKeyToIndexKey( keyValue.first.stringKey );
+    }
+
+    outMap.Insert( indexKey, keyValue.second );
+  }
+
+  propertyMap = outMap;
+}
+
+float TextVisual::GetHeightForWidth( float width )
+{
+  return mController->GetHeightForWidth( width );
+}
+
+void TextVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  naturalSize = mController->GetNaturalSize().GetVectorXY();
+}
+
+void TextVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  Property::Value value;
+
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
+
+  std::string text;
+  mController->GetText( text );
+  map.Insert( Toolkit::TextVisual::Property::TEXT, text );
+
+  map.Insert( Toolkit::TextVisual::Property::FONT_FAMILY, mController->GetDefaultFontFamily() );
+
+  GetFontStyleProperty( mController, value, Text::FontStyle::DEFAULT );
+  map.Insert( Toolkit::TextVisual::Property::FONT_STYLE, value );
+
+  map.Insert( Toolkit::TextVisual::Property::POINT_SIZE, mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ) );
+
+  map.Insert( Toolkit::TextVisual::Property::MULTI_LINE, mController->IsMultiLineEnabled() );
+
+  map.Insert( Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT, mController->GetHorizontalAlignment() );
+
+  map.Insert( Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT, mController->GetVerticalAlignment() );
+
+  map.Insert( Toolkit::TextVisual::Property::TEXT_COLOR, mController->GetDefaultColor() );
+
+  map.Insert( Toolkit::TextVisual::Property::ENABLE_MARKUP, mController->IsMarkupProcessorEnabled() );
+
+  GetShadowProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::TextVisual::Property::SHADOW, value );
+
+  GetUnderlineProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::TextVisual::Property::UNDERLINE, value );
+
+  GetOutlineProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::DevelTextVisual::Property::OUTLINE, value );
+
+  GetBackgroundProperties( mController, value, Text::EffectStyle::DEFAULT );
+  map.Insert( Toolkit::DevelTextVisual::Property::BACKGROUND, value );
+}
+
+void TextVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::TEXT );
+  std::string text;
+  mController->GetText( text );
+  map.Insert( Toolkit::TextVisual::Property::TEXT, text );
+}
+
+
+TextVisual::TextVisual( VisualFactoryCache& factoryCache )
+: Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO ),
+  mController( Text::Controller::New() ),
+  mTypesetter( Text::Typesetter::New( mController->GetTextModel() ) ),
+  mAnimatableTextColorPropertyIndex( Property::INVALID_INDEX ),
+  mRendererUpdateNeeded( false )
+{
+}
+
+TextVisual::~TextVisual()
+{
+}
+
+void TextVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  for( Property::Map::SizeType index = 0u, count = propertyMap.Count(); index < count; ++index )
+  {
+    const KeyValuePair& keyValue = propertyMap.GetKeyValue( index );
+
+    Property::Index indexKey = keyValue.first.indexKey;
+
+    if( keyValue.first.type == Property::Key::STRING )
+    {
+      indexKey = StringKeyToIndexKey( keyValue.first.stringKey );
+    }
+
+    DoSetProperty( indexKey, keyValue.second );
+  }
+
+  // Elide the text if it exceeds the boundaries.
+  mController->SetTextElideEnabled( true );
+
+  // Retrieve the layout engine to set the cursor's width.
+  Text::Layout::Engine& engine = mController->GetLayoutEngine();
+
+  // Sets 0 as cursor's width.
+  engine.SetCursorWidth( 0u ); // Do not layout space for the cursor.
+}
+
+void TextVisual::DoSetOnStage( Actor& actor )
+{
+  mControl = actor;
+
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
+  Shader shader = GetTextShader(mFactoryCache, TextType::SINGLE_COLOR_TEXT, TextType::NO_EMOJI, TextType::NO_STYLES);
+
+  mImpl->mRenderer = Renderer::New( geometry, shader );
+  mImpl->mRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT );
+
+  // Enable the pre-multiplied alpha to improve the text quality
+  EnablePreMultipliedAlpha(true);
+
+  const Vector4& defaultColor = mController->GetTextModel()->GetDefaultColor();
+  Dali::Property::Index shaderTextColorIndex = mImpl->mRenderer.RegisterProperty( "uTextColorAnimatable", defaultColor );
+
+  if ( mAnimatableTextColorPropertyIndex != Property::INVALID_INDEX )
+  {
+    // Create constraint for the animatable text's color Property with uTextColorAnimatable in the renderer.
+    if( shaderTextColorIndex != Property::INVALID_INDEX )
+    {
+      Constraint colorConstraint = Constraint::New<Vector4>( mImpl->mRenderer, shaderTextColorIndex, TextColorConstraint );
+      colorConstraint.AddSource( Source( actor, mAnimatableTextColorPropertyIndex ) );
+      colorConstraint.Apply();
+
+      // Make zero if the alpha value of text color is zero to skip rendering text
+      Constraint opacityConstraint = Constraint::New< float >( mImpl->mRenderer, Dali::DevelRenderer::Property::OPACITY, OpacityConstraint );
+      opacityConstraint.AddSource( Source( actor, mAnimatableTextColorPropertyIndex ) );
+      opacityConstraint.Apply();
+    }
+  }
+
+  // Renderer needs textures and to be added to control
+  mRendererUpdateNeeded = true;
+
+  UpdateRenderer();
+}
+
+void TextVisual::DoSetOffStage( Actor& actor )
+{
+  if( mImpl->mRenderer )
+  {
+    // Removes the renderer from the actor.
+    actor.RemoveRenderer( mImpl->mRenderer );
+
+    RemoveTextureSet();
+
+    // Resets the renderer.
+    mImpl->mRenderer.Reset();
+  }
+
+  // Resets the control handle.
+  mControl.Reset();
+}
+
+void TextVisual::OnSetTransform()
+{
+  UpdateRenderer();
+}
+
+void TextVisual::DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue )
+{
+  switch( index )
+  {
+    case Toolkit::TextVisual::Property::ENABLE_MARKUP:
+    {
+      const bool enableMarkup = propertyValue.Get<bool>();
+      mController->SetMarkupProcessorEnabled( enableMarkup );
+      break;
+    }
+    case Toolkit::TextVisual::Property::TEXT:
+    {
+      mController->SetText( propertyValue.Get<std::string>() );
+      break;
+    }
+    case Toolkit::TextVisual::Property::FONT_FAMILY:
+    {
+      SetFontFamilyProperty( mController, propertyValue );
+      break;
+    }
+    case Toolkit::TextVisual::Property::FONT_STYLE:
+    {
+      SetFontStyleProperty( mController, propertyValue, Text::FontStyle::DEFAULT );
+      break;
+    }
+    case Toolkit::TextVisual::Property::POINT_SIZE:
+    {
+      const float pointSize = propertyValue.Get<float>();
+      if( !Equals( mController->GetDefaultFontSize( Text::Controller::POINT_SIZE ), pointSize ) )
+      {
+        mController->SetDefaultFontSize( pointSize, Text::Controller::POINT_SIZE );
+      }
+      break;
+    }
+    case Toolkit::TextVisual::Property::MULTI_LINE:
+    {
+      mController->SetMultiLineEnabled( propertyValue.Get<bool>() );
+      break;
+    }
+    case Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT:
+    {
+      if( mController )
+      {
+        Text::HorizontalAlignment::Type alignment( static_cast< Text::HorizontalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+        if( Toolkit::Text::GetHorizontalAlignmentEnumeration( propertyValue, alignment ) )
+        {
+          mController->SetHorizontalAlignment( alignment );
+        }
+      }
+      break;
+    }
+    case Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT:
+    {
+      if( mController )
+      {
+        Toolkit::Text::VerticalAlignment::Type alignment( static_cast< Text::VerticalAlignment::Type >( -1 ) ); // Set to invalid value to ensure a valid mode does get set
+        if( Toolkit::Text::GetVerticalAlignmentEnumeration( propertyValue, alignment) )
+        {
+          mController->SetVerticalAlignment( alignment );
+        }
+      }
+      break;
+    }
+    case Toolkit::TextVisual::Property::TEXT_COLOR:
+    {
+      const Vector4& textColor = propertyValue.Get< Vector4 >();
+      if( mController->GetDefaultColor() != textColor )
+      {
+        mController->SetDefaultColor( textColor );
+      }
+      break;
+    }
+    case Toolkit::TextVisual::Property::SHADOW:
+    {
+      SetShadowProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
+    case Toolkit::TextVisual::Property::UNDERLINE:
+    {
+      SetUnderlineProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
+    case Toolkit::DevelTextVisual::Property::OUTLINE:
+    {
+      SetOutlineProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
+    case Toolkit::DevelTextVisual::Property::BACKGROUND:
+    {
+      SetBackgroundProperties( mController, propertyValue, Text::EffectStyle::DEFAULT );
+      break;
+    }
+  }
+}
+
+void TextVisual::UpdateRenderer()
+{
+  Actor control = mControl.GetHandle();
+  if( !control )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  // Calculates the size to be used to relayout.
+  Vector2 relayoutSize;
+
+  const bool isWidthRelative = fabsf( mImpl->mTransform.mOffsetSizeMode.z ) < Math::MACHINE_EPSILON_1000;
+  const bool isHeightRelative = fabsf( mImpl->mTransform.mOffsetSizeMode.w ) < Math::MACHINE_EPSILON_1000;
+
+  // Round the size and offset to avoid pixel alignement issues.
+  relayoutSize.width = floorf( 0.5f + ( isWidthRelative ? mImpl->mControlSize.width * mImpl->mTransform.mSize.x : mImpl->mTransform.mSize.width ) );
+  relayoutSize.height = floorf( 0.5f + ( isHeightRelative ? mImpl->mControlSize.height * mImpl->mTransform.mSize.y : mImpl->mTransform.mSize.height ) );
+
+  std::string text;
+  mController->GetText( text );
+
+  if( ( fabsf( relayoutSize.width ) < Math::MACHINE_EPSILON_1000 ) || ( fabsf( relayoutSize.height ) < Math::MACHINE_EPSILON_1000 ) || text.empty() )
+  {
+    // Removes the texture set.
+    RemoveTextureSet();
+
+    // Remove any renderer previously set.
+    if( mImpl->mRenderer )
+    {
+      control.RemoveRenderer( mImpl->mRenderer );
+    }
+
+    // Nothing else to do if the relayout size is zero.
+    ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+    return;
+  }
+
+  Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( control.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+  const Text::Controller::UpdateTextType updateTextType = mController->Relayout( relayoutSize, layoutDirection );
+
+  if( Text::Controller::NONE_UPDATED != ( Text::Controller::MODEL_UPDATED & updateTextType )
+   || mRendererUpdateNeeded )
+  {
+    mRendererUpdateNeeded = false;
+
+    // Removes the texture set.
+    RemoveTextureSet();
+
+    // Remove any renderer previously set.
+    if( mImpl->mRenderer )
+    {
+      control.RemoveRenderer( mImpl->mRenderer );
+    }
+
+    if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) &&
+        ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) )
+    {
+      // Check whether it is a markup text with multiple text colors
+      const Vector4* const colorsBuffer = mController->GetTextModel()->GetColors();
+      bool hasMultipleTextColors = ( NULL != colorsBuffer );
+
+      // Check whether the text contains any color glyph
+      bool containsColorGlyph = false;
+
+      TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+      const Text::GlyphInfo* const glyphsBuffer = mController->GetTextModel()->GetGlyphs();
+      const Text::Length numberOfGlyphs = mController->GetTextModel()->GetNumberOfGlyphs();
+      for ( Text::Length glyphIndex = 0; glyphIndex < numberOfGlyphs; glyphIndex++ )
+      {
+        // Retrieve the glyph's info.
+        const Text::GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+
+        // Whether the current glyph is a color one.
+        if( fontClient.IsColorGlyph( glyphInfo->fontId, glyphInfo->index ) )
+        {
+          containsColorGlyph = true;
+          break;
+        }
+      }
+
+      // Check whether the text contains any style colors (e.g. underline color, shadow color, etc.)
+
+      bool shadowEnabled = false;
+      const Vector2& shadowOffset = mController->GetTextModel()->GetShadowOffset();
+      if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 )
+      {
+        shadowEnabled = true;
+      }
+
+      const bool underlineEnabled = mController->GetTextModel()->IsUnderlineEnabled();
+      const bool outlineEnabled = ( mController->GetTextModel()->GetOutlineWidth() > Math::MACHINE_EPSILON_1 );
+      const bool backgroundEnabled = mController->GetTextModel()->IsBackgroundEnabled();;
+
+      const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled );
+
+      TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled );
+      mImpl->mRenderer.SetTextures( textureSet );
+
+      Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled );
+      mImpl->mRenderer.SetShader(shader);
+
+      mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED;
+
+      mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast<float>( hasMultipleTextColors ) );
+
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON);
+
+      //Register transform properties
+      mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+
+      control.AddRenderer( mImpl->mRenderer );
+
+      // Text rendered and ready to display
+      ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+    }
+  }
+}
+
+void TextVisual::RemoveTextureSet()
+{
+  if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED )
+  {
+    // Removes the text's image from the texture atlas.
+    Vector4 atlasRect;
+
+    const Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME );
+    if( index != Property::INVALID_INDEX )
+    {
+      const Property::Value& atlasRectValue = mImpl->mRenderer.GetProperty( index );
+      atlasRectValue.Get( atlasRect );
+
+      const TextureSet& textureSet = mImpl->mRenderer.GetTextures();
+      mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect );
+    }
+  }
+}
+
+TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
+{
+  // Filter mode needs to be set to linear to produce better quality while scaling.
+  Sampler sampler = Sampler::New();
+  sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
+
+  TextureSet textureSet = TextureSet::New();
+
+  // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture
+  Pixel::Format textPixelFormat = ( containsColorGlyph || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8;
+
+  // Check the text direction
+  Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection();
+
+  // Create a texture for the text without any styles
+  PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat );
+
+  // It may happen the image atlas can't handle a pixel data it exceeds the maximum size.
+  // In that case, create a texture. TODO: should tile the text.
+
+  Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                  data.GetPixelFormat(),
+                                  data.GetWidth(),
+                                  data.GetHeight() );
+
+  texture.Upload( data );
+
+  textureSet.SetTexture( 0u, texture );
+  textureSet.SetSampler( 0u, sampler );
+
+  if ( styleEnabled )
+  {
+    // Create RGBA texture for all the text styles (without the text itself)
+    PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 );
+
+    Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                         styleData.GetPixelFormat(),
+                                         styleData.GetWidth(),
+                                         styleData.GetHeight() );
+
+    styleTexture.Upload( styleData );
+
+    textureSet.SetTexture( 1u, styleTexture );
+    textureSet.SetSampler( 1u, sampler );
+  }
+
+  if ( containsColorGlyph && !hasMultipleTextColors )
+  {
+    // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation
+    PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 );
+
+    Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                        maskData.GetPixelFormat(),
+                                        maskData.GetWidth(),
+                                        maskData.GetHeight() );
+
+    maskTexture.Upload( maskData );
+
+    if ( !styleEnabled )
+    {
+      textureSet.SetTexture( 1u, maskTexture );
+      textureSet.SetSampler( 1u, sampler );
+    }
+    else
+    {
+      textureSet.SetTexture( 2u, maskTexture );
+      textureSet.SetSampler( 2u, sampler );
+    }
+  }
+
+  return textureSet;
+}
+
+Shader TextVisual::GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled )
+{
+  Shader shader;
+
+  if( hasMultipleTextColors && !styleEnabled )
+  {
+    // We don't animate text color if the text contains multiple colors
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT, shader );
+    }
+  }
+  else if( hasMultipleTextColors && styleEnabled )
+  {
+    // We don't animate text color if the text contains multiple colors
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE, shader );
+    }
+  }
+  else if( !hasMultipleTextColors && !containsColorGlyph && !styleEnabled )
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT, shader );
+    }
+  }
+  else if( !hasMultipleTextColors && !containsColorGlyph && styleEnabled )
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE, shader );
+    }
+  }
+  else if( !hasMultipleTextColors && containsColorGlyph && !styleEnabled )
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI, shader );
+    }
+  }
+  else // if( !hasMultipleTextColors && containsColorGlyph && styleEnabled )
+  {
+    shader = factoryCache.GetShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
+    if( !shader )
+    {
+      shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI );
+      shader.RegisterProperty( PIXEL_AREA_UNIFORM_NAME, FULL_TEXTURE_RECT );
+      factoryCache.SaveShader( VisualFactoryCache::TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI, shader );
+    }
+  }
+
+  return shader;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/text/text-visual.h b/dali-toolkit/internal/visuals/text/text-visual.h
new file mode 100644 (file)
index 0000000..6f47e45
--- /dev/null
@@ -0,0 +1,264 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/weak-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/text/rendering/text-typesetter.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class TextVisual;
+typedef IntrusivePtr< TextVisual > TextVisualPtr;
+
+/**
+ * The visual which renders text
+ *
+ * The following properties are optional:
+ *
+ * | %Property Name      | Type    |
+ * |---------------------|---------|
+ * | renderingBackend    | INTEGER |
+ * | text                | STRING  |
+ * | fontFamily          | STRING  |
+ * | fontStyle           | STRING  |
+ * | pointSize           | FLOAT   |
+ * | multiLine           | BOOLEAN |
+ * | horizontalAlignment | STRING  |
+ * | verticalAlignment   | STRING  |
+ * | textColor           | VECTOR4 |
+ * | enableMarkup        | BOOLEAN |
+ * | enableAutoScroll    | BOOLEAN |
+ * | autoScrollSpeed     | INTEGER |
+ * | autoScrollLoopCount | INTEGER |
+ * | autoScrollGap       | INTEGER |
+ * | lineSpacing         | FLOAT   |
+ * | underline           | STRING  |
+ * | shadow              | STRING  |
+ * | outline             | STRING  |
+ *
+ */
+class TextVisual : public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new text visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static TextVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+  /**
+   * @brief Converts all strings keys in property map to index keys.  Property Map can then be merged correctly.
+   * @param[in,out] propertyMap containing string keys or a mix of strings and indexes. Will be changed to index keys.
+   */
+  static void ConvertStringKeysToIndexKeys( Property::Map& propertyMap );
+
+  /**
+   * @brief Retrieve the text's controller.
+   * @param[in] visual The text visual.
+   * @return The text controller
+   */
+  static Text::ControllerPtr GetController( Toolkit::Visual::Base visual )
+  {
+    return GetVisualObject( visual ).mController;
+  };
+
+  /**
+   * @brief Set the index of the animatable text color property.
+   * @param[in] visual The text visual.
+   * @param[in] animatablePropertyIndex The index of the animatable property
+   */
+  static void SetAnimatableTextColorProperty( Toolkit::Visual::Base visual, Property::Index animatablePropertyIndex )
+  {
+    GetVisualObject( visual ).mAnimatableTextColorPropertyIndex = animatablePropertyIndex;
+  };
+
+  /**
+   * @brief Set the flag to trigger the textures to be initialized and renderer to be added to the control.
+   * @param[in] visual The text visual.
+   */
+  static void EnableRendererUpdate( Toolkit::Visual::Base visual )
+  {
+    GetVisualObject( visual ).mRendererUpdateNeeded = true;
+  };
+
+  /**
+   * @brief Instantly updates the renderer
+   * @param[in] visual The text visual.
+   */
+  static void UpdateRenderer( Toolkit::Visual::Base visual )
+  {
+    GetVisualObject( visual ).UpdateRenderer();
+  };
+
+public: // from Visual::Base
+
+  /**
+   * @copydoc Visual::Base::GetHeightForWidth()
+   */
+  float GetHeightForWidth( float width ) override;
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize()
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap()
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache The VisualFactoryCache object
+   */
+  TextVisual( VisualFactoryCache& factoryCache );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~TextVisual();
+
+  // from Visual::Base
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties()
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage()
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOffStage()
+   */
+  void DoSetOffStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+private:
+  /**
+   * @brief Set the individual property to the given value.
+   *
+   * @param[in] index The index key used to reference this value within the initial property map.
+   *
+   * @param[in] propertyValue The value to set.
+   */
+  void DoSetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue );
+
+  /**
+   * @brief Updates the text's renderer.
+   */
+  void UpdateRenderer();
+
+  /**
+   * @brief Removes the texture set from the renderer.
+   */
+  void RemoveTextureSet();
+
+  /**
+   * Get the texture of the text for rendering.
+   * @param[in] size The texture size.
+   * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+   * @param[in] containsColorGlyph Whether the text contains color glyph.
+   * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
+   */
+  TextureSet GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled );
+
+  /**
+   * Get the text rendering shader.
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] hasMultipleTextColors Whether the text contains multiple colors.
+   * @param[in] containsColorGlyph Whether the text contains color glyph.
+   * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.).
+   */
+  Shader GetTextShader( VisualFactoryCache& factoryCache, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled );
+
+  /**
+   * @brief Retrieve the TextVisual object.
+   * @param[in] visual A handle to the TextVisual
+   * @return The TextVisual object
+   */
+  static TextVisual& GetVisualObject( Toolkit::Visual::Base visual )
+  {
+    return static_cast< TextVisual& >( Toolkit::GetImplementation( visual ).GetVisualObject() );
+  };
+
+private:
+
+  /**
+   * Used as an alternative to boolean so that it is obvious whether the text contains single or multiple text colors, and emoji and styles.
+   */
+  struct TextType
+  {
+    enum Type
+    {
+      SINGLE_COLOR_TEXT = 0, ///< The text contains single color only.
+      MULTI_COLOR_TEXT = 1,  ///< The text contains multiple colors.
+      NO_EMOJI = 0,          ///< The text contains no emoji.
+      HAS_EMOJI = 1,         ///< The text contains emoji.
+      NO_STYLES = 0,         ///< The text contains contains no styles.
+      HAS_SYLES = 1          ///< The text contains contains styles.
+    };
+  };
+
+private:
+  Text::ControllerPtr mController;                        ///< The text's controller.
+  Text::TypesetterPtr mTypesetter;                        ///< The text's typesetter.
+  WeakHandle<Actor>   mControl;                           ///< The control where the renderer is added.
+  Property::Index     mAnimatableTextColorPropertyIndex;  ///< The index of animatable text color property registered by the control.
+  bool                mRendererUpdateNeeded:1;            ///< The flag to indicate whether the renderer needs to be updated.
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_TEXT_VISUAL_H */
diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.cpp b/dali-toolkit/internal/visuals/texture-manager-impl.cpp
new file mode 100644 (file)
index 0000000..71385e2
--- /dev/null
@@ -0,0 +1,1273 @@
+ /*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+// EXTERNAL HEADERS
+#include <cstdlib>
+#include <string>
+#include <dali/public-api/math/vector4.h>
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/devel-api/common/hash.h>
+#include <dali/devel-api/images/texture-set-image.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/image-loader/image-atlas-impl.h>
+#include <dali-toolkit/public-api/image-loader/sync-image-loader.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+
+namespace
+{
+
+constexpr auto DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS = size_t{4u};
+constexpr auto DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS = size_t{8u};
+
+constexpr auto NUMBER_OF_LOCAL_LOADER_THREADS_ENV = "DALI_TEXTURE_LOCAL_THREADS";
+constexpr auto NUMBER_OF_REMOTE_LOADER_THREADS_ENV = "DALI_TEXTURE_REMOTE_THREADS";
+
+size_t GetNumberOfThreads(const char* environmentVariable, size_t defaultValue)
+{
+  using Dali::EnvironmentVariable::GetEnvironmentVariable;
+  auto numberString = GetEnvironmentVariable(environmentVariable);
+  auto numberOfThreads = numberString ? std::strtoul(numberString, nullptr, 10) : 0;
+  constexpr auto MAX_NUMBER_OF_THREADS = 100u;
+  DALI_ASSERT_DEBUG( numberOfThreads < MAX_NUMBER_OF_THREADS );
+  return ( numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS ) ? numberOfThreads : defaultValue;
+}
+
+size_t GetNumberOfLocalLoaderThreads()
+{
+  return GetNumberOfThreads(NUMBER_OF_LOCAL_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_LOCAL_LOADER_THREADS);
+}
+
+size_t GetNumberOfRemoteLoaderThreads()
+{
+  return GetNumberOfThreads(NUMBER_OF_REMOTE_LOADER_THREADS_ENV, DEFAULT_NUMBER_OF_REMOTE_LOADER_THREADS);
+}
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#ifdef DEBUG_ENABLED
+Debug::Filter* gTextureManagerLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_TEXTURE_MANAGER" );
+
+#define GET_LOAD_STATE_STRING( loadState ) \
+  loadState == TextureManager::NOT_STARTED ? "NOT_STARTED" :             \
+    loadState == TextureManager::LOADING ? "LOADING" :                   \
+    loadState == TextureManager::LOAD_FINISHED ? "LOAD_FINISHED" :       \
+    loadState == TextureManager::WAITING_FOR_MASK ? "WAITING_FOR_MASK" : \
+    loadState == TextureManager::MASK_APPLYING ? "MASK_APPLYING" :         \
+    loadState == TextureManager::MASK_APPLIED ? "MASK_APPLIED" :         \
+    loadState == TextureManager::UPLOADED ? "UPLOADED" :                 \
+    loadState == TextureManager::CANCELLED ? "CANCELLED" :               \
+    loadState == TextureManager::LOAD_FAILED ? "LOAD_FAILED" : "Unknown"
+
+#endif
+
+const uint32_t      DEFAULT_ATLAS_SIZE( 1024u );                     ///< This size can fit 8 by 8 images of average size 128 * 128
+const Vector4       FULL_ATLAS_RECT( 0.0f, 0.0f, 1.0f, 1.0f );       ///< UV Rectangle that covers the full Texture
+const int           INVALID_INDEX( -1 );                             ///< Invalid index used to represent a non-existant TextureInfo struct
+const int           INVALID_CACHE_INDEX( -1 ); ///< Invalid Cache index
+
+
+void PreMultiply( Devel::PixelBuffer pixelBuffer, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  if( Pixel::HasAlpha( pixelBuffer.GetPixelFormat() ) )
+  {
+    if( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
+    {
+      pixelBuffer.MultiplyColorByAlpha();
+    }
+  }
+  else
+  {
+    preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  }
+}
+
+} // Anonymous namespace
+
+TextureManager::MaskingData::MaskingData()
+: mAlphaMaskUrl(),
+  mAlphaMaskId( INVALID_TEXTURE_ID ),
+  mContentScaleFactor( 1.0f ),
+  mCropToMask( true )
+{
+}
+
+TextureManager::TextureManager()
+: mAsyncLocalLoaders( GetNumberOfLocalLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
+  mAsyncRemoteLoaders( GetNumberOfRemoteLoaderThreads(), [&]() { return AsyncLoadingHelper(*this); } ),
+  mExternalTextures(),
+  mLifecycleObservers(),
+  mLoadQueue(),
+  mBrokenImageUrl(""),
+  mCurrentTextureId( 0 ),
+  mQueueLoadFlag(false)
+{
+}
+
+TextureManager::~TextureManager()
+{
+  for( auto iter = mLifecycleObservers.Begin(), endIter = mLifecycleObservers.End(); iter != endIter; ++iter)
+  {
+    (*iter)->TextureManagerDestroyed();
+  }
+}
+
+Devel::PixelBuffer TextureManager::LoadPixelBuffer(
+  const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool synchronousLoading, TextureUploadObserver* textureObserver, bool orientationCorrection, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  Devel::PixelBuffer pixelBuffer;
+  if( synchronousLoading )
+  {
+    if( url.IsValid() )
+    {
+      pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode,
+                                       orientationCorrection  );
+      if( pixelBuffer && preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD )
+      {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
+      }
+    }
+  }
+  else
+  {
+    RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
+                         false, KEEP_PIXEL_BUFFER, textureObserver, orientationCorrection, TextureManager::ReloadPolicy::FORCED,
+                         preMultiplyOnLoad, true );
+  }
+
+  return pixelBuffer;
+}
+
+TextureSet TextureManager::LoadTexture(
+  const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
+  Dali::SamplingMode::Type samplingMode, MaskingDataPointer& maskInfo,
+  bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
+  Dali::ImageDimensions& textureRectSize, bool& atlasingStatus, bool& loadingStatus,
+  Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV, TextureUploadObserver* textureObserver,
+  AtlasUploadObserver* atlasObserver, ImageAtlasManagerPtr imageAtlasManager, bool orientationCorrection,
+  TextureManager::ReloadPolicy reloadPolicy, TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  TextureSet textureSet;
+
+  loadingStatus = false;
+  textureRect = FULL_ATLAS_RECT;
+
+  if( VisualUrl::TEXTURE == url.GetProtocolType())
+  {
+    std::string location = url.GetLocation();
+    if( location.size() > 0u )
+    {
+      TextureId id = std::stoi( location );
+      for( auto&& elem : mExternalTextures )
+      {
+        if( elem.textureId == id )
+        {
+          preMultiplyOnLoad = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+          textureId = elem.textureId;
+          return elem.textureSet;
+        }
+      }
+    }
+  }
+  else if( synchronousLoading )
+  {
+    PixelData data;
+    if( url.IsValid() )
+    {
+      Devel::PixelBuffer pixelBuffer = LoadImageFromFile( url.GetUrl(), desiredSize, fittingMode, samplingMode,
+                                       orientationCorrection  );
+      if( maskInfo )
+      {
+        Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile( maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(),
+                                             FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true  );
+        if( maskPixelBuffer )
+        {
+          pixelBuffer.ApplyMask( maskPixelBuffer, maskInfo->mContentScaleFactor, maskInfo->mCropToMask );
+        }
+      }
+      if( pixelBuffer )
+      {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
+        data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      }
+    }
+    if( !data )
+    {
+      // use broken image
+      textureSet = TextureSet::New();
+      Devel::PixelBuffer pixelBuffer = LoadImageFromFile( mBrokenImageUrl );
+      if( pixelBuffer )
+      {
+        PreMultiply( pixelBuffer, preMultiplyOnLoad );
+        data = Devel::PixelBuffer::Convert(pixelBuffer); // takes ownership of buffer
+      }
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
+                                      data.GetWidth(), data.GetHeight() );
+      texture.Upload( data );
+      textureSet = TextureSet::New();
+      textureSet.SetTexture( 0u, texture );
+    }
+    else
+    {
+      if( atlasingStatus ) // attempt atlasing
+      {
+        textureSet = imageAtlasManager->Add( textureRect, data );
+      }
+      if( !textureSet ) // big image, no atlasing or atlasing failed
+      {
+        atlasingStatus = false;
+        Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, data.GetPixelFormat(),
+                                        data.GetWidth(), data.GetHeight() );
+        texture.Upload( data );
+        textureSet = TextureSet::New();
+        textureSet.SetTexture( 0u, texture );
+      }
+      else
+      {
+        textureRectSize.SetWidth(data.GetWidth());
+        textureRectSize.SetHeight(data.GetHeight());
+      }
+    }
+  }
+  else
+  {
+    loadingStatus = true;
+    if( atlasingStatus )
+    {
+      textureSet = imageAtlasManager->Add( textureRect, url.GetUrl(), desiredSize, fittingMode, true, atlasObserver);
+    }
+    if( !textureSet ) // big image, no atlasing or atlasing failed
+    {
+      atlasingStatus = false;
+      if( !maskInfo )
+      {
+        textureId = RequestLoad( url, desiredSize, fittingMode, samplingMode, TextureManager::NO_ATLAS,
+                                 textureObserver, orientationCorrection, reloadPolicy, preMultiplyOnLoad );
+      }
+      else
+      {
+        maskInfo->mAlphaMaskId = RequestMaskLoad( maskInfo->mAlphaMaskUrl );
+        textureId = RequestLoad( url,
+                                 maskInfo->mAlphaMaskId,
+                                 maskInfo->mContentScaleFactor,
+                                 desiredSize,
+                                 fittingMode, samplingMode,
+                                 TextureManager::NO_ATLAS,
+                                 maskInfo->mCropToMask,
+                                 textureObserver,
+                                 orientationCorrection,
+                                 reloadPolicy, preMultiplyOnLoad );
+      }
+
+      TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
+      if( loadState == TextureManager::UPLOADED )
+      {
+        // UploadComplete has already been called - keep the same texture set
+        textureSet = GetTextureSet( textureId );
+      }
+
+      // If we are loading the texture, or waiting for the ready signal handler to complete, inform
+      // caller that they need to wait.
+      loadingStatus = ( loadState == TextureManager::LOADING ||
+                        loadState == TextureManager::WAITING_FOR_MASK ||
+                        loadState == TextureManager::MASK_APPLYING ||
+                        loadState == TextureManager::MASK_APPLIED ||
+                        loadState == TextureManager::NOT_STARTED ||
+                        mQueueLoadFlag );
+
+    }
+    else
+    {
+      textureRectSize = desiredSize;
+    }
+  }
+
+  if( ! atlasingStatus && textureSet )
+  {
+    Sampler sampler = Sampler::New();
+    sampler.SetWrapMode(  wrapModeU, wrapModeV  );
+    textureSet.SetSampler( 0u, sampler );
+  }
+
+  return textureSet;
+}
+
+TextureManager::TextureId TextureManager::RequestLoad(
+  const VisualUrl&                url,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  const UseAtlas                  useAtlas,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  return RequestLoadInternal( url, INVALID_TEXTURE_ID, 1.0f, desiredSize, fittingMode, samplingMode, useAtlas,
+                              false, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+                              preMultiplyOnLoad, false );
+}
+
+TextureManager::TextureId TextureManager::RequestLoad(
+  const VisualUrl&                url,
+  TextureId                       maskTextureId,
+  float                           contentScale,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  const UseAtlas                  useAtlas,
+  bool                            cropToMask,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad )
+{
+  return RequestLoadInternal( url, maskTextureId, contentScale, desiredSize, fittingMode, samplingMode, useAtlas,
+                              cropToMask, UPLOAD_TO_TEXTURE, observer, orientationCorrection, reloadPolicy,
+                              preMultiplyOnLoad, false );
+}
+
+TextureManager::TextureId TextureManager::RequestMaskLoad( const VisualUrl& maskUrl )
+{
+  // Use the normal load procedure to get the alpha mask.
+  auto preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+  return RequestLoadInternal( maskUrl, INVALID_TEXTURE_ID, 1.0f, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+                              SamplingMode::NO_FILTER, NO_ATLAS, false, KEEP_PIXEL_BUFFER, NULL, true,
+                              TextureManager::ReloadPolicy::CACHED, preMultiply, false );
+}
+
+TextureManager::TextureId TextureManager::RequestLoadInternal(
+  const VisualUrl&                url,
+  TextureId                       maskTextureId,
+  float                           contentScale,
+  const ImageDimensions           desiredSize,
+  FittingMode::Type               fittingMode,
+  Dali::SamplingMode::Type        samplingMode,
+  UseAtlas                        useAtlas,
+  bool                            cropToMask,
+  StorageType                     storageType,
+  TextureUploadObserver*          observer,
+  bool                            orientationCorrection,
+  TextureManager::ReloadPolicy    reloadPolicy,
+  TextureManager::MultiplyOnLoad& preMultiplyOnLoad,
+  bool                            loadPixelBuffer )
+{
+  // First check if the requested Texture is cached.
+  const TextureHash textureHash = GenerateHash( url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
+                                                maskTextureId );
+
+  TextureManager::TextureId textureId = INVALID_TEXTURE_ID;
+
+  // Look up the texture by hash. Note: The extra parameters are used in case of a hash collision.
+  int cacheIndex = FindCachedTexture( textureHash, url.GetUrl(), desiredSize, fittingMode, samplingMode, useAtlas,
+                                      maskTextureId, preMultiplyOnLoad );
+
+  // Check if the requested Texture exists in the cache.
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    if ( TextureManager::ReloadPolicy::CACHED == reloadPolicy )
+    {
+      // Mark this texture being used by another client resource. Forced reload would replace the current texture
+      // without the need for incrementing the reference count.
+      ++( mTextureInfoContainer[ cacheIndex ].referenceCount );
+    }
+    textureId = mTextureInfoContainer[ cacheIndex ].textureId;
+
+    // Update preMultiplyOnLoad value. It should be changed according to preMultiplied value of the cached info.
+    preMultiplyOnLoad = mTextureInfoContainer[ cacheIndex ].preMultiplied ? TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD : TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
+
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) Using cached texture id@%d, textureId=%d\n",
+                   url.GetUrl().c_str(), observer, cacheIndex, textureId );
+  }
+
+  if( textureId == INVALID_TEXTURE_ID ) // There was no caching, or caching not required
+  {
+    // We need a new Texture.
+    textureId = GenerateUniqueTextureId();
+    bool preMultiply = ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD );
+    mTextureInfoContainer.push_back( TextureInfo( textureId, maskTextureId, url.GetUrl(),
+                                                  desiredSize, contentScale, fittingMode, samplingMode,
+                                                  false, cropToMask, useAtlas, textureHash, orientationCorrection,
+                                                  preMultiply, loadPixelBuffer ) );
+    cacheIndex = mTextureInfoContainer.size() - 1u;
+
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureManager::RequestLoad( url=%s observer=%p ) New texture, cacheIndex:%d, textureId=%d\n",
+                   url.GetUrl().c_str(), observer, cacheIndex, textureId );
+  }
+
+  // The below code path is common whether we are using the cache or not.
+  // The textureInfoIndex now refers to either a pre-existing cached TextureInfo,
+  // or a new TextureInfo just created.
+  TextureInfo& textureInfo( mTextureInfoContainer[ cacheIndex ] );
+  textureInfo.maskTextureId = maskTextureId;
+  textureInfo.storageType = storageType;
+  textureInfo.orientationCorrection = orientationCorrection;
+
+  DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "TextureInfo loadState:%s\n",
+                 GET_LOAD_STATE_STRING(textureInfo.loadState ) );
+
+  // Force reloading of texture by setting loadState unless already loading or cancelled.
+  if ( TextureManager::ReloadPolicy::FORCED == reloadPolicy &&
+       TextureManager::LOADING != textureInfo.loadState &&
+       TextureManager::WAITING_FOR_MASK != textureInfo.loadState &&
+       TextureManager::MASK_APPLYING != textureInfo.loadState &&
+       TextureManager::MASK_APPLIED != textureInfo.loadState &&
+       TextureManager::CANCELLED != textureInfo.loadState )
+  {
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Verbose, "TextureManager::RequestLoad( url=%s observer=%p ) ForcedReload cacheIndex:%d, textureId=%d\n",
+                   url.GetUrl().c_str(), observer, cacheIndex, textureId );
+    textureInfo.loadState = TextureManager::NOT_STARTED;
+  }
+
+  // Check if we should add the observer.
+  // Only do this if we have not loaded yet and it will not have loaded by the end of this method.
+  switch( textureInfo.loadState )
+  {
+    case TextureManager::LOAD_FAILED: // Failed notifies observer which then stops observing.
+    case TextureManager::NOT_STARTED:
+    {
+      LoadOrQueueTexture( textureInfo, observer ); // If called inside NotifyObservers, queues until afterwards
+      break;
+    }
+    case TextureManager::LOADING:
+    case TextureManager::WAITING_FOR_MASK:
+    case TextureManager::MASK_APPLYING:
+    case TextureManager::MASK_APPLIED:
+    {
+      ObserveTexture( textureInfo, observer );
+      break;
+    }
+    case TextureManager::UPLOADED:
+    {
+      if( observer )
+      {
+        LoadOrQueueTexture( textureInfo, observer );
+      }
+      break;
+    }
+    case TextureManager::CANCELLED:
+    {
+      // A cancelled texture hasn't finished loading yet. Treat as a loading texture
+      // (it's ref count has already been incremented, above)
+      textureInfo.loadState = TextureManager::LOADING;
+      ObserveTexture( textureInfo, observer );
+      break;
+    }
+    case TextureManager::LOAD_FINISHED:
+      // Loading has already completed.
+      if( observer && textureInfo.loadPixelBuffer )
+      {
+        LoadOrQueueTexture( textureInfo, observer );
+      }
+      break;
+  }
+
+  // Return the TextureId for which this Texture can now be referenced by externally.
+  return textureId;
+}
+
+void TextureManager::Remove( const TextureManager::TextureId textureId, TextureUploadObserver* observer )
+{
+  int textureInfoIndex = GetCacheIndexFromId( textureId );
+  if( textureInfoIndex != INVALID_INDEX )
+  {
+    TextureInfo& textureInfo( mTextureInfoContainer[ textureInfoIndex ] );
+
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise,
+                   "TextureManager::Remove(%d) url:%s\n  cacheIdx:%d loadState:%s reference count = %d\n",
+                   textureId, textureInfo.url.GetUrl().c_str(),
+                   textureInfoIndex, GET_LOAD_STATE_STRING( textureInfo.loadState ), textureInfo.referenceCount );
+
+    // Decrement the reference count and check if this is the last user of this Texture.
+    if( --textureInfo.referenceCount <= 0 )
+    {
+      // This is the last remove for this Texture.
+      textureInfo.referenceCount = 0;
+      bool removeTextureInfo = false;
+
+      // If loaded, we can remove the TextureInfo and the Atlas (if atlased).
+      if( textureInfo.loadState == UPLOADED )
+      {
+        if( textureInfo.atlas )
+        {
+          textureInfo.atlas.Remove( textureInfo.atlasRect );
+        }
+        removeTextureInfo = true;
+      }
+      else if( textureInfo.loadState == LOADING )
+      {
+        // We mark the textureInfo for removal.
+        // Once the load has completed, this method will be called again.
+        textureInfo.loadState = CANCELLED;
+      }
+      else
+      {
+        // In other states, we are not waiting for a load so we are safe to remove the TextureInfo data.
+        removeTextureInfo = true;
+      }
+
+      // If the state allows us to remove the TextureInfo data, we do so.
+      if( removeTextureInfo )
+      {
+        // Permanently remove the textureInfo struct.
+        mTextureInfoContainer.erase( mTextureInfoContainer.begin() + textureInfoIndex );
+      }
+    }
+
+    if( observer )
+    {
+      // Remove element from the LoadQueue
+      for( auto&& element : mLoadQueue )
+      {
+        if( element.mObserver == observer )
+        {
+          mLoadQueue.Erase( &element );
+          break;
+        }
+      }
+    }
+  }
+}
+
+VisualUrl TextureManager::GetVisualUrl( TextureId textureId )
+{
+  VisualUrl visualUrl("");
+  int cacheIndex = GetCacheIndexFromId( textureId );
+
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::GetVisualUrl. Using cached texture id=%d, textureId=%d\n",
+                   cacheIndex, textureId );
+
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    visualUrl = cachedTextureInfo.url;
+  }
+  return visualUrl;
+}
+
+TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId )
+{
+  LoadState loadState = TextureManager::NOT_STARTED;
+
+  int cacheIndex = GetCacheIndexFromId( textureId );
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    loadState = cachedTextureInfo.loadState;
+  }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        loadState = LoadState::UPLOADED;
+        break;
+      }
+    }
+  }
+  return loadState;
+}
+
+TextureManager::LoadState TextureManager::GetTextureStateInternal( TextureId textureId )
+{
+  LoadState loadState = TextureManager::NOT_STARTED;
+
+  int cacheIndex = GetCacheIndexFromId( textureId );
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    loadState = cachedTextureInfo.loadState;
+  }
+
+  return loadState;
+}
+
+TextureSet TextureManager::GetTextureSet( TextureId textureId )
+{
+  TextureSet textureSet;// empty handle
+
+  int cacheIndex = GetCacheIndexFromId( textureId );
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    textureSet = cachedTextureInfo.textureSet;
+  }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        textureSet = elem.textureSet;
+        break;
+      }
+    }
+  }
+  return textureSet;
+}
+
+std::string TextureManager::AddExternalTexture( TextureSet& textureSet )
+{
+  TextureManager::ExternalTextureInfo info;
+  info.textureId = GenerateUniqueTextureId();
+  info.textureSet = textureSet;
+  mExternalTextures.emplace_back( info );
+  return VisualUrl::CreateTextureUrl( std::to_string( info.textureId ) );
+}
+
+TextureSet TextureManager::RemoveExternalTexture( const std::string& url )
+{
+  if( url.size() > 0u )
+  {
+    // get the location from the Url
+    VisualUrl parseUrl( url );
+    if( VisualUrl::TEXTURE == parseUrl.GetProtocolType() )
+    {
+      std::string location = parseUrl.GetLocation();
+      if( location.size() > 0u )
+      {
+        TextureId id = std::stoi( location );
+        const auto end = mExternalTextures.end();
+        for( auto iter = mExternalTextures.begin(); iter != end; ++iter )
+        {
+          if( iter->textureId == id )
+          {
+            auto textureSet = iter->textureSet;
+            mExternalTextures.erase( iter );
+            return textureSet;
+          }
+        }
+      }
+    }
+  }
+  return TextureSet();
+}
+
+
+void TextureManager::AddObserver( TextureManager::LifecycleObserver& observer )
+{
+  // make sure an observer doesn't observe the same object twice
+  // otherwise it will get multiple calls to ObjectDestroyed()
+  DALI_ASSERT_DEBUG( mLifecycleObservers.End() == std::find( mLifecycleObservers.Begin(), mLifecycleObservers.End(), &observer));
+  mLifecycleObservers.PushBack( &observer );
+}
+
+void TextureManager::RemoveObserver( TextureManager::LifecycleObserver& observer)
+{
+  // Find the observer...
+  auto endIter =  mLifecycleObservers.End();
+  for( auto iter = mLifecycleObservers.Begin(); iter != endIter; ++iter)
+  {
+    if( (*iter) == &observer)
+    {
+      mLifecycleObservers.Erase( iter );
+      break;
+    }
+  }
+  DALI_ASSERT_DEBUG(endIter != mLifecycleObservers.End());
+}
+
+void TextureManager::LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer )
+{
+  switch( textureInfo.loadState )
+  {
+    case NOT_STARTED:
+    case LOAD_FAILED:
+    {
+      if( mQueueLoadFlag )
+      {
+        QueueLoadTexture( textureInfo, observer );
+      }
+      else
+      {
+        LoadTexture( textureInfo, observer );
+      }
+      break;
+    }
+    case UPLOADED:
+    {
+      if( mQueueLoadFlag )
+      {
+        QueueLoadTexture( textureInfo, observer );
+      }
+      else
+      {
+        // The Texture has already loaded. The other observers have already been notified.
+        // We need to send a "late" loaded notification for this observer.
+        observer->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet,
+                                  textureInfo.useAtlas, textureInfo.atlasRect,
+                                  textureInfo.preMultiplied );
+      }
+      break;
+    }
+    case LOADING:
+    case CANCELLED:
+    case LOAD_FINISHED:
+    case WAITING_FOR_MASK:
+    case MASK_APPLYING:
+    case MASK_APPLIED:
+    {
+      break;
+    }
+  }
+}
+
+void TextureManager::QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer )
+{
+  auto textureId = textureInfo.textureId;
+  mLoadQueue.PushBack( LoadQueueElement( textureId, observer) );
+}
+
+void TextureManager::LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer )
+{
+  DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::LoadTexture(): url:%s sync:%s\n",
+                 textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously?"T":"F" );
+
+  textureInfo.loadState = LOADING;
+  if( !textureInfo.loadSynchronously )
+  {
+    auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
+    auto loadingHelperIt = loadersContainer.GetNext();
+    auto premultiplyOnLoad = ( textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID ) ?
+                               DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
+    DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
+    loadingHelperIt->Load(textureInfo.textureId, textureInfo.url,
+                          textureInfo.desiredSize, textureInfo.fittingMode,
+                          textureInfo.samplingMode, textureInfo.orientationCorrection,
+                          premultiplyOnLoad );
+  }
+  ObserveTexture( textureInfo, observer );
+}
+
+void TextureManager::ProcessQueuedTextures()
+{
+  for( auto&& element : mLoadQueue )
+  {
+    int cacheIndex = GetCacheIndexFromId( element.mTextureId );
+    if( cacheIndex != INVALID_CACHE_INDEX )
+    {
+      TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+      if( textureInfo.loadState == UPLOADED )
+      {
+        element.mObserver->UploadComplete( true, textureInfo.textureId, textureInfo.textureSet,
+                                           textureInfo.useAtlas, textureInfo.atlasRect,
+                                           textureInfo.preMultiplied );
+      }
+      else if ( textureInfo.loadState == LOAD_FINISHED && textureInfo.loadPixelBuffer )
+      {
+        element.mObserver->LoadComplete( true, textureInfo.pixelBuffer, textureInfo.url, textureInfo.preMultiplied );
+      }
+      else
+      {
+        LoadTexture( textureInfo, element.mObserver );
+      }
+    }
+  }
+  mLoadQueue.Clear();
+}
+
+void TextureManager::ObserveTexture( TextureInfo& textureInfo,
+                                     TextureUploadObserver* observer )
+{
+  DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::ObserveTexture(): url:%s observer:%p\n",
+                 textureInfo.url.GetUrl().c_str(), observer );
+
+  if( observer )
+  {
+    textureInfo.observerList.PushBack( observer );
+    observer->DestructionSignal().Connect( this, &TextureManager::ObserverDestroyed );
+  }
+}
+
+void TextureManager::AsyncLoadComplete( AsyncLoadingInfoContainerType& loadingContainer, uint32_t id,
+                                        Devel::PixelBuffer pixelBuffer )
+{
+  DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::AsyncLoadComplete( id:%d )\n", id );
+
+  if( loadingContainer.size() >= 1u )
+  {
+    AsyncLoadingInfo loadingInfo = loadingContainer.front();
+
+    if( loadingInfo.loadId == id )
+    {
+      int cacheIndex = GetCacheIndexFromId( loadingInfo.textureId );
+      if( cacheIndex != INVALID_CACHE_INDEX )
+      {
+        TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+
+        DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise,
+                       "  textureId:%d Url:%s CacheIndex:%d LoadState: %d\n",
+                       textureInfo.textureId, textureInfo.url.GetUrl().c_str(), cacheIndex, textureInfo.loadState );
+
+        if( textureInfo.loadState != CANCELLED )
+        {
+          // textureInfo can be invalidated after this call (as the mTextureInfoContainer may be modified)
+          PostLoad( textureInfo, pixelBuffer );
+        }
+        else
+        {
+          Remove( textureInfo.textureId, nullptr );
+        }
+      }
+    }
+
+    loadingContainer.pop_front();
+  }
+}
+
+void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer )
+{
+  // Was the load successful?
+  if( pixelBuffer && ( pixelBuffer.GetWidth() != 0 ) && ( pixelBuffer.GetHeight() != 0 ) )
+  {
+    // No atlas support for now
+    textureInfo.useAtlas = NO_ATLAS;
+    textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied();
+
+    if( textureInfo.storageType == UPLOAD_TO_TEXTURE )
+    {
+      // If there is a mask texture ID associated with this texture, then apply the mask
+      // if it's already loaded. If it hasn't, and the mask is still loading,
+      // wait for the mask to finish loading.
+      if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
+      {
+        if( textureInfo.loadState == MASK_APPLYING )
+        {
+          textureInfo.loadState = MASK_APPLIED;
+          UploadTexture( pixelBuffer, textureInfo );
+          NotifyObservers( textureInfo, true );
+        }
+        else
+        {
+          LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId );
+          textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
+          if( maskLoadState == LOADING )
+          {
+            textureInfo.loadState = WAITING_FOR_MASK;
+          }
+          else if( maskLoadState == LOAD_FINISHED )
+          {
+            // Send New Task to Thread
+            ApplyMask( textureInfo, textureInfo.maskTextureId );
+          }
+        }
+      }
+      else
+      {
+        UploadTexture( pixelBuffer, textureInfo );
+        NotifyObservers( textureInfo, true );
+      }
+    }
+    else
+    {
+      textureInfo.pixelBuffer = pixelBuffer; // Store the pixel data
+      textureInfo.loadState = LOAD_FINISHED;
+
+      if( textureInfo.loadPixelBuffer )
+      {
+        NotifyObservers( textureInfo, true );
+      }
+      // Check if there was another texture waiting for this load to complete
+      // (e.g. if this was an image mask, and its load is on a different thread)
+      CheckForWaitingTexture( textureInfo );
+    }
+  }
+  else
+  {
+    // @todo If the load was unsuccessful, upload the broken image.
+    textureInfo.loadState = LOAD_FAILED;
+    CheckForWaitingTexture( textureInfo );
+    NotifyObservers( textureInfo, false );
+  }
+}
+
+void TextureManager::CheckForWaitingTexture( TextureInfo& maskTextureInfo )
+{
+  // Search the cache, checking if any texture has this texture id as a
+  // maskTextureId:
+  const unsigned int size = mTextureInfoContainer.size();
+
+  for( unsigned int cacheIndex = 0; cacheIndex < size; ++cacheIndex )
+  {
+    if( mTextureInfoContainer[cacheIndex].maskTextureId == maskTextureInfo.textureId &&
+        mTextureInfoContainer[cacheIndex].loadState == WAITING_FOR_MASK )
+    {
+      TextureInfo& textureInfo( mTextureInfoContainer[cacheIndex] );
+
+      if( maskTextureInfo.loadState == LOAD_FINISHED )
+      {
+        // Send New Task to Thread
+        ApplyMask( textureInfo, maskTextureInfo.textureId );
+      }
+      else
+      {
+        textureInfo.pixelBuffer.Reset();
+        textureInfo.loadState = LOAD_FAILED;
+        NotifyObservers( textureInfo, false );
+      }
+    }
+  }
+}
+
+void TextureManager::ApplyMask( TextureInfo& textureInfo, TextureId maskTextureId )
+{
+  int maskCacheIndex = GetCacheIndexFromId( maskTextureId );
+  if( maskCacheIndex != INVALID_CACHE_INDEX )
+  {
+    Devel::PixelBuffer maskPixelBuffer = mTextureInfoContainer[maskCacheIndex].pixelBuffer;
+    Devel::PixelBuffer pixelBuffer = textureInfo.pixelBuffer;
+    textureInfo.pixelBuffer.Reset();
+
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n",
+                   textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously?"T":"F" );
+
+    textureInfo.loadState = MASK_APPLYING;
+    auto& loadersContainer = textureInfo.url.IsLocalResource() ? mAsyncLocalLoaders : mAsyncRemoteLoaders;
+    auto loadingHelperIt = loadersContainer.GetNext();
+    auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
+    DALI_ASSERT_ALWAYS(loadingHelperIt != loadersContainer.End());
+    loadingHelperIt->ApplyMask( textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad );
+  }
+}
+
+void TextureManager::UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo )
+{
+  if( textureInfo.useAtlas != USE_ATLAS )
+  {
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::General, "  TextureManager::UploadTexture() New Texture for textureId:%d\n", textureInfo.textureId );
+
+    // Check if this pixelBuffer is premultiplied
+    textureInfo.preMultiplied = pixelBuffer.IsAlphaPreMultiplied();
+
+    Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, pixelBuffer.GetPixelFormat(),
+                                    pixelBuffer.GetWidth(), pixelBuffer.GetHeight() );
+
+    PixelData pixelData = Devel::PixelBuffer::Convert( pixelBuffer );
+    texture.Upload( pixelData );
+    if ( ! textureInfo.textureSet )
+    {
+      textureInfo.textureSet = TextureSet::New();
+    }
+    textureInfo.textureSet.SetTexture( 0u, texture );
+  }
+
+  // Update the load state.
+  // Note: This is regardless of success as we care about whether a
+  // load attempt is in progress or not.  If unsuccessful, a broken
+  // image is still loaded.
+  textureInfo.loadState = UPLOADED;
+}
+
+void TextureManager::NotifyObservers( TextureInfo& textureInfo, bool success )
+{
+  TextureId textureId = textureInfo.textureId;
+
+  // If there is an observer: Notify the load is complete, whether successful or not,
+  // and erase it from the list
+  TextureInfo* info = &textureInfo;
+
+  mQueueLoadFlag = true;
+
+  while( info->observerList.Count() )
+  {
+    TextureUploadObserver* observer = info->observerList[0];
+
+    // During UploadComplete() a Control ResourceReady() signal is emitted.
+    // During that signal the app may add remove /add Textures (e.g. via
+    // ImageViews).
+    // It is possible for observers to be removed from the observer list,
+    // and it is also possible for the mTextureInfoContainer to be modified,
+    // invalidating the reference to the textureInfo struct.
+    // Texture load requests for the same URL are deferred until the end of this
+    // method.
+    DALI_LOG_INFO( gTextureManagerLogFilter, Debug::Concise, "NotifyObservers() url:%s loadState:%s\n",
+                   textureInfo.url.GetUrl().c_str(), GET_LOAD_STATE_STRING(textureInfo.loadState ) );
+
+    // It is possible for the observer to be deleted.
+    // Disconnect and remove the observer first.
+    observer->DestructionSignal().Disconnect( this, &TextureManager::ObserverDestroyed );
+
+    info->observerList.Erase( info->observerList.begin() );
+
+    if( info->loadPixelBuffer )
+    {
+      observer->LoadComplete( success, info->pixelBuffer, info->url, info->preMultiplied );
+    }
+    else
+    {
+      observer->UploadComplete( success, info->textureId, info->textureSet, info->useAtlas, info->atlasRect,
+                                info->preMultiplied );
+    }
+
+    // Get the textureInfo from the container again as it may have been invalidated.
+    int textureInfoIndex = GetCacheIndexFromId( textureId );
+    if( textureInfoIndex == INVALID_CACHE_INDEX)
+    {
+      break; // texture has been removed - can stop.
+    }
+    info = &mTextureInfoContainer[ textureInfoIndex ];
+  }
+
+  mQueueLoadFlag = false;
+  ProcessQueuedTextures();
+
+  if( info->loadPixelBuffer && info->observerList.Count() == 0 )
+  {
+    Remove( info->textureId, nullptr );
+  }
+}
+
+TextureManager::TextureId TextureManager::GenerateUniqueTextureId()
+{
+  return mCurrentTextureId++;
+}
+
+int TextureManager::GetCacheIndexFromId( const TextureId textureId )
+{
+  const unsigned int size = mTextureInfoContainer.size();
+
+  for( unsigned int i = 0; i < size; ++i )
+  {
+    if( mTextureInfoContainer[i].textureId == textureId )
+    {
+      return i;
+    }
+  }
+
+  return INVALID_CACHE_INDEX;
+}
+
+TextureManager::TextureHash TextureManager::GenerateHash(
+  const std::string&             url,
+  const ImageDimensions          size,
+  const FittingMode::Type        fittingMode,
+  const Dali::SamplingMode::Type samplingMode,
+  const UseAtlas                 useAtlas,
+  TextureId                      maskTextureId )
+{
+  std::string hashTarget( url );
+  const size_t urlLength = hashTarget.length();
+  const uint16_t width = size.GetWidth();
+  const uint16_t height = size.GetWidth();
+
+  // If either the width or height has been specified, include the resizing options in the hash
+  if( width != 0 || height != 0 )
+  {
+    // We are appending 5 bytes to the URL to form the hash input.
+    hashTarget.resize( urlLength + 5u );
+    char* hashTargetPtr = &( hashTarget[ urlLength ] );
+
+    // Pack the width and height (4 bytes total).
+    *hashTargetPtr++ = size.GetWidth() & 0xff;
+    *hashTargetPtr++ = ( size.GetWidth() >> 8u ) & 0xff;
+    *hashTargetPtr++ = size.GetHeight() & 0xff;
+    *hashTargetPtr++ = ( size.GetHeight() >> 8u ) & 0xff;
+
+    // Bit-pack the FittingMode, SamplingMode and atlasing.
+    // FittingMode=2bits, SamplingMode=3bits, useAtlas=1bit
+    *hashTargetPtr   = ( fittingMode << 4u ) | ( samplingMode << 1 ) | useAtlas;
+  }
+  else
+  {
+    // We are not including sizing information, but we still need an extra byte for atlasing.
+    hashTarget.resize( urlLength + 1u );
+
+    // Add the atlasing to the hash input.
+    switch( useAtlas )
+    {
+      case UseAtlas::NO_ATLAS:
+      {
+        hashTarget[ urlLength ] = 'f';
+        break;
+      }
+      case UseAtlas::USE_ATLAS:
+      {
+        hashTarget[ urlLength ] = 't';
+        break;
+      }
+    }
+  }
+
+  if( maskTextureId != INVALID_TEXTURE_ID )
+  {
+    auto textureIdIndex = hashTarget.length();
+    hashTarget.resize( hashTarget.length() + sizeof( TextureId ) );
+    unsigned char* hashTargetPtr = reinterpret_cast<unsigned char*>(&( hashTarget[ textureIdIndex ] ));
+
+    // Append the texture id to the end of the URL byte by byte:
+    // (to avoid SIGBUS / alignment issues)
+    for( size_t byteIter = 0; byteIter < sizeof( TextureId ); ++byteIter )
+    {
+      *hashTargetPtr++ = maskTextureId & 0xff;
+      maskTextureId >>= 8u;
+    }
+  }
+
+  return Dali::CalculateHash( hashTarget );
+}
+
+int TextureManager::FindCachedTexture(
+  const TextureManager::TextureHash hash,
+  const std::string&                url,
+  const ImageDimensions             size,
+  const FittingMode::Type           fittingMode,
+  const Dali::SamplingMode::Type    samplingMode,
+  const bool                        useAtlas,
+  TextureId                         maskTextureId,
+  TextureManager::MultiplyOnLoad    preMultiplyOnLoad )
+{
+  // Default to an invalid ID, in case we do not find a match.
+  int cacheIndex = INVALID_CACHE_INDEX;
+
+  // Iterate through our hashes to find a match.
+  const unsigned int count = mTextureInfoContainer.size();
+  for( unsigned int i = 0u; i < count; ++i )
+  {
+    if( mTextureInfoContainer[i].hash == hash )
+    {
+      // We have a match, now we check all the original parameters in case of a hash collision.
+      TextureInfo& textureInfo( mTextureInfoContainer[i] );
+
+      if( ( url == textureInfo.url.GetUrl() ) &&
+          ( useAtlas == textureInfo.useAtlas ) &&
+          ( maskTextureId == textureInfo.maskTextureId ) &&
+          ( size == textureInfo.desiredSize ) &&
+          ( ( size.GetWidth() == 0 && size.GetHeight() == 0 ) ||
+            ( fittingMode == textureInfo.fittingMode &&
+              samplingMode == textureInfo.samplingMode ) ) )
+      {
+        // 1. If preMultiplyOnLoad is MULTIPLY_ON_LOAD, then textureInfo.preMultiplyOnLoad should be true. The premultiplication result can be different.
+        // 2. If preMultiplyOnLoad is LOAD_WITHOUT_MULTIPLY, then textureInfo.preMultiplied should be false.
+        if( ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::MULTIPLY_ON_LOAD && textureInfo.preMultiplyOnLoad )
+            || ( preMultiplyOnLoad == TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY && !textureInfo.preMultiplied ) )
+        {
+          // The found Texture is a match.
+          cacheIndex = i;
+          break;
+        }
+      }
+    }
+  }
+
+  return cacheIndex;
+}
+
+void TextureManager::ObserverDestroyed( TextureUploadObserver* observer )
+{
+  const unsigned int count = mTextureInfoContainer.size();
+  for( unsigned int i = 0; i < count; ++i )
+  {
+    TextureInfo& textureInfo( mTextureInfoContainer[i] );
+    for( TextureInfo::ObserverListType::Iterator j = textureInfo.observerList.Begin();
+         j != textureInfo.observerList.End(); )
+    {
+      if( *j == observer )
+      {
+        j = textureInfo.observerList.Erase( j );
+      }
+      else
+      {
+        ++j;
+      }
+    }
+  }
+}
+
+
+TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(TextureManager& textureManager)
+: AsyncLoadingHelper(Toolkit::AsyncImageLoader::New(), textureManager,
+                     AsyncLoadingInfoContainerType())
+{
+}
+
+void TextureManager::AsyncLoadingHelper::Load(TextureId          textureId,
+                                              const VisualUrl&   url,
+                                              ImageDimensions    desiredSize,
+                                              FittingMode::Type  fittingMode,
+                                              SamplingMode::Type samplingMode,
+                                              bool               orientationCorrection,
+                                              DevelAsyncImageLoader::PreMultiplyOnLoad  preMultiplyOnLoad)
+{
+  mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
+  auto id = DevelAsyncImageLoader::Load( mLoader, url.GetUrl(), desiredSize, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad );
+  mLoadingInfoContainer.back().loadId = id;
+}
+
+void TextureManager::AsyncLoadingHelper::ApplyMask( TextureId textureId,
+                                                    Devel::PixelBuffer pixelBuffer,
+                                                    Devel::PixelBuffer maskPixelBuffer,
+                                                    float contentScale,
+                                                    bool cropToMask,
+                                                    DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad )
+{
+  mLoadingInfoContainer.push_back(AsyncLoadingInfo(textureId));
+  auto id = DevelAsyncImageLoader::ApplyMask( mLoader, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad );
+  mLoadingInfoContainer.back().loadId = id;
+}
+
+TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(AsyncLoadingHelper&& rhs)
+: AsyncLoadingHelper(rhs.mLoader, rhs.mTextureManager, std::move(rhs.mLoadingInfoContainer))
+{
+}
+
+TextureManager::AsyncLoadingHelper::AsyncLoadingHelper(
+    Toolkit::AsyncImageLoader loader,
+    TextureManager& textureManager,
+    AsyncLoadingInfoContainerType&& loadingInfoContainer)
+: mLoader(loader),
+  mTextureManager(textureManager),
+  mLoadingInfoContainer(std::move(loadingInfoContainer))
+{
+  DevelAsyncImageLoader::PixelBufferLoadedSignal(mLoader).Connect(
+      this, &AsyncLoadingHelper::AsyncLoadComplete);
+}
+
+void TextureManager::AsyncLoadingHelper::AsyncLoadComplete(uint32_t           id,
+                                                           Devel::PixelBuffer pixelBuffer )
+{
+  mTextureManager.AsyncLoadComplete( mLoadingInfoContainer, id, pixelBuffer );
+}
+
+void TextureManager::SetBrokenImageUrl(const std::string& brokenImageUrl)
+{
+  mBrokenImageUrl = brokenImageUrl;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/texture-manager-impl.h b/dali-toolkit/internal/visuals/texture-manager-impl.h
new file mode 100755 (executable)
index 0000000..5146991
--- /dev/null
@@ -0,0 +1,849 @@
+#ifndef DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
+#define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
+
+/*
+ * Copyright (c) 2020 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 <deque>
+#include <functional>
+#include <string>
+#include <memory>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/texture-set.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/public-api/image-loader/async-image-loader.h>
+#include <dali-toolkit/internal/visuals/texture-upload-observer.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class ImageAtlasManager;
+typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
+
+/**
+ * The TextureManager provides a common Image loading API for Visuals.
+ *
+ * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
+ * Texture caching is provided and performed when possible.
+ * Broken Images are automatically provided on load failure.
+ */
+class TextureManager : public ConnectionTracker
+{
+public:
+
+  typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
+  static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
+
+  /**
+   * Whether the texture should be atlased or uploaded into it's own GPU texture
+   */
+  enum UseAtlas
+  {
+    NO_ATLAS,
+    USE_ATLAS
+  };
+
+  /**
+   * Whether the pixel data should be kept in TextureManager, or uploaded for rendering
+   */
+  enum StorageType
+  {
+    KEEP_PIXEL_BUFFER,
+    UPLOAD_TO_TEXTURE
+  };
+
+  /**
+   * Whether the texture should be loaded synchronously or asynchronously.
+   */
+  enum LoadType
+  {
+    LOAD_ASYNCHRONOUSLY,
+    LOAD_SYNCHRONOUSLY
+  };
+
+  /**
+   * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
+   */
+  enum LoadState
+  {
+    NOT_STARTED,     ///< Default
+    LOADING,         ///< Loading has been started, but not finished.
+    LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
+    WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
+    MASK_APPLYING,   ///< Loading has finished, Mask is applying
+    MASK_APPLIED,    ///< Loading has finished, Mask is applyied by GPU
+    UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
+    CANCELLED,       ///< Removed before loading completed
+    LOAD_FAILED      ///< Async loading failed, e.g. connection problem
+  };
+
+  /**
+   * @brief Types of reloading policies
+   */
+  enum class ReloadPolicy
+  {
+    CACHED = 0,             ///< Loads cached texture if it exists.
+    FORCED                  ///< Forces reloading of texture.
+  };
+
+  /**
+   * @brief Whether to multiply alpha into color channels on load
+   */
+  enum class MultiplyOnLoad
+  {
+    LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image
+    MULTIPLY_ON_LOAD           ///< Multiply alpha into color channels on load
+  };
+
+public:
+
+  struct MaskingData
+  {
+    MaskingData();
+    ~MaskingData() = default;
+
+    VisualUrl mAlphaMaskUrl;
+    TextureManager::TextureId mAlphaMaskId;
+    float mContentScaleFactor;
+    bool mCropToMask;
+  };
+  using MaskingDataPointer = std::unique_ptr<MaskingData>;
+
+
+  /**
+   * Class to provide lifecycle event on destruction of texture manager.
+   */
+  struct LifecycleObserver
+  {
+    /**
+     * Called shortly before the texture manager is destroyed.
+     */
+    virtual void TextureManagerDestroyed() = 0;
+  };
+
+  /**
+   * Constructor.
+   */
+  TextureManager();
+
+  /**
+   * Destructor.
+   */
+  ~TextureManager();
+
+  // TextureManager Main API:
+
+  /**
+   * @brief Requests an image load of the given URL to get PixelBuffer.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the LoadComplete method called when the load is ready.
+   *
+   * @param[in] url                   The URL of the image to load
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] synchronousLoading    true if the URL should be loaded synchronously
+   * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                  image has no alpha channel
+   *
+   * @return                          The pixel buffer containing the image, or empty if still loading.
+   */
+
+  Devel::PixelBuffer LoadPixelBuffer( const VisualUrl& url,
+                                      Dali::ImageDimensions desiredSize,
+                                      Dali::FittingMode::Type fittingMode,
+                                      Dali::SamplingMode::Type samplingMode,
+                                      bool synchronousLoading,
+                                      TextureUploadObserver* textureObserver,
+                                      bool orientationCorrection,
+                                      TextureManager::MultiplyOnLoad& preMultiplyOnLoad );
+
+
+  /**
+   * @brief Requests an image load of the given URL.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url                   The URL of the image to load
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in, out] maskInfo         Mask info structure
+   * @param[in] synchronousLoading    true if the URL should be loaded synchronously
+   * @param[out] textureId,           The textureId of the URL
+   * @param[out] textureRect          The rectangle within the texture atlas that this URL occupies,
+   *                                  this is the rectangle in normalized coordinates.
+   * @param[out] textureRectSize      The rectangle within the texture atlas that this URL occupies,
+   *                                  this is the same rectangle in pixels.
+   * @param[in,out] atlasingStatus    Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
+   *                                  be loaded, and marked successful, but this will be set to false.
+   *                                  If atlasing succeeds, this will be set to true.
+   * @param[out] loadingStatus        The loading status of the texture
+   * @param[in] wrapModeU             Horizontal Wrap mode
+   * @param[in] wrapModeV             Vertical Wrap mode
+   * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] atlasObserver         This is used if the texture is atlased, and will be called instead of
+   *                                  textureObserver.UploadCompleted
+   * @param[in] imageAtlasManager     The atlas manager to use for atlasing textures
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                  image has no alpha channel
+   *
+   * @return                          The texture set containing the image, or empty if still loading.
+   */
+
+  TextureSet LoadTexture( const VisualUrl&             url,
+                          Dali::ImageDimensions        desiredSize,
+                          Dali::FittingMode::Type      fittingMode,
+                          Dali::SamplingMode::Type     samplingMode,
+                          MaskingDataPointer&          maskInfo,
+                          bool                         synchronousLoading,
+                          TextureManager::TextureId&   textureId,
+                          Vector4&                     textureRect,
+                          Dali::ImageDimensions&       textureRectSize,
+                          bool&                        atlasingStatus,
+                          bool&                        loadingStatus,
+                          Dali::WrapMode::Type         wrapModeU,
+                          Dali::WrapMode::Type         wrapModeV,
+                          TextureUploadObserver*       textureObserver,
+                          AtlasUploadObserver*         atlasObserver,
+                          ImageAtlasManagerPtr         imageAtlasManager,
+                          bool                         orientationCorrection,
+                          TextureManager::ReloadPolicy reloadPolicy,
+                          MultiplyOnLoad&              preMultiplyOnLoad );
+
+  /**
+   * @brief Requests an image load of the given URL.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url                   The URL of the image to load
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
+   *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in,out] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
+   * @return                          A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestLoad( const VisualUrl&                   url,
+                         const ImageDimensions              desiredSize,
+                         FittingMode::Type                  fittingMode,
+                         Dali::SamplingMode::Type           samplingMode,
+                         const UseAtlas                     useAtlasing,
+                         TextureUploadObserver*             observer,
+                         bool                               orientationCorrection,
+                         TextureManager::ReloadPolicy       reloadPolicy,
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
+
+  /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, it will perform a blend with the image mask, and upload
+   * the blended texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url                   The URL of the image to load
+   * @param[in] maskTextureId         The texture id of an image to mask this with
+   *                                  (can be INVALID if no masking required)
+   * @param[in] contentScale          The scale factor to apply to the image before masking
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
+   *                                  be loaded, and marked successful,
+   *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from
+   *                                  the TextureManagerUploadObserver.
+   * @param[in] cropToMask            Only used with masking, this will crop the scaled image to the mask size.
+   *                                  If false, then the mask will be scaled to fit the image before being applied.
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
+   *                                  virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the
+   *                                  image has no alpha channel
+   * @return                          A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestLoad( const VisualUrl&                   url,
+                         TextureId                          maskTextureId,
+                         float                              contentScale,
+                         const ImageDimensions              desiredSize,
+                         FittingMode::Type                  fittingMode,
+                         Dali::SamplingMode::Type           samplingMode,
+                         const UseAtlas                     useAtlasing,
+                         bool                               cropToMask,
+                         TextureUploadObserver*             observer,
+                         bool                               orientationCorrection,
+                         TextureManager::ReloadPolicy       reloadPolicy,
+                         MultiplyOnLoad&                    preMultiplyOnLoad );
+
+  /**
+   * Requests a masking image to be loaded. This mask is not uploaded to GL,
+   * instead, it is stored in CPU memory, and can be used for CPU blending.
+   */
+  TextureId RequestMaskLoad( const VisualUrl& maskUrl );
+
+  /**
+   * @brief Remove a Texture from the TextureManager.
+   *
+   * Textures are cached and therefore only the removal of the last
+   * occurrence of a Texture will cause its removal internally.
+   *
+   * @param[in] textureId The ID of the Texture to remove.
+   * @param[in] textureObserver The texture observer.
+   */
+  void Remove( const TextureManager::TextureId textureId, TextureUploadObserver* textureObserver );
+
+  /**
+   * @brief Get the visualUrl associated with the texture id.
+   * @param[in] textureId The texture Id to get
+   * @return The visual Url associated with the texture id.
+   */
+  VisualUrl GetVisualUrl( TextureId textureId );
+
+  /**
+   * @brief Get the current state of a texture
+   * @param[in] textureId The texture id to query
+   * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+   * is not valid.
+   */
+  LoadState GetTextureState( TextureId textureId );
+
+  /**
+   * @brief Get the associated texture set if the texture id is valid
+   * @param[in] textureId The texture Id to look up
+   * @return the associated texture set, or an empty handle if textureId is not valid
+   */
+  TextureSet GetTextureSet( TextureId textureId );
+
+  /**
+   * Adds an external texture to the texture manager
+   * @param[in] texture The texture to add
+   * @return string containing the URL for the texture
+   */
+  std::string AddExternalTexture( TextureSet& texture );
+
+  /**
+   * Removes an external texture from texture manager
+   * @param[in] url The string containing the texture to remove
+   * @return handle to the texture
+   */
+  TextureSet RemoveExternalTexture( const std::string& url );
+
+  /**
+   * Add an observer to the object.
+   * @param[in] observer The observer to add.
+   */
+  void AddObserver( TextureManager::LifecycleObserver& observer );
+
+  /**
+   * Remove an observer from the object
+   * @pre The observer has already been added.
+   * @param[in] observer The observer to remove.
+   */
+  void RemoveObserver( TextureManager::LifecycleObserver& observer );
+
+  /**
+   * @brief Set an image to be used when a visual has failed to correctly render
+   * @param[in] brokenImageUrl The broken image url.
+   */
+  void SetBrokenImageUrl(const std::string& brokenImageUrl);
+
+private:
+
+  /**
+   * @brief Requests an image load of the given URL, when the texture has
+   * have loaded, if there is a valid maskTextureId, it will perform a
+   * CPU blend with the mask, and upload the blend texture.
+   *
+   * The parameters are used to specify how the image is loaded.
+   * The observer has the UploadComplete method called when the load is ready.
+   *
+   * When the client has finished with the Texture, Remove() should be called.
+   *
+   * @param[in] url                   The URL of the image to load
+   * @param[in] maskTextureId         The texture id of an image to use as a mask. If no mask is required, then set
+   *                                  to INVALID_TEXTURE_ID
+   * @param[in] contentScale          The scaling factor to apply to the content when masking
+   * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
+   * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be
+   *                                  loaded, and marked successful, but "useAtlasing" will be set to false in the
+   *                                  "UploadCompleted" callback from the TextureManagerUploadObserver.
+   * @param[in] cropToMask            Whether to crop the target after masking, or scale the mask to the image before
+   *                                  masking.
+   * @param[in] storageType,          Whether the pixel data is stored in the cache or uploaded to the GPU
+   * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
+   *                                  virtual.
+   *                                  This is called when an image load completes (or fails).
+   * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
+   * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
+   * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if
+   *                                  there is no alpha
+   * @return                          A TextureId to use as a handle to reference this Texture
+   */
+  TextureId RequestLoadInternal(
+    const VisualUrl&                    url,
+    TextureId                           maskTextureId,
+    float                               contentScale,
+    const ImageDimensions               desiredSize,
+    FittingMode::Type                   fittingMode,
+    Dali::SamplingMode::Type            samplingMode,
+    UseAtlas                            useAtlas,
+    bool                                cropToMask,
+    StorageType                         storageType,
+    TextureUploadObserver*              observer,
+    bool                                orientationCorrection,
+    TextureManager::ReloadPolicy        reloadPolicy,
+    MultiplyOnLoad&                     preMultiplyOnLoad,
+    bool                                loadPixelBuffer );
+
+  /**
+   * @brief Get the current state of a texture
+   * @param[in] textureId The texture id to query
+   * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+   * is not valid.
+   */
+  LoadState GetTextureStateInternal( TextureId textureId );
+
+  typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
+
+  // Structs:
+
+  /**
+   * @brief This struct is used to manage the life-cycle of Texture loading and caching.
+   */
+  struct TextureInfo
+  {
+    TextureInfo( TextureId textureId,
+                 TextureId maskTextureId,
+                 const VisualUrl& url,
+                 ImageDimensions desiredSize,
+                 float scaleFactor,
+                 FittingMode::Type fittingMode,
+                 Dali::SamplingMode::Type samplingMode,
+                 bool loadSynchronously,
+                 bool cropToMask,
+                 UseAtlas useAtlas,
+                 TextureManager::TextureHash hash,
+                 bool orientationCorrection,
+                 bool preMultiplyOnLoad,
+                 bool loadPixelBuffer )
+    : url( url ),
+      desiredSize( desiredSize ),
+      useSize( desiredSize ),
+      atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
+      textureId( textureId ),
+      maskTextureId( maskTextureId ),
+      hash( hash ),
+      scaleFactor( scaleFactor ),
+      referenceCount( 1u ),
+      loadState( NOT_STARTED ),
+      fittingMode( fittingMode ),
+      samplingMode( samplingMode ),
+      storageType( UPLOAD_TO_TEXTURE ),
+      loadSynchronously( loadSynchronously ),
+      useAtlas( useAtlas ),
+      cropToMask( cropToMask ),
+      orientationCorrection( true ),
+      preMultiplyOnLoad( preMultiplyOnLoad ),
+      preMultiplied( false ),
+      loadPixelBuffer( loadPixelBuffer )
+    {
+    }
+
+    /**
+     * Container type used to store all observer clients of this Texture
+     */
+    typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
+
+    ObserverListType observerList; ///< Container used to store all observer clients of this Texture
+    Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
+    Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
+    TextureSet textureSet;         ///< The TextureSet holding the Texture
+    VisualUrl url;                 ///< The URL of the image
+    ImageDimensions desiredSize;   ///< The size requested
+    ImageDimensions useSize;       ///< The size used
+    Vector4 atlasRect;             ///< The atlas rect used if atlased
+    TextureId textureId;           ///< The TextureId associated with this Texture
+    TextureId maskTextureId;       ///< The mask TextureId to be applied on load
+    TextureManager::TextureHash hash; ///< The hash used to cache this Texture
+    float scaleFactor;             ///< The scale factor to apply to the Texture when masking
+    int16_t referenceCount;        ///< The reference count of clients using this Texture
+    LoadState loadState:4;         ///< The load state showing the load progress of the Texture
+    FittingMode::Type fittingMode:2; ///< The requested FittingMode
+    Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
+    StorageType storageType:2;     ///< CPU storage / GPU upload;
+    bool loadSynchronously:1;      ///< True if synchronous loading was requested
+    UseAtlas useAtlas:2;           ///< USE_ATLAS if an atlas was requested.
+                                   ///< This is updated to false if atlas is not used
+    bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
+    bool orientationCorrection:1;  ///< true if the image should be rotated to match exif orientation data
+    bool preMultiplyOnLoad:1;      ///< true if the image's color should be multiplied by it's alpha
+    bool preMultiplied:1;          ///< true if the image's color was multiplied by it's alpha
+    bool loadPixelBuffer:1;        ///< true if the image is needed to be returned as PixelBuffer
+  };
+
+  /**
+   * Structure to hold info about a texture load queued during NotifyObservers
+   */
+  struct LoadQueueElement
+  {
+    LoadQueueElement( TextureId textureId, TextureUploadObserver* observer )
+    : mTextureId( textureId ),
+      mObserver( observer )
+    {
+    }
+
+    TextureId mTextureId; ///< The texture id of the requested load.
+    TextureUploadObserver* mObserver; ///< Observer of texture load.
+  };
+
+  /**
+   * Struct to hold information about a requested Async load.
+   * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
+   */
+  struct AsyncLoadingInfo
+  {
+    AsyncLoadingInfo( TextureId textureId )
+    : textureId( textureId ),
+      loadId( 0 )
+    {
+    }
+
+    TextureId           textureId;   ///< The external Texture Id assigned to this load
+    uint32_t            loadId;      ///< The load Id used by the async loader to reference this load
+  };
+
+  // Private typedefs:
+
+  typedef std::deque<AsyncLoadingInfo>  AsyncLoadingInfoContainerType;  ///< The container type used to manage Asynchronous loads in progress
+  typedef std::vector<TextureInfo>      TextureInfoContainerType;       ///< The container type used to manage the life-cycle and caching of Textures
+
+  /**
+   * @brief Initiate a load or queue load if NotifyObservers is invoking callbacks
+   * @param[in] textureInfo The TextureInfo struct associated with the Texture
+   * @param[in] observer The observer wishing to observe the texture upload
+   */
+  void LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
+
+  /**
+   * @brief Queue a texture load to be subsequently handled by ProcessQueuedTextures.
+   * @param[in] textureInfo The TextureInfo struct associated with the Texture
+   * @param[in] observer The observer wishing to observe the texture upload
+   */
+  void QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
+
+  /**
+   * @brief Used internally to initiate a load.
+   * @param[in] textureInfo The TextureInfo struct associated with the Texture
+   * @param[in] observer The observer wishing to observe the texture upload
+   */
+  void LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
+
+  /**
+   * @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
+   */
+  void ProcessQueuedTextures();
+
+  /**
+   * Add the observer to the observer list
+   * @param[in] textureInfo The TextureInfo struct associated with the texture
+   * @param[in] observer The observer wishing to observe the texture upload
+   */
+  void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
+
+  /**
+   * @brief This signal handler is called when the async local loader finishes loading.
+   * @param[in] id        This is the async image loaders Id
+   * @param[in] pixelBuffer The loaded image data
+   */
+  void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
+
+  /**
+   * @brief This signal handler is called when the async local loader finishes loading.
+   * @param[in] id        This is the async image loaders Id
+   * @param[in] pixelBuffer The loaded image data
+   */
+  void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
+
+  /**
+   * Common method to handle loading completion
+   * @param[in] container The Async loading container
+   * @param[in] id        This is the async image loaders Id
+   * @param[in] pixelBuffer The loaded image data
+   */
+  void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
+
+  /**
+   * @brief Performs Post-Load steps including atlasing.
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] pixelBuffer The image pixelBuffer
+   * @return    True if successful
+   */
+  void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
+
+  /**
+   * Check if there is a texture waiting to be masked. If there
+   * is then apply this mask and upload it.
+   * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
+   */
+  void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
+
+  /**
+   * Apply the mask to the pixelBuffer.
+   * @param[in] textureInfo The information of texture to apply the mask to
+   * @param[in] maskTextureId The texture id of the mask.
+   */
+  void ApplyMask( TextureInfo& textureInfo, TextureId maskTextureId );
+
+  /**
+   * Upload the texture specified in pixelBuffer to the appropriate location
+   * @param[in] pixelBuffer The image data to upload
+   * @param[in] textureInfo The texture info containing the location to
+   * store the data to.
+   */
+  void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
+
+  /**
+   * Mark the texture as complete, and inform observers
+   * @param[in] textureInfo The struct associated with this Texture
+   */
+  void UploadComplete( TextureInfo& textureInfo );
+
+  /**
+   * Notify the current observers that the texture upload is complete,
+   * then remove the observers from the list.
+   * @param[in] textureInfo The struct associated with this Texture
+   * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
+   */
+  void NotifyObservers( TextureInfo& textureInfo, bool success );
+
+  /**
+   * @brief Generates a new, unique TextureId
+   * @return A unique TextureId
+   */
+  TextureManager::TextureId GenerateUniqueTextureId();
+
+  /**
+   * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
+   * @param[in] textureId The TextureId to look up
+   * @return              The cache index
+   */
+  int GetCacheIndexFromId( TextureId textureId );
+
+
+  /**
+   * @brief Generates a hash for caching based on the input parameters.
+   * Only applies size, fitting mode andsampling mode if the size is specified.
+   * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
+   * Always applies useAtlas.
+   * @param[in] url          The URL of the image to load
+   * @param[in] size         The image size
+   * @param[in] fittingMode  The FittingMode to use
+   * @param[in] samplingMode The SamplingMode to use
+   * @param[in] useAtlas     True if atlased
+   * @param[in] maskTextureId The masking texture id (or INVALID_TEXTURE_ID)
+   * @return                 A hash of the provided data for caching.
+   */
+  TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
+                            const FittingMode::Type fittingMode,
+                            const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
+                            TextureId maskTextureId );
+
+  /**
+   * @brief Looks up a cached texture by its hash.
+   * If found, the given parameters are used to check there is no hash-collision.
+   * @param[in] hash          The hash to look up
+   * @param[in] url           The URL of the image to load
+   * @param[in] size          The image size
+   * @param[in] fittingMode   The FittingMode to use
+   * @param[in] samplingMode  The SamplingMode to use
+   * @param[in] useAtlas      True if atlased
+   * @param[in] maskTextureId Optional texture ID to use to mask this image
+   * @return A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
+   */
+  TextureManager::TextureId FindCachedTexture(
+    const TextureManager::TextureHash hash,
+    const std::string& url,
+    const ImageDimensions size,
+    const FittingMode::Type fittingMode,
+    const Dali::SamplingMode::Type samplingMode,
+    const bool useAtlas,
+    TextureId maskTextureId,
+    MultiplyOnLoad preMultiplyOnLoad);
+
+private:
+
+  /**
+   * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
+   */
+  class AsyncLoadingHelper : public ConnectionTracker
+  {
+  public:
+    /**
+     * @brief Create an AsyncLoadingHelper.
+     * @param[in] textureManager Reference to the texture manager
+     */
+    AsyncLoadingHelper(TextureManager& textureManager);
+
+    /**
+     * @brief Load a new texture.
+     * @param[in] textureId             TextureId to reference the texture that will be loaded
+     * @param[in] url                   The URL of the image to load
+     * @param[in] desiredSize           The size the image is likely to appear at.
+     *                                  This can be set to 0,0 for automatic
+     * @param[in] fittingMode           The FittingMode to use
+     * @param[in] samplingMode          The SamplingMode to use
+     * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
+     *                                  e.g., from portrait to landscape
+     * @param[in] preMultiplyOnLoad     if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+     */
+    void Load(TextureId textureId,
+              const VisualUrl& url,
+              ImageDimensions desiredSize,
+              FittingMode::Type fittingMode,
+              SamplingMode::Type samplingMode,
+              bool orientationCorrection,
+              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+
+    /**
+     * @brief Apply mask
+     * @param [in] id of the texture
+     * @param [in] pixelBuffer of the to be masked image
+     * @param [in] maskPixelBuffer of the mask image
+     * @param [in] contentScale The factor to scale the content
+     * @param [in] cropToMask Whether to crop the content to the mask size
+     * @param [in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
+     */
+    void ApplyMask( TextureId textureId,
+                    Devel::PixelBuffer pixelBuffer,
+                    Devel::PixelBuffer maskPixelBuffer,
+                    float contentScale,
+                    bool cropToMask,
+                    DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
+
+  public:
+    AsyncLoadingHelper(const AsyncLoadingHelper&) = delete;
+    AsyncLoadingHelper& operator=(const AsyncLoadingHelper&) = delete;
+
+    AsyncLoadingHelper(AsyncLoadingHelper&& rhs);
+    AsyncLoadingHelper& operator=(AsyncLoadingHelper&&rhs) = delete;
+
+  private:
+    /**
+     * @brief Main constructor that used by all other constructors
+     */
+    AsyncLoadingHelper( Toolkit::AsyncImageLoader loader,
+                        TextureManager& textureManager,
+                        AsyncLoadingInfoContainerType&& loadingInfoContainer );
+
+    /**
+     * @brief Callback to be called when texture loading is complete, it passes the pixel buffer on to texture manager.
+     * @param[in] id          Loader id
+     * @param[in] pixelBuffer Image data
+     */
+    void AsyncLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
+
+  private:
+    Toolkit::AsyncImageLoader     mLoader;
+    TextureManager&               mTextureManager;
+    AsyncLoadingInfoContainerType mLoadingInfoContainer;
+  };
+
+  struct ExternalTextureInfo
+  {
+    TextureId textureId;
+    TextureSet textureSet;
+  };
+
+private:
+
+  /**
+   * Deleted copy constructor.
+   */
+  TextureManager( const TextureManager& ) = delete;
+
+  /**
+   * Deleted assignment operator.
+   */
+  TextureManager& operator=( const TextureManager& rhs ) = delete;
+
+  /**
+   * This is called by the TextureManagerUploadObserver when an observer is destroyed.
+   * We use the callback to know when to remove an observer from our notify list.
+   * @param[in] observer The observer that generated the callback
+   */
+  void ObserverDestroyed( TextureUploadObserver* observer );
+
+private:  // Member Variables:
+
+  TextureInfoContainerType                      mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
+  RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders;    ///< The Asynchronous image loaders used to provide all local async loads
+  RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders;   ///< The Asynchronous image loaders used to provide all remote async loads
+  std::vector< ExternalTextureInfo >            mExternalTextures;     ///< Externally provided textures
+  Dali::Vector<LifecycleObserver*>              mLifecycleObservers;   ///< Lifecycle observers of texture manager
+  Dali::Vector<LoadQueueElement>                mLoadQueue;            ///< Queue of textures to load after NotifyObservers
+  std::string                                   mBrokenImageUrl;       ///< Broken image url
+  TextureId                                     mCurrentTextureId;     ///< The current value used for the unique Texture Id generation
+  bool                                          mQueueLoadFlag;        ///< Flag that causes Load Textures to be queued.
+};
+
+
+} // name Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
diff --git a/dali-toolkit/internal/visuals/texture-upload-observer.cpp b/dali-toolkit/internal/visuals/texture-upload-observer.cpp
new file mode 100644 (file)
index 0000000..8ffd35f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 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 "texture-upload-observer.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextureUploadObserver::TextureUploadObserver()
+{
+}
+
+TextureUploadObserver::~TextureUploadObserver()
+{
+  if( !mDestructionSignal.Empty() )
+  {
+    mDestructionSignal.Emit( this );
+  }
+}
+
+TextureUploadObserver::DestructionSignalType& TextureUploadObserver::DestructionSignal()
+{
+  return mDestructionSignal;
+}
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/texture-upload-observer.h b/dali-toolkit/internal/visuals/texture-upload-observer.h
new file mode 100644 (file)
index 0000000..b00722c
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
+#define DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
+
+/*
+ * Copyright (c) 2020 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 <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+
+class TextureSet;
+
+namespace Toolkit
+{
+
+
+/**
+ * @brief Base class used to observe the upload status of a texture.
+ *
+ * Derived class must implement the UploadComplete method which is
+ * executed once the texture is ready to draw.
+ */
+class TextureUploadObserver
+{
+public:
+
+  typedef Signal< void ( TextureUploadObserver* ) > DestructionSignalType; ///< Signal prototype for the Destruction Signal.
+
+  /**
+   * @brief Constructor.
+   */
+  TextureUploadObserver();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~TextureUploadObserver();
+
+  /**
+   * The action to be taken once the async load has finished and the upload to GPU is completed.
+   * This should be overridden by the deriving class.
+   *
+   * @param[in] loadSuccess True if the texture load was successful (i.e. the resource is available). If false, then the resource failed to load. In future, this will automatically upload a "broken" image.
+   * @param[in] textureId   The textureId of the loaded texture in the TextureManager
+   * @param[in] textureSet  The TextureSet containing the Texture
+   * @param[in] useAtlasing True if atlasing was used (note: this may be different to what was requested)
+   * @param[in] atlasRect   If using atlasing, this is the rectangle within the atlas to use.
+   * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
+   */
+  virtual void UploadComplete( bool loadSuccess, int32_t textureId, TextureSet textureSet, bool useAtlasing,
+                               const Vector4& atlasRect, bool preMultiplied ) = 0;
+
+  /**
+   * The action to be taken once the async load has finished.
+   * This should be overridden by the deriving class.
+   *
+   * @param[in] loadSuccess   True if the image load was successful (i.e. the resource is available). If false, then the resource failed to load.
+   * @param[in] pixelBuffer   The PixelBuffer of the loaded image.
+   * @param[in] url           The url address of the loaded image.
+   * @param[in] preMultiplied True if the image had pre-multiplied alpha applied
+   */
+  virtual void LoadComplete( bool loadSuccess, Devel::PixelBuffer pixelBuffer, const Internal::VisualUrl& url, bool preMultiplied ) = 0;
+
+  /**
+   * @brief Returns the destruction signal.
+   * This is emitted when the observer is destroyed.
+   * This is used by the observer notifier to mark this observer as destroyed (IE. It no longer needs notifying).
+   */
+  DestructionSignalType& DestructionSignal();
+
+private:
+
+  DestructionSignalType mDestructionSignal; ///< The destruction signal emitted when the observer is destroyed.
+
+};
+
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_TEXTURE_UPLOAD_OBSERVER_H
diff --git a/dali-toolkit/internal/visuals/transition-data-impl.cpp b/dali-toolkit/internal/visuals/transition-data-impl.cpp
new file mode 100644 (file)
index 0000000..a91b8ab
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/visuals/transition-data-impl.h>
+
+// EXTERNAL HEADERS
+#include <dali/dali.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <sstream>
+
+using namespace Dali;
+
+namespace
+{
+const char* TOKEN_TARGET("target");
+const char* TOKEN_PROPERTY("property");
+const char* TOKEN_INITIAL_VALUE("initialValue");
+const char* TOKEN_TARGET_VALUE("targetValue");
+const char* TOKEN_ANIMATOR("animator");
+const char* TOKEN_TIME_PERIOD("timePeriod");
+const char* TOKEN_DURATION("duration");
+const char* TOKEN_DELAY("delay");
+const char* TOKEN_ALPHA_FUNCTION("alphaFunction");
+
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( ALPHA_FUNCTION_BUILTIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, LINEAR)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, REVERSE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_IN)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_OUT)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_IN_OUT)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_IN_SQUARE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_OUT_SQUARE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_IN_SINE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_OUT_SINE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_IN_OUT_SINE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, EASE_OUT_BACK)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, BOUNCE)
+DALI_ENUM_TO_STRING_WITH_SCOPE(AlphaFunction, SIN)
+DALI_ENUM_TO_STRING_TABLE_END( ALPHA_FUNCTION_BUILTIN )
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+TransitionData::TransitionData()
+{
+}
+
+TransitionData::~TransitionData()
+{
+}
+
+TransitionDataPtr TransitionData::New( const Property::Array& value )
+{
+  TransitionDataPtr transitionData( new TransitionData() );
+  transitionData->Initialize(value);
+  return transitionData;
+}
+
+TransitionDataPtr TransitionData::New( const Property::Map& value )
+{
+  TransitionDataPtr transitionData( new TransitionData() );
+  transitionData->Initialize(value);
+  return transitionData;
+}
+
+
+void TransitionData::Initialize( const Property::Map& map )
+{
+  TransitionData::Animator* animator = ConvertMap( map );
+  Add( animator );
+}
+
+void TransitionData::Initialize( const Property::Array& array )
+{
+  for( unsigned int arrayIdx = 0, transitionArrayCount = array.Count(); arrayIdx < transitionArrayCount; ++arrayIdx )
+  {
+    const Property::Value& element = array.GetElementAt( arrayIdx );
+    // Expect each child to be an object representing an animator:
+
+    Property::Map* map = element.GetMap();
+    if( map != NULL )
+    {
+      TransitionData::Animator* animator = ConvertMap( *map );
+      Add( animator );
+    }
+  }
+}
+
+TransitionData::Animator* TransitionData::ConvertMap( const Property::Map& map)
+{
+  TransitionData::Animator* animator = new TransitionData::Animator();
+  animator->alphaFunction = AlphaFunction::LINEAR;
+  animator->timePeriodDelay = 0.0f;
+  animator->timePeriodDuration = 1.0f;
+
+  for( unsigned int mapIdx = 0; mapIdx < map.Count(); ++mapIdx )
+  {
+    const KeyValuePair pair( map.GetKeyValue( mapIdx ) );
+    if( pair.first.type == Property::Key::INDEX )
+    {
+      continue; // We don't consider index keys.
+    }
+
+    const std::string& key( pair.first.stringKey );
+    const Property::Value& value( pair.second );
+
+    if( key == TOKEN_TARGET )
+    {
+      animator->objectName = value.Get< std::string >();
+    }
+    else if( key == TOKEN_PROPERTY )
+    {
+      if( value.GetType() == Property::STRING )
+      {
+        animator->propertyKey = Property::Key( value.Get<std::string>() );
+      }
+      else
+      {
+        animator->propertyKey = Property::Key( value.Get<int>() );
+      }
+    }
+    else if( key == TOKEN_INITIAL_VALUE )
+    {
+      animator->initialValue = value;
+    }
+    else if( key == TOKEN_TARGET_VALUE )
+    {
+      animator->targetValue = value;
+    }
+    else if( key == TOKEN_ANIMATOR )
+    {
+      animator->animate = true;
+      Property::Map animatorMap = value.Get< Property::Map >();
+      for( size_t animatorMapIdx = 0; animatorMapIdx < animatorMap.Count(); ++animatorMapIdx )
+      {
+        const KeyValuePair pair( animatorMap.GetKeyValue( animatorMapIdx ) );
+
+        if( pair.first.type == Property::Key::INDEX )
+        {
+          continue; // We don't consider index keys.
+        }
+
+        const std::string& key( pair.first.stringKey );
+        const Property::Value& value( pair.second );
+
+        if( key == TOKEN_ALPHA_FUNCTION )
+        {
+          if( value.GetType() == Property::ARRAY )
+          {
+            bool valid = true;
+            Vector4 controlPoints;
+            Property::Array *array = value.GetArray();
+            if( array && array->Count() >= 4 )
+            {
+              for( size_t vecIdx = 0; vecIdx < 4; ++vecIdx )
+              {
+                Property::Value& v = array->GetElementAt(vecIdx);
+                if( v.GetType() == Property::FLOAT )
+                {
+                  controlPoints[vecIdx] = v.Get<float>();
+                }
+                else
+                {
+                  valid = false;
+                  break;
+                }
+              }
+            }
+            else
+            {
+              valid = false;
+            }
+
+            if( valid )
+            {
+              Vector2 controlPoint1( controlPoints.x, controlPoints.y );
+              Vector2 controlPoint2( controlPoints.z, controlPoints.w );
+              animator->alphaFunction = AlphaFunction( controlPoint1, controlPoint2 );
+            }
+            else
+            {
+              animator->animate = false;
+            }
+          }
+          else if( value.GetType() == Property::VECTOR4 )
+          {
+            Vector4 controlPoints = value.Get<Vector4>();
+            Vector2 controlPoint1( controlPoints.x, controlPoints.y );
+            Vector2 controlPoint2( controlPoints.z, controlPoints.w );
+            animator->alphaFunction = AlphaFunction( controlPoint1, controlPoint2 );
+          }
+          else if( value.GetType() == Property::STRING )
+          {
+            std::string alphaFunctionValue = value.Get< std::string >();
+
+            if( alphaFunctionValue == "LINEAR" )
+            {
+              animator->alphaFunction = AlphaFunction(AlphaFunction::LINEAR);
+            }
+            else if( ! alphaFunctionValue.compare(0, 5, "EASE_" ) )
+            {
+              if( alphaFunctionValue == "EASE_IN" )
+              {
+                animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_IN);
+              }
+              else if( alphaFunctionValue == "EASE_OUT" )
+              {
+                animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_OUT);
+              }
+              else if( ! alphaFunctionValue.compare( 5, 3, "IN_" ) )
+              {
+                if( ! alphaFunctionValue.compare(8, -1, "SQUARE" ))
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_IN_SQUARE);
+                }
+                else if( ! alphaFunctionValue.compare(8, -1, "OUT" ))
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_IN_OUT);
+                }
+                else if( ! alphaFunctionValue.compare(8, -1, "OUT_SINE" ))
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_IN_OUT_SINE);
+                }
+                else if( ! alphaFunctionValue.compare(8, -1, "SINE" ))
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_IN_SINE);
+                }
+              }
+              else if( ! alphaFunctionValue.compare( 5, 4, "OUT_" ) )
+              {
+                if( ! alphaFunctionValue.compare(9, -1, "SQUARE" ) )
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_OUT_SQUARE);
+                }
+                else if( ! alphaFunctionValue.compare(9, -1, "SINE" ) )
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_OUT_SINE);
+                }
+                else if( ! alphaFunctionValue.compare(9, -1, "BACK" ) )
+                {
+                  animator->alphaFunction = AlphaFunction(AlphaFunction::EASE_OUT_BACK);
+                }
+              }
+            }
+            else if( alphaFunctionValue == "REVERSE" )
+            {
+              animator->alphaFunction = AlphaFunction(AlphaFunction::REVERSE);
+            }
+            else if( alphaFunctionValue == "BOUNCE" )
+            {
+              animator->alphaFunction = AlphaFunction(AlphaFunction::BOUNCE);
+            }
+            else if( alphaFunctionValue == "SIN" )
+            {
+              animator->alphaFunction = AlphaFunction(AlphaFunction::SIN);
+            }
+          }
+          else
+          {
+            animator->animate = false;
+          }
+        }
+        else if( key == TOKEN_TIME_PERIOD )
+        {
+          Property::Map timeMap = value.Get< Property::Map >();
+          for( size_t timeMapIdx = 0; timeMapIdx < timeMap.Count(); ++timeMapIdx )
+          {
+            const KeyValuePair pair( timeMap.GetKeyValue( timeMapIdx ) );
+            if( pair.first.type == Property::Key::INDEX )
+            {
+              continue;
+            }
+            const std::string& key( pair.first.stringKey );
+
+            if( key == TOKEN_DELAY )
+            {
+              animator->timePeriodDelay = pair.second.Get< float >();
+            }
+            else if( key == TOKEN_DURATION )
+            {
+              animator->timePeriodDuration = pair.second.Get< float >();
+            }
+          }
+        }
+      }
+    }
+  }
+  return animator;
+}
+
+void TransitionData::Add( Animator* animator )
+{
+  mAnimators.PushBack( animator );
+}
+
+TransitionData::Iterator TransitionData::Begin() const
+{
+  return mAnimators.Begin();
+}
+
+TransitionData::Iterator TransitionData::End() const
+{
+  return mAnimators.End();
+}
+
+size_t TransitionData::Count() const
+{
+  return mAnimators.Count();
+}
+
+Property::Map TransitionData::GetAnimatorAt( size_t index )
+{
+  DALI_ASSERT_ALWAYS( index < Count() && "index exceeds bounds" );
+
+  Animator* animator = mAnimators[index];
+  Property::Map map;
+  map[TOKEN_TARGET] = animator->objectName;
+  if( animator->propertyKey.type == Property::Key::INDEX )
+  {
+    map[TOKEN_PROPERTY] = animator->propertyKey.indexKey;
+  }
+  else
+  {
+    map[TOKEN_PROPERTY] = animator->propertyKey.stringKey;
+  }
+  if( animator->initialValue.GetType() != Property::NONE )
+  {
+    map[TOKEN_INITIAL_VALUE] = animator->initialValue;
+  }
+  if( animator->targetValue.GetType() != Property::NONE )
+  {
+    map[TOKEN_TARGET_VALUE] = animator->targetValue;
+  }
+  if( animator->animate )
+  {
+    Property::Map animateMap;
+
+    if( animator->alphaFunction.GetMode() == AlphaFunction::BUILTIN_FUNCTION )
+    {
+      animateMap.Add(TOKEN_ALPHA_FUNCTION, GetEnumerationName( animator->alphaFunction.GetBuiltinFunction(),
+                                                               ALPHA_FUNCTION_BUILTIN_TABLE,
+                                                               ALPHA_FUNCTION_BUILTIN_TABLE_COUNT ));
+    }
+    else if( animator->alphaFunction.GetMode() == AlphaFunction::BEZIER )
+    {
+      Vector4 controlPoints = animator->alphaFunction.GetBezierControlPoints();
+      animateMap.Add( TOKEN_ALPHA_FUNCTION, controlPoints );
+    }
+    animateMap.Add(TOKEN_TIME_PERIOD, Property::Map()
+                   .Add( TOKEN_DELAY, animator->timePeriodDelay )
+                   .Add( TOKEN_DURATION, animator->timePeriodDuration ));
+
+    map[TOKEN_ANIMATOR] = animateMap;
+  }
+
+  return map;
+}
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/transition-data-impl.h b/dali-toolkit/internal/visuals/transition-data-impl.h
new file mode 100644 (file)
index 0000000..9ca8193
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_TOOLKIT_INTERNAL_TRANSITION_DATA_H
+#define DALI_TOOLKIT_INTERNAL_TRANSITION_DATA_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.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/object/property-key.h>
+#include <dali/devel-api/common/owner-container.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/transition-data.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+class TransitionData;
+typedef IntrusivePtr<TransitionData> TransitionDataPtr;
+
+/**
+ * TransitionData is an object that holds animator data.
+ */
+class TransitionData : public BaseObject
+{
+public:
+
+  /**
+   * @brief TransitionDataElement Describes one animator of an transition.
+   */
+  struct Animator
+  {
+    Animator()
+    : propertyKey( Property::INVALID_INDEX ),
+      alphaFunction( AlphaFunction::DEFAULT ),
+      timePeriodDelay( 0.0f ),
+      timePeriodDuration( 1.0f ),
+      animate(false)
+    {
+    }
+
+    std::string objectName;   ///< An identifier of the actor or visual
+    Property::Key propertyKey; ///< A property key of the property owner
+    Property::Value initialValue; ///< The value to set at the start of the transition
+    Property::Value targetValue;   ///< The value to set or animate to
+    Dali::AlphaFunction alphaFunction;
+    float timePeriodDelay;
+    float timePeriodDuration;
+    bool animate;
+  };
+
+  /**
+   * @brief TransitionData holds the required data required to define an
+   * transition to be performed on a property owner
+   */
+  typedef Dali::OwnerContainer< Animator* > AnimatorList;
+  typedef AnimatorList::Iterator Iterator;
+
+public:
+  /**
+   * @copydoc Dali::Transition::New()
+   */
+  static TransitionDataPtr New( const Property::Array& value );
+
+  /**
+   * @copydoc Dali::Transition::New()
+   */
+  static TransitionDataPtr New( const Property::Map& value );
+
+  /**
+   * @brief Iterator to the beginning of the data
+   */
+  Iterator Begin() const;
+
+  /**
+   * @brief Iterator to the end of the data (one past last element)
+   */
+  Iterator End() const;
+
+  /**
+   * @copydoc Dali::Transition::Count()
+   */
+  size_t Count() const;
+
+  /**
+   * @copydoc Dali::Transition::GetAnimatorAt()
+   */
+  Property::Map GetAnimatorAt( size_t index );
+
+private: // Implementation
+  /**
+   * Ref counted object - Only allow construction via New().
+   */
+  TransitionData();
+
+  /**
+   * Second stage initialiazation
+   */
+  void Initialize( const Property::Map& value );
+
+  /**
+   * Second stage initialiazation
+   */
+  void Initialize( const Property::Array& value );
+
+  /**
+   * @brief Adds one Animator to the list to describe a transition.
+   * @param[in] animator An animator data structure
+   */
+  void Add( Animator* animator );
+
+  /**
+   * Convert a Property map into Animator data
+   */
+  Animator* ConvertMap( const Property::Map& map );
+
+protected:
+  /**
+   *  A ref counted object may only be deleted by calling Unreference
+   */
+  virtual ~TransitionData();
+
+private: // Unimplemented methods
+  TransitionData( const TransitionData& );
+  TransitionData& operator=( const TransitionData& );
+
+private: // Data members
+  AnimatorList mAnimators; ///< A vector of individual property transitions from which to generate a Dali::Animation.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+inline Internal::TransitionData& GetImplementation( Dali::Toolkit::TransitionData& handle )
+{
+  DALI_ASSERT_ALWAYS(handle && "TransitionData handle is empty");
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::TransitionData&>(object);
+}
+
+inline const Internal::TransitionData& GetImplementation( const Dali::Toolkit::TransitionData& handle )
+{
+  DALI_ASSERT_ALWAYS(handle && "TransitionData handle is empty");
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::TransitionData&>(object);
+}
+
+} // namespace Toolkit
+} // namespace Dali
+
+
+#endif // DALI_TOOLKIT_INTERNAL_TRANSITION_DATA_H
diff --git a/dali-toolkit/internal/visuals/visual-base-data-impl.cpp b/dali-toolkit/internal/visuals/visual-base-data-impl.cpp
new file mode 100644 (file)
index 0000000..4bb7634
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2018 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 <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/helpers/property-helper.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( SHADER_HINT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Shader::Hint, NONE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Shader::Hint, OUTPUT_IS_TRANSPARENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Shader::Hint, MODIFIES_GEOMETRY )
+DALI_ENUM_TO_STRING_TABLE_END( SHADER_HINT )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( ALIGN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, TOP_BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, TOP_CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, TOP_END )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, CENTER_BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, CENTER_END )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, BOTTOM_BEGIN )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, BOTTOM_CENTER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Align, BOTTOM_END )
+DALI_ENUM_TO_STRING_TABLE_END( ALIGN )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( POLICY )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual::Transform::Policy, RELATIVE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual::Transform::Policy, ABSOLUTE )
+DALI_ENUM_TO_STRING_TABLE_END( POLICY )
+
+Dali::Vector2 PointToVector2( Toolkit::Align::Type point, Toolkit::Direction::Type direction )
+{
+  static const float pointToVector2[] = { 0.0f,0.0f,
+                                          0.5f,0.0f,
+                                          1.0f,0.0f,
+                                          0.0f,0.5f,
+                                          0.5f,0.5f,
+                                          1.0f,0.5f,
+                                          0.0f,1.0f,
+                                          0.5f,1.0f,
+                                          1.0f,1.0f };
+
+  Vector2 result( &pointToVector2[point*2] );
+  if( direction == Direction::RIGHT_TO_LEFT )
+  {
+    result.x = 1.0f - result.x;
+  }
+
+  return result;
+}
+
+bool GetPolicyFromValue( const Property::Value& value, Vector2& policy )
+{
+  bool success = false;
+  if( value.Get( policy ) )
+  {
+    success = true;
+  }
+  else
+  {
+    Property::Array* array = value.GetArray();
+    if( array && array->Size() == 2 )
+    {
+      Toolkit::Visual::Transform::Policy::Type xPolicy = static_cast< Toolkit::Visual::Transform::Policy::Type >( -1 ); // Assign an invalid value so definitely changes
+      Toolkit::Visual::Transform::Policy::Type yPolicy = static_cast< Toolkit::Visual::Transform::Policy::Type >( -1 ); // Assign an invalid value so definitely changes
+
+      if( Scripting::GetEnumerationProperty< Toolkit::Visual::Transform::Policy::Type >( array->GetElementAt( 0 ), POLICY_TABLE, POLICY_TABLE_COUNT, xPolicy ) &&
+          Scripting::GetEnumerationProperty< Toolkit::Visual::Transform::Policy::Type >( array->GetElementAt( 1 ), POLICY_TABLE, POLICY_TABLE_COUNT, yPolicy ) )
+      {
+        policy.x = xPolicy;
+        policy.y = yPolicy;
+        success = true;
+      }
+    }
+  }
+  return success;
+}
+
+} // unnamed namespace
+
+Internal::Visual::Base::Impl::Impl(FittingMode fittingMode)
+: mCustomShader( NULL ),
+  mBlendSlotDelegate( NULL ),
+  mEventObserver( NULL ),
+  mTransform(),
+  mMixColor( Color::WHITE ),
+  mControlSize( Vector2::ZERO ),
+  mCornerRadius( 0.0f ),
+  mDepthIndex( 0.0f ),
+  mMixColorIndex( Property::INVALID_INDEX ),
+  mCornerRadiusIndex( Property::INVALID_INDEX ),
+  mFittingMode( fittingMode ),
+  mFlags( 0 ),
+  mResourceStatus( Toolkit::Visual::ResourceStatus::PREPARING )
+{
+}
+
+Internal::Visual::Base::Impl::~Impl()
+{
+  delete mCustomShader;
+  delete mBlendSlotDelegate;
+}
+
+Internal::Visual::Base::Impl::CustomShader::CustomShader( const Property::Map& map )
+: mGridSize( 1, 1 ),
+  mHints( Shader::Hint::NONE )
+{
+  SetPropertyMap( map );
+}
+
+void Internal::Visual::Base::Impl::CustomShader::SetPropertyMap( const Property::Map& shaderMap )
+{
+  mVertexShader.clear();
+  mFragmentShader.clear();
+  mGridSize = ImageDimensions( 1, 1 );
+  mHints = Shader::Hint::NONE;
+
+  Property::Value* vertexShaderValue = shaderMap.Find( Toolkit::Visual::Shader::Property::VERTEX_SHADER, CUSTOM_VERTEX_SHADER );
+  if( vertexShaderValue )
+  {
+    if( ! GetStringFromProperty( *vertexShaderValue, mVertexShader ) )
+    {
+      DALI_LOG_ERROR( "'%s' parameter does not correctly specify a string\n", CUSTOM_VERTEX_SHADER );
+    }
+  }
+
+  Property::Value* fragmentShaderValue = shaderMap.Find( Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, CUSTOM_FRAGMENT_SHADER );
+  if( fragmentShaderValue )
+  {
+    if( ! GetStringFromProperty( *fragmentShaderValue, mFragmentShader ) )
+    {
+      DALI_LOG_ERROR( "'%s' parameter does not correctly specify a string\n", CUSTOM_FRAGMENT_SHADER );
+    }
+  }
+
+  Property::Value* subdivideXValue = shaderMap.Find( Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X, CUSTOM_SUBDIVIDE_GRID_X );
+  if( subdivideXValue )
+  {
+    int subdivideX;
+    if( !subdivideXValue->Get( subdivideX ) || subdivideX < 1 )
+    {
+      DALI_LOG_ERROR( "'%s' parameter does not correctly specify a value greater than 1\n", CUSTOM_SUBDIVIDE_GRID_X );
+    }
+    else
+    {
+      mGridSize = ImageDimensions( subdivideX, mGridSize.GetY() );
+    }
+  }
+
+  Property::Value* subdivideYValue = shaderMap.Find( Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y, CUSTOM_SUBDIVIDE_GRID_Y );
+  if( subdivideYValue )
+  {
+    int subdivideY;
+    if( !subdivideYValue->Get( subdivideY ) || subdivideY < 1 )
+    {
+      DALI_LOG_ERROR( "'%s' parameter does not correctly specify a value greater than 1\n", CUSTOM_SUBDIVIDE_GRID_Y );
+    }
+    else
+    {
+      mGridSize = ImageDimensions( mGridSize.GetX(), subdivideY );
+    }
+  }
+
+  Property::Value* hintsValue = shaderMap.Find( Toolkit::Visual::Shader::Property::HINTS, CUSTOM_SHADER_HINTS );
+  if( hintsValue )
+  {
+    if ( ! Scripting::GetBitmaskEnumerationProperty( *hintsValue, SHADER_HINT_TABLE, SHADER_HINT_TABLE_COUNT, mHints ) )
+    {
+      DALI_LOG_ERROR( "'%s' parameter does not correctly specify a hint or an array of hint strings\n", CUSTOM_SHADER_HINTS );
+    }
+  }
+}
+
+void Internal::Visual::Base::Impl::CustomShader::CreatePropertyMap( Property::Map& map ) const
+{
+  if( !mVertexShader.empty() || !mFragmentShader.empty() )
+  {
+    Property::Map customShader;
+    if( !mVertexShader.empty() )
+    {
+      customShader.Insert( Toolkit::Visual::Shader::Property::VERTEX_SHADER, mVertexShader );
+    }
+    if( !mFragmentShader.empty() )
+    {
+      customShader.Insert( Toolkit::Visual::Shader::Property::FRAGMENT_SHADER, mFragmentShader );
+    }
+
+    if( mGridSize.GetWidth() != 1 )
+    {
+      customShader.Insert( Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X, mGridSize.GetWidth() );
+    }
+    if( mGridSize.GetHeight() != 1 )
+    {
+      customShader.Insert( Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y, mGridSize.GetHeight() );
+    }
+
+    if( mHints != Dali::Shader::Hint::NONE )
+    {
+      customShader.Insert( Toolkit::Visual::Shader::Property::HINTS, static_cast< int >( mHints ) );
+    }
+
+    map.Insert( Toolkit::Visual::Property::SHADER, customShader );
+  }
+}
+
+Internal::Visual::Base::Impl::Transform::Transform()
+: mOffset( 0.0f,0.0f ),
+  mSize( 1.0f,1.0f ),
+  mExtraSize( 0.0f,0.0f ),
+  mOffsetSizeMode( 0.0f,0.0f,0.0f,0.0f ),
+  mOrigin( Toolkit::Align::TOP_BEGIN ),
+  mAnchorPoint( Toolkit::Align::TOP_BEGIN )
+{
+}
+
+void Internal::Visual::Base::Impl::Transform::SetPropertyMap( const Property::Map& map )
+{
+  // Set default values
+  mOffset = Vector2( 0.0f,0.0f );
+  mSize = Vector2( 1.0f,1.0f );
+  mExtraSize = Vector2( 0.0f,0.0f );
+  mOffsetSizeMode = Vector4( 0.0f,0.0f,0.0f,0.0f );
+  mOrigin = Toolkit::Align::TOP_BEGIN;
+  mAnchorPoint = Toolkit::Align::TOP_BEGIN;
+
+  UpdatePropertyMap( map );
+}
+
+void Internal::Visual::Base::Impl::Transform::UpdatePropertyMap( const Property::Map& map )
+{
+  for( Property::Map::SizeType i(0); i<map.Count(); ++i )
+  {
+    KeyValuePair keyValue = map.GetKeyValue( i );
+    if( keyValue.first.type == Property::Key::INDEX )
+    {
+      switch( keyValue.first.indexKey )
+      {
+        case Toolkit::Visual::Transform::Property::OFFSET:
+        {
+          keyValue.second.Get( mOffset );
+          break;
+        }
+        case Toolkit::Visual::Transform::Property::SIZE:
+        {
+          keyValue.second.Get( mSize );
+          break;
+        }
+        case Toolkit::Visual::Transform::Property::ORIGIN:
+        {
+          Scripting::GetEnumerationProperty< Toolkit::Align::Type >( keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mOrigin );
+          break;
+        }
+        case Toolkit::Visual::Transform::Property::ANCHOR_POINT:
+        {
+          Scripting::GetEnumerationProperty< Toolkit::Align::Type >( keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mAnchorPoint );
+          break;
+        }
+        case Toolkit::Visual::Transform::Property::OFFSET_POLICY:
+        {
+          Vector2 policy;
+          if( GetPolicyFromValue( keyValue.second, policy ) )
+          {
+            mOffsetSizeMode.x = policy.x;
+            mOffsetSizeMode.y = policy.y;
+          }
+          break;
+        }
+        case Toolkit::Visual::Transform::Property::SIZE_POLICY:
+        {
+          Vector2 policy;
+          if( GetPolicyFromValue( keyValue.second, policy ) )
+          {
+            mOffsetSizeMode.z = policy.x;
+            mOffsetSizeMode.w = policy.y;
+          }
+          break;
+        }
+        case Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE:
+        {
+          keyValue.second.Get( mExtraSize );
+          break;
+        }
+      }
+    }
+    else  // Key type is STRING
+    {
+      if( keyValue.first == "offset" )
+      {
+        keyValue.second.Get( mOffset );
+      }
+      else if( keyValue.first == "size" )
+      {
+        keyValue.second.Get( mSize );
+      }
+      else if( keyValue.first == "origin" )
+      {
+        Scripting::GetEnumerationProperty< Toolkit::Align::Type >( keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mOrigin );
+      }
+      else if( keyValue.first == "anchorPoint" )
+      {
+        Scripting::GetEnumerationProperty< Toolkit::Align::Type >( keyValue.second, ALIGN_TABLE, ALIGN_TABLE_COUNT, mAnchorPoint );
+      }
+      else if( keyValue.first == "offsetPolicy" )
+      {
+        Vector2 policy;
+        if( GetPolicyFromValue( keyValue.second, policy ) )
+        {
+          mOffsetSizeMode.x = policy.x;
+          mOffsetSizeMode.y = policy.y;
+        }
+      }
+      else if( keyValue.first == "sizePolicy" )
+      {
+        Vector2 policy;
+        if( GetPolicyFromValue( keyValue.second, policy ) )
+        {
+          mOffsetSizeMode.z = policy.x;
+          mOffsetSizeMode.w = policy.y;
+        }
+      }
+      else if( keyValue.first == "extraSize" )
+      {
+        keyValue.second.Get( mExtraSize );
+      }
+    }
+  }
+}
+
+void Internal::Visual::Base::Impl::Transform::GetPropertyMap( Property::Map& map ) const
+{
+  map.Clear();
+  map.Add( Toolkit::Visual::Transform::Property::OFFSET, mOffset )
+     .Add( Toolkit::Visual::Transform::Property::SIZE, mSize )
+     .Add( Toolkit::Visual::Transform::Property::ORIGIN, mOrigin )
+     .Add( Toolkit::Visual::Transform::Property::ANCHOR_POINT, mAnchorPoint )
+     .Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( mOffsetSizeMode.x, mOffsetSizeMode.y ) )
+     .Add( Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2( mOffsetSizeMode.z, mOffsetSizeMode.w ) )
+     .Add( Toolkit::DevelVisual::Transform::Property::EXTRA_SIZE, mExtraSize );
+}
+
+void Internal::Visual::Base::Impl::Transform::RegisterUniforms( Dali::Renderer renderer, Toolkit::Direction::Type direction )
+{
+  renderer.RegisterProperty( SIZE, mSize );
+  renderer.RegisterProperty( OFFSET, direction == Toolkit::Direction::LEFT_TO_RIGHT ? mOffset : mOffset * Vector2(-1.0f,1.0f));
+  renderer.RegisterProperty( OFFSET_SIZE_MODE, mOffsetSizeMode );
+  renderer.RegisterProperty( ORIGIN, PointToVector2( mOrigin, direction ) - Vector2(0.5,0.5) );
+  renderer.RegisterProperty( ANCHOR_POINT, Vector2(0.5,0.5) - PointToVector2( mAnchorPoint, direction ) );
+  renderer.RegisterProperty( EXTRA_SIZE, mExtraSize );
+}
+
+Vector2 Internal::Visual::Base::Impl::Transform::GetVisualSize( const Vector2& controlSize )
+{
+  return Vector2( Lerp( mOffsetSizeMode.z, mSize.x * controlSize.x, mSize.x ) ,
+                  Lerp( mOffsetSizeMode.w, mSize.y * controlSize.y, mSize.y ) ) + mExtraSize;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/visual-base-data-impl.h b/dali-toolkit/internal/visuals/visual-base-data-impl.h
new file mode 100644 (file)
index 0000000..839971b
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef DALI_TOOLKIT_INTERNAL_VISUAL_BASE_DATA_IMPL_H
+#define DALI_TOOLKIT_INTERNAL_VISUAL_BASE_DATA_IMPL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/math/vector2.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/internal/visuals/visual-event-observer.h>
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace Visual
+{
+
+struct Base::Impl
+{
+  /**
+   * Constructor
+   * @param [in] fittingMode that the derived class prefers
+   */
+  Impl(FittingMode fittingMode);
+
+  /**
+   * Destructor
+   */
+  ~Impl();
+
+  enum Flags
+  {
+    IS_ON_STAGE = 1,
+    IS_ATLASING_APPLIED = 1<<1,
+    IS_PREMULTIPLIED_ALPHA = 1 << 2,
+    IS_SYNCHRONOUS_RESOURCE_LOADING = 1 << 3
+  };
+
+  struct CustomShader
+  {
+    CustomShader( const Property::Map& map );
+    void SetPropertyMap( const Property::Map& map );
+    void CreatePropertyMap( Property::Map& map ) const;
+
+    std::string mVertexShader;
+    std::string mFragmentShader;
+    Dali::ImageDimensions mGridSize;
+    Dali::Shader::Hint::Value mHints; //(bitfield) values from enum Shader::Hint
+  };
+
+  struct Transform
+  {
+    /**
+     * Default constructor ensures the visual fills the control
+     */
+    Transform();
+
+    /**
+     * Use the property map to set zero or more of the transform
+     * attributes, and sets the remaining attributes to their default
+     * values.
+     */
+    void SetPropertyMap( const Property::Map& map );
+
+    /**
+     * Add the transform attributes to the map (using integer keys)
+     */
+    void GetPropertyMap( Property::Map& map ) const;
+
+    /**
+     * Update zero or more attributes from the property map.
+     */
+    void UpdatePropertyMap( const Property::Map& map );
+
+    /**
+     * Register or set the uniform properties onto the renderer
+     */
+    void RegisterUniforms( Renderer renderer, Toolkit::Direction::Type direction );
+
+    /**
+     * Convert the control size and the transform attributes into the actual
+     * size of the visual.
+     */
+    Vector2 GetVisualSize( const Vector2& controlSize );
+
+    Vector2 mOffset;
+    Vector2 mSize;
+    Vector2 mExtraSize;
+    Vector4 mOffsetSizeMode;
+    Toolkit::Align::Type mOrigin;
+    Toolkit::Align::Type mAnchorPoint;
+  };
+
+  Renderer        mRenderer;
+  CustomShader*   mCustomShader;
+  SlotDelegate<Visual::Base>* mBlendSlotDelegate; ///< Used to own mix color animation connection
+  EventObserver*  mEventObserver;  ///< Allows controls to observe when the visual has events to notify
+  std::string     mName;
+  Transform       mTransform;
+  Vector4         mMixColor;
+  Size            mControlSize;
+  float           mCornerRadius;
+  int             mDepthIndex;
+  Property::Index mMixColorIndex;
+  Property::Index mCornerRadiusIndex;
+  FittingMode     mFittingMode;  //< How the contents should fit the view
+  int             mFlags;
+  Toolkit::Visual::ResourceStatus  mResourceStatus;
+};
+
+} // namespace Visual
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_VISUAL_BASE_DATA_IMPL_H
diff --git a/dali-toolkit/internal/visuals/visual-base-impl.cpp b/dali-toolkit/internal/visuals/visual-base-impl.cpp
new file mode 100755 (executable)
index 0000000..b03a5ef
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2018 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 "visual-base-impl.h"
+
+// EXTERNAL HEADER
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/devel-api/object/handle-devel.h>
+#include <dali/devel-api/scripting/enum-helper.h>
+#include <dali/devel-api/rendering/renderer-devel.h>
+#include <dali/integration-api/debug.h>
+
+//INTERNAL HEARDER
+#include <dali-toolkit/public-api/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/primitive-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/internal/helpers/property-helper.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVisualBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VISUAL_BASE" );
+#endif
+
+const char * const PRE_MULTIPLIED_ALPHA_PROPERTY( "preMultipliedAlpha" );
+
+} // namespace
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_FITTING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FIT_KEEP_ASPECT_RATIO  )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Visual::FittingMode, FILL  )
+DALI_ENUM_TO_STRING_TABLE_END( VISUAL_FITTING_MODE )
+
+} // namespace
+
+Visual::Base::Base( VisualFactoryCache& factoryCache, FittingMode fittingMode )
+: mImpl( new Impl(fittingMode) ),
+  mFactoryCache( factoryCache )
+{
+}
+
+Visual::Base::~Base()
+{
+  delete mImpl;
+}
+
+void Visual::Base::SetCustomShader( const Property::Map& shaderMap )
+{
+  if( mImpl->mCustomShader )
+  {
+    mImpl->mCustomShader->SetPropertyMap( shaderMap );
+  }
+  else
+  {
+    mImpl->mCustomShader = new Impl::CustomShader( shaderMap );
+  }
+}
+
+void Visual::Base::SetProperties( const Property::Map& propertyMap )
+{
+  for( size_t i = 0; i < propertyMap.Count(); ++i )
+  {
+    const KeyValuePair& pair = propertyMap.GetKeyValue( i );
+    const Property::Key& key = pair.first;
+    const Property::Value& value = pair.second;
+
+    Property::Key matchKey = key;
+    if( matchKey.type == Property::Key::STRING )
+    {
+      if( matchKey == CUSTOM_SHADER )
+      {
+        matchKey = Property::Key( Toolkit::Visual::Property::SHADER );
+      }
+      else if( matchKey == TRANSFORM )
+      {
+        matchKey = Property::Key( Toolkit::Visual::Property::TRANSFORM );
+      }
+      else if( matchKey == PREMULTIPLIED_ALPHA )
+      {
+        matchKey = Property::Key( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA );
+      }
+      else if( matchKey == MIX_COLOR )
+      {
+        matchKey = Property::Key( Toolkit::Visual::Property::MIX_COLOR );
+      }
+      else if( matchKey == OPACITY )
+      {
+        matchKey = Property::Key( Toolkit::Visual::Property::OPACITY );
+      }
+      else if( matchKey == VISUAL_FITTING_MODE )
+      {
+        matchKey = Property::Key( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE );
+      }
+      else if( matchKey == CORNER_RADIUS )
+      {
+        matchKey = Property::Key( Toolkit::DevelVisual::Property::CORNER_RADIUS );
+      }
+    }
+
+    switch( matchKey.indexKey )
+    {
+      case Toolkit::Visual::Property::SHADER:
+      {
+        Property::Map shaderMap;
+        if( value.Get( shaderMap ) )
+        {
+          SetCustomShader( shaderMap );
+        }
+        break;
+      }
+
+      case Toolkit::Visual::Property::TRANSFORM:
+      {
+        Property::Map map;
+        if( value.Get( map ) )
+        {
+          mImpl->mTransform.SetPropertyMap( map );
+        }
+        break;
+      }
+
+      case Toolkit::Visual::Property::PREMULTIPLIED_ALPHA:
+      {
+        bool premultipliedAlpha = false;
+        if( value.Get( premultipliedAlpha ) )
+        {
+          EnablePreMultipliedAlpha( premultipliedAlpha );
+        }
+        break;
+      }
+
+      case Toolkit::Visual::Property::MIX_COLOR:
+      {
+        Vector4 mixColor;
+        if( value.Get( mixColor ) )
+        {
+          if( value.GetType() == Property::VECTOR4 )
+          {
+            SetMixColor( mixColor );
+          }
+          else
+          {
+            Vector3 mixColor3(mixColor);
+            SetMixColor( mixColor3 );
+          }
+        }
+        break;
+      }
+      case Toolkit::Visual::Property::OPACITY:
+      {
+        float opacity;
+        if( value.Get( opacity ) )
+        {
+          mImpl->mMixColor.a = opacity;
+          SetMixColor( mImpl->mMixColor );
+        }
+        break;
+      }
+      case Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE:
+      {
+        Scripting::GetEnumerationProperty< Visual::FittingMode >(
+          value, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT, mImpl->mFittingMode );
+        break;
+      }
+      case Toolkit::DevelVisual::Property::CORNER_RADIUS:
+      {
+        float radius;
+        if( value.Get( radius ) )
+        {
+          mImpl->mCornerRadius = radius;
+        }
+        break;
+      }
+    }
+  }
+
+  DoSetProperties( propertyMap );
+}
+
+void Visual::Base::SetTransformAndSize( const Property::Map& transform, Size controlSize )
+{
+  mImpl->mControlSize = controlSize;
+  mImpl->mTransform.UpdatePropertyMap( transform );
+
+#if defined(DEBUG_ENABLED)
+  std::ostringstream oss;
+  oss << transform;
+  DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::SetTransformAndSize(%s) - [\e[1;32mtransform: %s  controlSize: (%3.1f, %3.1f)]\e[0m\n",
+                 GetName().c_str(), oss.str().c_str(), controlSize.x, controlSize.y );
+#endif
+
+  OnSetTransform();
+}
+
+void Visual::Base::SetName( const std::string& name )
+{
+  mImpl->mName = name;
+}
+
+const std::string& Visual::Base::GetName() const
+{
+  return mImpl->mName;
+}
+
+float Visual::Base::GetHeightForWidth( float width )
+{
+  float aspectCorrectedHeight = 0.f;
+  Vector2 naturalSize;
+  GetNaturalSize( naturalSize );
+  if( naturalSize.width )
+  {
+    aspectCorrectedHeight = naturalSize.height * width / naturalSize.width;
+  }
+  return aspectCorrectedHeight;
+}
+
+float Visual::Base::GetWidthForHeight( float height )
+{
+  float aspectCorrectedWidth = 0.f;
+  Vector2 naturalSize;
+  GetNaturalSize( naturalSize );
+  if( naturalSize.height > 0.0f )
+  {
+    aspectCorrectedWidth = naturalSize.width * height / naturalSize.height;
+  }
+  return aspectCorrectedWidth;
+}
+
+void Visual::Base::GetNaturalSize( Vector2& naturalSize )
+{
+  naturalSize = Vector2::ZERO;
+}
+
+void Visual::Base::DoAction( const Property::Index actionId, const Property::Value attributes )
+{
+  OnDoAction( actionId, attributes );
+}
+
+void Visual::Base::SetDepthIndex( int index )
+{
+  mImpl->mDepthIndex = index;
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
+  }
+}
+
+int Visual::Base::GetDepthIndex() const
+{
+  return mImpl->mDepthIndex;
+}
+
+void Visual::Base::SetOnStage( Actor& actor )
+{
+  if( !IsOnStage() )
+  {
+    // To display the actor correctly, renderer should not be added to actor until all required resources are ready.
+    // Thus the calling of actor.AddRenderer() should happen inside derived class as base class does not know the exact timing.
+    DoSetOnStage( actor );
+
+    if( mImpl->mRenderer )
+    {
+      RegisterMixColor();
+
+      if( IsRoundedCornerRequired() )
+      {
+        mImpl->mCornerRadiusIndex = mImpl->mRenderer.RegisterProperty( CORNER_RADIUS, mImpl->mCornerRadius );
+
+        mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+      }
+
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, IsPreMultipliedAlphaEnabled());
+      mImpl->mRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mImpl->mDepthIndex );
+      mImpl->mFlags |= Impl::IS_ON_STAGE; // Only sets the flag if renderer exists
+    }
+  }
+}
+
+void Visual::Base::SetOffStage( Actor& actor )
+{
+  if( IsOnStage() )
+  {
+    DoSetOffStage( actor );
+    mImpl->mMixColorIndex = Property::INVALID_INDEX;
+    mImpl->mCornerRadiusIndex = Property::INVALID_INDEX;
+    mImpl->mFlags &= ~Impl::IS_ON_STAGE;
+  }
+}
+
+void Visual::Base::CreatePropertyMap( Property::Map& map ) const
+{
+  DoCreatePropertyMap( map );
+
+  if( mImpl->mCustomShader )
+  {
+    mImpl->mCustomShader->CreatePropertyMap( map );
+  }
+
+  Property::Map transform;
+  mImpl->mTransform.GetPropertyMap( transform );
+  map.Insert( Toolkit::Visual::Property::TRANSFORM, transform );
+
+  bool premultipliedAlpha( IsPreMultipliedAlphaEnabled() );
+  map.Insert( Toolkit::Visual::Property::PREMULTIPLIED_ALPHA, premultipliedAlpha );
+
+  // Note, Color and Primitive will also insert their own mix color into the map
+  // which is ok, because they have a different key value range.
+  map.Insert( Toolkit::Visual::Property::MIX_COLOR, mImpl->mMixColor ); // vec4
+  map.Insert( Toolkit::Visual::Property::OPACITY, mImpl->mMixColor.a );
+  map.Insert( Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, IsSynchronousLoadingRequired() );
+
+  auto fittingModeString = Scripting::GetLinearEnumerationName< FittingMode >(
+    mImpl->mFittingMode, VISUAL_FITTING_MODE_TABLE, VISUAL_FITTING_MODE_TABLE_COUNT );
+  map.Insert( Toolkit::DevelVisual::Property::VISUAL_FITTING_MODE, fittingModeString );
+
+  map.Insert( Toolkit::DevelVisual::Property::CORNER_RADIUS, mImpl->mCornerRadius );
+}
+
+void Visual::Base::CreateInstancePropertyMap( Property::Map& map ) const
+{
+  DoCreateInstancePropertyMap( map );
+
+  if( mImpl->mCustomShader )
+  {
+    mImpl->mCustomShader->CreatePropertyMap( map );
+  }
+
+  //map.Insert( Toolkit::Visual::Property::DEPTH_INDEX, mImpl->mDepthIndex );
+  //map.Insert( Toolkit::Visual::Property::ENABLED, (bool) mImpl->mRenderer );
+}
+
+
+void Visual::Base::EnablePreMultipliedAlpha( bool preMultiplied )
+{
+  if( preMultiplied )
+  {
+    mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
+  }
+  else
+  {
+    mImpl->mFlags &= ~Impl::IS_PREMULTIPLIED_ALPHA;
+  }
+
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty(Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, preMultiplied);
+    mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, static_cast<float>( preMultiplied ) );
+  }
+}
+
+bool Visual::Base::IsPreMultipliedAlphaEnabled() const
+{
+  return mImpl->mFlags & Impl::IS_PREMULTIPLIED_ALPHA;
+}
+
+void Visual::Base::DoSetOffStage( Actor& actor )
+{
+  actor.RemoveRenderer( mImpl->mRenderer );
+  mImpl->mRenderer.Reset();
+}
+
+bool Visual::Base::IsOnStage() const
+{
+  return mImpl->mFlags & Impl::IS_ON_STAGE;
+}
+
+bool Visual::Base::IsRoundedCornerRequired() const
+{
+  return !EqualsZero( mImpl->mCornerRadius );
+}
+
+void Visual::Base::OnDoAction( const Property::Index actionId, const Property::Value& attributes )
+{
+  // May be overriden by derived class
+}
+
+void Visual::Base::RegisterMixColor()
+{
+  // Only register if not already registered.
+  // (Color and Primitive visuals will register their own and save to this index)
+  if( mImpl->mMixColorIndex == Property::INVALID_INDEX )
+  {
+    mImpl->mMixColorIndex = DevelHandle::RegisterProperty(
+      mImpl->mRenderer,
+      Toolkit::Visual::Property::MIX_COLOR,
+      MIX_COLOR,
+      Vector3(mImpl->mMixColor) );
+  }
+
+  if( mImpl->mMixColor.a < 1.f )
+  {
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+  }
+
+  mImpl->mRenderer.SetProperty( DevelRenderer::Property::OPACITY, mImpl->mMixColor.a );
+
+  float preMultipliedAlpha = 0.0f;
+  if( IsPreMultipliedAlphaEnabled() )
+  {
+    preMultipliedAlpha = 1.0f;
+  }
+  mImpl->mRenderer.RegisterProperty( PRE_MULTIPLIED_ALPHA_PROPERTY, preMultipliedAlpha );
+}
+
+void Visual::Base::SetMixColor( const Vector4& color )
+{
+  mImpl->mMixColor = color;
+
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, Vector3(color) );
+    mImpl->mRenderer.SetProperty( DevelRenderer::Property::OPACITY, color.a );
+    if( color.a < 1.f )
+    {
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+    }
+  }
+}
+
+void Visual::Base::SetMixColor( const Vector3& color )
+{
+  mImpl->mMixColor.r = color.r;
+  mImpl->mMixColor.g = color.g;
+  mImpl->mMixColor.b = color.b;
+
+  if( mImpl->mRenderer )
+  {
+    mImpl->mRenderer.SetProperty( mImpl->mMixColorIndex, color );
+  }
+}
+
+const Vector4& Visual::Base::GetMixColor() const
+{
+  return mImpl->mMixColor;
+}
+
+void Visual::Base::AddEventObserver( Visual::EventObserver& observer)
+{
+  mImpl->mEventObserver = &observer;
+}
+
+void Visual::Base::RemoveEventObserver( Visual::EventObserver& observer )
+{
+  mImpl->mEventObserver = NULL;
+}
+
+void Visual::Base::ResourceReady(Toolkit::Visual::ResourceStatus resourceStatus)
+{
+  if( mImpl->mResourceStatus != resourceStatus )
+  {
+    mImpl->mResourceStatus = resourceStatus;
+
+    if( mImpl->mEventObserver )
+    {
+      // observer is currently a control impl
+      mImpl->mEventObserver->ResourceReady( *this );
+    }
+  }
+}
+
+bool Visual::Base::IsResourceReady() const
+{
+  return ( mImpl->mResourceStatus == Toolkit::Visual::ResourceStatus::READY );
+}
+
+bool Visual::Base::IsSynchronousLoadingRequired() const
+{
+  return ( mImpl->mFlags & Impl::IS_SYNCHRONOUS_RESOURCE_LOADING );
+}
+
+Toolkit::Visual::ResourceStatus Visual::Base::GetResourceStatus() const
+{
+  return mImpl->mResourceStatus;
+}
+
+Visual::FittingMode Visual::Base::GetFittingMode() const
+{
+  return mImpl->mFittingMode;
+}
+
+Visual::Base& Visual::Base::GetVisualObject()
+{
+  return *this;
+}
+
+Renderer Visual::Base::GetRenderer()
+{
+  return mImpl->mRenderer;
+}
+
+Property::Index Visual::Base::GetPropertyIndex( Property::Key key )
+{
+  Property::Index index = DevelHandle::GetPropertyIndex( mImpl->mRenderer, key );
+
+  if( index == Property::INVALID_INDEX )
+  {
+    // Is it a shader property?
+    Shader shader = mImpl->mRenderer.GetShader();
+    index = DevelHandle::GetPropertyIndex( shader, key );
+    if( index != Property::INVALID_INDEX )
+    {
+      // Yes - we should register it in the Renderer so it can be set / animated
+      // independently, as shaders are shared across multiple renderers.
+      std::string keyName;
+      Property::Index keyIndex( Property::INVALID_KEY );
+      if( key.type == Property::Key::INDEX )
+      {
+        keyName = shader.GetPropertyName( index );
+        keyIndex = key.indexKey;
+      }
+      else
+      {
+        keyName = key.stringKey;
+        // Leave keyIndex as INVALID_KEY - it can still be registered against the string key.
+      }
+      Property::Value value = shader.GetProperty( index );
+      index = DevelHandle::RegisterProperty( mImpl->mRenderer, keyIndex, keyName, value );
+    }
+  }
+  return index;
+}
+
+void Visual::Base::SetupTransition(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator,
+  Property::Index index,
+  Property::Value& initialValue,
+  Property::Value& targetValue )
+{
+  if( index != Property::INVALID_INDEX )
+  {
+    if( mImpl->mRenderer )
+    {
+      if( animator.animate == false )
+      {
+        mImpl->mRenderer.SetProperty( index, targetValue );
+      }
+      else
+      {
+        if( animator.initialValue.GetType() != Property::NONE )
+        {
+          mImpl->mRenderer.SetProperty( index, initialValue );
+        }
+
+        if( ! transition )
+        {
+          transition = Dali::Animation::New( 0.1f );
+        }
+
+        transition.AnimateTo( Property( mImpl->mRenderer, index ),
+                              targetValue,
+                              animator.alphaFunction,
+                              TimePeriod( animator.timePeriodDelay,
+                                          animator.timePeriodDuration ) );
+      }
+    }
+  }
+}
+
+void Visual::Base::AnimateProperty(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator )
+{
+#if defined(DEBUG_ENABLED)
+  {
+    std::ostringstream oss;
+    oss << "Visual::Base::AnimateProperty(Visual:" << mImpl->mName << " Property:" << animator.propertyKey << " Target: " << animator.targetValue << std::endl;
+    DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, oss.str().c_str() );
+  }
+#endif
+
+  Property::Map map;
+  DoCreatePropertyMap( map );
+  Property::Value* valuePtr = map.Find( Toolkit::Visual::Property::TYPE );
+  int visualType = -1;
+  if( valuePtr )
+  {
+    valuePtr->Get( visualType );
+  }
+
+  if( animator.propertyKey == Toolkit::Visual::Property::MIX_COLOR ||
+      animator.propertyKey == MIX_COLOR ||
+      ( visualType == Toolkit::Visual::COLOR &&
+        animator.propertyKey == ColorVisual::Property::MIX_COLOR ) ||
+      ( visualType == Toolkit::Visual::PRIMITIVE &&
+        animator.propertyKey == PrimitiveVisual::Property::MIX_COLOR ) )
+  {
+    AnimateMixColorProperty( transition, animator );
+  }
+  else if(animator.propertyKey == Toolkit::Visual::Property::OPACITY ||
+          animator.propertyKey == OPACITY )
+  {
+    AnimateOpacityProperty( transition, animator );
+  }
+  else if( mImpl->mRenderer )
+  {
+    AnimateRendererProperty( transition, animator );
+  }
+}
+
+void Visual::Base::AnimateOpacityProperty(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator )
+{
+  bool isOpaque = mImpl->mMixColor.a >= 1.0f;
+
+  float initialOpacity;
+  if( animator.initialValue.Get( initialOpacity ) )
+  {
+    isOpaque = (initialOpacity >= 1.0f);
+  }
+
+  float targetOpacity;
+  if( animator.targetValue.Get( targetOpacity ) )
+  {
+    mImpl->mMixColor.a = targetOpacity;
+  }
+
+  SetupTransition( transition, animator, DevelRenderer::Property::OPACITY, animator.initialValue, animator.targetValue );
+  SetupBlendMode( transition, isOpaque, animator.animate );
+}
+
+void Visual::Base::AnimateRendererProperty(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator )
+{
+  Property::Index index = GetPropertyIndex( animator.propertyKey );
+  if( index != Property::INVALID_INDEX )
+  {
+    if( animator.targetValue.GetType() != Property::NONE )
+    {
+      // Try writing target value into transform property map
+      // if it's not a valid key, then it won't alter mTransform
+      Property::Map map;
+      if( animator.propertyKey.type == Property::Key::INDEX )
+      {
+        map.Add( animator.propertyKey.indexKey, animator.targetValue );
+      }
+      else
+      {
+        map.Add( animator.propertyKey.stringKey, animator.targetValue );
+      }
+
+      mImpl->mTransform.UpdatePropertyMap( map );
+    }
+
+    SetupTransition( transition, animator, index, animator.initialValue, animator.targetValue );
+  }
+}
+
+void Visual::Base::AnimateMixColorProperty(
+  Dali::Animation& transition,
+  Internal::TransitionData::Animator& animator )
+{
+  Property::Index index = mImpl->mMixColorIndex;
+  bool animateOpacity = false;
+  bool isOpaque = true;
+
+  Property::Value initialOpacity;
+  Property::Value targetOpacity;
+  Property::Value initialMixColor;
+  Property::Value targetMixColor;
+
+  if( index != Property::INVALID_INDEX )
+  {
+    Vector4 initialColor;
+    if( animator.initialValue.Get(initialColor) )
+    {
+      if( animator.initialValue.GetType() == Property::VECTOR4 )
+      {
+        // if there is an initial color specifying alpha, test it
+        isOpaque = initialColor.a >= 1.0f;
+        initialOpacity = initialColor.a;
+      }
+      initialMixColor = Vector3( initialColor );
+    }
+
+    // Set target value into data store
+    if( animator.targetValue.GetType() != Property::NONE )
+    {
+      Vector4 mixColor;
+      animator.targetValue.Get(mixColor);
+      if( animator.targetValue.GetType() == Property::VECTOR4 )
+      {
+        mImpl->mMixColor.a = mixColor.a;
+        targetOpacity = mixColor.a;
+        animateOpacity = true;
+      }
+
+      mImpl->mMixColor.r = mixColor.r;
+      mImpl->mMixColor.g = mixColor.g;
+      mImpl->mMixColor.b = mixColor.b;
+      targetMixColor = Vector3(mixColor);
+    }
+
+    SetupTransition( transition, animator, index, initialMixColor, targetMixColor );
+    if( animateOpacity )
+    {
+      SetupTransition( transition, animator, DevelRenderer::Property::OPACITY, initialOpacity, targetOpacity );
+      SetupBlendMode( transition, isOpaque, animator.animate );
+    }
+  }
+}
+
+void Visual::Base::SetupBlendMode( Animation& transition, bool isInitialOpaque, bool animating )
+{
+  // Ensure the blend mode is turned on if we are animating opacity, and
+  // turned off after the animation ends if the final value is opaque
+  if( ! isInitialOpaque || mImpl->mMixColor.a < 1.0f )
+  {
+    if( mImpl->mRenderer )
+    {
+      mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+
+      if( animating == true && mImpl->mMixColor.a >= 1.0f )
+      {
+        // When it becomes opaque, set the blend mode back to automatically
+        if( ! mImpl->mBlendSlotDelegate )
+        {
+          mImpl->mBlendSlotDelegate = new SlotDelegate<Visual::Base>(this);
+        }
+        transition.FinishedSignal().Connect( *(mImpl->mBlendSlotDelegate),
+                                             &Visual::Base::OnMixColorFinished );
+      }
+    }
+  }
+}
+
+void Visual::Base::OnMixColorFinished( Animation& animation )
+{
+  if( mImpl->mRenderer )
+  {
+    DALI_LOG_INFO( gVisualBaseLogFilter, Debug::General, "Visual::Base::OnMixColorFinished()\n");
+    mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE,
+                                  ( mImpl->mMixColor.a < 1.0 ) ? BlendMode::ON : BlendMode::AUTO );
+  }
+  delete mImpl->mBlendSlotDelegate;
+  mImpl->mBlendSlotDelegate = NULL;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/visual-base-impl.h b/dali-toolkit/internal/visuals/visual-base-impl.h
new file mode 100644 (file)
index 0000000..a04fa1f
--- /dev/null
@@ -0,0 +1,488 @@
+#ifndef DALI_TOOLKIT_INTERNAL_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_VISUAL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/animation/animation.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/rendering/shader.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/internal/visuals/transition-data-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/devel-api/direction-enums.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace Visual
+{
+
+class EventObserver;
+
+using FittingMode = DevelVisual::FittingMode;
+
+/**
+ * Base class for all Control rendering logic. A control may have multiple visuals.
+ *
+ * Note: The visual responds to the the Actor::COLOR by blending it with the 'Multiply' operator.
+ *
+ * The following properties are optional
+ *
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | customShader            | MAP              |
+ *
+ * where custom-shader is a map with the following properties:
+ * | %Property Name          | Type             |
+ * |-------------------------|------------------|
+ * | vertexShader            | STRING           |
+ * | fragmentShader          | STRING           |
+ * | subdivideGridX          | INT              |
+ * | subdivideGridY          | INT              |
+ * | shaderHints             | INT              |
+ */
+class Base : public BaseObject
+{
+public:
+
+  /**
+   * Setting the properties of the visual, this API should only called by the VisualFactory
+   * @param[in] propertyMap The properties for the requested Visual object.
+   */
+  void SetProperties( const Property::Map& propertyMap );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetName
+   */
+  void SetName( const std::string& name );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetName
+   */
+  const std::string& GetName() const;
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetSize
+   */
+  void SetTransformAndSize( const Property::Map& transform, Size controlSize );
+
+  /**
+   * @brief Performs an action on the visual with the given action name and attributes.
+   *
+   * @param[in] actionName The name of the action to perform this API only takes an Index
+   * @param[in] attributes The list of attributes for the action. ( optional for this data structure to have content )
+   */
+  void DoAction( const Dali::Property::Index actionName, const Dali::Property::Value attributes );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetHeightForWidth
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetWidthForHeight
+   */
+  virtual float GetWidthForHeight( float height );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetNaturalSize
+   */
+  virtual void GetNaturalSize( Vector2& naturalSize );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetDepthIndex
+   */
+  void SetDepthIndex( int index );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetDepthIndex
+   */
+  int GetDepthIndex() const;
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetOnStage
+   * @pre Impl->mGeometry must be created before this method is called
+   */
+  void SetOnStage( Actor& actor );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetOffStage
+   */
+  void SetOffStage( Actor& actor );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::CreatePropertyMap
+   */
+  void CreatePropertyMap( Property::Map& map ) const;
+
+  /**
+   * @brief Create a property map containing per-instance visual properties.
+   *
+   * This will enable creation of new visuals on control state change with
+   * any alternative style properties and the relevant instance properties
+   * (e.g. for image visual, the desired size, and for text visual, the actual text).
+   * @param[in] map The property map into which to write
+   */
+  void CreateInstancePropertyMap( Property::Map& map ) const;
+
+  /**
+   * @brief Set whether the Pre-multiplied Alpha Blending is required
+   *
+   * @param[in] preMultiplied whether alpha is pre-multiplied.
+   */
+  void EnablePreMultipliedAlpha( bool preMultiplied );
+
+  /**
+   * @brief Query whether alpha is pre-multiplied.
+   *
+   * @return True is alpha is pre-multiplied, false otherwise.
+   */
+  bool IsPreMultipliedAlphaEnabled() const;
+
+  /**
+   * @brief Sets properties of custom shader
+   * @param[in] propertyMap Property map containing the custom shader data
+   */
+  void SetCustomShader( const Property::Map& propertyMap );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::SetProperty
+   */
+  void SetProperty( Dali::Property::Index index, const Dali::Property::Value& propertyValue );
+
+  /**
+   * @copydoc Toolkit::Visual::Base::GetProperty
+   */
+  Dali::Property::Value GetProperty( Dali::Property::Index index );
+
+  /**
+   * Gets currently staged renderer, or an empty handle if not staged
+   */
+  Renderer GetRenderer();
+
+  /**
+   * Sets the mix color ( including opacity )  of the visual.
+   * @param[in] mixColor The new mix color
+   */
+  void SetMixColor( const Vector4& color );
+
+  /**
+   * Sets the mix color of the visual.
+   * @param[in] mixColor The new mix color
+   */
+  void SetMixColor( const Vector3& color );
+
+  /**
+   * Gets the mix color of the visual.
+   * @return The mix color
+   */
+  const Vector4& GetMixColor() const;
+
+  /**
+   * Animate the property if it exists in the visual or renderer.
+   *
+   * If it's a visual property such as mix color or a transform property,
+   * saves the target value to the local data.
+   *
+   * If the visual isn't staged (i.e. it doesn't have a renderer),
+   * then this will not add an animation.
+   *
+   * If the animator is valid and the transition handle is empty - it will
+   * be created.
+   *
+   * @param[in] transition The animation to create or attach to
+   * @param[in] animator The animation parameters of the property.
+   */
+  void AnimateProperty( Dali::Animation& transition,
+                        Internal::TransitionData::Animator& animator );
+
+  /**
+   * @brief Add an observer to watch for when the Visuals have events to notify
+   * Currently only supports a single observer
+   */
+  void AddEventObserver( Visual::EventObserver& observer );
+
+  /**
+   * @brief Remove an observer
+   */
+  void RemoveEventObserver( Visual::EventObserver& observer );
+
+  /**
+   * @brief Called when the visuals resources are loaded / ready
+   */
+  void ResourceReady( Toolkit::Visual::ResourceStatus resourceStatus );
+
+  /**
+   * @brief Called when the visuals resources are loaded / ready
+   * @return true if ready, false otherwise
+   */
+  virtual bool IsResourceReady() const;
+
+  /**
+   * @brief Get the loading state of the visual resource
+   * @return Return the loading status (PREPARING, READY and FAILED) of visual resource
+   */
+  Toolkit::Visual::ResourceStatus GetResourceStatus() const;
+
+  /**
+   * @brief Get the fitting mode for the visual
+   */
+  FittingMode GetFittingMode() const;
+
+  /**
+   * @brief Get the actual Visual Object.
+   * @return The actual visual object
+   * @note Should be overridden by deriving controls if they are acting as a proxy to other visual objects.
+   */
+  virtual Base& GetVisualObject();
+
+  /**
+   * @brief Query whether resources requires to be loaded synchronously.
+   * @return Returns true if synchronous resource loading is required, false otherwise.
+   */
+  bool IsSynchronousLoadingRequired() const;
+
+ protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   */
+  Base( VisualFactoryCache& factoryCache, FittingMode fittingMode );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~Base();
+
+protected:
+
+  /**
+   * @brief Called by CreatePropertyMap() allowing sub classes to respond to the CreatePropertyMap event
+   *
+   * @param[out] map The visual property map.
+   */
+  virtual void DoCreatePropertyMap( Property::Map& map ) const = 0;
+
+  /**
+   * @brief Called by CreateInstancePropertyMap() allowing derived
+   * classes to store instanced data (separate to styled data) that
+   * needs copying between visuals on state change.
+   *
+   * @param[out] map The visual property map
+   */
+  virtual void DoCreateInstancePropertyMap( Property::Map& map ) const = 0;
+
+  /**
+   * @brief Called by SetProperties() allowing sub classes to set their properties
+   *
+   * @param[in] propertyMap The properties for the requested Visual object.
+   */
+  virtual void DoSetProperties( const Property::Map& propertyMap ) = 0;
+
+  /**
+   * @brief Called when transform or control size changes
+   * ( Of use to SVG and Text visuals )
+   */
+  virtual void OnSetTransform() = 0;
+
+  /**
+   * @brief Called by SetOnStage() allowing sub classes to respond to the SetOnStage event
+   *
+   * @note The derived class is required to create the renderer, and add it to the actor when all the resources are in place.
+   *
+   * @param[in] actor The actor applying this visual.
+   */
+  virtual void DoSetOnStage( Actor& actor ) = 0;
+
+  /**
+   * @brief Called by SetOffStage() allowing sub classes to respond to the SetOffStage event
+   *
+   * @param[in] actor The actor applying this visual.
+   */
+  virtual void DoSetOffStage( Actor& actor );
+
+  /**
+   * @brief Called by DoAction() allowing sub classes to do the given action.
+   *
+   * @param[in] actionId The action to perform
+   * @param[in] attributes The list of attributes for the action. ( optional for this data structure to have content )
+   */
+  virtual void OnDoAction( const Property::Index actionId, const Property::Value& attributes );
+
+protected:
+
+  /**
+   * @brief Gets the on stage state for this Visual
+   *
+   * @return Returns true if this Visual is on stage, false if it is off the stage
+   */
+  bool IsOnStage() const;
+
+  /**
+   * @brief Query whether the corners of the visual requires to be rounded.
+   *
+   * @return Returns true if the rounded corner is required, false otherwise.
+   */
+  bool IsRoundedCornerRequired() const;
+
+private:
+
+  /**
+   * Register the mix color uniform on the Renderer and store the property index.
+   * Note, this is not used by Color or Primitive Visuals, which will use their
+   * own property index.
+   */
+  void RegisterMixColor();
+
+  /**
+   * Find the matching property on the renderer or shader. If it's a shader
+   * property, register it on the renderer in order to animate it for this
+   * visual independently.
+   * @param[in] key The key to match.
+   * @return the matching index, or INVALID_INDEX if it's not found
+   */
+  Property::Index GetPropertyIndex( Property::Key key );
+
+  /**
+   * Set up the transition. If no animation is required, then
+   * transition will be untouched.
+   *
+   * @param[in] transition The transition to use or set up.
+   * @param[in] animator The animation data to use
+   * @param[in] index The property index on the renderer to animate
+   * @param[in] initialValue The optional initial value
+   * @param[in] targetValue The target value to use
+   */
+  void SetupTransition( Dali::Animation& transition,
+                        Internal::TransitionData::Animator& animator,
+                        Property::Index index,
+                        Property::Value& initialValue,
+                        Property::Value& targetValue );
+
+  /**
+   * Animate the opacity property - Special handling to
+   * ensure that the blend mode is set to ON whilst animating,
+   * and set back to AUTO if it's opaque at the end of the
+   * animation.
+   *
+   * @param[in] transition The transition to use or set up.
+   * @param[in] animator The animation data to use
+   */
+  void AnimateOpacityProperty( Dali::Animation& transition,
+                               Internal::TransitionData::Animator& animator );
+
+  /**
+   * Animate the renderer property - no special handling
+   *
+   * @param[in] transition The transition to use or set up.
+   * @param[in] animator The animation data to use
+   */
+  void AnimateRendererProperty( Dali::Animation& transition,
+                                Internal::TransitionData::Animator& animator );
+
+  /**
+   * Animate the mix color property.
+   *
+   * If the animator is a vec3, then it only animates the color
+   * channels without animating the opacity.  If it's a vec4, then it
+   * runs 2 animators, one for the the vec3 mixColor, and one for the
+   * opacity. (They are separate uniforms in the shader )
+   *
+   * @param[in] transition The transition to use or set up.
+   * @param[in] animator The animation data to use
+   */
+  void AnimateMixColorProperty( Dali::Animation& transition,
+                                Internal::TransitionData::Animator& animator );
+
+  /**
+   * Set up the right blend mode if the opacity is being animated.
+   * Also ensure that when the animation finishes, the blend mode is
+   * set to the appropriate value. It also uses the target value as
+   * set into mMixColor.
+   *
+   * @param[in] transition The transition to listen to
+   * @param[in] isInitialOpaque Whether the initial value is opaque
+   * @param[in] animating If the transition animates the value.
+   */
+  void SetupBlendMode( Dali::Animation& transition,
+                       bool isInitialOpaque, bool animating );
+
+  /**
+   * When a mix color animation has finished, ensure the blend mode is set back
+   * to the right value for the target opacity.
+   */
+  void OnMixColorFinished( Animation& animation );
+
+  // Undefined
+  Base( const Visual::Base& visual );
+
+  // Undefined
+  Base& operator=( const Visual::Base& visual );
+
+protected:
+  struct Impl;
+  Impl* mImpl;
+  VisualFactoryCache& mFactoryCache;
+};
+
+typedef IntrusivePtr<Base> BasePtr;
+
+} // namspace Visual
+
+} // namespace Internal
+
+inline const Internal::Visual::Base& GetImplementation(const Toolkit::Visual::Base& visualBase )
+{
+  DALI_ASSERT_ALWAYS( visualBase && "visual base handle is empty" );
+
+  const BaseObject& handle = visualBase.GetBaseObject();
+
+  return static_cast<const Internal::Visual::Base&>(handle);
+}
+
+inline Internal::Visual::Base& GetImplementation(Toolkit::Visual::Base& visualBase)
+{
+  DALI_ASSERT_ALWAYS( visualBase && "visual base handle is empty" );
+
+  BaseObject& handle = visualBase.GetBaseObject();
+
+  return static_cast<Internal::Visual::Base&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_VISUAL_H
diff --git a/dali-toolkit/internal/visuals/visual-event-observer.h b/dali-toolkit/internal/visuals/visual-event-observer.h
new file mode 100644 (file)
index 0000000..d816c34
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_INTERNAL_TOOLKIT_VISUAL_EVENT_OBSERVER_H
+#define DALI_INTERNAL_TOOLKIT_VISUAL_EVENT_OBSERVER_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/object/property-value.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+namespace Visual
+{
+
+class Base;
+
+/**
+ * Observer to be informed when visuals have events.
+ */
+class EventObserver
+{
+public:
+
+  /**
+   * Inform the observer of the object when a resource is ready.
+   * @param[in] object The connection owner
+   */
+  virtual void ResourceReady( Visual::Base& object ) = 0;
+
+  /**
+   * Inform the observer of the object when an event occurs.
+   * @param[in] object The connection owner
+   * @param[in] signalId The signal to emit. See Visual to find supported signals
+   */
+  virtual void NotifyVisualEvent( Visual::Base& object, Property::Index signalId ) = 0;
+
+protected:
+
+  /**
+   * constructor
+   */
+  EventObserver()
+  {
+  }
+
+  /**
+   * virtual destructor
+   */
+  virtual ~EventObserver()
+  {
+  }
+
+  // Undefined copy constructor.
+  EventObserver( const EventObserver& ) = delete;
+
+  // Undefined assignment operator.
+  EventObserver& operator=( const EventObserver& ) = delete;
+};
+
+} // Visual
+} // Internal
+} // Toolkit
+} // Dali
+
+#endif // DALI_INTERNAL_TOOLKIT_VISUAL_EVENT_OBSERVER_H
diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.cpp b/dali-toolkit/internal/visuals/visual-factory-cache.cpp
new file mode 100644 (file)
index 0000000..854a43a
--- /dev/null
@@ -0,0 +1,252 @@
+ /*
+ * 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.
+ */
+
+// CLASS HEADER
+#include "visual-factory-cache.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/hash.h>
+#include <dali/public-api/images/resource-image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad )
+: mSvgRasterizeThread( NULL ),
+  mVectorAnimationThread(),
+  mBrokenImageUrl(""),
+  mPreMultiplyOnLoad( preMultiplyOnLoad )
+{
+}
+
+VisualFactoryCache::~VisualFactoryCache()
+{
+  SvgRasterizeThread::TerminateThread( mSvgRasterizeThread );
+}
+
+Geometry VisualFactoryCache::GetGeometry( GeometryType type )
+{
+  if( !mGeometry[type] && type == QUAD_GEOMETRY )
+  {
+    mGeometry[type] = CreateQuadGeometry();
+  }
+
+  return mGeometry[type];
+}
+
+void VisualFactoryCache::SaveGeometry( GeometryType type, Geometry geometry )
+{
+  mGeometry[type] = geometry;
+}
+
+Shader VisualFactoryCache::GetShader( ShaderType type )
+{
+  return mShader[type];
+}
+
+void VisualFactoryCache::SaveShader( ShaderType type, Shader shader )
+{
+  mShader[type] = shader;
+}
+
+Geometry VisualFactoryCache::CreateQuadGeometry()
+{
+  const float halfWidth = 0.5f;
+  const float halfHeight = 0.5f;
+  struct QuadVertex { Vector2 position;};
+  QuadVertex quadVertexData[4] =
+  {
+      { Vector2(-halfWidth, -halfHeight) },
+      { Vector2(-halfWidth, halfHeight)  },
+      { Vector2( halfWidth, -halfHeight) },
+      { Vector2( halfWidth, halfHeight)  }
+  };
+
+  Property::Map quadVertexFormat;
+  quadVertexFormat["aPosition"] = Property::VECTOR2;
+  PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
+  quadVertices.SetData( quadVertexData, 4 );
+
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( quadVertices );
+  geometry.SetType( Geometry::TRIANGLE_STRIP );
+
+  return geometry;
+}
+
+ImageAtlasManagerPtr VisualFactoryCache::GetAtlasManager()
+{
+  if( !mAtlasManager )
+  {
+    mAtlasManager = new ImageAtlasManager();
+    mAtlasManager->SetBrokenImage( mBrokenImageUrl );
+  }
+
+  return mAtlasManager;
+}
+
+TextureManager& VisualFactoryCache::GetTextureManager()
+{
+  return mTextureManager;
+}
+
+NPatchLoader& VisualFactoryCache::GetNPatchLoader()
+{
+  return mNPatchLoader;
+}
+
+SvgRasterizeThread* VisualFactoryCache::GetSVGRasterizationThread()
+{
+  if( !mSvgRasterizeThread )
+  {
+    mSvgRasterizeThread = new SvgRasterizeThread( new EventThreadCallback( MakeCallback( this, &VisualFactoryCache::ApplyRasterizedSVGToSampler ) ) );
+    mSvgRasterizeThread->Start();
+  }
+  return mSvgRasterizeThread;
+}
+
+VectorAnimationThread& VisualFactoryCache::GetVectorAnimationThread()
+{
+  if( !mVectorAnimationThread )
+  {
+    mVectorAnimationThread = std::unique_ptr< VectorAnimationThread >( new VectorAnimationThread() );
+    mVectorAnimationThread->Start();
+  }
+  return *mVectorAnimationThread;
+}
+
+void VisualFactoryCache::ApplyRasterizedSVGToSampler()
+{
+  while( RasterizingTaskPtr task = mSvgRasterizeThread->NextCompletedTask() )
+  {
+    task->GetSvgVisual()->ApplyRasterizedImage( task->GetParsedImage(), task->GetPixelData() );
+  }
+}
+
+Geometry VisualFactoryCache::CreateGridGeometry( Uint16Pair gridSize )
+{
+  uint16_t gridWidth = gridSize.GetWidth();
+  uint16_t gridHeight = gridSize.GetHeight();
+
+  // Create vertices
+  Vector< Vector2 > vertices;
+  vertices.Reserve( ( gridWidth + 1 ) * ( gridHeight + 1 ) );
+
+  for( int y = 0; y < gridHeight + 1; ++y )
+  {
+    for( int x = 0; x < gridWidth + 1; ++x )
+    {
+      vertices.PushBack( Vector2( (float)x/gridWidth - 0.5f, (float)y/gridHeight  - 0.5f) );
+    }
+  }
+
+  // Create indices
+  Vector< unsigned short > indices;
+  indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
+
+  for( unsigned int row = 0u; row < gridHeight; ++row )
+  {
+    unsigned int rowStartIndex = row*(gridWidth+1u);
+    unsigned int nextRowStartIndex = rowStartIndex + gridWidth +1u;
+
+    if( row != 0u ) // degenerate index on non-first row
+    {
+      indices.PushBack( rowStartIndex );
+    }
+
+    for( unsigned int column = 0u; column < gridWidth+1u; column++) // main strip
+    {
+      indices.PushBack( rowStartIndex + column);
+      indices.PushBack( nextRowStartIndex + column);
+    }
+
+    if( row != gridHeight-1u ) // degenerate index on non-last row
+    {
+      indices.PushBack( nextRowStartIndex + gridWidth );
+    }
+  }
+
+  Property::Map vertexFormat;
+  vertexFormat[ "aPosition" ] = Property::VECTOR2;
+  PropertyBuffer vertexPropertyBuffer = PropertyBuffer::New( vertexFormat );
+  if( vertices.Size() > 0 )
+  {
+    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 )
+  {
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+  }
+
+  geometry.SetType( Geometry::TRIANGLE_STRIP );
+
+  return geometry;
+}
+
+Image VisualFactoryCache::GetBrokenVisualImage()
+{
+  return ResourceImage::New( mBrokenImageUrl );
+}
+
+void VisualFactoryCache::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactoryCache::GetPreMultiplyOnLoad()
+{
+  return mPreMultiplyOnLoad;
+}
+
+void VisualFactoryCache::SetBrokenImageUrl(const std::string& brokenImageUrl)
+{
+  mBrokenImageUrl = brokenImageUrl;
+
+  if( !mAtlasManager )
+  {
+    mAtlasManager = new ImageAtlasManager();
+  }
+
+  mAtlasManager->SetBrokenImage( mBrokenImageUrl );
+  mTextureManager.SetBrokenImageUrl( mBrokenImageUrl );
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/visual-factory-cache.h b/dali-toolkit/internal/visuals/visual-factory-cache.h
new file mode 100644 (file)
index 0000000..e3629d3
--- /dev/null
@@ -0,0 +1,256 @@
+#ifndef DALI_TOOLKIT_VISUAL_FACTORY_CACHE_H
+#define DALI_TOOLKIT_VISUAL_FACTORY_CACHE_H
+
+/*
+ * Copyright (c) 2020 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 <dali/public-api/math/uint-16-pair.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/shader.h>
+#include <dali/devel-api/common/owner-container.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/npatch-loader.h>
+#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+class ImageAtlasManager;
+class NPatchLoader;
+class TextureManager;
+
+typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
+
+
+/**
+ * Caches shaders and geometries. Owned by VisualFactory.
+ */
+class VisualFactoryCache
+{
+public:
+
+  /**
+   * Type of shader for caching.
+   */
+  enum ShaderType
+  {
+    COLOR_SHADER,
+    COLOR_SHADER_ROUNDED_CORNER,
+    COLOR_SHADER_BLUR_EDGE,
+    BORDER_SHADER,
+    BORDER_SHADER_ANTI_ALIASING,
+    GRADIENT_SHADER_LINEAR_USER_SPACE,
+    GRADIENT_SHADER_LINEAR_BOUNDING_BOX,
+    GRADIENT_SHADER_RADIAL_USER_SPACE,
+    GRADIENT_SHADER_RADIAL_BOUNDING_BOX,
+    IMAGE_SHADER,
+    IMAGE_SHADER_ATLAS_DEFAULT_WRAP,
+    IMAGE_SHADER_ATLAS_CUSTOM_WRAP,
+    IMAGE_SHADER_ROUNDED_CORNER,
+    NINE_PATCH_SHADER,
+    NINE_PATCH_MASK_SHADER,
+    TEXT_SHADER_MULTI_COLOR_TEXT,
+    TEXT_SHADER_MULTI_COLOR_TEXT_WITH_STYLE,
+    TEXT_SHADER_SINGLE_COLOR_TEXT,
+    TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE,
+    TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_EMOJI,
+    TEXT_SHADER_SINGLE_COLOR_TEXT_WITH_STYLE_AND_EMOJI,
+    ANIMATED_GRADIENT_SHADER_LINEAR_BOUNDING_REFLECT,
+    ANIMATED_GRADIENT_SHADER_LINEAR_BOUNDING_REPEAT,
+    ANIMATED_GRADIENT_SHADER_LINEAR_BOUNDING_CLAMP,
+    ANIMATED_GRADIENT_SHADER_LINEAR_USER_REFLECT,
+    ANIMATED_GRADIENT_SHADER_LINEAR_USER_REPEAT,
+    ANIMATED_GRADIENT_SHADER_LINEAR_USER_CLAMP,
+    ANIMATED_GRADIENT_SHADER_RADIAL_BOUNDING_REFLECT,
+    ANIMATED_GRADIENT_SHADER_RADIAL_BOUNDING_REPEAT,
+    ANIMATED_GRADIENT_SHADER_RADIAL_BOUNDING_CLAMP,
+    ANIMATED_GRADIENT_SHADER_RADIAL_USER_REFLECT,
+    ANIMATED_GRADIENT_SHADER_RADIAL_USER_REPEAT,
+    ANIMATED_GRADIENT_SHADER_RADIAL_USER_CLAMP,
+    WIREFRAME_SHADER,
+    ARC_BUTT_CAP_SHADER,
+    ARC_ROUND_CAP_SHADER,
+    SHADER_TYPE_MAX = ARC_ROUND_CAP_SHADER
+  };
+
+  /**
+   * Type of geometry for caching.
+   */
+  enum GeometryType
+  {
+    QUAD_GEOMETRY,
+    BORDER_GEOMETRY,
+    NINE_PATCH_GEOMETRY,
+    NINE_PATCH_BORDER_GEOMETRY,
+    WIREFRAME_GEOMETRY,
+    GEOMETRY_TYPE_MAX = WIREFRAME_GEOMETRY
+  };
+
+public:
+
+  /**
+   * @brief Constructor
+   *
+   * @param[in] preMultiplyOnLoad True if image visuals should pre-multiply alpha on image load.
+   */
+  VisualFactoryCache( bool preMultiplyOnLoad );
+
+  /**
+   * @brief Destructor
+   */
+  ~VisualFactoryCache();
+
+  /**
+   * Request geometry of the given type.
+   * @return The geometry of the required type if it exist in the cache. Otherwise, an empty handle is returned.
+   */
+  Geometry GetGeometry( GeometryType type );
+
+  /**
+   * Cache the geometry of the give type.
+   * @param[in] type The geometry type.
+   * @param[in] geometry The geometry for caching.
+   */
+  void SaveGeometry( GeometryType type, Geometry geometry);
+
+  /**
+   * Request shader of the given type.
+   * @return The shader of the required type if it exist in the cache. Otherwise, an empty handle is returned.
+   */
+  Shader GetShader( ShaderType type );
+
+  /**
+   * Cache the geometry of the give type.
+   * @param[in] type The geometry type.
+   * @param[in] geometry The geometry for caching.
+   */
+  void SaveShader( ShaderType type, Shader shader );
+
+  /*
+   * Greate the quad geometry.
+   * Quad geometry is shared by multiple kind of Renderer, so implement it in the factory-cache.
+   */
+  static Geometry CreateQuadGeometry();
+
+  /**
+   * Create the grid geometry.
+   * @param[in] gridSize The size of the grid.
+   * @return The created grid geometry.
+   */
+  static Geometry CreateGridGeometry( Uint16Pair gridSize );
+
+  /**
+   * @brief Returns an image to be used when a visual has failed to correctly render
+   * @return The broken image handle.
+   */
+  Image GetBrokenVisualImage();
+
+  /**
+   * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+   */
+  bool GetPreMultiplyOnLoad();
+
+  /**
+   * @brief Set an image to be used when a visual has failed to correctly render
+   * @param[in] brokenImageUrl The broken image url.
+   */
+  void SetBrokenImageUrl(const std::string& brokenImageUrl);
+
+public:
+  /**
+   * Get the image atlas manager.
+   * @return A pointer to the atlas manager
+   */
+  ImageAtlasManagerPtr GetAtlasManager();
+
+  /**
+   * Get the texture manager
+   * @return A reference to the texture manager
+   */
+  TextureManager& GetTextureManager();
+
+  /**
+   * Get the N-Patch texture cache.
+   * @return A reference to the N patch loader
+   */
+  NPatchLoader& GetNPatchLoader();
+
+  /**
+   * Get the SVG rasterization thread.
+   * @return A raw pointer pointing to the SVG rasterization thread.
+   */
+  SvgRasterizeThread* GetSVGRasterizationThread();
+
+  /**
+   * Get the vector animation thread.
+   * @return A raw pointer pointing to the vector animation thread.
+   */
+  VectorAnimationThread& GetVectorAnimationThread();
+
+private: // for svg rasterization thread
+
+  /**
+   * Applies the rasterized image to material
+   */
+  void ApplyRasterizedSVGToSampler();
+
+protected:
+
+  /**
+   * Undefined copy constructor.
+   */
+  VisualFactoryCache(const VisualFactoryCache&);
+
+  /**
+   * Undefined assignment operator.
+   */
+  VisualFactoryCache& operator=(const VisualFactoryCache& rhs);
+
+private:
+  Geometry mGeometry[GEOMETRY_TYPE_MAX+1];
+  Shader mShader[SHADER_TYPE_MAX+1];
+
+  ImageAtlasManagerPtr                     mAtlasManager;
+  TextureManager                           mTextureManager;
+  NPatchLoader                             mNPatchLoader;
+  SvgRasterizeThread*                      mSvgRasterizeThread;
+  std::unique_ptr< VectorAnimationThread > mVectorAnimationThread;
+  std::string                              mBrokenImageUrl;
+  bool                                     mPreMultiplyOnLoad;
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VISUAL_FACTORY_CACHE_H
diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.cpp b/dali-toolkit/internal/visuals/visual-factory-impl.cpp
new file mode 100644 (file)
index 0000000..dc35220
--- /dev/null
@@ -0,0 +1,444 @@
+ /*
+ * Copyright (c) 2020 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 <dali-toolkit/internal/visuals/visual-factory-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/image.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/scripting/scripting.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+#include <dali-toolkit/public-api/visuals/image-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/border/border-visual.h>
+#include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/gradient/gradient-visual.h>
+#include <dali-toolkit/internal/visuals/animated-gradient/animated-gradient-visual.h>
+#include <dali-toolkit/internal/visuals/image/image-visual.h>
+#include <dali-toolkit/internal/visuals/mesh/mesh-visual.h>
+#include <dali-toolkit/internal/visuals/npatch/npatch-visual.h>
+#include <dali-toolkit/internal/visuals/primitive/primitive-visual.h>
+#include <dali-toolkit/internal/visuals/svg/svg-visual.h>
+#include <dali-toolkit/internal/visuals/text/text-visual.h>
+#include <dali-toolkit/internal/visuals/animated-image/animated-image-visual.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.h>
+#include <dali-toolkit/internal/visuals/arc/arc-visual.h>
+#include <dali-toolkit/internal/visuals/wireframe/wireframe-visual.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+BaseHandle Create()
+{
+  BaseHandle handle = Toolkit::VisualFactory::Get();
+
+  return handle;
+}
+
+DALI_TYPE_REGISTRATION_BEGIN_CREATE( Toolkit::VisualFactory, Dali::BaseHandle, Create, true )
+DALI_TYPE_REGISTRATION_END()
+const char* const BROKEN_IMAGE_FILE_NAME = "broken.png"; ///< The file name of the broken image.
+
+} // namespace
+
+VisualFactory::VisualFactory( bool debugEnabled )
+: mFactoryCache(),
+  mImageVisualShaderFactory(),
+  mSlotDelegate(this),
+  mDebugEnabled( debugEnabled ),
+  mPreMultiplyOnLoad( true )
+{
+}
+
+VisualFactory::~VisualFactory()
+{
+}
+
+void VisualFactory::OnStyleChangedSignal( Toolkit::StyleManager styleManager, StyleChange::Type type)
+{
+  if( type == StyleChange::THEME_CHANGE )
+  {
+    const std::string imageDirPath = AssetManager::GetDaliImagePath();
+    std::string brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
+
+    Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
+    config["brokenImageUrl"].Get( brokenImageUrl );
+
+    if( mFactoryCache )
+    {
+      mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
+    }
+  }
+}
+
+Toolkit::Visual::Base VisualFactory::CreateVisual( const Property::Map& propertyMap )
+{
+  Visual::BasePtr visualPtr;
+
+  Property::Value* typeValue = propertyMap.Find( Toolkit::Visual::Property::TYPE, VISUAL_TYPE );
+  Toolkit::DevelVisual::Type visualType = Toolkit::DevelVisual::IMAGE; // Default to IMAGE type.
+  if( typeValue )
+  {
+    Scripting::GetEnumerationProperty( *typeValue, VISUAL_TYPE_TABLE, VISUAL_TYPE_TABLE_COUNT, visualType );
+  }
+
+  switch( visualType )
+  {
+    case Toolkit::Visual::BORDER:
+    {
+      visualPtr = BorderVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::COLOR:
+    {
+      visualPtr = ColorVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::GRADIENT:
+    {
+      visualPtr = GradientVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::IMAGE:
+    {
+      Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+      std::string imageUrl;
+      if( imageURLValue )
+      {
+        if( imageURLValue->Get( imageUrl ) )
+        {
+          if( !imageUrl.empty() )
+          {
+            VisualUrl visualUrl( imageUrl );
+
+            switch( visualUrl.GetType() )
+            {
+              case VisualUrl::N_PATCH:
+              {
+                visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl, propertyMap );
+                break;
+              }
+              case VisualUrl::SVG:
+              {
+                visualPtr = SvgVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap );
+                break;
+              }
+              case VisualUrl::GIF:
+              {
+                visualPtr = AnimatedImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap );
+                break;
+              }
+              case VisualUrl::JSON:
+              {
+                visualPtr = AnimatedVectorImageVisual::New( GetFactoryCache(),  GetImageVisualShaderFactory(), imageUrl, propertyMap );
+                break;
+              }
+              case VisualUrl::REGULAR_IMAGE:
+              {
+                visualPtr = ImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, propertyMap );
+                break;
+              }
+            }
+          }
+        }
+        else
+        {
+          Property::Array* array = imageURLValue->GetArray();
+          if( array )
+          {
+            visualPtr = AnimatedImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), *array, propertyMap );
+          }
+        }
+      }
+      break;
+    }
+
+    case Toolkit::Visual::MESH:
+    {
+      visualPtr = MeshVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::PRIMITIVE:
+    {
+      visualPtr = PrimitiveVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::WIREFRAME:
+    {
+      visualPtr = WireframeVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::TEXT:
+    {
+      visualPtr = TextVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::Visual::N_PATCH:
+    {
+      Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+      std::string imageUrl;
+      if( imageURLValue && imageURLValue->Get( imageUrl ) )
+      {
+        visualPtr = NPatchVisual::New( GetFactoryCache(), imageUrl, propertyMap );
+      }
+      break;
+    }
+
+    case Toolkit::Visual::SVG:
+    {
+      Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+      std::string imageUrl;
+      if( imageURLValue && imageURLValue->Get( imageUrl ) )
+      {
+        visualPtr = SvgVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap );
+      }
+      break;
+    }
+
+    case Toolkit::Visual::ANIMATED_IMAGE:
+    {
+      Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+      std::string imageUrl;
+      if( imageURLValue )
+      {
+        if( imageURLValue->Get( imageUrl ) )
+        {
+          visualPtr = AnimatedImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), imageUrl, propertyMap );
+        }
+        else
+        {
+          Property::Array* array = imageURLValue->GetArray();
+          if( array )
+          {
+            visualPtr = AnimatedImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), *array, propertyMap );
+          }
+        }
+      }
+      break;
+    }
+
+    case Toolkit::DevelVisual::ANIMATED_GRADIENT:
+    {
+      visualPtr = AnimatedGradientVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+
+    case Toolkit::DevelVisual::ANIMATED_VECTOR_IMAGE:
+    {
+      Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+      std::string imageUrl;
+      if( imageURLValue && imageURLValue->Get( imageUrl ) )
+      {
+        visualPtr = AnimatedVectorImageVisual::New( GetFactoryCache(),  GetImageVisualShaderFactory(), imageUrl, propertyMap );
+      }
+      break;
+    }
+
+    case Toolkit::DevelVisual::ARC:
+    {
+      visualPtr = ArcVisual::New( GetFactoryCache(), propertyMap );
+      break;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "VisualFactory::CreateVisual( VisualType:%s %s%s)\n",
+                 Scripting::GetEnumerationName<Toolkit::DevelVisual::Type>( visualType,
+                                                                            VISUAL_TYPE_TABLE,
+                                                                            VISUAL_TYPE_TABLE_COUNT ),
+                 ( visualType == Toolkit::DevelVisual::IMAGE ) ? "url:" : "",
+                 ( visualType == Toolkit::DevelVisual::IMAGE ) ?
+                             ( ([&] (){
+                                        // Return URL if present in PropertyMap else return "not found message"
+                                        Property::Value* imageURLValue = propertyMap.Find( Toolkit::ImageVisual::Property::URL, IMAGE_URL_NAME );
+                                        return ( imageURLValue ) ? imageURLValue->Get<std::string>().c_str() : "url not found in PropertyMap";
+                                      })()
+                             )
+                             : "" );
+
+  if( !visualPtr )
+  {
+    DALI_LOG_ERROR( "VisualType unknown\n" );
+  }
+
+  if( mDebugEnabled && visualType !=  Toolkit::DevelVisual::WIREFRAME )
+  {
+    //Create a WireframeVisual if we have debug enabled
+    visualPtr = WireframeVisual::New(GetFactoryCache(), visualPtr, propertyMap );
+  }
+
+  return Toolkit::Visual::Base( visualPtr.Get() );
+}
+
+Toolkit::Visual::Base VisualFactory::CreateVisual( const Image& image )
+{
+  Visual::BasePtr visualPtr;
+
+  if( image )
+  {
+    NinePatchImage npatchImage = NinePatchImage::DownCast( image );
+    if( npatchImage )
+    {
+      visualPtr = NPatchVisual::New( GetFactoryCache(), npatchImage );
+    }
+    else
+    {
+      visualPtr = ImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), image );
+    }
+  }
+
+  if( mDebugEnabled )
+  {
+    //Create a WireframeVisual if we have debug enabled
+    visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
+  }
+
+  return Toolkit::Visual::Base( visualPtr.Get() );
+}
+
+Toolkit::Visual::Base VisualFactory::CreateVisual( const std::string& url, ImageDimensions size )
+{
+  Visual::BasePtr visualPtr;
+
+  if( !url.empty() )
+  {
+    // first resolve url type to know which visual to create
+    VisualUrl visualUrl( url );
+    switch( visualUrl.GetType() )
+    {
+      case VisualUrl::N_PATCH:
+      {
+        visualPtr = NPatchVisual::New( GetFactoryCache(), visualUrl );
+        break;
+      }
+      case VisualUrl::SVG:
+      {
+        visualPtr = SvgVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl );
+        break;
+      }
+      case VisualUrl::GIF:
+      {
+        visualPtr = AnimatedImageVisual::New( GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl );
+        break;
+      }
+      case VisualUrl::JSON:
+      {
+        visualPtr = AnimatedVectorImageVisual::New( GetFactoryCache(),  GetImageVisualShaderFactory(), visualUrl );
+        break;
+      }
+      case VisualUrl::REGULAR_IMAGE:
+      {
+        visualPtr = ImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size );
+        break;
+      }
+    }
+  }
+
+  if( mDebugEnabled )
+  {
+    //Create a WireframeVisual if we have debug enabled
+    visualPtr = WireframeVisual::New( GetFactoryCache(), visualPtr );
+  }
+
+  return Toolkit::Visual::Base( visualPtr.Get() );
+}
+
+void VisualFactory::SetPreMultiplyOnLoad( bool preMultiply )
+{
+  if( mPreMultiplyOnLoad != preMultiply )
+  {
+    GetFactoryCache().SetPreMultiplyOnLoad( preMultiply );
+  }
+  mPreMultiplyOnLoad = preMultiply;
+}
+
+bool VisualFactory::GetPreMultiplyOnLoad() const
+{
+  return mPreMultiplyOnLoad;
+}
+
+Internal::TextureManager& VisualFactory::GetTextureManager()
+{
+  return GetFactoryCache().GetTextureManager();
+}
+
+Internal::VisualFactoryCache& VisualFactory::GetFactoryCache()
+{
+  if( !mFactoryCache )
+  {
+    mFactoryCache = std::unique_ptr<VisualFactoryCache>( new VisualFactoryCache( mPreMultiplyOnLoad ) );
+
+    const std::string imageDirPath = AssetManager::GetDaliImagePath();
+    std::string brokenImageUrl = imageDirPath + BROKEN_IMAGE_FILE_NAME;
+
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
+      config["brokenImageUrl"].Get( brokenImageUrl );
+      styleManager.StyleChangedSignal().Connect( mSlotDelegate, &VisualFactory::OnStyleChangedSignal );
+    }
+
+    mFactoryCache->SetBrokenImageUrl(brokenImageUrl);
+  }
+  return *mFactoryCache;
+}
+
+ImageVisualShaderFactory& VisualFactory::GetImageVisualShaderFactory()
+{
+  if( !mImageVisualShaderFactory )
+  {
+    mImageVisualShaderFactory = std::unique_ptr< ImageVisualShaderFactory >( new ImageVisualShaderFactory() );
+  }
+  return *mImageVisualShaderFactory;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/visual-factory-impl.h b/dali-toolkit/internal/visuals/visual-factory-impl.h
new file mode 100644 (file)
index 0000000..0e4dcb4
--- /dev/null
@@ -0,0 +1,196 @@
+#ifndef DALI_TOOLKIT_VISUAL_FACTORY_IMPL_H
+#define DALI_TOOLKIT_VISUAL_FACTORY_IMPL_H
+
+/*
+ * Copyright (c) 2017 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 <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
+#include <dali-toolkit/devel-api/visual-factory/visual-base.h>
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
+#include <dali-toolkit/devel-api/styling/style-manager-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class VisualFactoryCache;
+class ImageVisualShaderFactory;
+
+/**
+ * @copydoc Toolkit::VisualFactory
+ */
+class VisualFactory : public BaseObject
+{
+public:
+
+  /**
+   * @brief Constructor
+   *
+   * @param[in] debugEnabled If true, use debug renderer to replace all the concrete renderer.
+   */
+  VisualFactory( bool debugEnabled );
+
+  /**
+   * @brief StyleChanged callback
+   *
+   * @param[in] styleManager Handle for style manager.
+   * @param[in] type Style change type.
+   */
+  void OnStyleChangedSignal( Toolkit::StyleManager styleManager, StyleChange::Type type );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const Property::Map& )
+   */
+  Toolkit::Visual::Base CreateVisual( const Property::Map& propertyMap );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const Image& )
+   */
+  Toolkit::Visual::Base CreateVisual( const Image& image );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::CreateVisual( const std::string&, ImageDimensions )
+   */
+  Toolkit::Visual::Base CreateVisual( const std::string& image, ImageDimensions size );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::SetPreMultiplyOnLoad()
+   */
+  void SetPreMultiplyOnLoad( bool preMultiply );
+
+  /**
+   * @copydoc Toolkit::VisualFactory::GetPreMultiplyOnLoad()
+   */
+  bool GetPreMultiplyOnLoad() const;
+
+  /**
+   * @return the reference to texture manager
+   */
+  Internal::TextureManager& GetTextureManager();
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~VisualFactory();
+
+private:
+  /**
+   * Get the factory cache, creating it if necessary.
+   */
+  Internal::VisualFactoryCache& GetFactoryCache();
+
+  /**
+   * Get the image visual shader factory, creating it if necessary.
+   */
+  ImageVisualShaderFactory& GetImageVisualShaderFactory();
+
+  VisualFactory(const VisualFactory&) = delete;
+
+  VisualFactory& operator=(const VisualFactory& rhs) = delete;
+
+private:
+  std::unique_ptr< VisualFactoryCache >       mFactoryCache;
+  std::unique_ptr< ImageVisualShaderFactory > mImageVisualShaderFactory;
+  SlotDelegate< VisualFactory >               mSlotDelegate;
+  bool                                        mDebugEnabled:1;
+  bool                                        mPreMultiplyOnLoad:1; ///< Local store for this flag
+};
+
+/**
+ * @brief Template to allow discard old visual, get new one and set it on stage if possible
+ *
+ * @tparam ParameterType0 The type of first argument passed to the CreateVisual()
+ * @tparam ParameterType1 The type of second argument passed to the CreateVisual()
+ * @SINCE_1_0.39
+ * @param[in] actor Actor for which the visual will be replaced
+ * @param[in,out] visual The visual to be replaced
+ * @param[in] param0 First template based argument passed to the visual factory
+ * @param[in] param1 Second template based argument passed to the visual factory
+ */
+template< class ParameterType0, class ParameterType1 >
+void InitializeVisual( Actor& actor, Toolkit::Visual::Base& visual, ParameterType0& param0, ParameterType1& param1 )
+{
+  if( actor )
+  {
+    Toolkit::GetImplementation(visual).SetOffStage( actor );
+  }
+  visual = Toolkit::VisualFactory::Get().CreateVisual( param0, param1 );
+  if( visual && actor && actor.OnStage() )
+  {
+    Toolkit::GetImplementation(visual).SetOnStage(actor);
+  }
+}
+
+/**
+ * @brief Template to allow discard old visual, get new one and set it on stage if possible
+ *
+ * @tparam ParameterType The type of argument passed to the CreateVisual()
+ * @SINCE_1_0.39
+ * @param[in] actor Actor for which the visual will be replaced
+ * @param[in,out] visual The visual to be replaced
+ * @param[in] param Template based argument passed to the visual factory
+ */
+template< class ParameterType >
+void InitializeVisual( Actor& actor, Toolkit::Visual::Base& visual, ParameterType& param )
+{
+  if( actor && visual )
+  {
+    Toolkit::GetImplementation(visual).SetOffStage( actor );
+  }
+  visual =  Toolkit::VisualFactory::Get().CreateVisual( param );
+  if( visual && actor && actor.OnStage() )
+  {
+    Toolkit::GetImplementation(visual).SetOnStage(actor);
+  }
+}
+
+} // namespace Internal
+
+inline const Internal::VisualFactory& GetImplementation(const Toolkit::VisualFactory& factory)
+{
+  DALI_ASSERT_ALWAYS( factory && "VisualFactory handle is empty" );
+
+  const BaseObject& handle = factory.GetBaseObject();
+
+  return static_cast<const Internal::VisualFactory&>(handle);
+}
+
+inline Internal::VisualFactory& GetImplementation(Toolkit::VisualFactory& factory)
+{
+  DALI_ASSERT_ALWAYS( factory && "VisualFactory handle is empty" );
+
+  BaseObject& handle = factory.GetBaseObject();
+
+  return static_cast<Internal::VisualFactory&>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_VISUAL_FACTORY_IMPL_H */
diff --git a/dali-toolkit/internal/visuals/visual-string-constants.cpp b/dali-toolkit/internal/visuals/visual-string-constants.cpp
new file mode 100644 (file)
index 0000000..293628e
--- /dev/null
@@ -0,0 +1,225 @@
+ /*
+ * Copyright (c) 2020 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 "visual-string-constants.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( VISUAL_TYPE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, BORDER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, GRADIENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, IMAGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, MESH )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, PRIMITIVE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, TEXT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, N_PATCH )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, SVG )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, ANIMATED_IMAGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::Visual, WIREFRAME )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelVisual, ANIMATED_GRADIENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelVisual, ANIMATED_VECTOR_IMAGE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::DevelVisual, ARC )
+DALI_ENUM_TO_STRING_TABLE_END( VISUAL_TYPE )
+
+// Visual Type
+const char * const VISUAL_TYPE( "visualType" );
+
+// Custom shader
+const char * const CUSTOM_SHADER( "shader" );
+const char * const CUSTOM_VERTEX_SHADER( "vertexShader" );
+const char * const CUSTOM_FRAGMENT_SHADER( "fragmentShader" );
+const char * const CUSTOM_SUBDIVIDE_GRID_X( "subdivideGridX" );
+const char * const CUSTOM_SUBDIVIDE_GRID_Y( "subdivideGridY" );
+const char * const CUSTOM_SHADER_HINTS( "hints" );
+
+// Transform
+const char * const TRANSFORM( "transform" );
+const char * const SIZE( "size" );
+const char * const OFFSET( "offset" );
+const char * const OFFSET_SIZE_MODE( "offsetSizeMode" );
+const char * const ORIGIN( "origin" );
+const char * const ANCHOR_POINT( "anchorPoint" );
+const char * const EXTRA_SIZE( "extraSize" );
+
+// Premultipled alpha
+const char * const PREMULTIPLIED_ALPHA( "premultipliedAlpha" );
+
+// Mix color
+const char * const MIX_COLOR( "mixColor" );
+const char * const OPACITY( "opacity" );
+
+// Fitting mode
+const char * const VISUAL_FITTING_MODE( "visualFittingMode" );
+
+// Corner radius
+const char * const CORNER_RADIUS( "cornerRadius" );
+
+// Color visual
+const char * const RENDER_IF_TRANSPARENT_NAME( "renderIfTransparent" );
+const char * const BLUR_RADIUS_NAME( "blurRadius" );
+
+// Image visual
+const char * const IMAGE_URL_NAME( "url" );
+const char * const ATLAS_RECT_UNIFORM_NAME( "uAtlasRect" );
+const char * const PIXEL_AREA_UNIFORM_NAME( "pixelArea" );
+const char * const WRAP_MODE_UNIFORM_NAME( "wrapMode" );
+const char * const IMAGE_WRAP_MODE_U("wrapModeU");
+const char * const IMAGE_WRAP_MODE_V("wrapModeV");
+const char * const IMAGE_BORDER( "border" );
+const char * const PIXEL_ALIGNED_UNIFORM_NAME( "uPixelAligned" );
+const char * const ANIMATED_IMAGE_URLS_NAME("urls");
+const char * const BATCH_SIZE_NAME("batchSize");
+const char * const CACHE_SIZE_NAME("cacheSize");
+const char * const FRAME_DELAY_NAME("frameDelay");
+const char * const LOOP_COUNT_NAME("loopCount");
+const char * const MASK_CONTENT_SCALE_NAME("maskContentScale");
+const char * const CROP_TO_MASK_NAME("cropToMask");
+const char * const LOAD_POLICY_NAME("loadPolicy");
+const char * const RELEASE_POLICY_NAME("releasePolicy");
+const char * const ORIENTATION_CORRECTION_NAME("orientationCorrection");
+const char * const AUXILIARY_IMAGE_NAME("auxiliaryImage");
+const char * const AUXILIARY_IMAGE_ALPHA_NAME("auxiliaryImageAlpha");
+const char * const PLAY_RANGE_NAME( "playRange" );
+const char * const PLAY_STATE_NAME( "playState" );
+const char * const CURRENT_FRAME_NUMBER_NAME( "currentFrameNumber" );
+const char * const TOTAL_FRAME_NUMBER_NAME( "totalFrameNumber" );
+const char * const STOP_BEHAVIOR_NAME( "stopBehavior" );
+const char * const LOOPING_MODE_NAME( "loopingMode" );
+const char * const IMAGE_ATLASING( "atlasing" );
+const char * const SYNCHRONOUS_LOADING( "synchronousLoading" );
+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" );
+const char * const ALPHA_MASK_URL("alphaMaskUrl");
+
+// Text visual
+const char * const TEXT_PROPERTY( "text" );
+const char * const FONT_FAMILY_PROPERTY( "fontFamily" );
+const char * const FONT_STYLE_PROPERTY( "fontStyle" );
+const char * const POINT_SIZE_PROPERTY( "pointSize" );
+const char * const MULTI_LINE_PROPERTY( "multiLine" );
+const char * const HORIZONTAL_ALIGNMENT_PROPERTY( "horizontalAlignment" );
+const char * const VERTICAL_ALIGNMENT_PROPERTY( "verticalAlignment" );
+const char * const TEXT_COLOR_PROPERTY( "textColor" );
+const char * const ENABLE_MARKUP_PROPERTY( "enableMarkup" );
+const char * const SHADOW_PROPERTY( "shadow" );
+const char * const UNDERLINE_PROPERTY( "underline" );
+const char * const OUTLINE_PROPERTY( "outline" );
+const char * const BACKGROUND_PROPERTY( "textBackground" );
+
+
+//NPatch visual
+const char * const BORDER_ONLY( "borderOnly" );
+const char * const BORDER( "border" );
+
+// non-animated property
+const char* const GRADIENT_TYPE_NAME("gradientType");
+const char* const UNIT_TYPE_NAME("unitType");
+const char* const SPREAD_TYPE_NAME("spreadType");
+
+// animated property
+const char* const START_POSITION_NAME("startPosition");
+const char* const START_COLOR_NAME("startColor");
+const char* const END_POSITION_NAME("endPosition");
+const char* const END_COLOR_NAME("endColor");
+const char* const ROTATE_CENTER_NAME("rotateCenter");
+const char* const ROTATE_AMOUNT_NAME("rotateAmount");
+const char* const OFFSET_NAME("offset");
+
+// animation parameter property
+const char* const START_VALUE_NAME("startValue");
+const char* const TARGET_VALUE_NAME("targetValue");
+const char* const DIRECTION_TYPE_NAME("directionType");
+const char* const DURATION_NAME("duration");
+const char* const DELAY_NAME("delay");
+const char* const REPEAT_NAME("repeat");
+const char* const REPEAT_DELAY_NAME("repeatDelay");
+const char* const MOTION_TYPE_NAME("motionType");
+const char* const EASING_TYPE_NAME("easingType");
+
+// common shader property
+const char* const UNIFORM_START_POINT_NAME("start_point");
+const char* const UNIFORM_START_COLOR_NAME("start_color");
+const char* const UNIFORM_END_POINT_NAME("end_point");
+const char* const UNIFORM_END_COLOR_NAME("end_color");
+const char* const UNIFORM_ROTATE_CENTER_NAME("rotate_center");
+const char* const UNIFORM_ROTATE_ANGLE_NAME("rotate_angle");
+const char* const UNIFORM_OFFSET_NAME("gradient_offset");
+
+// Border visual
+const char * const COLOR_NAME("borderColor");
+const char * const SIZE_NAME("borderSize");
+const char * const ANTI_ALIASING("antiAliasing");
+
+// properties: radial gradient
+const char * const CENTER_NAME("center"); // Property::VECTOR2
+const char * const RADIUS_NAME("radius"); // Property::FLOAT
+
+// properties: linear&radial gradient
+const char * const STOP_OFFSET_NAME("stopOffset"); // Property::Array FLOAT
+const char * const STOP_COLOR_NAME("stopColor"); // Property::Array VECTOR4
+const char * const UNITS_NAME("units"); // Property::String  "userSpaceOnUse | objectBoundingBox"
+const char * const SPREAD_METHOD_NAME("spreadMethod"); // Property::String  "pad | reflect | repeat"
+
+//mesh visual
+const char * const OBJECT_URL_NAME( "objectUrl" );
+const char * const MATERIAL_URL_NAME( "materialUrl" );
+const char * const TEXTURES_PATH_NAME( "texturesPath" );
+const char * const SHADING_MODE_NAME( "shadingMode" );
+const char * const USE_MIPMAPPING_NAME( "useMipmapping" );
+const char * const USE_SOFT_NORMALS_NAME( "useSoftNormals" );
+const char * const LIGHT_POSITION_NAME( "lightPosition" );
+
+
+//Primitive properties
+const char * const PRIMITIVE_SHAPE( "shape" );
+const char * const SLICES( "slices" );
+const char * const STACKS( "stacks" );
+const char * const SCALE_TOP_RADIUS( "scaleTopRadius" );
+const char * const SCALE_BOTTOM_RADIUS( "scaleBottomRadius" );
+const char * const SCALE_HEIGHT( "scaleHeight" );
+const char * const SCALE_RADIUS( "scaleRadius" );
+const char * const SCALE_DIMENSIONS( "scaleDimensions" );
+const char * const BEVEL_PERCENTAGE( "bevelPercentage" );
+const char * const BEVEL_SMOOTHNESS( "bevelSmoothness" );
+const char * const LIGHT_POSITION_UNIFORM_NAME( "lightPosition" );
+
+// Arc visual
+const char * const THICKNESS_NAME( "thickness" );
+const char * const START_ANGLE_NAME( "startAngle" );
+const char * const SWEEP_ANGLE_NAME( "sweepAngle" );
+const char * const CAP_NAME( "cap" );
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/visual-string-constants.h b/dali-toolkit/internal/visuals/visual-string-constants.h
new file mode 100644 (file)
index 0000000..d402e7f
--- /dev/null
@@ -0,0 +1,211 @@
+#ifndef DALI_TOOLKIT_INTERNAL_VISUAL_STRING_CONSTANTS_H
+#define DALI_TOOLKIT_INTERNAL_VISUAL_STRING_CONSTANTS_H
+
+/*
+ * Copyright (c) 2020 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 <dali/devel-api/scripting/enum-helper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+// Visual type
+extern const char * const VISUAL_TYPE;
+extern const Dali::Scripting::StringEnum VISUAL_TYPE_TABLE[];
+extern const unsigned int VISUAL_TYPE_TABLE_COUNT;
+
+// Custom shader
+extern const char * const CUSTOM_SHADER;
+extern const char * const CUSTOM_VERTEX_SHADER;
+extern const char * const CUSTOM_FRAGMENT_SHADER;
+extern const char * const CUSTOM_SUBDIVIDE_GRID_X;
+extern const char * const CUSTOM_SUBDIVIDE_GRID_Y;
+extern const char * const CUSTOM_SHADER_HINTS;
+
+// Transform
+extern const char * const TRANSFORM;
+extern const char * const SIZE;
+extern const char * const OFFSET;
+extern const char * const OFFSET_SIZE_MODE;
+extern const char * const ORIGIN;
+extern const char * const ANCHOR_POINT;
+extern const char * const EXTRA_SIZE;
+
+// Premultiplied alpha
+extern const char * const PREMULTIPLIED_ALPHA;
+
+// Mix color
+extern const char * const MIX_COLOR;
+extern const char * const OPACITY;
+
+// Fitting mode
+extern const char * const VISUAL_FITTING_MODE;
+
+// Corner radius
+extern const char * const CORNER_RADIUS;
+
+// Color visual
+extern const char * const RENDER_IF_TRANSPARENT_NAME;
+extern const char * const BLUR_RADIUS_NAME;
+
+// Image visual
+extern const char * const IMAGE_URL_NAME;
+extern const char * const ATLAS_RECT_UNIFORM_NAME;
+extern const char * const PIXEL_AREA_UNIFORM_NAME;
+extern const char * const WRAP_MODE_UNIFORM_NAME;
+extern const char * const IMAGE_WRAP_MODE_U;
+extern const char * const IMAGE_WRAP_MODE_V;
+extern const char * const IMAGE_BORDER;
+extern const char * const PIXEL_ALIGNED_UNIFORM_NAME;
+extern const char * const ANIMATED_IMAGE_URLS_NAME;
+extern const char * const BATCH_SIZE_NAME;
+extern const char * const CACHE_SIZE_NAME;
+extern const char * const FRAME_DELAY_NAME;
+extern const char * const LOOP_COUNT_NAME;
+extern const char * const MASK_CONTENT_SCALE_NAME;
+extern const char * const CROP_TO_MASK_NAME;
+extern const char * const LOAD_POLICY_NAME;
+extern const char * const RELEASE_POLICY_NAME;
+extern const char * const ORIENTATION_CORRECTION_NAME;
+extern const char * const AUXILLARY_IMAGE_NAME;
+extern const char * const AUXILLARY_IMAGE_ALPHA_NAME;
+extern const char * const PLAY_RANGE_NAME;
+extern const char * const PLAY_STATE_NAME;
+extern const char * const CURRENT_FRAME_NUMBER_NAME;
+extern const char * const TOTAL_FRAME_NUMBER_NAME;
+extern const char * const STOP_BEHAVIOR_NAME;
+extern const char * const LOOPING_MODE_NAME;
+extern const char * const IMAGE_ATLASING;
+extern const char * const SYNCHRONOUS_LOADING;
+extern const char * const IMAGE_FITTING_MODE;
+extern const char * const IMAGE_SAMPLING_MODE;
+extern const char * const IMAGE_DESIRED_WIDTH;
+extern const char * const IMAGE_DESIRED_HEIGHT;
+extern const char * const ALPHA_MASK_URL;
+
+// Text visual
+extern const char * const TEXT_PROPERTY;
+extern const char * const FONT_FAMILY_PROPERTY;
+extern const char * const FONT_STYLE_PROPERTY;
+extern const char * const POINT_SIZE_PROPERTY;
+extern const char * const MULTI_LINE_PROPERTY;
+extern const char * const HORIZONTAL_ALIGNMENT_PROPERTY;
+extern const char * const VERTICAL_ALIGNMENT_PROPERTY;
+extern const char * const TEXT_COLOR_PROPERTY;
+extern const char * const ENABLE_MARKUP_PROPERTY;
+extern const char * const SHADOW_PROPERTY;
+extern const char * const UNDERLINE_PROPERTY;
+extern const char * const OUTLINE_PROPERTY;
+extern const char * const BACKGROUND_PROPERTY;
+
+//NPatch visual
+extern const char * const BORDER_ONLY;
+extern const char * const BORDER;
+extern const char * const AUXILIARY_IMAGE_NAME;
+extern const char * const AUXILIARY_IMAGE_ALPHA_NAME;
+
+// non-animated property
+extern const char* const GRADIENT_TYPE_NAME;
+extern const char* const UNIT_TYPE_NAME;
+extern const char* const SPREAD_TYPE_NAME;
+
+// animated property
+extern const char* const START_POSITION_NAME;
+extern const char* const START_COLOR_NAME;
+extern const char* const END_POSITION_NAME;
+extern const char* const END_COLOR_NAME;
+extern const char* const ROTATE_CENTER_NAME;
+extern const char* const ROTATE_AMOUNT_NAME;
+extern const char* const OFFSET_NAME;
+
+// animation parameter property
+extern const char* const START_VALUE_NAME;
+extern const char* const TARGET_VALUE_NAME;
+extern const char* const DIRECTION_TYPE_NAME;
+extern const char* const DURATION_NAME;
+extern const char* const DELAY_NAME;
+extern const char* const REPEAT_NAME;
+extern const char* const REPEAT_DELAY_NAME;
+extern const char* const MOTION_TYPE_NAME;
+extern const char* const EASING_TYPE_NAME;
+
+// common shader property
+extern const char* const UNIFORM_START_POINT_NAME;
+extern const char* const UNIFORM_START_COLOR_NAME;
+extern const char* const UNIFORM_END_POINT_NAME;
+extern const char* const UNIFORM_END_COLOR_NAME;
+extern const char* const UNIFORM_ROTATE_CENTER_NAME;
+extern const char* const UNIFORM_ROTATE_ANGLE_NAME;
+extern const char* const UNIFORM_OFFSET_NAME;
+
+// Border visual
+extern const char * const COLOR_NAME;
+extern const char * const SIZE_NAME;
+extern const char * const ANTI_ALIASING;
+
+// properties: radial gradient
+extern const char * const CENTER_NAME; // Property::VECTOR2
+extern const char * const RADIUS_NAME; // Property::FLOAT
+
+// properties: linear&radial gradient
+extern const char * const STOP_OFFSET_NAME; // Property::Array FLOAT
+extern const char * const STOP_COLOR_NAME; // Property::Array VECTOR4
+extern const char * const UNITS_NAME; // Property::String  "userSpaceOnUse | objectBoundingBox"
+extern const char * const SPREAD_METHOD_NAME; // Property::String  "pad | reflect | repeat"
+
+//mesh visual
+extern const char * const OBJECT_URL_NAME;
+extern const char * const MATERIAL_URL_NAME;
+extern const char * const TEXTURES_PATH_NAME;
+extern const char * const SHADING_MODE_NAME;
+extern const char * const USE_MIPMAPPING_NAME;
+extern const char * const USE_SOFT_NORMALS_NAME;
+extern const char * const LIGHT_POSITION_NAME;
+
+//Primitive properties
+extern const char * const PRIMITIVE_SHAPE;
+extern const char * const SLICES;
+extern const char * const STACKS;
+extern const char * const SCALE_TOP_RADIUS;
+extern const char * const SCALE_BOTTOM_RADIUS;
+extern const char * const SCALE_HEIGHT;
+extern const char * const SCALE_RADIUS;
+extern const char * const SCALE_DIMENSIONS;
+extern const char * const BEVEL_PERCENTAGE;
+extern const char * const BEVEL_SMOOTHNESS;
+extern const char * const LIGHT_POSITION_UNIFORM_NAME;
+
+// Arc visual
+extern const char * const THICKNESS_NAME;
+extern const char * const START_ANGLE_NAME;
+extern const char * const SWEEP_ANGLE_NAME;
+extern const char * const CAP_NAME;
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_VISUAL_STRING_CONSTANTS_H */
diff --git a/dali-toolkit/internal/visuals/visual-url.cpp b/dali-toolkit/internal/visuals/visual-url.cpp
new file mode 100644 (file)
index 0000000..731ed20
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/internal/visuals/visual-url.h>
+
+// EXTERNAL HEADERS
+#include <cstring> // for toupper()
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+namespace
+{
+
+VisualUrl::ProtocolType ResolveLocation( const std::string& url )
+{
+  const char* urlCStr = url.c_str();
+  const uint32_t length = url.size();
+  if( ( length > 7 ) && urlCStr[5] == ':' && urlCStr[6] == '/' && urlCStr[7] == '/' )
+  {
+    // https://
+    if( ( 'h' == tolower( urlCStr[0] ) )&&
+        ( 't' == tolower( urlCStr[1] ) )&&
+        ( 't' == tolower( urlCStr[2] ) )&&
+        ( 'p' == tolower( urlCStr[3] ) )&&
+        ( 's' == tolower( urlCStr[4] ) ) )
+    {
+      return VisualUrl::REMOTE;
+    }
+  }
+  else if( ( length > 6 ) && urlCStr[4] == ':' && urlCStr[5] == '/' && urlCStr[6] == '/' )
+  {
+    // http:// or dali://
+    const char hOrd = tolower( urlCStr[0] );
+    const char tOra = tolower( urlCStr[1] );
+    const char tOrl = tolower( urlCStr[2] );
+    const char pOri = tolower( urlCStr[3] );
+    if( ( 'h' == hOrd )&&
+        ( 't' == tOra )&&
+        ( 't' == tOrl )&&
+        ( 'p' == pOri ) )
+    {
+      return VisualUrl::REMOTE;
+    }
+    if( ( 'd' == hOrd )&&
+        ( 'a' == tOra )&&
+        ( 'l' == tOrl )&&
+        ( 'i' == pOri ) )
+    {
+      return VisualUrl::TEXTURE;
+    }
+  }
+  else if( ( length > 5 ) && urlCStr[3] == ':' && urlCStr[4] == '/' && urlCStr[5] == '/' )
+  {
+    // ftp:// or ssh://
+    const char fOrS = tolower( urlCStr[0] );
+    if( ( 'f' == fOrS )||( 's' == fOrS ) )
+    {
+      const char tOrs = tolower( urlCStr[1] );
+      if( ( 't' == tOrs )||( 's' == tOrs ) )
+      {
+        const char pOrh = tolower( urlCStr[2] );
+        if( ( 'p' == pOrh )||( 'h' == pOrh ) )
+        {
+          return VisualUrl::REMOTE;
+        }
+      }
+    }
+  }
+  return VisualUrl::LOCAL;
+}
+
+
+VisualUrl::Type ResolveType( const std::string& url )
+{
+  // if only one char in string, can only be regular image
+  const std::size_t count = url.size();
+  if( count > 0 )
+  {
+    // parsing from the end for better chance of early outs
+    enum { SUFFIX, HASH, HASH_DOT } state = SUFFIX;
+    char SVG[ 4 ] = { 'g', 'v', 's', '.' };
+    char GIF[ 4 ] = { 'f', 'i', 'g', '.' };
+    char JSON[ 5 ] = { 'n', 'o', 's', 'j', '.' };
+    unsigned int svgScore = 0;
+    unsigned int gifScore = 0;
+    unsigned int jsonScore = 0;
+    int index = count;
+    while( --index >= 0 )
+    {
+      const char currentChar = tolower( url[ index ] );
+      const std::size_t offsetFromEnd = count - index - 1u;
+      if( ( offsetFromEnd < sizeof(SVG) )&&( currentChar == SVG[ offsetFromEnd ] ) )
+      {
+        // early out if SVG as can't be used in N patch for now
+        if( ++svgScore == sizeof(SVG) )
+        {
+          return VisualUrl::SVG;
+        }
+      }
+      if( ( offsetFromEnd < sizeof(GIF) )&&( currentChar == GIF[ offsetFromEnd ] ) )
+      {
+        // early out if GIF as can't be used in N patch for now
+        if( ++gifScore == sizeof(GIF) )
+        {
+          return VisualUrl::GIF;
+        }
+      }
+      if( ( offsetFromEnd < sizeof(JSON) )&&( currentChar == JSON[ offsetFromEnd ] ) )
+      {
+        // early out if JSON as can't be used in N patch for now
+        if( ++jsonScore == sizeof(JSON) )
+        {
+          return VisualUrl::JSON;
+        }
+      }
+      switch( state )
+      {
+        case SUFFIX:
+        {
+          if( '.' == currentChar )
+          {
+            state = HASH;
+          }
+          break;
+        }
+        case HASH:
+        {
+          if( ( '#' == currentChar ) || ( '9' == currentChar ) )
+          {
+            state = HASH_DOT;
+          }
+          else
+          {
+            // early out, not a valid N/9-patch URL
+            return VisualUrl::REGULAR_IMAGE;
+          }
+          break;
+        }
+        case HASH_DOT:
+        {
+          if( '.' == currentChar )
+          {
+            return VisualUrl::N_PATCH;
+          }
+          else
+          {
+            // early out, not a valid N/9-patch URL
+            return VisualUrl::REGULAR_IMAGE;
+          }
+          break;
+        }
+      }
+    }
+  }
+  // if we got here it is a regular image
+  return VisualUrl::REGULAR_IMAGE;
+}
+
+}
+
+
+VisualUrl::VisualUrl()
+: mUrl(),
+  mType( VisualUrl::REGULAR_IMAGE ),
+  mLocation( VisualUrl::LOCAL )
+{
+}
+
+VisualUrl::VisualUrl( const std::string& url )
+: mUrl( url ),
+  mType( VisualUrl::REGULAR_IMAGE ),
+  mLocation( VisualUrl::LOCAL )
+{
+  if( ! url.empty() )
+  {
+    mLocation = ResolveLocation( url );
+    if( VisualUrl::TEXTURE != mLocation )
+    {
+      // TEXTURE location url doesn't need type resolving, REGULAR_IMAGE is fine
+      mType = ResolveType( url );
+    }
+  }
+}
+
+VisualUrl::VisualUrl( const VisualUrl& url )
+: mUrl( url.mUrl ),
+  mType( url.mType ),
+  mLocation( url.mLocation )
+{
+}
+
+VisualUrl& VisualUrl::operator=( const VisualUrl& url )
+{
+  if( &url != this )
+  {
+    mUrl = url.mUrl;
+    mType = url.mType;
+    mLocation = url.mLocation;
+  }
+  return *this;
+}
+
+const std::string& VisualUrl::GetUrl() const
+{
+  return mUrl;
+}
+
+VisualUrl::Type VisualUrl::GetType() const
+{
+  return mType;
+}
+
+VisualUrl::ProtocolType VisualUrl::GetProtocolType() const
+{
+  return mLocation;
+}
+
+bool VisualUrl::IsValid() const
+{
+  return mUrl.size() > 0u;
+}
+
+bool VisualUrl::IsLocalResource() const
+{
+  return mLocation == VisualUrl::LOCAL;
+}
+
+std::string VisualUrl::GetLocation() const
+{
+  const auto location = mUrl.find( "://" );
+  if( std::string::npos != location )
+  {
+    return mUrl.substr( location + 3u ); // 3 characters forwards from the start of ://
+  }
+  return mUrl;
+}
+
+std::string VisualUrl::CreateTextureUrl( const std::string& location )
+{
+  return "dali://" + location;
+}
+
+} // Internal
+
+} // Toolkit
+
+} // Dali
diff --git a/dali-toolkit/internal/visuals/visual-url.h b/dali-toolkit/internal/visuals/visual-url.h
new file mode 100644 (file)
index 0000000..f3af2e0
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef DALI_TOOLKIT_INTERNAL_VISUAL_URL_H
+#define DALI_TOOLKIT_INTERNAL_VISUAL_URL_H
+
+/*
+ * Copyright (c) 2017 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>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class VisualUrl
+{
+public:
+
+  /**
+   * The type of the URL based on the string contents
+   */
+  enum Type
+  {
+    REGULAR_IMAGE,
+    N_PATCH,
+    SVG,
+    GIF,
+    JSON
+  };
+
+  enum ProtocolType
+  {
+    LOCAL,   ///< file in local file system
+    TEXTURE, ///< texture uploaded to texture manager
+    REMOTE   ///< remote image
+  };
+
+  /**
+   * Default Constructor.
+   * Resulting URL is not valid
+   */
+  VisualUrl();
+
+  /**
+   * Constructor.
+   * Determines type of visual and whether the url is local or remote
+   * @param[in] url The URL to store and resolve
+   */
+  VisualUrl( const std::string& url );
+
+  /**
+   * Copy constructor
+   * @param[in] url The VisualUrl to copy
+   */
+  VisualUrl( const VisualUrl& url );
+
+  /**
+   * Assignment operator
+   * @param[in] url The VisualUrl to copy
+   */
+  VisualUrl& operator=( const VisualUrl& url );
+
+  /**
+   * Get the full URL
+   * @return The url
+   */
+  const std::string& GetUrl() const;
+
+  /**
+   * Get the visual type of the URL
+   * @return The visual type of the URL
+   */
+  Type GetType() const;
+
+  /**
+   * Is the URL is local to the device, or remote?
+   * @return the location of the resource
+   */
+  ProtocolType GetProtocolType() const;
+
+  /**
+   * Is the URL valid?
+   * @return true if the URL has length
+   */
+  bool IsValid() const;
+
+  /**
+   * @return true if the location is LOCAL, i.e. is loadable from local file system
+   */
+  bool IsLocalResource() const;
+
+  /**
+   * @return the location part of the url
+   */
+  std::string GetLocation() const;
+
+  /**
+   * Helper to create a URL of type TEXTURE
+   * @param location the location of the texture
+   * @return the Url
+   */
+  static std::string CreateTextureUrl( const std::string& location );
+
+private:
+  std::string mUrl;
+  Type mType;
+  ProtocolType mLocation;
+};
+
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* DALI_TOOLKIT_INTERNAL_VISUAL_URL_H */
diff --git a/dali-toolkit/internal/visuals/wireframe/wireframe-visual.cpp b/dali-toolkit/internal/visuals/wireframe/wireframe-visual.cpp
new file mode 100644 (file)
index 0000000..1202d1c
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2018 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 "wireframe-visual.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/internal/visuals/visual-factory-impl.h>
+#include <dali-toolkit/internal/visuals/visual-factory-cache.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+const char * const POSITION_ATTRIBUTE_NAME("aPosition");
+const char * const INDEX_NAME("indices");
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+attribute mediump vec2  aPosition;\n
+uniform   highp   mat4  uMvpMatrix;\n
+uniform   mediump vec3  uSize;\n
+\n
+
+//Visual size and offset
+uniform mediump vec2 offset;\n
+uniform mediump vec2 size;\n
+uniform mediump vec4 offsetSizeMode;\n
+uniform mediump vec2 origin;\n
+uniform mediump vec2 anchorPoint;\n
+
+vec4 ComputeVertexPosition()\n
+{\n
+  vec2 visualSize = mix(uSize.xy*size, size, offsetSizeMode.zw );\n
+  vec2 visualOffset = mix( offset, offset/uSize.xy, offsetSizeMode.xy);\n
+  return vec4( (aPosition + anchorPoint)*visualSize + (visualOffset + origin)*uSize.xy, 0.0, 1.0 );\n
+}\n
+
+void main()\n
+{\n
+  gl_Position = uMvpMatrix * ComputeVertexPosition();\n
+}\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(\n
+  uniform lowp vec4 uColor;\n
+  uniform lowp vec3 mixColor;\n
+\n
+void main()\n
+{\n
+  gl_FragColor = uColor * vec4( mixColor, 1.0 );\n
+}\n
+);
+
+}
+
+WireframeVisualPtr WireframeVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
+{
+  Visual::BasePtr emtptyVisual;
+
+  return New(factoryCache, emtptyVisual, properties);
+}
+
+WireframeVisualPtr WireframeVisual::New( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual )
+{
+  return new WireframeVisual( factoryCache, actualVisual );
+}
+
+WireframeVisualPtr WireframeVisual::New( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual, const Property::Map& properties )
+{
+  WireframeVisualPtr wireframeVisual( new WireframeVisual( factoryCache, actualVisual ) );
+
+  // Instead of calling SetProperties, looking for the only valid property 'transform'
+  Property::Value* transformValue = properties.Find( Toolkit::Visual::Property::TRANSFORM, TRANSFORM );
+  Property::Map transformMap;
+  if( transformValue && transformValue->Get( transformMap ) )
+  {
+    wireframeVisual->SetTransformAndSize( transformMap, Vector2::ZERO );
+  }
+
+  return wireframeVisual;
+}
+
+WireframeVisual::WireframeVisual( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual )
+: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
+  mActualVisual( actualVisual )
+{
+}
+
+WireframeVisual::~WireframeVisual()
+{
+}
+
+float WireframeVisual::GetHeightForWidth( float width )
+{
+  if( mActualVisual )
+  {
+    return mActualVisual->GetHeightForWidth( width );
+  }
+  else
+  {
+    return Visual::Base::GetHeightForWidth( width );
+  }
+}
+
+void WireframeVisual::GetNaturalSize( Vector2& naturalSize )
+{
+  if( mActualVisual )
+  {
+    mActualVisual->GetNaturalSize( naturalSize );
+  }
+  else
+  {
+    Visual::Base::GetNaturalSize( naturalSize );
+  }
+}
+
+void WireframeVisual::DoCreatePropertyMap( Property::Map& map ) const
+{
+  if( mActualVisual )
+  {
+    mActualVisual->CreatePropertyMap( map );
+  }
+  else
+  {
+    map.Clear();
+    map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::WIREFRAME );
+  }
+}
+
+void WireframeVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
+{
+  // Do nothing
+}
+
+void WireframeVisual::DoSetProperties( const Property::Map& propertyMap )
+{
+  Property::Value* mixValue = propertyMap.Find( Toolkit::Visual::Property::MIX_COLOR, MIX_COLOR );
+  if( mixValue )
+  {
+    Vector4 mixColor;
+    mixValue->Get( mixColor );
+    SetMixColor( mixColor );
+  }
+}
+
+void WireframeVisual::DoSetOnStage( Actor& actor )
+{
+  InitializeRenderer();
+
+  actor.AddRenderer( mImpl->mRenderer );
+
+  // Wireframe generated and ready to display
+  ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+}
+
+void WireframeVisual::InitializeRenderer()
+{
+  Shader shader = mFactoryCache.GetShader( VisualFactoryCache::WIREFRAME_SHADER );
+  if( !shader )
+  {
+    shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    mFactoryCache.SaveShader( VisualFactoryCache::WIREFRAME_SHADER, shader );
+  }
+
+  Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::WIREFRAME_GEOMETRY );
+  if( !geometry )
+  {
+    geometry = CreateQuadWireframeGeometry();
+    mFactoryCache.SaveGeometry( VisualFactoryCache::WIREFRAME_GEOMETRY, geometry );
+  }
+
+  //Create the renderer
+  mImpl->mRenderer = Renderer::New( geometry, shader);
+
+  //Register transform properties
+  mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+}
+
+Geometry WireframeVisual::CreateQuadWireframeGeometry()
+{
+  const float halfWidth = 0.5f;
+  const float halfHeight = 0.5f;
+  struct QuadVertex { Vector2 position;};
+  QuadVertex quadVertexData[4] =
+  {
+      { Vector2(-halfWidth, -halfHeight) },
+      { Vector2( halfWidth, -halfHeight) },
+      { Vector2( halfWidth,  halfHeight) },
+      { Vector2(-halfWidth,  halfHeight) }
+  };
+
+  Property::Map quadVertexFormat;
+  quadVertexFormat[POSITION_ATTRIBUTE_NAME] = Property::VECTOR2;
+  PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
+  quadVertices.SetData( quadVertexData, 4 );
+
+  // Create indices
+  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( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+  geometry.SetType( Geometry::LINES );
+
+  return geometry;
+}
+
+void WireframeVisual::OnSetTransform()
+{
+  if( mImpl->mRenderer )
+  {
+    //Register transform properties
+    mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
+  }
+}
+
+Visual::Base& WireframeVisual::GetVisualObject()
+{
+  if( mActualVisual )
+  {
+    return *mActualVisual.Get();
+  }
+
+  return *this;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/visuals/wireframe/wireframe-visual.h b/dali-toolkit/internal/visuals/wireframe/wireframe-visual.h
new file mode 100644 (file)
index 0000000..eb54b71
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef DALI_TOOLKIT_INTERNAL_WIREFRAME_VISUAL_H
+#define DALI_TOOLKIT_INTERNAL_WIREFRAME_VISUAL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/intrusive-ptr.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/visuals/visual-base-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+class WireframeVisual;
+typedef IntrusivePtr< WireframeVisual > WireframeVisualPtr;
+
+/**
+ * @brief Renders a wireframe outline to the control's quad.
+ */
+class WireframeVisual: public Visual::Base
+{
+public:
+
+  /**
+   * @brief Create a new wireframe visual.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static WireframeVisualPtr New( VisualFactoryCache& factoryCache, const Property::Map& properties );
+
+  /**
+   * @brief Create a new wireframe visual with an encapsulated actual visual.
+   *
+   * For debugging purpose, the rendering of the encapsulated visual is replaced with wireframe
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] actualVisual The encapsulated actual visual.
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static WireframeVisualPtr New( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual );
+
+  /**
+   * @brief Create a new wireframe visual with an encapsulated actual visual.
+   *
+   * For debugging purpose, the rendering of the encapsulated visual is replaced with wireframe
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] actualVisual The encapsulated actual visual.
+   * @param[in] properties A Property::Map containing settings for this visual
+   * @return A smart-pointer to the newly allocated visual.
+   */
+  static WireframeVisualPtr New( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual, const Property::Map& properties );
+
+
+protected:
+
+  /**
+   * @brief Constructor.
+   *
+   * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
+   * @param[in] actualVisual The encapsulated actual visual.
+   */
+  WireframeVisual( VisualFactoryCache& factoryCache, Visual::BasePtr actualVisual );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   */
+  virtual ~WireframeVisual();
+
+protected: // from Visual::Base
+
+  /**
+   * @copydoc Visual::Base::GetHeightForWidth()
+   */
+  float GetHeightForWidth( float width ) override;
+
+  /**
+   * @copydoc Visual::Base::GetNaturalSize()
+   */
+  void GetNaturalSize( Vector2& naturalSize ) override;
+
+  /**
+   * @copydoc Visual::Base::CreatePropertyMap()
+   */
+  void DoCreatePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::CreateInstancePropertyMap
+   */
+  void DoCreateInstancePropertyMap( Property::Map& map ) const override;
+
+  /**
+   * @copydoc Visual::Base::DoSetProperties()
+   */
+  void DoSetProperties( const Property::Map& propertyMap ) override;
+
+  /**
+   * @copydoc Visual::Base::DoSetOnStage
+   */
+  void DoSetOnStage( Actor& actor ) override;
+
+  /**
+   * @copydoc Visual::Base::OnSetTransform
+   */
+  void OnSetTransform() override;
+
+  /**
+   * @copydoc Visual::Base::GetVisualObject
+   *
+   * Overriding as this visual can sometimes act as a proxy to the actual visual, i.e. when using debug rendering.
+   */
+  Base& GetVisualObject() override;
+
+private:
+  /**
+   * Create the geometry which presents the quad wireframe.
+   * @return The border geometry
+   */
+  Geometry CreateQuadWireframeGeometry();
+
+  /**
+   * @brief Initialise the renderer from the cache, if not available, create and save to the cache for sharing.
+   */
+  void InitializeRenderer();
+
+  // Undefined
+  WireframeVisual( const WireframeVisual& visual);
+
+  // Undefined
+  WireframeVisual& operator=( const WireframeVisual& visual );
+
+private:
+
+  Visual::BasePtr mActualVisual;
+
+};
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_INTERNAL_WIREFRAME_VISUAL_H
diff --git a/dali-toolkit/po/ar.po b/dali-toolkit/po/ar.po
new file mode 100755 (executable)
index 0000000..414fb07
--- /dev/null
@@ -0,0 +1,22 @@
+#: Used to know if the language is using a right to left script
+msgid "IDS_LTR"
+msgstr "RTL"
+
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "اختيار الكل"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "نسخ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "اختيار"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "قص"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "لصق"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "الحافظة"
+
diff --git a/dali-toolkit/po/as.po b/dali-toolkit/po/as.po
new file mode 100644 (file)
index 0000000..2e29597
--- /dev/null
@@ -0,0 +1,17 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "সকলো চয়ন কৰক"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "প্ৰতিলিপি"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "চয়ন কৰক"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "কাটক"
+msgid "IDS_COM_BODY_PASTE"
+msgstr "লেপন কৰক"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ক্লিপব'ৰ্ড"
+
diff --git a/dali-toolkit/po/az.po b/dali-toolkit/po/az.po
new file mode 100755 (executable)
index 0000000..6581e52
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Hamısını seç"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Köçür"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Göndər"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Kəs"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Yapışdır"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Mübadilə buferi"
+
diff --git a/dali-toolkit/po/be_BY.po b/dali-toolkit/po/be_BY.po
new file mode 100644 (file)
index 0000000..744e328
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Вылучыць усё"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Скапіраваць"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Выразаць"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Буфер абмену"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Выбраць"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Уставіць"
+
diff --git a/dali-toolkit/po/bg.po b/dali-toolkit/po/bg.po
new file mode 100755 (executable)
index 0000000..52a2d78
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Избери всички"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Копиране"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Избери"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Отрежи"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Поставяне"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Системен буфер"
+
diff --git a/dali-toolkit/po/bn.po b/dali-toolkit/po/bn.po
new file mode 100644 (file)
index 0000000..5a69435
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "সমস্ত নির্বাচন করুন"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "অনুলিপি করুন"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "নির্বাচন"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "কাট"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "প্রতিলেপন"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ক্লিপবোর্ড"
+
diff --git a/dali-toolkit/po/bn_BD.po b/dali-toolkit/po/bn_BD.po
new file mode 100644 (file)
index 0000000..c29c744
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "সমস্ত নির্বাচন করুন"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "কপি করুন"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "নির্বাচন"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "কাট"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "পেস্ট করুন"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ক্লিপবোর্ড"
+
diff --git a/dali-toolkit/po/ca.po b/dali-toolkit/po/ca.po
new file mode 100755 (executable)
index 0000000..34c6125
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Seleccioni-ho tot"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copia"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Selec."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Tallar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Enganxar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Porta-retalls"
+
diff --git a/dali-toolkit/po/cs.po b/dali-toolkit/po/cs.po
new file mode 100755 (executable)
index 0000000..c8c68f9
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Vybrat vše"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopírovat"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Vybrat"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Vyjmout"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Vložit"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Schránka"
+
diff --git a/dali-toolkit/po/da.po b/dali-toolkit/po/da.po
new file mode 100755 (executable)
index 0000000..0898d64
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Vælg alle"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiér"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Vælg"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Klip"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Indsæt"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Udklipsholder"
+
diff --git a/dali-toolkit/po/de.po b/dali-toolkit/po/de.po
new file mode 100755 (executable)
index 0000000..3082bbb
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Alle auswählen"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopieren"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Auswählen"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Ausschneiden"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Einfügen"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Zwischenablage"
+
diff --git a/dali-toolkit/po/el_GR.po b/dali-toolkit/po/el_GR.po
new file mode 100755 (executable)
index 0000000..8f93b05
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Επιλογή όλων"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Αντιγραφή"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Επιλογή"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Αποκοπή"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Επικόλληση"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Πρόχειρο"
+
diff --git a/dali-toolkit/po/en.po b/dali-toolkit/po/en.po
new file mode 100755 (executable)
index 0000000..2579c1c
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Select all"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copy"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Select"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Paste"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Clipboard"
+
diff --git a/dali-toolkit/po/en_PH.po b/dali-toolkit/po/en_PH.po
new file mode 100755 (executable)
index 0000000..2579c1c
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Select all"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copy"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Select"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Paste"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Clipboard"
+
diff --git a/dali-toolkit/po/en_US.po b/dali-toolkit/po/en_US.po
new file mode 100755 (executable)
index 0000000..2579c1c
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Select all"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copy"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Select"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Paste"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Clipboard"
+
diff --git a/dali-toolkit/po/es_ES.po b/dali-toolkit/po/es_ES.po
new file mode 100755 (executable)
index 0000000..5fed085
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Seleccionar todo"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiar"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Seleccionar"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cortar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Pegar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Portapapeles"
+
diff --git a/dali-toolkit/po/es_US.po b/dali-toolkit/po/es_US.po
new file mode 100755 (executable)
index 0000000..fdb40d8
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Todo"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiar"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Seleccionar"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cortar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Pegar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Portapapeles"
+
diff --git a/dali-toolkit/po/et.po b/dali-toolkit/po/et.po
new file mode 100755 (executable)
index 0000000..361b88a
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Vali kõik"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopeeri"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Vali"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Lõika"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Kleebi"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Lõikelaud"
+
diff --git a/dali-toolkit/po/eu.po b/dali-toolkit/po/eu.po
new file mode 100755 (executable)
index 0000000..86fe6e5
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Hautatu denak"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiatu"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Aukeratu"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Moztu"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Itsatsi"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Arbela"
+
diff --git a/dali-toolkit/po/fa.po b/dali-toolkit/po/fa.po
new file mode 100644 (file)
index 0000000..5e8369b
--- /dev/null
@@ -0,0 +1,22 @@
+#: Used to know if the language is using a right to left script
+msgid "IDS_LTR"
+msgstr "RTL"
+
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "انتخاب همه"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "کپی"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "انتخاب"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "برش"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "الحاق"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "کلیپ بورد"
+
diff --git a/dali-toolkit/po/fi.po b/dali-toolkit/po/fi.po
new file mode 100755 (executable)
index 0000000..fd23422
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Valitse kaikki"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopioi"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Valitse"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Poimi"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Liitä"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Leikepöytä"
+
diff --git a/dali-toolkit/po/fr.po b/dali-toolkit/po/fr.po
new file mode 100755 (executable)
index 0000000..e217eef
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Sélect. tout"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copie"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Sélect."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Couper"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Coller"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Presse-papier"
+
diff --git a/dali-toolkit/po/fr_CA.po b/dali-toolkit/po/fr_CA.po
new file mode 100755 (executable)
index 0000000..0a8fdd2
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Sélectionner tout"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copier"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Sélectionner"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Couper"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Coller"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Presse-papier"
+
diff --git a/dali-toolkit/po/ga.po b/dali-toolkit/po/ga.po
new file mode 100755 (executable)
index 0000000..99328c5
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Roghnaigh gach"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Cóipeáil"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Roghnaigh"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Gearr"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Greamaigh"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Gearrthaisce"
+
diff --git a/dali-toolkit/po/gl.po b/dali-toolkit/po/gl.po
new file mode 100755 (executable)
index 0000000..3e66cbf
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Seleccionar todo"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiar"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Selecc."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cortar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Pegar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Portapapeis"
+
diff --git a/dali-toolkit/po/gu.po b/dali-toolkit/po/gu.po
new file mode 100644 (file)
index 0000000..598fda3
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "બધું પસંદ કરો"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "કૉપિ કરો"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "પસંદ કરો"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "કટ કરો"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ચોંટાડો"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ક્લિપબોર્ડ"
+
diff --git a/dali-toolkit/po/hi.po b/dali-toolkit/po/hi.po
new file mode 100755 (executable)
index 0000000..1892408
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "सभी चुनें"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "कॉपी करें"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "चुनें"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "काटें"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "पेस्ट करें"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "क्लिपबोर्ड"
+
diff --git a/dali-toolkit/po/hr.po b/dali-toolkit/po/hr.po
new file mode 100755 (executable)
index 0000000..6c8a251
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Odaberi sve"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiraj"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Odaberi"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Izreži"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Zalijepi"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Međuspremnik"
+
diff --git a/dali-toolkit/po/hu.po b/dali-toolkit/po/hu.po
new file mode 100755 (executable)
index 0000000..accab91
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Összes kijelölése"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Másol"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Választ"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Kivág"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Beilleszt"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Vágólap"
+
diff --git a/dali-toolkit/po/hy.po b/dali-toolkit/po/hy.po
new file mode 100755 (executable)
index 0000000..9892948
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Ընտրել բոլորը"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Պատճենել"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Ընտրել"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Կտրել"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Տեղադրել"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Գզրոց"
+
diff --git a/dali-toolkit/po/id.po b/dali-toolkit/po/id.po
new file mode 100644 (file)
index 0000000..4e1aada
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Pilih semua"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Salin"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Pilih"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Memotong"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Kutip"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Papan klip"
+
diff --git a/dali-toolkit/po/is.po b/dali-toolkit/po/is.po
new file mode 100755 (executable)
index 0000000..bd1952e
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Velja allt"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Afrita"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Velja"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Klippa"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Líma"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Klippiborð"
+
diff --git a/dali-toolkit/po/it_IT.po b/dali-toolkit/po/it_IT.po
new file mode 100755 (executable)
index 0000000..f68a4f9
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Seleziona tutto"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copia"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Seleziona"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Taglia"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Incolla"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Appunti"
+
diff --git a/dali-toolkit/po/ja_JP.po b/dali-toolkit/po/ja_JP.po
new file mode 100755 (executable)
index 0000000..4cea292
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "全て選択"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "コピー"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "選択"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "切り取り"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "貼り付け"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "クリップボード"
+
diff --git a/dali-toolkit/po/ka.po b/dali-toolkit/po/ka.po
new file mode 100755 (executable)
index 0000000..5dd6d53
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ყველას არჩევა"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ასლი"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "არჩევა"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "მოჭრა"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ჩასმა"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ბუფერული მეხს."
+
diff --git a/dali-toolkit/po/kk.po b/dali-toolkit/po/kk.po
new file mode 100755 (executable)
index 0000000..6de1a32
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Бәрін бөлектеу"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Көшіру"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Таңдау"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Кесу"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Қою"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Буфер"
+
diff --git a/dali-toolkit/po/km.po b/dali-toolkit/po/km.po
new file mode 100644 (file)
index 0000000..c78133b
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ជ្រើស​ទាំង​អស់"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ចម្លង"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ជ្រើស"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "កាត់"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "បិទ​ភ្ជាប់"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ក្ដារ​តម្បៀតខ្ទាស់"
+
diff --git a/dali-toolkit/po/kn.po b/dali-toolkit/po/kn.po
new file mode 100644 (file)
index 0000000..b169d33
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ಎಲ್ಲಾ ಆಯ್ಕೆಮಾಡಿ"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ನಕಲಿಸಿ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ಆಯ್ಕೆ"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "ಕತ್ತರಿಸು"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ಅಂಟಿಸಿರಿ"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ಕ್ಲಿಪ್‌ಬೋರ್ಡ್"
+
diff --git a/dali-toolkit/po/ko_KR.po b/dali-toolkit/po/ko_KR.po
new file mode 100755 (executable)
index 0000000..8ecb8d3
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "모두 선택"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "복사"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "선택"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "잘라내기"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "붙여넣기"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "클립보드"
+
diff --git a/dali-toolkit/po/ky_KG.po b/dali-toolkit/po/ky_KG.po
new file mode 100644 (file)
index 0000000..9917b9a
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Баарын тандоо"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Көчүрүү"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Тандоо"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Кесүү"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Коюу"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Буфер"
+
diff --git a/dali-toolkit/po/lo.po b/dali-toolkit/po/lo.po
new file mode 100644 (file)
index 0000000..f09612b
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ເລືອກທັງໝົດ"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ອັດສຳເນົາ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ເລືອກ"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "ຕັດ"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ວາງໃສ່"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ກະດານເກັບຄວາມຈໍາ"
+
diff --git a/dali-toolkit/po/lt.po b/dali-toolkit/po/lt.po
new file mode 100755 (executable)
index 0000000..d403fcc
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Pasirinkti visus"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopijuoti"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Rinktis"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Iškirpti"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Įklijuoti"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Iškarpinė"
+
diff --git a/dali-toolkit/po/lv.po b/dali-toolkit/po/lv.po
new file mode 100755 (executable)
index 0000000..519597b
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Izv. visu"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopēt"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Atlasīt"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Izgriezt"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Ielīmēt"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Starpliktuve"
+
diff --git a/dali-toolkit/po/mk.po b/dali-toolkit/po/mk.po
new file mode 100755 (executable)
index 0000000..d12d533
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Избери ги сите"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Копирај"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Избери"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Исечи"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Пресликај"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Посредна меморија"
+
diff --git a/dali-toolkit/po/ml.po b/dali-toolkit/po/ml.po
new file mode 100644 (file)
index 0000000..39c700b
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "എല്ലാം തിരഞ്ഞെടുക്കുക"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "പകര്‍ത്തുക"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "തിരഞ്ഞെ."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "മുറിക്കുക"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ഒട്ടിക്കുക"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ക്ലിപ്ബോര്‍ഡ്"
+
diff --git a/dali-toolkit/po/mn_MN.po b/dali-toolkit/po/mn_MN.po
new file mode 100644 (file)
index 0000000..cc2b51b
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Бүгдийг сонгох"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Хуулах"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Сонгох"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Хайчлах"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Буулгах"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Түр санах ой"
+
diff --git a/dali-toolkit/po/mr.po b/dali-toolkit/po/mr.po
new file mode 100644 (file)
index 0000000..6e8dc2e
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "सर्व निवडा"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "कॉपी"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "निवडा"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "कट"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "पेस्ट"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "क्लिपबोर्ड"
+
diff --git a/dali-toolkit/po/ms.po b/dali-toolkit/po/ms.po
new file mode 100644 (file)
index 0000000..25aa6f7
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Pilih semua"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Salin"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Pilih"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Potong"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Tampal"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Papan klip"
+
diff --git a/dali-toolkit/po/my_ZG.po b/dali-toolkit/po/my_ZG.po
new file mode 100644 (file)
index 0000000..604bc54
--- /dev/null
@@ -0,0 +1,19 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "အားလုံးကုိ ေရြးပါ"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ကူးပါ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ေရြးခ်ယ္"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "ျဖတ္ေတာက္ပါ"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ကူးထည့္ပါ"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ကလစ္ဘုတ္"
+
+
diff --git a/dali-toolkit/po/nb.po b/dali-toolkit/po/nb.po
new file mode 100755 (executable)
index 0000000..0c15456
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Merk alt"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopier"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Velg"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Klipp ut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Lim inn"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Utklippstavle"
+
diff --git a/dali-toolkit/po/ne.po b/dali-toolkit/po/ne.po
new file mode 100644 (file)
index 0000000..c984cf2
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "सबै छान्नुहोस्"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "कपी गर्नुहोस्"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "चयन गर"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "काट्नुहोस्"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "पेस्ट गर्नुहोस्"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "क्लिपबोर्ड"
+
diff --git a/dali-toolkit/po/nl.po b/dali-toolkit/po/nl.po
new file mode 100755 (executable)
index 0000000..48645c4
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Selecteer alles"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopieer"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Select."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Knippen"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Plakken"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Klembord"
+
diff --git a/dali-toolkit/po/or.po b/dali-toolkit/po/or.po
new file mode 100644 (file)
index 0000000..8ba6b5c
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ସମସ୍ତ ଚୟନ"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "କପି"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ଚୟନ"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "କଟ୍"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ଲେପନ"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "କ୍ଲିପବୋର୍ଡ"
+
diff --git a/dali-toolkit/po/pa.po b/dali-toolkit/po/pa.po
new file mode 100644 (file)
index 0000000..f301088
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "ਸਭ ਚੁਣੋ"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "ਕਾਪੀ ਕਰੋ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ਚੁਣੋ"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "ਕੱਟੋ"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ਪੇਸਟ ਕਰੋ"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ਕਲਿਪਬੋਰਡ"
+
diff --git a/dali-toolkit/po/pl.po b/dali-toolkit/po/pl.po
new file mode 100755 (executable)
index 0000000..c87ec62
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Zaznacz wszystko"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiuj"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Wybierz"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Wytnij"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Wklej"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Schowek"
+
diff --git a/dali-toolkit/po/pt_BR.po b/dali-toolkit/po/pt_BR.po
new file mode 100755 (executable)
index 0000000..9c6743a
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Selecionar tudo"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiar"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Selecionar"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cortar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Colar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Área de transferência"
+
diff --git a/dali-toolkit/po/pt_PT.po b/dali-toolkit/po/pt_PT.po
new file mode 100755 (executable)
index 0000000..e1a21da
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Seleccionar tudo"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiar"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Selec."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cortar"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Colar"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Área transferência"
+
diff --git a/dali-toolkit/po/ro.po b/dali-toolkit/po/ro.po
new file mode 100755 (executable)
index 0000000..0d78703
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Selectare toate"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Copiere"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Selectare"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Decupare"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Lipire"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Clipboard"
+
diff --git a/dali-toolkit/po/ru_RU.po b/dali-toolkit/po/ru_RU.po
new file mode 100755 (executable)
index 0000000..8134f66
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Выделить все"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Копировать"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Выделить"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Вырезать"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Вставить"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Буфер обмена"
+
diff --git a/dali-toolkit/po/si.po b/dali-toolkit/po/si.po
new file mode 100644 (file)
index 0000000..ffc7eb9
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "සියල්ල තෝරන්න"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "පිටපත් කරන්න"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "තෝරන්න"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "කපන්න"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "අලවන්න"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "ක්ලිප් පුවරුව"
+
diff --git a/dali-toolkit/po/sk.po b/dali-toolkit/po/sk.po
new file mode 100755 (executable)
index 0000000..1944646
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Vybrať všetky"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopírovať"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Vybrať"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Vystrihnúť"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Vložiť"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Schránka"
+
diff --git a/dali-toolkit/po/sl.po b/dali-toolkit/po/sl.po
new file mode 100755 (executable)
index 0000000..4c8ad23
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Izberi vse"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiraj"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Izberi"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Izreži"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Prilepi"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Odložišče"
+
diff --git a/dali-toolkit/po/sr.po b/dali-toolkit/po/sr.po
new file mode 100755 (executable)
index 0000000..1be1832
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Izaberi sve"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiraj"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Izaberi"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Iseci"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Zalepi"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Privremena memorija"
+
diff --git a/dali-toolkit/po/sv.po b/dali-toolkit/po/sv.po
new file mode 100755 (executable)
index 0000000..13c587d
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Välj alla"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopiera"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Välj"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Klipp ut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Klistra in"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Urklipp"
+
diff --git a/dali-toolkit/po/ta.po b/dali-toolkit/po/ta.po
new file mode 100644 (file)
index 0000000..1bb609d
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "எல்லாம் தேர்வு"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "நகல்"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "தேர்வு"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "வெட்டு"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "ஒட்டு"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "கிளிப்போர்டு"
+
diff --git a/dali-toolkit/po/te.po b/dali-toolkit/po/te.po
new file mode 100644 (file)
index 0000000..3bb6e90
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "అన్నీ ఎంచుకోండి"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "కాపీ"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "ఎంచు."
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "కట్"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "అతికించు"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "క్లిప్‌బోర్డ్"
+
diff --git a/dali-toolkit/po/tg_TJ.po b/dali-toolkit/po/tg_TJ.po
new file mode 100644 (file)
index 0000000..63ab566
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Ҳамаро интихоб кардан"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Нусха"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Интихоб кардан"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Бурида гирифтан"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Гузоштан"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Планшет"
+
diff --git a/dali-toolkit/po/th.po b/dali-toolkit/po/th.po
new file mode 100644 (file)
index 0000000..a750a7e
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "เลือก​ทั้ง​หมด"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "คัด​ลอก"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "เลือก"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "ตัด"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "วาง"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "คลิ​ป​บอร์ด"
+
diff --git a/dali-toolkit/po/tk_TM.po b/dali-toolkit/po/tk_TM.po
new file mode 100644 (file)
index 0000000..efbb7aa
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Ählisini saýla"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Nusga"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Saýla"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Kes"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Goýmak"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Alyş-çalyş buferi"
+
diff --git a/dali-toolkit/po/tl.po b/dali-toolkit/po/tl.po
new file mode 100644 (file)
index 0000000..bf63c56
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Piliin lahat"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopyahin"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Piliin"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "I-cut"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "I-paste"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Clipboard"
+
diff --git a/dali-toolkit/po/tr_TR.po b/dali-toolkit/po/tr_TR.po
new file mode 100755 (executable)
index 0000000..a360194
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Hepsini seç"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Kopyala"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Seç"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Kes"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Yapıştır"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Pano"
+
diff --git a/dali-toolkit/po/uk.po b/dali-toolkit/po/uk.po
new file mode 100755 (executable)
index 0000000..c41b559
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Вибрати всі"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Копіювати"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Вибрати"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Вирізати"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Вставити"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Буфер обміну"
+
diff --git a/dali-toolkit/po/ur.po b/dali-toolkit/po/ur.po
new file mode 100644 (file)
index 0000000..b4bf3be
--- /dev/null
@@ -0,0 +1,22 @@
+#: Used to know if the language is using a right to left script
+msgid "IDS_LTR"
+msgstr "RTL"
+
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "تمام منتخب کریں"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "کاپی"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "انتخاب"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "کٹ"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "جوڑ دیں"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "کلپ بورڈ"
+
diff --git a/dali-toolkit/po/uz.po b/dali-toolkit/po/uz.po
new file mode 100755 (executable)
index 0000000..bcad8b0
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Barchasini tanlash"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Nusxa olish"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Tanlash"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Qirqish"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Qo‘shib qo‘yish"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Bufer"
+
diff --git a/dali-toolkit/po/vi.po b/dali-toolkit/po/vi.po
new file mode 100644 (file)
index 0000000..e22211f
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "Chọn tất cả"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "Chép"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "Chọn"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "Cắt"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "Dán"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "Bộ nhớ tạm"
+
diff --git a/dali-toolkit/po/zh_CN.po b/dali-toolkit/po/zh_CN.po
new file mode 100755 (executable)
index 0000000..b80e9d9
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "全选"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "复制"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "选择"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "剪切"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "粘贴"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "剪贴板"
+
diff --git a/dali-toolkit/po/zh_HK.po b/dali-toolkit/po/zh_HK.po
new file mode 100755 (executable)
index 0000000..338a38a
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "選擇全部"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "複製"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "選擇"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "剪下"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "貼上"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "剪貼板"
+
diff --git a/dali-toolkit/po/zh_TW.po b/dali-toolkit/po/zh_TW.po
new file mode 100755 (executable)
index 0000000..0980255
--- /dev/null
@@ -0,0 +1,18 @@
+msgid "IDS_COM_BODY_SELECT_ALL"
+msgstr "全選"
+
+msgid "IDS_COM_BODY_COPY"
+msgstr "複製"
+
+msgid "IDS_COM_SK_SELECT"
+msgstr "選擇"
+
+msgid "IDS_COM_BODY_CUT"
+msgstr "剪下"
+
+msgid "IDS_COM_BODY_PASTE"
+msgstr "貼上"
+
+msgid "IDS_COM_BODY_CLIPBOARD"
+msgstr "剪貼簿"
+
diff --git a/dali-toolkit/public-api/accessibility-manager/accessibility-manager.cpp b/dali-toolkit/public-api/accessibility-manager/accessibility-manager.cpp
new file mode 100644 (file)
index 0000000..a683838
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * 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 <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AccessibilityManager::AccessibilityManager()
+{
+}
+
+AccessibilityManager::~AccessibilityManager()
+{
+}
+
+AccessibilityManager AccessibilityManager::Get()
+{
+  AccessibilityManager manager;
+
+  // Check whether the accessibility manager is already created
+  SingletonService singletonService( SingletonService::Get() );
+  if ( singletonService )
+  {
+    Dali::BaseHandle handle = singletonService.GetSingleton(typeid(AccessibilityManager));
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to focus manager
+      manager = AccessibilityManager(dynamic_cast<Internal::AccessibilityManager*>(handle.GetObjectPtr()));
+    }
+
+    if(!manager)
+    {
+      // If not, create the accessibility manager and register it as a singleton
+      Internal::AccessibilityManager* internalManager = new Internal::AccessibilityManager();
+      manager = AccessibilityManager( internalManager );
+      internalManager->Initialise();
+      singletonService.Register( typeid(manager), manager );
+    }
+  }
+
+  return manager;
+}
+
+AccessibilityManager::AccessibilityManager(Internal::AccessibilityManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+void AccessibilityManager::SetAccessibilityAttribute(Actor actor, AccessibilityAttribute type, const std::string& text)
+{
+  GetImpl(*this).SetAccessibilityAttribute(actor, type, text);
+}
+
+std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, AccessibilityAttribute type) const
+{
+  return GetImpl(*this).GetAccessibilityAttribute(actor, type);
+}
+
+void AccessibilityManager::SetFocusOrder(Actor actor, const unsigned int order)
+{
+  GetImpl(*this).SetFocusOrder(actor, order);
+}
+
+unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const
+{
+  return GetImpl(*this).GetFocusOrder(actor);
+}
+
+unsigned int AccessibilityManager::GenerateNewFocusOrder() const
+{
+  return GetImpl(*this).GenerateNewFocusOrder();
+}
+
+Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order)
+{
+  return GetImpl(*this).GetActorByFocusOrder(order);
+}
+
+bool AccessibilityManager::SetCurrentFocusActor(Actor actor)
+{
+  return GetImpl(*this).SetCurrentFocusActor(actor);
+}
+
+Actor AccessibilityManager::GetCurrentFocusActor()
+{
+  return GetImpl(*this).GetCurrentFocusActor();
+}
+
+Actor AccessibilityManager::GetCurrentFocusGroup()
+{
+  return GetImpl(*this).GetCurrentFocusGroup();
+}
+
+unsigned int AccessibilityManager::GetCurrentFocusOrder()
+{
+  return GetImpl(*this).GetCurrentFocusOrder();
+}
+
+bool AccessibilityManager::MoveFocusForward()
+{
+  return GetImpl(*this).MoveFocusForward();
+}
+
+bool AccessibilityManager::MoveFocusBackward()
+{
+  return GetImpl(*this).MoveFocusBackward();
+}
+
+void AccessibilityManager::ClearFocus()
+{
+  GetImpl(*this).ClearFocus();
+}
+
+void AccessibilityManager::Reset()
+{
+  GetImpl(*this).Reset();
+}
+
+void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup)
+{
+  GetImpl(*this).SetFocusGroup(actor, isFocusGroup);
+}
+
+bool AccessibilityManager::IsFocusGroup(Actor actor) const
+{
+  return GetImpl(*this).IsFocusGroup(actor);
+}
+
+void AccessibilityManager::SetGroupMode(bool enabled)
+{
+  GetImpl(*this).SetGroupMode(enabled);
+}
+
+bool AccessibilityManager::GetGroupMode() const
+{
+  return GetImpl(*this).GetGroupMode();
+}
+
+void AccessibilityManager::SetWrapMode(bool wrapped)
+{
+  GetImpl(*this).SetWrapMode(wrapped);
+}
+
+bool AccessibilityManager::GetWrapMode() const
+{
+  return GetImpl(*this).GetWrapMode();
+}
+
+void AccessibilityManager::SetFocusIndicatorActor(Actor indicator)
+{
+  GetImpl(*this).SetFocusIndicatorActor(indicator);
+}
+
+Actor AccessibilityManager::GetFocusIndicatorActor()
+{
+  return GetImpl(*this).GetFocusIndicatorActor();
+}
+
+Actor AccessibilityManager::GetFocusGroup(Actor actor)
+{
+  return GetImpl(*this).GetFocusGroup(actor);
+}
+
+Vector2 AccessibilityManager::GetReadPosition() const
+{
+  return GetImpl(*this).GetReadPosition();
+}
+
+AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
+{
+  return GetImpl(*this).FocusChangedSignal();
+}
+
+AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
+{
+  return GetImpl(*this).FocusOvershotSignal();
+}
+
+AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
+{
+  return GetImpl(*this).FocusedActorActivatedSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::StatusChangedSignal()
+{
+  return GetImpl(*this).StatusChangedSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionNextSignal()
+{
+  return GetImpl(*this).ActionNextSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionPreviousSignal()
+{
+  return GetImpl(*this).ActionPreviousSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionActivateSignal()
+{
+  return GetImpl(*this).ActionActivateSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionOverSignal()
+{
+  return GetImpl(*this).ActionOverSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadSignal()
+{
+  return GetImpl(*this).ActionReadSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadNextSignal()
+{
+  return GetImpl(*this).ActionReadNextSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadPreviousSignal()
+{
+  return GetImpl(*this).ActionReadPreviousSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionUpSignal()
+{
+  return GetImpl(*this).ActionUpSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionDownSignal()
+{
+  return GetImpl(*this).ActionDownSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionClearFocusSignal()
+{
+  return GetImpl(*this).ActionClearFocusSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionBackSignal()
+{
+  return GetImpl(*this).ActionBackSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionScrollUpSignal()
+{
+  return GetImpl(*this).ActionScrollUpSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionScrollDownSignal()
+{
+  return GetImpl(*this).ActionScrollDownSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionPageLeftSignal()
+{
+  return GetImpl(*this).ActionPageLeftSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionPageRightSignal()
+{
+  return GetImpl(*this).ActionPageRightSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionPageUpSignal()
+{
+  return GetImpl(*this).ActionPageUpSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionPageDownSignal()
+{
+  return GetImpl(*this).ActionPageDownSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionMoveToFirstSignal()
+{
+  return GetImpl(*this).ActionMoveToFirstSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionMoveToLastSignal()
+{
+  return GetImpl(*this).ActionMoveToLastSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadFromTopSignal()
+{
+  return GetImpl(*this).ActionReadFromTopSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadFromNextSignal()
+{
+  return GetImpl(*this).ActionReadFromNextSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionZoomSignal()
+{
+  return GetImpl(*this).ActionZoomSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadIndicatorInformationSignal()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: ActionReadIndicatorInformationSignal is deprecated and will be removed from next release.\n" );
+
+  return GetImpl(*this).ActionReadIndicatorInformationSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionReadPauseResumeSignal()
+{
+  return GetImpl(*this).ActionReadPauseResumeSignal();
+}
+
+AccessibilityManager::AccessibilityActionSignalType& AccessibilityManager::ActionStartStopSignal()
+{
+  return GetImpl(*this).ActionStartStopSignal();
+}
+
+AccessibilityManager::AccessibilityActionScrollSignalType& AccessibilityManager::ActionScrollSignal()
+{
+  return GetImpl(*this).ActionScrollSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/accessibility-manager/accessibility-manager.h b/dali-toolkit/public-api/accessibility-manager/accessibility-manager.h
new file mode 100755 (executable)
index 0000000..eefbcdb
--- /dev/null
@@ -0,0 +1,831 @@
+#ifndef DALI_TOOLKIT_ACCESSIBILITY_MANAGER_H
+#define DALI_TOOLKIT_ACCESSIBILITY_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class AccessibilityManager;
+}
+/**
+ * @addtogroup dali_toolkit_managers
+ * @{
+ */
+
+/**
+ * @brief Manages registration of actors in an accessibility focus chain and changing the
+ * focused actor within that chain.
+ *
+ * This class provides the functionality of registering the focus order and description
+ * of actors and maintaining the focus chain.
+ *
+ * It provides functionality of setting the
+ * focus and moving the focus forward and backward. It also draws a highlight for the
+ * focused actor and emits a signal when the focus is changed.
+ *
+ * Signals
+ * | %Signal Name          | Method                             |
+ * |-----------------------|------------------------------------|
+ * | focusChanged          | @ref FocusChangedSignal()          |
+ * | focusOvershot         | @ref FocusOvershotSignal()         |
+ * | focusedActorActivated | @ref FocusedActorActivatedSignal() |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API AccessibilityManager : public BaseHandle
+{
+public:
+
+  // Typedefs
+
+  /**
+   * @brief Accessibility Action Signal.
+   *
+   * The connected signal callback should return true if handled.
+   * @SINCE_1_0.0
+   */
+  typedef Signal< bool ( AccessibilityManager& ) > AccessibilityActionSignalType; ///< Generic signal type @SINCE_1_0.0
+  typedef Signal< bool ( AccessibilityManager&, const Dali::TouchEvent& )> AccessibilityActionScrollSignalType; ///< Scroll signal type @SINCE_1_0.0
+
+  /**
+   * @brief Enumeration for accessibility that needs four information which will be read by screen-reader.
+   *
+   * Reading order : Label -> Trait -> Optional (Value and Hint)
+   * @SINCE_1_0.0
+   */
+  enum AccessibilityAttribute
+  {
+    ACCESSIBILITY_LABEL = 0, ///< Simple text which contained in ui-control @SINCE_1_0.0
+    ACCESSIBILITY_TRAIT,     ///< Description of ui-control trait @SINCE_1_0.0
+    ACCESSIBILITY_VALUE,     ///< Current value of ui-control (Optional) @SINCE_1_0.0
+    ACCESSIBILITY_HINT,      ///< Hint for action (Optional) @SINCE_1_0.0
+    ACCESSIBILITY_ATTRIBUTE_NUM ///< Number of attributes @SINCE_1_0.0
+  };
+
+   /**
+    * @brief Enumeration for overshoot direction.
+    * @SINCE_1_0.0
+    */
+  enum FocusOvershotDirection
+  {
+    OVERSHOT_PREVIOUS = -1, ///< Try to move previous of the first actor @SINCE_1_0.0
+    OVERSHOT_NEXT = 1,      ///< Try to move next of the last actor @SINCE_1_0.0
+  };
+
+ public:
+
+  /// @brief Focus changed signal
+  /// @SINCE_1_0.0
+  typedef Signal< void ( Actor, Actor ) > FocusChangedSignalType;
+
+  /// @brief Focus overshooted signal
+  /// @SINCE_1_0.0
+  typedef Signal< void ( Actor, FocusOvershotDirection ) > FocusOvershotSignalType;
+
+  /// @brief Focused actor activated signal
+  /// @SINCE_1_0.0
+  typedef Signal< void ( Actor ) > FocusedActorActivatedSignalType;
+
+  /**
+   * @brief Creates an AccessibilityManager handle; this can be initialised with AccessibilityManager::New().
+   *
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_0.0
+   */
+  AccessibilityManager();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~AccessibilityManager();
+
+  /**
+   * @brief Gets the singleton of AccessibilityManager object.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the AccessibilityManager control
+   */
+  static AccessibilityManager Get();
+
+  /**
+   * @brief Sets the information of the specified actor's accessibility attribute.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor, the text to be set with
+   * @param type The attribute type the text to be set with
+   * @param text The text for the actor's accessibility information
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  void SetAccessibilityAttribute(Actor actor, AccessibilityAttribute type, const std::string& text);
+
+  /**
+   * @brief Gets the text of the specified actor's accessibility attribute.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be queried
+   * @param type The attribute type to be queried
+   * @return The text of the actor's accessibility information
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  std::string GetAccessibilityAttribute(Actor actor, AccessibilityAttribute type) const;
+
+  /**
+   * @brief Sets the focus order of the actor.
+   *
+   * The focus order of each actor in the focus chain is unique.
+   * If there is another actor assigned with the same focus order
+   * already, the new actor will be inserted to the focus chain with
+   * that focus order, and the focus order of the original actor and
+   * all the actors followed in the focus chain will be increased
+   * accordingly. If the focus order assigned to the actor is 0, it
+   * means that actor's focus order is undefined (e.g. the actor has a
+   * description but with no focus order being set yet) and therefore
+   * that actor is not focusable.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor the focus order to be set with
+   * @param order The focus order of the actor
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  void SetFocusOrder(Actor actor, const unsigned int order);
+
+  /**
+   * @brief Gets the focus order of the actor.
+   *
+   * When the focus order is 0, it means the focus order of the actor
+   * is undefined.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be queried
+   * @return The focus order of the actor
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  unsigned int GetFocusOrder(Actor actor) const;
+
+  /**
+   * @brief Generates a new focus order number which can be used to
+   * assign to actors which need to be appended to the end of the
+   * current focus order chain.
+   *
+   * The new number will be an increment over the very last focus
+   * order number in the focus chain. If the focus chain is empty then
+   * the function returns 1, else the number returned will be FOLast +
+   * 1 where FOLast is the focus order of the very last control in the
+   * focus chain.
+   *
+   * @SINCE_1_0.0
+   * @return The focus order of the actor
+   * @pre The AccessibilityManager has been initialized.
+   */
+  unsigned int GenerateNewFocusOrder() const;
+
+  /**
+   * @brief Gets the actor that has the specified focus order.
+   *
+   * It will return an empty handle if no actor in the stage
+   * has the specified focus order.
+   *
+   * @SINCE_1_0.0
+   * @param order The focus order of the actor
+   *
+   * @return The actor that has the specified focus order or an empty
+   * handle if no actor in the stage has the specified focus order
+   * @pre The AccessibilityManager has been initialized.
+   */
+  Actor GetActorByFocusOrder(const unsigned int order);
+
+  /**
+   * @brief Moves the focus to the specified actor.
+   *
+   * Only one actor can be focused at the same time. The actor must
+   * have a defined focus order and must be focusable, visible and in
+   * the stage.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be focused
+   * @return Whether the focus is successful or not
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  bool SetCurrentFocusActor(Actor actor);
+
+  /**
+   * @brief Gets the current focused actor.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the current focused actor or an empty handle if no actor is focused
+   * @pre The AccessibilityManager has been initialized.
+   */
+  Actor GetCurrentFocusActor();
+
+  /**
+   * @brief Gets the focus group of current focused actor.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the immediate parent of the current focused
+   * actor which is also a focus group, or an empty handle if no actor
+   * is focused
+   * @pre The AccessibilityManager has been initialized.
+   *
+   */
+  Actor GetCurrentFocusGroup();
+
+  /**
+   * @brief Gets the focus order of currently focused actor.
+   * @SINCE_1_0.0
+   * @return The focus order of the currently focused actor or 0 if no
+   * actor is in focus
+   * @pre The AccessibilityManager has been initialized.
+   *
+   */
+  unsigned int GetCurrentFocusOrder();
+
+  /**
+   * @brief Moves the focus to the next focusable actor in the focus
+   * chain (according to the focus traversal order).
+   *
+   * When the focus movement is wrapped around, the focus will be moved
+   * to the first focusable actor when it reaches the end of the focus chain.
+   *
+   * @SINCE_1_0.0
+   * @return true if the moving was successful
+   * @pre The AccessibilityManager has been initialized.
+   */
+  bool MoveFocusForward();
+
+  /**
+   * @brief Moves the focus to the previous focusable actor in the
+   * focus chain (according to the focus traversal order).
+   *
+   * When the focus movement is wrapped around, the focus will be
+   * moved to the last focusable actor when it reaches the beginning
+   * of the focus chain.
+   *
+   * @SINCE_1_0.0
+   * @return true if the moving was successful
+   * @pre The AccessibilityManager has been initialized.
+   */
+  bool MoveFocusBackward();
+
+  /**
+   * @brief Clears the focus from the current focused actor if any, so
+   * that no actor is focused in the focus chain.
+   *
+   * It will emit focus changed signal without current focused actor.
+   * @SINCE_1_0.0
+   * @pre The AccessibilityManager has been initialized.
+   */
+  void ClearFocus();
+
+  /**
+   * @brief Clears every registered focusable actor from focus-manager.
+   * @SINCE_1_0.0
+   * @pre The AccessibilityManager has been initialized.
+   */
+  void Reset();
+
+  /**
+   * @brief Sets whether an actor is a focus group that can limit the
+   * scope of focus movement to its child actors in the focus chain.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be set as a focus group
+   * @param isFocusGroup Whether to set the actor to be a focus group or not
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  void SetFocusGroup(Actor actor, bool isFocusGroup);
+
+  /**
+   * @brief Checks whether the actor is set as a focus group or not.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be checked
+   * @return Whether the actor is set as a focus group
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  bool IsFocusGroup(Actor actor) const;
+
+  /**
+   * @brief Sets whether the group mode is enabled or not.
+   *
+   * When the group mode is enabled, the focus movement will be limited to the child actors
+   * of the current focus group including the current focus group itself. The current focus
+   * group is the closest ancestor of the current focused actor that is set as a focus group.
+   * @SINCE_1_0.0
+   * @param enabled Whether the group mode is enabled or not
+   * @pre The AccessibilityManager has been initialized.
+   */
+  void SetGroupMode(bool enabled);
+
+  /**
+   * @brief Gets whether the group mode is enabled or not.
+   *
+   * @SINCE_1_0.0
+   * @return Whether the group mode is enabled or not.
+   * @pre The AccessibilityManager has been initialized.
+   */
+  bool GetGroupMode() const;
+
+  /**
+   * @brief Sets whether focus will be moved to the beginning of the
+   * focus chain when it reaches the end or vice versa.
+   *
+   * When both the wrap mode and the group mode are enabled, focus will be
+   * wrapped within the current focus group. Focus will not be wrapped in default.
+   * @SINCE_1_0.0
+   * @param wrapped Whether the focus movement is wrapped around or not
+   * @pre The AccessibilityManager has been initialized.
+   */
+  void SetWrapMode(bool wrapped);
+
+  /**
+   * @brief Gets whether the wrap mode is enabled or not.
+   *
+   * @SINCE_1_0.0
+   * @return Whether the wrap mode is enabled or not.
+   * @pre The AccessibilityManager has been initialized.
+   */
+  bool GetWrapMode() const;
+
+  /**
+   * @brief Sets the focus indicator actor.
+   *
+   * This will replace the default focus indicator actor in
+   * AccessibilityManager and will be added to the focused actor as a
+   * highlight.
+   *
+   * @SINCE_1_0.0
+   * @param indicator The indicator actor to be added
+   * @pre The AccessibilityManager has been initialized.
+   * @pre The indicator actor has been initialized.
+   */
+  void SetFocusIndicatorActor(Actor indicator);
+
+  /**
+   * @brief Gets the focus indicator actor.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the focus indicator actor
+   * @pre The AccessibilityManager has been initialized.
+   */
+  Actor GetFocusIndicatorActor();
+
+  /**
+   * @brief Returns the closest ancestor of the given actor that is a focus group.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be checked for its focus group
+   * @return The focus group the given actor belongs to or an empty handle if the given actor doesn't belong to any focus group
+   */
+  Actor GetFocusGroup(Actor actor);
+
+  /**
+   * @brief Returns the current position of the read action.
+   * @SINCE_1_0.0
+   * @return The current event position
+   */
+  Vector2 GetReadPosition() const;
+
+ public: // Signals
+
+  /**
+   * @brief This signal is emitted when the current focused actor is changed.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor originalFocusedActor, Actor currentFocusedActor);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusChangedSignalType& FocusChangedSignal();
+
+  /**
+   * @brief This signal is emitted when there is no way to move focus further.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor currentFocusedActor, FocusOvershotDirection direction);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusOvershotSignalType& FocusOvershotSignal();
+
+  /**
+   * @brief This signal is emitted when the current focused actor is activated.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor activatedActor);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusedActorActivatedSignalType& FocusedActorActivatedSignal();
+
+ public: // Accessibility action signals
+
+  /**
+   * @brief This is emitted when accessibility(screen-reader) feature turned on or off.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& StatusChangedSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move focus to the next
+   * focusable actor (by one finger flick down).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionNextSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move focus to the previous
+   * focusable actor (by one finger flick up).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionPreviousSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to activate the current focused
+   * actor (by one finger double tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionActivateSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to focus and read the actor
+   * (by one finger tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to focus and read the actor
+   * (by one finger move).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionOverSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move focus to the next
+   * focusable actor (by one finger flick right).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadNextSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move focus to the previous
+   * focusable actor (by one finger flick left).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadPreviousSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to change the value when the
+   * current focused actor is a slider (by double finger down and move up and right).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionUpSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to change the value when the
+   * current focused actor is a slider (by double finger down and move down and left).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionDownSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to clear the focus from the
+   * current focused actor if any, so that no actor is focused in the focus chain.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionClearFocusSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to navigate back (by two
+   * fingers circle draw).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionBackSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll up the list
+   * (by two finger swipe up).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionScrollUpSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll down the list
+   * (by two finger swipe down).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionScrollDownSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll left to the
+   * previous page (by two finger swipe left).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionPageLeftSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll right to the
+   * next page (by two finger swipe right).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionPageRightSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll up to the
+   * previous page (by one finger swipe left and right).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionPageUpSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to scroll down to the
+   * next page (by one finger swipe right and left).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionPageDownSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move the focus to
+   * the first item on the screen (by one finger swipe up and down).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionMoveToFirstSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move the focus to
+   * the last item on the screen (by one finger swipe down and up).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionMoveToLastSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to focus and read from the
+   * first item on the top continuously (by three fingers single tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to.
+   */
+  AccessibilityActionSignalType& ActionReadFromTopSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to move the focus to and
+   * read from the next item continuously (by three fingers double tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadFromNextSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to zoom (by one finger
+   * triple tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionZoomSignal();
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief This is emitted when accessibility action is received to read the information
+   * in the indicator (by two fingers triple tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadIndicatorInformationSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to pause/resume the
+   * current speech (by two fingers single tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionReadPauseResumeSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to start/stop the
+   * current action (by two fingers double tap).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionSignalType& ActionStartStopSignal();
+
+  /**
+   * @brief This is emitted when accessibility action is received to handle scroll event (by two
+   * fingers drag).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallback( AccessibilityManager& manager, const TouchEvent& event );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AccessibilityActionScrollSignalType& ActionScrollSignal();
+
+public:
+
+  explicit DALI_INTERNAL AccessibilityManager( Internal::AccessibilityManager *impl );
+
+}; // class AccessibilityManager
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ACCESSIBILITY_MANAGER_H
diff --git a/dali-toolkit/public-api/align-enumerations.h b/dali-toolkit/public-api/align-enumerations.h
new file mode 100644 (file)
index 0000000..7934d16
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMERATIONS_H
+#define DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMERATIONS_H
+
+/*
+ * Copyright (c) 2019 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
+{
+
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+/**
+ * @brief Enumerations for the alignment of Visuals
+ * @SINCE_1_2.60
+ */
+namespace Align
+{
+
+/**
+ * @brief Describes anchor point and parent origin of visuals
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  TOP_BEGIN = 0, ///< @SINCE_1_2.60
+  TOP_CENTER,    ///< @SINCE_1_2.60
+  TOP_END,       ///< @SINCE_1_2.60
+  CENTER_BEGIN,  ///< @SINCE_1_2.60
+  CENTER,        ///< @SINCE_1_2.60
+  CENTER_END,    ///< @SINCE_1_2.60
+  BOTTOM_BEGIN,  ///< @SINCE_1_2.60
+  BOTTOM_CENTER, ///< @SINCE_1_2.60
+  BOTTOM_END     ///< @SINCE_1_2.60
+};
+}
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEVEL_API_ALIGN_ENUMERATIONS_H
diff --git a/dali-toolkit/public-api/controls/alignment/alignment.cpp b/dali-toolkit/public-api/controls/alignment/alignment.cpp
new file mode 100644 (file)
index 0000000..6778b63
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/alignment/alignment.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/alignment/alignment-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Alignment::Alignment()
+{
+}
+
+Alignment Alignment::New( Type horizontal, Type vertical )
+{
+  return Internal::Alignment::New( horizontal, vertical );
+}
+
+Alignment::Alignment(const Alignment& alignment)
+: Control( alignment )
+{
+}
+
+Alignment::~Alignment()
+{
+}
+
+Alignment Alignment::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Alignment, Internal::Alignment>(handle);
+}
+
+void Alignment::SetAlignmentType( Type type )
+{
+  GetImpl( *this ).SetAlignmentType( type );
+}
+
+Alignment::Type Alignment::GetAlignmentType() const
+{
+  return GetImpl( *this ).GetAlignmentType();
+}
+
+void Alignment::SetScaling( Scaling scaling )
+{
+  GetImpl( *this ).SetScaling( scaling );
+}
+
+Alignment::Scaling Alignment::GetScaling() const
+{
+  return GetImpl( *this ).GetScaling();
+}
+
+void Alignment::SetPadding( const Alignment::Padding& padding )
+{
+  GetImpl( *this ).SetPadding( padding );
+}
+
+const Alignment::Padding& Alignment::GetPadding() const
+{
+  return GetImpl( *this ).GetPadding();
+}
+
+Alignment::Alignment( Internal::Alignment& implementation )
+: Control( implementation )
+{
+}
+
+Alignment& Alignment::operator=(const Alignment& alignment)
+{
+  if( &alignment != this )
+  {
+    Control::operator=( alignment );
+  }
+  return *this;
+}
+
+Alignment::Alignment( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Alignment>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/alignment/alignment.h b/dali-toolkit/public-api/controls/alignment/alignment.h
new file mode 100644 (file)
index 0000000..116f658
--- /dev/null
@@ -0,0 +1,266 @@
+#ifndef DALI_ALIGNMENT_H
+#define DALI_ALIGNMENT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Alignment;
+}
+/**
+ * @addtogroup dali_toolkit_controls_alignment
+ * @{
+ */
+
+/**
+ * @brief Alignment is a container which provides an easy way to align other actors inside its boundary.
+ *
+ * Additionally, it provides a scaling property to resize the contained actors @see Scaling.
+ * @SINCE_1_0.0
+ * @note The use of scaling property will override all constraints applied to actors.
+ *
+ * All actors added to an alignment are going to be set with the same anchor point and parent origin. And if the scaling property is set to a value
+ * different than ScaleNone, constraints as well.
+ */
+class DALI_TOOLKIT_API Alignment : public Control
+{
+public:
+  /**
+   * @brief Enumeration for different types of alignment.
+   * @SINCE_1_0.0
+   */
+  enum Type
+  {
+    HorizontalLeft   = 1, ///< Horizontal left alignment @SINCE_1_0.0
+    HorizontalCenter = 2, ///< Horizontal center alignment @SINCE_1_0.0
+    HorizontalRight  = 4, ///< Horizontal right alignment @SINCE_1_0.0
+    VerticalTop      = 8, ///< Vertical top alignment @SINCE_1_0.0
+    VerticalCenter   = 16, ///< Vertical center alignment @SINCE_1_0.0
+    VerticalBottom   = 32 ///< Vertical bottom alignment @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Scaling determines how actors are scaled to match the alignment's boundary.
+   * @SINCE_1_0.0
+   */
+  enum Scaling
+  {
+    ScaleNone,             ///< The original size is kept. @SINCE_1_0.0
+    ScaleToFill,           ///< Scale added actors to fill alignment's boundary. Aspect ratio is not maintained. @SINCE_1_0.0
+    ScaleToFitKeepAspect,  ///< Scale added actors to fit within the alignment's boundary. Aspect ratio is maintained. @SINCE_1_0.0
+    ScaleToFillKeepAspect, ///< Scale added actors to fill the alignment's boundary. Aspect ratio is maintained, and the actor may exceed the alignment's boundary. @SINCE_1_0.0
+    ShrinkToFit,           ///< If added actors are larger than the alignment's boundary it will be shrunk down to fit. Aspect ratio is not maintained @SINCE_1_0.0
+    ShrinkToFitKeepAspect, ///< If added actors are larger than the alignment's boundary it will be shrunk down to fit. Aspect ratio is maintained @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Structure describing the padding values.
+   * @SINCE_1_0.0
+   */
+  struct Padding
+  {
+    /**
+     * @brief Constructor.
+     * @SINCE_1_0.0
+     */
+    Padding()
+    : left( 0.f ),
+      right( 0.f ),
+      top( 0.f ),
+      bottom( 0.f )
+    {
+    }
+
+    /**
+     * @brief Constructor.
+     *
+     * @SINCE_1_0.0
+     * @param[in] l Left padding
+     * @param[in] r Right padding
+     * @param[in] t Top padding
+     * @param[in] b Bottom padding
+     */
+    Padding( float l, float r, float t, float b )
+    : left( l ),
+      right( r ),
+      top( t ),
+      bottom( b )
+    {
+    }
+
+    float left;  ///< The left padding
+    float right; ///< The right padding
+    float top;   ///< The top padding
+    float bottom; ///< The bottom padding
+  };
+
+  /**
+   * @brief Creates an Alignment handle; this can be initialized with Alignment::New().
+   *
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_0.0
+   */
+  Alignment();
+
+  /**
+   * @brief Creates an alignment control.
+   *
+   * @SINCE_1_0.0
+   * @param[in] horizontal Specifies how to align actors horizontally. Could be HorizontalLeft, HorizontalCenter or HorizontalRight. By default, HorizontalCenter
+   * @param[in] vertical Specifies how to align actors vertically. Could be VerticalTop, VerticalCenter or VerticalBottom. By default, VerticalCenter
+   * @return A handle to the Alignment control
+   */
+  static Alignment New( Type horizontal = HorizontalCenter, Type vertical = VerticalCenter );
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object.
+   *
+   * @SINCE_1_0.0
+   * @param[in] alignment Object to copy
+   */
+  Alignment(const Alignment& alignment);
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Alignment();
+
+  /**
+   * @brief Downcasts a handle to Alignment handle.
+   *
+   * If handle points to an Alignment, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a Alignment or an uninitialized handle
+   */
+  static Alignment DownCast( BaseHandle handle );
+
+  /**
+   * @brief Sets the new alignment. By default, ( HorizontalCenter | VerticalCenter ).
+   *
+   * @SINCE_1_0.0
+   * @param[in] type The new alignment option
+   * @note There should only be one horizontal and one vertical policy.
+   */
+  void SetAlignmentType( Type type );
+
+  /**
+   * @brief Gets the current alignment combined into a single value.
+   *
+   * The values can be tested by using the & operator and the desired
+   * flag. e.g.
+   * @code
+   *   if (GetAlignmentType() & HorizontalCentre)
+   *   {
+   *     ...
+   *   }
+   * @endcode
+   *
+   * @SINCE_1_0.0
+   * @return the alignment value
+   */
+  Type GetAlignmentType() const;
+
+  /**
+   * @brief Sets how added actors scale to fit the alignment's boundary.
+   *
+   * @SINCE_1_0.0
+   * @param[in] scaling The scaling property
+   * @see Scaling.
+   */
+  void SetScaling( Scaling scaling );
+
+  /**
+   * @brief Retrieves the scaling property.
+   *
+   * @SINCE_1_0.0
+   * @return The scaling
+   * @see Scaling.
+   */
+  Scaling GetScaling() const;
+
+  /**
+   * @brief Sets a padding value.
+   *
+   * @SINCE_1_0.0
+   * @param[in] padding The left, right, top, bottom padding values
+   */
+  void SetPadding( const Padding& padding );
+
+  /**
+   * @brief Gets the padding values.
+   *
+   * @SINCE_1_0.0
+   * @return The left, right, top, bottom padding values
+   */
+  const Padding& GetPadding() const;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   * @param[in] alignment Object to copy
+   * @return A reference to this
+   */
+  Alignment& operator=(const Alignment& alignment);
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL Alignment( Internal::Alignment& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL Alignment( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_ALIGNMENT_H
diff --git a/dali-toolkit/public-api/controls/buttons/button.cpp b/dali-toolkit/public-api/controls/buttons/button.cpp
new file mode 100644 (file)
index 0000000..70377b3
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/controls/buttons/button.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/images/resource-image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/buttons/button-impl.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/public-api/visuals/text-visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Button::Button()
+{}
+
+Button::Button( const Button& button )
+: Control( button )
+{
+}
+
+Button& Button::operator=( const Button& button )
+{
+  if( &button != this )
+  {
+    Control::operator=( button );
+  }
+  return *this;
+}
+
+Button::~Button()
+{
+}
+
+Button Button::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Button, Internal::Button>(handle);
+}
+
+Button::ButtonSignalType& Button::PressedSignal()
+{
+  return Dali::Toolkit::GetImplementation( *this ).PressedSignal();
+}
+
+Button::ButtonSignalType& Button::ReleasedSignal()
+{
+  return Dali::Toolkit::GetImplementation( *this ).ReleasedSignal();
+}
+
+Button::ButtonSignalType& Button::ClickedSignal()
+{
+  return Dali::Toolkit::GetImplementation( *this ).ClickedSignal();
+}
+
+Button::ButtonSignalType& Button::StateChangedSignal()
+{
+  return Dali::Toolkit::GetImplementation( *this ).StateChangedSignal();
+}
+
+Button::Button( Internal::Button& implementation )
+: Control( implementation )
+{
+}
+
+Button::Button( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Button>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/buttons/button.h b/dali-toolkit/public-api/controls/buttons/button.h
new file mode 100644 (file)
index 0000000..2544d46
--- /dev/null
@@ -0,0 +1,352 @@
+#ifndef DALI_TOOLKIT_BUTTON_H
+#define DALI_TOOLKIT_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Button;
+}
+/**
+ * @addtogroup dali_toolkit_controls_buttons
+ * @{
+ */
+
+/**
+ * @brief Button is a base class for different kinds of buttons.
+ *
+ * This class provides the disabled property and the clicked signal.
+ *
+ * A ClickedSignal() is emitted when the button is touched and the touch point doesn't leave the boundary of the button.
+ *
+ * When the \e disabled property is set to \e true, no signal is emitted.
+ *
+ * Button provides the following properties which modify the signals emitted:
+ * <ul>
+ *   <li>\e autorepeating
+ *       When \e autorepeating is set to \e true, a Button::PressedSignal(), Button::ReleasedSignal() and Button::ClickedSignal() signals are emitted at regular
+ *       intervals while the button is touched.
+ *       The intervals could be modified with the Button::SetInitialAutoRepeatingDelay and Button::SetNextAutoRepeatingDelay methods.
+ *
+ *       A \e togglable button can't be \e autorepeating. If the \e autorepeating property is set to \e true, then the \e togglable property is set to
+ *       false but no signal is emitted.
+ *
+ *   <li>\e togglable
+ *       When \e togglable is set to \e true, a Button::StateChangedSignal() signal is emitted, with the selected state.
+ * </ul>
+ *
+ * 'Visual' describes not just traditional images like png, bmp but refers to whatever is used to show the button, it could be a color, gradient or some other kind of renderer.
+ *
+ * The button's appearance can be modified by setting properties for the various visuals/images.
+ *
+ * It is not mandatory to set all visuals. A button could be defined only by setting its \e background visual or by setting its \e background and \e selected visuals.
+ *
+ * The \e button visual is shown over the \e background visual.
+ * When pressed the unselected visuals are replaced by the \e selected visual. The text label is always placed on the top of all images.
+ *
+ * When the button is disabled, \e background, \e button and \e selected visuals are replaced by their \e disabled visuals.
+ *
+ *
+ * Signals
+ * | %Signal Name     | Method                      |
+ * |------------------|-----------------------------|
+ * | pressed          | @ref PressedSignal()        |
+ * | released         | @ref ReleasedSignal()       |
+ * | clicked          | @ref ClickedSignal()        |
+ * | stateChanged     | @ref StateChangedSignal()   |
+ *
+ * Actions
+ * | %Action Name     | Attributes              | Description                                   |
+ * |------------------|-------------------------|-----------------------------------------------|
+ * | buttonClick      | Doesn't have attributes | Simulates a button click. See @ref DoAction() |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API Button : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the Button class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the Button class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      /**
+       * @brief name "disabled", type bool
+       * @details Sets the button as \e disabled.
+       * @SINCE_1_0.0
+       */
+      DISABLED = PROPERTY_START_INDEX,
+
+      /**
+       * @brief name "autoRepeating", type bool
+       * @details If the \e autorepeating property is set to \e true then the \e togglable property is set to false
+       * @SINCE_1_0.0
+       */
+      AUTO_REPEATING,
+
+      /**
+       * @brief name "initialAutoRepeatingDelay", type float
+       * @details By default this value is set to 0.15 seconds.
+       * @SINCE_1_0.0
+       */
+      INITIAL_AUTO_REPEATING_DELAY,
+
+      /**
+       * @brief name "nextAutoRepeatingDelay", type float
+       * @details default this value is set to 0.05 seconds
+       * @SINCE_1_0.0
+       */
+      NEXT_AUTO_REPEATING_DELAY,
+
+      /**
+       * @brief name "togglable", type bool
+       * @details If the \e togglable property is set to \e true, then the \e autorepeating property is set to false.
+       * @SINCE_1_0.0
+       */
+      TOGGLABLE,
+
+      /**
+       * @brief name "selected", type bool
+       * @details Sets the togglable button as either selected or unselected, \e togglable property must be set to \e true.
+       * @SINCE_1_0.0
+       */
+      SELECTED,
+
+      /**
+       * @brief name "unselectedVisual", type string if it is a url, map otherwise.
+       * @details Sets the unselected button foreground/icon visual
+       * @SINCE_1_4.32
+       */
+      UNSELECTED_VISUAL,
+
+      /**
+       * @brief name "selectedImage", type string if it is a url, map otherwise
+       * @details Sets the selected button foreground/icon visual
+       * @SINCE_1_4.32
+       */
+      SELECTED_VISUAL,
+
+      /**
+       * @brief name "disabledSelectedVisual", type string if it is a url, map otherwise
+       * @details Sets the disabled selected state foreground/icon button visual
+       * @SINCE_1_4.32
+       */
+      DISABLED_SELECTED_VISUAL,
+
+      /**
+       * @brief name "disabledUnselectedVisual", type string if it is a url, map otherwise
+       * @details Sets the disabled unselected state foreground/icon visual
+       * @SINCE_1_4.32
+       */
+      DISABLED_UNSELECTED_VISUAL,
+
+      /**
+       * @brief name "unselectedBackgroundVisual", type string if it is a url, map otherwise
+       * @details Sets the disabled in the unselected state background, button visual
+       * @SINCE_1_4.32
+       */
+      UNSELECTED_BACKGROUND_VISUAL,
+
+      /**
+       * @brief name "label", type Property::Map or std::string
+       * @SINCE_1_0.0
+       */
+      LABEL,
+
+      /**
+       * @brief name "selectedBackgroundVisual", type string if it is a url, map otherwise
+       * @details Sets the selected background button visual
+       * @SINCE_1_4.32
+       */
+      SELECTED_BACKGROUND_VISUAL,
+
+      /**
+       * @brief name "disabledUnselectedBackgroundVisual", type string if it is a url, map otherwise
+       * @details Sets the disabled while unselected background button visual
+       * @SINCE_1_4.32
+       */
+      DISABLED_UNSELECTED_BACKGROUND_VISUAL,
+
+      /**
+       * @brief name "disabledSelectedBackgroundVisual", type string if it is a url, map otherwise
+       * @details Sets the disabled while selected background button visual
+       * @SINCE_1_4.32
+       */
+      DISABLED_SELECTED_BACKGROUND_VISUAL,
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates an uninitialized Button.
+   *
+   * Only derived versions can be instantiated.  Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  Button();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] button Handle to an object
+   */
+  Button( const Button& button );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] button Handle to an object
+   * @return A reference to this
+   */
+  Button& operator=( const Button& button );
+
+  /**
+   * @brief Downcasts a handle to Button handle.
+   *
+   * If handle points to a Button, the downcast produces valid handle.
+   * If not the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a Button or an uninitialized handle
+   */
+  static Button DownCast( BaseHandle handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Button();
+
+public: //Signals
+
+  /**
+   * @brief Button signal type.
+   * @SINCE_1_0.0
+   */
+  typedef Signal< bool ( Button ) > ButtonSignalType;
+
+  /**
+   * @brief This signal is emitted when the button is touched.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Button button );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  ButtonSignalType& PressedSignal();
+
+  /**
+   * @brief This signal is emitted when the button is touched and the touch point leaves the boundary of the button.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Button button );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  ButtonSignalType& ReleasedSignal();
+
+  /**
+   * @brief This signal is emitted when the button is touched and the touch point doesn't leave the boundary of the button.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Button button );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  ButtonSignalType& ClickedSignal();
+
+  /**
+   * @brief This signal is emitted when the button's state is changed.
+   *
+   * The application can get the state by calling IsSelected().
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Button button );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  ButtonSignalType& StateChangedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL Button( Internal::Button& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL Button( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_BUTTON_H
diff --git a/dali-toolkit/public-api/controls/buttons/check-box-button.cpp b/dali-toolkit/public-api/controls/buttons/check-box-button.cpp
new file mode 100644 (file)
index 0000000..e2f7f56
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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 "check-box-button.h"
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/controls/buttons/check-box-button-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+CheckBoxButton::CheckBoxButton()
+: Button()
+{
+}
+
+CheckBoxButton::CheckBoxButton( const CheckBoxButton& checkBox )
+: Button( checkBox )
+{
+}
+
+CheckBoxButton& CheckBoxButton::operator=( const CheckBoxButton& checkBox )
+{
+  if( &checkBox != this )
+  {
+    Button::operator=( checkBox );
+  }
+  return *this;
+}
+
+CheckBoxButton::~CheckBoxButton()
+{
+}
+
+CheckBoxButton CheckBoxButton::New()
+{
+  return Internal::CheckBoxButton::New();
+}
+
+CheckBoxButton CheckBoxButton::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<CheckBoxButton, Internal::CheckBoxButton>(handle);
+}
+
+CheckBoxButton::CheckBoxButton( Internal::CheckBoxButton& implementation )
+: Button( implementation )
+{
+}
+
+CheckBoxButton::CheckBoxButton( Dali::Internal::CustomActor* internal )
+: Button( internal )
+{
+  VerifyCustomActorPointer<Internal::CheckBoxButton>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/buttons/check-box-button.h b/dali-toolkit/public-api/controls/buttons/check-box-button.h
new file mode 100644 (file)
index 0000000..8b4c8cf
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef DALI_TOOLKIT_CHECK_BOX_BUTTON_H
+#define DALI_TOOLKIT_CHECK_BOX_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/buttons/button.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+
+namespace Internal DALI_INTERNAL
+{
+class CheckBoxButton;
+}
+/**
+ * @addtogroup dali_toolkit_controls_buttons
+ * @{
+ */
+
+/**
+ * @brief CheckBoxButton provides a check box button which user can check or uncheck.
+ *
+ * By default, a CheckBoxButton emits a Button::ClickedSignal() signal when the button changes its state to selected or unselected.
+ *
+ * The button's appearance could be modified by Button::SetUnselectedImage, Button::SetBackgroundImage,
+ * Button::SetSelectedImage, Button::SetSelectedBackgroundImage, Button::SetDisabledBackgroundImage,
+ * Button::SetDisabledImage, and Button::SetDisabledSelectedImage.
+ *
+ * When the button is not disabled, if it's not selected it only shows the \e background image. The \e selected image is shown over the
+ * \e background image when the box is selected (\e background image is not replaced by \e selected image).
+ *
+ * When the button is disabled, \e background image and \e selected image are replaced by \e disabled images.
+ *
+ * Usage example: -
+ *
+ * @code
+ * // in Creating a DALi Application
+ * void HelloWorldExample::Create( Application& application )
+ * {
+ *   CheckBoxButton button = CheckBoxButton::New();
+ *   button.SetParentOrigin( ParentOrigin::CENTER );
+ *   button.SetProperty( Button::Property::LABEL, "Check" );
+ *   button.SetSize( 200, 40 );
+ *   button.SetBackgroundColor( Color::WHITE );
+ *   Stage::GetCurrent().Add( button );
+ *
+ *   // Connect to a button signal emitted by the button
+ *   button.StateChangedSignal().Connect( this, &HelloWorldExample::OnButtonStateChanged );
+ * }
+ *
+ * bool HelloWorldExample::OnButtonStateChanged( Button button )
+ * {
+ *   // Do something when the button state is changed
+ *   // You can get the state using button.IsSelected() call
+ *   return true;
+ * }
+ * @endcode
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API CheckBoxButton : public Button
+{
+public:
+
+  /**
+   * @brief Creates an uninitialized CheckBoxButton; this can be initialized with CheckBoxButton::New().
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  CheckBoxButton();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] checkBox Handle to an object
+   */
+  CheckBoxButton( const CheckBoxButton& checkBox );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] checkBox Handle to an object
+   * @return A reference to this
+   */
+  CheckBoxButton& operator=( const CheckBoxButton& checkBox );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~CheckBoxButton();
+
+  /**
+   * @brief Creates an initialized CheckBoxButton.
+   * @SINCE_1_0.0
+   * @return A handle to a newly allocated Dali resource
+   */
+  static CheckBoxButton New();
+
+  /**
+   * @brief Downcasts a handle to CheckBoxButton handle.
+   *
+   * If handle points to a CheckBoxButton, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a CheckBoxButton or an uninitialized handle
+   */
+  static CheckBoxButton DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL CheckBoxButton( Internal::CheckBoxButton& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL CheckBoxButton( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CHECK_BOX_BUTTON_H
diff --git a/dali-toolkit/public-api/controls/buttons/push-button.cpp b/dali-toolkit/public-api/controls/buttons/push-button.cpp
new file mode 100644 (file)
index 0000000..6a70aaf
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/controls/buttons/push-button.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+#include <dali/public-api/images/resource-image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/buttons/push-button-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+PushButton::PushButton()
+: Button()
+{
+}
+
+PushButton::PushButton( Internal::PushButton& implementation )
+: Button( implementation )
+{
+}
+
+PushButton::PushButton( const PushButton& pushButton )
+: Button( pushButton )
+{
+}
+
+PushButton& PushButton::operator=( const PushButton& pushButton )
+{
+  if( &pushButton != this )
+  {
+    Button::operator=( pushButton );
+  }
+  return *this;
+}
+
+PushButton::PushButton( Dali::Internal::CustomActor* internal )
+: Button( internal )
+{
+  VerifyCustomActorPointer<Internal::PushButton>(internal);
+}
+
+PushButton::~PushButton()
+{
+}
+
+PushButton PushButton::New()
+{
+  return Internal::PushButton::New();
+}
+
+PushButton PushButton::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<PushButton, Internal::PushButton>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/buttons/push-button.h b/dali-toolkit/public-api/controls/buttons/push-button.h
new file mode 100644 (file)
index 0000000..fdcc657
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef DALI_TOOLKIT_PUSH_BUTTON_H
+#define DALI_TOOLKIT_PUSH_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "button.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+
+class PushButton;
+}
+/**
+ * @addtogroup dali_toolkit_controls_buttons
+ * @{
+ */
+
+/**
+ * @brief A PushButton changes its appearance when is pressed and returns to its original when is released.
+ *
+ * By default, a PushButton emits a Button::PressedSignal() signal when the button is pressed, a Button::ClickedSignal() signal when it's clicked.
+ * and a Button::ReleasedSignal() signal when it's released or having pressed it, the touch point leaves the boundary of the button.
+ *
+ * Usage example: -
+ *
+ * @code
+ * // in Creating a DALi Application
+ * void HelloWorldExample::Create( Application& application )
+ * {
+ *   PushButton button = PushButton::New();
+ *   button.SetParentOrigin( ParentOrigin::CENTER );
+ *   button.SetProperty( Button::Property::LABEL, "Press" );
+ *   Stage::GetCurrent().Add( button );
+ *
+ *   // Connect to button signals emitted by the button
+ *   button.ClickedSignal().Connect( this, &HelloWorldExample::OnButtonClicked );
+ *   button.PressedSignal().Connect( this, &HelloWorldExample::OnButtonPressed );
+ *   button.ReleasedSignal().Connect( this, &HelloWorldExample::OnButtonReleased );
+ * }
+ *
+ * bool HelloWorldExample::OnButtonClicked( Button button )
+ * {
+ *   // Do something when the button is clicked
+ *   return true;
+ * }
+ *
+ * bool HelloWorldExample::OnButtonPressed( Button button )
+ * {
+ *   // Do something when the button is pressed
+ *   return true;
+ * }
+ *
+ * bool HelloWorldExample::OnButtonReleased( Button button )
+ * {
+ *   // Do something when the button is released
+ *   return true;
+ * }
+ * @endcode
+ *
+ * See Button for more details on signals and modifying appearance via properties.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API PushButton : public Button
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Button::PROPERTY_END_INDEX + 1,          ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserving 1000 property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the PushButton class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the PushButton class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      UNSELECTED_ICON = PROPERTY_START_INDEX, ///< Property, name "unselectedIcon",  type std::string @SINCE_1_0.0 @DEPRECATED_1_2.XX Button::Property::UNSELECTED_VISUAL
+      SELECTED_ICON,                          ///< Property, name "selectedIcon",    type std::string @SINCE_1_0.0 @DEPRECATED_1_2.XX Button::Property::SELECTED_VISUAL
+      ICON_ALIGNMENT,                         ///< Property, name "iconAlignment",   type std::string @SINCE_1_0.0 @DEPRECATED_1_2.XX Use Button::Property::LABEL_RELATIVE_ALIGNMENT
+      LABEL_PADDING,                          ///< Property, name "labelPadding",    type Vector4 @SINCE_1_0.0
+      ICON_PADDING,                           ///< Property, name "iconPadding",     type Vector4 @SINCE_1_0.0
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates an uninitialized PushButton; this can be initialized with PushButton::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  PushButton();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] pushButton Handle to an object
+   */
+  PushButton( const PushButton& pushButton );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] pushButton Handle to an object
+   * @return A reference to this
+   */
+  PushButton& operator=( const PushButton& pushButton );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~PushButton();
+
+  /**
+   * @brief Creates an initialized PushButton.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to a newly allocated Dali resource
+   */
+  static PushButton New();
+
+  /**
+   * @brief Downcasts a handle to PushButton handle.
+   *
+   * If handle points to a PushButton, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return handle to a PushButton or an uninitialized handle
+   */
+  static PushButton DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL PushButton( Internal::PushButton& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL PushButton( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_PUSH_BUTTON_H
diff --git a/dali-toolkit/public-api/controls/buttons/radio-button.cpp b/dali-toolkit/public-api/controls/buttons/radio-button.cpp
new file mode 100644 (file)
index 0000000..7538723
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/public-api/controls/buttons/radio-button.h>
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/controls/buttons/radio-button-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+RadioButton::RadioButton()
+  : Button()
+{
+}
+
+RadioButton::RadioButton( Internal::RadioButton& implementation )
+  : Button( implementation )
+{
+}
+
+RadioButton::RadioButton( const RadioButton& radioButton )
+  : Button( radioButton )
+{
+}
+
+RadioButton& RadioButton::operator=( const RadioButton& radioButton )
+{
+  if( &radioButton != this )
+  {
+    Button::operator=( radioButton );
+  }
+  return *this;
+}
+
+RadioButton::RadioButton( Dali::Internal::CustomActor* internal )
+  : Button( internal )
+{
+  VerifyCustomActorPointer<Internal::RadioButton>( internal );
+}
+
+RadioButton::~RadioButton()
+{
+}
+
+RadioButton RadioButton::New()
+{
+  return Internal::RadioButton::New();
+}
+
+RadioButton RadioButton::New( const std::string& label )
+{
+  RadioButton radioButton = Internal::RadioButton::New();
+  radioButton.SetProperty( Toolkit::Button::Property::LABEL, label );
+  return radioButton;
+}
+
+RadioButton RadioButton::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<RadioButton, Internal::RadioButton>( handle );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/buttons/radio-button.h b/dali-toolkit/public-api/controls/buttons/radio-button.h
new file mode 100644 (file)
index 0000000..2793710
--- /dev/null
@@ -0,0 +1,178 @@
+#ifndef DALI_TOOLKIT_RADIO_BUTTON_H
+#define DALI_TOOLKIT_RADIO_BUTTON_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "button.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+// Forward declarations
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+
+class RadioButton;
+}
+/**
+ * @addtogroup dali_toolkit_controls_buttons
+ * @{
+ */
+
+/**
+ * @brief A RadioButton provides a radio button which two states \e selected or \e unselected.
+ *
+ * Radio buttons are designed to select one of many option at the same time.
+ *
+ * Every button have its own \e label and \e state, which can be modified by Button::Property::LABEL and Button::Property::SELECTED.
+ *
+ * RadioButton can change its current state using Button::SetSelected.
+ *
+ * RadioButtons can be grouped.
+ * Two or more RadioButtons are in one group when they have this same parent.
+ * In each groups only one RadioButton can be \e selected at a given time.
+ * So when RadioButton is set to \e selected, other RadioButtons in its group are set to \e unselected.
+ * When \e selected RadioButton is set to \e unselected no other RadioButtons in his group is set to \e selected.
+ *
+ * A Button::StateChangedSignal() is emitted when the RadioButton change its state to \e selected or \e unselected.
+ *
+ * Usage example: -
+ *
+ * @code
+ * // In Creating a DALi Application
+ *
+ * // Create a group to bind two or more RadioButtons together
+ * Actor radioGroup = Actor::New();
+ * radioGroup.SetParentOrigin( ParentOrigin::CENTER );
+ * Stage::GetCurrent().Add( radioGroup );
+ *
+ * // Make the first RadioButton and add it to its parent
+ * RadioButton button1 = RadioButton::New();
+ * button1.SetProperty( Button::Property::LABEL, "button1" );
+ * button1.SetBackgroundColor( Color::WHITE );
+ * button1.SetPosition( 0, -40 );
+ * radioGroup.Add( button1 );
+ *
+ * // Make more RadioButtons and add them to their parent
+ * RadioButton button2 = RadioButton::New();
+ * button2.SetProperty( Toolkit::Button::Property::LABEL, "button2" );
+ * button2.SetBackgroundColor( Color::WHITE );
+ * button2.SetPosition( 0, 40 );
+ * radioGroup.Add( button2 );
+ *
+ * @endcode
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API RadioButton: public Button
+{
+ public:
+  /**
+   * @brief Creates an uninitialized RadioButton; this can be initialized with RadioButton::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  RadioButton();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] radioButton Handle to an object
+   */
+  RadioButton( const RadioButton& radioButton );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] radioButton Handle to an object
+   * @return A reference to this
+   */
+  RadioButton& operator=( const RadioButton& radioButton );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~RadioButton();
+
+  /**
+   * @brief Creates an initialized RadioButton.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to a newly allocated Dali resource
+   */
+  static RadioButton New();
+
+  /**
+   * @brief Creates an initialized RadioButton with given label.
+   *
+   * @SINCE_1_0.0
+   * @param[in] label The button label
+   * @return A handle to a newly allocated Dali resource
+   */
+  static RadioButton New( const std::string& label );
+
+  /**
+   * @brief Downcasts a handle to RadioButton handle.
+   *
+   * If handle points to a RadioButton, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a RadioButton or an uninitialized handle
+   */
+  static RadioButton DownCast( BaseHandle handle );
+
+ public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL RadioButton( Internal::RadioButton& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL RadioButton( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_RADIO_BUTTON_H
diff --git a/dali-toolkit/public-api/controls/control-impl.cpp b/dali-toolkit/public-api/controls/control-impl.cpp
new file mode 100755 (executable)
index 0000000..c469d1c
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/controls/control-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+#include <limits>
+#include <stack>
+#include <typeinfo>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
+#include <dali/devel-api/scripting/scripting.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/align-enumerations.h>
+#include <dali-toolkit/public-api/controls/control.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/visuals/color-visual-properties.h>
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/devel-api/controls/control-devel.h>
+#include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
+#include <dali-toolkit/devel-api/visuals/color-visual-properties-devel.h>
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+#include <dali-toolkit/internal/visuals/color/color-visual.h>
+#include <dali-toolkit/internal/visuals/visual-string-constants.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_CONTROL_VISUALS");
+#endif
+
+/**
+ * @brief Replace the background visual if it's a color visual with the renderIfTransparent property set as required.
+ * @param[in] controlImpl The control implementation
+ * @param[in] renderIfTransaparent Whether we should render if the color is transparent
+ */
+void ChangeBackgroundColorVisual( Control& controlImpl, bool renderIfTransparent )
+{
+  Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+
+  Toolkit::Visual::Base backgroundVisual = controlDataImpl.GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( backgroundVisual )
+  {
+    Property::Map map;
+    backgroundVisual.CreatePropertyMap( map );
+    Property::Value* typeValue = map.Find( Toolkit::Visual::Property::TYPE );
+    if( typeValue && typeValue->Get< int >() == Toolkit::Visual::COLOR )
+    {
+      // Only change it if it's a color visual
+      map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = renderIfTransparent;
+      controlImpl.SetBackground( map );
+    }
+  }
+}
+
+/**
+ * @brief Creates a clipping renderer if required.
+ * (EG. If no renders exist and clipping is enabled).
+ * @param[in] controlImpl The control implementation.
+ */
+void CreateClippingRenderer( Control& controlImpl )
+{
+  // We want to add a transparent background if we do not have one for clipping.
+  Actor self( controlImpl.Self() );
+  int clippingMode = ClippingMode::DISABLED;
+  if( self.GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) )
+  {
+    switch( clippingMode )
+    {
+      case ClippingMode::CLIP_CHILDREN:
+      {
+        if( self.GetRendererCount() == 0u )
+        {
+          Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
+          if( controlDataImpl.mVisuals.Empty() )
+          {
+            controlImpl.SetBackgroundColor( Color::TRANSPARENT );
+          }
+          else
+          {
+            // We have visuals, check if we've set the background and re-create it to
+            // render even if transparent (only if it's a color visual)
+            ChangeBackgroundColorVisual( controlImpl, true );
+          }
+        }
+        break;
+      }
+
+      case ClippingMode::DISABLED:
+      case ClippingMode::CLIP_TO_BOUNDING_BOX:
+      {
+        // If we have a background visual, check if it's a color visual and remove the render if transparent flag
+        ChangeBackgroundColorVisual( controlImpl, false );
+        break;
+      }
+    }
+  }
+}
+
+} // unnamed namespace
+
+
+Toolkit::Control Control::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr<Control> controlImpl = new Control( ControlBehaviour( CONTROL_BEHAVIOUR_DEFAULT ) );
+
+  // Pass ownership to handle
+  Toolkit::Control handle( *controlImpl );
+
+  // Second-phase init of the implementation
+  // This can only be done after the CustomActor connection has been made...
+  controlImpl->Initialize();
+
+  return handle;
+}
+
+void Control::SetStyleName( const std::string& styleName )
+{
+  if( styleName != mImpl->mStyleName )
+  {
+    mImpl->mStyleName = styleName;
+
+    // Apply new style, if stylemanager is available
+    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    if( styleManager )
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+    }
+  }
+}
+
+const std::string& Control::GetStyleName() const
+{
+  return mImpl->mStyleName;
+}
+
+void Control::SetBackgroundColor( const Vector4& color )
+{
+  mImpl->mBackgroundColor = color;
+  Property::Map map;
+  map[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::COLOR;
+  map[ Toolkit::ColorVisual::Property::MIX_COLOR ] = color;
+
+  int clippingMode = ClippingMode::DISABLED;
+  if( ( Self().GetProperty( Actor::Property::CLIPPING_MODE ).Get( clippingMode ) ) &&
+      ( clippingMode == ClippingMode::CLIP_CHILDREN ) )
+  {
+    // If clipping-mode is set to CLIP_CHILDREN, then force visual to add the render even if transparent
+    map[ Toolkit::DevelColorVisual::Property::RENDER_IF_TRANSPARENT ] = true;
+  }
+
+  SetBackground( map );
+}
+
+void Control::SetBackground( const Property::Map& map )
+{
+  Toolkit::Visual::Base visual = Toolkit::VisualFactory::Get().CreateVisual( map );
+  visual.SetName("background");
+  if( visual )
+  {
+    mImpl->RegisterVisual( Toolkit::Control::Property::BACKGROUND, visual, DepthIndex::BACKGROUND );
+
+    // Trigger a size negotiation request that may be needed by the new visual to relayout its contents.
+    RelayoutRequest();
+  }
+}
+
+void Control::ClearBackground()
+{
+   mImpl->UnregisterVisual( Toolkit::Control::Property::BACKGROUND );
+   mImpl->mBackgroundColor = Color::TRANSPARENT;
+
+   // Trigger a size negotiation request that may be needed when unregistering a visual.
+   RelayoutRequest();
+}
+
+void Control::EnableGestureDetection(Gesture::Type type)
+{
+  if ( (type & Gesture::Pinch) && !mImpl->mPinchGestureDetector )
+  {
+    mImpl->mPinchGestureDetector = PinchGestureDetector::New();
+    mImpl->mPinchGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PinchDetected);
+    mImpl->mPinchGestureDetector.Attach(Self());
+  }
+
+  if ( (type & Gesture::Pan) && !mImpl->mPanGestureDetector )
+  {
+    mImpl->mPanGestureDetector = PanGestureDetector::New();
+    mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected);
+    mImpl->mPanGestureDetector.Attach(Self());
+  }
+
+  if ( (type & Gesture::Tap) && !mImpl->mTapGestureDetector )
+  {
+    mImpl->mTapGestureDetector = TapGestureDetector::New();
+    mImpl->mTapGestureDetector.DetectedSignal().Connect(mImpl, &Impl::TapDetected);
+    mImpl->mTapGestureDetector.Attach(Self());
+  }
+
+  if ( (type & Gesture::LongPress) && !mImpl->mLongPressGestureDetector )
+  {
+    mImpl->mLongPressGestureDetector = LongPressGestureDetector::New();
+    mImpl->mLongPressGestureDetector.DetectedSignal().Connect(mImpl, &Impl::LongPressDetected);
+    mImpl->mLongPressGestureDetector.Attach(Self());
+  }
+}
+
+void Control::DisableGestureDetection(Gesture::Type type)
+{
+  if ( (type & Gesture::Pinch) && mImpl->mPinchGestureDetector )
+  {
+    mImpl->mPinchGestureDetector.Detach(Self());
+    mImpl->mPinchGestureDetector.Reset();
+  }
+
+  if ( (type & Gesture::Pan) && mImpl->mPanGestureDetector )
+  {
+    mImpl->mPanGestureDetector.Detach(Self());
+    mImpl->mPanGestureDetector.Reset();
+  }
+
+  if ( (type & Gesture::Tap) && mImpl->mTapGestureDetector )
+  {
+    mImpl->mTapGestureDetector.Detach(Self());
+    mImpl->mTapGestureDetector.Reset();
+  }
+
+  if ( (type & Gesture::LongPress) && mImpl->mLongPressGestureDetector)
+  {
+    mImpl->mLongPressGestureDetector.Detach(Self());
+    mImpl->mLongPressGestureDetector.Reset();
+  }
+}
+
+PinchGestureDetector Control::GetPinchGestureDetector() const
+{
+  return mImpl->mPinchGestureDetector;
+}
+
+PanGestureDetector Control::GetPanGestureDetector() const
+{
+  return mImpl->mPanGestureDetector;
+}
+
+TapGestureDetector Control::GetTapGestureDetector() const
+{
+  return mImpl->mTapGestureDetector;
+}
+
+LongPressGestureDetector Control::GetLongPressGestureDetector() const
+{
+  return mImpl->mLongPressGestureDetector;
+}
+
+void Control::SetKeyboardNavigationSupport(bool isSupported)
+{
+  mImpl->mIsKeyboardNavigationSupported = isSupported;
+}
+
+bool Control::IsKeyboardNavigationSupported()
+{
+  return mImpl->mIsKeyboardNavigationSupported;
+}
+
+void Control::SetKeyInputFocus()
+{
+  if( Self().OnStage() )
+  {
+    Toolkit::KeyInputFocusManager::Get().SetFocus(Toolkit::Control::DownCast(Self()));
+  }
+}
+
+bool Control::HasKeyInputFocus()
+{
+  bool result = false;
+  if( Self().OnStage() )
+  {
+    Toolkit::Control control = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl();
+    if( Self() == control )
+    {
+      result = true;
+    }
+  }
+  return result;
+}
+
+void Control::ClearKeyInputFocus()
+{
+  if( Self().OnStage() )
+  {
+    Toolkit::KeyInputFocusManager::Get().RemoveFocus(Toolkit::Control::DownCast(Self()));
+  }
+}
+
+void Control::SetAsKeyboardFocusGroup(bool isFocusGroup)
+{
+  mImpl->mIsKeyboardFocusGroup = isFocusGroup;
+
+  // The following line will be removed when the deprecated API in KeyboardFocusManager is deleted
+  Toolkit::KeyboardFocusManager::Get().SetAsFocusGroup(Self(), isFocusGroup);
+}
+
+bool Control::IsKeyboardFocusGroup()
+{
+  return Toolkit::KeyboardFocusManager::Get().IsFocusGroup(Self());
+}
+
+void Control::AccessibilityActivate()
+{
+  // Inform deriving classes
+  OnAccessibilityActivated();
+}
+
+void Control::KeyboardEnter()
+{
+  // Inform deriving classes
+  OnKeyboardEnter();
+}
+
+bool Control::OnAccessibilityActivated()
+{
+  return false; // Accessibility activation is not handled by default
+}
+
+bool Control::OnKeyboardEnter()
+{
+  return false; // Keyboard enter is not handled by default
+}
+
+bool Control::OnAccessibilityPan(PanGesture gesture)
+{
+  return false; // Accessibility pan gesture is not handled by default
+}
+
+bool Control::OnAccessibilityTouch(const TouchEvent& touchEvent)
+{
+  return false; // Accessibility touch event is not handled by default
+}
+
+bool Control::OnAccessibilityValueChange(bool isIncrease)
+{
+  return false; // Accessibility value change action is not handled by default
+}
+
+bool Control::OnAccessibilityZoom()
+{
+  return false; // Accessibility zoom action is not handled by default
+}
+
+Actor Control::GetNextKeyboardFocusableActor(Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  return Actor();
+}
+
+void Control::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
+{
+}
+
+Toolkit::Control::KeyEventSignalType& Control::KeyEventSignal()
+{
+  return mImpl->mKeyEventSignal;
+}
+
+Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusGainedSignal()
+{
+  return mImpl->mKeyInputFocusGainedSignal;
+}
+
+Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusLostSignal()
+{
+  return mImpl->mKeyInputFocusLostSignal;
+}
+
+bool Control::EmitKeyEventSignal( const KeyEvent& event )
+{
+  // Guard against destruction during signal emission
+  Dali::Toolkit::Control handle( GetOwner() );
+
+  bool consumed = false;
+
+  consumed = mImpl->FilterKeyEvent( event );
+
+  // signals are allocated dynamically when someone connects
+  if ( !consumed && !mImpl->mKeyEventSignal.Empty() )
+  {
+    consumed = mImpl->mKeyEventSignal.Emit( handle, event );
+  }
+
+  if ( !consumed )
+  {
+    // Notification for derived classes
+    consumed = OnKeyEvent(event);
+  }
+
+  return consumed;
+}
+
+Control::Control( ControlBehaviour behaviourFlags )
+: CustomActorImpl( static_cast< ActorFlags >( behaviourFlags ) ),
+  mImpl(new Impl(*this))
+{
+  mImpl->mFlags = behaviourFlags;
+}
+
+Control::~Control()
+{
+  delete mImpl;
+}
+
+void Control::Initialize()
+{
+  // Call deriving classes so initialised before styling is applied to them.
+  OnInitialize();
+
+  if( (mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS) ||
+      !(mImpl->mFlags & DISABLE_STYLE_CHANGE_SIGNALS) )
+  {
+    Toolkit::StyleManager styleManager = StyleManager::Get();
+
+    // if stylemanager is available
+    if( styleManager )
+    {
+      StyleManager& styleManagerImpl = GetImpl( styleManager );
+
+      // Register for style changes
+      styleManagerImpl.ControlStyleChangeSignal().Connect( this, &Control::OnStyleChange );
+
+      // Apply the current style
+      styleManagerImpl.ApplyThemeStyleAtInit( Toolkit::Control( GetOwner() ) );
+    }
+  }
+
+  if( mImpl->mFlags & REQUIRES_KEYBOARD_NAVIGATION_SUPPORT )
+  {
+    SetKeyboardNavigationSupport( true );
+  }
+}
+
+void Control::OnInitialize()
+{
+}
+
+void Control::OnControlChildAdd( Actor& child )
+{
+}
+
+void Control::OnControlChildRemove( Actor& child )
+{
+}
+
+void Control::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
+{
+  // By default the control is only interested in theme (not font) changes
+  if( styleManager && change == StyleChange::THEME_CHANGE )
+  {
+    GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+    RelayoutRequest();
+  }
+}
+
+void Control::OnPinch(const PinchGesture& pinch)
+{
+  if( !( mImpl->mStartingPinchScale ) )
+  {
+    // lazy allocate
+    mImpl->mStartingPinchScale = new Vector3;
+  }
+
+  if( pinch.state == Gesture::Started )
+  {
+    *( mImpl->mStartingPinchScale ) = Self().GetCurrentScale();
+  }
+
+  Self().SetScale( *( mImpl->mStartingPinchScale ) * pinch.scale );
+}
+
+void Control::OnPan( const PanGesture& pan )
+{
+}
+
+void Control::OnTap(const TapGesture& tap)
+{
+}
+
+void Control::OnLongPress( const LongPressGesture& longPress )
+{
+}
+
+void Control::EmitKeyInputFocusSignal( bool focusGained )
+{
+  Dali::Toolkit::Control handle( GetOwner() );
+
+  if ( focusGained )
+  {
+    // signals are allocated dynamically when someone connects
+    if ( !mImpl->mKeyInputFocusGainedSignal.Empty() )
+    {
+      mImpl->mKeyInputFocusGainedSignal.Emit( handle );
+    }
+  }
+  else
+  {
+    // signals are allocated dynamically when someone connects
+    if ( !mImpl->mKeyInputFocusLostSignal.Empty() )
+    {
+      mImpl->mKeyInputFocusLostSignal.Emit( handle );
+    }
+  }
+}
+
+void Control::OnStageConnection( int depth )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection number of registered visuals(%d)\n",  mImpl->mVisuals.Size() );
+
+  Actor self( Self() );
+
+  for(RegisteredVisualContainer::Iterator iter = mImpl->mVisuals.Begin(); iter!= mImpl->mVisuals.End(); iter++)
+  {
+    // Check whether the visual is empty and enabled
+    if( (*iter)->visual && (*iter)->enabled )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::OnStageConnection Setting visual(%d) on stage\n", (*iter)->index );
+      Toolkit::GetImplementation((*iter)->visual).SetOnStage( self );
+    }
+  }
+
+  // The clipping renderer is only created if required.
+  CreateClippingRenderer( *this );
+
+  // Request to be laid out when the control is connected to the Stage.
+  // Signal that a Relayout may be needed
+}
+
+
+void Control::OnStageDisconnection()
+{
+  mImpl->OnStageDisconnection();
+}
+
+void Control::OnKeyInputFocusGained()
+{
+  EmitKeyInputFocusSignal( true );
+}
+
+void Control::OnKeyInputFocusLost()
+{
+  EmitKeyInputFocusSignal( false );
+}
+
+void Control::OnChildAdd(Actor& child)
+{
+  // Notify derived classes.
+  OnControlChildAdd( child );
+}
+
+void Control::OnChildRemove(Actor& child)
+{
+  // Notify derived classes.
+  OnControlChildRemove( child );
+}
+
+void Control::OnPropertySet( Property::Index index, Property::Value propertyValue )
+{
+  // If the clipping mode has been set, we may need to create a renderer.
+  // Only do this if we are already on-stage as the OnStageConnection will handle the off-stage clipping controls.
+  if( ( index == Actor::Property::CLIPPING_MODE ) && Self().OnStage() )
+  {
+    // Note: This method will handle whether creation of the renderer is required.
+    CreateClippingRenderer( *this );
+  }
+}
+
+void Control::OnSizeSet(const Vector3& targetSize)
+{
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
+  {
+    Vector2 size( targetSize );
+    visual.SetTransformAndSize( Property::Map(), size ); // Send an empty map as we do not want to modify the visual's set transform
+  }
+}
+
+void Control::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
+{
+  // @todo size negotiate background to new size, animate as well?
+}
+
+bool Control::OnTouchEvent(const TouchEvent& event)
+{
+  return false; // Do not consume
+}
+
+bool Control::OnHoverEvent(const HoverEvent& event)
+{
+  return false; // Do not consume
+}
+
+bool Control::OnKeyEvent(const KeyEvent& event)
+{
+  return false; // Do not consume
+}
+
+bool Control::OnWheelEvent(const WheelEvent& event)
+{
+  return false; // Do not consume
+}
+
+void Control::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  for( unsigned int i = 0, numChildren = Self().GetChildCount(); i < numChildren; ++i )
+  {
+    Actor child = Self().GetChildAt( i );
+    Vector2 newChildSize( size );
+
+    // When set the padding or margin on the control, child should be resized and repositioned.
+    if( ( mImpl->mPadding.start != 0 ) || ( mImpl->mPadding.end != 0 ) || ( mImpl->mPadding.top != 0 ) || ( mImpl->mPadding.bottom != 0 ) ||
+        ( mImpl->mMargin.start != 0 ) || ( mImpl->mMargin.end != 0 ) || ( mImpl->mMargin.top != 0 ) || ( mImpl->mMargin.bottom != 0 ) )
+    {
+      Extents padding = mImpl->mPadding;
+
+      Dali::CustomActor ownerActor(GetOwner());
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>( ownerActor.GetProperty( Dali::Actor::Property::LAYOUT_DIRECTION ).Get<int>() );
+
+      if( Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection )
+      {
+        std::swap( padding.start, padding.end );
+      }
+
+      newChildSize.width = size.width - ( padding.start + padding.end );
+      newChildSize.height = size.height - ( padding.top + padding.bottom );
+
+      // Cannot use childs Position property as it can already have padding and margin applied on it,
+      // so we end up cumulatively applying them over and over again.
+      Vector2 childOffset( 0.f, 0.f );
+      childOffset.x += ( mImpl->mMargin.start + padding.start );
+      childOffset.y += ( mImpl->mMargin.top + padding.top );
+
+      child.SetPosition( childOffset.x, childOffset.y );
+    }
+    container.Add( child, newChildSize );
+  }
+
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
+  {
+    visual.SetTransformAndSize( Property::Map(), size ); // Send an empty map as we do not want to modify the visual's set transform
+  }
+}
+
+void Control::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+{
+}
+
+Vector3 Control::GetNaturalSize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Control::GetNaturalSize for %s\n", Self().GetName().c_str() );
+  Toolkit::Visual::Base visual = mImpl->GetVisual( Toolkit::Control::Property::BACKGROUND );
+  if( visual )
+  {
+    Vector2 naturalSize;
+    visual.GetNaturalSize( naturalSize );
+    naturalSize.width += ( mImpl->mPadding.start + mImpl->mPadding.end );
+    naturalSize.height += ( mImpl->mPadding.top + mImpl->mPadding.bottom );
+    return Vector3( naturalSize );
+  }
+  return Vector3::ZERO;
+}
+
+float Control::CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension )
+{
+  return CalculateChildSizeBase( child, dimension );
+}
+
+float Control::GetHeightForWidth( float width )
+{
+  return GetHeightForWidthBase( width );
+}
+
+float Control::GetWidthForHeight( float height )
+{
+  return GetWidthForHeightBase( height );
+}
+
+bool Control::RelayoutDependentOnChildren( Dimension::Type dimension )
+{
+  return RelayoutDependentOnChildrenBase( dimension );
+}
+
+void Control::OnCalculateRelayoutSize( Dimension::Type dimension )
+{
+}
+
+void Control::OnLayoutNegotiated( float size, Dimension::Type dimension )
+{
+}
+
+void Control::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
+{
+  mImpl->SignalConnected( slotObserver, callback );
+}
+
+void Control::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
+{
+  mImpl->SignalDisconnected( slotObserver, callback );
+}
+
+Control& GetImplementation( Dali::Toolkit::Control& handle )
+{
+  CustomActorImpl& customInterface = handle.GetImplementation();
+  // downcast to control
+  Control& impl = dynamic_cast< Internal::Control& >( customInterface );
+  return impl;
+}
+
+const Control& GetImplementation( const Dali::Toolkit::Control& handle )
+{
+  const CustomActorImpl& customInterface = handle.GetImplementation();
+  // downcast to control
+  const Control& impl = dynamic_cast< const Internal::Control& >( customInterface );
+  return impl;
+}
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/control-impl.h b/dali-toolkit/public-api/controls/control-impl.h
new file mode 100644 (file)
index 0000000..f2e4402
--- /dev/null
@@ -0,0 +1,715 @@
+#ifndef DALI_TOOLKIT_CONTROL_IMPL_H
+#define DALI_TOOLKIT_CONTROL_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/style-change.h>
+#include <dali/public-api/events/long-press-gesture.h>
+#include <dali/public-api/events/pan-gesture.h>
+#include <dali/public-api/events/pinch-gesture.h>
+#include <dali/public-api/events/tap-gesture.h>
+#include <dali/public-api/object/property-index-ranges.h>
+#include <dali/public-api/object/type-info.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+class StyleManager;
+
+namespace Internal
+{
+
+/**
+ * @brief This is the internal base class for all controls.
+ *
+ * It will provide some common functionality required by all controls.
+ * Implements ConnectionTrackerInterface so that signals (typically connected to member functions) will
+ * be disconnected automatically when the control is destroyed.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API Control : public CustomActorImpl, public ConnectionTrackerInterface
+{
+public:
+
+  class Extension; ///< Forward declare future extension interface
+
+  // Creation & Destruction
+
+  /**
+   * @brief Creates a new ControlImpl instance that does not require touch by default.
+   *
+   * If touch is required, then the user can connect to this class' touch signal.
+   * @SINCE_1_0.0
+   * @return A handle to the ControlImpl instance
+   */
+  static Toolkit::Control New();
+
+protected:
+  /**
+   * @brief Virtual destructor.
+   * @SINCE_1_0.0
+   */
+  virtual ~Control();
+
+public:
+  // Styling
+
+  /**
+   * @copydoc Dali::Toolkit::Control::SetStyleName
+   */
+  void SetStyleName( const std::string& styleName );
+
+  /**
+   * @copydoc Dali::Toolkit::Control::GetStyleName
+   */
+  const std::string& GetStyleName() const;
+
+  // Background
+
+  /**
+   * @copydoc Dali::Toolkit::Control::SetBackgroundColor
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+   * @brief Sets the background with a property map.
+   *
+   * @SINCE_1_0.0
+   * @param[in] map The background property map
+   */
+  void SetBackground(const Property::Map& map);
+
+  /**
+   * @copydoc Dali::Toolkit::Control::ClearBackground
+   */
+  void ClearBackground();
+
+  // Gesture Detection
+
+  /**
+   * @brief Allows deriving classes to enable any of the gesture detectors that are available.
+   *
+   * Gesture detection can be enabled one at a time or in bitwise format as shown:
+   * @code
+   * EnableGestureDetection(Gesture::Type(Gesture::Pinch | Gesture::Tap | Gesture::Pan));
+   * @endcode
+   * @SINCE_1_0.0
+   * @param[in] type The gesture type(s) to enable
+   */
+  void EnableGestureDetection( Gesture::Type type );
+
+  /**
+   * @brief Allows deriving classes to disable any of the gesture detectors.
+   *
+   * Like EnableGestureDetection, this can also be called using bitwise or.
+   * @SINCE_1_0.0
+   * @param[in] type The gesture type(s) to disable
+   * @see EnableGetureDetection
+   */
+  void DisableGestureDetection( Gesture::Type type );
+
+  /**
+   * @brief If deriving classes wish to fine tune pinch gesture
+   * detection, then they can access the gesture detector through this
+   * API and modify the detection.
+   *
+   * @SINCE_1_0.0
+   * @return The pinch gesture detector
+   * @pre Pinch detection should have been enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  PinchGestureDetector GetPinchGestureDetector() const;
+
+  /**
+   * @brief If deriving classes wish to fine tune pan gesture
+   * detection, then they can access the gesture detector through this
+   * API and modify the detection.
+   *
+   * @SINCE_1_0.0
+   * @return The pan gesture detector
+   * @pre Pan detection should have been enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  PanGestureDetector GetPanGestureDetector() const;
+
+  /**
+   * @brief If deriving classes wish to fine tune tap gesture
+   * detection, then they can access the gesture detector through this
+   * API and modify the detection.
+   *
+   * @SINCE_1_0.0
+   * @return The tap gesture detector
+   * @pre Tap detection should have been enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  TapGestureDetector GetTapGestureDetector() const;
+
+  /**
+   * @brief If deriving classes wish to fine tune long press gesture
+   * detection, then they can access the gesture detector through this
+   * API and modify the detection.
+   *
+   * @SINCE_1_0.0
+   * @return The long press gesture detector
+   * @pre Long press detection should have been enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  LongPressGestureDetector GetLongPressGestureDetector() const;
+
+  // Keyboard Navigation
+
+  /**
+   * @brief Sets whether this control supports two dimensional
+   * keyboard navigation (i.e. whether it knows how to handle the
+   * keyboard focus movement between its child actors).
+   *
+   * The control doesn't support it by default.
+   * @SINCE_1_0.0
+   * @param[in] isSupported Whether this control supports two dimensional keyboard navigation
+   */
+  void SetKeyboardNavigationSupport( bool isSupported );
+
+  /**
+   * @brief Gets whether this control supports two dimensional keyboard navigation.
+   *
+   * @SINCE_1_0.0
+   * @return true if this control supports two dimensional keyboard navigation
+   */
+  bool IsKeyboardNavigationSupported();
+
+  // Key Input
+
+  /**
+   * @copydoc Toolkit::Control::SetKeyInputFocus()
+   */
+  void SetKeyInputFocus();
+
+  /**
+   * @copydoc Toolkit::Control::HasKeyInputFocus()
+   */
+  bool HasKeyInputFocus();
+
+  /**
+   * @copydoc Toolkit::Control::ClearKeyInputFocus()
+   */
+  void ClearKeyInputFocus();
+
+  // Keyboard Focus
+
+  /**
+   * @brief Sets whether this control is a focus group for keyboard navigation.
+   *
+   * (i.e. the scope of keyboard focus movement
+   * can be limited to its child actors). The control is not a focus group by default.
+   * @SINCE_1_0.0
+   * @param[in] isFocusGroup Whether this control is set as a focus group for keyboard navigation
+   */
+  void SetAsKeyboardFocusGroup( bool isFocusGroup );
+
+  /**
+   * @brief Gets whether this control is a focus group for keyboard navigation.
+   *
+   * @SINCE_1_0.0
+   * @return true if this control is set as a focus group for keyboard navigation
+   */
+  bool IsKeyboardFocusGroup();
+
+  /// @cond internal
+  /**
+   * @brief Called by the AccessibilityManager to activate the Control.
+   * @SINCE_1_0.0
+   */
+  DALI_INTERNAL void AccessibilityActivate();
+
+  /**
+   * @brief Called by the KeyboardFocusManager.
+   * @SINCE_1_0.0
+   */
+  DALI_INTERNAL void KeyboardEnter();
+  /// @endcond
+
+  // Signals
+
+  /**
+   * @copydoc Dali::Toolkit::Control::KeyEventSignal()
+   */
+  Toolkit::Control::KeyEventSignalType& KeyEventSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Control::KeyInputFocusGainedSignal()
+   */
+  Toolkit::Control::KeyInputFocusSignalType& KeyInputFocusGainedSignal();
+
+  /**
+   * @copydoc Dali::Toolkit::Control::KeyInputFocusLostSignal()
+   */
+  Toolkit::Control::KeyInputFocusSignalType& KeyInputFocusLostSignal();
+
+  /// @cond internal
+  /**
+   * @brief Called by the KeyInputFocusManager to emit key event signals.
+   *
+   * @SINCE_1_0.0
+   * @param[in] event The key event
+   * @return True if the event was consumed
+   */
+  DALI_INTERNAL bool EmitKeyEventSignal( const KeyEvent& event );
+  /// @endcond
+
+protected: // For derived classes to call
+
+  /**
+   * @brief Emits KeyInputFocusGained signal if true else emits KeyInputFocusLost signal.
+   *
+   * Should be called last by the control after it acts on the Input Focus change.
+   *
+   * @SINCE_1_0.0
+   * @param[in] focusGained True if gained, False if lost
+   */
+  void EmitKeyInputFocusSignal( bool focusGained );
+
+protected: // From CustomActorImpl, not to be used by application developers
+
+  /**
+   * @copydoc CustomActorImpl::OnStageConnection()
+   * @note If overridden, then an up-call to Control::OnStageConnection MUST be made at the end.
+   */
+  virtual void OnStageConnection( int depth );
+
+  /**
+   * @copydoc CustomActorImpl::OnStageDisconnection()
+   * @note If overridden, then an up-call to Control::OnStageDisconnection MUST be made at the end.
+   */
+  virtual void OnStageDisconnection();
+
+  /**
+   * @copydoc CustomActorImpl::OnChildAdd()
+   * @note If overridden, then an up-call to Control::OnChildAdd MUST be made at the end.
+   */
+  virtual void OnChildAdd( Actor& child );
+
+  /**
+   * @copydoc CustomActorImpl::OnChildRemove()
+   * @note If overridden, then an up-call to Control::OnChildRemove MUST be made at the end.
+   */
+  virtual void OnChildRemove( Actor& child );
+
+  /**
+   * @copydoc CustomActorImpl::OnPropertySet()
+   * @note If overridden, then an up-call to Control::OnChildRemove MUST be made at the end.
+   */
+  virtual void OnPropertySet( Property::Index index, Property::Value propertyValue );
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeSet()
+   * @note If overridden, then an up-call to Control::OnSizeSet MUST be made at the end.
+   */
+  virtual void OnSizeSet( const Vector3& targetSize );
+
+  /**
+   * @copydoc CustomActorImpl::OnSizeAnimation()
+   * @note If overridden, then an up-call to Control::OnSizeAnimation MUST be made at the end.
+   */
+  virtual void OnSizeAnimation( Animation& animation, const Vector3& targetSize );
+
+  /**
+   * @copydoc CustomActorImpl::OnTouchEvent()
+   */
+  virtual bool OnTouchEvent( const TouchEvent& event );
+
+  /**
+   * @copydoc CustomActorImpl::OnHoverEvent()
+   */
+  virtual bool OnHoverEvent( const HoverEvent& event );
+
+  /**
+   * @copydoc CustomActorImpl::OnKeyEvent()
+   */
+  virtual bool OnKeyEvent( const KeyEvent& event );
+
+  /**
+   * @copydoc CustomActorImpl::OnWheelEvent()
+   */
+  virtual bool OnWheelEvent( const WheelEvent& event );
+
+  /**
+   * @copydoc CustomActorImpl::OnRelayout()
+   */
+  virtual void OnRelayout( const Vector2& size, RelayoutContainer& container );
+
+  /**
+   * @copydoc CustomActorImpl::OnSetResizePolicy()
+   */
+  virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension );
+
+  /**
+   * @copydoc CustomActorImpl::GetNaturalSize()
+   */
+  virtual Vector3 GetNaturalSize();
+
+  /**
+   * @copydoc CustomActorImpl::CalculateChildSize()
+   */
+  virtual float CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension );
+
+  /**
+   * @copydoc CustomActorImpl::GetHeightForWidth()
+   */
+  virtual float GetHeightForWidth( float width );
+
+  /**
+   * @copydoc CustomActorImpl::GetWidthForHeight()
+   */
+  virtual float GetWidthForHeight( float height );
+
+  /**
+   * @copydoc CustomActorImpl::RelayoutDependentOnChildren()
+   */
+  virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS );
+
+  /**
+   * @copydoc CustomActorImpl::OnCalculateRelayoutSize()
+   */
+  virtual void OnCalculateRelayoutSize( Dimension::Type dimension );
+
+  /**
+   * @copydoc CustomActorImpl::OnLayoutNegotiated()
+   */
+  virtual void OnLayoutNegotiated( float size, Dimension::Type dimension );
+
+protected: // Helpers for deriving classes
+
+  // Construction
+
+  /**
+   * @brief Flags for the constructor.
+   * @SINCE_1_0.0
+   */
+  enum ControlBehaviour
+  {
+    CONTROL_BEHAVIOUR_DEFAULT            = 0, ///< Default behaviour: Size negotiation is enabled & listens to Style Change signal, but doesn't receive event callbacks. @SINCE_1_2_10
+    REQUIRES_STYLE_CHANGE_SIGNALS        = 1 << ( CustomActorImpl::ACTOR_FLAG_COUNT + 0 ),     ///< True if needs to monitor style change signals such as theme/font change @SINCE_1_0.0 @DEPRECATED_1_2_10
+    REQUIRES_KEYBOARD_NAVIGATION_SUPPORT = 1 << ( CustomActorImpl::ACTOR_FLAG_COUNT + 1 ),     ///< True if needs to support keyboard navigation @SINCE_1_0.0
+
+    DISABLE_STYLE_CHANGE_SIGNALS         = 1 << ( CustomActorImpl::ACTOR_FLAG_COUNT + 2 ),     ///< True if control should not monitor style change signals @SINCE_1_2_10
+
+    LAST_CONTROL_BEHAVIOUR_FLAG
+  };
+
+  static const int CONTROL_BEHAVIOUR_FLAG_COUNT = Log< LAST_CONTROL_BEHAVIOUR_FLAG - 1 >::value + 1;      ///< Total count of flags
+
+  /**
+   * @brief Control constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] behaviourFlags Behavioural flags from ControlBehaviour enum
+   */
+  Control( ControlBehaviour behaviourFlags );
+
+  /**
+   * @brief Second phase initialization.
+   * @SINCE_1_0.0
+   */
+  void Initialize();
+
+public: // API for derived classes to override
+
+  // Lifecycle
+
+  /**
+   * @brief This method is called after the Control has been initialized.
+   *
+   * Derived classes should do any second phase initialization by overriding this method.
+   * @SINCE_1_0.0
+   */
+  virtual void OnInitialize();
+
+  /**
+   * @DEPRECATED_1_1.30. Override OnChildAdd instead.
+   *
+   * @brief Called whenever an Actor is added to the control.
+   *
+   * Could be overridden by derived classes.
+   *
+   * @SINCE_1_0.0
+   * @param[in] child The added actor
+   */
+  virtual void OnControlChildAdd( Actor& child ) DALI_DEPRECATED_API;
+
+  /**
+   * @DEPRECATED_1_1.30. Override OnChildRemove instead.
+   *
+   * @brief Called whenever an Actor is removed from the control.
+   *
+   * Could be overridden by derived classes.
+   *
+   * @SINCE_1_0.0
+   * @param[in] child The removed actor
+   */
+  virtual void OnControlChildRemove( Actor& child ) DALI_DEPRECATED_API;
+
+  // Styling
+
+  /**
+   * @brief This method should be overridden by deriving classes requiring notifications when the style changes.
+   *
+   * @SINCE_1_0.0
+   * @param[in] styleManager The StyleManager object
+   * @param[in] change Information denoting what has changed
+   */
+  virtual void OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change );
+
+  // Accessibility
+
+  /**
+   * @brief This method is called when the control is accessibility activated.
+   *
+   * Derived classes should override this to perform custom accessibility activation.
+   * @SINCE_1_0.0
+   * @return true if this control can perform accessibility activation
+   */
+  virtual bool OnAccessibilityActivated();
+
+  /**
+   * @brief This method should be overridden by deriving classes when they wish to respond the accessibility
+   * pan gesture.
+   *
+   * @SINCE_1_0.0
+   * @param[in] gesture The pan gesture
+   * @return true if the pan gesture has been consumed by this control
+   */
+  virtual bool OnAccessibilityPan( PanGesture gesture );
+
+  /**
+   * @brief This method should be overridden by deriving classes when they wish to respond the accessibility
+   * touch event.
+   *
+   * @SINCE_1_0.0
+   * @param[in] touchEvent The touch event
+   * @return true if the touch event has been consumed by this control
+   */
+  virtual bool OnAccessibilityTouch( const TouchEvent& touchEvent );
+
+  /**
+   * @brief This method should be overridden by deriving classes when they wish to respond
+   * the accessibility up and down action (i.e. value change of slider control).
+   *
+   * @SINCE_1_0.0
+   * @param[in] isIncrease Whether the value should be increased or decreased
+   * @return true if the value changed action has been consumed by this control
+   */
+  virtual bool OnAccessibilityValueChange( bool isIncrease );
+
+  /**
+   * @brief This method should be overridden by deriving classes when they wish to respond
+   * the accessibility zoom action.
+   *
+   * @SINCE_1_0.0
+   * @return true if the zoom action has been consumed by this control
+   */
+  virtual bool OnAccessibilityZoom();
+
+  // Keyboard focus
+
+  /**
+   * @brief Called when the control gains key input focus.
+   *
+   * Should be overridden by derived classes if they need to customize what happens when focus is gained.
+   * @SINCE_1_0.0
+   */
+  virtual void OnKeyInputFocusGained();
+
+  /**
+   * @brief Called when the control loses key input focus.
+   *
+   * Should be overridden by derived classes if they need to customize what happens when focus is lost.
+   * @SINCE_1_0.0
+   */
+  virtual void OnKeyInputFocusLost();
+
+  /**
+   * @brief Gets the next keyboard focusable actor in this control towards the given direction.
+   *
+   * A control needs to override this function in order to support two dimensional keyboard navigation.
+   * @SINCE_1_0.0
+   * @param[in] currentFocusedActor The current focused actor
+   * @param[in] direction The direction to move the focus towards
+   * @param[in] loopEnabled Whether the focus movement should be looped within the control
+   * @return The next keyboard focusable actor in this control or an empty handle if no actor can be focused
+   */
+  virtual Actor GetNextKeyboardFocusableActor( Actor currentFocusedActor, Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled );
+
+  /**
+   * @brief Informs this control that its chosen focusable actor will be focused.
+   *
+   * This allows the application to perform any actions if wishes
+   * before the focus is actually moved to the chosen actor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] commitedFocusableActor The commited focusable actor
+   */
+  virtual void OnKeyboardFocusChangeCommitted( Actor commitedFocusableActor );
+
+  /**
+   * @brief This method is called when the control has enter pressed on it.
+   *
+   * Derived classes should override this to perform custom actions.
+   * @SINCE_1_0.0
+   * @return true if this control supported this action
+   */
+  virtual bool OnKeyboardEnter();
+
+  // Gestures
+
+  /**
+   * @brief Called whenever a pinch gesture is detected on this control.
+   *
+   * This can be overridden by deriving classes when pinch detection
+   * is enabled.  The default behaviour is to scale the control by the
+   * pinch scale.
+   *
+   * @SINCE_1_0.0
+   * @param[in] pinch The pinch gesture
+   * @note If overridden, then the default behavior will not occur.
+   * @note Pinch detection should be enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  virtual void OnPinch( const PinchGesture& pinch );
+
+  /**
+   * @brief Called whenever a pan gesture is detected on this control.
+   *
+   * This should be overridden by deriving classes when pan detection
+   * is enabled.
+   *
+   * @SINCE_1_0.0
+   * @param[in] pan The pan gesture
+   * @note There is no default behavior with panning.
+   * @note Pan detection should be enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  virtual void OnPan( const PanGesture& pan );
+
+  /**
+   * @brief Called whenever a tap gesture is detected on this control.
+   *
+   * This should be overridden by deriving classes when tap detection
+   * is enabled.
+   *
+   * @SINCE_1_0.0
+   * @param[in] tap The tap gesture
+   * @note There is no default behavior with a tap.
+   * @note Tap detection should be enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  virtual void OnTap( const TapGesture& tap );
+
+  /**
+   * @brief Called whenever a long press gesture is detected on this control.
+   *
+   * This should be overridden by deriving classes when long press
+   * detection is enabled.
+   *
+   * @SINCE_1_0.0
+   * @param[in] longPress The long press gesture
+   * @note There is no default behaviour associated with a long press.
+   * @note Long press detection should be enabled via EnableGestureDetection().
+   * @see EnableGestureDetection
+   */
+  virtual void OnLongPress( const LongPressGesture& longPress );
+
+  // From ConnectionTrackerInterface
+
+  /**
+   * @copydoc ConnectionTrackerInterface::SignalConnected
+   */
+  virtual void SignalConnected( SlotObserver* slotObserver, CallbackBase* callback );
+
+  /**
+   * @copydoc ConnectionTrackerInterface::SignalDisconnected
+   */
+  virtual void SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback );
+
+  /**
+   * @brief Retrieves the extension for this control.
+   *
+   * @SINCE_1_0.0
+   * @return The extension if available, NULL otherwise
+   */
+  virtual Extension* GetControlExtension()
+  {
+    return NULL;
+  }
+
+private:
+
+  /// @cond internal
+  // Undefined
+  DALI_INTERNAL Control( const Control& );
+  DALI_INTERNAL Control& operator=( const Control& );
+
+public:
+  class DALI_INTERNAL Impl; // Class declaration is public so we can internally add devel API's to the Controls Impl
+
+private:
+  Impl* mImpl;
+  /// @endcond
+
+};
+
+/**
+ * @brief Gets implementation from the handle.
+ *
+ * @SINCE_1_0.0
+ * @param handle
+ * @return Implementation
+ * @pre handle is initialized and points to a control
+ */
+DALI_TOOLKIT_API Internal::Control& GetImplementation( Dali::Toolkit::Control& handle );
+
+/**
+ * @brief Gets implementation from the handle.
+ *
+ * @SINCE_1_0.0
+ * @param handle
+ * @return Implementation
+ * @pre Handle is initialized and points to a control.
+ */
+DALI_TOOLKIT_API const Internal::Control& GetImplementation( const Dali::Toolkit::Control& handle );
+
+} // namespace Internal
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_IMPL_H
diff --git a/dali-toolkit/public-api/controls/control.cpp b/dali-toolkit/public-api/controls/control.cpp
new file mode 100644 (file)
index 0000000..d9b2f8f
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/controls/control.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali-toolkit/internal/controls/control/control-data-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Control Control::New()
+{
+  return Internal::Control::New();
+}
+
+Control::Control()
+{
+}
+
+Control::Control( const Control& uiControl )
+: CustomActor( uiControl  )
+{
+}
+
+Control::~Control()
+{
+}
+
+Control& Control::operator=( const Control& handle )
+{
+  if( &handle != this )
+  {
+    CustomActor::operator=( handle );
+  }
+  return *this;
+}
+
+Control Control::DownCast( BaseHandle handle )
+{
+  return DownCast< Control, Internal::Control >(handle);
+}
+
+void Control::SetKeyInputFocus()
+{
+  Internal::GetImplementation(*this).SetKeyInputFocus();
+}
+
+bool Control::HasKeyInputFocus()
+{
+  return Internal::GetImplementation(*this).HasKeyInputFocus();
+}
+
+void Control::ClearKeyInputFocus()
+{
+  Internal::GetImplementation(*this).ClearKeyInputFocus();
+}
+
+PinchGestureDetector Control::GetPinchGestureDetector() const
+{
+  return Internal::GetImplementation(*this).GetPinchGestureDetector();
+}
+
+PanGestureDetector Control::GetPanGestureDetector() const
+{
+  return Internal::GetImplementation(*this).GetPanGestureDetector();
+}
+
+TapGestureDetector Control::GetTapGestureDetector() const
+{
+  return Internal::GetImplementation(*this).GetTapGestureDetector();
+}
+
+LongPressGestureDetector Control::GetLongPressGestureDetector() const
+{
+  return Internal::GetImplementation(*this).GetLongPressGestureDetector();
+}
+
+void Control::SetStyleName( const std::string& styleName )
+{
+  Internal::GetImplementation(*this).SetStyleName( styleName );
+}
+
+const std::string& Control::GetStyleName() const
+{
+  return Internal::GetImplementation(*this).GetStyleName();
+}
+
+void Control::SetBackgroundColor( const Vector4& color )
+{
+  Internal::GetImplementation(*this).SetBackgroundColor( color );
+}
+
+void Control::ClearBackground()
+{
+  Internal::GetImplementation(*this).ClearBackground();
+}
+
+bool Control::IsResourceReady() const
+{
+  const Internal::Control& internalControl = Toolkit::Internal::GetImplementation( *this );
+  const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
+
+  return controlDataImpl.IsResourceReady();
+}
+
+Toolkit::Visual::ResourceStatus Control::GetVisualResourceStatus( Dali::Property::Index index )
+{
+  const Internal::Control& internalControl = Toolkit::Internal::GetImplementation( *this );
+  const Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( internalControl );
+  return controlDataImpl.GetVisualResourceStatus( index );
+}
+
+Control::KeyEventSignalType& Control::KeyEventSignal()
+{
+  return Internal::GetImplementation(*this).KeyEventSignal();
+}
+
+Control::KeyInputFocusSignalType& Control::KeyInputFocusGainedSignal()
+{
+  return Internal::GetImplementation(*this).KeyInputFocusGainedSignal();
+}
+
+Control::KeyInputFocusSignalType& Control::KeyInputFocusLostSignal()
+{
+  return Internal::GetImplementation(*this).KeyInputFocusLostSignal();
+}
+
+Control::ResourceReadySignalType&  Control::ResourceReadySignal()
+{
+  Internal::Control& internalControl = Toolkit::Internal::GetImplementation( *this );
+  Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl );
+
+  return controlImpl.mResourceReadySignal;
+}
+
+Control::Control(Internal::Control& implementation)
+: CustomActor(implementation)
+{
+}
+
+Control::Control(Dali::Internal::CustomActor* internal)
+: CustomActor(internal)
+{
+  VerifyCustomActorPointer<Internal::Control>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/control.h b/dali-toolkit/public-api/controls/control.h
new file mode 100644 (file)
index 0000000..ed68e15
--- /dev/null
@@ -0,0 +1,536 @@
+#ifndef DALI_TOOLKIT_CONTROL_H
+#define DALI_TOOLKIT_CONTROL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/custom-actor.h>
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+#include <dali/public-api/events/long-press-gesture-detector.h>
+#include <dali/public-api/events/pan-gesture-detector.h>
+#include <dali/public-api/events/pinch-gesture-detector.h>
+#include <dali/public-api/events/tap-gesture-detector.h>
+#include <dali/public-api/events/tap-gesture-detector.h>
+#include <dali/public-api/images/image.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/visuals/visual-properties.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+//Forward declarations.
+
+namespace Internal
+{
+class Control;
+}
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+/**
+ * @brief Control is the base class for all controls.
+ *
+ * The implementation of the control must be supplied; see Internal::Control for more details.
+ * @SINCE_1_0.0
+ * @see Internal::Control
+ *
+ * Signals
+ * | %Signal Name           | Method                                              |
+ * |------------------------|-----------------------------------------------------|
+ * | keyEvent               | @ref KeyEventSignal()                               |
+ * | keyInputFocusGained    | @ref KeyInputFocusGainedSignal()                    |
+ * | keyInputFocusLost      | @ref KeyInputFocusLostSignal()                      |
+ * | resourceReady          | @ref ResourceReadySignal()                          |
+ * | tapped                 | @ref GetTapGestureDetector().DetectedSignal()       |
+ * | panned                 | @ref GetPanGestureDetector().DetectedSignal()       |
+ * | pinched                | @ref GetPinchGestureDetector().DetectedSignal()     |
+ * | longPressed            | @ref GetLongPressGestureDetector().DetectedSignal() |
+ *
+ * Actions
+ * | %Action Name           | %Control method called                             |
+ * |------------------------|----------------------------------------------------|
+ * | accessibilityActivated | %OnAccessibilityActivated()                        |
+ */
+class DALI_TOOLKIT_API Control : public CustomActor
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = PROPERTY_REGISTRATION_START_INDEX,        ///< Start index is used by the property registration macro. @SINCE_1_0.0
+    CONTROL_PROPERTY_START_INDEX = PROPERTY_START_INDEX,             ///< Start index of Control properties. @SINCE_1_0.0
+    CONTROL_PROPERTY_END_INDEX = CONTROL_PROPERTY_START_INDEX + 1000 ///< Reserving 1000 property indices. @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the Control class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the Control class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      /**
+       * @brief The name of the style to be applied to the control.
+       * @details Name "styleName", type Property::STRING.
+       * @see Toolkit::Control::SetStyleName()
+       * @SINCE_1_0.0
+       */
+      STYLE_NAME = PROPERTY_START_INDEX,
+
+      RESERVED_PROPERTY_01, ///< Reserved index for a removed property.
+      RESERVED_PROPERTY_02, ///< Reserved index for a removed property.
+
+      /**
+       * @brief Receives key events to the control.
+       * @details Name "keyInputFocus", type Property::BOOLEAN.
+       * @see Toolkit::Control::SetKeyInputFocus()
+       * @SINCE_1_0.0
+       */
+      KEY_INPUT_FOCUS,
+
+      /**
+       * @brief The background of the control.
+       *
+       * @details Name "background", type Property::MAP or std::string for URL or Property::VECTOR4 for Color.
+       * @SINCE_1_1.3
+       */
+      BACKGROUND,
+
+      /**
+       * @brief The outer space around the control.
+       * @details Name "margin", type Property::EXTENTS.
+       * @SINCE_1_2.62
+       * @note Margin property is to be supported by Layout algorithms and containers in future.
+       */
+      MARGIN,
+
+      /**
+       * @brief The inner space of the control.
+       * @details Name "padding", type Property::EXTENTS.
+       * @SINCE_1_2.62
+       */
+      PADDING
+    };
+  };
+
+  /**
+   * @brief Describes the direction to move the keyboard focus towards.
+   * @SINCE_1_0.0
+   */
+  struct KeyboardFocus
+  {
+    /**
+     * @brief Keyboard focus direction.
+     * @SINCE_1_0.0
+     */
+    enum Direction
+    {
+      LEFT,   ///< Move keyboard focus towards the left direction @SINCE_1_0.0
+      RIGHT,  ///< Move keyboard focus towards the right direction @SINCE_1_0.0
+      UP,     ///< Move keyboard focus towards the up direction @SINCE_1_0.0
+      DOWN,    ///< Move keyboard focus towards the down direction @SINCE_1_0.0
+      PAGE_UP,     ///< Move keyboard focus towards the previous page direction @SINCE_1_2.14
+      PAGE_DOWN    ///< Move keyboard focus towards the next page direction @SINCE_1_2.14
+    };
+  };
+
+  // Typedefs
+
+  /// @brief Key Event signal type. @SINCE_1_0.0
+  typedef Signal<bool ( Control, const KeyEvent& ) > KeyEventSignalType;
+
+  /// @brief Key InputFocusType signal type. @SINCE_1_0.0
+  typedef Signal<void ( Control ) > KeyInputFocusSignalType;
+
+  /// @brief ResourceReady signal type. @SINCE_1_2.60
+  typedef Signal<void ( Control ) > ResourceReadySignalType;
+
+public: // Creation & Destruction
+
+  /**
+   * @brief Creates a new instance of a Control.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to a new Control
+   */
+  static Control New();
+
+  /**
+   * @brief Creates an uninitialized Control handle.
+   *
+   * Only derived versions can be instantiated.  Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  Control();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   * @SINCE_1_0.0
+   * @param[in] uiControl Handle to copy
+   */
+  Control(const Control& uiControl);
+
+  /**
+   * @brief Dali::Control is intended as a base class.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Control();
+
+public: // operators
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   * @param[in] handle Object to assign this to
+   * @return Reference to this
+   */
+  Control& operator=( const Control& handle );
+
+public:
+
+  /**
+   * @brief Downcasts a handle to Control handle.
+   *
+   * If handle points to a Control, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a Control or an uninitialized handle
+   */
+  static Control DownCast( BaseHandle handle );
+
+  // Key Input
+
+  /**
+   * @brief This sets the control to receive key events.
+   *
+   * The key event can originate from a virtual or physical keyboard.
+   * @SINCE_1_0.0
+   * @pre The Control has been initialized.
+   * @pre The Control should be on the stage before setting keyboard focus.
+   */
+  void SetKeyInputFocus();
+
+  /**
+   * @brief Quries whether the control has key input focus.
+   *
+   * @SINCE_1_0.0
+   * @return true if this control has keyboard input focus
+   * @pre The Control has been initialized.
+   * @pre The Control should be on the stage before setting keyboard focus.
+   * @note The control can be set to have the focus and still not receive all the key events if another control has over ridden it.
+   * As the key input focus mechanism works like a stack, the top most control receives all the key events, and passes on the
+   * unhandled events to the controls below in the stack. A control in the stack will regain key input focus when there are no more
+   * controls above it in the focus stack.
+   * To query for the control which is on top of the focus stack use Dali::Toolkit::KeyInputFocusManager::GetCurrentKeyboardFocusActor().
+   */
+  bool HasKeyInputFocus();
+
+  /**
+   * @brief Once an actor is Set to receive key input focus this function is called to stop it receiving key events.
+   *
+   * A check is performed to ensure it was previously set, if this check fails then nothing is done.
+   * @SINCE_1_0.0
+   * @pre The Actor has been initialized.
+   */
+  void ClearKeyInputFocus();
+
+  // Gesture Detection
+
+  /**
+   * @brief Retrieves the pinch gesture detector of the control.
+   *
+   * @SINCE_1_0.0
+   * @return The pinch gesture detector
+   * @note Will return an empty handle if the control does not handle the gesture itself.
+   */
+  PinchGestureDetector GetPinchGestureDetector() const;
+
+  /**
+   * @brief Retrieves the pan gesture detector of the control.
+   *
+   * @SINCE_1_0.0
+   * @return The pan gesture detector
+   * @note Will return an empty handle if the control does not handle the gesture itself.
+   */
+  PanGestureDetector GetPanGestureDetector() const;
+
+  /**
+   * @brief Retrieves the tap gesture detector of the control.
+   *
+   * @SINCE_1_0.0
+   * @return The tap gesture detector
+   * @note Will return an empty handle if the control does not handle the gesture itself.
+   */
+  TapGestureDetector GetTapGestureDetector() const;
+
+  /**
+   * @brief Retrieves the long press gesture detector of the control.
+   *
+   * @SINCE_1_0.0
+   * @return The long press gesture detector
+   * @note Will return an empty handle if the control does not handle the gesture itself.
+   */
+  LongPressGestureDetector GetLongPressGestureDetector() const;
+
+  // Styling
+
+  /**
+   * @brief Sets the name of the style to be applied to the control.
+   *
+   * @SINCE_1_0.0
+   * @param[in] styleName A string matching a style described in a stylesheet
+   */
+  void SetStyleName( const std::string& styleName );
+
+  /**
+   * @brief Retrieves the name of the style to be applied to the control (if any).
+   * @SINCE_1_0.0
+   * @return A string matching a style, or an empty string
+   */
+  const std::string& GetStyleName() const;
+
+  // Background
+
+  /**
+   * @brief Sets the background color of the control.
+   *
+   * @SINCE_1_0.0
+   * @param[in] color The required background color of the control
+   *
+   * @note If SetBackgroundImage is called later, this background color is removed.
+   *
+   * @note The background color fully blends with the actor color.
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+   * @brief Clears the background.
+   * @SINCE_1_0.0
+   */
+  void ClearBackground();
+
+  // Resources
+
+  /**
+   * @brief Query if all resources required by a control are loaded and ready.
+   *
+   * Most resources are only loaded when the control is placed on stage.
+   * @SINCE_1_2.60
+   * @return true if the resources are loaded and ready, false otherwise
+   */
+  bool IsResourceReady() const;
+
+  /**
+   * @brief Get the loading state of the visual resource.
+   *
+   * @SINCE_1_3_5
+   * @param[in] index The Property index of the visual
+   * @return Return the loading status (PREPARING, READY and FAILED) of visual resource
+   */
+  Visual::ResourceStatus GetVisualResourceStatus( const Dali::Property::Index index );
+
+  // Signals
+
+  /**
+   * @brief This signal is emitted when key event is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName(Control control, const KeyEvent& event);
+   * @endcode
+   * The return value of True, indicates that the event should be consumed.
+   * Otherwise the signal will be emitted on the next parent of the actor.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Control has been initialized.
+   */
+  KeyEventSignalType& KeyEventSignal();
+
+  /**
+   * @brief This signal is emitted when the control gets Key Input Focus.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Control control );
+   * @endcode
+   * The return value of True, indicates that the event should be consumed.
+   * Otherwise the signal will be emitted on the next parent of the actor.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Control has been initialized.
+   */
+  KeyInputFocusSignalType& KeyInputFocusGainedSignal();
+
+  /**
+   * @brief This signal is emitted when the control loses Key Input Focus.
+   *
+   * This could be due to it being gained by another Control or Actor or just cleared from
+   * this control as no longer required.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Control control );
+   * @endcode
+   * The return value of True, indicates that the event should be consumed.
+   * Otherwise the signal will be emitted on the next parent of the actor.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Control has been initialized.
+   */
+  KeyInputFocusSignalType& KeyInputFocusLostSignal();
+
+  /**
+   * @brief This signal is emitted after all resources required by a control are loaded and ready.
+   *
+   * Most resources are only loaded when the control is placed on stage.
+   *
+   * If resources are shared between ImageViews, they are cached.
+   * In this case, the ResourceReady signal may be sent before there is an object to connect to.
+   * To protect against this, IsResourceReady() can be checked first.
+   *
+   * @code
+   *    auto newControl = Control::New();
+   *    newControl.SetResource( resourceUrl );
+   *    if ( newControl.IsResourceReady() )
+   *    {
+   *       // do something
+   *    }
+   *    else
+   *    {
+   *      newControl.ResourceReadySignal.Connect( .... )
+   *    }
+   * @endcode
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( Control control );
+   * @endcode
+   *
+   * @SINCE_1_2.60
+   * @return The signal to connect to
+   * @note A RelayoutRequest is queued by Control before this signal is emitted
+   */
+  ResourceReadySignalType& ResourceReadySignal();
+
+public: // Intended for control developers
+
+  /**
+   * @brief Creates an initialized Control.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The implementation for this control
+   * @return A handle to a newly allocated Dali resource
+   * @note Should NOT be called to create a handle from the implementation. As stated, this allocates a NEW Dali resource.
+   */
+  explicit Control(Internal::Control& implementation);
+
+  /**
+   * @brief This constructor is used by CustomActor within Dali core to create additional Control handles
+   * using an Internal CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to a newly allocated Dali resource
+   */
+  explicit Control(Dali::Internal::CustomActor* internal);
+
+public: // Templates for Deriving Classes
+
+  /**
+   * @brief Template to allow deriving controls to DownCast handles to deriving handle classes.
+   *
+   * @tparam     T      The handle class
+   * @tparam     I      The implementation class
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a class T or an uninitialized handle
+   * @see DownCast(BaseHandle)
+   */
+  template<typename T, typename I>
+  DALI_INTERNAL static T DownCast( BaseHandle handle )
+  {
+    T result;
+
+    CustomActor custom = Dali::CustomActor::DownCast( handle );
+    if ( custom )
+    {
+      CustomActorImpl& customImpl = custom.GetImplementation();
+
+      I* impl = dynamic_cast<I*>(&customImpl);
+
+      if (impl)
+      {
+        result = T(customImpl.GetOwner());
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * @brief Template to allow deriving controls to verify whether the Internal::CustomActor* is actually an
+   * implementation of their class.
+   *
+   * @tparam     I       The implementation class
+   * @SINCE_1_0.0
+   * @param[in] internal Pointer to the Internal::CustomActor
+   */
+  template<typename I>
+  DALI_INTERNAL void VerifyCustomActorPointer(Dali::Internal::CustomActor* internal)
+  {
+    // Can have a NULL pointer so we only need to check if the internal implementation is our class
+    // when there is a value.
+    if (internal)
+    {
+      DALI_ASSERT_DEBUG(dynamic_cast<I*>(&CustomActor(internal).GetImplementation()));
+    }
+  }
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_CONTROL_H
diff --git a/dali-toolkit/public-api/controls/flex-container/flex-container.cpp b/dali-toolkit/public-api/controls/flex-container/flex-container.cpp
new file mode 100644 (file)
index 0000000..ec95d8c
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/controls/flex-container/flex-container.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/flex-container/flex-container-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+FlexContainer FlexContainer::New()
+{
+  return Internal::FlexContainer::New();
+}
+
+FlexContainer::FlexContainer()
+{
+}
+
+FlexContainer::FlexContainer( const FlexContainer& handle )
+: Control( handle )
+{
+}
+
+FlexContainer& FlexContainer::operator=( const FlexContainer& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+FlexContainer::~FlexContainer()
+{
+}
+
+FlexContainer FlexContainer::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<FlexContainer, Internal::FlexContainer>(handle);
+}
+
+FlexContainer::FlexContainer( Internal::FlexContainer& implementation )
+: Control(implementation)
+{
+}
+
+FlexContainer::FlexContainer( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::FlexContainer>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/flex-container/flex-container.h b/dali-toolkit/public-api/controls/flex-container/flex-container.h
new file mode 100644 (file)
index 0000000..78965f8
--- /dev/null
@@ -0,0 +1,310 @@
+#ifndef DALI_TOOLKIT_FLEX_CONTAINER_H
+#define DALI_TOOLKIT_FLEX_CONTAINER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class FlexContainer;
+}
+
+/**
+ * @addtogroup dali_toolkit_controls_flex_container
+ * @{
+ */
+
+/**
+ * @brief FlexContainer implements a subset of the flexbox spec (defined by W3C):
+ *
+ * https://www.w3.org/TR/css3-flexbox/
+ *
+ * It aims at providing a more efficient way to lay out, align and distribute space among
+ * items in the container, even when their size is unknown or dynamic.
+ *
+ * FlexContainer has the ability to alter the width and height of its children (i.e. flex
+ * items) to fill the available space in the best possible way on different screen sizes.
+ * FlexContainer can expand items to fill available free space, or shrink them to prevent
+ * overflow.
+ *
+ * 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
+ *    |-|----------------|-|-------|--------------------------|-|------------>
+ *    | |                | |       |                          | |
+ *    | |                | |       |                          | |
+ *    | |                | |       |                          | |
+ *    | ------------------ --------|--------------------------- |
+ *    -----------------------------|--------------------------------- cross end
+ *    |                            |                            |
+ *    | main start                 | cross axis                 | main end
+ *    |                            |                            |
+ *                                 v
+ * @endcode
+ *
+ * @nosubgrouping
+ * <h3>Per-child Custom properties for script supporting:</h3>
+ *
+ * The following custom properties of the actor are checked to decide how to lay out the
+ * actor inside the flex container.
+ *
+ * These properties are registered dynamically to the child and are non-animatable.
+ *
+ * | %Property Name          | Type        |
+ * |-------------------------|-------------|
+ * | flex                    | float       |
+ * | alignSelf               | integer     |
+ * | flexMargin              | Vector4     |
+ *
+ * The available values for alignSelf are: ALIGN_AUTO, ALIGN_FLEX_START, ALIGN_CENTER, ALIGN_FLEX_END, ALIGN_STRETCH
+ *
+ * @code
+ * "name":"icon",
+ * "type":"ImageView",
+ * "image":"image.png",
+ *   "properties": {
+ *     "flex":1,                        // Property to make the item to receive the specified proportion of the free space in the container.
+ *     "alignSelf":"flexStart",         // Property to specify how the item will align along the cross axis.
+ *     "flexMargin":[10, 10, 10, 10]    // Property to specify the space around the item.
+ *   }
+ * @endcode
+ * @SINCE_1_1.35
+ */
+
+class DALI_TOOLKIT_API FlexContainer : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the direction of the main axis in the flex container. This determines
+   * the direction that flex items are laid out in the flex container.
+   * @SINCE_1_1.35
+   */
+  enum FlexDirection
+  {
+    COLUMN,                  ///< The flexible items are displayed vertically as a column @SINCE_1_1.35
+    COLUMN_REVERSE,          ///< The flexible items are displayed vertically as a column, but in reverse order @SINCE_1_1.35
+    ROW,                     ///< The flexible items are displayed horizontally as a row @SINCE_1_1.35
+    ROW_REVERSE              ///< The flexible items are displayed horizontally as a row, but in reverse order @SINCE_1_1.35
+  };
+
+  /**
+   * @brief Enumeration for the primary direction in which content is ordered in the flex container
+   * and on which sides the “start” and “end” are.
+   * @SINCE_1_1.35
+   */
+  enum ContentDirection
+  {
+    INHERIT,                 ///< Inherits the same direction from the parent @SINCE_1_1.35
+    LTR,                     ///< From left to right @SINCE_1_1.35
+    RTL                      ///< From right to left @SINCE_1_1.35
+  };
+
+  /**
+   * @brief Enumeration for the alignment of the flex items when the items do not use all available
+   * space on the main-axis.
+   * @SINCE_1_1.35
+   */
+  enum Justification
+  {
+    JUSTIFY_FLEX_START,      ///< Items are positioned at the beginning of the container @SINCE_1_1.35
+    JUSTIFY_CENTER,          ///< Items are positioned at the center of the container @SINCE_1_1.35
+    JUSTIFY_FLEX_END,        ///< Items are positioned at the end of the container @SINCE_1_1.35
+    JUSTIFY_SPACE_BETWEEN,   ///< Items are positioned with equal space between the lines @SINCE_1_1.35
+    JUSTIFY_SPACE_AROUND     ///< Items are positioned with equal space before, between, and after the lines @SINCE_1_1.35
+  };
+
+  /**
+   * @brief Enumeration for the alignment of the flex items or lines when the items or lines do not
+   * use all the available space on the cross-axis.
+   * @SINCE_1_1.35
+   */
+  enum Alignment
+  {
+    ALIGN_AUTO,              ///< Inherits the same alignment from the parent (only valid for "alignSelf" property) @SINCE_1_1.35
+    ALIGN_FLEX_START,        ///< At the beginning of the container @SINCE_1_1.35
+    ALIGN_CENTER,            ///< At the center of the container @SINCE_1_1.35
+    ALIGN_FLEX_END,          ///< At the end of the container @SINCE_1_1.35
+    ALIGN_STRETCH            ///< Stretch to fit the container @SINCE_1_1.35
+  };
+
+  /**
+   * @brief Enumeration for the wrap type of the flex container when there is no enough room for
+   * all the items on one flex line.
+   * @SINCE_1_1.35
+   */
+  enum WrapType
+  {
+    NO_WRAP,                 ///< Flex items laid out in single line (shrunk to fit the flex container along the main axis) @SINCE_1_1.35
+    WRAP                     ///< Flex items laid out in multiple lines if needed @SINCE_1_1.35
+  };
+
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_1.35
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,               ///< @SINCE_1_1.35
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,                           ///< Reserve property indices @SINCE_1_1.35
+
+    CHILD_PROPERTY_START_INDEX = CHILD_PROPERTY_REGISTRATION_START_INDEX,         ///< @SINCE_1_1.35
+    CHILD_PROPERTY_END_INDEX =   CHILD_PROPERTY_REGISTRATION_START_INDEX + 1000   ///< Reserve child property indices @SINCE_1_1.35
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the FlexContainer class.
+   * @SINCE_1_1.35
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the FlexContainer class.
+     * @SINCE_1_1.35
+     */
+    enum
+    {
+      // Event side properties
+      CONTENT_DIRECTION = PROPERTY_START_INDEX, ///< name "contentDirection",   The primary direction in which content is ordered,                                                 @see FlexContainer::ContentDirection,  type INTEGER @SINCE_1_1.35
+      FLEX_DIRECTION,                           ///< name "flexDirection",      The direction of the main-axis which determines the direction that flex items are laid out,        @see FlexContainer::FlexDirection,     type INTEGER @SINCE_1_1.35
+      FLEX_WRAP,                                ///< name "flexWrap",           Whether the flex items should wrap or not if there is no enough room for them on one flex line,    @see FlexContainer::WrapType,          type INTEGER @SINCE_1_1.35
+      JUSTIFY_CONTENT,                          ///< name "justifyContent",     The alignment of flex items when the items do not use all available space on the main-axis,        @see FlexContainer::Justification,     type INTEGER @SINCE_1_1.35
+      ALIGN_ITEMS,                              ///< name "alignItems",         The alignment of flex items when the items do not use all available space on the cross-axis,       @see FlexContainer::Alignment,         type INTEGER @SINCE_1_1.35
+      ALIGN_CONTENT                             ///< name "alignContent",       Similar to "alignItems", but it aligns flex lines, so only works when there are multiple lines,    @see FlexContainer::Alignment,         type INTEGER @SINCE_1_1.35
+    };
+  };
+
+  /**
+   * @brief Enumeration for the instance of child properties belonging to the FlexContainer class.
+   * @SINCE_1_1.35
+   */
+  struct ChildProperty
+  {
+    /**
+     * @brief Enumeration for the instance of child properties belonging to the FlexContainer class.
+     * @SINCE_1_1.35
+     */
+    enum
+    {
+      // Event side child properties
+      FLEX = CHILD_PROPERTY_START_INDEX,        ///< name "flex",               The proportion of the free space in the container the flex item will receive. If all items in the container set this property, their sizes will be proportional to the specified flex factor,  type FLOAT @SINCE_1_1.35
+      ALIGN_SELF,                               ///< name "alignSelf",          The alignment of the flex item along the cross axis, which, if set, overrides the default alignment for all items in the container,                         @see FlexContainer::Alignment,     type INTEGER @SINCE_1_1.35
+      FLEX_MARGIN                               ///< name "flexMargin",         The space around the flex item,                                                                                                                                                                type VECTOR4 @SINCE_1_1.35
+    };
+  };
+
+  /**
+   * @brief Creates a FlexContainer handle; this can be initialized with FlexContainer::New()
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_1.35
+   */
+  FlexContainer();
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object.
+   * @SINCE_1_1.35
+   *
+   * @param[in] handle The handle to copy from
+   */
+  FlexContainer( const FlexContainer& handle );
+
+  /**
+   * @brief Assignment operator. Changes this handle to point to another real object.
+   * @SINCE_1_1.35
+   * @param[in] handle Handle to an object
+   * @return A reference to this
+   */
+  FlexContainer& operator=( const FlexContainer& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * @details This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_1_1.35
+   */
+  ~FlexContainer();
+
+  /**
+   * @brief Creates the FlexContainer control.
+   * @SINCE_1_1.35
+   *
+   * @return A handle to the FlexContainer control
+   */
+  static FlexContainer New();
+
+  /**
+   * @brief Downcasts an Object handle to FlexContainer.
+   *
+   * @details If handle points to a FlexContainer, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_1.35
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to a FlexContainer or an uninitialized handle
+   */
+  static FlexContainer DownCast( BaseHandle handle );
+
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_1.35
+   *
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL FlexContainer( Internal::FlexContainer& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_1.35
+   *
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL FlexContainer( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_FLEX_CONTAINER_H
diff --git a/dali-toolkit/public-api/controls/image-view/image-view.cpp b/dali-toolkit/public-api/controls/image-view/image-view.cpp
new file mode 100644 (file)
index 0000000..02d3e0d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/image-view/image-view.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/resource-image.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ImageView::ImageView()
+{
+}
+
+ImageView::ImageView( const ImageView& imageView )
+: Control( imageView )
+{
+}
+
+ImageView& ImageView::operator=( const ImageView& imageView )
+{
+  if( &imageView != this )
+  {
+    Control::operator=( imageView );
+  }
+  return *this;
+}
+
+ImageView::~ImageView()
+{
+}
+
+ImageView ImageView::New()
+{
+  return Internal::ImageView::New();
+}
+
+ImageView ImageView::New( Image image )
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: New() is deprecated and will be removed from next release. use New( const std::string& ) instead.\n" );
+
+  ImageView imageView = Internal::ImageView::New();
+  imageView.SetImage( image );
+  return imageView;
+}
+
+ImageView ImageView::New( const std::string& url )
+{
+  ImageView imageView = Internal::ImageView::New();
+  imageView.SetImage( url, ImageDimensions() );
+  return imageView;
+}
+
+ImageView ImageView::New( const std::string& url, ImageDimensions size )
+{
+  ImageView imageView = Internal::ImageView::New();
+  imageView.SetImage( url, size );
+  return imageView;
+}
+
+ImageView ImageView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ImageView, Internal::ImageView>( handle );
+}
+
+void ImageView::SetImage( Image image )
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: SetImage() is deprecated and will be removed from next release. Use SetImage( const std::string& ) instead.\n" );
+
+  Dali::Toolkit::GetImpl( *this ).SetImage( image );
+}
+
+void ImageView::SetImage( const std::string& url )
+{
+  Dali::Toolkit::GetImpl( *this ).SetImage( url, ImageDimensions() );
+}
+
+void ImageView::SetImage( const std::string& url, ImageDimensions size )
+{
+  Dali::Toolkit::GetImpl( *this ).SetImage( url, size );
+}
+
+Image ImageView::GetImage() const
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetImage() is deprecated and will be removed from next release.\n" );
+
+  return Dali::Toolkit::GetImpl( *this ).GetImage();
+}
+
+ImageView::ImageView( Internal::ImageView& implementation )
+ : Control( implementation )
+{
+}
+
+ImageView::ImageView( Dali::Internal::CustomActor* internal )
+ : Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ImageView>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/image-view/image-view.h b/dali-toolkit/public-api/controls/image-view/image-view.h
new file mode 100644 (file)
index 0000000..c6d0b2a
--- /dev/null
@@ -0,0 +1,308 @@
+#ifndef DALI_TOOLKIT_IMAGE_VIEW_H
+#define DALI_TOOLKIT_IMAGE_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/image-operations.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ImageView;
+}
+/**
+ * @addtogroup dali_toolkit_controls_image_view
+ * @{
+ */
+
+/**
+ * @brief ImageView is a class for displaying an image resource.
+ *
+ * An instance of ImageView can be created using a URL or an Image instance.
+ *
+ * Some resources can be loaded before the ImageView is staged ( already cached ), in these cases if the connection to
+ * ResouceReadySignal is done after the resource is set then signal will be missed.
+ *
+ * To protect against this, IsResourceReady() can be checked before connecting to ResourceReadySignal,
+ * or the signal connection can be done before setting the resource.
+ *
+ * @code
+ *    auto myImageView = ImageView::New( resourceUrl );
+ *    if ( myImageView.IsResourceReady() )
+ *    {
+ *       // do something
+ *    }
+ *    else
+ *    {
+ *      myImageView.ResourceReadySignal.Connect( .... )
+ *    }
+ * @endcode
+ *
+ * OR Connect to signal before setting resource
+ *
+ * @code
+ *    auto myImageView = ImageView::New();
+ *    myImageView.ResourceReadySignal.Connect( .... )
+ *    myImageView.SetProperty( ImageView::Property::IMAGE, resourceUrl );
+ * @endcode
+ *
+ * @SINCE_1_0.0
+ *
+ */
+class DALI_TOOLKIT_API ImageView : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,  ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,              ///< Reserve property indices @SINCE_1_0.0
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,        ///< @SINCE_1_1.18
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000  ///< Reserve animatable property indices, @SINCE_1_1.18
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the ImageView class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the ImageView class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      // Event side properties
+
+      RESERVED_PROPERTY_01 = PROPERTY_START_INDEX, ///< Reserved index for a removed property.
+
+      /**
+       * @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
+       * @pre image must be initialized.
+       */
+      PRE_MULTIPLIED_ALPHA,
+
+
+      // 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].
+       * @SINCE_1_1.18
+       */
+      PIXEL_AREA = ANIMATABLE_PROPERTY_START_INDEX,
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates an uninitialized ImageView.
+   * @SINCE_1_0.0
+   */
+  ImageView();
+
+  /**
+   * @brief Create an initialized ImageView.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to a newly allocated Dali ImageView
+   *
+   * @note ImageView will not display anything.
+   */
+  static ImageView New();
+
+  /**
+   * @DEPRECATED_1_2_8, use New( const std::string& ) instead.
+   *
+   * @brief Creates 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 instance to display
+   * @return A handle to a newly allocated ImageView
+   */
+  static ImageView New( Image image ) DALI_DEPRECATED_API;
+
+  /**
+   * @brief Creates an initialized ImageView from an URL to an image resource.
+   *
+   * If the string is empty, ImageView will not display anything.
+   *
+   * @SINCE_1_0.0
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The url of the image resource to display
+   * @return A handle to a newly allocated ImageView
+   */
+  static ImageView New( const std::string& url );
+
+  /**
+   * @brief Creates an initialized ImageView from a URL to an image resource.
+   *
+   * If the string is empty, ImageView will not display anything.
+   *
+   * @SINCE_1_1.10
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The url of the image resource to display
+   * @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.
+   *       However, do not set a size that is bigger than the actual image size, as up-scaling is not available.
+   *       The content of the area not covered by the actual image is undefined and will not be cleared.
+   */
+  static ImageView New( const std::string& url, ImageDimensions size );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~ImageView();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] imageView ImageView to copy. The copied ImageView will point at the same implementation
+   */
+  ImageView( const ImageView& imageView );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_0.0
+   * @param[in] imageView The ImageView to assign from
+   * @return The updated ImageView
+   */
+  ImageView& operator=( const ImageView& imageView );
+
+  /**
+   * @brief Downcasts a handle to ImageView handle.
+   *
+   * If handle points to a ImageView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a ImageView or an uninitialized handle
+   */
+  static ImageView DownCast( BaseHandle handle );
+
+  /**
+   * @DEPRECATED_1_2_8, use SetImage( const std::string& ) instead.
+   *
+   * @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 instance to display.
+   */
+  void SetImage( Image image ) DALI_DEPRECATED_API;
+
+  /**
+   * @brief Sets this ImageView from the given URL.
+   *
+   * If the URL is empty, ImageView will not display anything.
+   *
+   * @SINCE_1_1.4
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The URL to the image resource to display
+   */
+  void SetImage( const std::string& url );
+
+  /**
+   * @brief Sets this ImageView from the given URL.
+   *
+   * If the URL is empty, ImageView will not display anything.
+   *
+   * @SINCE_1_1.10
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @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 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
+   * @return The Image instance currently used by the ImageView
+   */
+  Image GetImage() const DALI_DEPRECATED_API;
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The ImageView implementation
+   */
+  DALI_INTERNAL ImageView( Internal::ImageView& implementation );
+
+  /**
+   * @brief Allows the creation of this ImageView from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL ImageView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VIEW_H
diff --git a/dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp b/dali-toolkit/public-api/controls/model3d-view/model3d-view.cpp
new file mode 100644 (file)
index 0000000..e1dc94c
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/model3d-view/model3d-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/model3d-view/model3d-view-impl.h>
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Model3dView::Model3dView()
+{}
+
+Model3dView::Model3dView( const Model3dView& model3dView )
+: Control( model3dView )
+{
+}
+
+Model3dView& Model3dView::operator=( const Model3dView& model3dView )
+{
+  if( &model3dView != this )
+  {
+    Control::operator=( model3dView );
+  }
+  return *this;
+}
+
+Model3dView::~Model3dView()
+{
+}
+
+Model3dView Model3dView::New()
+{
+  return Internal::Model3dView::New();
+}
+
+Model3dView Model3dView::New( const std::string& objUrl, const std::string& mtlUrl, const std::string& imagesUrl )
+{
+  Model3dView model3dView = Internal::Model3dView::New();
+  model3dView.SetProperty( Model3dView::Property::GEOMETRY_URL, Dali::Property::Value( objUrl ) );
+  model3dView.SetProperty( Model3dView::Property::MATERIAL_URL, Dali::Property::Value( mtlUrl ) );
+  model3dView.SetProperty( Model3dView::Property::IMAGES_URL, Dali::Property::Value( imagesUrl ) );
+
+  return model3dView;
+}
+
+Model3dView Model3dView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Model3dView, Internal::Model3dView>(handle);
+}
+
+Model3dView::Model3dView( Internal::Model3dView& implementation )
+ : Control( implementation )
+{
+}
+
+Model3dView::Model3dView( Dali::Internal::CustomActor* internal )
+ : Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Model3dView>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/model3d-view/model3d-view.h b/dali-toolkit/public-api/controls/model3d-view/model3d-view.h
new file mode 100755 (executable)
index 0000000..dfa6830
--- /dev/null
@@ -0,0 +1,193 @@
+#ifndef DALI_TOOLKIT_MODEL3D_VIEW_H
+#define DALI_TOOLKIT_MODEL3D_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Model3dView;
+}
+
+/**
+ * @addtogroup dali_toolkit_controls_model3d_view
+ * @{
+ */
+
+/**
+ * @brief Model3dView is a control for displaying 3d geometry.
+ *
+ * All the geometry loaded with the control is automatically centered and scaled to fit
+ * the size of all the other controls. So the max is (0.5,0.5) and the min is (-0.5,-0.5).
+ *
+ * @SINCE_1_1.4
+ */
+class DALI_TOOLKIT_API Model3dView : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_1.4
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,  ///< @SINCE_1_1.4
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,              ///< Reserve property indices @SINCE_1_1.4
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,                    ///< @SINCE_1_1.4
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000              ///< Reserve animatable property indices @SINCE_1_1.4
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the TextLabel class.
+   * @SINCE_1_1.4
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the TextLabel class.
+     * @SINCE_1_1.4
+     */
+    enum
+    {
+      GEOMETRY_URL = PROPERTY_START_INDEX,  ///< name "geometryUrl",       The path to the geometry file,    type STRING @SINCE_1_1.4
+      MATERIAL_URL,                         ///< name "materialUrl",       The path to the material file,    type STRING @SINCE_1_1.4
+      IMAGES_URL,                           ///< name "imagesUrl",         The path to the images directory, type STRING @SINCE_1_1.4
+      ILLUMINATION_TYPE,                    ///< name "illuminationType",  The type of illumination,         type INTEGER @SINCE_1_1.4
+      TEXTURE0_URL,                         ///< name "texture0Url",       The path to first texture,        type STRING @SINCE_1_1.4
+      TEXTURE1_URL,                         ///< name "texture1Url",       The path to second texture,       type STRING @SINCE_1_1.4
+      TEXTURE2_URL,                         ///< name "texture2Url",       The path to third texture,        type STRING @SINCE_1_1.4
+
+      LIGHT_POSITION = ANIMATABLE_PROPERTY_START_INDEX    ///< name "lightPosition",     The coordinates of the light,     type Vector3 @SINCE_1_1.4
+    };
+  };
+
+  /**
+   * @brief Enumeration for the type of illumination.
+   * @SINCE_1_1.4
+   */
+  enum IlluminationType
+  {
+    DIFFUSE,                 ///< diffuse @SINCE_1_1.4
+    DIFFUSE_WITH_TEXTURE,    ///< diffuse with texture @SINCE_1_1.4
+    DIFFUSE_WITH_NORMAL_MAP  ///< diffuse with normal map @SINCE_1_1.4
+  };
+
+  /**
+   * @brief Creates a new instance of a Model3dView control.
+   *
+   * @SINCE_1_1.4
+   * @return A handle to the new Model3dView control
+   */
+  static Model3dView New();
+
+  /**
+   * @brief Creates a new instance of a Model3dView control.
+   *
+   * @SINCE_1_1.4
+   * @param[in] objUrl The path to the geometry file
+   * @param[in] mtlUrl The path to the material file
+   * @param[in] imagesUrl The path to the images directory
+   * @return A handle to the new Model3dView control
+   */
+  static Model3dView New( const std::string& objUrl, const std::string& mtlUrl, const std::string& imagesUrl );
+
+
+  /**
+   * @brief Creates an uninitialized Model3dView.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_1.4
+   */
+  Model3dView();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.4
+   */
+  ~Model3dView();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_1.4
+   * @param[in] model3dView Handle to an object
+   */
+  Model3dView( const Model3dView& model3dView );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_1.4
+   * @param[in] model3dView Handle to an object
+   * @return reference to this
+   */
+  Model3dView& operator=( const Model3dView& model3dView );
+
+  /**
+   * @brief Downcasts an Object handle to Model3dView.
+   *
+   * If handle points to a Model3dView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_1.4
+   * @param[in] handle Handle to an object
+   * @return Handle to a Model3dView or an uninitialized handle
+   */
+  static Model3dView DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_1.4
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL Model3dView( Internal::Model3dView& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_1.4
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL Model3dView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_MODEL3D_VIEW_H
diff --git a/dali-toolkit/public-api/controls/progress-bar/progress-bar.cpp b/dali-toolkit/public-api/controls/progress-bar/progress-bar.cpp
new file mode 100644 (file)
index 0000000..d34a5a8
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/public-api/controls/progress-bar/progress-bar.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ProgressBar::ProgressBar()
+{
+}
+
+ProgressBar::ProgressBar( const ProgressBar& handle )
+: Control( handle )
+{
+}
+
+ProgressBar& ProgressBar::operator=( const ProgressBar& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+ProgressBar::ProgressBar(Internal::ProgressBar& implementation)
+: Control(implementation)
+{
+}
+
+ProgressBar::ProgressBar( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ProgressBar>(internal);
+}
+
+ProgressBar ProgressBar::New()
+{
+  return Internal::ProgressBar::New();
+}
+
+ProgressBar::~ProgressBar()
+{
+}
+
+ProgressBar::ValueChangedSignalType& ProgressBar::ValueChangedSignal()
+{
+  return GetImpl( *this ).ValueChangedSignal();
+}
+
+ProgressBar ProgressBar::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ProgressBar, Internal::ProgressBar>(handle);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/progress-bar/progress-bar.h b/dali-toolkit/public-api/controls/progress-bar/progress-bar.h
new file mode 100644 (file)
index 0000000..a7b87c2
--- /dev/null
@@ -0,0 +1,255 @@
+#ifndef DALI_TOOLKIT_PROGRESS_BAR_H
+#define DALI_TOOLKIT_PROGRESS_BAR_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ProgressBar;
+}
+/**
+ * @addtogroup dali_toolkit_controls_progress_bar
+ * @{
+ */
+
+/**
+ * @brief ProgressBar is a control to give the user an indication of the progress of an operation.
+ *
+ * Signals
+ * | %Signal Name      | Method                        |
+ * |-------------------|-------------------------------|
+ * | valueChanged      | @ref ValueChangedSignal()     |
+ *
+ * @SINCE_1_2.60
+ */
+
+class DALI_TOOLKIT_API ProgressBar : public Control
+{
+public:
+
+  // Properties
+
+  /**
+   * @brief The start and end property ranges for this control.
+   * @SINCE_1_2.60
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< Start Index. @SINCE_1_2.60
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices. @SINCE_1_2.60
+  };
+
+  /**
+   * @brief Enumeration of properties belonging to the ProgressBar class.
+   * @SINCE_1_2.60
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the ProgressBar class.
+     * @SINCE_1_2.60
+     */
+    enum
+    {
+      /**
+       * @brief The progress value of progress bar, progress runs form 0 to 1.
+       * @details Name "progressValue", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the default is 0.
+       * @note Value should be between 0 to 1.
+       * @note If Value is set to 0, progress bar will be set to beginning.
+       * @note If Value is set to 1, progress bar will be set to end.
+       * @note Any Value outside of the range is ignored.
+       */
+      PROGRESS_VALUE = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The secondary progress value of progress bar, secondary progress runs form 0 to 1.
+       * @details Name "secondaryProgressValue", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the default is 0.
+       * @note Value should be between 0 to 1.
+       * @note If Value is set to 0, progress bar will be set secondary progress to beginning.
+       * @note If Value is set to 1, progress bar will be set secondary progress to end.
+       * @note Any Value outside of the range is ignored.
+       */
+      SECONDARY_PROGRESS_VALUE,
+
+      /**
+       * @brief Sets the progress-bar as \e indeterminate state.
+       * @details name "indeterminate", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      INDETERMINATE,
+
+      /**
+       * @brief The track Visual value of progress bar, it's a full progress area and it's shown behind PROGRESS_VISUAL.
+       * @details Name "trackVisual", type Property::MAP or Property::STRING (url to image).
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the default track visual will be shown.
+       */
+      TRACK_VISUAL,
+
+      /**
+       * @brief The progress Visual value of progress bar, size of the progress visual is changed based on PROGRESS_VALUE.
+       * @details Name "progressVisual", type Property::MAP or Property::STRING (url to image).
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the default progress visual will be shown.
+       */
+      PROGRESS_VISUAL,
+
+      /**
+       * @brief The secondary progress visual of progress bar, size of the secondary progress visual is changed based on SECONDARY_PROGRESS_VALUE.
+       * @details Name "secondaryProgressVisual", type Property::MAP or Property::STRING (url to image).
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the secondary progress visual will not be shown.
+       */
+      SECONDARY_PROGRESS_VISUAL,
+
+      /**
+       * @brief The indeterminate visual of progress bar.
+       * @details Name "inditerminateVisual", type Property::MAP or Property::STRING (url to image).
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, the default indeterminate visual will be shown.
+       */
+      INDETERMINATE_VISUAL,
+
+      /**
+       * @brief The transition data for indeterminate visual animation.
+       * @details Name "indeterminateVisualAnimation", type Property::MAP or Property::ARRAY.
+       * @SINCE_1_2.60
+       * @note Optional. If not supplied, default animation will be played.
+       */
+      INDETERMINATE_VISUAL_ANIMATION,
+
+      /**
+       * @brief The Label visual of progress bar.
+       * @details Name "labelVisual", type Property::MAP.
+       * @SINCE_1_2.60
+       */
+      LABEL_VISUAL,
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates the ProgressBar control.
+   * @SINCE_1_2.60
+   * @return A handle to the ProgressBar control
+   */
+  static ProgressBar New();
+
+  /**
+   * @brief Creates an empty ProgressBar handle.
+   * @SINCE_1_2.60
+   */
+  ProgressBar();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   * @SINCE_1_2.60
+   * @param[in] handle Handle to an object
+   */
+  ProgressBar( const ProgressBar& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_2.60
+   * @param[in] handle Handle to an object
+   * @return A reference to this
+   */
+  ProgressBar& operator=( const ProgressBar& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_2.60
+   */
+  ~ProgressBar();
+
+  /**
+   * @brief Downcast an Object handle to ProgressBar.
+   *
+   * If handle points to a ProgressBar the
+   * downcast produces valid handle. If not the returned handle is left uninitialized.
+   * @SINCE_1_2.60
+   * @param[in] handle Handle to an object
+   * @return handle to a ProgressBar or an uninitialized handle
+   */
+  static ProgressBar DownCast( BaseHandle handle );
+
+public:  // Signals
+
+  /**
+   * @brief Value changed signal type.
+   * @SINCE_1_2.60
+   */
+  typedef Signal< void ( ProgressBar, float, float ) > ValueChangedSignalType;
+
+  /**
+   * @brief Signal emitted when the ProgressBar value changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( ProgressBar progressBar, float progressValue, float secondaryProgressValue );
+   * @endcode
+   * @SINCE_1_2.60
+   * @return The signal to connect to
+   */
+  ValueChangedSignalType& ValueChangedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @param[in]  implementation  The Control implementation
+   */
+  DALI_INTERNAL ProgressBar(Internal::ProgressBar& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @param[in]  internal  A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL ProgressBar( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_PROGRESS_BAR_H
diff --git a/dali-toolkit/public-api/controls/scroll-bar/scroll-bar.cpp b/dali-toolkit/public-api/controls/scroll-bar/scroll-bar.cpp
new file mode 100755 (executable)
index 0000000..b55f29c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ScrollBar::ScrollBar()
+{
+}
+
+ScrollBar::ScrollBar(Internal::ScrollBar& implementation)
+: Control( implementation )
+{
+}
+
+ScrollBar::ScrollBar( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::ScrollBar>(internal);
+}
+
+ScrollBar::ScrollBar( const ScrollBar& handle )
+: Control( handle )
+{
+}
+
+ScrollBar& ScrollBar::operator=( const ScrollBar& scrollBar )
+{
+  if( &scrollBar != this )
+  {
+    Control::operator=( scrollBar );
+  }
+  return *this;
+}
+
+ScrollBar ScrollBar::New(ScrollBar::Direction direction)
+{
+  return Internal::ScrollBar::New(direction);
+}
+
+ScrollBar ScrollBar::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ScrollBar, Internal::ScrollBar>(handle);
+}
+
+ScrollBar::~ScrollBar()
+{
+}
+
+void ScrollBar::SetScrollPropertySource( Handle handle, Dali::Property::Index propertyScrollPosition, Dali::Property::Index propertyMinScrollPosition, Dali::Property::Index propertyMaxScrollPosition, Dali::Property::Index propertyScrollContentSize )
+{
+  GetImpl(*this).SetScrollPropertySource(handle, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize);
+}
+
+void ScrollBar::SetScrollIndicator( Actor indicator )
+{
+  GetImpl(*this).SetScrollIndicator(indicator);
+}
+
+Actor ScrollBar::GetScrollIndicator()
+{
+  return GetImpl(*this).GetScrollIndicator();
+}
+
+void ScrollBar::SetScrollPositionIntervals( const Dali::Vector<float>& positions )
+{
+  GetImpl(*this).SetScrollPositionIntervals(positions);
+}
+
+Dali::Vector<float> ScrollBar::GetScrollPositionIntervals() const
+{
+  return GetImpl(*this).GetScrollPositionIntervals();
+}
+
+void ScrollBar::SetScrollDirection( ScrollBar::Direction direction )
+{
+  GetImpl(*this).SetScrollDirection(direction);
+}
+
+ScrollBar::Direction ScrollBar::GetScrollDirection() const
+{
+  return GetImpl(*this).GetScrollDirection();
+}
+
+void ScrollBar::SetIndicatorHeightPolicy( ScrollBar::IndicatorHeightPolicy policy )
+{
+  GetImpl(*this).SetIndicatorHeightPolicy(policy);
+}
+
+ScrollBar::IndicatorHeightPolicy ScrollBar::GetIndicatorHeightPolicy() const
+{
+  return GetImpl(*this).GetIndicatorHeightPolicy();
+}
+
+void ScrollBar::SetIndicatorFixedHeight( float height )
+{
+  GetImpl(*this).SetIndicatorFixedHeight(height);
+}
+
+float ScrollBar::GetIndicatorFixedHeight() const
+{
+  return GetImpl(*this).GetIndicatorFixedHeight();
+}
+
+void ScrollBar::SetIndicatorShowDuration( float durationSeconds )
+{
+  GetImpl(*this).SetIndicatorShowDuration(durationSeconds);
+}
+
+float ScrollBar::GetIndicatorShowDuration() const
+{
+  return GetImpl(*this).GetIndicatorShowDuration();
+}
+
+void ScrollBar::SetIndicatorHideDuration( float durationSeconds )
+{
+  GetImpl(*this).SetIndicatorHideDuration(durationSeconds);
+}
+
+float ScrollBar::GetIndicatorHideDuration() const
+{
+  return GetImpl(*this).GetIndicatorHideDuration();
+}
+
+void ScrollBar::ShowIndicator()
+{
+  GetImpl(*this).ShowIndicator();
+}
+
+void ScrollBar::HideIndicator()
+{
+  GetImpl(*this).HideIndicator();
+}
+
+ScrollBar::PanFinishedSignalType& ScrollBar::PanFinishedSignal()
+{
+  return GetImpl(*this).PanFinishedSignal();
+}
+
+ScrollBar::ScrollPositionIntervalReachedSignalType& ScrollBar::ScrollPositionIntervalReachedSignal()
+{
+  return GetImpl(*this).ScrollPositionIntervalReachedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h b/dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h
new file mode 100755 (executable)
index 0000000..d988212
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef DALI_TOOLKIT_SCROLL_BAR_H
+#define DALI_TOOLKIT_SCROLL_BAR_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+// Forward declarations
+
+class ScrollBar;
+}
+/**
+ * @addtogroup dali_toolkit_controls_scroll_bar
+ * @{
+ */
+
+/**
+ * @brief ScrollBar is a UI component that can be linked to the scrollable objects
+ * indicating the current scroll position of the scrollable object.
+ *
+ * Signals
+ * | %Signal Name                  | Method                                     |
+ * |-------------------------------|--------------------------------------------|
+ * | panFinished                   | @ref PanFinishedSignal()                   |
+ * | scrollPositionIntervalReached | @ref ScrollPositionIntervalReachedSignal() |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API ScrollBar : public Control
+{
+public:
+
+  // Properties
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the ScrollBar class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the ScrollBar class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      /**
+       * @brief The scrolling direction of the indicator.
+       * @details Name "scrollDirection", type Property::STRING.
+       *          Possible values are "Vertical" and "Horizontal".
+       * @SINCE_1_0.0
+       * @see SetScrollDirection()
+       */
+      SCROLL_DIRECTION = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The indicator height policy.
+       * @details Name "indicatorHeightPolicy", type Property::STRING.
+       *          Possible values are "Variable" and "Fixed".
+       * @SINCE_1_0.0
+       * @see SetIndicatorHeightPolicy()
+       */
+      INDICATOR_HEIGHT_POLICY,
+
+      /**
+       * @brief The fixed height of the indicator.
+       * @details Name "indicatorFixedHeight", type Property::FLOAT.
+       * @SINCE_1_0.0
+       * @see SetIndicatorFixedHeight()
+       */
+      INDICATOR_FIXED_HEIGHT,
+
+      /**
+       * @brief The duration in seconds to show the indicator.
+       * @details Name "indicatorShowDuration", type Property::FLOAT.
+       * @SINCE_1_0.0
+       * @see SetIndicatorShowDuration()
+       */
+      INDICATOR_SHOW_DURATION,
+
+      /**
+       * @brief The duration in seconds to hide the indicator.
+       * @details Name "indicatorHideDuration", type Property::FLOAT.
+       * @SINCE_1_0.0
+       * @see SetIndicatorHideDuration()
+       */
+      INDICATOR_HIDE_DURATION,
+
+      /**
+       * @brief The intervals at which point a notification is emitted.
+       * @details Name "scrollPositionIntervals", type Property::ARRAY.
+       * @SINCE_1_0.0
+       * @see SetScrollPositionIntervals()
+       */
+      SCROLL_POSITION_INTERVALS,
+
+      /**
+       * @brief The minimum height for a variable size indicator.
+       * @details Name "indicatorMinimumHeight", type Property::FLOAT.
+       * @SINCE_1_1.36
+       */
+      INDICATOR_MINIMUM_HEIGHT,
+
+      /**
+       * @brief The padding at the start of the indicator.
+       * @details Name "indicatorStartPadding", type Property::FLOAT.
+       *          For example, the padding at the top if scrollDirection is Vertical.
+       * @SINCE_1_1.36
+       */
+      INDICATOR_START_PADDING,
+
+      /**
+       * @brief The padding at the end of the indicator.
+       * @details Name "indicatorEndPadding", type Property::FLOAT.
+       *          For example, the padding at the bottom if scrollDirection is Vertical.
+       * @SINCE_1_1.36
+       */
+      INDICATOR_END_PADDING,
+
+      /**
+       * @brief The duration that transient indicators will remain fully visible.
+       * @details name "indicatorTransientDuration", type Property::FLOAT.
+       * @SINCE_1_2.60
+       */
+      INDICATOR_TRANSIENT_DURATION,
+    };
+  };
+
+  // Signals
+
+  typedef Signal< void () > PanFinishedSignalType;
+  typedef Signal< void ( float ) > ScrollPositionIntervalReachedSignalType;
+
+public:
+
+  /**
+   * @brief Direction.
+   * @SINCE_1_0.0
+   */
+  enum Direction
+  {
+    Vertical = 0,   ///< Scroll in the vertical direction @SINCE_1_0.0
+    Horizontal      ///< Scroll in the horizontal direction @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Indicator height policy.
+   * @SINCE_1_0.0
+   */
+  enum IndicatorHeightPolicy
+  {
+    Variable = 0,  ///< Variable height changed dynamically according to the length of scroll content @SINCE_1_0.0
+    Fixed          ///< Fixed height regardless of the length of scroll content @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Creates an uninitialized ScrollBar; this can be initialized with ScrollBar::New()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  ScrollBar();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] scrollBar Handle to an object
+   */
+  ScrollBar( const ScrollBar& scrollBar );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] scrollBar Handle to an object
+   * @return A reference to this
+   */
+  ScrollBar& operator=( const ScrollBar& scrollBar );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~ScrollBar();
+
+  /**
+   * @brief Creates an initialized ScrollBar.
+   * @SINCE_1_0.0
+   * @param[in] direction The direction of scroll bar (either vertically or horizontally)
+   * @return A pointer to the created ScrollBar
+   */
+  static ScrollBar New(Direction direction = Vertical);
+
+  /**
+   * @brief Downcasts a handle to ScrollBar handle.
+   *
+   * If handle points to a ScrollBar, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a ScrollBar or an uninitialized handle
+   */
+  static ScrollBar DownCast( BaseHandle handle );
+
+  /**
+   * @brief Sets the source of the scroll position properties.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle The handle of the object owing the scroll properties
+   * @param[in] propertyScrollPosition The index of the scroll position property (The scroll position, type float)
+   * @param[in] propertyMinScrollPosition The index of the minimum scroll position property (The minimum scroll position, type float)
+   * @param[in] propertyMaxScrollPosition The index of the maximum scroll position property (The maximum scroll position, type float)
+   * @param[in] propertyScrollContentSize The index of the scroll content size property (The size of the scrollable content in actor coordinates, type float)
+   * @pre The handle to the object owing the scroll properties has been initialised and the property index must be valid.
+   */
+  void SetScrollPropertySource( Handle handle, Dali::Property::Index propertyScrollPosition, Dali::Property::Index propertyMinScrollPosition, Dali::Property::Index propertyMaxScrollPosition, Dali::Property::Index propertyScrollContentSize );
+
+  /**
+   * @brief Sets the indicator of scroll bar.
+   *
+   * @SINCE_1_0.0
+   * @param[in] indicator The indicator that moves to indicate the current scroll position
+   * @pre The scroll bar actor has been initialized.
+   */
+  void SetScrollIndicator( Actor indicator );
+
+  /**
+   * @brief Gets the indicator of scroll bar.
+   *
+   * @SINCE_1_0.0
+   * @return The indicator indicates the current scroll position of the scrollable content
+   * @pre The scroll bar actor has been initialized.
+   */
+  Actor GetScrollIndicator();
+
+  /**
+   * @brief Sets the list of values to get notification when the current scroll position of the scrollable
+   * object goes above or below any of these values.
+   *
+   * @SINCE_1_0.0
+   * @param[in] positions List of values to receive notifications for when the current scroll position crosses them
+   * @pre The scroll bar actor has been initialized.
+   */
+  void SetScrollPositionIntervals( const Dali::Vector<float>& positions );
+
+  /**
+   * @brief Gets the list of values to receive notifications when the current scroll position of the scrollable
+   * object goes above or below any of these values.
+   *
+   * @SINCE_1_0.0
+   * @return The list of values to receive notifications for when the current scroll position crosses them
+   * @pre The scroll bar actor has been initialized.
+   *
+   */
+  Dali::Vector<float> GetScrollPositionIntervals() const;
+
+  /**
+   * @brief Sets the direction of scroll bar to scroll either vertically or horizontally.
+   *
+   * @SINCE_1_0.0
+   * @param[in] direction The direction of scroll bar (either vertically or horizontally)
+   * @pre The scroll bar actor has been initialized.
+   */
+  void SetScrollDirection( Direction direction );
+
+  /**
+   * @brief Gets the direction of scroll bar.
+   *
+   * @SINCE_1_0.0
+   * @return The direction of scroll bar
+   */
+  Direction GetScrollDirection() const;
+
+  /**
+   * @brief Sets the height policy of scroll indicator to have either variable or fixed height.
+   *
+   * @SINCE_1_0.0
+   * @param[in] policy The height policy of scroll indicator
+   * @pre The scroll bar actor has been initialized.
+   */
+  void SetIndicatorHeightPolicy( IndicatorHeightPolicy policy );
+
+  /**
+   * @brief Gets the height policy of scroll indicator.
+   *
+   * @SINCE_1_0.0
+   * @return The height policy of scroll indicator
+   */
+  IndicatorHeightPolicy GetIndicatorHeightPolicy() const;
+
+  /**
+   * @brief Sets the fixed height of scroll indicator.
+   *
+   * Normally the height of scroll indicator is changed dynamically according to the length of scroll content.
+   * However, when the height policy of scroll indicator is set to be fixed, the height will be kept fixed
+   * regardless of the length of scroll content.
+   *
+   * @SINCE_1_0.0
+   * @param[in] height The fixed height of the scroll indicator
+   * @pre The scroll bar actor has been initialized.
+   *
+   */
+  void SetIndicatorFixedHeight( float height );
+
+  /**
+   * @brief Gets the fix height of scroll indicator.
+   * @SINCE_1_0.0
+   * @return The fixed height of the scroll indicator
+   */
+  float GetIndicatorFixedHeight() const;
+
+  /**
+   * @brief Sets the duration in seconds for the scroll indicator to become fully visible.
+   *
+   * @SINCE_1_0.0
+   * @param[in] durationSeconds The duration for the scroll indicator to become fully visible
+   * @pre The scroll bar actor has been initialised; durationSeconds must be zero or greater; zero means the indicator will be shown instantly.
+   *
+   */
+  void SetIndicatorShowDuration( float durationSeconds );
+
+  /**
+   * @brief Gets the duration in seconds for the scroll indicator to become fully visible.
+   * @SINCE_1_0.0
+   * @return The duration for the scroll indicator to become fully visible
+   */
+  float GetIndicatorShowDuration() const;
+
+  /**
+   * @brief Sets the duration in seconds for the scroll indicator to become fully invisible.
+   *
+   * @SINCE_1_0.0
+   * @param[in] durationSeconds The duration for the scroll indicator to become fully invisible
+   * @pre The scroll bar actor has been initialised; durationSeconds must be zero or greater; zero means the indicator will be hidden instantly.
+   *
+   */
+  void SetIndicatorHideDuration( float durationSeconds );
+
+  /**
+   * @brief Gets the duration in seconds for the scroll indicator to become fully invisible.
+   * @SINCE_1_0.0
+   * @return The duration for the scroll indicator to become fully invisible
+   */
+  float GetIndicatorHideDuration() const;
+
+  /**
+   * @brief Shows the scroll indicator.
+   * @SINCE_1_0.0
+   */
+  void ShowIndicator();
+
+  /**
+   * @brief Hides the scroll indicator.
+   * @SINCE_1_0.0
+   */
+  void HideIndicator();
+
+public: // Signals
+
+  /**
+   * @brief Signal emitted when panning is finished on the scroll indicator.
+   *
+   * Signal only emitted when the source of the scroll position properties are set.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName();
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  ScrollBar::PanFinishedSignalType& PanFinishedSignal();
+
+  /**
+   * @brief Signal emitted when the current scroll position of the scrollable content
+   * goes above or below the values specified by SCROLL_POSITION_INTERVALS property.
+   *
+   * Signal only emitted when the source of the scroll position properties are set.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(float currentScrollPosition);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  ScrollBar::ScrollPositionIntervalReachedSignalType& ScrollPositionIntervalReachedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL ScrollBar( Internal::ScrollBar& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL ScrollBar( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_BAR_H
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h b/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h
new file mode 100755 (executable)
index 0000000..5660714
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_PROPERTY_H
+#define DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_PROPERTY_H
+
+/*
+ * Copyright (c) 2017 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
+{
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+/**
+ * @brief Default item layout property.
+ * @SINCE_1_2.60
+ */
+namespace DefaultItemLayoutProperty
+{
+
+/**
+ * @brief The properties of each type of item layout.
+ * @SINCE_1_2.60
+ */
+enum Property
+{
+  /**
+  * @brief The type of the Layout.
+  * @details Name "type", type Dali::Toolkit::DefaultItemLayout::Type (Property::INTEGER).
+  * @SINCE_1_2.60
+  * @note Mandatory.
+  */
+  TYPE = 0,
+
+  /**
+  * @brief The size of each item in the Layout.
+  * @details Name "itemSize", type Property::VECTOR3
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, see ItemLayout::GetDefaultItemSize().
+  */
+  ITEM_SIZE,
+
+  /**
+  * @brief The internal orientation of the Layout.
+  * @details Name "orientation", type Dali::Toolkit::ControlOrientation::Type (Property::INTEGER).
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is ControlOrientation::Up, The contents of control are in a vertical layout, from top to bottom.
+  */
+  ORIENTATION,
+
+  /**
+  * @brief The number of columns in the GridLayout.
+  * @details Name "gridColumnNumber", type Property::INTEGER.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 4.
+  */
+  GRID_COLUMN_NUMBER,
+
+  /**
+  * @brief The spacing between rows in the GridLayout.
+  * @details Name "gridRowSpacing", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 20.0f.
+  */
+  GRID_ROW_SPACING,
+
+  /**
+  * @brief The spacing between columns in the GridLayout.
+  * @details Name "gridColumnSpacing", type Property::FLOAT
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 20.0f.
+  */
+  GRID_COLUMN_SPACING,
+
+  /**
+  * @brief The margin in the top of the GridLayout.
+  * @details Name "gridTopMargin", type Property::FLOAT
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 95.0f.
+  */
+  GRID_TOP_MARGIN,
+
+  /**
+  * @brief The margin in the bottom of the GridLayout.
+  * @details Name "gridBottomMargin", type Property::FLOAT
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 20.0f.
+  */
+  GRID_BOTTOM_MARGIN,
+
+  /**
+  * @brief The margin in the left and right of the GridLayout.
+  * @details Name "gridSideMargin", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 20.0f.
+  */
+  GRID_SIDE_MARGIN,
+
+  /**
+  * @brief The factor used to customise the scroll speed while dragging and swiping the GridLayout.
+  * @details Name "gridScrollSpeedFactor", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 0.03f.
+  */
+  GRID_SCROLL_SPEED_FACTOR,
+
+  /**
+  * @brief The maximum swipe speed in pixels per second of GridLayout.
+  * @details Name "gridMaximumSwipSpeed", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 100.0f.
+  */
+  GRID_MAXIMUM_SWIPE_SPEED,
+
+  /**
+  * @brief The duration of the flick animation in seconds of GridLayout.
+  * @details Name "gridItemFlickAnimationDuration", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note This is the time taken to animate each item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered by a swipe gesture.
+  * @note Must be greater than zero;If not supplied, the default is 0.015f.
+  */
+  GRID_ITEM_FLICK_ANIMATION_DURATION,
+
+  /**
+  * @brief The number of columns in the DepthLayout.
+  * @details Name "depthColumnNumber", type Property::INTEGER.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 3.
+  */
+  DEPTH_COLUMN_NUMBER,
+
+  /**
+  * @brief The number of rows in the DepthLayout.
+  * @details Name "depthRowNumber", type Property::INTEGER.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 26.
+  */
+  DEPTH_ROW_NUMBER,
+
+  /**
+  * @brief The spacing between rows in the DepthLayout.
+  * @details Name "depthRowSpacing", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 55.0f.
+  */
+  DEPTH_ROW_SPACING,
+
+  /**
+  * @brief The factor used to customise the scroll speed while dragging and swiping the  DepthLayout.
+  * @details Name "depthScrollSpeedFactor", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 0.02f.
+  */
+  DEPTH_SCROLL_SPEED_FACTOR,
+
+  /**
+  * @brief The maximumSwipSpeed of the DepthLayout.
+  * @details Name "depthMaximumSwipSpeed", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 50.0f.
+  */
+  DEPTH_MAXIMUM_SWIPE_SPEED,
+
+  /**
+  * @brief The duration of the flick animation in seconds of DepthLayout.
+  * @details Name "depthItemFlickAnimationDuration", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note This is the time taken to animate each item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered by a swipe gesture.
+  * @note Must be greater than zero; If not supplied, the default is 0.03f.
+  */
+  DEPTH_ITEM_FLICK_ANIMATION_DURATION,
+
+  /**
+  * @brief The tilt angle of DepthLayout.
+  * @details Name "depthTiltAngle",Property::FLOAT
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is (Math::PI)*0.15f.
+  * @note This is clamped between -45 & 45 degrees.
+  */
+  DEPTH_TILT_ANGLE,
+
+  /**
+  * @brief The tilt angle of the individual items in the DepthLayout.
+  * @details Name "depthItemTiltAngle", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is -(Math::PI)*0.025f.
+  */
+  DEPTH_ITEM_TILT_ANGLE,
+
+  /**
+  * @brief The spacing angle between items in the SpiralLayout.
+  * @details Name "spiralItemSpacing", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 9.5f.
+  */
+  SPIRAL_ITEM_SPACING,
+
+  /**
+  * @brief The factor used to customise the scroll speed while dragging and swiping the SpiralLayout.
+  * @details Name "spiralScrollSpeedFactor", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 0.01f.
+  */
+  SPIRAL_SCROLL_SPEED_FACTOR,
+
+  /**
+  * @brief The maximum swipe speed in pixels per second of the SpiralLayout.
+  * @details Name "spiralMaximumSwipSpeed", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 30.0f.
+  */
+  SPIRAL_MAXIMUM_SWIPE_SPEED,
+
+  /**
+  * @brief The duration of the flick animation in seconds of the SpiralLayout.
+  * @details Name "spiralItemFlickAnimationDuration", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note This is the time taken to animate each item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered by a swipe gesture.
+  * @note Must be greater than zero; If not supplied, the default is 0.1f.
+  */
+  SPIRAL_ITEM_FLICK_ANIMATION_DURATION,
+
+  /**
+  * @brief The vertical distance for one revolution of the SpiralLayout.
+  * @details Name "spiralRevolutionDistance", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note If not supplied, the default is 190.0f.
+  */
+  SPIRAL_REVOLUTION_DISTANCE,
+
+  /**
+  * @brief The alignment of the top-item, when at the beginning of the SpiralLayout.
+  * @details Name "spiralTopItemAlignment", type Property::FLOAT.
+  * @SINCE_1_2.60
+  * @note Optional.
+  * @note When at the beginning of the spiral (with a first-item layout-position of zero).A value of 0 indicates that the top-item is centered in the middle of the layout.
+  * A value of -0.5 or 0.5 indicates that the top-item is centred at the top or bottom of the layout respectively.
+  * @note If not supplied, the default is (-0.125f).
+  */
+  SPIRAL_TOP_ITEM_ALIGNMENT,
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+}
+
+#endif // DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_PROPERTY_H
+
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.cpp b/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.cpp
new file mode 100644 (file)
index 0000000..954e958
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ */
+
+// HEADER
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace DefaultItemLayout
+{
+
+ItemLayoutPtr New( Type type )
+{
+  ItemLayoutPtr itemLayout;
+
+  switch ( type )
+  {
+    case DEPTH:
+    {
+      itemLayout = Internal::DepthLayout::New();
+      break;
+    }
+
+    case GRID:
+    {
+      itemLayout = Internal::GridLayout::New();
+      break;
+    }
+
+    case LIST:
+    {
+      Internal::GridLayoutPtr layout = Internal::GridLayout::New();
+      layout->SetNumberOfColumns( 1 );
+      itemLayout = layout;
+      break;
+    }
+
+    case SPIRAL:
+    {
+      itemLayout = Internal::SpiralLayout::New();
+      break;
+    }
+  }
+
+  return itemLayout;
+}
+
+} // namespace DefaultItemLayout
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h b/dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h
new file mode 100644 (file)
index 0000000..d3f1514
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_H
+#define DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+/**
+ * @brief Enumeration for default item layout mode.
+ * @SINCE_1_0.0
+ */
+namespace DefaultItemLayout
+{
+
+/**
+ * @brief Enumeration for the type of DefaultItemLayout
+ * @SINCE_1_0.0
+ */
+enum Type
+{
+  DEPTH,     ///< Items arranged in a grid, scrolling along the Z-Axis. @SINCE_1_0.0
+  GRID,      ///< Items arranged in a grid, scrolling along the Y-Axis. @SINCE_1_0.0
+  LIST,      ///< One item per line, scrolling along the Y-Axis. @SINCE_1_0.0
+  SPIRAL     ///< Items arranged in a spiral, centered around the Y-Axis. @SINCE_1_0.0
+};
+
+/**
+ * @brief Creates a built-in default item-layout.
+ *
+ * @SINCE_1_0.0
+ * @param[in] type The type of layout required
+ * @return An ItemLayoutPtr to the newly created layout
+ */
+DALI_TOOLKIT_API ItemLayoutPtr New( Type type );
+
+} // namespace DefaultItemLayout
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_DEFAULT_ITEM_LAYOUT_H
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h b/dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h
new file mode 100644 (file)
index 0000000..49ed6d3
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef DALI_TOOLKIT_ITEM_FACTORY_H
+#define DALI_TOOLKIT_ITEM_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/actors/actor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+/**
+ * @brief ItemFactory is for providing actors to ItemView.
+ *
+ * Each actor is identified by a unique ID, and has a linear order from 0 to GetNumberOfItems()-1.
+ * @SINCE_1_0.0
+ */
+class ItemFactory
+{
+public:
+
+  class Extension; ///< Forward declare future extension interface
+
+  /**
+   * @brief Virtual destructor.
+   * @SINCE_1_0.0
+   */
+  DALI_TOOLKIT_API virtual ~ItemFactory() {};
+
+  /**
+   * @brief Queries the number of items available from the factory.
+   *
+   * The maximum available item has an ID of GetNumberOfItems() - 1.
+   * @SINCE_1_0.0
+   * @return The number of items
+   */
+  virtual unsigned int GetNumberOfItems() = 0;
+
+  /**
+   * @brief Creates an Actor to represent a visible item.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of the newly visible item
+   * @return An actor, or an uninitialized pointer if the ID is out of range
+   */
+  virtual Actor NewItem(unsigned int itemId) = 0;
+
+  /**
+   * @brief Notifies the factory the actor representing the item is removed from ItemView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of the released item
+   * @param[in] actor The actor that represents the released item
+   */
+  virtual void ItemReleased(unsigned int itemId, Actor actor) {};
+
+  /**
+   * @brief Retrieves the extension for this control.
+   *
+   * @SINCE_1_0.0
+   * @return The extension if available, NULL otherwise
+   */
+  virtual Extension* GetExtension()
+  {
+    return NULL;
+  }
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ITEM_FACTORY_H
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-layout.cpp b/dali-toolkit/public-api/controls/scrollable/item-view/item-layout.cpp
new file mode 100755 (executable)
index 0000000..04297dd
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/animation/constraint.h>
+#include <dali/public-api/animation/time-period.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+struct ItemLayout::Impl
+{
+  Vector3 mItemSize;                              ///< The size of an item in the layout
+  ControlOrientation::Type mOrientation;          ///< the orientation of the layout.
+  Property::Map mProperties;
+};
+
+ItemLayout::ItemLayout()
+: mImpl( new Impl )
+{
+  mImpl->mOrientation = ControlOrientation::Up;
+}
+
+ItemLayout::~ItemLayout()
+{
+  delete mImpl;
+}
+
+void ItemLayout::SetOrientation(ControlOrientation::Type orientation)
+{
+  mImpl->mOrientation = orientation;
+}
+
+ControlOrientation::Type ItemLayout::GetOrientation() const
+{
+  return mImpl->mOrientation;
+}
+
+void ItemLayout::GetItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
+{
+  // If item-size has not been set then get the default size
+  if ( mImpl->mItemSize == Vector3::ZERO )
+  {
+    GetDefaultItemSize( itemId, layoutSize, itemSize );
+  }
+  else
+  {
+    itemSize = mImpl->mItemSize;
+  }
+}
+
+void ItemLayout::SetItemSize( const Vector3& itemSize )
+{
+  mImpl->mItemSize = itemSize;
+}
+
+float ItemLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
+{
+  Vector3 itemPosition = GetItemPosition( itemID, currentLayoutPosition, layoutSize );
+  Vector3 itemSize;
+  GetItemSize(itemID, layoutSize, itemSize);
+  Vector3 onScreenArea = (layoutSize - itemSize) * 0.5f;
+  if (itemPosition.x < -onScreenArea.x
+      || itemPosition.x > onScreenArea.x
+      || itemPosition.y < -onScreenArea.y
+      || itemPosition.y > onScreenArea.y)
+  {
+    // item not within viewable area
+    // safest thing to do here since we have no idea how the implementation will work is to return the scroll to position
+    return GetItemScrollToPosition(itemID);
+  }
+  return currentLayoutPosition;
+}
+
+int ItemLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
+{
+  switch( direction )
+  {
+    case Control::KeyboardFocus::LEFT:
+    case Control::KeyboardFocus::UP:
+    {
+      itemID--;
+      if( itemID < 0 )
+      {
+        itemID = loopEnabled ? maxItems - 1 : 0;
+      }
+      break;
+    }
+    case Control::KeyboardFocus::RIGHT:
+    case Control::KeyboardFocus::DOWN:
+    {
+      itemID++;
+      if( itemID >= maxItems )
+      {
+        itemID = loopEnabled ? 0 : maxItems - 1;
+      }
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+  return itemID;
+}
+
+float ItemLayout::GetFlickSpeedFactor() const
+{
+  // By default, the speed factor while dragging and swiping is the same.
+  return GetScrollSpeedFactor();
+}
+
+void ItemLayout::SetLayoutProperties(const Property::Map& properties)
+{
+  for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
+  {
+    KeyValuePair propertyPair( properties.GetKeyValue( idx ) );
+
+    if(propertyPair.first == DefaultItemLayoutProperty::ITEM_SIZE)
+    {
+      SetItemSize(propertyPair.second.Get<Vector3>());
+    }
+    else if(propertyPair.first == DefaultItemLayoutProperty::ORIENTATION)
+    {
+      //Up, Left, Down, Right
+      int orientationType = propertyPair.second.Get<int>();
+      if(orientationType <= ControlOrientation::Right && orientationType >= ControlOrientation::Up)
+      {
+        SetOrientation(ControlOrientation::Type(orientationType));
+      }
+    }
+  }
+  mImpl->mProperties = properties;
+}
+
+Property::Map ItemLayout::GetLayoutProperties()
+{
+  return mImpl->mProperties;
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h b/dali-toolkit/public-api/controls/scrollable/item-view/item-layout.h
new file mode 100755 (executable)
index 0000000..7fa1703
--- /dev/null
@@ -0,0 +1,430 @@
+#ifndef DALI_TOOLKIT_ITEM_LAYOUT_H
+#define DALI_TOOLKIT_ITEM_LAYOUT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/alpha-function.h>
+#include <dali/public-api/object/property-key.h>
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/enums.h>
+#include <dali-toolkit/public-api/controls/control.h>
+
+#undef min
+#undef max
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+class ItemLayout;
+
+typedef IntrusivePtr<ItemLayout> ItemLayoutPtr; ///< Pointer to a Dali::Toolkit::ItemLayout object @SINCE_1_0.0
+
+/**
+ * @brief A support class for managing ranges of items.
+ * @SINCE_1_0.0
+ */
+struct ItemRange
+{
+  /**
+   * @brief Creates a range of item identifiers.
+   *
+   * @SINCE_1_0.0
+   * @param[in] beginItem The first item within the range
+   * @param[in] endItem The past-the-end item
+   */
+  ItemRange(unsigned int beginItem, unsigned int endItem)
+  : begin(beginItem),
+    end(endItem)
+  {
+  }
+
+  /**
+   * @brief Copy Constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] copy ItemRange we should copy from
+   */
+  ItemRange(const ItemRange& copy)
+  : begin(copy.begin),
+    end(copy.end)
+  {
+  }
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_0.0
+   * @param[in] range The Range to assign from
+   * @return The updated range
+   */
+  ItemRange& operator=(const ItemRange& range)
+  {
+    if( this != &range )
+    {
+      begin = range.begin;
+      end = range.end;
+    }
+    return *this;
+  }
+
+  /**
+   * @brief Tests whether an item is within the range.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The item identifier
+   * @return true if the item is within the range
+   */
+  bool Within(unsigned int itemId)
+  {
+    return itemId >= begin &&
+           itemId < end;
+  }
+
+  /**
+   * @brief Creates the intersection of two ranges.
+   *
+   * @SINCE_1_0.0
+   * @param[in] second The second range
+   * @return The intersection
+   */
+  ItemRange Intersection(const ItemRange& second)
+  {
+    ItemRange intersection(0u, 0u);
+
+    // If the ranges intersect
+    if ( (begin < second.end && end > second.begin) ||
+         (second.begin < end && second.end > begin) )
+    {
+      intersection.begin = std::max(begin, second.begin);
+      intersection.end   = std::min(end, second.end);
+    }
+
+    return intersection;
+  }
+
+  unsigned int begin; ///< The start of the range
+  unsigned int end;   ///< The end of the range
+};
+
+/**
+ * @brief An ItemLayout describes the constraints which are imposed on items in the layout.
+ *
+ *   - Potentially visible items are represented by Actors, created for ItemView by the ItemFactory.
+ *   - Constraints are applied after ItemView activates a layout.
+ *
+ * An ItemLayout also describes the direction of input gestures, used to scroll through the layout.
+ * Whilst scrolling, the layout provides a range of items that are within a layout-area (3D bounding volume).
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API ItemLayout : public RefObject
+{
+public:
+
+  class Extension; ///< Forward declare future extension interface
+
+  /**
+   * @brief Virtual destructor.
+   * @SINCE_1_0.0
+   */
+  virtual ~ItemLayout();
+
+  /**
+   * @brief Set the orientation of the layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] orientation The orientation of the layout.
+   */
+  void SetOrientation(ControlOrientation::Type orientation);
+
+  /**
+   * @brief Query the orientation of the layout.
+   *
+   * @SINCE_1_0.0
+   * @return the orientation of the layout.
+   */
+  ControlOrientation::Type GetOrientation() const;
+
+  /**
+   * @brief Apply the layout Properties.
+   * @SINCE_1_2.20
+   * @param[in] properties The properties the layout.
+   */
+  void SetLayoutProperties(const Property::Map& properties);
+
+  /**
+   * @brief Get the layout Properties.
+   * @SINCE_1_2.20
+   * @return the property of the layout.
+   */
+  Property::Map GetLayoutProperties();
+
+  /**
+   * @brief Retrieve the target size of an item in the layout.
+   *
+   * This will return the default size for the layout unless overridden by calling SetItemSize().
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of an item in the layout.
+   * @param[in] layoutSize The layout size
+   * @param[out] itemSize The target size of an item.
+   * @note layout-position is not provided as a parameter, since applying size constraints is not recommended.
+   * Animating to target-sizes is preferable, since this allows controls to perform layouting without constraints.
+   */
+  void GetItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const;
+
+  /**
+   * @brief Overrides the default size for the layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemSize The size of each item.
+   */
+  void SetItemSize( const Vector3& itemSize );
+
+  /**
+   * @brief Query the minimum valid layout position; this is a negative value.
+   *
+   * When scrolling, the first item will move within the range 0 to GetMinimumLayoutPosition().
+   * @SINCE_1_0.0
+   * @param[in] numberOfItems The current number of items in the layout.
+   * @param[in] layoutSize The size of the layout area.
+   * @return The minimum layout position.
+   */
+  virtual float GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const = 0;
+
+  /**
+   * @brief Query the closest anchor position for the given layout position.
+   *
+   * This anchor position is the position where all the items in the layout are aligned to
+   * their rounded layout positions in integer.
+   * @SINCE_1_0.0
+   * @param[in] layoutPosition The layout position.
+   * @return The closest anchor position for the given layout position.
+   */
+  virtual float GetClosestAnchorPosition(float layoutPosition) const = 0;
+
+  /**
+   * @brief Query the layout position for the first item in the layout to move to when the layout
+   * needs to scroll to a particular item.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of an item in the layout.
+   * @return The layout position for the first item in the layout to move to.
+   */
+  virtual float GetItemScrollToPosition(unsigned int itemId) const = 0;
+
+  /**
+   * @brief Query the items within a given layout-area.
+   *
+   * @SINCE_1_0.0
+   * @param[in] firstItemPosition The layout-position of the first item in the layout.
+   * @param[in] layoutSize The size of the layout area.
+   * @return The ID of the first & last visible item.
+   */
+  virtual ItemRange GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const = 0;
+
+  /**
+   * @brief Get the closest layout position to bring an item onto the screen.
+   *
+   * If the item is already fully on the screen this function will
+   * return the current layout position.
+   *
+   * This function is used by systems such as KeyboardFocusManager to
+   * bring the next focusable item into view and all layout
+   * implementations should provide their own version of this function
+   * to ensure proper functionality of internal toolkit systems.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemID id of the item to bring within the viewable screen area
+   * @param[in] currentLayoutPosition the current layout position of the item view instance
+   * @param[in] layoutSize the current size of the item view instance
+   * @return The layout position
+   */
+  virtual float GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize);
+
+  /**
+   * @brief Query the number of items that should be reserved, for scrolling purposes.
+   *
+   * @SINCE_1_0.0
+   * @param[in] layoutSize The size of the layout area.
+   * @return The number of extra items. ItemView will populate itself with actors within the layout-area
+   * (see GetItemsWithinArea), plus this number of additional items on either-side.
+   */
+  virtual unsigned int GetReserveItemCount(Vector3 layoutSize) const = 0;
+
+  /**
+   * @brief Retrieve the default size of an item in the layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of an item in the layout.
+   * @param[in] layoutSize The layout size
+   * @param[out] itemSize The target size of an item.
+   * @note layout-position is not provided as a parameter, since applying size constraints is not recommended.
+   * Animating to target-sizes is preferable, since this allows controls to perform layouting without constraints.
+   */
+  virtual void GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const = 0;
+
+  /**
+   * @brief Query the scroll direction of the layout.
+   *
+   * When an input gesture follows this direction, the layout-position of items will be increased.
+   * If the input gesture points in the opposite direction, then the layout-positions will decrease.
+   * @SINCE_1_0.0
+   * @return The scroll direction in degrees.
+   */
+  virtual Degree GetScrollDirection() const = 0;
+
+  /**
+   * @brief Query the scroll speed factor of the layout while dragging.
+   *
+   * This factor is used by the layout to customise its scroll speed while dragging.
+   * The factor will be multiplied with the scroll distance of how many pixels in actor coordinate,
+   * and the layout position of the actors in ItemView will be moved by this result.
+   * For example, when the speed factor is 0.01, if the scroll distance is 100 pixels, the layout
+   * position of actors will be moved by 1.
+   * Therefore, the bigger the factor is, the faster the scroll speed will be.
+   *
+   * @SINCE_1_0.0
+   * @return The scroll speed factor of the layout.
+   */
+  virtual float GetScrollSpeedFactor() const = 0;
+
+  /**
+   * @brief Query the maximum swipe speed in pixels per second.
+   *
+   * Swipe gestures will be clamped when exceeding this speed limit.
+   * @SINCE_1_0.0
+   * @return speed The maximum swipe speed.
+   */
+  virtual float GetMaximumSwipeSpeed() const = 0;
+
+  /**
+   * @brief Get the duration of the flick animation in second.
+   *
+   * This is the time taken to animate each
+   * item to its next layout position (e.g. from 1.0 to 2.0) when a flick animation is triggered
+   * by a swipe gesture.
+   * @SINCE_1_0.0
+   * @return The duration of the flick animation.
+   */
+  virtual float GetItemFlickAnimationDuration() const = 0;
+
+  /**
+   * @brief Gets the id of the next item for KeyboardFocusManager to focus on depending on the inputted item ID.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemID The current focused item
+   * @param[in] maxItems The maximum number of items in the list
+   * @param[in] direction The directional key pressed on the keyboard
+   * @param[in] loopEnabled Whether the KeyboardFocusManager is set to wrap around between first and last item
+   * @return The next item ID.
+   */
+  virtual int GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled);
+
+  /**
+   * @brief Query the flick speed factor of the layout while swipping.
+   *
+   * This factor is used by the layout to customise its scroll speed while swiping.
+   * The factor will be multiplied with the scroll distance of how many pixels in actor coordinate,
+   * and the layout position of the actors in ItemView will be moved by this result.
+   * For example, when the speed factor is 0.01, if the scroll distance is 100 pixels, the layout
+   * position of actors will be moved by 1.
+   * Therefore, the bigger the factor is, the faster the flick speed will be.
+   *
+   * @SINCE_1_0.0
+   * @return The scroll speed factor of the layout.
+   */
+  virtual float GetFlickSpeedFactor() const;
+
+  /**
+   * @brief Applies constraints defined by the layout to an actor.
+   *
+   * @param[in] actor The actor to constrain.
+   * @param[in] itemId The ID of the item represented by the actor.
+   * @param[in] layoutSize The current size of the item view instance.
+   * @param[in] itemViewActor The item view instance which requests the application of constraints.
+   */
+  virtual void ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor ) = 0;
+
+  /**
+   * @brief Gets the position of a given item
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemID The id of the item we want to get its position
+   * @param[in] currentLayoutPosition The current layout position of the item view instance
+   * @param[in] layoutSize The current size of the item view instance
+   * @return The item position (x,y,z)
+   */
+  virtual Vector3 GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const = 0;
+
+  /**
+   * @brief Retrieve the extension for this layout.
+   *
+   * @SINCE_1_0.0
+   * @return The extension if available, NULL otherwise
+   */
+  virtual Extension* GetExtension()
+  {
+    return NULL;
+  }
+
+protected:
+
+  /**
+   * @brief Create a new ItemLayout; Only derived versions are instantiatable.
+   * @SINCE_1_0.0
+   */
+  ItemLayout();
+
+private:
+
+  /**
+   * @brief Don't allow copy constructor
+   * @SINCE_1_0.0
+   */
+  ItemLayout( const ItemLayout& handle );
+
+  /**
+   * @brief Don't allow copy operator
+   * @SINCE_1_0.0
+   */
+  ItemLayout& operator=( const ItemLayout& handle );
+
+protected:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ITEM_LAYOUT_H
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-view-declarations.h b/dali-toolkit/public-api/controls/scrollable/item-view/item-view-declarations.h
new file mode 100644 (file)
index 0000000..ca09059
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef DALI_TOOLKIT_ITEM_VIEW_DECLARATIONS_H
+#define DALI_TOOLKIT_ITEM_VIEW_DECLARATIONS_H
+
+/*
+ * Copyright (c) 2019 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 <utility> // std::pair
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+typedef unsigned int ItemId; ///< Unique identity for each item in the view. @SINCE_1_0.0
+
+typedef std::vector<ItemId> ItemIdContainer;  ///< Item id container type @SINCE_1_0.0
+typedef ItemIdContainer::iterator ItemIdIter; ///< Item id iterator type @SINCE_1_0.0
+typedef ItemIdContainer::const_iterator ConstItemIdIter;  ///< Item id const iterator type @SINCE_1_0.0
+
+typedef std::pair<ItemId, Actor> Item;  ///< Item type @SINCE_1_0.0
+
+typedef std::vector<Item> ItemContainer;  ///< Item container type @SINCE_1_0.0
+typedef ItemContainer::iterator ItemIter; ///< Item iterator type @SINCE_1_0.0
+typedef ItemContainer::const_iterator ConstItemIter;  ///< Item const iterator type @SINCE_1_0.0
+
+class ItemView;
+class ItemLayout;
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ITEM_VIEW_DECLARATIONS_H
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-view.cpp b/dali-toolkit/public-api/controls/scrollable/item-view/item-view.cpp
new file mode 100644 (file)
index 0000000..12a6baf
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ItemView::ItemView()
+{
+}
+
+ItemView::ItemView(Internal::ItemView& implementation)
+: Scrollable(implementation)
+{
+}
+
+ItemView::ItemView( Dali::Internal::CustomActor* internal )
+: Scrollable(internal)
+{
+  VerifyCustomActorPointer<Internal::ItemView>(internal);
+}
+
+ItemView::ItemView( const ItemView& itemView )
+: Scrollable(itemView)
+{
+}
+
+ItemView& ItemView::operator=( const ItemView& itemView )
+{
+  if( &itemView != this )
+  {
+    Control::operator=( itemView );
+  }
+  return *this;
+}
+
+ItemView ItemView::New(ItemFactory& factory)
+{
+  return Internal::ItemView::New(factory);
+}
+
+ItemView ItemView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ItemView, Internal::ItemView>(handle);
+}
+
+ItemView::~ItemView()
+{
+}
+
+unsigned int ItemView::GetLayoutCount() const
+{
+  return GetImpl(*this).GetLayoutCount();
+}
+
+void ItemView::AddLayout(ItemLayout& layout)
+{
+  GetImpl(*this).AddLayout(layout);
+}
+
+void ItemView::RemoveLayout(unsigned int layoutIndex)
+{
+  GetImpl(*this).RemoveLayout(layoutIndex);
+}
+
+ItemLayoutPtr ItemView::GetLayout(unsigned int layoutIndex) const
+{
+  return GetImpl(*this).GetLayout(layoutIndex);
+}
+
+ItemLayoutPtr ItemView::GetActiveLayout() const
+{
+  return GetImpl(*this).GetActiveLayout();
+}
+
+float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
+{
+  return GetImpl(*this).GetCurrentLayoutPosition(itemId);
+}
+
+void ItemView::ActivateLayout(unsigned int layoutIndex, Vector3 targetSize, float durationSeconds)
+{
+  GetImpl(*this).ActivateLayout(layoutIndex, targetSize, durationSeconds);
+}
+
+void ItemView::DeactivateCurrentLayout()
+{
+  GetImpl(*this).DeactivateCurrentLayout();
+}
+
+void ItemView::SetMinimumSwipeSpeed(float speed)
+{
+  GetImpl(*this).SetMinimumSwipeSpeed(speed);
+}
+
+float ItemView::GetMinimumSwipeSpeed() const
+{
+  return GetImpl(*this).GetMinimumSwipeSpeed();
+}
+
+void ItemView::SetMinimumSwipeDistance(float distance)
+{
+  GetImpl(*this).SetMinimumSwipeDistance(distance);
+}
+
+float ItemView::GetMinimumSwipeDistance() const
+{
+  return GetImpl(*this).GetMinimumSwipeDistance();
+}
+
+void ItemView::SetWheelScrollDistanceStep(float step)
+{
+  GetImpl(*this).SetWheelScrollDistanceStep(step);
+}
+
+float ItemView::GetWheelScrollDistanceStep() const
+{
+  return GetImpl(*this).GetWheelScrollDistanceStep();
+}
+
+void ItemView::SetAnchoring(bool enabled)
+{
+  GetImpl(*this).SetAnchoring(enabled);
+}
+
+bool ItemView::GetAnchoring() const
+{
+  return GetImpl(*this).GetAnchoring();
+}
+
+void ItemView::SetAnchoringDuration(float durationSeconds)
+{
+  GetImpl(*this).SetAnchoringDuration(durationSeconds);
+}
+
+float ItemView::GetAnchoringDuration() const
+{
+  return GetImpl(*this).GetAnchoringDuration();
+}
+
+void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
+{
+  GetImpl(*this).ScrollToItem(itemId, durationSeconds);
+}
+
+void ItemView::SetRefreshInterval(float intervalLayoutPositions)
+{
+  GetImpl(*this).SetRefreshInterval(intervalLayoutPositions);
+}
+
+float ItemView::GetRefreshInterval() const
+{
+  return GetImpl(*this).GetRefreshInterval();
+}
+
+void ItemView::Refresh()
+{
+  return GetImpl(*this).Refresh();
+}
+
+Actor ItemView::GetItem(unsigned int itemId) const
+{
+  return GetImpl(*this).GetItem(itemId);
+}
+
+unsigned int ItemView::GetItemId(Actor actor) const
+{
+  return GetImpl(*this).GetItemId(actor);
+}
+
+void ItemView::InsertItem(Item newItem, float durationSeconds)
+{
+  GetImpl(*this).InsertItem( newItem, durationSeconds );
+}
+
+void ItemView::InsertItems(const ItemContainer& newItems, float durationSeconds)
+{
+  GetImpl(*this).InsertItems( newItems, durationSeconds );
+}
+
+void ItemView::RemoveItem(unsigned int itemId, float durationSeconds)
+{
+  GetImpl(*this).RemoveItem( itemId, durationSeconds );
+}
+
+void ItemView::RemoveItems(const ItemIdContainer& itemIds, float durationSeconds)
+{
+  GetImpl(*this).RemoveItems( itemIds, durationSeconds );
+}
+
+void ItemView::ReplaceItem(Item replacementItem, float durationSeconds)
+{
+  GetImpl(*this).ReplaceItem( replacementItem, durationSeconds );
+}
+
+void ItemView::ReplaceItems(const ItemContainer& replacementItems, float durationSeconds)
+{
+  GetImpl(*this).ReplaceItems( replacementItems, durationSeconds );
+}
+
+void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
+{
+  GetImpl(*this).SetItemsParentOrigin( parentOrigin );
+}
+
+Vector3 ItemView::GetItemsParentOrigin() const
+{
+  return GetImpl(*this).GetItemsParentOrigin();
+}
+
+void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
+{
+  GetImpl(*this).SetItemsAnchorPoint(anchorPoint);
+}
+
+Vector3 ItemView::GetItemsAnchorPoint() const
+{
+  return GetImpl(*this).GetItemsAnchorPoint();
+}
+
+void ItemView::GetItemsRange(ItemRange& range)
+{
+  GetImpl(*this).GetItemsRange(range);
+}
+
+ItemView::LayoutActivatedSignalType& ItemView::LayoutActivatedSignal()
+{
+  return GetImpl(*this).LayoutActivatedSignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h b/dali-toolkit/public-api/controls/scrollable/item-view/item-view.h
new file mode 100755 (executable)
index 0000000..692d129
--- /dev/null
@@ -0,0 +1,638 @@
+#ifndef DALI_TOOLKIT_ITEM_VIEW_H
+#define DALI_TOOLKIT_ITEM_VIEW_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/item-view-declarations.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ItemView;
+}
+/**
+ * @addtogroup dali_toolkit_controls_item_view
+ * @{
+ */
+
+class ItemFactory;
+class ItemLayout;
+struct ItemRange;
+
+typedef IntrusivePtr<ItemLayout> ItemLayoutPtr;
+
+/**
+ * @brief ItemView is a scrollable layout container.
+ *
+ * Multiple ItemLayouts may be provided to determine the logical position of each item layout.
+ * Actors are provided from an external ItemFactory to display the currently visible items.
+ *
+ * Signals
+ * | %Signal Name                    | Method                                     |
+ * |---------------------------------|--------------------------------------------|
+ * | layoutActivated                 | @ref LayoutActivatedSignal()               |
+ * @SINCE_1_0.0
+ *
+ * Actions
+ * | %Action Name  | Attributes              | Description                                     |
+ * |---------------|-------------------------|-------------------------------------------------|
+ * | stopScrolling | Doesn't have attributes | Stops the scroll animation. See @ref DoAction() |
+ * @SINCE_1_1.33
+ */
+
+class DALI_TOOLKIT_API ItemView : public Scrollable
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_1.18
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Toolkit::Scrollable::PROPERTY_END_INDEX + 1,                        ///< @SINCE_1_1.18
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,                                        ///< Reserve property indices, @SINCE_1_1.18
+
+    ANIMATABLE_PROPERTY_START_INDEX = Toolkit::Scrollable::ANIMATABLE_PROPERTY_END_INDEX + 1,
+    ANIMATABLE_PROPERTY_END_INDEX   = ANIMATABLE_PROPERTY_START_INDEX + 1000                   ///< Reserve animatable property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the ScrollView class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the ScrollView class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      ///////////////////////////////////////////////////////////////////////////////
+      // Event side (non-animatable) properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @brief The minimum swipe speed in pixels per second.
+       * @details Name "minimumSwipeSpeed", type Property::FLOAT.
+       * @SINCE_1_1.18
+       * @see SetMinimumSwipeSpeed()
+       */
+      MINIMUM_SWIPE_SPEED = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The minimum swipe distance in actor coordinates.
+       * @details Name "minimumSwipeDistance", type Property::FLOAT.
+       * @SINCE_1_1.18
+       * @see SetMinimumSwipeDistance()
+       */
+      MINIMUM_SWIPE_DISTANCE,
+
+      /**
+       * @brief The step of scroll distance in actor coordinates for each wheel event received.
+       * @details Name "wheelScrollDistanceStep", type Property::FLOAT.
+       * @SINCE_1_1.18
+       * @see SetWheelScrollDistanceStep()
+       */
+      WHEEL_SCROLL_DISTANCE_STEP,
+
+      /**
+       * @brief Whether the animation for the layout to scroll to its anchor position after dragging or swiping is enabled.
+       * @details Name "snapToItemEnabled", type Property::BOOLEAN.
+       * @SINCE_1_1.18
+       * @see SetAnchoring()
+       */
+      SNAP_TO_ITEM_ENABLED,
+
+      /**
+       * @brief The interval between refreshes.
+       * @details Name "refreshInterval", type Property::FLOAT.
+       * @SINCE_1_1.18
+       * @see SetRefreshInterval()
+       */
+      REFRESH_INTERVAL,
+
+      /**
+       * @brief The layout used.
+       * @details Name "layout", type Property::ARRAY.
+       * @SINCE_1_2.60
+       * @see Dali::Toolkit::DefaultItemLayoutProperty
+       */
+      LAYOUT,
+
+      ///////////////////////////////////////////////////////////////////////////////
+      // Animatable Properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @brief The current logical position within the layout.
+       * @details Name "layoutPosition", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      LAYOUT_POSITION = ANIMATABLE_PROPERTY_START_INDEX,
+
+      /**
+       * @brief The scrolling speed when playing the flick animation.
+       * @details Name "scrollSpeed", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_SPEED,
+
+      /**
+       * @brief The amount that we can scroll beyond the boundary.
+       * @details Name "overshoot", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      OVERSHOOT,
+
+      /**
+       * @brief The current scrolling direction.
+       * @details Name "scrollDirection", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_DIRECTION,
+
+      /**
+       * @brief The current orientation of the layout.
+       * @details Name "layoutOrientation", type Property::INTEGER.
+       * @SINCE_1_0.0
+       */
+      LAYOUT_ORIENTATION,
+
+      /**
+       * @brief The size of the content.
+       * @details Name "scrollContentSize", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_CONTENT_SIZE,
+    };
+  };
+
+  // Signals
+
+  typedef Signal< void () > LayoutActivatedSignalType;
+
+public:
+
+  /**
+   * @brief Creates an uninitialized ItemView; this can be initialized with ItemView::New().
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   * @SINCE_1_0.0
+   */
+  ItemView();
+
+  /**
+   * @brief Copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] itemView Handle to an object
+   */
+  ItemView( const ItemView& itemView );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] itemView Handle to an object
+   * @return A reference to this
+   */
+  ItemView& operator=( const ItemView& itemView );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~ItemView();
+
+  /**
+   * @brief Creates an initialized ItemView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] factory The factory which provides ItemView with items
+   * @return A handle to a newly allocated Dali resource
+   */
+  static ItemView New(ItemFactory& factory);
+
+  /**
+   * @brief Downcasts a handle to ItemView handle.
+   *
+   * If handle points to a ItemView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a ItemView or an uninitialized handle
+   */
+  static ItemView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Queries the number of layouts.
+   *
+   * @SINCE_1_0.0
+   * @return The number of layouts
+   */
+  unsigned int GetLayoutCount() const;
+
+  /**
+   * @brief Adds a layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] layout The layout
+   */
+  void AddLayout(ItemLayout& layout);
+
+  /**
+   * @brief Removes a layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] layoutIndex The index of one of the ItemView layouts
+   * @pre layoutIndex is less than GetLayoutCount().
+   */
+  void RemoveLayout(unsigned int layoutIndex);
+
+  /**
+   * @brief Retrieves a layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] layoutIndex The index of the layout to retrieve
+   * @return The layout
+   * @pre layoutIndex is less than GetLayoutCount().
+   */
+  ItemLayoutPtr GetLayout(unsigned int layoutIndex) const;
+
+  /**
+   * @brief Retrieves the currently active layout, if any.
+   *
+   * @SINCE_1_0.0
+   * @return The layout, or an uninitialized pointer if no layout is active
+   */
+  ItemLayoutPtr GetActiveLayout() const;
+
+  /**
+   * @brief Retrieves the current layout-position of an item in the ItemView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The item identifier
+   * @return The current layout-position
+   */
+  float GetCurrentLayoutPosition(ItemId itemId) const;
+
+  /**
+   * @brief Activates one of the layouts; this will resize the ItemView
+   * & relayout actors within the ItemView.
+   *
+   * This is done by applying constraints from the new layout, and
+   * removing constraints from the previous layout.
+   *
+   * @SINCE_1_0.0
+   * @param[in] layoutIndex The index of one of the ItemView layouts
+   * @param[in] targetSize The target ItemView & layout size
+   * @param[in] durationSeconds The time taken to relayout in seconds (zero for immediate)
+   * @pre layoutIndex is less than GetLayoutCount().
+   * @pre durationSeconds is greater or equal to zero.
+   */
+  void ActivateLayout(unsigned int layoutIndex, Vector3 targetSize, float durationSeconds);
+
+  /**
+   * @brief Deactivates the current layout, if any.
+   *
+   * The constraints applied by the layout will be removed.
+   * @SINCE_1_0.0
+   */
+  void DeactivateCurrentLayout();
+
+  /**
+   * @brief Sets the minimum swipe speed in pixels per second;
+   *  A pan gesture must exceed this to trigger a swipe.
+   *
+   * @SINCE_1_0.0
+   * @param[in] speed The minimum swipe speed
+   */
+  void SetMinimumSwipeSpeed(float speed);
+
+  /**
+   * @brief Gets the minimum swipe speed in pixels per second.
+   *
+   * @SINCE_1_0.0
+   * @return The minimum swipe speed
+   */
+  float GetMinimumSwipeSpeed() const;
+
+  /**
+   * @brief Sets the minimum swipe distance in actor coordinates;
+   *  A pan gesture must exceed this to trigger a swipe.
+   *
+   * @SINCE_1_0.0
+   * @param[in] distance The minimum swipe distance
+   */
+  void SetMinimumSwipeDistance(float distance);
+
+  /**
+   * @brief Gets the minimum swipe distance in actor coordinates.
+   *
+   * @SINCE_1_0.0
+   * @return The minimum swipe distance
+   */
+  float GetMinimumSwipeDistance() const;
+
+  /**
+   * @brief Set the step of scroll distance in actor coordinates for each wheel event received.
+   *
+   * @SINCE_1_0.0
+   * @param[in] step The step of scroll distance(pixel).
+   */
+  void SetWheelScrollDistanceStep(float step);
+
+  /**
+   * @brief Get the step of scroll distance in actor coordinates for each wheel event received.
+   *
+   * @SINCE_1_0.0
+   * @return The step of scroll distance(pixel)
+   */
+  float GetWheelScrollDistanceStep() const;
+
+  /**
+   * @brief Set whether to enable the animation for the layout to
+   * scroll to its anchor position after dragging or swiping.
+   *
+   * The anchor position is the position where all the items in the layout
+   * are aligned to their closest rounded layout positions in integer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] enabled Whether the anchor animation is enabled or not.
+   */
+  void SetAnchoring(bool enabled);
+
+  /**
+   * @brief Get whether the anchor animation is enabled or not.
+   *
+   * @SINCE_1_0.0
+   * @return Whether the anchor animation is enabled or not.
+   */
+  bool GetAnchoring() const;
+
+  /**
+   * @brief Set the duration of the anchor animation in seconds.
+   *
+   * This is the time taken to reach the nearest anchor position after
+   * a drag or swipe gesture ends.
+   *
+   * @SINCE_1_0.0
+   * @param[in] durationSeconds The duration of the anchor animation in seconds.
+   * @pre durationSeconds must be greater than zero.
+   */
+  void SetAnchoringDuration(float durationSeconds);
+
+  /**
+   * @brief Get the duration of the anchor animation in seconds.
+   *
+   * @SINCE_1_0.0
+   * @return The duration of the anchor animation
+   */
+  float GetAnchoringDuration() const;
+
+  /**
+   * @brief Scroll the current layout to a particular item.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The ID of an item in the layout.
+   * @param[in] durationSeconds How long the scrolling takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the layout should scroll to the particular item instantly.
+   * If calling this with zero second of duration immediately after calling ActivateLayout, it might not work unless
+   * the duration of relayout animation for ActivateLayout is also set to be zero.
+   */
+  void ScrollToItem(ItemId itemId, float durationSeconds);
+
+  /**
+   * @brief Set the interval between refreshes.
+   *
+   * When the layout-position of items is changed by this interval,
+   * new items are requested from ItemFactory.
+   *
+   * @SINCE_1_0.0
+   * @param[in] intervalLayoutPositions The refresh interval in layout position.
+   */
+  void SetRefreshInterval(float intervalLayoutPositions);
+
+  /**
+   * @brief Get the interval between refreshes in layout position.
+   *
+   * @SINCE_1_0.0
+   * @return  The refresh interval
+   */
+  float GetRefreshInterval() const;
+
+  /**
+   * @brief Do a refresh of the item view.
+   * @SINCE_1_0.0
+   */
+  void Refresh();
+
+  /**
+   * @brief Given the Item ID, this returns the accompanying actor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemId The Item ID of the actor required.
+   * @return The Actor corresponding to the Item ID.
+   */
+  Actor GetItem(ItemId itemId) const;
+
+  /**
+   * @brief Returns the Item ID of the specified actor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] actor The actor whose Item ID is required.
+   * @return The Item ID of the item.
+   * @pre The actor should be an item of ItemView.
+   */
+  ItemId GetItemId(Actor actor) const;
+
+  /**
+   * @brief Insert an item.
+   *
+   * A relayout will occur for the existing actors; for example if InsertItem(Item(2, ActorZ), 0) is called,
+   * the items with ID 2 or greater will be moved:
+   *   Initial actors:     After insert:
+   *     ID 1 - ActorA       ID 1 - ActorA
+   *     ID 2 - ActorB       ID 2 - ActorZ !
+   *     ID 3 - ActorC       ID 3 - ActorB
+   *                         ID 4 - ActorC
+   * @SINCE_1_0.0
+   * @param[in] newItem The item to insert.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void InsertItem(Item newItem, float durationSeconds);
+
+  /**
+   * @brief Insert a set of items; this is more efficient than calling InsertItem() repeatedly.
+   *
+   * @SINCE_1_0.0
+   * @param[in] newItems The items to insert.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void InsertItems(const ItemContainer& newItems, float durationSeconds);
+
+  /**
+   * @brief Removes an item with the given ID.
+   *
+   * A relayout will occur for the remaining actors; for example if RemoveItem(Item(2, ActorZ), 0) is called,
+   * the items with ID 3 or greater will be moved:
+   *  | Initial actors:    | After remove:  |
+   *  |:------------------ |:-------------- |
+   *  |  ID 1 - ActorA     |  ID 1 - ActorA |
+   *  |  ID 2 - ActorB     |  ID 2 - ActorC (previously ID 3) |
+   *  |  ID 3 - ActorC     |  ID 3 - ActorB (previously ID 4) |
+   *  |  ID 4 - ActorD     |                |
+   * @SINCE_1_0.0
+   * @param[in] itemId The Item ID of the item to remove.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void RemoveItem(ItemId itemId, float durationSeconds);
+
+  /**
+   * @brief Remove a set of items; this is more efficient than calling RemoveItem() repeatedly.
+   *
+   * @SINCE_1_0.0
+   * @param[in] itemIds The IDs of the items to remove.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void RemoveItems(const ItemIdContainer& itemIds, float durationSeconds);
+
+  /**
+   * @brief Replace an item.
+   *
+   * A relayout will occur for the replacement item only.
+   * @SINCE_1_0.0
+   * @param[in] replacementItem The replacement for an existing item.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void ReplaceItem(Item replacementItem, float durationSeconds);
+
+  /**
+   * @brief Replace a set of items.
+   *
+   * A relayout will occur for the replacement items only.
+   * @SINCE_1_0.0
+   * @param[in] replacementItems The replacements for a set of existing items.
+   * @param[in] durationSeconds How long the relayout takes in seconds.
+   * @pre durationSeconds must be zero or greater; zero means the relayout occurs instantly.
+   */
+  void ReplaceItems(const ItemContainer& replacementItems, float durationSeconds);
+
+  /**
+   * @brief Set the parent origin of the items.
+   *
+   * A relayout will occur for all the items if the parent origin is different than the current one.
+   * @SINCE_1_0.0
+   * @param[in] parentOrigin New parent origin position vector
+   */
+  void SetItemsParentOrigin( const Vector3& parentOrigin );
+
+  /**
+   * @brief Get the parent origin of the items.
+   *
+   * @SINCE_1_0.0
+   * @return The current parent origin of the items
+   */
+  Vector3 GetItemsParentOrigin() const;
+
+  /**
+   * @brief Set the anchor point of the items.
+   *
+   * A relayout will occur for all the items if the anchor point is different than the current one.
+   * @SINCE_1_0.0
+   * @param[in] anchorPoint New anchor point position vector
+   */
+  void SetItemsAnchorPoint( const Vector3& anchorPoint );
+
+  /**
+   * @brief Get the anchor point of the items.
+   *
+   * @SINCE_1_0.0
+   * @return The current anchor point of the items
+   */
+  Vector3 GetItemsAnchorPoint() const;
+
+  /**
+   * @brief Get the range of items that are currently in ItemView.
+   *
+   * @SINCE_1_0.0
+   * @param[out] range The range of items.
+   */
+  void GetItemsRange(ItemRange& range);
+
+public: // Signals
+
+  /**
+   * @brief Signal emitted when layout activation is finished.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName();
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to.
+   * @pre The Object has been initialized.
+   */
+  ItemView::LayoutActivatedSignalType& LayoutActivatedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in]  implementation  The Control implementation.
+   */
+  DALI_INTERNAL ItemView(Internal::ItemView& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in]  internal  A pointer to the internal CustomActor.
+   */
+  explicit DALI_INTERNAL ItemView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ITEM_VIEW_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h
new file mode 100644 (file)
index 0000000..53b1f83
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef DALI_TOOLKIT_SCROLL_VIEW_SCROLL_MODE_H
+#define DALI_TOOLKIT_SCROLL_VIEW_SCROLL_MODE_H
+
+/*
+ * Copyright (c) 2017 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
+{
+
+/**
+ * @addtogroup dali_toolkit_controls_scroll_view
+ * @{
+ */
+
+/**
+ * @brief Properties to use in a Property::MAP when setting a ScrollView's scroll mode.
+ * @SINCE_1_2.60
+ */
+namespace ScrollMode
+{
+
+/**
+ * @brief Properties to use in a Property::MAP when setting a ScrollView's scroll mode.
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  /**
+   * @brief Whether the content can be scrolled along the X axis or not.
+   * @details Name "xAxisScrollEnabled", type Property::BOOLEAN.
+   * @SINCE_1_2.60
+   */
+  X_AXIS_SCROLL_ENABLED,
+
+  /**
+   * @brief When set, causes scroll view to snap to multiples of the
+   * value of the interval while flicking along the X axis.
+   * @details Name "xAxisSnapToInterval", type Property::FLOAT
+   * @SINCE_1_2.60
+   * @note By default, there is no snapping.
+   */
+  X_AXIS_SNAP_TO_INTERVAL,
+
+  /**
+   * @brief When set, the scroll view is unable to scroll beyond the
+   * value of the boundary along the X axis.
+   * @details Name "xAxisScrollBoundary", type Property::FLOAT.
+   * @SINCE_1_2.60
+   * @note By default, there is no boundary.
+   */
+  X_AXIS_SCROLL_BOUNDARY,
+
+  /**
+   * @brief Whether the content can be scrolled along the Y axis or not.
+   * @details Name "yAxisScrollEnabled", type Property::BOOLEAN
+   * @SINCE_1_2.60
+   */
+  Y_AXIS_SCROLL_ENABLED,
+
+  /**
+   * @brief When set, causes scroll view to snap to multiples of the
+   * value of the interval while flicking along the Y axis.
+   * @details Name "yAxisSnapToInterval", type Property::FLOAT.
+   * @SINCE_1_2.60
+   * @note By default, there is no snapping.
+   */
+  Y_AXIS_SNAP_TO_INTERVAL,
+
+  /**
+   * @brief When set, the scroll view is unable to scroll beyond the
+   * value of the boundary along the Y axis.
+   * @details Name "yAxisScrollBoundary", type Property::FLOAT.
+   * @SINCE_1_2.60
+   * @note By default, there is no boundary.
+   */
+  Y_AXIS_SCROLL_BOUNDARY
+};
+
+} // ScrollMode
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_VIEW_SCROLL_MODE_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.cpp b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.cpp
new file mode 100644 (file)
index 0000000..ac3b3ed
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+#include <dali/public-api/common/constants.h>
+#include <dali/public-api/math/math-utils.h>
+#include <dali/public-api/object/property-input.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+void MoveActorConstraint( Vector3& current, const PropertyInputContainer& inputs )
+{
+  current += Vector3(inputs[0]->GetVector2());
+}
+
+void WrapActorConstraint( Vector3& position, const PropertyInputContainer& inputs )
+{
+  bool wrap = inputs[5]->GetBoolean();
+
+  if(wrap)
+  {
+    const Vector2& min = inputs[3]->GetVector2();
+    const Vector2& max = inputs[4]->GetVector2();
+
+    const Vector3& anchor = inputs[1]->GetVector3();
+    const Vector3 scale = inputs[0]->GetVector3();
+    const Vector3 size = inputs[2]->GetVector3();
+
+    if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
+    {
+      // WRAP X (based on the position of the right side)
+      float offsetX = (1.0f - anchor.x) * size.x * scale.x;
+      position.x = WrapInDomain(position.x + offsetX, min.x, max.x) - offsetX;
+    }
+
+    if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
+    {
+      // WRAP Y (based on the position of the bottom side)
+      float offsetY = (1.0f - anchor.y) * size.y * scale.y;
+      position.y = WrapInDomain(position.y + offsetY, min.y, max.y) - offsetY;
+    }
+  }
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
+
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h
new file mode 100755 (executable)
index 0000000..737c3bd
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_TOOLKIT_SCROLL_VIEW_CONSTRAINTS_H
+#define DALI_TOOLKIT_SCROLL_VIEW_CONSTRAINTS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/constraint.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+class PropertyInput;
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls_scroll_view
+ * @{
+ */
+
+// Constraints ////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Useful constraints to apply to a ScrollView.
+ */
+
+/**
+ * @brief Moves an Actor in accordance with the scroll position.
+ *
+ * @SINCE_1_0.0
+ * @param[in] current Current position
+ * @param[in] inputs The position input that Actor will move
+ */
+DALI_TOOLKIT_API void MoveActorConstraint( Vector3& current, const PropertyInputContainer& inputs );
+
+/**
+ * @brief Wraps an Actor's position in accordance with the min/max bounds of domain.
+ *
+ * @SINCE_1_0.0
+ * @param[in] position Position to be wrapped
+ * @param[in] inputs The input that Actor's position will be wrapped
+ */
+DALI_TOOLKIT_API void WrapActorConstraint( Vector3& position, const PropertyInputContainer& inputs );
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_VIEW_CONSTRAINTS_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.cpp b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.cpp
new file mode 100644 (file)
index 0000000..abdd901
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ScrollViewEffect::ScrollViewEffect()
+{
+
+}
+
+ScrollViewEffect::ScrollViewEffect(Internal::ScrollViewEffect *impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h
new file mode 100755 (executable)
index 0000000..d6f3402
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef DALI_TOOLKIT_SCROLL_VIEW_EFFECT_H
+#define DALI_TOOLKIT_SCROLL_VIEW_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+class PropertyInput;
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ScrollViewEffect;
+class ScrollViewWobbleEffect;
+}
+/**
+ * @addtogroup dali_toolkit_controls_scroll_view
+ * @{
+ */
+
+class ScrollView;
+class ScrollViewEffect;
+
+/**
+ * @brief ScrollView Effect base class, used to apply custom effects to a
+ * ScrollView instance.
+ *
+ * Such effects are purely logical (i.e. physics), and may produce
+ * properties that can be used with visual effects, such as creating
+ * constraints that are applied to ShaderEffects or Actors using these
+ * properties as inputs.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API ScrollViewEffect : public Dali::BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Creates an uninitialized ScrollViewEffect; this can only be initialized with derived classes.
+   *
+   * Calling member functions with an uninitialized Toolkit::BaseObject is not allowed.
+   * @SINCE_1_0.0
+   */
+  ScrollViewEffect();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by Dali New() methods.
+   *
+   * @SINCE_1_0.0
+   * @param[in] impl A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL ScrollViewEffect(Internal::ScrollViewEffect *impl);
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_VIEW_EFFECT_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.cpp b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.cpp
new file mode 100644 (file)
index 0000000..d8bdc75
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h>
+
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+ScrollViewPagePathEffect ScrollViewPagePathEffect::New(Path path, const Vector3& forward, Dali::Property::Index inputPropertyIndex, const Vector3& viewPageSize, unsigned int pageCount)
+{
+  return ScrollViewPagePathEffect(new Internal::ScrollViewPagePathEffect(path, forward, inputPropertyIndex, viewPageSize,pageCount));
+}
+
+ScrollViewPagePathEffect::ScrollViewPagePathEffect()
+{
+}
+
+ScrollViewPagePathEffect::ScrollViewPagePathEffect(Internal::ScrollViewPagePathEffect *impl)
+:ScrollViewEffect(impl)
+{
+}
+
+ScrollViewPagePathEffect ScrollViewPagePathEffect::DownCast( BaseHandle handle )
+{
+  return ScrollViewPagePathEffect( dynamic_cast<Internal::ScrollViewPagePathEffect*>(handle.GetObjectPtr()) );
+}
+
+void ScrollViewPagePathEffect::ApplyToPage( Actor page,  unsigned int pageOrder )
+{
+  GetImpl(*this).ApplyToPage( page, pageOrder );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-page-path-effect.h
new file mode 100755 (executable)
index 0000000..6847d43
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef DALI_TOOLKIT_SCROLL_VIEW_PAGE_PATH_EFFECT_H
+#define DALI_TOOLKIT_SCROLL_VIEW_PAGE_PATH_EFFECT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-effect.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+class Actor;
+class Path;
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ScrollViewPagePathEffect;
+}
+/**
+ * @addtogroup dali_toolkit_controls_scroll_view
+ * @{
+ */
+
+/**
+ * @brief ScrollView Page Path Effect.
+ *
+ * This effect causes Actors to follow a given path. The opacity of the actor will be 0.0 at
+ * the beginning of the path and will go to 1.0 as it is approximating to half of the path to return
+ * to 0.0 at the end of the path.
+ *
+ *
+ * ScrollView
+ * |
+ * Page (1..n)
+ *
+ * You should ensure ScrollView's default constraints have been removed,
+ * by calling ScrollView::RemoveConstraintsFromChildren() before applying
+ * this effect to ScrollView.
+ *
+ * Manual operation:
+ * ApplyToPage(...) method should be called on every page.
+ *
+ * Automatic operation:
+ * not implemented.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API ScrollViewPagePathEffect : public ScrollViewEffect
+{
+
+public:
+
+  /**
+   * @brief Creates an initialized ScrollViewPagePathEffect.
+   * @SINCE_1_0.0
+   * @param[in] path The path that will be used by the scroll effect
+   * @param[in] forward Vector in page object space which will be aligned with the tangent of the path
+   * @param[in] inputPropertyIndex Index of a property of the scroll-view which will be used as the input for the path
+   * @param[in] viewPageSize Size of a page in the scrollview
+   * @param[in] pageCount Total number of pages in the scrollview
+   * @return A handle to a newly allocated Dali resource
+   */
+  static ScrollViewPagePathEffect New(Path path, const Vector3& forward, Dali::Property::Index inputPropertyIndex, const Vector3& viewPageSize, unsigned int pageCount);
+
+  /**
+   * @brief Creates an uninitialized ScrollViewPagePathEffect; this can be initialized with ScrollViewPagePathEffect::New().
+   * Calling member functions with an uninitialized Toolkit::ScrollViewPagePathEffect is not allowed.
+   * @SINCE_1_0.0
+   */
+  ScrollViewPagePathEffect();
+
+  /**
+   * @brief Downcasts a handle to ScrollViewPagePathEffect handle.
+   *
+   * If handle points to a ScrollViewPagePathEffect, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a ScrollViewPagePathEffect or an uninitialized handle
+   */
+  static ScrollViewPagePathEffect DownCast( BaseHandle handle );
+
+  /**
+   * @brief Manually apply effect to a page in the scroll-view.
+   * @SINCE_1_0.0
+   * @param[in] page The page to be affected by this effect
+   * @param[in] pageOrder The order of the page in the scroll view
+   */
+  void ApplyToPage( Actor page, unsigned int pageOrder );
+
+protected:
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by Dali New() methods.
+   * @SINCE_1_0.0
+   * @param[in] impl A pointer to a newly allocated Dali resource
+   */
+  explicit DALI_INTERNAL ScrollViewPagePathEffect( Internal::ScrollViewPagePathEffect *impl );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_VIEW_PAGE_PATH_EFFECT_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.cpp b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.cpp
new file mode 100644 (file)
index 0000000..471f371
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// RulerDomain
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+RulerDomain::RulerDomain(float min, float max, bool enabled)
+: min(min),
+  max(max),
+  enabled(enabled)
+{
+}
+
+float RulerDomain::Clamp(float x, float length, float scale) const
+{
+  ClampState clamped;
+
+  return Clamp(x, length, scale, clamped);
+}
+
+float RulerDomain::Clamp(float x, float length, float scale, ClampState &clamped) const
+{
+  if(!enabled)
+  {
+    clamped = NotClamped;
+    return x;
+  }
+
+  const float minExtent = min * scale;
+  const float maxExtent = max * scale - length;
+  if(x < minExtent)
+  {
+    clamped = ClampedToMin;
+    return minExtent;
+  }
+  else if(x > maxExtent)
+  {
+    clamped = ClampedToMax;
+    return maxExtent;
+  }
+
+  clamped = NotClamped;
+  return x;
+}
+
+float RulerDomain::GetSize() const
+{
+  return max-min;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Ruler
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+Ruler::Ruler()
+: mType(Free),
+  mEnabled(true),
+  mDomain(RulerDomain(0.0f,1.0f,false))
+{
+}
+
+Ruler::~Ruler()
+{
+}
+
+Ruler::RulerType Ruler::GetType() const
+{
+  return mType;
+}
+
+bool Ruler::IsEnabled() const
+{
+  return mEnabled;
+}
+
+void Ruler::Enable()
+{
+  mEnabled = true;
+}
+
+void Ruler::Disable()
+{
+  mEnabled = false;
+}
+
+void Ruler::SetDomain(RulerDomain domain)
+{
+  mDomain = domain;
+}
+
+const RulerDomain &Ruler::GetDomain() const
+{
+  return mDomain;
+}
+
+void Ruler::DisableDomain()
+{
+  mDomain = RulerDomain(0.0f,1.0f,false);
+}
+
+float Ruler::Clamp(float x, float length, float scale) const
+{
+  return mDomain.Clamp(x, length, scale);
+}
+
+float Ruler::Clamp(float x, float length, float scale, ClampState &clamped) const
+{
+  return mDomain.Clamp(x, length, scale, clamped);
+}
+
+float Ruler::SnapAndClamp(float x, float bias, float length, float scale) const
+{
+  return Clamp(Snap(x, bias), length, scale);
+}
+
+float Ruler::SnapAndClamp(float x, float bias, float length, float scale, ClampState &clamped) const
+{
+  return Clamp(Snap(x, bias), length, scale, clamped);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// DefaultRuler
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+DefaultRuler::DefaultRuler()
+{
+  mType = Free;
+}
+
+float DefaultRuler::Snap(float x, float bias) const
+{
+  return x;
+}
+
+float DefaultRuler::GetPositionFromPage(unsigned int page, unsigned int &volume, bool wrap) const
+{
+  volume = 0;
+  return 0.0f;
+}
+
+unsigned int DefaultRuler::GetPageFromPosition(float position, bool wrap) const
+{
+  return 0;
+}
+
+unsigned int DefaultRuler::GetTotalPages() const
+{
+  return 1;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// FixedRuler
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+FixedRuler::FixedRuler(float spacing)
+: mSpacing(spacing)
+{
+  if(fabsf(mSpacing) <= Math::MACHINE_EPSILON_1)
+  {
+    DALI_LOG_ERROR( "Page spacing too small (%f).\n", double(spacing) );
+    mSpacing = spacing >= 0.0f ? Math::MACHINE_EPSILON_1 : -Math::MACHINE_EPSILON_1;
+  }
+  mType = Fixed;
+}
+
+float FixedRuler::Snap(float x, float bias) const
+{
+  return floor(x / mSpacing + bias) * mSpacing;
+}
+
+float FixedRuler::GetPositionFromPage(unsigned int page, unsigned int &volume, bool wrap) const
+{
+  float position = mDomain.min;
+
+  volume = 0;
+
+  // spacing must be present.
+  if( mEnabled )
+  {
+    unsigned int column = page;
+
+    // In carry mode, a volume (carry) is produced when page exceeds limit within domain
+    if(wrap)
+    {
+      unsigned int pagesPerVolume = mDomain.GetSize() / mSpacing;
+      if(pagesPerVolume>0)
+      {
+        column += pagesPerVolume;
+        column %= pagesPerVolume;
+        volume = page/pagesPerVolume;
+      }
+    }
+
+    position = mDomain.min + column * mSpacing;
+  }
+  else  // Domain (or Spacing) is not present, carry page to volume.
+  {
+    if(wrap)
+    {
+      volume = page;
+    }
+  }
+
+  return position;
+}
+
+unsigned int FixedRuler::GetPageFromPosition(float position, bool wrap) const
+{
+  unsigned int page = 0;
+
+  // spacing must be present.
+  if( mEnabled )
+  {
+    if( wrap )
+    {
+      position = WrapInDomain(position, mDomain.min, mDomain.max);
+    }
+    page = std::max(static_cast<double>(0.0f), static_cast<double>(floor((position - mDomain.min) / mSpacing + 0.5f)));
+
+    if(wrap)
+    {
+      unsigned int pagesPerVolume = mDomain.GetSize() / mSpacing;
+      // Defensive check to avoid a divide by zero below when the ruler is in an invalid state (entire domain smaller than spacing between pages of it):
+      if(pagesPerVolume < 1u)
+      {
+        pagesPerVolume = 1u;
+        DALI_LOG_ERROR("Ruler domain(%f) is smaller than its spacing(%f).\n", mDomain.GetSize() * 1.0, mSpacing * 1.0 );
+      }
+      page %= pagesPerVolume;
+    }
+  }
+
+  return page;
+}
+
+unsigned int FixedRuler::GetTotalPages() const
+{
+  unsigned int pagesPerVolume = 1;
+
+  // spacing must be present.
+  if( mEnabled )
+  {
+    pagesPerVolume = mDomain.GetSize() / mSpacing;
+  }
+
+  return pagesPerVolume;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ScrollView
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ScrollView::ScrollView()
+{
+}
+
+ScrollView::ScrollView(Internal::ScrollView& implementation)
+: Scrollable(implementation)
+{
+}
+
+ScrollView::ScrollView( Dali::Internal::CustomActor* internal )
+: Scrollable( internal )
+{
+  VerifyCustomActorPointer<Internal::ScrollView>(internal);
+}
+
+ScrollView::ScrollView( const ScrollView& handle )
+: Scrollable( handle )
+{
+}
+
+ScrollView& ScrollView::operator=( const ScrollView& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+ScrollView ScrollView::New()
+{
+  return Internal::ScrollView::New();
+}
+
+ScrollView::~ScrollView()
+{
+}
+
+ScrollView ScrollView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<ScrollView, Internal::ScrollView>(handle);
+}
+
+AlphaFunction ScrollView::GetScrollSnapAlphaFunction() const
+{
+  return GetImpl(*this).GetScrollSnapAlphaFunction();
+}
+
+void ScrollView::SetScrollSnapAlphaFunction(AlphaFunction alpha)
+{
+  GetImpl(*this).SetScrollSnapAlphaFunction(alpha);
+}
+
+AlphaFunction ScrollView::GetScrollFlickAlphaFunction() const
+{
+  return GetImpl(*this).GetScrollFlickAlphaFunction();
+}
+
+void ScrollView::SetScrollFlickAlphaFunction(AlphaFunction alpha)
+{
+  GetImpl(*this).SetScrollFlickAlphaFunction(alpha);
+}
+
+float ScrollView::GetScrollSnapDuration() const
+{
+  return GetImpl(*this).GetScrollSnapDuration();
+}
+
+void ScrollView::SetScrollSnapDuration(float time)
+{
+  GetImpl(*this).SetScrollSnapDuration(time);
+}
+
+float ScrollView::GetScrollFlickDuration() const
+{
+  return GetImpl(*this).GetScrollFlickDuration();
+}
+
+void ScrollView::SetScrollFlickDuration(float time)
+{
+  GetImpl(*this).SetScrollFlickDuration(time);
+}
+
+void ScrollView::SetRulerX(RulerPtr ruler)
+{
+  GetImpl(*this).SetRulerX(ruler);
+}
+
+void ScrollView::SetRulerY(RulerPtr ruler)
+{
+  GetImpl(*this).SetRulerY(ruler);
+}
+
+void ScrollView::SetScrollSensitive(bool sensitive)
+{
+  GetImpl(*this).SetScrollSensitive(sensitive);
+}
+
+void ScrollView::SetMaxOvershoot(float overshootX, float overshootY)
+{
+  GetImpl(*this).SetMaxOvershoot(overshootX, overshootY);
+}
+
+void ScrollView::SetSnapOvershootAlphaFunction(AlphaFunction alpha)
+{
+  GetImpl(*this).SetSnapOvershootAlphaFunction(alpha);
+}
+
+void ScrollView::SetSnapOvershootDuration(float duration)
+{
+  GetImpl(*this).SetSnapOvershootDuration(duration);
+}
+
+void ScrollView::SetActorAutoSnap(bool enable)
+{
+  GetImpl(*this).SetActorAutoSnap(enable);
+}
+
+void ScrollView::SetWrapMode(bool enable)
+{
+  GetImpl(*this).SetWrapMode(enable);
+}
+
+int ScrollView::GetScrollUpdateDistance() const
+{
+  return GetImpl(*this).GetScrollUpdateDistance();
+}
+
+void ScrollView::SetScrollUpdateDistance(int distance)
+{
+  GetImpl(*this).SetScrollUpdateDistance(distance);
+}
+
+bool ScrollView::GetAxisAutoLock() const
+{
+  return GetImpl(*this).GetAxisAutoLock();
+}
+
+void ScrollView::SetAxisAutoLock(bool enable)
+{
+  GetImpl(*this).SetAxisAutoLock(enable);
+}
+
+float ScrollView::GetAxisAutoLockGradient() const
+{
+  return GetImpl(*this).GetAxisAutoLockGradient();
+}
+
+void ScrollView::SetAxisAutoLockGradient(float gradient)
+{
+  GetImpl(*this).SetAxisAutoLockGradient(gradient);
+}
+
+float ScrollView::GetFrictionCoefficient() const
+{
+  return GetImpl(*this).GetFrictionCoefficient();
+}
+
+void ScrollView::SetFrictionCoefficient(float friction)
+{
+  GetImpl(*this).SetFrictionCoefficient(friction);
+}
+
+float ScrollView::GetFlickSpeedCoefficient() const
+{
+  return GetImpl(*this).GetFlickSpeedCoefficient();
+}
+
+void ScrollView::SetFlickSpeedCoefficient(float speed)
+{
+  GetImpl(*this).SetFlickSpeedCoefficient(speed);
+}
+
+Vector2 ScrollView::GetMinimumDistanceForFlick() const
+{
+  return GetImpl(*this).GetMinimumDistanceForFlick();
+}
+
+void ScrollView::SetMinimumDistanceForFlick( const Vector2& distance )
+{
+  GetImpl(*this).SetMinimumDistanceForFlick(distance);
+}
+
+float ScrollView::GetMinimumSpeedForFlick() const
+{
+  return GetImpl(*this).GetMinimumSpeedForFlick();
+}
+
+void ScrollView::SetMinimumSpeedForFlick( float speed )
+{
+  GetImpl(*this).SetMinimumSpeedForFlick(speed);
+}
+
+float ScrollView::GetMaxFlickSpeed() const
+{
+  return GetImpl(*this).GetMaxFlickSpeed();
+}
+
+void ScrollView::SetMaxFlickSpeed(float speed)
+{
+  GetImpl(*this).SetMaxFlickSpeed(speed);
+}
+
+Vector2 ScrollView::GetWheelScrollDistanceStep() const
+{
+  return GetImpl(*this).GetWheelScrollDistanceStep();
+}
+
+void ScrollView::SetWheelScrollDistanceStep(Vector2 step)
+{
+  GetImpl(*this).SetWheelScrollDistanceStep(step);
+}
+
+Vector2 ScrollView::GetCurrentScrollPosition() const
+{
+  return GetImpl(*this).GetCurrentScrollPosition();
+}
+
+unsigned int ScrollView::GetCurrentPage() const
+{
+  return GetImpl(*this).GetCurrentPage();
+}
+
+void ScrollView::ScrollTo(const Vector2 &position)
+{
+  GetImpl(*this).ScrollTo(position);
+}
+
+void ScrollView::ScrollTo(const Vector2 &position, float duration)
+{
+  GetImpl(*this).ScrollTo(position, duration);
+}
+
+void ScrollView::ScrollTo(const Vector2 &position, float duration, AlphaFunction alpha)
+{
+  GetImpl(*this).ScrollTo(position, duration, alpha);
+}
+
+void ScrollView::ScrollTo(const Vector2 &position, float duration,
+                          DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  GetImpl(*this).ScrollTo(position, duration, horizontalBias, verticalBias);
+}
+
+void ScrollView::ScrollTo(const Vector2 &position, float duration, AlphaFunction alpha,
+                          DirectionBias horizontalBias, DirectionBias verticalBias)
+{
+  GetImpl(*this).ScrollTo(position, duration, alpha, horizontalBias, verticalBias);
+}
+
+void ScrollView::ScrollTo(unsigned int page)
+{
+  GetImpl(*this).ScrollTo(page);
+}
+
+void ScrollView::ScrollTo(unsigned int page, float duration)
+{
+  GetImpl(*this).ScrollTo(page, duration);
+}
+
+void ScrollView::ScrollTo(unsigned int page, float duration, DirectionBias bias)
+{
+  GetImpl(*this).ScrollTo(page, duration, bias);
+}
+
+void ScrollView::ScrollTo(Actor &actor)
+{
+  GetImpl(*this).ScrollTo(actor);
+}
+
+void ScrollView::ScrollTo(Actor &actor, float duration)
+{
+  GetImpl(*this).ScrollTo(actor, duration);
+}
+
+bool ScrollView::ScrollToSnapPoint()
+{
+  return GetImpl(*this).ScrollToSnapPoint();
+}
+
+void ScrollView::ApplyConstraintToChildren(Constraint constraint)
+{
+  GetImpl(*this).ApplyConstraintToChildren(constraint);
+}
+
+void ScrollView::RemoveConstraintsFromChildren()
+{
+  GetImpl(*this).RemoveConstraintsFromChildren();
+}
+
+void ScrollView::ApplyEffect(ScrollViewEffect effect)
+{
+  GetImpl(*this).ApplyEffect(effect);
+}
+
+void ScrollView::RemoveEffect(ScrollViewEffect effect)
+{
+  GetImpl(*this).RemoveEffect(effect);
+}
+
+void ScrollView::RemoveAllEffects()
+{
+  GetImpl(*this).RemoveAllEffects();
+}
+
+void ScrollView::BindActor(Actor child)
+{
+  GetImpl(*this).BindActor(child);
+}
+
+void ScrollView::UnbindActor(Actor child)
+{
+  GetImpl(*this).UnbindActor(child);
+}
+
+ScrollView::SnapStartedSignalType& ScrollView::SnapStartedSignal()
+{
+  return GetImpl(*this).SnapStartedSignal();
+}
+
+void ScrollView::SetScrollingDirection( Radian direction, Radian threshold )
+{
+  GetImpl(*this).SetScrollingDirection( direction, threshold );
+}
+
+void ScrollView::RemoveScrollingDirection( Radian direction )
+{
+  GetImpl(*this).RemoveScrollingDirection( direction );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h b/dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h
new file mode 100755 (executable)
index 0000000..2822027
--- /dev/null
@@ -0,0 +1,1448 @@
+#ifndef DALI_TOOLKIT_SCROLL_VIEW_H
+#define DALI_TOOLKIT_SCROLL_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/animation/alpha-function.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class ScrollView;
+}
+/**
+ * @addtogroup dali_toolkit_controls_scroll_view
+ * @{
+ */
+
+/**
+ * @brief Enumeration for how axes/rotation or scale are clamped.
+ * @SINCE_1_0.0
+ */
+enum ClampState
+{
+  NotClamped,   ///< The quantity isn't clamped @SINCE_1_0.0
+  ClampedToMin, ///< The quantity is clamped to the min value @SINCE_1_0.0
+  ClampedToMax  ///< The quantity is clamped to the max value @SINCE_1_0.0
+};
+
+/**
+ * @brief A 2 dimensional clamp.
+ * @SINCE_1_0.0
+ */
+struct ClampState2D
+{
+  ClampState x; ///< The clamp state of the x axis
+  ClampState y; ///< The clamp state of the y axis
+};
+
+/**
+ * @brief Enumeration for the snap type.
+ * @SINCE_1_0.0
+ */
+enum SnapType
+{
+  Snap,  ///< Snap @SINCE_1_0.0
+  Flick  ///< Flick @SINCE_1_0.0
+};
+
+/**
+ * @brief Enumeration for DirectionBias types.
+ * @SINCE_1_0.0
+ */
+enum DirectionBias
+{
+  DirectionBiasLeft  = -1,  ///< Bias scroll snap to Left @SINCE_1_0.0
+  DirectionBiasNone  =  0,  ///< Don't bias scroll snap @SINCE_1_0.0
+  DirectionBiasRight =  1   ///< Bias scroll snap to Right @SINCE_1_0.0
+};
+
+/**
+ * @brief Used for specifying minimum/maximum extents of a ruler.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API RulerDomain
+{
+public:
+
+  /**
+   * @brief Creates Ruler domain allowing a point to traverse between min and max extents.
+   *
+   * @SINCE_1_0.0
+   * @param[in] min Minimum extent (point cannot traverse less than this)
+   * @param[in] max Maximum extent (point cannot traverse greater than this)
+   * @param[in] enabled Whether domain has been enabled or not
+   */
+  explicit RulerDomain(float min, float max, bool enabled = true);
+
+public:
+
+  float min;    ///< Minimum extent (point cannot traverse less than this)
+  float max;    ///< Maximum extent (point cannot traverse greater than this)
+  bool enabled; ///< Whether domain has been enabled or not.
+
+  /**
+   * @brief Clamps value (x) from (min) to (max).
+   *
+   * An optional length parameter can be specified to suggest that the
+   * subject is not a point but a line to that should be clamped.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X point to be clamped between (min) and (max) extents
+   * @param[in] length (optional) The Length of the line from (x) to (x + length) to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @return The clamped value
+   */
+  float Clamp(float x, float length = 0.0f, float scale = 1.0f) const;
+
+  /**
+   * @brief Clamps value (x) from (min) to (max).
+   *
+   * An optional length parameter can be specified to suggest that the
+   * subject is not a point but a line to that should be clamped.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X point to be clamped between (min) and (max) extents
+   * @param[in] length (optional) The Length of the line from (x) to (x + length) to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @param[out] clamped Whether clamping occurred and which size (None, Min or Max)
+   * @return The clamped value
+   */
+  float Clamp(float x, float length, float scale, ClampState &clamped) const;
+
+  /**
+   * @brief Returns (max-min) size of ruler.
+   *
+   * @SINCE_1_0.0
+   * @return The size of the ruler from min to max
+   */
+  float GetSize() const;
+
+};
+
+// Forward declare future extension interface
+class RulerExtension;
+
+/**
+ * @brief Abstracts class to define scroll axes.
+ *
+ * It can specify whether they are traversable,
+ * where their snap points are and their domain.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API Ruler : public RefObject
+{
+public:
+  /**
+   * @brief Enumeration for the type of the ruler.
+   * @SINCE_1_0.0
+   */
+  enum RulerType {
+    Fixed,  ///< A fixed ruler @SINCE_1_0.0
+    Free    ///< A free ruler @SINCE_1_0.0
+  };
+
+public:
+
+  /**
+   * @brief Constructs ruler, enabled by default, with limitless domain.
+   * @SINCE_1_0.0
+   */
+  Ruler();
+
+  /**
+   * @brief Snaps (x) in accordance to the ruler settings.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x The input value on the ruler to be snapped
+   * @param[in] bias (optional) The biasing employed for snapping
+   * 0 floor input (floor x) "Used for Flick Left"
+   * 0.5 round input (floor x + 0.5) "Used for Release"
+   * 1 ceil input (floor x + 1.0) "Used for Flick Right"
+   * @return The position of the one dimensional point passed in once snapped.
+   */
+  virtual float Snap(float x, float bias = 0.5f) const = 0;
+
+  /**
+   * @brief Returns position from page, based on whatever the ruler
+   * defines as a page.
+   *
+   * If (wrap) is true, then will set volume to the number of
+   * times page has exceeded the domain's volume (volume being the
+   * number of pages within the domain), while wrapping the position
+   * within the domain.
+   *
+   * @SINCE_1_0.0
+   * @param[in] page The page index
+   * @param[out] volume The overflow volume when the page exceeds the domain (wrap must be enabled)
+   * @param[in] wrap Enable wrap mode
+   * @return The position representing this page point
+   */
+  virtual float GetPositionFromPage(unsigned int page, unsigned int &volume, bool wrap) const = 0;
+
+  /**
+   * @brief Returns page from position, based on whatever the ruler
+   * defines as a page.
+   *
+   * If (wrap) is true, then will return a page wrapped within the domain.
+   *
+   * @SINCE_1_0.0
+   * @param[in] position The position on the domain
+   * @param[in] wrap Enable wrap mode
+   * @return The page where this position resides
+   */
+  virtual unsigned int GetPageFromPosition(float position, bool wrap) const = 0;
+
+  /**
+   * @brief Returns the total number of pages within this Ruler.
+   *
+   * @SINCE_1_0.0
+   * @return The number of pages in the Ruler
+   */
+  virtual unsigned int GetTotalPages() const = 0;
+
+  /**
+   * @brief Gets the extension interface of the Ruler.
+   *
+   * @SINCE_1_0.0
+   * @return The extension interface of the Ruler
+   */
+  virtual RulerExtension* GetExtension() { return NULL; }
+
+public:
+
+  /**
+   * @brief Gets the ruler type.
+   *
+   * @SINCE_1_0.0
+   * @return The ruler type
+   */
+  Ruler::RulerType GetType() const;
+
+  /**
+   * @brief Returns whether this axis has been enabled or not.
+   *
+   * @SINCE_1_0.0
+   * @return true if axis is enabled
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @brief Enables ruler (ruler must be enabled in order to traverse along it).
+   * @SINCE_1_0.0
+   */
+  void Enable();
+
+  /**
+   * @brief Disables ruler.
+   * @SINCE_1_0.0
+   */
+  void Disable();
+
+  /**
+   * @brief Sets the Domain.
+   *
+   * @SINCE_1_0.0
+   * @param[in] domain Ruler domain object
+   */
+  void SetDomain(RulerDomain domain);
+
+  /**
+   * @brief Gets the Domain.
+   *
+   * @SINCE_1_0.0
+   * @return The domain
+   */
+  const RulerDomain &GetDomain() const;
+
+  /**
+   * @brief Disables Domain (minimum/maximum extents for this axis).
+   * @SINCE_1_0.0
+   */
+  void DisableDomain();
+
+  /**
+   * @brief Clamps value (x) from (min) to (max).
+   *
+   * An optional length parameter can be specified to suggest that the
+   * subject is not a point but a line that should be clamped.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X point to be clamped between (min) and (max) extents
+   * @param[in] length (optional) The Length of the line from (x) to (x + length) to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @return The clamped value
+   */
+  float Clamp(float x, float length = 0.0f, float scale = 1.0f) const;
+
+
+  /**
+   * @brief Clamps value (x) from (min) to (max).
+   *
+   * An optional length parameter can be specified to suggest that the
+   * subject is not a point but a line to that should be clamped.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X point to be clamped between (min) and (max) extents
+   * @param[in] length (optional) The Length of the line from (x) to (x + length) to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @param[out] clamped Whether clamping occurred and which size (None, Min or Max)
+   * @return The clamped value
+   */
+  float Clamp(float x, float length, float scale, ClampState &clamped) const;
+
+  /**
+   * @brief Snaps and Clamps (x) in accordance to ruler settings.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X value to be snapped in accordance to ruler snap value,
+   *            and clamped in accordance to the ruler's domain (if set)
+   * @param[in] bias (optional) The biasing employed for snapping
+   *            0 floor input (floor x) "Used for Flick Left"
+   *            0.5 round input (floor x + 0.5) "Used for Release"
+   *            1 ceil input (floor x + 1.0) "Used for Flick Right"
+   * @param[in] length (optional) The Length of the line from (x) to (x + length)
+   *            to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @return The clamped value after snapping
+   */
+  float SnapAndClamp(float x, float bias = 0.5f, float length = 0.0f, float scale = 1.0f) const;
+
+  /**
+   * @brief Snaps and Clamps (x) in accordance to ruler settings.
+   *
+   * @SINCE_1_0.0
+   * @param[in] x X value to be snapped in accordance to ruler snap value,
+   *            and clamped in accordance to the ruler's domain (if set)
+   * @param[in] bias (optional) The biasing employed for snapping
+   * 0 floor input (floor x) "Used for Flick Left"
+   * 0.5 round input (floor x + 0.5) "Used for Release"
+   * 1 ceil input (floor x + 1.0) "Used for Flick Right"
+   * @param[in] length (optional) The Length of the line from (x) to (x + length)
+   * to be clamped
+   * @param[in] scale Scaling parameter which treats domain as scaled in calculations
+   * @param[out] clamped Whether clamping occurred and which size (None, Min or Max)
+   * @return The clamped value after snapping
+   */
+  float SnapAndClamp(float x, float bias, float length, float scale, ClampState &clamped) const;
+
+protected:
+
+  /**
+   * @brief Destructor - A reference counted object may only be deleted by calling Unreference().
+   * @SINCE_1_0.0
+   */
+  virtual ~Ruler();
+
+protected:
+
+  RulerType mType;               ///< Type of Ruler (Fixed or Free).
+  bool mEnabled;                 ///< If the ruler is enabled.
+  RulerDomain mDomain;           ///< The domain of the ruler.
+
+};
+
+typedef IntrusivePtr<Ruler> RulerPtr; ///< Pointer to Dali::Toolkit::Ruler object @SINCE_1_0.0
+
+/**
+ * @brief Concrete implementation of Ruler that has no snapping and has one single page.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API DefaultRuler : public Ruler
+{
+public:
+  /**
+   * @brief DefaultRuler constructor.
+   * @SINCE_1_0.0
+   */
+  DefaultRuler();
+
+  /**
+   * @copydoc Toolkit::Ruler::Snap
+   */
+  virtual float Snap(float x, float bias) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetPositionFromPage
+   */
+  virtual float GetPositionFromPage(unsigned int page, unsigned int &volume, bool wrap) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetPageFromPosition
+   */
+  virtual unsigned int GetPageFromPosition(float position, bool wrap) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetTotalPages
+   */
+  virtual unsigned int GetTotalPages() const;
+};
+
+/**
+ * @brief Concrete implementation of Ruler that has fixed snapping.
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API FixedRuler : public Ruler
+{
+public:
+  /**
+   * @brief Constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] spacing The spacing between each interval on this ruler
+   */
+  FixedRuler(float spacing = 1.0f);
+
+  /**
+   * @copydoc Toolkit::Ruler::Snap
+   */
+  virtual float Snap(float x, float bias) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetPositionFromPage
+   */
+  virtual float GetPositionFromPage(unsigned int page, unsigned int &volume, bool wrap) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetPageFromPosition
+   */
+  virtual unsigned int GetPageFromPosition(float position, bool wrap) const;
+
+  /**
+   * @copydoc Toolkit::Ruler::GetTotalPages
+   */
+  virtual unsigned int GetTotalPages() const;
+
+private:
+  float mSpacing; ///< The spacing between each interval
+};
+
+class ScrollViewEffect;
+class ScrollView;
+
+/**
+ * @brief ScrollView contains actors that can be scrolled manually (via touch)
+ * or automatically.
+ *
+ * Signals
+ * | %Signal Name      | Method                     |
+ * |-------------------|----------------------------|
+ * | snap-started      | @ref SnapStartedSignal()   |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API ScrollView : public Scrollable
+{
+
+public:
+
+  /**
+   * @brief Clamps signal event's data.
+   * @SINCE_1_0.0
+   */
+  struct ClampEvent
+  {
+    ClampState2D scale;       ///< Clamp information for scale axes
+    ClampState2D position;    ///< Clamp information for position axes
+    ClampState   rotation;    ///< Clamp information for rotation
+  };
+
+  /**
+   * @brief Snaps signal event's data.
+   * @SINCE_1_0.0
+   */
+  struct SnapEvent
+  {
+    SnapType type;    ///< Current snap commencing
+    Vector2 position; ///< Target snap position
+    float duration;   ///< Duration of snap animation.
+  };
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Toolkit::Scrollable::PROPERTY_END_INDEX + 1,                        ///< @SINCE_1_1.18
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,                                        ///< Reserve property indices, @SINCE_1_1.18
+
+    ANIMATABLE_PROPERTY_START_INDEX = Toolkit::Scrollable::ANIMATABLE_PROPERTY_END_INDEX + 1,
+    ANIMATABLE_PROPERTY_END_INDEX   = ANIMATABLE_PROPERTY_START_INDEX + 1000                   ///< Reserve animatable property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the ScrollView class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the ScrollView class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      ///////////////////////////////////////////////////////////////////////////////
+      // Event side (non-animatable) properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @brief Whether wrapping is enabled.
+       * @details Name "wrapEnabled", type Property::BOOLEAN.
+       * @SINCE_1_1.18
+       * @see SetWrapMode()
+       */
+      WRAP_ENABLED = PROPERTY_START_INDEX,
+
+      /**
+       * @brief Whether panning is enabled.
+       * @details Name "panningEnabled", type Property::BOOLEAN.
+       * @SINCE_1_1.18
+       * @see SetScrollSensitive()
+       */
+      PANNING_ENABLED,
+
+      /**
+       * @brief Whether the Axis Auto Lock mode for panning within the ScrollView is enabled.
+       * @details Name "axisAutoLockEnabled", type Property::BOOLEAN.
+       * @SINCE_1_1.18
+       * @see SetAxisAutoLock()
+       */
+      AXIS_AUTO_LOCK_ENABLED,
+
+      /**
+       * @brief The step of scroll distance in actor coordinates for each wheel event received in free panning mode.
+       * @details Name "wheelScrollDistanceStep", type Property::VECTOR2.
+       * @SINCE_1_1.18
+       * @see SetWheelScrollDistanceStep()
+       */
+      WHEEL_SCROLL_DISTANCE_STEP,
+
+      /**
+       * @brief The scroll mode.
+       * @details Name "scrollMode", type Property::MAP.
+       * The scroll mode map is a frontend for the Ruler helper class, containing the following keys:
+       *
+       * | %Property Name       | Type     | Required | Description                                                                                                                           |
+       * |----------------------|----------|----------|---------------------------------------------------------------------------------------------------------------------------------------|
+       * | xAxisScrollEnabled   | BOOLEAN  | No       | True if the content can be scrolled in X axis or false if not.                                                                        |
+       * | xAxisSnapToInterval  | FLOAT    | No       | When set, causes scroll view to snap to multiples of the value of the interval in the X axis while flicking. (by default no snapping) |
+       * | xAxisScrollBoundary  | FLOAT    | No       | When set, causes scroll view unable to scroll beyond the value of the boundary in the X axis (by default no boundary)                 |
+       * | yAxisScrollEnabled   | BOOLEAN  | No       | True if the content can be scrolled in Y axis or false if not.                                                                        |
+       * | yAxisSnapToInterval  | FLOAT    | No       | When set, causes scroll view to snap to multiples of the value of the interval in the Y axis while flicking. (by default no snapping) |
+       * | yAxisScrollBoundary  | FLOAT    | No       | When set, causes scroll view unable to scroll beyond the value of the boundary in the Y axis (by default no boundary)                 |
+       *
+       * Alternatively, one can use the keys defined in the Dali::Toolkit::ScrollMode::Type enumeration.
+       * @SINCE_1_2.60
+       */
+      SCROLL_MODE,
+
+      ///////////////////////////////////////////////////////////////////////////////
+      // Animatable Properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @brief The current scroll position.
+       * @details Name "scrollPosition", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_POSITION = ANIMATABLE_PROPERTY_START_INDEX,
+
+      /**
+       * @brief The position before we set the clamp at scroll boundaries.
+       * @details Name "scrollPrePosition", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION,
+
+      /**
+       * @brief The X component of SCROLL_PRE_POSITION.
+       * @details Name "scrollPrePositionX", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION_X,
+
+      /**
+       * @brief The Y component of SCROLL_PRE_POSITION.
+       * @details Name "scrollPrePositionY", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION_Y,
+
+      /**
+       * @brief The maximum value that SCROLL_PRE_POSITION can be.
+       * @details Name "scrollPrePositionMax", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION_MAX,
+
+      /**
+       * @brief The X component of SCROLL_PRE_POSITION_MAX.
+       * @details Name "scrollPrePositionMaxX", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION_MAX_X,
+
+      /**
+       * @brief The Y component of SCROLL_PRE_POSITION_MAX.
+       * @details Name "scrollPrePositionMaxY", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_PRE_POSITION_MAX_Y,
+
+      /**
+       * @brief The amount that we can scroll beyond the boundary along the X axis.
+       * @details Name "overshootX", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      OVERSHOOT_X,
+
+      /**
+       * @brief The amount that we can scroll beyond the boundary along the Y axis.
+       * @details Name "overshootY", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      OVERSHOOT_Y,
+
+      /**
+       * @brief The position after the overshoot value has been considered in the calculation.
+       * @details Name "scrollFinal", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_FINAL,
+
+      /**
+       * @brief The X component of SCROLL_FINAL.
+       * @details Name "scrollFinalX", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_FINAL_X,
+
+      /**
+       * @brief The Y component of SCROLL_FINAL.
+       * @details Name "scrollFinalY", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_FINAL_Y,
+
+      /**
+       * @brief Whether scrolling wraps.
+       * @details Name "wrap", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       */
+      WRAP,
+
+      /**
+       * @brief Whether we are currently panning.
+       * @details Name "panning", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       */
+      PANNING,
+
+      /**
+       * @brief Whether we are currently scrolling.
+       * @details Name "scrolling", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       */
+      SCROLLING,
+
+      /**
+       * @brief The size of the scrolling domain.
+       * @details Name "scrollDomainSize", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_DOMAIN_SIZE,
+
+      /**
+       * @brief The X component of SCROLL_DOMAIN_SIZE.
+       * @details Name "scrollDomainSizeX", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_DOMAIN_SIZE_X,
+
+      /**
+       * @brief The Y component of SCROLL_DOMAIN_SIZE.
+       * @details Name "scrollDomainSizeY", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_DOMAIN_SIZE_Y,
+
+      /**
+       * @brief The offset of the scroll domain.
+       * @details Name "scrollDomainOffset", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_DOMAIN_OFFSET,
+
+      /**
+       * @brief The delta in the position when scrolling.
+       * @details Name "scrollPositionDelta", type Property::VECTOR2.
+       * @SINCE_1_0.0
+       */
+      SCROLL_POSITION_DELTA,
+
+      /**
+       * @brief The starting page position.
+       * @details Name "startPagePosition", type Property::VECTOR3.
+       * @SINCE_1_0.0
+       */
+      START_PAGE_POSITION,
+    };
+  };
+
+  // Typedefs
+
+  typedef Signal< void ( const SnapEvent& ) > SnapStartedSignalType; ///< SnapStarted signal type @SINCE_1_0.0
+
+public:
+
+  /**
+   * @brief Creates an empty ScrollView handle.
+   * @SINCE_1_0.0
+   */
+  ScrollView();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to copy from
+   */
+  ScrollView( const ScrollView& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   * @param[in] handle The handle to copy from
+   * @return A reference to this
+   */
+  ScrollView& operator=( const ScrollView& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~ScrollView();
+
+  /**
+   * @brief Creates an initialized ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to a newly allocated Dali resource
+   */
+  static ScrollView New();
+
+  /**
+   * @brief Downcasts a handle to ScrollView handle.
+   *
+   * If handle points to a ScrollView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a ScrollView or an uninitialized handle
+   */
+  static ScrollView DownCast( BaseHandle handle );
+
+public:
+
+  /**
+   * @brief Gets snap-animation's AlphaFunction.
+   *
+   * @SINCE_1_0.0
+   * @return Current easing alpha function of the snap animation
+   */
+  AlphaFunction GetScrollSnapAlphaFunction() const;
+
+  /**
+   * @brief Sets snap-animation's AlphaFunction.
+   *
+   * @SINCE_1_0.0
+   * @param[in] alpha Easing alpha function of the snap animation
+   */
+  void SetScrollSnapAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @brief Gets flick-animation's AlphaFunction.
+   *
+   * @SINCE_1_0.0
+   * @return Current easing alpha function of the flick animation
+   */
+  AlphaFunction GetScrollFlickAlphaFunction() const;
+
+  /**
+   * @brief Sets flick-animation's AlphaFunction.
+   *
+   * @SINCE_1_0.0
+   * @param[in] alpha Easing alpha function of the flick animation
+   */
+  void SetScrollFlickAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @brief Gets the time for the scroll snap-animation.
+   *
+   * This animation occurs when the user drags, and releases.
+   *
+   * @SINCE_1_0.0
+   * @return The time in seconds for the animation to take
+   */
+  float GetScrollSnapDuration() const;
+
+  /**
+   * @brief Sets the time for the scroll snap-animation.
+   *
+   * This animation occurs when the user drags, and releases.
+   *
+   * @SINCE_1_0.0
+   * @param[in] time The time in seconds for the animation to take
+   */
+  void SetScrollSnapDuration(float time);
+
+  /**
+   * @brief Gets the time for the scroll flick-animation.
+   *
+   * This animation occurs when the user flicks scroll view.
+   *
+   * @SINCE_1_0.0
+   * @return The time in seconds for the animation to take
+   */
+  float GetScrollFlickDuration() const;
+
+  /**
+   * @brief Sets the time for the scroll flick-animation.
+   *
+   * This animation occurs when the user flicks scroll view.
+   *
+   * @SINCE_1_0.0
+   * @param[in] time The time in seconds for the animation to take
+   */
+  void SetScrollFlickDuration(float time);
+
+  /**
+   * @brief Sets X axis ruler.
+   *
+   * Defines how scrolling horizontally is snapped, and
+   * the boundary (domain) in which the ScrollView can pan.
+   *
+   * @SINCE_1_0.0
+   * @param[in] ruler The ruler to be used for the X axis
+   */
+  void SetRulerX(RulerPtr ruler);
+
+  /**
+   * @brief Sets Y axis ruler.
+   *
+   * Defines how scrolling vertically is snapped, and the boundary
+   * (domain) in which the ScrollView can pan.
+   *
+   * @SINCE_1_0.0
+   * @param[in] ruler The ruler to be used for the Y axis
+   */
+  void SetRulerY(RulerPtr ruler);
+
+  /**
+   * @brief Sets scroll sensitivity of pan gesture.
+   *
+   * @SINCE_1_0.0
+   * @param[in] sensitive @c true to enable scroll, @c false to disable scrolling
+   * @note Unlike Actor::SetSensitive(), this determines whether this ScrollView
+   * should react (e.g. pan), without disrupting the sensitivity of its children.
+   *
+   */
+  void SetScrollSensitive(bool sensitive);
+
+  /**
+   * @brief Sets maximum overshoot amount.
+   *
+   * The final overshoot value is within 0.0f to 1.0f, but the maximum
+   * overshoot is in pixels (e.g. if you scroll 75 pixels beyond the
+   * edge of a scrollable area and the maximum overshoot is 100 then
+   * the final overshoot value will be 0.75f).
+   *
+   * @SINCE_1_0.0
+   * @param[in] overshootX The maximum number of horizontally scrolled pixels before overshoot X reaches 1.0f
+   * @param[in] overshootY The maximum number of vertically scrolled pixels before overshoot Y reaches 1.0f
+   */
+  void SetMaxOvershoot(float overshootX, float overshootY);
+
+  /**
+   * @brief Sets Snap Overshoot animation's AlphaFunction.
+   *
+   * @SINCE_1_0.0
+   * @param[in] alpha Easing alpha function of the overshoot snap animation
+   */
+  void SetSnapOvershootAlphaFunction(AlphaFunction alpha);
+
+  /**
+   * @brief Sets Snap Overshoot animation's Duration.
+   *
+   * @SINCE_1_0.0
+   * @param[in] duration The duration of the overshoot snap animation
+   * @note Set duration to 0 seconds to disable Animation.
+   *
+   */
+  void SetSnapOvershootDuration(float duration);
+
+  /**
+   * @brief Enables or Disables Actor Auto-Snap mode.
+   *
+   * When Actor Auto-Snap mode has been enabled, ScrollView will automatically
+   * snap to the closest actor (The closest actor will appear in the center of
+   * the ScrollView).
+   *
+   * @SINCE_1_0.0
+   * @param[in] enable Enables (true), or disables (false) Actor AutoSnap
+   */
+  void SetActorAutoSnap(bool enable);
+
+  /**
+   * @brief Enables or Disables Wrap mode for ScrollView contents.
+   *
+   * When enabled, the ScrollView contents are wrapped over the X/Y Domain.
+   *
+   * @SINCE_1_0.0
+   * @param[in] enable Enables (true), or disables (false) Wrap Mode
+   * @note You must apply a position constraint that causes Wrapping
+   * to all children.
+   *
+   */
+  void SetWrapMode(bool enable);
+
+  /**
+   * @brief Gets the current distance needed to scroll for ScrollUpdatedSignal to be emitted.
+   *
+   * @SINCE_1_0.0
+   * @return Current scroll update distance
+   */
+  int GetScrollUpdateDistance() const;
+
+  /**
+   * @brief Sets the distance needed to scroll for ScrollUpdatedSignal to be emitted.
+   *
+   * The scroll update distance tells ScrollView how far to move before ScrollUpdatedSignal the informs application.
+   * Each time the ScrollView crosses this distance the signal will be emitted.
+   *
+   * @SINCE_1_0.0
+   * @param[in] distance The distance for ScrollView to move before emitting update signal
+   */
+  void SetScrollUpdateDistance(int distance);
+
+  /**
+   * @brief Returns state of Axis Auto Lock mode.
+   *
+   * @SINCE_1_0.0
+   * @return Whether Axis Auto Lock mode has been enabled or not
+   */
+  bool GetAxisAutoLock() const;
+
+  /**
+   * @brief Enables or Disables Axis Auto Lock mode for panning within the ScrollView.
+   *
+   * When enabled, any pan gesture that appears mostly horizontal or mostly
+   * vertical, will be automatically restricted to horizontal only or vertical
+   * only panning, until the pan gesture has completed.
+   *
+   * @SINCE_1_0.0
+   * @param[in] enable Enables (true), or disables (false) AxisAutoLock mode
+   */
+  void SetAxisAutoLock(bool enable);
+
+  /**
+   * @brief Gets the gradient threshold at which a panning gesture
+   * should be locked to the Horizontal or Vertical axis.
+   *
+   * @SINCE_1_0.0
+   * @return The gradient, a value between 0.0 and 1.0f
+   */
+  float GetAxisAutoLockGradient() const;
+
+  /**
+   * @brief Sets the gradient threshold at which a panning gesture should be locked to the
+   * Horizontal or Vertical axis.
+   *
+   * By default, this is 0.36 (0.36:1) which means angles less than 20
+   * degrees to an axis will lock to that axis.
+   *
+   * @SINCE_1_0.0
+   * @param[in] gradient A value between 0.0 and 1.0 (auto-lock for all angles)
+   * @note Specifying a value of 1.0 (the maximum value accepted) indicates that
+   * all panning gestures will auto-lock either to the horizontal or vertical axis.
+   *
+   */
+  void SetAxisAutoLockGradient(float gradient);
+
+  /**
+   * @brief Gets the friction coefficient setting for ScrollView when
+   * flicking in free panning mode.
+   *
+   * This is a value in stage-diagonals per second^2.
+   * stage-diagonal = Length( stage.width, stage.height )
+   * @SINCE_1_0.0
+   * @return Friction coefficient is returned
+   */
+  float GetFrictionCoefficient() const;
+
+  /**
+   * @brief Sets the friction coefficient for ScrollView when flicking
+   * in free panning mode.
+   *
+   * This is a value in stage-diagonals per second^2.
+   * stage-diagonal = Length( stage.width, stage.height ).
+   * example:
+   * A stage 480x800 in size has a diagonal length of 933.
+   * Friction coefficient of 1.0 means the swipe velocity will
+   * reduce by 1.0 * 933 pixels/sec^2.
+   * @SINCE_1_0.0
+   * @param[in] friction Friction coefficient must be greater than 0.0 (default = 1.0)
+   */
+  void SetFrictionCoefficient(float friction);
+
+  /**
+   * @brief Gets the flick speed coefficient for ScrollView when
+   * flicking in free panning mode.
+   *
+   * This is a constant which multiplies the input touch
+   * flick velocity to determine the actual velocity at
+   * which to move the scrolling area.
+   * @SINCE_1_0.0
+   * @return The flick speed coefficient is returned
+   */
+  float GetFlickSpeedCoefficient() const;
+
+  /**
+   * @brief Sets the flick speed coefficient for ScrollView when
+   * flicking in free panning mode.
+   *
+   * This is a constant which multiplies the input touch
+   * flick velocity to determine the actual velocity at
+   * which to move the scrolling area.
+   * @SINCE_1_0.0
+   * @param[in] speed The flick speed coefficient (default = 1.0)
+   */
+  void SetFlickSpeedCoefficient(float speed);
+
+  /**
+   * @brief Returns the minimum pan distance required for a flick gesture in pixels.
+   *
+   * @SINCE_1_0.0
+   * @return Minimum pan distance vector with separate x and y distance
+   */
+  Vector2 GetMinimumDistanceForFlick() const;
+
+  /**
+   * @brief Sets the minimum pan distance required for a flick in pixels.
+   *
+   * Takes a Vector2 containing separate x and y values. As long as the pan distance exceeds one of these axes, a flick will be allowed.
+   *
+   * @SINCE_1_0.0
+   * @param[in] distance The minimum pan distance for a flick
+   */
+  void SetMinimumDistanceForFlick( const Vector2& distance );
+
+  /**
+   * @brief Returns the minimum pan speed required for a flick gesture in pixels per second.
+   *
+   * @SINCE_1_0.0
+   * @return Minimum pan speed
+   */
+  float GetMinimumSpeedForFlick() const;
+
+  /**
+   * @brief Sets the minimum pan speed required for a flick in pixels per second.
+   *
+   * @SINCE_1_0.0
+   * @param[in] speed The minimum pan speed for a flick
+   */
+  void SetMinimumSpeedForFlick( float speed );
+
+  /**
+   * @brief Gets the maximum flick speed setting for ScrollView when
+   * flicking in free panning mode.
+   *
+   * This is a value in stage-diagonals per second.
+   * stage-diagonal = Length( stage.width, stage.height )
+   * @SINCE_1_0.0
+   * @return Maximum flick speed is returned
+   */
+  float GetMaxFlickSpeed() const;
+
+  /**
+   * @brief Sets the maximum flick speed for the ScrollView when
+   * flicking in free panning mode.
+   *
+   * This is a value in stage-diagonals per second.
+   * stage-diagonal = Length( stage.width, stage.height )
+   * example:
+   * A stage 480x800 in size has a diagonal length of 933.
+   * Max Flick speed of 1.0 means the maximum velocity of
+   * a swipe can be 1.0 * 933 pixels/sec.
+   * @SINCE_1_0.0
+   * @param[in] speed Maximum flick speed (default = 3.0)
+   */
+  void SetMaxFlickSpeed(float speed);
+
+  /**
+   * @brief Gets the step of scroll distance in actor coordinates for
+   * each wheel event received in free panning mode.
+   *
+   * @SINCE_1_0.0
+   * @return The step of scroll distance(pixel) in X and Y axes
+   */
+  Vector2 GetWheelScrollDistanceStep() const;
+
+  /**
+   * @brief Sets the step of scroll distance in actor coordinates for
+   * each wheel event received in free panning mode.
+   *
+   * @SINCE_1_0.0
+   * @param[in] step The step of scroll distance(pixel) in X and Y axes
+   *
+   * @note If snap points are defined in the rulers, it will always
+   * scroll to the next snap point towards the scroll direction while
+   * receiving the wheel events.
+   *
+   */
+  void SetWheelScrollDistanceStep(Vector2 step);
+
+  /**
+   * @brief Retrieves current scroll position.
+   *
+   * @SINCE_1_0.0
+   * @return The current scroll position
+   */
+  Vector2 GetCurrentScrollPosition() const;
+
+  /**
+   * @brief Retrieves current scroll page based on ScrollView
+   * dimensions being the size of one page, and all pages laid out in
+   * a grid fashion, increasing from left to right until the end of
+   * the X-domain.
+   *
+   * @SINCE_1_0.0
+   * @note Pages start from 0 as the first page, not 1.
+   *
+   * @return The Current page
+   */
+  unsigned int GetCurrentPage() const;
+
+  /**
+   * @brief Scrolls View to position specified (contents will scroll to this position).
+   *
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * - If Rulers have been applied to the axes, then the contents will scroll until
+   * reaching the domain boundary.
+   * @SINCE_1_0.0
+   * @param[in] position The position to scroll to
+   * @note Contents will not snap to ruler snap points.
+   *
+   */
+  void ScrollTo(const Vector2& position);
+
+  /**
+   * @brief Scrolls View to position specified (contents will scroll to this position).
+   *
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * - If Rulers have been applied to the axes, then the contents will scroll until
+   * reaching the domain boundary.
+   * @SINCE_1_0.0
+   * @param[in] position The position to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @note Contents will not snap to ruler snap points.
+   *
+   */
+  void ScrollTo(const Vector2& position, float duration);
+
+  /**
+   * @brief Scrolls View to position specified (contents will scroll to this position).
+   *
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * - If Rulers have been applied to the axes, then the contents will scroll until
+   * reaching the domain boundary.
+   * @SINCE_1_0.0
+   * @param[in] position The position to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @param[in] alpha The alpha function to use
+   * @note Contents will not snap to ruler snap points.
+   *
+   */
+  void ScrollTo(const Vector2& position, float duration, AlphaFunction alpha);
+
+  /**
+   * @brief Scrolls View to position specified (contents will scroll to this position).
+   *
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * - If Rulers have been applied to the axes, then the contents will scroll until
+   * reaching the domain boundary.
+   * @SINCE_1_0.0
+   * @param[in] position The position to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @param[in] horizontalBias Whether to bias scrolling to left or right
+   * @param[in] verticalBias Whether to bias scrolling to top or bottom
+   * @note Contents will not snap to ruler snap points.
+   * Biasing parameters are provided such that in scenarios with 2 or 2x2 pages in
+   * wrap mode, the application developer can decide whether to scroll left or right
+   * to get to the target page.
+   *
+   */
+  void ScrollTo(const Vector2& position, float duration,
+                DirectionBias horizontalBias, DirectionBias verticalBias);
+
+  /**
+   * @brief Scrolls View to position specified (contents will scroll to this position).
+   *
+   * Position 0,0 is the origin. Increasing X scrolls contents left, while
+   * increasing Y scrolls contents up.
+   * - If Rulers have been applied to the axes, then the contents will scroll until
+   * reaching the domain boundary.
+   * @SINCE_1_0.0
+   * @param[in] position The position to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @param[in] horizontalBias Whether to bias scrolling to left or right
+   * @param[in] verticalBias Whether to bias scrolling to top or bottom
+   * @param[in] alpha Alpha function to use
+   * @note Contents will not snap to ruler snap points.
+   * Biasing parameters are provided such that in scenarios with 2 or 2x2 pages in
+   * wrap mode, the application developer can decide whether to scroll left or right
+   * to get to the target page.
+   *
+   */
+  void ScrollTo(const Vector2& position, float duration, AlphaFunction alpha,
+                DirectionBias horizontalBias, DirectionBias verticalBias);
+
+  /**
+   * @brief Scrolls View to page currently based on assumption that each page is
+   * "(page) * ScrollViewSize.width, 0".
+   *
+   * @SINCE_1_0.0
+   * @param[in] page The page to scroll to
+   * @note Should probably be upgraded so that page is an abstract class, that can be
+   * a function of ScrollViewSize, ruler domain, ruler snap points etc. as pages may be
+   * orchestrated in a 2D grid fashion, or variable width.
+   *
+   */
+  void ScrollTo(unsigned int page);
+
+  /**
+   * @brief Scrolls View to page currently based on assumption that each page is
+   * "(page) * ScrollViewSize.width, 0".
+   *
+   * @SINCE_1_0.0
+   * @param[in] page The page to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @note Should probably be upgraded so that page is an abstract class, that can be
+   * a function of ScrollViewSize, ruler domain, ruler snap points etc. as pages may be
+   * orchestrated in a 2D grid fashion, or variable width.
+   *
+   */
+  void ScrollTo(unsigned int page, float duration);
+
+  /**
+   * @brief Scrolls View to page currently based on assumption that each page is
+   * "(page) * ScrollViewSize.width, 0".
+   *
+   * @SINCE_1_0.0
+   * @param[in] page The page to scroll to
+   * @param[in] duration The duration of the animation in seconds
+   * @param[in] bias Whether to bias scrolling to left or right
+   * @note Should probably be upgraded so that page is an abstract class, that can be
+   * a function of ScrollViewSize, ruler domain, ruler snap points etc. as pages may be
+   * orchestrated in a 2D grid fashion, or variable width.
+   * A biasing parameter is provided such that in scenarios with 2 pages in wrap mode,
+   * the application developer can decide whether to scroll left or right to get to
+   * the target page.
+   *
+   */
+  void ScrollTo(unsigned int page, float duration, DirectionBias bias);
+
+  /**
+   * @brief Scrolls View such that actor appears in the center of the ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] actor The actor to center in on (via Scrolling)
+   * @note Actor must be a direct child of ScrollView, otherwise will
+   * cause an assertion failure.
+   */
+  void ScrollTo(Actor& actor);
+
+  /**
+   * @brief Scrolls View such that actor appears in the center of the ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] actor The actor to center in on (via Scrolling)
+   * @param[in] duration The duration of the animation in seconds
+   * @note Actor must be a direct child of ScrollView, otherwise will
+   * cause an assertion failure.
+   */
+  void ScrollTo(Actor& actor, float duration);
+
+  /**
+   * @brief Scrolls View to the nearest snap points as specified by the Rulers.
+   *
+   * If already at snap points, then will return false, and not scroll.
+   *
+   * @SINCE_1_0.0
+   * @return True if Snapping necessary
+   */
+  bool ScrollToSnapPoint();
+
+  /**
+   * @brief Applies a constraint that will affect the children of ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] constraint The constraint to apply
+   * @note This affects all existing and future Actors that are added to scrollview.
+   */
+  void ApplyConstraintToChildren(Constraint constraint);
+
+  /**
+   * @brief Removes all constraints that will affect the children of ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @note This removes all constraints from actors that have been added
+   * to scrollview.
+   */
+  void RemoveConstraintsFromChildren();
+
+  /**
+   * @brief Applies Effect to ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] effect The effect to apply to scroll view
+   */
+  void ApplyEffect(ScrollViewEffect effect);
+
+  /**
+   * @brief Removes Effect from ScrollView.
+   *
+   * @SINCE_1_0.0
+   * @param[in] effect The effect to remove
+   */
+  void RemoveEffect(ScrollViewEffect effect);
+
+  /**
+   * @brief Remove All Effects from ScrollView.
+   * @SINCE_1_0.0
+   */
+  void RemoveAllEffects();
+
+  /**
+   * @brief Binds actor to this ScrollView.
+   *
+   * Once an actor is bound to a ScrollView, it will be subject to
+   * that ScrollView's properties.
+   *
+   * @SINCE_1_0.0
+   * @param[in] child The actor to add to this ScrollView
+   */
+  void BindActor(Actor child);
+
+  /**
+   * @brief Unbinds Actor from this ScrollView.
+   *
+   * Once Unbound, this ScrollView will not affect the actor.
+   * @SINCE_1_0.0
+   * @param[in] child The actor to be unbound
+   * @note This does not remove the child from the ScrollView container
+   *
+   */
+  void UnbindActor(Actor child);
+
+  /**
+   * @brief Allows the user to constrain the scroll view in a particular direction.
+   *
+   * @SINCE_1_0.0
+   * @param[in] direction The axis to constrain the scroll-view to.
+   *                      Usually set to PanGestureDetector::DIRECTION_VERTICAL or PanGestureDetector::DIRECTION_HORIZONTAL (but can be any other angle if desired).
+   * @param[in] threshold The threshold to apply around the axis
+   * @note If no threshold is specified, then the default threshold of PI * 0.25 radians (or 45 degrees) is used.
+   */
+  void SetScrollingDirection( Radian direction, Radian threshold = PanGestureDetector::DEFAULT_THRESHOLD );
+
+  /**
+   * @brief Removes a direction constraint from the scroll view.
+   *
+   * @SINCE_1_0.0
+   * @param[in] direction The axis to stop constraining to.
+   *                      Usually will be PanGestureDetector::DIRECTION_VERTICAL or PanGestureDetector::DIRECTION_HORIZONTAL (but can be any other angle if desired).
+   */
+  void RemoveScrollingDirection( Radian direction );
+
+public: // Signals
+
+  /**
+   * @brief Signal emitted when the ScrollView has started to snap or flick (it tells the target
+   * position, scale, rotation for the snap or flick).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const SnapEvent& event);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  SnapStartedSignalType& SnapStartedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL ScrollView(Internal::ScrollView& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL ScrollView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLL_VIEW_H
diff --git a/dali-toolkit/public-api/controls/scrollable/scrollable.cpp b/dali-toolkit/public-api/controls/scrollable/scrollable.cpp
new file mode 100644 (file)
index 0000000..9e1c66f
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/scrollable/scrollable.h>
+#include <dali-toolkit/internal/controls/scrollable/scrollable-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Scrollable::Scrollable()
+{
+}
+
+Scrollable::Scrollable(Internal::Scrollable& implementation)
+: Control(implementation)
+{
+}
+
+Scrollable::Scrollable( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Scrollable>(internal);
+}
+
+Scrollable::Scrollable( const Scrollable& handle )
+: Control( handle )
+{
+}
+
+Scrollable& Scrollable::operator=( const Scrollable& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+Scrollable::~Scrollable()
+{
+}
+
+Scrollable Scrollable::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Scrollable, Internal::Scrollable>(handle);
+}
+
+Scrollable::ScrollStartedSignalType& Scrollable::ScrollStartedSignal()
+{
+  return GetImpl(*this).ScrollStartedSignal();
+}
+
+Scrollable::ScrollUpdatedSignalType& Scrollable::ScrollUpdatedSignal()
+{
+  return GetImpl(*this).ScrollUpdatedSignal();
+}
+
+Scrollable::ScrollCompletedSignalType& Scrollable::ScrollCompletedSignal()
+{
+  return GetImpl(*this).ScrollCompletedSignal();
+}
+
+bool Scrollable::IsOvershootEnabled() const
+{
+  return GetImpl(*this).IsOvershootEnabled();
+}
+
+void Scrollable::SetOvershootEnabled(bool enable)
+{
+  GetImpl(*this).SetOvershootEnabled(enable);
+}
+
+void Scrollable::SetOvershootEffectColor( const Vector4& color )
+{
+  GetImpl(*this).SetOvershootEffectColor(color);
+}
+
+Vector4 Scrollable::GetOvershootEffectColor() const
+{
+  return GetImpl(*this).GetOvershootEffectColor();
+}
+
+void Scrollable::SetOvershootAnimationSpeed( float pixelsPerSecond )
+{
+  GetImpl(*this).SetOvershootAnimationSpeed(pixelsPerSecond);
+}
+
+float Scrollable::GetOvershootAnimationSpeed() const
+{
+  return GetImpl(*this).GetOvershootAnimationSpeed();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/scrollable/scrollable.h b/dali-toolkit/public-api/controls/scrollable/scrollable.h
new file mode 100644 (file)
index 0000000..38050ae
--- /dev/null
@@ -0,0 +1,272 @@
+#ifndef DALI_TOOLKIT_SCROLLABLE_H
+#define DALI_TOOLKIT_SCROLLABLE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Scrollable;
+}
+/**
+ * @addtogroup dali_toolkit_controls_scrollable
+ * @{
+ */
+
+/**
+ * @brief Base class for derived Scrollables that contains actors that can be scrolled manually
+ * (via touch) or automatically.
+ *
+ * Scrollables such as ScrollView and ItemView can be derived from this class.
+ *
+ * Signals
+ * | %Signal Name     | Method                       |
+ * |------------------|------------------------------|
+ * | scrollStarted    | @ref ScrollStartedSignal()   |
+ * | scrollCompleted  | @ref ScrollCompletedSignal() |
+ * | scrollUpdated    | @ref ScrollUpdatedSignal()   |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API Scrollable : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,             ///< Reserve property indices @SINCE_1_0.0
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000              ///< Reserve animatable property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the Scrollable class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the Scrollable class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      // Event side properties
+      OVERSHOOT_EFFECT_COLOR = PROPERTY_START_INDEX, ///< Property, name "overshootEffectColor",      @see SetOvershootEffectColor(),    type Vector4 @SINCE_1_0.0
+      OVERSHOOT_ANIMATION_SPEED,                     ///< Property, name "overshootAnimationSpeed",   @see SetOvershootAnimationSpeed(), type float @SINCE_1_0.0
+      OVERSHOOT_ENABLED,                             ///< Property, name "overshootEnabled",          @see SetOvershootEnabled(),        type bool,    @SINCE_1_1.18
+      OVERSHOOT_SIZE,                                ///< Property, name "overshootSize",                                                type Vector2, @SINCE_1_1.31
+      SCROLL_TO_ALPHA_FUNCTION,                      ///< Property, name "scrollToAlphaFunction",                                        type int,     @SINCE_1_1.33
+
+      // Animatable properties
+      SCROLL_RELATIVE_POSITION = ANIMATABLE_PROPERTY_START_INDEX, ///< Property, name "scrollRelativePosition",   type Vector2 @SINCE_1_0.0
+      SCROLL_POSITION_MIN,                                        ///< Property, name "scrollPositionMin",        type Vector2 @SINCE_1_0.0
+      SCROLL_POSITION_MIN_X,                                      ///< Property, name "scrollPositionMinX",       type float @SINCE_1_0.0
+      SCROLL_POSITION_MIN_Y,                                      ///< Property, name "scrollPositionMinY",       type float @SINCE_1_0.0
+      SCROLL_POSITION_MAX,                                        ///< Property, name "scrollPositionMax",        type Vector2 @SINCE_1_0.0
+      SCROLL_POSITION_MAX_X,                                      ///< Property, name "scrollPositionMaxX",       type float @SINCE_1_0.0
+      SCROLL_POSITION_MAX_Y,                                      ///< Property, name "scrollPositionMaxY",       type float @SINCE_1_0.0
+      CAN_SCROLL_VERTICAL,                                        ///< Property, name "canScrollVertical",        type bool @SINCE_1_0.0
+      CAN_SCROLL_HORIZONTAL                                       ///< Property, name "canScrollHorizontal",      type bool @SINCE_1_0.0
+    };
+  };
+
+  // Typedefs
+
+  typedef Signal< void ( const Vector2& ) > ScrollStartedSignalType;   ///< ScrollStarted signal type @SINCE_1_0.0
+  typedef Signal< void ( const Vector2& ) > ScrollCompletedSignalType; ///< ScrollCompleted signal type @SINCE_1_0.0
+  typedef Signal< void ( const Vector2& ) > ScrollUpdatedSignalType;   ///< Scroll updated signal type @SINCE_1_0.0
+
+public:
+
+  /**
+   * @brief Creates an uninitialized Scrollable handle.
+   * @SINCE_1_0.0
+   */
+  Scrollable();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   *
+   * @SINCE_1_0.0
+   * @param handle to copy from
+   */
+  Scrollable( const Scrollable& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to copy from
+   * @return A reference to this
+   */
+  Scrollable& operator=( const Scrollable& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Scrollable();
+
+  /**
+   * @brief Downcasts a handle to Scrollable handle.
+   *
+   * If handle points to a Scrollable, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A handle to a Scrollable or an uninitialized handle
+   */
+  static Scrollable DownCast( BaseHandle handle );
+
+  /**
+   * @brief Checks if scroll overshoot has been enabled or not.
+   *
+   * @SINCE_1_0.0
+   * @return Whether the scroll overshoot is enabled
+   */
+  bool IsOvershootEnabled() const;
+
+  /**
+   * @brief Sets whether to enables or disable scroll overshoot.
+   *
+   * @SINCE_1_0.0
+   * @param[in] enable Whether to enable the scroll overshoot or not
+   */
+  void SetOvershootEnabled(bool enable);
+
+  /**
+   * @brief Sets the color of the overshoot effect.
+   *
+   * @SINCE_1_0.0
+   * @param[in] color The color of the overshoot effect
+   */
+  void SetOvershootEffectColor( const Vector4& color );
+
+  /**
+   * @brief Gets the color of the overshoot effect.
+   * @SINCE_1_0.0
+   * @return The color of the overshoot effect
+   */
+  Vector4 GetOvershootEffectColor() const;
+
+  /**
+   * @brief Sets the speed of overshoot animation in pixels per second.
+   *
+   * When the speed is not greater than 0, the overshoot is set instantly with no animation.
+   * @SINCE_1_0.0
+   * @param[in] pixelsPerSecond The speed of the overshoot animation
+   */
+  void SetOvershootAnimationSpeed( float pixelsPerSecond );
+
+  /**
+   * @brief Gets the speed of overshoot animation in pixels per second.
+   * @SINCE_1_0.0
+   * @return The speed of the overshoot animation
+   */
+  float GetOvershootAnimationSpeed() const;
+
+public: // Signals
+
+  /**
+   * @brief Signal emitted when the Scrollable has moved (whether by touch or animation).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const Vector2& currentScrollPosition);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  ScrollStartedSignalType& ScrollStartedSignal();
+
+  /**
+   * @brief Signal emitted when the Scrollable has moved (whether by touch or animation).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const Vector2& currentScrollPosition);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  ScrollUpdatedSignalType& ScrollUpdatedSignal();
+
+  /**
+   * @brief Signal emitted when the Scrollable has completed movement (whether by touch or animation).
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const Vector2& currentScrollPosition);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  ScrollCompletedSignalType& ScrollCompletedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL Scrollable(Internal::Scrollable& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL Scrollable( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SCROLLABLE_H
diff --git a/dali-toolkit/public-api/controls/slider/slider.cpp b/dali-toolkit/public-api/controls/slider/slider.cpp
new file mode 100644 (file)
index 0000000..8aa47d0
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/controls/slider/slider.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/slider/slider-impl.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+Slider::Slider()
+{
+}
+
+Slider::Slider( const Slider& handle )
+: Control( handle )
+{
+}
+
+Slider& Slider::operator=( const Slider& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+Slider::Slider(Internal::Slider& implementation)
+: Control(implementation)
+{
+}
+
+Slider::Slider( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::Slider>(internal);
+}
+
+Slider Slider::New()
+{
+  return Internal::Slider::New();
+}
+
+Slider::~Slider()
+{
+}
+
+Slider::ValueChangedSignalType& Slider::ValueChangedSignal()
+{
+  return GetImpl( *this ).ValueChangedSignal();
+}
+
+Slider::ValueChangedSignalType& Slider::SlidingFinishedSignal()
+{
+  return GetImpl( *this ).SlidingFinishedSignal();
+}
+
+Slider::MarkReachedSignalType& Slider::MarkReachedSignal()
+{
+  return GetImpl( *this ).MarkReachedSignal();
+}
+
+Slider Slider::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<Slider, Internal::Slider>(handle);
+}
+
+
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/slider/slider.h b/dali-toolkit/public-api/controls/slider/slider.h
new file mode 100644 (file)
index 0000000..603e110
--- /dev/null
@@ -0,0 +1,302 @@
+#ifndef DALI_TOOLKIT_SLIDER_H
+#define DALI_TOOLKIT_SLIDER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class Slider;
+}
+/**
+ * @addtogroup dali_toolkit_controls_slider
+ * @{
+ */
+
+/**
+ * @brief Slider is a control to enable sliding an indicator between two values.
+ *
+ * Signals
+ * | %Signal Name      | Method                        |
+ * |-------------------|-------------------------------|
+ * | valueChanged      | @ref ValueChangedSignal()     |
+ * | markReached       | @ref MarkReachedSignal()      |
+ * | slidingFinished   | @ref SlidingFinishedSignal()  |
+ * @SINCE_1_1.39
+ */
+class DALI_TOOLKIT_API Slider : public Control
+{
+public:
+
+  // Properties
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_1.39
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_1.39
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices @SINCE_1_1.39
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the Slider class.
+   * @SINCE_1_1.39
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the Slider class.
+     * @SINCE_1_1.39
+     */
+    enum
+    {
+
+      /**
+       * @brief name "lowerBound", type float.
+       * @SINCE_1_1.39
+       */
+      LOWER_BOUND = PROPERTY_START_INDEX,
+
+      /**
+       * @brief name "upperBound", type float.
+       * @SINCE_1_1.39
+       */
+      UPPER_BOUND,
+
+      /**
+       * @brief name "value", type float.
+       * @SINCE_1_1.39
+       */
+      VALUE,
+
+      /**
+       * @brief name "trackVisual", type string if it is a url, map otherwise.
+       * @SINCE_1_1.39
+       */
+      TRACK_VISUAL,
+
+      /**
+       * @brief name "handleVisual", type string if it is a url, map otherwise.
+       * @SINCE_1_1.39
+       */
+      HANDLE_VISUAL,
+
+      /**
+       * @brief name "progressVisual", type string if it is a url, map otherwise.
+       * @SINCE_1_1.39
+       */
+      PROGRESS_VISUAL,
+
+      /**
+       * @brief name "popupVisual", type string if it is a url, map otherwise.
+       * @SINCE_1_1.39
+       */
+      POPUP_VISUAL,
+
+      /**
+       * @brief name "popupArrowVisual", type string if it is a url, map otherwise.
+       * @SINCE_1_1.39
+       */
+      POPUP_ARROW_VISUAL,
+
+      /**
+       * @brief name "disabledColor", type Vector4.
+       * @SINCE_1_1.39
+       */
+      DISABLED_COLOR,
+
+      /**
+       * @brief name "valuePrecision", type int.
+       * @SINCE_1_1.39
+       */
+      VALUE_PRECISION,
+
+      /**
+       * @brief name "showPopup", type bool.
+       * @SINCE_1_1.39
+       */
+      SHOW_POPUP,
+
+      /**
+       * @brief name "showValue", type bool.
+       * @SINCE_1_1.39
+       */
+      SHOW_VALUE,
+
+      /**
+       * @brief name "marks", type Property::Array<float>.
+       * @SINCE_1_1.39
+       */
+      MARKS,
+
+      /**
+       * @brief name "snapToMarks", type bool.
+       * @SINCE_1_1.39
+       */
+      SNAP_TO_MARKS,
+
+      /**
+       * @brief name "markTolerance", type float.
+       * @SINCE_1_1.39
+       */
+      MARK_TOLERANCE,
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates the Slider control.
+   * @SINCE_1_1.39
+   * @return A handle to the Slider control
+   */
+  static Slider New();
+
+  /**
+   * @brief Creates an empty Slider handle.
+   * @SINCE_1_1.39
+   */
+  Slider();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * Creates another handle that points to the same real object.
+   * @SINCE_1_1.39
+   * @param[in] handle Handle to an object
+   */
+  Slider( const Slider& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * Changes this handle to point to another real object.
+   * @SINCE_1_1.39
+   * @param[in] handle Handle to an object
+   * @return A reference to this
+   */
+  Slider& operator=( const Slider& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.39
+   */
+  ~Slider();
+
+  /**
+   * @brief Downcasts an Object handle to Slider.
+   *
+   * If handle points to a Slider, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @SINCE_1_1.39
+   * @param[in] handle Handle to an object
+   * @return handle to a Slider or an uninitialized handle
+   */
+  static Slider DownCast( BaseHandle handle );
+
+public:  // Signals
+
+  /**
+   * @brief Value changed signal type.
+   * @SINCE_1_1.39
+   */
+  typedef Signal< bool ( Slider, float ) > ValueChangedSignalType;
+
+  /**
+   * @brief Mark reached signal type.
+   * @SINCE_1_1.39
+   */
+  typedef Signal< bool ( Slider, int ) > MarkReachedSignalType;
+
+  /**
+   * @brief Signal emitted when the slider value changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Slider slider, float value );
+   * @endcode
+   * @SINCE_1_1.39
+   * @return The signal to connect to
+   */
+  ValueChangedSignalType& ValueChangedSignal();
+
+  /**
+   * @brief Signal emitted when the sliding is finished.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Slider slider, float value );
+   * @endcode
+   * @SINCE_1_1.39
+   * @return The signal to connect to
+   */
+  ValueChangedSignalType& SlidingFinishedSignal();
+
+  /**
+   * @brief Signal emitted when the slider handle reaches a mark.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName( Slider slider, int value );
+   * @endcode
+   * @SINCE_1_1.39
+   * @return The signal to connect to
+   */
+  MarkReachedSignalType& MarkReachedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_1.39
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL Slider(Internal::Slider& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_1.39
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL Slider( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SLIDER_H
diff --git a/dali-toolkit/public-api/controls/table-view/table-view.cpp b/dali-toolkit/public-api/controls/table-view/table-view.cpp
new file mode 100644 (file)
index 0000000..126c254
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/table-view/table-view.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/table-view/table-view-impl.h>
+
+using std::vector;
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TableView::TableView()
+{
+}
+
+TableView::TableView( const TableView& handle )
+: Control( handle )
+{
+}
+
+TableView& TableView::operator=( const TableView& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TableView TableView::New( unsigned int initialRows, unsigned int initialColumns )
+{
+  return Internal::TableView::New( initialRows, initialColumns );
+}
+
+TableView::~TableView()
+{
+}
+
+TableView TableView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TableView, Internal::TableView>(handle);
+}
+
+bool TableView::AddChild( Actor child, CellPosition position )
+{
+  return GetImpl(*this).AddChild( child, position );
+}
+
+Actor TableView::GetChildAt( CellPosition position )
+{
+  return GetImpl(*this).GetChildAt( position );
+}
+
+Actor TableView::RemoveChildAt( CellPosition position )
+{
+  return GetImpl(*this).RemoveChildAt( position );
+}
+
+bool TableView::FindChildPosition( Actor child, CellPosition& position )
+{
+  return GetImpl(*this).FindChildPosition( child, position );
+}
+
+void TableView::InsertRow( unsigned int rowIndex )
+{
+  GetImpl(*this).InsertRow( rowIndex );
+}
+
+void TableView::DeleteRow( unsigned int rowIndex )
+{
+  GetImpl(*this).DeleteRow( rowIndex );
+}
+
+void TableView::DeleteRow( unsigned int rowIndex, vector<Actor>& removed )
+{
+  GetImpl(*this).DeleteRow( rowIndex, removed );
+}
+
+void TableView::InsertColumn( unsigned int columnIndex )
+{
+  GetImpl(*this).InsertColumn( columnIndex );
+}
+
+void TableView::DeleteColumn( unsigned int columnIndex )
+{
+  GetImpl(*this).DeleteColumn( columnIndex );
+}
+
+void TableView::DeleteColumn( unsigned int columnIndex, vector<Actor>& removed )
+{
+  GetImpl(*this).DeleteColumn( columnIndex, removed );
+}
+
+void TableView::Resize( unsigned int rows, unsigned int columns )
+{
+  GetImpl(*this).Resize( rows, columns );
+}
+
+void TableView::Resize( unsigned int rows, unsigned int columns, vector<Actor>& removed )
+{
+  GetImpl(*this).Resize( rows, columns, removed );
+}
+
+void TableView::SetCellPadding( Size padding )
+{
+  GetImpl(*this).SetCellPadding( padding );
+}
+
+Size TableView::GetCellPadding()
+{
+  return GetImpl(*this).GetCellPadding();
+}
+
+void TableView::SetFitHeight( unsigned int rowIndex )
+{
+  GetImpl(*this).SetFitHeight( rowIndex );
+}
+
+bool TableView::IsFitHeight( unsigned int rowIndex ) const
+{
+  return GetImpl(*this).IsFitHeight( rowIndex );
+}
+
+void TableView::SetFitWidth( unsigned int columnIndex )
+{
+  GetImpl(*this).SetFitWidth( columnIndex );
+}
+
+bool TableView::IsFitWidth( unsigned int columnIndex ) const
+{
+  return GetImpl(*this).IsFitWidth( columnIndex );
+}
+
+void TableView::SetFixedHeight( unsigned int rowIndex, float height )
+{
+  GetImpl(*this).SetFixedHeight( rowIndex, height );
+}
+
+float TableView::GetFixedHeight( unsigned int rowIndex ) const
+{
+  return GetImpl(*this).GetFixedHeight( rowIndex );
+}
+
+void TableView::SetRelativeHeight( unsigned int rowIndex, float heightPercentage )
+{
+  GetImpl(*this).SetRelativeHeight( rowIndex, heightPercentage );
+}
+
+float TableView::GetRelativeHeight( unsigned int rowIndex ) const
+{
+  return GetImpl(*this).GetRelativeHeight( rowIndex );
+}
+
+void TableView::SetFixedWidth( unsigned int columnIndex, float width )
+{
+  GetImpl(*this).SetFixedWidth( columnIndex, width );
+}
+
+float TableView::GetFixedWidth( unsigned int columnIndex ) const
+{
+  return GetImpl(*this).GetFixedWidth( columnIndex );
+}
+
+void TableView::SetRelativeWidth( unsigned int columnIndex, float widthPercentage )
+{
+  GetImpl(*this).SetRelativeWidth( columnIndex, widthPercentage );
+}
+
+float TableView::GetRelativeWidth( unsigned int columnIndex ) const
+{
+  return GetImpl(*this).GetRelativeWidth( columnIndex );
+}
+
+unsigned int TableView::GetRows()
+{
+  return GetImpl(*this).GetRows();
+}
+
+unsigned int TableView::GetColumns()
+{
+  return GetImpl(*this).GetColumns();
+}
+
+void TableView::SetCellAlignment( CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical )
+{
+  GetImpl(*this).SetCellAlignment( position, horizontal, vertical );
+}
+
+TableView::TableView(Internal::TableView& implementation)
+: Control(implementation)
+{
+}
+
+TableView::TableView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TableView>(internal);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/table-view/table-view.h b/dali-toolkit/public-api/controls/table-view/table-view.h
new file mode 100644 (file)
index 0000000..c73d8d0
--- /dev/null
@@ -0,0 +1,544 @@
+#ifndef DALI_TOOLKIT_TABLE_VIEW_H
+#define DALI_TOOLKIT_TABLE_VIEW_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TableView;
+}
+/**
+ * @addtogroup dali_toolkit_controls_table_view
+ * @{
+ */
+
+/**
+ * @brief TableView is a layout container for aligning child actors in a grid like layout.
+ *
+ * TableView constrains the x and y position and width and height of the child actors.
+ * z position and depth are left intact so that 3D model actors can also be laid out
+ * in a grid without loosing their depth scaling.
+ *
+ * @nosubgrouping
+ * <h3>Per-child Custom properties for script supporting:</h3>
+ *
+ * When an actor is add to the tableView through Actor::Add() instead of TableView::AddChild,
+ * the following custom properties of the actor are checked to decide the actor position inside the table.
+ *
+ * These properties are registered dynamically to the child and is non-animatable.
+ *
+ * | %Property Name          | Type        |
+ * |-------------------------|-------------|
+ * | cellIndex               | Vector2     |
+ * | rowSpan                 | float       |
+ * | columnSpan              | float       |
+ * | cellHorizontalAlignment | string      |
+ * | cellVerticalAlignment   | string      |
+ *
+ * The rowSpan or columnSpan has integer value, but its type is float here due to the limitation of the builder's ability to differentiate integer and float from Json string.
+ * The available values for cellHorizontalAlignment are: left, center, right.
+ * The available values for cellVerticalAlignment are: top, center, bottom.
+ *
+ * @code
+ * "name":"gallery1",
+ * "type":"ImageView",
+ * "image": {
+ *    "url": "{DALI_IMAGE_DIR}gallery-small-1.jpg"
+ *  },
+ *  "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
+ *     "cellHorizontalAlignment": "left", // Property to specify how to align horizontally inside the cells, if not set, default value is 'left'
+ *     "cellVerticalAlignment": "center"  // Property to specify how to align vertically inside the cells, if not set, default value is 'top'
+ *   }
+ * @endcode
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API TableView : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,             ///< Reserve property indices @SINCE_1_0.0
+
+    CHILD_PROPERTY_START_INDEX = CHILD_PROPERTY_REGISTRATION_START_INDEX,         ///< @SINCE_1_1.36
+    CHILD_PROPERTY_END_INDEX =   CHILD_PROPERTY_REGISTRATION_START_INDEX + 1000   ///< Reserve child property indices @SINCE_1_1.36
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the TableView class.
+   *
+   * LayoutRows: set the height of the rows.
+   * It has the format as follows in script:
+   * @code
+   * "layoutRows":
+   *       {
+   *         "0": { "policy": "fixed", "value": 40 },       //@see SetFixedHight
+   *         "2": { "policy": "relative", "value": 0.33 },  //@see SetRelativeHeight
+   *         "3": { "policy": "fit", "value":0.0 }          //@see SetFitHeight, the value is not used, its height is decided by the children in this row
+   *       }
+   * @endcode
+   *
+   * LayoutColumns: set the width of the columns.
+   * It has the format as follows in script:
+   * @code
+   * "layoutColumns":
+   *       {
+   *         "0": { "policy": "fixed", "value": 40 },       //@see SetFixedWidth
+   *         "1": { "policy": "fit", "value":0.0 }          //@see SetFitHeight, the value is not used, its width is decided by the children in this column
+   *         "2": { "policy": "relative", "value": 0.33 }   //@see SetRelativeWidth
+   *       }
+   * @endcode
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the TableView class.
+     *
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      ROWS = PROPERTY_START_INDEX, ///< name "rows",           type unsigned int @SINCE_1_0.0
+      COLUMNS,                     ///< name "columns",        type unsigned int @SINCE_1_0.0
+      CELL_PADDING,                ///< name "cellPadding",    type Vector2 @SINCE_1_0.0
+      LAYOUT_ROWS,                 ///< name "layoutRows",     type Map @SINCE_1_0.0
+      LAYOUT_COLUMNS,              ///< name "layoutColumns",  type Map @SINCE_1_0.0
+    };
+  };
+
+  /**
+   * @brief Enumeration for the instance of child properties belonging to the TableView class.
+   * @SINCE_1_1.36
+   */
+  struct ChildProperty
+  {
+    /**
+     * @brief Enumeration for the instance of child properties belonging to the TableView class.
+     * @SINCE_1_1.36
+     */
+    enum
+    {
+      CELL_INDEX = CHILD_PROPERTY_START_INDEX,  ///< name "cellIndex",                The top-left cell this child occupies, if not set, the first available cell is used,           type VECTOR2 @SINCE_1_1.36
+      ROW_SPAN,                                 ///< name "rowSpan",                  The number of rows this child occupies, if not set, default value is 1,                        type FLOAT @SINCE_1_1.36
+      COLUMN_SPAN,                              ///< name "columnSpan",               The number of columns this child occupies, if not set, default value is 1,                     type FLOAT @SINCE_1_1.36
+      CELL_HORIZONTAL_ALIGNMENT,                ///< name "cellHorizontalAlignment",  The horizontal alignment of this child inside the cells, if not set, default value is 'left',  type STRING @SINCE_1_1.36
+      CELL_VERTICAL_ALIGNMENT                   ///< name "cellVerticalAlignment",    The vertical alignment of this child inside the cells, if not set, default value is 'top',     type STRING @SINCE_1_1.36
+    };
+  };
+
+  /**
+   * @brief Enumeration for describing how the size of a row / column has been set.
+   * @SINCE_1_0.0
+   */
+  enum LayoutPolicy
+  {
+    FIXED,      ///< Fixed with the given value. @SINCE_1_0.0
+    RELATIVE,   ///< Calculated as percentage of the remainder after subtracting Padding and Fixed height/width @SINCE_1_0.0
+    FILL,       ///< Default policy, get the remainder of the 100% (after subtracting Fixed, Fit and Relative height/ width) divided evenly between 'fill' rows/columns @SINCE_1_0.0
+    FIT         ///< Fit around its children. @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Structure to specify layout position for child actor.
+   * @SINCE_1_0.0
+   */
+  struct CellPosition
+  {
+    /**
+     * @brief Constructor to initialise values to defaults for convenience.
+     * @SINCE_1_0.0
+     * @param[in] rowIndex The row index initialized
+     * @param[in] columnIndex The column index initialized
+     * @param[in] rowSpan The row span initialized
+     * @param[in] columnSpan The column span initialized
+     */
+    CellPosition( unsigned int rowIndex = 0, unsigned int columnIndex = 0,
+                    unsigned int rowSpan = 1, unsigned int columnSpan = 1 )
+    : rowIndex( rowIndex ), columnIndex( columnIndex ),
+      rowSpan( rowSpan ), columnSpan( columnSpan )
+    { }
+
+    unsigned int rowIndex;
+    unsigned int columnIndex;
+    unsigned int rowSpan;
+    unsigned int columnSpan;
+  };
+
+  /**
+   * @brief Creates a TableView handle; this can be initialized with TableView::New().
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_0.0
+   */
+  TableView();
+
+  /**
+   * @brief Copy constructor. Creates another handle that points to the same real object.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to copy from
+   */
+  TableView( const TableView& handle );
+
+  /**
+   * @brief Assignment operator. Changes this handle to point to another real object.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return A reference to this
+   */
+  TableView& operator=( const TableView& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~TableView();
+
+  /**
+   * @brief Creates the TableView control.
+   * @SINCE_1_0.0
+   * @param[in] initialRows for the table
+   * @param[in] initialColumns for the table
+   * @return A handle to the TableView control
+   */
+  static TableView New( unsigned int initialRows, unsigned int initialColumns );
+
+  /**
+   * @brief Downcasts a handle to TableView handle.
+   *
+   * If handle points to a TableView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a TableView or an uninitialized handle
+   */
+  static TableView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Adds a child to the table.
+   * If the row or column index is outside the table, the table gets resized bigger.
+   * @SINCE_1_0.0
+   * @param[in] child The child to add
+   * @param[in] position The position for the child
+   * @return @c true if the addition succeeded, @c false if the cell is already occupied
+   * @pre The child actor has been initialized.
+   */
+  bool AddChild( Actor child, CellPosition position );
+
+  /**
+   * @brief Returns a child from the given layout position.
+   * @SINCE_1_0.0
+   * @param[in] position The position in the table
+   * @return Child that was in the cell or an uninitialized handle
+   * @note If there is no child in this position this method returns an uninitialized.
+   * Actor handle
+   */
+  Actor GetChildAt( CellPosition position );
+
+  /**
+   * @brief Removes a child from the given layout position.
+   * @SINCE_1_0.0
+   * @param[in] position The position for the child to remove
+   * @return Child that was removed or an uninitialized handle
+   * @note If there is no child in this position, this method does nothing.
+   */
+  Actor RemoveChildAt( CellPosition position );
+
+  /**
+   * @brief Finds the child's layout position.
+   * @SINCE_1_0.0
+   * @param[in] child The child to search for
+   * @param[out] position The position for the child
+   * @return true if the child was included in this TableView
+   */
+  bool FindChildPosition( Actor child, CellPosition& position );
+
+  /**
+   * @brief Inserts a new row to given index.
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The rowIndex of the new row
+   */
+  void InsertRow( unsigned int rowIndex );
+
+  /**
+   * @brief Deletes a row from the given index.
+   * Removed elements are deleted.
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The rowIndex of the row to delete
+   */
+  void DeleteRow( unsigned int rowIndex );
+
+  /**
+   * @brief Deletes a row from the given index.
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The rowIndex of the row to delete
+   * @param[out] removed The removed elements
+   */
+  void DeleteRow( unsigned int rowIndex, std::vector<Actor>& removed );
+
+  /**
+   * @brief Inserts a new column to the given index.
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The columnIndex of the new column
+   */
+  void InsertColumn( unsigned int columnIndex );
+
+  /**
+   * @brief Deletes a column from the given index.
+   * Removed elements are deleted.
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The columnIndex of the column to delete
+   */
+  void DeleteColumn( unsigned int columnIndex );
+
+  /**
+   * @brief Deletes a column from the given index.
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The columnIndex of the column to delete
+   * @param[out] removed The removed elements
+   */
+  void DeleteColumn( unsigned int columnIndex, std::vector<Actor>& removed );
+
+  /**
+   * @brief Resizes the TableView.
+   * @SINCE_1_0.0
+   * @param[in] rows The rows for the table
+   * @param[in] columns The columns for the table
+   * @note If the new size is smaller than old,
+   * superfluous actors get removed. If you want to relayout removed children,
+   * use the variant that returns the removed Actors and reinsert them into the table.
+   * If an actor spans to a removed row or column, it gets removed from the table.
+   */
+  void Resize( unsigned int rows, unsigned int columns );
+
+  /**
+   * @brief Resizes the TableView.
+   * @SINCE_1_0.0
+   * @param[in] rows The rows for the table
+   * @param[in] columns The columns for the table
+   * @param[out] removed The removed actor handles
+   * @note If the new size is smaller than old, superfluous actors get removed.
+   * If an actor spans to a removed row or column it gets removed from the table.
+   */
+  void Resize( unsigned int rows, unsigned int columns, std::vector<Actor>& removed );
+
+  /**
+   * @brief Sets horizontal and vertical padding between cells.
+   * @SINCE_1_0.0
+   * @param[in] padding Width and height
+   */
+  void SetCellPadding( Size padding );
+
+  /**
+   * @brief Gets the current padding as width and height.
+   * @SINCE_1_0.0
+   * @return The current padding as width and height
+   */
+  Size GetCellPadding();
+
+  /**
+   * @brief Specifies this row as fitting its height to its children.
+   *
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The row to set
+   */
+  void SetFitHeight( unsigned int rowIndex );
+
+  /**
+   * @brief Checks if the row is a fit row.
+   *
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The row to check
+   * @return Return true if the row is fit
+   */
+  bool IsFitHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @brief Specifies this column as fitting its width to its children.
+   *
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The column to set
+   */
+  void SetFitWidth( unsigned int columnIndex );
+
+  /**
+   * @brief Checks if the column is a fit column.
+   *
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The column to check
+   * @return Return true if the column is fit
+   */
+  bool IsFitWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @brief Sets a row to have fixed height.
+   * Setting a fixed height of 0 has no effect.
+   * @SINCE_1_0.0
+   * @param rowIndex The rowIndex for row with fixed height
+   * @param height The height in world coordinate units
+   * @pre The row rowIndex must exist.
+   */
+  void SetFixedHeight( unsigned int rowIndex, float height );
+
+  /**
+   * @brief Gets a row's fixed height.
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The row index with fixed height
+   * @return height The height in world coordinate units
+   * @pre The row rowIndex must exist.
+   * @note The returned value is valid if it has been set before.
+   */
+  float GetFixedHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @brief Sets a row to have relative height. Relative height means percentage of
+   * the remainder of the table height after subtracting Padding and Fixed height rows.
+   * Setting a relative height of 0 has no effect.
+   * @SINCE_1_0.0
+   * @param rowIndex The rowIndex for row with relative height
+   * @param heightPercentage between 0.0f and 1.0f
+   * @pre The row rowIndex must exist.
+   */
+  void SetRelativeHeight( unsigned int rowIndex, float heightPercentage );
+
+  /**
+   * @brief Gets a row's relative height.
+   * @SINCE_1_0.0
+   * @param[in] rowIndex The row index with relative height
+   * @return Height in percentage units, between 0.0f and 1.0f
+   * @pre The row rowIndex must exist.
+   * @note The returned value is valid if it has been set before.
+   */
+  float GetRelativeHeight( unsigned int rowIndex ) const;
+
+  /**
+   * @brief Sets a column to have fixed width.
+   * Setting a fixed width of 0 has no effect.
+   * @SINCE_1_0.0
+   * @param columnIndex The columnIndex for column with fixed width
+   * @param width The width in world coordinate units
+   * @pre The column columnIndex must exist.
+   */
+  void SetFixedWidth( unsigned int columnIndex, float width );
+
+  /**
+   * @brief Gets a column's fixed width.
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The column index with fixed width
+   * @return Width in world coordinate units
+   * @pre The column columnIndex must exist.
+   * @note The returned value is valid if it has been set before.
+   */
+  float GetFixedWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @brief Sets a column to have relative width. Relative width means percentage of
+   * the remainder of table width after subtracting Padding and Fixed width columns.
+   * Setting a relative width of 0 has no effect.
+   * @SINCE_1_0.0
+   * @param columnIndex The columnIndex for column with fixed width
+   * @param widthPercentage The widthPercentage between 0.0f and 1.0f
+   * @pre The column columnIndex must exist.
+   */
+  void SetRelativeWidth( unsigned int columnIndex, float widthPercentage );
+
+  /**
+   * @brief Gets a column's relative width.
+   * @SINCE_1_0.0
+   * @param[in] columnIndex The column index with relative width
+   * @return Width in percentage units, between 0.0f and 1.0f
+   * @pre The column columnIndex must exist.
+   * @note The returned value is valid if it has been set before.
+   */
+  float GetRelativeWidth( unsigned int columnIndex ) const;
+
+  /**
+   * @brief Gets the amount of rows in the table.
+   * @SINCE_1_0.0
+   * @return The amount of rows in the table
+   */
+  unsigned int GetRows();
+
+  /**
+   * @brief Gets the amount of columns in the table.
+   * @SINCE_1_0.0
+   * @return The amount of columns in the table
+   */
+  unsigned int GetColumns();
+
+  /**
+   * @brief Sets the alignment on a cell.
+   *
+   * Cells without calling this function have the default values of LEFT and TOP respectively.
+   *
+   * @SINCE_1_0.0
+   * @param[in] position The cell to set alignment on
+   * @param[in] horizontal The horizontal alignment
+   * @param[in] vertical The vertical alignment
+   */
+  void SetCellAlignment( CellPosition position, HorizontalAlignment::Type horizontal, VerticalAlignment::Type vertical );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL TableView(Internal::TableView& implementation);
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL TableView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TABLE_VIEW_H
diff --git a/dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h b/dali-toolkit/public-api/controls/text-controls/hidden-input-properties.h
new file mode 100644 (file)
index 0000000..4f7c503
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_HIDDEN_INPUT_PROPERTIES_H
+#define DALI_HIDDEN_INPUT_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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
+{
+
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+namespace HiddenInput
+{
+
+/**
+ * @brief HiddenInput Property.
+ * @SINCE_1_2.60
+ */
+namespace Property
+{
+
+/**
+ * @brief HiddenInput Property.
+ * @SINCE_1_2.60
+ */
+enum
+{
+  /**
+   * @brief The mode for input text display.
+   * @details Name "mode", type HiddenInput::Mode (Property::INTEGER).
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @see HiddenInput::Mode
+   */
+  MODE,
+
+  /**
+   * @brief All input characters are substituted by this character.
+   * @details Name "substituteCharacter", type Property::INTEGER.
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  SUBSTITUTE_CHARACTER,
+
+  /**
+   * @brief Length of text to show or hide, available when HIDE_COUNT/SHOW_COUNT mode is used.
+   * @details Name "substituteCount", type Property::INTEGER.
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  SUBSTITUTE_COUNT,
+
+  /**
+   * @brief Hide last character after this duration, available when SHOW_LAST_CHARACTER mode.
+   * @details Name "showDuration", type Property::INTEGER.
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  SHOW_LAST_CHARACTER_DURATION
+};
+
+} // namespace Property
+
+/**
+ * @brief The type for HiddenInput::Property::MODE.
+ * @SINCE_1_2.60
+ */
+namespace Mode
+{
+
+/**
+ * @brief The type for HiddenInput::Property::MODE.
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  HIDE_NONE,            ///< Do not hide text. @SINCE_1_2.60
+  HIDE_ALL,             ///< Hide all the input text. @SINCE_1_2.60
+  HIDE_COUNT,           ///< Hide n characters from start. @SINCE_1_2.60
+  SHOW_COUNT,           ///< Show n characters from start. @SINCE_1_2.60
+  SHOW_LAST_CHARACTER   ///< Show last character for the duration (use Property::SHOW_LAST_CHARACTER_DURATION to modify duration). @SINCE_1_2.60
+};
+
+} // namespace Mode
+
+} // namespace HiddenInput
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_HIDDEN_INPUT_PROPERTIES_H
diff --git a/dali-toolkit/public-api/controls/text-controls/placeholder-properties.h b/dali-toolkit/public-api/controls/text-controls/placeholder-properties.h
new file mode 100644 (file)
index 0000000..1e34ebf
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef DALI_TOOLKIT_PLACEHOLDER_PROPERTIES_H
+#define DALI_TOOLKIT_PLACEHOLDER_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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
+{
+
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+namespace Text
+{
+
+/**
+ * @brief Placeholder text used by Text controls to show text before any text inputed.
+ * @SINCE_1_2.62
+ *
+ */
+namespace PlaceHolder
+{
+
+/**
+ * @brief Placeholder text Properties used by Text controls to show placeholder
+ * @SINCE_1_2.62
+ *
+ */
+namespace Property
+{
+
+/**
+ * @brief The configurable settings for the Placeholder text.
+ * @SINCE_1_2.62
+ *
+ */
+enum Setting
+{
+  /**
+   * @brief The text to display as a placeholder.
+   * @details Name "text", type Property::STRING.
+   * @note Optional. If not provided then no placeholder text will be shown whilst control not focused.
+   * @SINCE_1_2.62
+   */
+  TEXT,
+
+  /**
+   * @brief The text to display as placeholder when focused.
+   * @details Name "textFocused", type Property::STRING.
+   * @note Optional. If not provided then no placeholder text will be shown when focused.
+   * @SINCE_1_2.62
+   */
+  TEXT_FOCUSED,
+
+  /**
+   * @brief The colour of the placeholder text.
+   * @details Name "color", type Property::VECTOR4.
+   * @note If color not provided then 80% white will be used.
+   * @SINCE_1_2.62
+   */
+  COLOR,
+
+  /**
+   * @brief The font family to be used for placeholder text.
+   * @details Name "fontFamily", type Property::STRING.
+   * @note Optional. Default font family used if not provided.
+   * @SINCE_1_2.62
+   */
+  FONT_FAMILY,
+
+  /**
+   * @brief The font style to be used for placeholder text.
+   * @details Name "fontStyle", type Property::MAP.
+   *
+   * Example usage:
+   * @code
+   *   Property::Map fontStylePropertyMap;
+   *   fontStylePropertyMap.Insert( "weight", "bold" );
+   *   fontStylePropertyMap.Insert( "width", "condensed" );
+   *   fontStylePropertyMap.Insert( "slant", "italic" );
+   *   ...
+   *   placeholderPropertyMap[ Text::PlaceHolder::Property::FONT_STYLE] = fontStylePropertyMap;
+   * @endcode
+   *
+   * @note Optional. Default font style used if not provided.
+   * @SINCE_1_2.62
+   */
+  FONT_STYLE,
+
+  /**
+   * @brief The font point size to be used.
+   * @details Name "pointSize", type Property::FLOAT.
+   * @note Optional. Not required if PIXEL_SIZE provided.  If neither provided then the text control point size is used.
+   * @SINCE_1_2.62
+   */
+  POINT_SIZE,
+
+  /**
+   * @brief The font size in pixels to be used
+   * @details Name "pixelSize", type Property::FLOAT.
+   * @note Optional. Not required if POINT_SIZE provided. If neither provided then the text control point size is used.
+   * @SINCE_1_2.62
+   */
+  PIXEL_SIZE,
+
+  /**
+   * @brief If ellipsis should be used when placeholder is too long.
+   * @details Name "ellipsis", type Property::BOOLEAN
+   * @note Optional. Default is false.
+   * @SINCE_1_2.62
+   */
+  ELLIPSIS
+};
+
+} // namespace Property
+
+} // namespace PlaceHolder
+
+
+} // namespace Text
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_PLACEHOLDER_PROPERTIES_H
diff --git a/dali-toolkit/public-api/controls/text-controls/text-editor.cpp b/dali-toolkit/public-api/controls/text-controls/text-editor.cpp
new file mode 100644 (file)
index 0000000..f02d843
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 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 <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-editor-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextEditor TextEditor::New()
+{
+  return Internal::TextEditor::New();
+}
+
+TextEditor::TextEditor()
+{
+}
+
+TextEditor::TextEditor( const TextEditor& handle )
+: Control( handle )
+{
+}
+
+TextEditor& TextEditor::operator=( const TextEditor& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextEditor::~TextEditor()
+{
+}
+
+TextEditor TextEditor::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextEditor, Internal::TextEditor>( handle );
+}
+
+TextEditor::TextChangedSignalType& TextEditor::TextChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).TextChangedSignal();
+}
+
+TextEditor::InputStyleChangedSignalType& TextEditor::InputStyleChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).InputStyleChangedSignal();
+}
+
+
+TextEditor::ScrollStateChangedSignalType& TextEditor::ScrollStateChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).ScrollStateChangedSignal();
+}
+
+TextEditor::TextEditor( Internal::TextEditor& implementation )
+: Control( implementation )
+{
+}
+
+TextEditor::TextEditor( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextEditor>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/text-controls/text-editor.h b/dali-toolkit/public-api/controls/text-controls/text-editor.h
new file mode 100644 (file)
index 0000000..389b0fe
--- /dev/null
@@ -0,0 +1,637 @@
+#ifndef DALI_TOOLKIT_TEXT_EDITOR_H
+#define DALI_TOOLKIT_TEXT_EDITOR_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TextEditor;
+}
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+/**
+ * @brief A control which provides a multi-line editable text editor.
+ *
+ * Signals
+ * | %Signal Name         | Method                         |                    |
+ * |----------------------|--------------------------------|--------------------|
+ * | textChanged          | @ref TextChangedSignal()       | @SINCE_1_1.37      |
+ * | inputStyleChanged    | @ref InputStyleChangedSignal() | @SINCE_1_2_2       |
+ *
+ */
+class DALI_TOOLKIT_API TextEditor : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_1.37
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the TextEditor class.
+   * @SINCE_1_1.37
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the TextEditor class.
+     * @SINCE_1_1.37
+     */
+    enum
+    {
+      /**
+       * @brief The type or rendering e.g. bitmap-based.
+       * @details Name "renderingBackend", type Property::INTEGER.
+       * @SINCE_1_1.37
+       */
+      RENDERING_BACKEND = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The text to display in UTF-8 format.
+       * @details Name "text", type Property::STRING.
+       * @SINCE_1_1.37
+       */
+      TEXT,
+
+      /**
+       * @brief The text color.
+       * @details Name "textColor", type Property::VECTOR4.
+       * @SINCE_1_1.37
+       */
+      TEXT_COLOR,
+
+      /**
+       * @brief The requested font family.
+       * @details Name "fontFamily", type Property::STRING.
+       * @SINCE_1_1.37
+       */
+      FONT_FAMILY,
+
+      /**
+       * @brief The requested font style.
+       * @details Name "fontStyle", type Property::STRING or Property::MAP.
+       * @SINCE_1_2.13
+       */
+      FONT_STYLE,
+
+      /**
+       * @brief The size of font in points.
+       * @details Name "pointSize", type Property::FLOAT.
+       *          Conversion from Pixel size to Point size : Point size = Pixel size * 72 / DPI.
+       * @SINCE_1_1.37
+       */
+      POINT_SIZE,
+
+      /**
+       * @brief The text horizontal alignment.
+       * @details Name "horizontalAlignment", type Property::STRING or type HorizontalAlignment::Type (Property::INTEGER)
+       *          Values "BEGIN" "CENTER" "END".
+       * @note Return type is Property::STRING
+       * @SINCE_1_1.37
+       */
+      HORIZONTAL_ALIGNMENT,
+
+      /**
+       * @brief Vertical scrolling will occur if the cursor is this close to the control border.
+       * @details Name "scrollThreshold", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      SCROLL_THRESHOLD,
+
+      /**
+       * @brief The scroll speed in pixels per second.
+       * @details Name "scrollSpeed", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      SCROLL_SPEED,
+
+      /**
+       * @brief The color to apply to the primary cursor.
+       * @details Name "primaryCursorColor", type Property::VECTOR4.
+       * @SINCE_1_1.37
+       */
+      PRIMARY_CURSOR_COLOR,
+
+      /**
+       * @brief The color to apply to the secondary cursor.
+       * @details Name "secondaryCursorColor", type Property::VECTOR4.
+       * @SINCE_1_1.37
+       */
+      SECONDARY_CURSOR_COLOR,
+
+      /**
+       * @brief Whether the cursor should blink or not.
+       * @details Name "enableCursorBlink", type Property::BOOLEAN.
+       * @SINCE_1_1.37
+       */
+      ENABLE_CURSOR_BLINK,
+
+      /**
+       * @brief The time interval in seconds between cursor on/off states.
+       * @details Name "cursorBlinkInterval", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      CURSOR_BLINK_INTERVAL,
+
+      /**
+       * @brief The cursor will stop blinking after this number of seconds (if non-zero).
+       * @details Name "cursorBlinkDuration", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      CURSOR_BLINK_DURATION,
+
+      /**
+       * @brief The cursor width.
+       * @details Name "cursorWidth", type Property::INTEGER.
+       * @SINCE_1_1.37
+       */
+      CURSOR_WIDTH,
+
+      /**
+       * @brief The image to display for the grab handle.
+       * @details Name "grabHandleImage", type Property::STRING.
+       * @SINCE_1_1.37
+       */
+      GRAB_HANDLE_IMAGE,
+
+      /**
+       * @brief The image to display when the grab handle is pressed.
+       * @details Name "grabHandlePressedImage", type Property::STRING.
+       * @SINCE_1_1.37
+       */
+      GRAB_HANDLE_PRESSED_IMAGE,
+
+      /**
+       * @brief The image to display for the left selection handle.
+       * @details Name "selectionHandleImageLeft", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display for the right selection handle.
+       * @details Name "selectionHandleImageRight", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_IMAGE_RIGHT,
+
+      /**
+       * @brief The image to display when the left selection handle is pressed.
+       * @details Name "selectionHandlePressedImageLeft", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_PRESSED_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display when the right selection handle is pressed.
+       * @details Name "selectionHandlePressedImageRight", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_PRESSED_IMAGE_RIGHT,
+
+      /**
+       * @brief The image to display for the left selection handle marker.
+       * @details Name "selectionHandleMarkerImageLeft", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_MARKER_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display for the right selection handle marker.
+       * @details Name "selectionHandleMarkerImageRight", type Property::MAP.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HANDLE_MARKER_IMAGE_RIGHT,
+
+      /**
+       * @brief The color of the selection highlight.
+       * @details Name "selectionHighlightColor", type Property::VECTOR4.
+       * @SINCE_1_1.37
+       */
+      SELECTION_HIGHLIGHT_COLOR,
+
+      /**
+       * @brief The decorations (handles etc) will positioned within this area on-screen.
+       * @details Name "decorationBoundingBox", type Property::RECTANGLE.
+       * @SINCE_1_1.37
+       */
+      DECORATION_BOUNDING_BOX,
+
+      /**
+       * @brief Whether the mark-up processing is enabled.
+       * @details Name "enableMarkup", type Property::BOOLEAN.
+       * @SINCE_1_1.37
+       */
+      ENABLE_MARKUP,
+
+      /**
+       * @brief The color of the new input text.
+       * @details Name "inputColor", type Property::VECTOR4.
+       * @SINCE_1_1.37
+       */
+      INPUT_COLOR,
+
+      /**
+       * @brief The font's family of the new input text.
+       * @details Name "inputFontFamily", type Property::STRING.
+       * @SINCE_1_1.37
+       */
+      INPUT_FONT_FAMILY,
+
+      /**
+       * @brief The font's style of the new input text.
+       * @details Name "inputFontStyle", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_FONT_STYLE,
+
+      /**
+       * @brief The font's size of the new input text in points.
+       * @details Name "inputPointSize", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      INPUT_POINT_SIZE,
+
+      /**
+       * @brief The default extra space between lines in points.
+       * @details Name "lineSpacing", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      LINE_SPACING,
+
+      /**
+       * @brief The extra space between lines in points.
+       * @details Name "inputLineSpacing",  type Property::FLOAT.
+       * @SINCE_1_1.37
+       * @note This affects the whole paragraph where the new input text is inserted.
+       */
+      INPUT_LINE_SPACING,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::UNDERLINE
+       */
+      UNDERLINE,
+
+      /**
+       * @brief The underline parameters of the new input text.
+       * @details Name "inputUnderline", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_UNDERLINE,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::SHADOW
+       */
+      SHADOW,
+
+      /**
+       * @brief The shadow parameters of the new input text.
+       * @details Name "inputShadow", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_SHADOW,
+
+      /**
+       * @brief The default emboss parameters.
+       * @details Name "emboss", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      EMBOSS,
+
+      /**
+       * @brief The emboss parameters of the new input text.
+       * @details Name "inputEmboss", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_EMBOSS,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::OUTLINE
+       */
+      OUTLINE,
+
+      /**
+       * @brief The outline parameters of the new input text.
+       * @details Name "inputOutline", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_OUTLINE,
+
+      /**
+       * @brief Enable or disable the smooth scroll animation.
+       * @details Name "smoothScroll", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      SMOOTH_SCROLL,
+
+      /**
+       * @brief Sets the duration of smooth scroll animation.
+       * @details Name "smoothScrollDuration", type Property::FLOAT.
+       * @SINCE_1_2.60
+       */
+      SMOOTH_SCROLL_DURATION,
+
+      /**
+       * @brief Enable or disable the scroll bar.
+       * @details Name "enableScrollBar", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      ENABLE_SCROLL_BAR,
+
+      /**
+       * @brief Sets the duration of scroll bar to show.
+       * @details Name "scrollBarShowDuration", type Property::FLOAT.
+       * @SINCE_1_2.60
+       */
+      SCROLL_BAR_SHOW_DURATION,
+
+      /**
+       * @brief Sets the duration of scroll bar to fade out.
+       * @details Name "scrollBarFadeDuration", type Property::FLOAT.
+       * @SINCE_1_2.60
+       */
+      SCROLL_BAR_FADE_DURATION,
+
+      /**
+       * @brief The size of font in pixels.
+       * @details Name "pixelSize", type Property::FLOAT.
+       *          Conversion from Point size to Pixel size:
+       *           Pixel size = Point size * DPI / 72
+       * @SINCE_1_2.60
+       */
+      PIXEL_SIZE,
+
+      /**
+       * @brief The line count of text.
+       * @details Name "lineCount", type Property::INTEGER.
+       * @SINCE_1_2.60
+       * @note This property is read-only.
+       */
+      LINE_COUNT,
+
+      /**
+       * @brief Enables Text selection, such as the cursor, handle, clipboard, and highlight color.
+       * @details Name "enableSelection", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      ENABLE_SELECTION,
+
+      /**
+       * @brief Sets the placeholder : text, color, font family, font style, point size, and pixel size.
+       * @details Name "placeholder", type Property::MAP.
+       * Example:
+       * @code
+       *   Property::Map propertyMap;
+       *   propertyMap["placeholderText"] = "Setting Placeholder Text";
+       *   propertyMap["placeholderTextFocused"] = "Setting Placeholder Text Focused";
+       *   propertyMap["placeholderColor"] = Color::RED;
+       *   propertyMap["placeholderFontFamily"] = "Arial";
+       *   propertyMap["placeholderPointSize"] = 12.0f;
+       *
+       *   Property::Map fontStyleMap;
+       *   fontStyleMap.Insert( "weight", "bold" );
+       *   fontStyleMap.Insert( "width", "condensed" );
+       *   fontStyleMap.Insert( "slant", "italic" );
+       *   propertyMap["placeholderFontStyle"] = fontStyleMap;
+       *
+       *   editor.SetProperty( TextEditor::Property::PLACEHOLDER, propertyMap );
+       * @endcode
+       *
+       * @SINCE_1_2.60
+       */
+      PLACEHOLDER,
+
+      /**
+       * @brief Line wrap mode when text lines are greater than the layout width.
+       * @details Name "lineWrapMode", type Text::LineWrap::Mode (Text::Property::INTEGER) or Property::STRING.
+       * @SINCE_1_2.60
+       * @note Default is Text::LineWrap::WORD.
+       * @note Return type is Text::LineWrap::Mode (Text::Property::INTEGER).
+       * @see Text::LineWrap
+       */
+      LINE_WRAP_MODE,
+    };
+  };
+
+  /**
+   * @brief Mask used by the signal InputStyleChangedSignal(). Notifies which parameters of the input style have changed.
+   *
+   * @SINCE_1_2_2
+   */
+  struct InputStyle
+  {
+  /**
+   * @brief Enumeration for mask used by the signal InputStyleChangedSignal().
+   * @SINCE_1_2_2
+   */
+    enum Mask
+    {
+      NONE         = 0x0000, ///< @SINCE_1_2_2
+      COLOR        = 0x0001, ///< @SINCE_1_2_2
+      FONT_FAMILY  = 0x0002, ///< @SINCE_1_2_2
+      POINT_SIZE   = 0x0004, ///< @SINCE_1_2_2
+      FONT_STYLE   = 0x0008, ///< @SINCE_1_2_2
+      LINE_SPACING = 0x0010, ///< @SINCE_1_2_2
+      UNDERLINE    = 0x0020, ///< @SINCE_1_2_2
+      SHADOW       = 0x0040, ///< @SINCE_1_2_2
+      EMBOSS       = 0x0080, ///< @SINCE_1_2_2
+      OUTLINE      = 0x0100  ///< @SINCE_1_2_2
+    };
+  };
+
+  /**
+   * @brief Enumerations for the type of scrolling.
+   * @SINCE_1_2.60
+   * @see ScrollStateChangedSignal()
+   */
+  struct Scroll
+  {
+    /**
+     * @brief Enumerations for the type of scrolling.
+     * @SINCE_1_2.60
+     * @see ScrollStateChangedSignal()
+     */
+    enum Type
+    {
+      STARTED,   ///< Scrolling has started. @SINCE_1_2.60
+      FINISHED   ///< Scrolling has finished. @SINCE_1_2.60
+    };
+  };
+
+  // Type Defs
+
+  /**
+   * @brief Text changed signal type.
+   * @SINCE_1_1.37
+   */
+  typedef Signal<void ( TextEditor ) > TextChangedSignalType;
+
+  /**
+   * @brief Input Style changed signal type.
+   * @SINCE_1_2_2
+   */
+  typedef Signal<void ( TextEditor, InputStyle::Mask ) > InputStyleChangedSignalType;
+
+  /**
+   * @brief Scroll state changed signal type.
+   * @SINCE_1_2.60
+   */
+  typedef Signal< void ( TextEditor, Scroll::Type ) > ScrollStateChangedSignalType;
+
+  /**
+   * @brief Creates the TextEditor control.
+   *
+   * @SINCE_1_1.37
+   * @return A handle to the TextEditor control
+   */
+  static TextEditor New();
+
+  /**
+   * @brief Creates an empty handle.
+   *
+   * @SINCE_1_1.37
+   */
+  TextEditor();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_1.37
+   * @param[in] handle The handle to copy from
+   */
+  TextEditor( const TextEditor& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_1.37
+   * @param[in] handle The handle to copy from
+   * @return A reference to this
+   */
+  TextEditor& operator=( const TextEditor& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.37
+   */
+  ~TextEditor();
+
+  /**
+   * @brief Downcasts a handle to TextEditor.
+   *
+   * If the BaseHandle points is a TextEditor, the downcast returns a valid handle.
+   * If not, the returned handle is left empty.
+   *
+   * @SINCE_1_1.37
+   * @param[in] handle Handle to an object
+   * @return Handle to a TextEditor or an empty handle
+   */
+  static TextEditor DownCast( BaseHandle handle );
+
+  // Signals
+
+  /**
+   * @brief This signal is emitted when the text changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TextEditor textEditor );
+   * @endcode
+   *
+   * @SINCE_1_1.37
+   * @return The signal to connect to
+   */
+  TextChangedSignalType& TextChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the input style is updated as a consequence of a change in the cursor position.
+   * i.e. The signal is not emitted when the input style is updated through the property system.
+   *
+   * A callback of the following type may be connected. The @p mask parameter notifies which parts of the style have changed.
+   * @code
+   *   void YourCallbackName( TextEditor textEditor, TextEditor::InputStyle::Mask mask );
+   * @endcode
+   *
+   * @SINCE_1_2_2
+   * @return The signal to connect to
+   */
+  InputStyleChangedSignalType& InputStyleChangedSignal();
+
+  /**
+   * @brief This signal is emitted when TextEditor scrolling is started or finished.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( Scroll::Type type );
+   * @endcode
+   * type: Whether the scrolling is started or finished.
+   *
+   * @SINCE_1_2.60
+   * @return The signal to connect to
+   */
+  ScrollStateChangedSignalType& ScrollStateChangedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_1.37
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL TextEditor( Internal::TextEditor& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_1.37
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL TextEditor( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_EDITOR_H
diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.cpp b/dali-toolkit/public-api/controls/text-controls/text-field.cpp
new file mode 100644 (file)
index 0000000..fc58261
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextField TextField::New()
+{
+  return Internal::TextField::New();
+}
+
+TextField::TextField()
+{
+}
+
+TextField::TextField( const TextField& handle )
+: Control( handle )
+{
+}
+
+TextField& TextField::operator=( const TextField& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextField::~TextField()
+{
+}
+
+TextField TextField::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextField, Internal::TextField>(handle);
+}
+
+TextField::TextChangedSignalType& TextField::TextChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).TextChangedSignal();
+}
+
+TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).MaxLengthReachedSignal();
+}
+
+TextField::InputStyleChangedSignalType& TextField::InputStyleChangedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).InputStyleChangedSignal();
+}
+
+TextField::TextField( Internal::TextField& implementation )
+: Control(implementation)
+{
+}
+
+TextField::TextField( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextField>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.h b/dali-toolkit/public-api/controls/text-controls/text-field.h
new file mode 100644 (file)
index 0000000..133b2c7
--- /dev/null
@@ -0,0 +1,653 @@
+#ifndef DALI_TOOLKIT_TEXT_FIELD_H
+#define DALI_TOOLKIT_TEXT_FIELD_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TextField;
+}
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+/**
+ * @brief A control which provides a single-line editable text field.
+ *
+ * Signals
+ * | %Signal Name         | Method                         |                    |
+ * |----------------------|--------------------------------|--------------------|
+ * | textChanged          | @ref TextChangedSignal()       | @SINCE_1_0.0       |
+ * | maxLengthReached     | @ref MaxLengthReachedSignal()  | @SINCE_1_0.0       |
+ * | inputStyleChanged    | @ref InputStyleChangedSignal() | @SINCE_1_2_2       |
+ */
+class DALI_TOOLKIT_API TextField : public Control
+{
+public:
+
+  /**
+   * @brief The start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000              ///< Reserve property indices @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the TextField class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the TextField class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      /**
+       * @brief The type or rendering e.g. bitmap-based.
+       * @details Name "renderingBackend", type Property::INTEGER.
+       * @SINCE_1_0.0
+       */
+      RENDERING_BACKEND = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The text to display in UTF-8 format.
+       * @details Name "text", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      TEXT,
+
+      /**
+       * @brief The text to display when the TextField is empty and inactive.
+       * @details Name "placeholderText", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      PLACEHOLDER_TEXT,
+
+      /**
+       * @brief The text to display when the TextField is empty with key-input focus.
+       * @details Name "placeholderTextFocused", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      PLACEHOLDER_TEXT_FOCUSED,
+
+      /**
+       * @brief The requested font family.
+       * @details Name "fontFamily", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      FONT_FAMILY,
+
+      /**
+       * @brief The requested font style
+       * @details Name "fontStyle", type Property::STRING or Property::MAP.
+       * @SINCE_1_2.13
+       */
+      FONT_STYLE,
+
+      /**
+       * @brief The size of font in points.
+       * @details Name "pointSize", type Property::FLOAT.
+       *          (Conversion from Pixel size to Point size : Point size = Pixel size * 72 / DPI).
+       * @SINCE_1_0.0
+       */
+      POINT_SIZE,
+
+      /**
+       * @brief The maximum number of characters that can be inserted.
+       * @details Name "maxLength", type Property::INTEGER.
+       * @SINCE_1_0.0
+       */
+      MAX_LENGTH,
+
+      /**
+       * @brief Specifies how the text is truncated when it does not fit.
+       * @details Name "exceedPolicy", type Property::INTEGER.
+       * @SINCE_1_0.0
+       */
+      EXCEED_POLICY,
+
+      /**
+       * @brief The line horizontal alignment.
+       * @details Name "horizontalAlignment", type Property::STRING or type HorizontalAlignment::Type (Property::INTEGER)
+       *          Values "BEGIN", "CENTER", "END".
+       * @note Return type is Property::STRING
+       * @SINCE_1_0.0
+       */
+      HORIZONTAL_ALIGNMENT,
+
+      /**
+       * @brief The line vertical alignment.
+       * @details Name "verticalAlignment", type Property::STRING type VerticalAlignment::Type (Property::INTEGER)
+       *          Values "TOP",   "CENTER", "BOTTOM".
+       * @note Return type is Property::STRING
+       * @SINCE_1_0.0
+       */
+      VERTICAL_ALIGNMENT,
+
+      /**
+       * @brief The text color.
+       * @details Name "textColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      TEXT_COLOR,
+
+      /**
+       * @brief The placeholder-text color.
+       * @details Name "placeholderTextColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      PLACEHOLDER_TEXT_COLOR,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_01,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_02,
+
+      /**
+       * @brief The color to apply to the primary cursor.
+       * @details Name "primaryCursorColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      PRIMARY_CURSOR_COLOR,
+
+      /**
+       * @brief The color to apply to the secondary cursor.
+       * @details Name "secondaryCursorColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      SECONDARY_CURSOR_COLOR,
+
+      /**
+       * @brief Whether the cursor should blink or not.
+       * @details Name "enableCursorBlink", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       */
+      ENABLE_CURSOR_BLINK,
+
+      /**
+       * @brief The time interval in seconds between cursor on/off states.
+       * @details Name "cursorBlinkInterval", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      CURSOR_BLINK_INTERVAL,
+
+      /**
+       * @brief The cursor will stop blinking after this number of seconds (if non-zero)
+       * @details Name "cursorBlinkDuration", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      CURSOR_BLINK_DURATION,
+
+      /**
+       * @brief The cursor width.
+       * @details Name "cursorWidth", type Property::INTEGER.
+       * @SINCE_1_0.0
+       */
+      CURSOR_WIDTH,
+
+      /**
+       * @brief The image to display for the grab handle.
+       * @details Name "grabHandleImage", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      GRAB_HANDLE_IMAGE,
+
+      /**
+       * @brief The image to display when the grab handle is pressed
+       * @details Name "grabHandlePressedImage", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      GRAB_HANDLE_PRESSED_IMAGE,
+
+      /**
+       * @brief Horizontal scrolling will occur if the cursor is this close to the control border.
+       * @details Name "scrollThreshold", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_THRESHOLD,
+
+      /**
+       * @brief The scroll speed in pixels per second.
+       * @details Name "scrollSpeed", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      SCROLL_SPEED,
+
+      /**
+       * @brief The image to display for the left selection handle.
+       * @details Name "selectionHandleImageLeft", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display for the right selection handle.
+       * @details Name "selectionHandleImageRight", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_IMAGE_RIGHT,
+
+      /**
+       * @brief The image to display when the left selection handle is pressed.
+       * @details Name "selectionHandlePressedImageLeft", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_PRESSED_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display when the right selection handle is pressed.
+       * @details Name "selectionHandlePressedImageRight", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_PRESSED_IMAGE_RIGHT,
+
+      /**
+       * @brief The image to display for the left selection handle marker.
+       * @details Name "selectionHandleMarkerImageLeft", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_MARKER_IMAGE_LEFT,
+
+      /**
+       * @brief The image to display for the right selection handle marker.
+       * @details Name "selectionHandleMarkerImageRight", type Property::MAP.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HANDLE_MARKER_IMAGE_RIGHT,
+
+      /**
+       * @brief The color of the selection highlight.
+       * @details Name "selectionHighlightColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      SELECTION_HIGHLIGHT_COLOR,
+
+      /**
+       * @brief The decorations (handles etc) will positioned within this area on-screen.
+       * @details Name "decorationBoundingBox", type Property::RECTANGLE.
+       * @SINCE_1_0.0
+       */
+      DECORATION_BOUNDING_BOX,
+
+      /**
+       * @brief The settings to relating to the System's Input Method, Key and Value.
+       * @details Name "inputMethodSettings", type Property::MAP.
+       *
+       * @note VARIATION key can be changed depending on PANEL_LAYOUT.
+       * For example, when PANEL_LAYOUT key is InputMethod::PanelLayout::NORMAL,
+       * then VARIATION would be among NORMAL, WITH_FILENAME, and WITH_PERSON_NAME in Dali::InputMethod::NormalLayout.
+       * For more information, see Dali::InputMethod::Category.
+       *
+       * Example Usage:
+       * @code
+       *   Property::Map propertyMap;
+       *   InputMethod::PanelLayout::Type panelLayout = InputMethod::PanelLayout::NUMBER;
+       *   InputMethod::AutoCapital::Type autoCapital = InputMethod::AutoCapital::WORD;
+       *   InputMethod::ButtonAction::Type buttonAction = InputMethod::ButtonAction::GO;
+       *   int inputVariation = 1;
+       *   propertyMap["PANEL_LAYOUT"] = panelLayout;
+       *   propertyMap["AUTO_CAPITALIZE"] = autoCapital;
+       *   propertyMap["BUTTON_ACTION"] = buttonAction;
+       *   propertyMap["VARIATION"] = inputVariation;
+       *
+       *   field.SetProperty( TextField::Property::INPUT_METHOD_SETTINGS, propertyMap );
+       * @endcode
+       * @SINCE_1_0.0
+       */
+      INPUT_METHOD_SETTINGS,
+
+      /**
+       * @brief The color of the new input text.
+       * @details Name "inputColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      INPUT_COLOR,
+
+      /**
+       * @brief Whether the mark-up processing is enabled.
+       * @details Name "enableMarkup", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       */
+      ENABLE_MARKUP,
+
+      /**
+       * @brief The font's family of the new input text.
+       * @details Name "inputFontFamily", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      INPUT_FONT_FAMILY,
+
+      /**
+       * @brief The font's style of the new input text.
+       * @details Name "inputFontStyle", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_FONT_STYLE,
+
+      /**
+       * @brief The font's size of the new input text in points.
+       * @details Name "inputPointSize", type Property::FLOAT.
+       * @SINCE_1_0.0
+       */
+      INPUT_POINT_SIZE,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::UNDERLINE
+       */
+      UNDERLINE,
+
+      /**
+       * @brief The underline parameters of the new input text.
+       * @details Name "inputUnderline", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_UNDERLINE,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::SHADOW
+       */
+      SHADOW,
+
+      /**
+       * @brief The shadow parameters of the new input text.
+       * @details Name "inputShadow", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_SHADOW,
+
+      /**
+       * @brief The default emboss parameters.
+       * @details Name "emboss", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      EMBOSS,
+
+      /**
+       * @brief The emboss parameters of the new input text.
+       * @details Name "inputEmboss", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_EMBOSS,
+
+      /**
+       * @copydoc Dali::Toolkit::TextLabel::Property::OUTLINE
+       */
+      OUTLINE,
+
+      /**
+       * @brief The outline parameters of the new input text.
+       * @details Name "inputOutline", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      INPUT_OUTLINE,
+
+      /**
+       * @brief Hides the input characters and instead shows a default character for password or pin entry.
+       * @details Name "hiddenInputSettings", type Property::MAP.
+       * @SINCE_1_2.60
+       * @note Optional.
+       * @see HiddenInput::Property
+       */
+      HIDDEN_INPUT_SETTINGS,
+
+      /**
+       * @brief The size of font in pixels.
+       * @details Name "pixelSize", type Property::FLOAT.
+       *          Conversion from Point size to Pixel size:
+       *           Pixel size = Point size * DPI / 72
+       * @SINCE_1_2.60
+       */
+      PIXEL_SIZE,
+
+      /**
+       * @brief Enables Text selection, such as the cursor, handle, clipboard, and highlight color.
+       * @details Name "enableSelection", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      ENABLE_SELECTION,
+
+      /**
+       * @brief Sets the placeholder : text, color, font family, font style, point size, and pixel size.
+       * @details Name "placeholder", type Property::MAP.
+       * Example Usage:
+       * @code
+       *   Property::Map propertyMap;
+       *   propertyMap[ Text::PlaceHolder::Property::TEXT ] = "Setting Placeholder Text";
+       *   propertyMap[ Text::PlaceHolder::Property::TEXT_FOCUSED] = "Setting Placeholder Text Focused";
+       *   propertyMap[ Text::PlaceHolder::Property::COLOR] = Color::RED;
+       *   propertyMap[ Text::PlaceHolder::Property::FONT_FAMILY ] = "Arial";
+       *   propertyMap[ Text::PlaceHolder::Property::POINT_SIZE ] = 12.0f;
+       *   propertyMap[ Text::PlaceHolder::Property::ELLIPSIS ] = true;
+       *
+       *   Property::Map fontStyleMap;
+       *   fontStyleMap.Insert( "weight", "bold" );
+       *   fontStyleMap.Insert( "width", "condensed" );
+       *   fontStyleMap.Insert( "slant", "italic" );
+       *   propertyMap[ Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMap;
+       *
+       *   field.SetProperty( TextField::Property::PLACEHOLDER, propertyMap );
+       * @endcode
+       * @SINCE_1_2.60
+       */
+      PLACEHOLDER,
+
+      /**
+       * @brief Whether we should show the ellipsis if it is required.
+       * @details Name "ellipsis", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       * @note PLACEHOLDER map is used to add ellipsis to placeholder text.
+       */
+      ELLIPSIS,
+    };
+  };
+
+  /**
+   * @brief Enumeration for specifying how the text is truncated when it does not fit.
+   *
+   * The default value is \e EXCEED_POLICY_CLIP.
+   * @SINCE_1_0.0
+   */
+  enum ExceedPolicy
+  {
+    EXCEED_POLICY_ORIGINAL,        ///< The text will be display at original size, and may exceed the TextField boundary. @SINCE_1_0.0
+    EXCEED_POLICY_CLIP             ///< The end of text will be clipped to fit within the TextField. @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Mask used by the signal InputStyleChangedSignal(). Notifies which parameters of the input style have changed.
+   *
+   * @SINCE_1_2_2
+   */
+  struct InputStyle
+  {
+  /**
+   * @brief Mask used by the signal InputStyleChangedSignal().
+   *
+   * @SINCE_1_2_2
+   */
+    enum Mask
+    {
+      NONE         = 0x0000, ///< @SINCE_1_2_2
+      COLOR        = 0x0001, ///< @SINCE_1_2_2
+      FONT_FAMILY  = 0x0002, ///< @SINCE_1_2_2
+      POINT_SIZE   = 0x0004, ///< @SINCE_1_2_2
+      FONT_STYLE   = 0x0008, ///< @SINCE_1_2_2
+      UNDERLINE    = 0x0010, ///< @SINCE_1_2_2
+      SHADOW       = 0x0020, ///< @SINCE_1_2_2
+      EMBOSS       = 0x0040, ///< @SINCE_1_2_2
+      OUTLINE      = 0x0080  ///< @SINCE_1_2_2
+    };
+  };
+
+  // Type Defs
+
+  /**
+   * @brief Text changed signal type.
+   * @SINCE_1_0.0
+   */
+  typedef Signal<void ( TextField ) > TextChangedSignalType;
+
+  /**
+   * @brief Max Characters Exceed signal type.
+   * @SINCE_1_0.0
+   */
+  typedef Signal<void ( TextField ) > MaxLengthReachedSignalType;
+
+  /**
+   * @brief Input Style changed signal type.
+   * @SINCE_1_2_2
+   */
+  typedef Signal<void ( TextField, InputStyle::Mask ) > InputStyleChangedSignalType;
+
+  /**
+   * @brief Creates the TextField control.
+   * @SINCE_1_0.0
+   * @return A handle to the TextField control
+   */
+  static TextField New();
+
+  /**
+   * @brief Creates an empty handle.
+   * @SINCE_1_0.0
+   */
+  TextField();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle The handle to copy from
+   */
+  TextField( const TextField& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle The handle to copy from
+   * @return A reference to this
+   */
+  TextField& operator=( const TextField& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~TextField();
+
+  /**
+   * @brief Downcasts a handle to TextField.
+   *
+   * If the BaseHandle points is a TextField, the downcast returns a valid handle.
+   * If not, the returned handle is left empty.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a TextField or an empty handle
+   */
+  static TextField DownCast( BaseHandle handle );
+
+  // Signals
+
+  /**
+   * @brief This signal is emitted when the text changes.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TextField textField );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to.
+   */
+  TextChangedSignalType& TextChangedSignal();
+
+  /**
+   * @brief This signal is emitted when inserted text exceeds the maximum character limit.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TextField textField );
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  MaxLengthReachedSignalType& MaxLengthReachedSignal();
+
+  /**
+   * @brief This signal is emitted when the input style is updated as a consequence of a change in the cursor position.
+   * i.e. The signal is not emitted when the input style is updated through the property system.
+   *
+   * A callback of the following type may be connected. The @p mask parameter notifies which parts of the style have changed.
+   * @code
+   *   void YourCallbackName( TextField textField, TextField::InputStyle::Mask mask );
+   * @endcode
+   *
+   * @SINCE_1_2_2
+   * @return The signal to connect to
+   */
+  InputStyleChangedSignalType& InputStyleChangedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL TextField( Internal::TextField& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL TextField( Dali::Internal::CustomActor* internal );
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_FIELD_H
diff --git a/dali-toolkit/public-api/controls/text-controls/text-label.cpp b/dali-toolkit/public-api/controls/text-controls/text-label.cpp
new file mode 100644 (file)
index 0000000..7a61615
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 <dali-toolkit/public-api/controls/text-controls/text-label.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/text-label-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+TextLabel TextLabel::New()
+{
+  return Internal::TextLabel::New();
+}
+
+TextLabel TextLabel::New( const std::string& text )
+{
+  TextLabel label = Internal::TextLabel::New();
+  label.SetProperty( TextLabel::Property::TEXT, text );
+
+  return label;
+}
+
+TextLabel::TextLabel()
+{
+}
+
+TextLabel::TextLabel( const TextLabel& handle )
+: Control( handle )
+{
+}
+
+TextLabel& TextLabel::operator=( const TextLabel& handle )
+{
+  if( &handle != this )
+  {
+    Control::operator=( handle );
+  }
+  return *this;
+}
+
+TextLabel::~TextLabel()
+{
+}
+
+TextLabel TextLabel::DownCast( BaseHandle handle )
+{
+  return Control::DownCast<TextLabel, Internal::TextLabel>(handle);
+}
+
+TextLabel::TextLabel( Internal::TextLabel& implementation )
+: Control(implementation)
+{
+}
+
+TextLabel::TextLabel( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer<Internal::TextLabel>( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/text-controls/text-label.h b/dali-toolkit/public-api/controls/text-controls/text-label.h
new file mode 100644 (file)
index 0000000..a3a0c3d
--- /dev/null
@@ -0,0 +1,500 @@
+#ifndef DALI_TOOLKIT_TEXT_LABEL_H
+#define DALI_TOOLKIT_TEXT_LABEL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class TextLabel;
+}
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+/**
+ * @brief A control which renders a short text string.
+ *
+ * Text labels are lightweight, non-editable and do not respond to user input.
+ *
+ * @section TextLabelProperties Properties
+ * |%Property enum                    |String name          |Type            |Writable|Animatable|
+ * |----------------------------------|---------------------|----------------|--------|----------|
+ * | Property::RENDERING_BACKEND      | renderingBackend    |  INTEGER       | O      | X        |
+ * | Property::TEXT                   | text                |  STRING        | O      | X        |
+ * | Property::FONT_FAMILY            | fontFamily          |  STRING        | O      | X        |
+ * | Property::FONT_STYLE             | fontStyle           |  STRING or MAP | O      | X        |
+ * | Property::POINT_SIZE             | pointSize           |  FLOAT         | O      | X        |
+ * | Property::MULTI_LINE             | multiLine           |  BOOLEAN       | O      | X        |
+ * | Property::HORIZONTAL_ALIGNMENT   | horizontalAlignment |  STRING        | O      | X        |
+ * | Property::VERTICAL_ALIGNMENT     | verticalAlignment   |  STRING        | O      | X        |
+ * | Property::TEXT_COLOR             | textColor           |  VECTOR4       | O      | X        |
+ * | Property::ENABLE_MARKUP          | enableMarkup        |  BOOLEAN       | O      | X        |
+ * | Property::ENABLE_AUTO_SCROLL     | enableAutoScroll    |  BOOLEAN       | O      | X        |
+ * | Property::AUTO_SCROLL_SPEED      | autoScrollSpeed     |  INTEGER       | O      | X        |
+ * | Property::AUTO_SCROLL_LOOP_COUNT | autoScrollLoopCount |  INTEGER       | O      | X        |
+ * | Property::AUTO_SCROLL_GAP        | autoScrollGap       |  INTEGER       | O      | X        |
+ * | Property::SHADOW                 | shadow              |  STRING or MAP | O      | X        |
+ * | Property::UNDERLINE              | underline           |  STRING or MAP | O      | X        |
+ *
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API TextLabel : public Control
+{
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1, ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,             ///< Reserve property indices @SINCE_1_0.0
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX, ///< @SINCE_1_2.60
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000 ///< Reserve animatable property indices @SINCE_1_2.60
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the TextLabel class.
+   * @SINCE_1_0.0
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the TextLabel class.
+     * @SINCE_1_0.0
+     */
+    enum
+    {
+      ///////////////////////////////////////////////////////////////////////////////
+      // Event side (non-animatable) properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @DEPRECATED_1_2.53 No longer be supported and will be ignored.
+       * @brief The type of rendering e.g. bitmap-based.
+       * @details Name "renderingBackend", type Property::INT.
+       * @SINCE_1_0.0
+       */
+      RENDERING_BACKEND = PROPERTY_START_INDEX,
+
+      /**
+       * @brief The text to display in UTF-8 format.
+       * @details Name "text", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      TEXT,
+
+      /**
+       * @brief The requested font family to use.
+       * @details Name "fontFamily", type Property::STRING.
+       * @SINCE_1_0.0
+       */
+      FONT_FAMILY,
+
+      /**
+       * @brief The requested font style to use.
+       * @details Name "fontStyle", type Property::STRING or Property::MAP.
+       * @SINCE_1_2.13
+       */
+      FONT_STYLE,
+
+      /**
+       * @brief The size of font in points.
+       * @details Name "pointSize", type Property::FLOAT.
+       *          Conversion from Pixel size to Point size:
+       *           Point size = Pixel size * 72 / DPI
+       * @SINCE_1_0.0
+       */
+      POINT_SIZE,
+
+      /**
+       * @brief The single-line or multi-line layout option.
+       * @details Name "multiLine", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       * @note Default is false.
+       */
+      MULTI_LINE,
+
+      /**
+       * @brief The line horizontal alignment.
+       * @details Name "horizontalAlignment", type Property::STRING or type HorizontalAlignment::Type (Property::INTEGER)
+       *          Values "BEGIN", "CENTER", "END", default BEGIN.
+       * @note Return type is Property::STRING
+       * @SINCE_1_0.0
+       */
+      HORIZONTAL_ALIGNMENT,
+
+      /**
+       * @brief The line vertical alignment.
+       * @details Name "verticalAlignment", type Property::STRING or type VerticalAlignment::Type (Property::INTEGER).
+       *          Values "TOP",   "CENTER", "BOTTOM" @SINCE_1_0.0, default TOP.
+       * @note Return type is Property::STRING
+       * @SINCE_1_0.0
+       */
+      VERTICAL_ALIGNMENT,
+
+      /**
+       * @DEPRECATED_1_2.60 Use the new enum value of TEXT_COLOR instead.
+       * @brief The color of the text.
+       * @details Name "unusedPropertyTextColor", type Property::VECTOR4.
+       * @SINCE_1_0.0
+       */
+      UNUSED_PROPERTY_TEXT_COLOR,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_01,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_02,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_03,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_04,
+
+      /**
+       * @brief This property is removed because it's deprecated.
+       */
+      RESERVED_PROPERTY_05,
+
+      /**
+       * @brief Whether the mark-up processing is enabled.
+       * @details Name "enableMarkup", type Property::BOOLEAN.
+       * @SINCE_1_0.0
+       * @note Default is false.
+       */
+      ENABLE_MARKUP,
+
+      /**
+       * @brief Starts or stops auto scrolling.
+       * @details Name "enableAutoScroll", type Property::BOOLEAN.
+       * @SINCE_1_1.35
+       * @note Default is false.
+       */
+      ENABLE_AUTO_SCROLL,
+
+      /**
+       * @brief Sets the speed of scrolling in pixels per second.
+       * @details Name "autoScrollSpeed", type Property::INT.
+       * @SINCE_1_1.35
+       * @note Default in style sheet.
+       */
+      AUTO_SCROLL_SPEED,
+
+      /**
+       * @brief Number of complete loops when scrolling enabled.
+       * @details Name "autoScrollLoopCount", type Property::INT.
+       * @SINCE_1_1.35
+       * @note Default in style sheet.
+       */
+      AUTO_SCROLL_LOOP_COUNT,
+
+      /**
+       * @brief Gap before scrolling wraps.
+       * @details Name "autoScrollGap", type Property::INT.
+       * @SINCE_1_1.35
+       * @note Default in style sheet but can be overridden to prevent same text being shown at start and end.
+       * @note Displayed gap size is not guaranteed if the text length plus gap exceeds the maximum texture size (i.e. GL_MAX_TEXTURE_SIZE).
+       */
+      AUTO_SCROLL_GAP,
+
+      /**
+       * @brief The default extra space between lines in points.
+       * @details Name "lineSpacing", type Property::FLOAT.
+       * @SINCE_1_1.37
+       */
+      LINE_SPACING,
+
+      /**
+       * @brief The default underline parameters.
+       * @details Name "underline", type Property::MAP.
+       *
+       * The underline map contains the following keys:
+       *
+       * | %Property Name       | Type     | Required | Description                                                                                                        |
+       * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+       * | enable               | BOOLEAN  | No       | True to enable the underline or false to disable (the default value is false)                                      |
+       * | color                | VECTOR4  | No       | The color of the underline (the default value is Color::BLACK)                                                     |
+       * | height               | FLOAT    | No       | The height of the underline (the default value is 0)                                                               |
+       *
+       * @SINCE_1_2.13
+       */
+      UNDERLINE,
+
+      /**
+       * @brief The default shadow parameters.
+       * @details Name "shadow", type Property::MAP.
+       *
+       * The shadow map contains the following keys:
+       *
+       * | %Property Name       | Type     | Required | Description                                                                                                        |
+       * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+       * | color                | VECTOR4  | No       | The color of the shadow (the default value is Color::BLACK)                                                        |
+       * | offset               | VECTOR2  | No       | The offset from the text to draw the shadow in the X and Y axes (the default value is 0 which means no shadow)     |
+       * | blurRadius           | FLOAT    | No       | The radius of blur to be applied to the shadow (the default value is 0 which means no blur)                        |
+       *
+       * @SINCE_1_2.13
+       */
+      SHADOW,
+
+      /**
+       * @brief The default emboss parameters.
+       * @details Name "emboss", type Property::MAP.
+       * @SINCE_1_2.13
+       */
+      EMBOSS,
+
+      /**
+       * @brief The default outline parameters.
+       * @details Name "outline", type Property::MAP.
+       *
+       * The outline map contains the following keys:
+       *
+       * | %Property Name       | Type     | Required | Description                                                                                                        |
+       * |----------------------|----------|----------|--------------------------------------------------------------------------------------------------------------------|
+       * | color                | VECTOR4  | No       | The color of the outline (the default value is Color::WHITE)                                                       |
+       * | width                | INTEGER  | No       | The width of the outline (the default value is 0 which means no outline)                                           |
+       *
+       * @SINCE_1_2.13
+       */
+      OUTLINE,
+
+      /**
+       * @brief The size of font in pixels.
+       * @details Name "pixelSize", type Property::FLOAT.
+       *          Conversion from Point size to Pixel size:
+       *            Pixel size = Point size * DPI / 72
+       * @SINCE_1_2.60
+       */
+      PIXEL_SIZE,
+
+      /**
+       * @brief Whether we should show the ellipsis if required.
+       * @details Name "ellipsis", type Property::BOOLEAN.
+       * @SINCE_1_2.60
+       */
+      ELLIPSIS,
+
+      /**
+       * @brief The amount of time to delay the starting time of auto scrolling and further loops.
+       * @details Name "autoScrollLoopDelay", type Property::FLOAT.
+       * @SINCE_1_2.60
+       */
+      AUTO_SCROLL_LOOP_DELAY,
+
+      /**
+       * @brief The auto scrolling stop behaviour.
+       * @details Name "autoScrollStopMode", type AutoScrollStopMode::Type (Property::INTEGER) or Property::STRING.
+       * @SINCE_1_2.60
+       * @note Default is AutoScrollStopMode::FINISH_LOOP.
+       * @see AutoScrollStopMode::Type
+       */
+      AUTO_SCROLL_STOP_MODE,
+
+      /**
+       * @brief The line count of text.
+       * @details name "lineCount", type Property::INTEGER.
+       * @SINCE_1_2.60
+       * @note This property is read-only.
+       */
+      LINE_COUNT,
+
+      /**
+       * @brief Line wrap mode when text lines are greater than the layout width.
+       * @details Name "lineWrapMode", type Text::LineWrap::Mode (Text::Property::INTEGER) or Property::STRING.
+       * @SINCE_1_2.60
+       * @note Default is Text::LineWrap::WORD.
+       * @note Return type is Text::LineWrap::Mode (Text::Property::INTEGER).
+       * @see Text::LineWrap
+       */
+      LINE_WRAP_MODE,
+
+      ///////////////////////////////////////////////////////////////////////////////
+      // Animatable Properties
+      ///////////////////////////////////////////////////////////////////////////////
+
+      /**
+       * @brief The color of the text.
+       * @details Name "textColor", type Property::VECTOR4.
+       * @SINCE_1_2.60
+       */
+      TEXT_COLOR = ANIMATABLE_PROPERTY_START_INDEX,
+
+      /**
+       * @brief The red component of the text color.
+       * @details Name "textColorRed", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @see TEXT_COLOR
+       */
+      TEXT_COLOR_RED,
+
+      /**
+       * @brief The green component of the text color.
+       * @details Name "textColorGreen", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @see TEXT_COLOR
+       */
+      TEXT_COLOR_GREEN,
+
+      /**
+       * @brief The blue component of the text color.
+       * @details Name "textColorBlue", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @see TEXT_COLOR
+       */
+      TEXT_COLOR_BLUE,
+
+      /**
+       * @brief The alpha component of the text color.
+       * @details Name "textColorAlpha", type Property::FLOAT.
+       * @SINCE_1_2.60
+       * @see TEXT_COLOR
+       */
+      TEXT_COLOR_ALPHA,
+    };
+  };
+
+  /**
+   * @brief The enumerations used for auto scroll stop mode.
+   * @SINCE_1_2.60
+   * @see Property::AUTO_SCROLL_STOP_MODE.
+   */
+  struct AutoScrollStopMode
+  {
+    /**
+     * @brief The enumerations used for auto scroll stop mode.
+     * @SINCE_1_2.60
+     * @see Property::AUTO_SCROLL_STOP_MODE.
+     */
+    enum Type
+    {
+      FINISH_LOOP = 0,  ///< Stop animation after current loop finishes. @SINCE_1_2.60
+      IMMEDIATE         ///< Stop animation immediately and reset position. @SINCE_1_2.60
+    };
+  };
+
+  /**
+   * @brief Creates the TextLabel control.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the TextLabel control
+   */
+  static TextLabel New();
+
+  /**
+   * @brief Creates the TextLabel control.
+   *
+   * @SINCE_1_0.0
+   * @param[in] text The text to display
+   * @return A handle to the TextLabel control
+   */
+  static TextLabel New( const std::string& text );
+
+  /**
+   * @brief Creates an empty handle.
+   * @SINCE_1_0.0
+   */
+  TextLabel();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle The handle to copy from
+   */
+  TextLabel( const TextLabel& handle );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle The handle to copy from
+   * @return A reference to this
+   */
+  TextLabel& operator=( const TextLabel& handle );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~TextLabel();
+
+  /**
+   * @brief Downcasts a handle to TextLabel.
+   *
+   * If the BaseHandle points is a TextLabel, the downcast returns a valid handle.
+   * If not, the returned handle is left empty.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle Handle to an object
+   * @return Handle to a TextLabel or an empty handle
+   */
+  static TextLabel DownCast( BaseHandle handle );
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] implementation The Control implementation
+   */
+  DALI_INTERNAL TextLabel( Internal::TextLabel& implementation );
+
+  /**
+   * @brief Allows the creation of this Control from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_0.0
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  explicit DALI_INTERNAL TextLabel( Dali::Internal::CustomActor* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_LABEL_H
diff --git a/dali-toolkit/public-api/controls/video-view/video-view.cpp b/dali-toolkit/public-api/controls/video-view/video-view.cpp
new file mode 100644 (file)
index 0000000..e709a58
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/controls/video-view/video-view.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/video-view/video-view-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+VideoView::VideoView()
+{
+}
+
+VideoView::VideoView( const VideoView& videoView )
+: Control( videoView )
+{
+}
+
+VideoView& VideoView::operator=( const VideoView& videoView )
+{
+  if( &videoView != this )
+  {
+    Control::operator=( videoView );
+  }
+
+  return *this;
+}
+
+VideoView::~VideoView()
+{
+}
+
+VideoView VideoView::New()
+{
+  return Internal::VideoView::New();
+}
+
+VideoView VideoView::New( const std::string& url )
+{
+  VideoView videoView = Internal::VideoView::New();
+  Dali::Toolkit::GetImpl( videoView ).SetUrl( url );
+  return videoView;
+}
+
+VideoView VideoView::New( bool swCodec )
+{
+  VideoView videoView = Internal::VideoView::New();
+  Dali::Toolkit::GetImpl( videoView ).SetSWCodec( swCodec );
+  return videoView;
+}
+
+VideoView VideoView::New( const std::string& url, bool swCodec )
+{
+  VideoView videoView = Internal::VideoView::New();
+  Dali::Toolkit::GetImpl( videoView ).SetUrl( url );
+  Dali::Toolkit::GetImpl( videoView ).SetSWCodec( swCodec );
+  return videoView;
+}
+
+VideoView VideoView::DownCast( BaseHandle handle )
+{
+  return Control::DownCast< VideoView, Internal::VideoView >( handle );
+}
+
+void VideoView::Play()
+{
+  Dali::Toolkit::GetImpl( *this ).Play();
+}
+
+void VideoView::Pause()
+{
+  Dali::Toolkit::GetImpl( *this ).Pause();
+}
+
+void VideoView::Stop()
+{
+  Dali::Toolkit::GetImpl( *this ).Stop();
+}
+
+void VideoView::Forward( int millisecond )
+{
+  Dali::Toolkit::GetImpl( *this ).Forward( millisecond );
+}
+
+void VideoView::Backward( int millisecond )
+{
+  Dali::Toolkit::GetImpl( *this ).Backward( millisecond );
+}
+
+VideoView::VideoViewSignalType& VideoView::FinishedSignal()
+{
+  return Dali::Toolkit::GetImpl( *this ).FinishedSignal();
+}
+
+VideoView::VideoView( Internal::VideoView& implementation )
+: Control( implementation )
+{
+}
+
+VideoView::VideoView( Dali::Internal::CustomActor* internal )
+: Control( internal )
+{
+  VerifyCustomActorPointer< Internal::VideoView >( internal );
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/controls/video-view/video-view.h b/dali-toolkit/public-api/controls/video-view/video-view.h
new file mode 100755 (executable)
index 0000000..88728ee
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef DALI_TOOLKIT_VIDEO_VIEW_H
+#define DALI_TOOLKIT_VIDEO_VIEW_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+  class VideoView;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_toolkit_controls_video_view
+ * @{
+ */
+
+/**
+ * @brief VideoView is a control for video playback and display.
+ *
+ * For working VideoView, a video plugin for a platform should be provided.
+ *
+ * Signals
+ * | %Signal Name  | Method                  |
+ * |---------------|-------------------------|
+ * | finished      | @ref FinishedSignal()   |
+ * @SINCE_1_1.38
+ *
+ * Actions
+ * | %Action Name    | Attributes                                         | Description                                             |
+ * |-----------------|----------------------------------------------------|---------------------------------------------------------|
+ * | videoPlay       | Doesn't have attributes                            | Plays video. See @ref DoAction()                        |
+ * | videoPause      | Doesn't have attributes                            | Pauses video. See @ref DoAction()                       |
+ * | videoStop       | Doesn't have attributes                            | Stops video. See @ref DoAction()                        |
+ * | videoForward    | The position ( millisecond ) for forward playback  | Sets forward position for playback. See @ref DoAction() |
+ * | videoBackward   | The position ( millisecond ) for backward playback | Sets backward position for playback. See @ref DoAction()|
+ * @SINCE_1_1.38
+ *
+ */
+class DALI_TOOLKIT_API VideoView: public Control
+{
+public:
+
+  // Signal
+  typedef Signal< void (VideoView&) > VideoViewSignalType; ///< Video playback finished signal type @ SINCE_1_1.38
+
+public:
+
+  /**
+   * @brief Enumeration for the start and end property ranges for this control.
+   * @SINCE_1_0.0
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,  ///< @SINCE_1_0.0
+  };
+
+  /**
+   * @brief Enumeration for the instance of properties belonging to the VideoView class.
+   * @SINCE_1_1.38
+   */
+  struct Property
+  {
+    /**
+     * @brief Enumeration for the instance of properties belonging to the VideoView class.
+     * @SINCE_1_1.38
+     */
+    enum
+    {
+      /**
+       * @brief name "video", video file url as string type or Property::Map.
+       * @SINCE_1_1.38
+       * @REMARK_INTERNET
+       * @REMARK_STORAGE
+       */
+      VIDEO = PROPERTY_START_INDEX,
+
+     /**
+       * @brief name "looping", looping status, true or false.
+       * @SINCE_1_1.38
+       */
+      LOOPING,
+
+     /**
+       * @brief name "muted", mute status, true or false.
+       * @SINCE_1_1.38
+       */
+      MUTED,
+
+     /**
+       * @brief name "volume", left and right volume scalar as float type, Property::Map with two values ( "left" and "right" ).
+       * @SINCE_1_1.38
+       */
+      VOLUME,
+
+     /**
+       * @brief name "underlay", Video rendering by underlay, true or false
+       * This shows video composited underneath the window by the system. This means it may ignore rotation of the video-view
+       * If false, video-view shows decoded frame images sequentially.
+       * If Platform or video plugin doesn't support decoded frame images, this should always be true.
+       * @SINCE_1_2.62
+       * @REMARK_RAWVIDEO
+       */
+      UNDERLAY,
+
+     /**
+       * @brief The play position (millisecond) of the video.
+       * @details Name "playPosition", type Property::INTEGER
+       * @SINCE_1_3_9
+       */
+      PLAY_POSITION,
+
+      /**
+        * @brief The display mode of the video.
+        * @SINCE_1_3_15
+        */
+      DISPLAY_MODE
+    };
+  };
+
+  /**
+   * @brief The values of this enum determine how the video should be display mode to the view
+   * @SINCE_1_3_15
+   */
+  struct DisplayMode
+  {
+    /**
+     * @brief The values of this enum determine how the video should be display mode to the view.
+     * @SINCE_1_3_15
+     */
+    enum Type
+    {
+      /**
+       * @brief Letter box
+       * @SINCE_1_3_15
+       */
+      LETTER_BOX = 0,
+      /**
+       * @brief Origin size
+       * @SINCE_1_3_15
+       */
+      ORIGIN_SIZE,
+      /**
+       * @brief Full-screen
+       * @SINCE_1_3_15
+       */
+      FULL_SCREEN,
+      /**
+       * @brief Cropped full-screen
+       * @SINCE_1_3_15
+       */
+      CROPPED_FULL,
+      /**
+       * @brief  Origin size (if surface size is larger than video size(width/height)) or Letter box (if video size(width/height) is larger than surface size)
+       * @SINCE_1_3_15
+       */
+      ORIGIN_OR_LETTER,
+      /**
+       * @brief  Region of Interest
+       * @SINCE_1_3_15
+       */
+      DST_ROI
+    };
+  };
+
+public:
+
+  /**
+   * @brief Creates an initialized VideoView.
+   * @SINCE_1_1.38
+   * @return A handle to a newly allocated Dali ImageView
+   *
+   */
+  static VideoView New();
+
+  /**
+   * @brief Creates an initialized VideoView.
+   * If the string is empty, VideoView will not display anything.
+   *
+   * @SINCE_1_1.38
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The url of the video resource to display
+   * @return A handle to a newly allocated Dali VideoView
+   */
+  static VideoView New( const std::string& url );
+
+  /**
+   * @brief Creates an initialized VideoView.
+   * @SINCE_1_3_9
+   * @param[in] swCodec Video rendering by H/W codec if false
+   * @return A handle to a newly allocated Dali ImageView
+   *
+   * @note If platform or target does not support sw codec, video-view shows an error message and video by default codec type
+   */
+  static VideoView New( bool swCodec );
+
+  /**
+   * @brief Creates an initialized VideoView.
+   * If the string is empty, VideoView will not display anything.
+   *
+   * @SINCE_1_3_9
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The url of the video resource to display
+   * @param[in] swCodec Video rendering by H/W codec if false
+   * @return A handle to a newly allocated Dali VideoView
+   *
+   * @note If platform or target does not support sw codec, video-view shows an error message and video by default codec type
+   */
+  static VideoView New( const std::string& url, bool swCodec );
+
+  /**
+   * @brief Creates an uninitialized VideoView.
+   * @SINCE_1_1.38
+   */
+  VideoView();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handel types must not contain data or virtual methods.
+   * @SINCE_1_1.38
+   */
+  ~VideoView();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_1.38
+   * @param[in] videoView VideoView to copy. The copied VideoView will point at the same implementation
+   */
+  VideoView( const VideoView& videoView );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_1.38
+   * @param[in] videoView The VideoView to assign from
+   * @return The updated VideoView
+   */
+  VideoView& operator=( const VideoView& videoView );
+
+  /**
+   * @brief Downcasts a handle to VideoView handle.
+   *
+   * If handle points to a VideoView, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_1.38
+   * @param[in] handle Handle to an object
+   * @return Handle to a VideoView or an uninitialized handle
+   */
+  static VideoView DownCast( BaseHandle handle );
+
+  /**
+   * @brief Starts the video playback.
+   * @SINCE_1_1.38
+   */
+  void Play();
+
+  /**
+   * @brief Pauses the video playback.
+   * @SINCE_1_1.38
+   */
+  void Pause();
+
+  /**
+   * @brief Stops the video playback.
+   * @SINCE_1_1.38
+   */
+  void Stop();
+
+  /**
+   * @brief Seeks forward by the specified number of milliseconds.
+   *
+   * @SINCE_1_1.38
+   * @param[in] millisecond The position for forward playback
+   */
+  void Forward( int millisecond );
+
+  /**
+   * @brief Seeks backward by the specified number of milliseconds.
+   *
+   * @SINCE_1_1.38
+   * @param[in] millisecond The position for backward playback
+   */
+  void Backward( int millisecond );
+
+  /**
+   * @brief Connects to this signal to be notified when a video playback is finished.
+   *
+   * @SINCE_1_1.38
+   * @return A signal object to connect with
+   */
+  VideoViewSignalType& FinishedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Toolkit::Internal implementation.
+   *
+   * @SINCE_1_1.38
+   * @param[in] implementation The VideoView implementation
+   */
+  DALI_INTERNAL VideoView( Internal::VideoView& implementation );
+
+  /**
+   * @brief Allows the creation of this VideoView from an Internal::CustomActor pointer.
+   *
+   * @SINCE_1_1.38
+   * @param[in] internal A pointer to the internal CustomActor
+   */
+  DALI_INTERNAL VideoView( Dali::Internal::CustomActor* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VIDEO_VIEW_H
diff --git a/dali-toolkit/public-api/dali-toolkit-common.h b/dali-toolkit/public-api/dali-toolkit-common.h
new file mode 100755 (executable)
index 0000000..d16ef81
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_COMMON_H
+#define DALI_TOOLKIT_COMMON_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/dali-adaptor-common.h>
+
+/*
+ * Definitions for shared library support.
+ *
+ * If a library is configured with --enable-exportall or --enable-debug
+ * then HIDE_DALI_INTERNALS is not defined, and nothing is hidden.
+ * If it is configured without these options (the default), then HIDE_INTERNALS
+ * is defined when building the library, visibility is automatically hidden, and the explicit
+ * defines below come into use.
+ * When building a library that uses DALI, HIDE_DALI_INTERNALS.
+ */
+#if __GNUC__ >= 4
+#  ifndef HIDE_DALI_INTERNALS
+#    define DALI_TOOLKIT_API
+#  else
+#    define DALI_TOOLKIT_API __attribute__ ((visibility ("default")))
+#  endif
+#else
+#ifdef WIN32
+#ifdef BUILDING_DALI_TOOLKIT
+/** Visibility attribute to hide declarations */
+#  define DALI_TOOLKIT_API __declspec(dllexport)
+#else
+/** Visibility attribute to hide declarations */
+#  define DALI_TOOLKIT_API __declspec(dllimport)
+#endif
+#else
+/** Visibility attribute to show declarations */
+#  define DALI_TOOLKIT_API
+#endif
+#endif
+
+#endif // DALI_TOOLKIT_COMMON_H
diff --git a/dali-toolkit/public-api/dali-toolkit-version.cpp b/dali-toolkit/public-api/dali-toolkit-version.cpp
new file mode 100644 (file)
index 0000000..464d107
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2020 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.
+ *
+ */
+
+// HEADER
+#include <dali-toolkit/public-api/dali-toolkit-version.h>
+
+// EXTERNAL INCLUDES
+#ifdef DEBUG_ENABLED
+#include <iostream>
+#endif
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+const unsigned int TOOLKIT_MAJOR_VERSION = 1;
+const unsigned int TOOLKIT_MINOR_VERSION = 5;
+const unsigned int TOOLKIT_MICRO_VERSION = 8;
+const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
+
+#ifdef DEBUG_ENABLED
+namespace
+{
+/// Allows the printing of the version number ONLY when debug is enabled
+struct PrintVersion
+{
+  PrintVersion()
+  {
+    std::cerr << "DALi Toolkit:   " << TOOLKIT_MAJOR_VERSION << "." << TOOLKIT_MINOR_VERSION << "." << TOOLKIT_MICRO_VERSION << " (" << TOOLKIT_BUILD_DATE << ")" << std::endl;
+  }
+};
+PrintVersion TOOLKIT_VERSION;
+} // unnamed namespace
+#endif
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/dali-toolkit-version.h b/dali-toolkit/public-api/dali-toolkit-version.h
new file mode 100755 (executable)
index 0000000..5f174dd
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef DALI_TOOLKIT_VERSION_H
+#define DALI_TOOLKIT_VERSION_H
+
+/*
+ * Copyright (c) 2019 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 <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+DALI_TOOLKIT_API extern const unsigned int TOOLKIT_MAJOR_VERSION; ///< The major version number of the Toolkit.
+DALI_TOOLKIT_API extern const unsigned int TOOLKIT_MINOR_VERSION; ///< The minor version number of the Toolkit.
+DALI_TOOLKIT_API extern const unsigned int TOOLKIT_MICRO_VERSION; ///< The micro version number of the Toolkit.
+DALI_TOOLKIT_API extern const char * const TOOLKIT_BUILD_DATE;    ///< The date/time the Toolkit library was built.
+} // namespace Toolkit
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VERSION_H
diff --git a/dali-toolkit/public-api/enums.cpp b/dali-toolkit/public-api/enums.cpp
new file mode 100644 (file)
index 0000000..e520bbc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <dali-toolkit/public-api/enums.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+bool IsVertical(ControlOrientation::Type orientation)
+{
+  return (orientation == ControlOrientation::Up ||
+          orientation == ControlOrientation::Down);
+}
+
+bool IsHorizontal(ControlOrientation::Type orientation)
+{
+  return (orientation == ControlOrientation::Left ||
+          orientation == ControlOrientation::Right);
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/enums.h b/dali-toolkit/public-api/enums.h
new file mode 100644 (file)
index 0000000..e2529f2
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_TOOLKIT_ENUMS_H
+#define DALI_TOOLKIT_ENUMS_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+/**
+ * @brief DALi Toolkit namespace.
+ * @SINCE_1_0.0
+ */
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+/**
+ * @brief Control Orientation namespace.
+ * @SINCE_1_0.0
+ */
+namespace ControlOrientation
+{
+
+/**
+ * @brief Enumeration for the internal orientation of a control.
+ * @SINCE_1_0.0
+ */
+enum Type
+{
+  Up,   ///< The contents of control are in a vertical layout, from top to bottom @SINCE_1_0.0
+  Left, ///< The contents of control are in a horizontal layout, from left to right @SINCE_1_0.0
+  Down, ///< The contents of control are in a vertical layout, from bottom to top @SINCE_1_0.0
+  Right ///< The contents of control are in a horizontal layout, from right to left @SINCE_1_0.0
+};
+
+} // namespace ControlOrientation
+
+/**
+ * @brief Queries whether an orientation is vertical.
+ *
+ * @param[in] orientation The orientation
+ * @return true if the orientation is vertical
+ */
+DALI_TOOLKIT_API bool IsVertical(ControlOrientation::Type orientation);
+
+/**
+ * @brief Queries whether an orientation is horizontal.
+ *
+ * @SINCE_1_0.0
+ * @param[in] orientation The orientation
+ * @return true if the orientation is horizontal
+ */
+DALI_TOOLKIT_API bool IsHorizontal(ControlOrientation::Type orientation);
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ENUMS_H
diff --git a/dali-toolkit/public-api/file.list b/dali-toolkit/public-api/file.list
new file mode 100644 (file)
index 0000000..732531f
--- /dev/null
@@ -0,0 +1,187 @@
+# Set the source directory
+SET( public_api_src_dir ${ROOT_SRC_DIR}/dali-toolkit/public-api )
+
+# Add local source files here
+SET( public_api_src_files
+  ${public_api_src_dir}/controls/control-impl.cpp
+  ${public_api_src_dir}/controls/control.cpp
+  ${public_api_src_dir}/controls/alignment/alignment.cpp
+  ${public_api_src_dir}/controls/buttons/button.cpp
+  ${public_api_src_dir}/controls/buttons/check-box-button.cpp
+  ${public_api_src_dir}/controls/buttons/push-button.cpp
+  ${public_api_src_dir}/controls/buttons/radio-button.cpp
+  ${public_api_src_dir}/controls/flex-container/flex-container.cpp
+  ${public_api_src_dir}/controls/image-view/image-view.cpp
+  ${public_api_src_dir}/controls/model3d-view/model3d-view.cpp
+  ${public_api_src_dir}/controls/progress-bar/progress-bar.cpp
+  ${public_api_src_dir}/controls/scroll-bar/scroll-bar.cpp
+  ${public_api_src_dir}/controls/scrollable/item-view/default-item-layout.cpp
+  ${public_api_src_dir}/controls/scrollable/item-view/item-layout.cpp
+  ${public_api_src_dir}/controls/scrollable/item-view/item-view.cpp
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-constraints.cpp
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-effect.cpp
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect.cpp
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view.cpp
+  ${public_api_src_dir}/controls/scrollable/scrollable.cpp
+  ${public_api_src_dir}/controls/slider/slider.cpp
+  ${public_api_src_dir}/controls/table-view/table-view.cpp
+  ${public_api_src_dir}/controls/text-controls/text-editor.cpp
+  ${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/video-view/video-view.cpp
+  ${public_api_src_dir}/image-loader/async-image-loader.cpp
+  ${public_api_src_dir}/image-loader/sync-image-loader.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
+  ${public_api_src_dir}/enums.cpp
+)
+
+# Add public header files here
+SET( public_api_header_files
+  ${public_api_src_dir}/dali-toolkit-version.h
+  ${public_api_src_dir}/dali-toolkit-common.h
+  ${public_api_src_dir}/enums.h
+  ${public_api_src_dir}/align-enumerations.h
+  ${public_api_src_dir}/toolkit-property-index-ranges.h
+)
+
+SET( public_api_controls_header_files
+  ${public_api_src_dir}/controls/control-impl.h
+  ${public_api_src_dir}/controls/control.h
+)
+
+SET( public_api_alignment_header_files
+  ${public_api_src_dir}/controls/alignment/alignment.h
+)
+
+SET( public_api_buttons_header_files
+  ${public_api_src_dir}/controls/buttons/button.h
+  ${public_api_src_dir}/controls/buttons/check-box-button.h
+  ${public_api_src_dir}/controls/buttons/push-button.h
+  ${public_api_src_dir}/controls/buttons/radio-button.h
+)
+
+SET( public_api_model3d_view_header_files
+  ${public_api_src_dir}/controls/model3d-view/model3d-view.h
+)
+
+SET( public_api_flex_container_header_files
+  ${public_api_src_dir}/controls/flex-container/flex-container.h
+)
+
+SET( public_api_image_view_header_files
+  ${public_api_src_dir}/controls/image-view/image-view.h
+)
+
+SET( public_api_item_view_header_files
+  ${public_api_src_dir}/controls/scrollable/item-view/default-item-layout.h
+  ${public_api_src_dir}/controls/scrollable/item-view/default-item-layout-property.h
+  ${public_api_src_dir}/controls/scrollable/item-view/item-factory.h
+  ${public_api_src_dir}/controls/scrollable/item-view/item-layout.h
+  ${public_api_src_dir}/controls/scrollable/item-view/item-view-declarations.h
+  ${public_api_src_dir}/controls/scrollable/item-view/item-view.h
+)
+
+SET( public_api_image_loader_header_files
+  ${public_api_src_dir}/image-loader/async-image-loader.h
+  ${public_api_src_dir}/image-loader/sync-image-loader.h
+)
+
+SET( public_api_progress_bar_header_files
+  ${public_api_src_dir}/controls/progress-bar/progress-bar.h
+)
+
+SET( public_api_scrollable_header_files
+  ${public_api_src_dir}/controls/scrollable/scrollable.h
+)
+
+SET( public_api_scroll_bar_header_files
+  ${public_api_src_dir}/controls/scroll-bar/scroll-bar.h
+)
+
+SET( public_api_scroll_view_header_files
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-mode.h
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-constraints.h
+  ${public_api_src_dir}/controls/scrollable/scroll-view/scroll-view-effect.h
+  ${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
+)
+
+SET( public_api_slider_header_files
+  ${public_api_src_dir}/controls/slider/slider.h
+)
+
+SET( public_api_styling_header_files
+  ${public_api_src_dir}/styling/style-manager.h
+)
+
+SET( public_api_table_view_header_files
+  ${public_api_src_dir}/controls/table-view/table-view.h
+)
+
+SET( public_api_text_controls_header_files
+  ${public_api_src_dir}/controls/text-controls/hidden-input-properties.h
+  ${public_api_src_dir}/controls/text-controls/placeholder-properties.h
+  ${public_api_src_dir}/controls/text-controls/text-editor.h
+  ${public_api_src_dir}/controls/text-controls/text-label.h
+  ${public_api_src_dir}/controls/text-controls/text-field.h
+)
+
+SET( public_api_accessibility_manager_header_files
+  ${public_api_src_dir}/accessibility-manager/accessibility-manager.h
+)
+
+SET( public_api_focus_manager_header_files
+  ${public_api_src_dir}/focus-manager/keyboard-focus-manager.h
+)
+
+SET( public_api_text_header_files
+  ${public_api_src_dir}/text/rendering-backend.h
+  ${public_api_src_dir}/text/text-enumerations.h
+)
+
+SET( public_api_video_view_header_files
+  ${public_api_src_dir}/controls/video-view/video-view.h
+)
+
+SET( public_api_visuals_header_files
+  ${public_api_src_dir}/visuals/border-visual-properties.h
+  ${public_api_src_dir}/visuals/color-visual-properties.h
+  ${public_api_src_dir}/visuals/gradient-visual-properties.h
+  ${public_api_src_dir}/visuals/image-visual-properties.h
+  ${public_api_src_dir}/visuals/mesh-visual-properties.h
+  ${public_api_src_dir}/visuals/primitive-visual-properties.h
+  ${public_api_src_dir}/visuals/visual-properties.h
+  ${public_api_src_dir}/visuals/text-visual-properties.h
+)
+
+SET( SOURCES ${SOURCES}
+  ${public_api_src_files}
+)
+
+SET( PUBLIC_API_HEADERS ${PUBLIC_API_HEADERS}
+  ${public_api_header_files}
+  ${public_api_controls_header_files}
+  ${public_api_alignment_header_files}
+  ${public_api_buttons_header_files}
+  ${public_api_model3d_view_header_files}
+  ${public_api_flex_container_header_files}
+  ${public_api_image_view_header_files}
+  ${public_api_item_view_header_files}
+  ${public_api_image_loader_header_files}
+  ${public_api_progress_bar_header_files}
+  ${public_api_scrollable_header_files}
+  ${public_api_scroll_bar_header_files}
+  ${public_api_scroll_view_header_files}
+  ${public_api_slider_header_files}
+  ${public_api_styling_header_files}
+  ${public_api_table_view_header_files}
+  ${public_api_text_controls_header_files}
+  ${public_api_accessibility_manager_header_files}
+  ${public_api_focus_manager_header_files}
+  ${public_api_text_header_files}
+  ${public_api_video_view_header_files}
+  ${public_api_visuals_header_files}
+)
diff --git a/dali-toolkit/public-api/focus-manager/keyboard-focus-manager.cpp b/dali-toolkit/public-api/focus-manager/keyboard-focus-manager.cpp
new file mode 100644 (file)
index 0000000..d42a344
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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 <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+
+// EXTERNAL INCLUDES
+#include <cstring> // for strcmp
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+KeyboardFocusManager::KeyboardFocusManager()
+{
+}
+
+KeyboardFocusManager::~KeyboardFocusManager()
+{
+}
+
+KeyboardFocusManager KeyboardFocusManager::Get()
+{
+  return Internal::KeyboardFocusManager::Get();
+}
+
+KeyboardFocusManager::KeyboardFocusManager(Internal::KeyboardFocusManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+bool KeyboardFocusManager::SetCurrentFocusActor(Actor actor)
+{
+  return GetImpl(*this).SetCurrentFocusActor(actor);
+}
+
+Actor KeyboardFocusManager::GetCurrentFocusActor()
+{
+  return GetImpl(*this).GetCurrentFocusActor();
+}
+
+bool KeyboardFocusManager::MoveFocus(Control::KeyboardFocus::Direction direction)
+{
+  return GetImpl(*this).MoveFocus(direction);
+}
+
+void KeyboardFocusManager::ClearFocus()
+{
+  GetImpl(*this).ClearFocus();
+}
+
+void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
+{
+  // deprecated method.
+  GetImpl(*this).SetAsFocusGroup(actor, isFocusGroup);
+}
+
+bool KeyboardFocusManager::IsFocusGroup(Actor actor) const
+{
+  // deprecated method.
+  return GetImpl(*this).IsFocusGroup(actor);
+}
+
+Actor KeyboardFocusManager::GetFocusGroup(Actor actor)
+{
+  return GetImpl(*this).GetFocusGroup(actor);
+}
+
+void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
+{
+  GetImpl(*this).SetFocusGroupLoop(enabled);
+}
+
+bool KeyboardFocusManager::GetFocusGroupLoop() const
+{
+  return GetImpl(*this).GetFocusGroupLoop();
+}
+
+void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator)
+{
+  GetImpl(*this).SetFocusIndicatorActor(indicator);
+}
+
+Actor KeyboardFocusManager::GetFocusIndicatorActor()
+{
+  return GetImpl(*this).GetFocusIndicatorActor();
+}
+
+void KeyboardFocusManager::MoveFocusBackward()
+{
+  return GetImpl(*this).MoveFocusBackward();
+}
+
+KeyboardFocusManager::PreFocusChangeSignalType& KeyboardFocusManager::PreFocusChangeSignal()
+{
+  return GetImpl(*this).PreFocusChangeSignal();
+}
+
+KeyboardFocusManager::FocusChangedSignalType& KeyboardFocusManager::FocusChangedSignal()
+{
+  return GetImpl(*this).FocusChangedSignal();
+}
+
+KeyboardFocusManager::FocusGroupChangedSignalType& KeyboardFocusManager::FocusGroupChangedSignal()
+{
+  return GetImpl(*this).FocusGroupChangedSignal();
+}
+
+KeyboardFocusManager::FocusedActorEnterKeySignalType& KeyboardFocusManager::FocusedActorEnterKeySignal()
+{
+  return GetImpl(*this).FocusedActorEnterKeySignal();
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h b/dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h
new file mode 100644 (file)
index 0000000..56b57cf
--- /dev/null
@@ -0,0 +1,316 @@
+#ifndef DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_H
+#define DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class KeyboardFocusManager;
+}
+/**
+ * @addtogroup dali_toolkit_managers
+ * @{
+ */
+
+/**
+ * @brief Provides the functionality of handling keyboard navigation
+ * and maintaining the two dimensional keyboard focus chain.
+ *
+ * It provides functionality of setting the focus and moving the focus
+ * in four directions (i.e. Left, Right, Up and Down). It also draws a
+ * highlight for the focused actor and emits a signal when the focus
+ * is changed.
+ *
+ * Signals
+ * | %Signal Name                 | Method                             |
+ * |------------------------------|------------------------------------|
+ * | keyboardPreFocusChange       | @ref PreFocusChangeSignal()        |
+ * | keyboardFocusChanged         | @ref FocusChangedSignal()          |
+ * | keyboardFocusGroupChanged    | @ref FocusGroupChangedSignal()     |
+ * | keyboardFocusedActorEnterKey | @ref FocusedActorEnterKeySignal()  |
+ * @SINCE_1_0.0
+ */
+class DALI_TOOLKIT_API KeyboardFocusManager : public BaseHandle
+{
+
+public:
+
+  /// @brief Pre focus change signal
+  typedef Signal< Actor ( Actor, Actor, Control::KeyboardFocus::Direction ) > PreFocusChangeSignalType;
+
+  /// @brief Focus changed signal
+  typedef Signal< void ( Actor, Actor ) > FocusChangedSignalType;
+
+  /// @brief Focus group changed signal
+  typedef Signal< void ( Actor, bool ) > FocusGroupChangedSignalType;
+
+  /// @brief Focused actor has the enter key pressed signal
+  typedef Signal< void ( Actor ) > FocusedActorEnterKeySignalType;
+
+  /**
+   * @brief Creates a KeyboardFocusManager handle; this can be initialized with KeyboardFocusManager::New().
+   *
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_0.0
+   */
+  KeyboardFocusManager();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~KeyboardFocusManager();
+
+  /**
+   * @brief Gets the singleton of KeyboardFocusManager object.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the KeyboardFocusManager control
+   */
+  static KeyboardFocusManager Get();
+
+  /**
+   * @brief Moves the keyboard focus to the given actor.
+   *
+   * Only one actor can be focused at the same time.  The actor must
+   * be in the stage already and keyboard focusable.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be focused
+   * @return Whether the focus is successful or not
+   * @pre The KeyboardFocusManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  bool SetCurrentFocusActor(Actor actor);
+
+  /**
+   * @brief Gets the current focused actor.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the current focused actor or an empty handle if no actor is focused
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  Actor GetCurrentFocusActor();
+
+  /**
+   * @brief Moves the focus to the next focusable actor in the focus
+   * chain in the given direction (according to the focus traversal
+   * order).
+   *
+   * @SINCE_1_0.0
+   * @param direction The direction of focus movement
+   * @return true if the movement was successful
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  bool MoveFocus(Control::KeyboardFocus::Direction direction);
+
+  /**
+   * @brief Clears the focus from the current focused actor if any, so
+   * that no actor is focused in the focus chain.
+   *
+   * It will emit focus changed signal without current focused actor.
+   * @SINCE_1_0.0
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  void ClearFocus();
+
+  /**
+   * @brief Sets whether the focus movement should be looped within the same focus group.
+   *
+   * The focus movement is not looped by default.
+   * @SINCE_1_0.0
+   * @param enabled Whether the focus movement should be looped
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  void SetFocusGroupLoop(bool enabled);
+
+  /**
+   * @brief Gets whether the focus movement should be looped within the same focus group.
+   *
+   * @SINCE_1_0.0
+   * @return Whether the focus movement should be looped
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  bool GetFocusGroupLoop() const;
+
+  /**
+   * @brief Sets whether an actor is a focus group that can limit the
+   * scope of focus movement to its child actors in the focus chain.
+   *
+   * Layout controls set themselves as focus groups by default.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be set as a focus group
+   * @param isFocusGroup Whether to set the actor as a focus group or not
+   * @pre The KeyboardFocusManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  void SetAsFocusGroup(Actor actor, bool isFocusGroup);
+
+  /**
+   * @brief Checks whether the actor is set as a focus group or not.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be checked
+   * @return Whether the actor is set as a focus group
+   * @pre The KeyboardFocusManager has been initialized.
+   * @pre The Actor has been initialized.
+   */
+  bool IsFocusGroup(Actor actor) const;
+
+  /**
+   * @brief Returns the closest ancestor of the given actor that is a focus group.
+   *
+   * @SINCE_1_0.0
+   * @param actor The actor to be checked for its focus group
+   * @return The focus group the given actor belongs to or an empty handle if the given actor
+   * doesn't belong to any focus group
+   */
+  Actor GetFocusGroup(Actor actor);
+
+  /**
+   * @brief Sets the focus indicator actor.
+   *
+   * This will replace the default focus indicator actor in
+   * KeyboardFocusManager and will be added to the focused actor as a
+   * highlight.
+   *
+   * @SINCE_1_0.0
+   * @param indicator The indicator actor to be added
+   * @pre The KeyboardFocusManager has been initialized.
+   * @pre The indicator actor has been initialized.
+   */
+  void SetFocusIndicatorActor(Actor indicator);
+
+  /**
+   * @brief Gets the focus indicator actor.
+   *
+   * @SINCE_1_0.0
+   * @return A handle to the focus indicator actor
+   * @pre The KeyboardFocusManager has been initialized.
+   */
+  Actor GetFocusIndicatorActor();
+
+  /**
+   * @brief Move the focus to prev focused actor
+   *
+   * @SINCE_1_2.19
+   */
+  void MoveFocusBackward();
+
+public: // Signals
+
+  /**
+   * @brief This signal is emitted before the focus is going to be changed.
+   *
+   * KeyboardFocusManager makes the best guess for which actor to
+   * focus towards the given direction, but applications might want to
+   * change that. By connecting with this signal, they can check the
+   * proposed actor to focus and return a different actor if they
+   * wish. This signal is only emitted when the navigation key is
+   * pressed and KeyboardFocusManager tries to move the focus
+   * automatically. It won't be emitted for focus movement by calling
+   * SetCurrentFocusActor directly.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   Actor YourCallbackName(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  PreFocusChangeSignalType& PreFocusChangeSignal();
+
+  /**
+   * @brief This signal is emitted after the current focused actor has been changed.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor originalFocusedActor, Actor currentFocusedActor);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusChangedSignalType& FocusChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the focus group has been changed.
+   *
+   * If the current focus group has a parent layout control,
+   * KeyboardFocusManager will make the best guess for the next focus
+   * group to move the focus to in the given direction (forward or
+   * backward). If not, the application has to set the new focus.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor currentFocusedActor, bool forward);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusGroupChangedSignalType& FocusGroupChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the current focused actor has the enter key pressed on it.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Actor enterPressedActor);
+   * @endcode
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   * @pre The Object has been initialized.
+   */
+  FocusedActorEnterKeySignalType& FocusedActorEnterKeySignal();
+
+  // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief Creates a new handle from the implementation.
+   *
+   * @SINCE_1_0.0
+   * @param[in] impl A pointer to the object
+   */
+  explicit DALI_INTERNAL KeyboardFocusManager(Internal::KeyboardFocusManager *impl);
+  /// @endcond
+
+}; // class KeyboardFocusManager
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_KEYBOARD_FOCUS_MANAGER_H
diff --git a/dali-toolkit/public-api/image-loader/async-image-loader.cpp b/dali-toolkit/public-api/image-loader/async-image-loader.cpp
new file mode 100644 (file)
index 0000000..a1d21e7
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+// CLASS HEADER
+#include "async-image-loader.h"
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
+#include <dali-toolkit/internal/visuals/visual-url.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+AsyncImageLoader::AsyncImageLoader()
+{
+}
+
+AsyncImageLoader::~AsyncImageLoader()
+{
+}
+
+AsyncImageLoader::AsyncImageLoader( Internal::AsyncImageLoader* impl )
+: BaseHandle( impl )
+{
+}
+
+AsyncImageLoader::AsyncImageLoader( const AsyncImageLoader& handle )
+: BaseHandle( handle )
+{
+}
+
+AsyncImageLoader& AsyncImageLoader::operator=( const AsyncImageLoader& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+AsyncImageLoader AsyncImageLoader::DownCast( BaseHandle handle )
+{
+  return AsyncImageLoader( dynamic_cast<Dali::Toolkit::Internal::AsyncImageLoader*>( handle.GetObjectPtr() ) );
+}
+
+AsyncImageLoader AsyncImageLoader::New()
+{
+  IntrusivePtr<Internal::AsyncImageLoader> internal = Internal::AsyncImageLoader::New();
+   return AsyncImageLoader( internal.Get() );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url )
+{
+  return GetImplementation( *this ).Load( Toolkit::Internal::VisualUrl(url), ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url, ImageDimensions dimensions )
+{
+  return GetImplementation( *this ).Load( Toolkit::Internal::VisualUrl(url), dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true , DevelAsyncImageLoader::PreMultiplyOnLoad::OFF );
+}
+
+uint32_t AsyncImageLoader::Load( const std::string& url,
+                                 ImageDimensions dimensions,
+                                 FittingMode::Type fittingMode,
+                                 SamplingMode::Type samplingMode,
+                                 bool orientationCorrection )
+{
+  return GetImplementation(*this).Load( Toolkit::Internal::VisualUrl(url), dimensions, fittingMode, samplingMode, orientationCorrection, DevelAsyncImageLoader::PreMultiplyOnLoad::OFF );
+}
+
+bool AsyncImageLoader::Cancel( uint32_t loadingTaskId )
+{
+  return GetImplementation(*this).Cancel( loadingTaskId );
+}
+
+void AsyncImageLoader::CancelAll()
+{
+  GetImplementation( *this ).CancelAll();
+}
+
+AsyncImageLoader::ImageLoadedSignalType& AsyncImageLoader::ImageLoadedSignal()
+{
+  return GetImplementation( *this ).ImageLoadedSignal();
+}
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/image-loader/async-image-loader.h b/dali-toolkit/public-api/image-loader/async-image-loader.h
new file mode 100755 (executable)
index 0000000..3a30253
--- /dev/null
@@ -0,0 +1,257 @@
+#ifndef DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H
+#define DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H
+
+/*
+ * Copyright (c) 2018 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/public-api/object/base-handle.h>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+class PixelData;
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class AsyncImageLoader;
+}
+
+/**
+ * @addtogroup dali_toolkit_image_loader
+ * @{
+ */
+
+/**
+ * @brief The AsyncImageLoader is used to load pixel data from a URL asynchronously.
+ *
+ * The images are loaded in a worker thread to avoid blocking the main event thread.
+ *
+ * To keep track of the loading images, each load call is assigned an ID (which is returned by the Load() call).
+ * To know when the Load has completed, connect to the ImageLoadedSignal.
+ * This signal should be connected before Load is called (in case the signal is emitted immediately).
+ *
+ * Load errors can be detected by checking the PixelData object is valid from within the signal handler.
+
+ * Note: The PixelData object will automatically be destroyed when it leaves its scope.
+ *
+ * Example:
+ *
+ * @code
+ * class MyClass : public ConnectionTracker
+ * {
+ *   public:
+ *
+ *   MyCallback( uint32_t loadedTaskId, PixelData pixelData )
+ *   {
+ *     // First check if the image loaded correctly.
+ *     if( pixelData )
+ *     {
+ *       if( loadedTaskId == mId1 )
+ *       {
+ *         // use the loaded pixel data from the first image
+ *       }
+ *       else if( loadedTaskId == mId2 )
+ *       {
+ *         // use the loaded pixel data from the second image
+ *       }
+ *     }
+ *   }
+ *
+ *   uint32_t mId1;
+ *   uint32_t mId2;
+ * };
+ *
+ * MyClass myObject;
+ * AsyncImageLoader imageLoader = AsyncImageLoader::New();
+ *
+ * // Connect the signal here.
+ * imageLoader.ImageLoadedSignal().Connect( &myObject, &MyClass::MyCallback );
+ *
+ * // Invoke the load calls (must do this after connecting the signal to guarantee callbacks occur).
+ * myObject.mId1 = imageLoader.Load( "first_image_url.jpg" );
+ * myObject.mId2 = imageLoader.Load( "second_image_url.jpg" );
+ *
+ * @endcode
+ */
+class DALI_TOOLKIT_API AsyncImageLoader : public BaseHandle
+{
+public:
+
+  typedef Signal< void( uint32_t, PixelData ) > ImageLoadedSignalType; ///< Image loaded signal type @SINCE_1_2_14
+
+public:
+
+  /**
+   * @brief Constructor which creates an empty AsyncImageLoader handle.
+   * @SINCE_1_2_14
+   *
+   * Use AsyncImageLoader::New() to create an initialised object.
+   */
+  AsyncImageLoader();
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_2_14
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AsyncImageLoader();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   * @SINCE_1_2_14
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  AsyncImageLoader( const AsyncImageLoader& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   * @SINCE_1_2_14
+   *
+   * @param[in] handle  A reference to the copied handle
+   * @return A reference to this
+   */
+  AsyncImageLoader& operator=( const AsyncImageLoader& handle );
+
+  /**
+   * @brief Creates a new loader to load the image asynchronously in a worker thread.
+   * @SINCE_1_2_14
+   *
+   * @return The image loader
+   */
+  static AsyncImageLoader New();
+
+  /**
+   * @brief Downcasts a handle to AsyncImageLoader handle.
+   *
+   * If the handle points to an AsyncImageLoader object, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_2_14
+   * @param[in] handle A handle to an object
+   * @return A handle to a AsyncImageLoader object or an uninitialized handle
+   */
+  static AsyncImageLoader DownCast( BaseHandle handle );
+
+  /**
+   * @brief Starts an image loading task.
+   * Note: When using this method, the following defaults will be used:
+   * fittingMode = FittingMode::DEFAULT
+   * samplingMode = SamplingMode::BOX_THEN_LINEAR
+   * orientationCorrection = true
+   *
+   * @SINCE_1_2_14
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The URL of the image file to load
+   * @return The loading task id
+   */
+  uint32_t Load( const std::string& url );
+
+  /**
+   * @brief Starts an image loading task.
+   * Note: When using this method, the following defaults will be used:
+   * fittingMode = FittingMode::DEFAULT
+   * samplingMode = SamplingMode::BOX_THEN_LINEAR
+   * orientationCorrection = true
+   *
+   * @SINCE_1_2_14
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The URL of the image file to load
+   * @param[in] dimensions The width and height to fit the loaded image to
+   * @return The loading task id
+   */
+  uint32_t Load( const std::string& url, ImageDimensions dimensions );
+
+  /**
+   * @brief Starts an image loading task.
+   * @SINCE_1_2_14
+   * @REMARK_INTERNET
+   * @REMARK_STORAGE
+   * @param[in] url The URL of the image file to load
+   * @param[in] dimensions The width and height to fit the loaded image to
+   * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+   * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+   * @param[in] orientationCorrection Reorient the image to respect any orientation metadata in its header
+   * @return The loading task id
+   */
+  uint32_t Load( const std::string& url,
+                 ImageDimensions dimensions,
+                 FittingMode::Type fittingMode,
+                 SamplingMode::Type samplingMode,
+                 bool orientationCorrection );
+
+  /**
+   * @brief Cancels an image loading task if it is still queueing in the work thread.
+   * @SINCE_1_2_14
+   *
+   * @param[in] loadingTaskId The task id returned when invoking the load call.
+   * @return If true, the loading task is removed from the queue, otherwise the loading is already implemented and unable to cancel anymore
+   */
+  bool Cancel( uint32_t loadingTaskId );
+
+  /**
+   * @brief Cancels all the loading tasks in the queue.
+   * @SINCE_1_2_14
+   */
+  void CancelAll();
+
+  /**
+   * @brief Signal emitted for connected callback functions to get access to the loaded pixel data.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( uint32_t id, PixelData pixelData );
+   * @endcode
+   * @SINCE_1_2_14
+   * @return A reference to a signal object to Connect() with
+   */
+  ImageLoadedSignalType& ImageLoadedSignal();
+
+public: // Not intended for developer use
+
+  /// @cond internal
+  /**
+   * @brief Allows the creation of a AsyncImageLoader handle from an internal pointer.
+   *
+   * @note Not intended for application developers
+   * @SINCE_1_2_14
+   * @param[in] impl A pointer to the object
+   */
+  explicit DALI_INTERNAL AsyncImageLoader( Internal::AsyncImageLoader* impl );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_ASYNC_IMAGE_LOADER_H
diff --git a/dali-toolkit/public-api/image-loader/sync-image-loader.cpp b/dali-toolkit/public-api/image-loader/sync-image-loader.cpp
new file mode 100644 (file)
index 0000000..e8f8ad7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+// CLASS HEADER
+#include "sync-image-loader.h"
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace SyncImageLoader
+{
+
+
+PixelData Load( const std::string& url )
+{
+  return Load( url, ImageDimensions(), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+PixelData Load( const std::string& url, ImageDimensions dimensions )
+{
+  return Load( url, dimensions, FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+PixelData Load( const std::string& url,
+                ImageDimensions dimensions,
+                FittingMode::Type fittingMode,
+                SamplingMode::Type samplingMode,
+                bool orientationCorrection )
+{
+  // Load the image synchronously (block the thread here).
+  Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( url, dimensions, fittingMode, samplingMode, orientationCorrection );
+  if( pixelBuffer )
+  {
+    return Devel::PixelBuffer::Convert( pixelBuffer );
+  }
+  return Dali::PixelData(); // return empty handle
+}
+
+
+} // namespace SyncImageLoader
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/image-loader/sync-image-loader.h b/dali-toolkit/public-api/image-loader/sync-image-loader.h
new file mode 100755 (executable)
index 0000000..7d52867
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_TOOLKIT_SYNC_IMAGE_LOADER_H
+#define DALI_TOOLKIT_SYNC_IMAGE_LOADER_H
+
+/*
+ * Copyright (c) 2018 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/public-api/images/image-operations.h>
+#include <dali/public-api/images/pixel-data.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/dali-toolkit-common.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_image_loader
+ * @{
+ */
+
+namespace SyncImageLoader
+{
+
+/**
+ * @brief The methods in the SyncImageLoader namespace are used to load pixel data from a URL synchronously.
+ *
+ * Example:
+ *
+ * @code
+ * PixelData pixelData = Toolkit::SyncImageLoader::Load( "image_url.jpg" );
+ *
+ * // Check the image was loaded without error.
+ * if( pixelData )
+ * {
+ *   // Do work...
+ * }
+ *
+ * @endcode
+ */
+
+/**
+ * @brief Loads an image synchronously.
+ * Note: When using this method, the following defaults will be used:
+ * fittingMode = FittingMode::DEFAULT
+ * samplingMode = SamplingMode::BOX_THEN_LINEAR
+ * orientationCorrection = true
+ *
+ * @SINCE_1_2_14
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] url The URL of the image file to load
+ * @return A PixelData object containing the image, or an invalid object on failure
+ */
+DALI_TOOLKIT_API PixelData Load( const std::string& url );
+
+/**
+ * @brief Loads an image synchronously by specifying the target dimensions.
+ * Note: When using this method, the following defaults will be used:
+ * fittingMode = FittingMode::DEFAULT
+ * samplingMode = SamplingMode::BOX_THEN_LINEAR
+ * orientationCorrection = true
+ *
+ * @SINCE_1_2_14
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] url The URL of the image file to load
+ * @param[in] dimensions The width and height to fit the loaded image to
+ * @return A PixelData object containing the image, or an invalid object on failure
+ */
+DALI_TOOLKIT_API PixelData Load( const std::string& url, ImageDimensions dimensions );
+
+/**
+ * @brief Loads an image synchronously by specifying the target dimensions and options.
+ * @SINCE_1_2_14
+ * @REMARK_INTERNET
+ * @REMARK_STORAGE
+ * @param[in] url The URL of the image file to load
+ * @param[in] dimensions The width and height to fit the loaded image to
+ * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+ * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+ * @param[in] orientationCorrection Reorient the image to respect any orientation metadata in its header
+ * @return A PixelData object containing the image, or an invalid object on failure
+ */
+DALI_TOOLKIT_API PixelData Load( const std::string& url,
+                ImageDimensions dimensions,
+                FittingMode::Type fittingMode,
+                SamplingMode::Type samplingMode,
+                bool orientationCorrection );
+
+} // namespace SyncImageLoader
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_SYNC_IMAGE_LOADER_H
diff --git a/dali-toolkit/public-api/styling/style-manager.cpp b/dali-toolkit/public-api/styling/style-manager.cpp
new file mode 100644 (file)
index 0000000..e7231d6
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+// CLASS HEADER
+
+#include <dali-toolkit/public-api/styling/style-manager.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/internal/styling/style-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+StyleManager::StyleManager()
+{
+}
+
+StyleManager::~StyleManager()
+{
+}
+
+StyleManager StyleManager::Get()
+{
+  return Internal::StyleManager::Get();
+}
+
+void StyleManager::ApplyTheme( const std::string& themeFile )
+{
+  GetImpl(*this).ApplyTheme( themeFile );
+}
+
+void StyleManager::ApplyDefaultTheme()
+{
+  GetImpl(*this).ApplyDefaultTheme();
+}
+
+void StyleManager::SetStyleConstant( const std::string& key, const Property::Value& value )
+{
+  GetImpl(*this).SetStyleConstant( key, value );
+}
+
+bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& valueOut )
+{
+  return GetImpl(*this).GetStyleConstant( key, valueOut );
+}
+
+void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName )
+{
+  GetImpl(*this).ApplyStyle( control, jsonFileName, styleName );
+}
+
+StyleManager::StyleChangedSignalType& StyleManager::StyleChangedSignal()
+{
+  return GetImpl( *this ).StyleChangedSignal();
+}
+
+StyleManager::StyleManager( Internal::StyleManager *impl )
+  : BaseHandle( impl )
+{
+}
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/public-api/styling/style-manager.h b/dali-toolkit/public-api/styling/style-manager.h
new file mode 100644 (file)
index 0000000..4e42f57
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef DALI_TOOLKIT_STYLE_MANAGER_H
+#define DALI_TOOLKIT_STYLE_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/style-change.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/controls/control.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal DALI_INTERNAL
+{
+class StyleManager;
+}
+
+/**
+ * @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, it automatically updates all controls, then raises
+ * a signal to inform the application.
+ *
+ * The default theme is automatically loaded and applied, followed by
+ * any application specific theme defined in Application::New().
+ *
+ * If the application wants to customize the theme, RequestThemeChange
+ * needs to be called.
+ *
+ * To supply resource paths ( in json ) the following constant is available: APPLICATION_RESOURCE_PATH.
+ * It provides the path to the  application resource root folder, from there the filename can an be specified along with
+ * any sub folders, e.g Images, Models etc.
+ * The APPLICATION_RESOURCE_PATH can be retrieved using Application::GetResourcePath()
+ *
+ * Signals
+ * | %Signal Name            | Method                           |
+ * |------------------------------------------------------------|
+ * | styleChanged            | @ref StyleChangedSignal()        |
+ * @SINCE_1_1.32
+ */
+class DALI_TOOLKIT_API StyleManager : public BaseHandle
+{
+public:
+
+  /// @brief Style Changed signal. Emitted after controls have been updated.
+  typedef Signal< void ( StyleManager, StyleChange::Type ) >  StyleChangedSignalType;
+
+  /**
+   * @brief Creates a StyleManager handle; this can be initialized with StyleManager::Get().
+   *
+   * Calling member functions with an uninitialized handle is not allowed.
+   * @SINCE_1_1.32
+   */
+  StyleManager();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.32
+   */
+  ~StyleManager();
+
+  /**
+   * @brief Gets the singleton of StyleManager object.
+   *
+   * @SINCE_1_1.32
+   * @return A handle to the StyleManager control
+   */
+  static StyleManager Get();
+
+  /**
+   * @brief Applies a new theme to the application. This will be merged
+   * on top of the default Toolkit theme.
+   *
+   * 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.
+   *
+   * 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().
+   *
+   * @SINCE_1_1.32
+   * @param[in] themeFile If a relative path is specified, then this is relative
+   * to the directory returned by Application::GetResourcePath()
+   */
+  void ApplyTheme( const std::string& themeFile );
+
+  /**
+   * @brief Applies the default Toolkit theme.
+   *
+   * Request that any application specific styling is removed
+   * and that the default Toolkit theme is re-applied.
+   *
+   * @SINCE_1_1.32
+   */
+  void ApplyDefaultTheme();
+
+  /**
+   * @brief Sets a constant for use when building styles.
+   *
+   * 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
+   */
+  void SetStyleConstant( const std::string& key, const Property::Value& value );
+
+  /**
+   * @brief Returns 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
+   *
+   * @return If the constant for key exists, then return the constant in valueOut and return true
+   */
+  bool GetStyleConstant( const std::string& key, Property::Value& valueOut );
+
+  /**
+   * @brief Applies the specified style to the control.
+   *
+   * @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 Application::GetResourcePath()
+   * @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 );
+
+public: // Signals
+
+  /**
+   * @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
+   */
+  StyleChangedSignalType& StyleChangedSignal();
+
+public:
+
+  /// @cond internal
+  /**
+   * @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 );
+  /// @endcond
+
+}; // class StyleManager
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_STYLE_MANAGER_H
diff --git a/dali-toolkit/public-api/text/rendering-backend.h b/dali-toolkit/public-api/text/rendering-backend.h
new file mode 100755 (executable)
index 0000000..6c266f8
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_TOOLKIT_RENDERING_BACKEND_H
+#define DALI_TOOLKIT_RENDERING_BACKEND_H
+
+/*
+ * Copyright (c) 2019 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
+{
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+namespace Text
+{
+
+/**
+ * @brief Enumeration for the type of text renderer required.
+ * @SINCE_1_0.0
+ */
+enum RenderingType
+{
+  RENDERING_SHARED_ATLAS, ///< A bitmap-based solution where renderers can share a texture atlas @SINCE_1_0.0
+  RENDERING_VECTOR_BASED  ///< A solution where glyphs are stored as vectors (scalable). Requires highp shader support. @SINCE_1_1.31
+};
+
+const unsigned int DEFAULT_RENDERING_BACKEND = RENDERING_SHARED_ATLAS;
+
+} // namespace Text
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_RENDERING_BACKEND_H
diff --git a/dali-toolkit/public-api/text/text-enumerations.h b/dali-toolkit/public-api/text/text-enumerations.h
new file mode 100644 (file)
index 0000000..5276d32
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef DALI_TOOLKIT_TEXT_ENUMERATIONS_H
+#define DALI_TOOLKIT_TEXT_ENUMERATIONS_H
+
+/*
+ * Copyright (c) 2017 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
+{
+/**
+ * @addtogroup dali_toolkit_controls_text_controls
+ * @{
+ */
+
+namespace Text
+{
+
+/**
+ * @brief The available Horizontal alignments for text.
+ *
+ * @SINCE_1_2.60
+ */
+namespace HorizontalAlignment
+{
+
+/**
+ * @brief Enumerations for Horizontal alignment.
+ *
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  BEGIN,   ///< @SINCE_1_2.60
+  CENTER,  ///< @SINCE_1_2.60
+  END      ///< @SINCE_1_2.60
+};
+
+} // namespace HorizontalAlignment
+
+/**
+ * @brief The available Vertical alignments for text.
+ *
+ * @SINCE_1_2.60
+ */
+namespace VerticalAlignment
+{
+
+/**
+ * @brief Enumerations for Vertical alignment.
+ *
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  TOP,     ///< @SINCE_1_2.60
+  CENTER,  ///< @SINCE_1_2.60
+  BOTTOM   ///< @SINCE_1_2.60
+};
+
+} // namespace VerticalAlignment
+
+/**
+ * @brief Contains modes which specify how lines are wrapped.
+ *
+ * If the layout width is too short to show the full text, then a wrapping mode can be specified.
+ *
+ * LineWrap::WORD mode will move an entire word to the next line:
+ * @code
+ * +---------+
+ * |HELLO    |
+ * |WORLD    |
+ * +---------+
+ * @endcode
+ *
+ * LineWrap::CHARACTER mode will move character by character to the next line:
+ * @code
+ * +---------+
+ * |HELLO WOR|
+ * |LD       |
+ * +---------+
+ * @endcode
+ *
+ * @SINCE_1_2.60
+ */
+namespace LineWrap
+{
+
+/**
+ * @brief Enumerations specifying how a line is wrapped.
+ * @SINCE_1_2.60
+ * @see LineWrap
+ */
+enum Mode
+{
+  WORD,      ///< @SINCE_1_2.60
+  CHARACTER  ///< @SINCE_1_2.60
+};
+
+} // namespace LineWrap
+
+} // namespace Text
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif //DALI_TOOLKIT_TEXT_ENUMERATIONS_H
diff --git a/dali-toolkit/public-api/toolkit-property-index-ranges.h b/dali-toolkit/public-api/toolkit-property-index-ranges.h
new file mode 100644 (file)
index 0000000..c3bb73b
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_TOOLKIT_PROPERTY_INDEX_RANGES_H
+#define DALI_TOOLKIT_PROPERTY_INDEX_RANGES_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_controls
+ * @{
+ */
+
+/**
+ * @brief Enumeration for the start and end property ranges.
+ * @SINCE_1_1.45
+ */
+enum PropertyRanges
+{
+  VISUAL_PROPERTY_BASE_START_INDEX  = CORE_PROPERTY_MAX_INDEX + 1,             ///< Visual Property Base Start Index. @SINCE_1_1.45
+  VISUAL_PROPERTY_BASE_END_INDEX   = VISUAL_PROPERTY_BASE_START_INDEX + 100,   ///< Visual Property Base End Index. @SINCE_1_1.45
+  VISUAL_PROPERTY_START_INDEX = VISUAL_PROPERTY_BASE_END_INDEX + 1,            ///< Visual Property Start Index. @SINCE_1_1.45
+  VISUAL_PROPERTY_END_INDEX   = VISUAL_PROPERTY_START_INDEX + 100000,          ///< Visual Property End Index. @SINCE_1_1.45
+};
+
+/**
+ * @}
+ */
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_PROPERTY_INDEX_RANGES_H
diff --git a/dali-toolkit/public-api/visuals/border-visual-properties.h b/dali-toolkit/public-api/visuals/border-visual-properties.h
new file mode 100644 (file)
index 0000000..3b6c99b
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef DALI_TOOLKIT_BORDER_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_BORDER_VISUAL_PROPERTIES_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief BorderVisual is to render a solid color as an internal border to the control's quad.
+ * @SINCE_1_1.45
+ */
+namespace BorderVisual
+{
+
+/**
+ * @brief BorderVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the BorderVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The color of the border.
+   * @details Name "borderColor", type Property::VECTOR4.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   */
+  COLOR = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The width of the border (in pixels).
+   * @details Name "borderSize", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   */
+  SIZE,
+
+  /**
+   * @brief Whether anti-aliasing of the border is required.
+   * @details Name "antiAliasing", type Property::BOOLEAN.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is false.
+   */
+  ANTI_ALIASING,
+};
+
+} // namespace Property
+
+} // namespace BorderVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_BORDER_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/color-visual-properties.h b/dali-toolkit/public-api/visuals/color-visual-properties.h
new file mode 100644 (file)
index 0000000..5f1aab9
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief ColorVisual is to render a solid color to the control's quad.
+ * @SINCE_1_1.45
+ */
+namespace ColorVisual
+{
+
+/**
+ * @brief ColorVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the ColorVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The solid color required.
+   * @details Name "mixColor", type Property::VECTOR4.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   */
+  MIX_COLOR = VISUAL_PROPERTY_START_INDEX,
+};
+
+} // namespace Property
+
+} // namespace ColorVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_COLOR_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/gradient-visual-properties.h b/dali-toolkit/public-api/visuals/gradient-visual-properties.h
new file mode 100644 (file)
index 0000000..cdfd624
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef DALI_TOOLKIT_GRADIENT_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_GRADIENT_VISUAL_PROPERTIES_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief GradientVisual is to render a smooth transition of colors to the control's quad.
+ * @SINCE_1_1.45
+ */
+namespace GradientVisual
+{
+
+/**
+ * @brief GradientVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the GradientVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The start position of a linear gradient.
+   * @details Name "startPosition", type Property::VECTOR2.
+   * @SINCE_1_1.45
+   * @note Mandatory for Linear.
+   */
+  START_POSITION = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The end position of a linear gradient.
+   * @details Name "endPosition", type Property::VECTOR2.
+   * @SINCE_1_1.45
+   * @note Mandatory for Linear.
+   */
+  END_POSITION,
+
+  /**
+   * @brief The center point of a radial gradient.
+   * @details Name "center", type Property::VECTOR2.
+   * @SINCE_1_1.45
+   * @note Mandatory for Radial.
+   */
+  CENTER,
+
+  /**
+   * @brief The size of the radius of a radial gradient.
+   * @details Name "radius", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Mandatory for Radial.
+   */
+  RADIUS,
+
+  /**
+   * @brief All the stop offsets.
+   * @details Name "stopOffset", type Property::ARRAY of Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is 0.0 and 1.0.
+   */
+  STOP_OFFSET,
+
+  /**
+   * @brief The color at the stop offsets.
+   * @details Name "stopColor", type Property::ARRAY of Property::VECTOR4.
+   * @SINCE_1_1.45
+   * @note Mandatory. At least 2 values required to show a gradient.
+   */
+  STOP_COLOR,
+
+  /**
+   * @brief Defines the coordinate system for certain attributes of the points in a gradient.
+   * @details Name "units", type Units::Type (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is Units::OBJECT_BOUNDING_BOX.
+   * @see Units::Type
+   */
+  UNITS,
+
+  /**
+   * @brief Indicates what happens if the gradient starts or ends inside the bounds of the target rectangle.
+   * @details Name "spreadMethod", type SpreadMethod::Type (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is SpreadMethod::PAD.
+   * @see SpreadMethod::Type
+   */
+  SPREAD_METHOD
+};
+
+} // namespace Property
+
+/**
+ * @brief The type of coordinate system for certain attributes of the points in a gradient.
+ *
+ * This applies to the:
+ * - Start (x1, y1) and End (x2 and y2) points of a line if using a linear gradient.
+ * - Center point (cx, cy) and radius (r) of a circle if using a radial gradient.
+ * @SINCE_1_1.45
+ */
+namespace Units
+{
+
+/**
+ * @brief The type of coordinate system for certain attributes of the points in a gradient.
+ *
+ * This applies to the:
+ * - Start (x1, y1) and End (x2 and y2) points of a line if using a linear gradient.
+ * - Center point (cx, cy) and radius (r) of a circle if using a radial gradient.
+ * @SINCE_1_1.45
+ */
+enum Type
+{
+  OBJECT_BOUNDING_BOX, ///< Uses the normals for the start, end & center points, i.e. top-left is (-0.5, -0.5) and bottom-right is (0.5, 0.5). @SINCE_1_1.45
+  USER_SPACE ///< Uses the user coordinates for the start, end & center points, i.e. in a 200 by 200 control, top-left is (0, 0) and bottom-right is (200, 200). @SINCE_1_1.45
+};
+
+} // namespace Units
+
+/**
+ * @brief Policies that define what happens if the gradient starts or ends inside the bounds of the target rectangle.
+ * @SINCE_1_1.45
+ */
+namespace SpreadMethod
+{
+
+/**
+ * @brief Policies that define what happens if the gradient starts or ends inside the bounds of the target rectangle.
+ * @SINCE_1_1.45
+ */
+enum Type
+{
+  PAD, ///< Uses the terminal colors of the gradient to fill the remainder of the quad. @SINCE_1_1.45
+  REFLECT, ///< Reflect the gradient pattern start-to-end, end-to-start, start-to-end etc. until the quad is filled. @SINCE_1_1.45
+  REPEAT ///< Repeat the gradient pattern start-to-end, start-to-end, start-to-end etc. until the quad is filled. @SINCE_1_1.45
+};
+
+} // namespace SpreadMethod
+
+} // namespace GradientVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_GRADIENT_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/image-visual-properties.h b/dali-toolkit/public-api/visuals/image-visual-properties.h
new file mode 100644 (file)
index 0000000..0f5d58b
--- /dev/null
@@ -0,0 +1,317 @@
+#ifndef DALI_TOOLKIT_IMAGE_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_IMAGE_VISUAL_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief ImageVisual is to render an image into the control's quad.
+ * @SINCE_1_1.45
+ */
+namespace ImageVisual
+{
+
+/**
+ * @brief ImageVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the ImageVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The URL of the image.
+   * @details Name "url", type Property::STRING or Property::ARRAY of Property::STRING.
+   * @note The array form is used for generating animated image visuals.
+   * @note The number of threads used for local and remote image loading can be controlled by the
+   *       environment variables DALI_TEXTURE_LOCAL_THREADS and DALI_TEXTURE_REMOTE_THREADS respectively.
+   *       The default values are 4 threads for local image loading and 8 threads for remote image loading.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   */
+  URL = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief Fitting options, used when resizing images to fit desired dimensions.
+   * @details Name "fittingMode", type Dali::FittingMode (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is FittingMode::SHRINK_TO_FIT.
+   * @note For Normal Quad images only.
+   * @see Dali::FittingMode
+   */
+  FITTING_MODE,
+
+  /**
+   * @brief Filtering options, used when resizing images to sample original pixels.
+   * @details Name "samplingMode", type Dali::SamplingMode (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not supplied, default is SamplingMode::BOX.
+   * @note For Normal Quad images only.
+   * @see Dali::SamplingMode
+   */
+  SAMPLING_MODE,
+
+  /**
+   * @brief The desired image width.
+   * @details Name "desiredWidth", type Property::INTEGER.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the actual image width is used.
+   * @note For Normal Quad images only.
+   */
+  DESIRED_WIDTH,
+
+  /**
+   * @brief The desired image height.
+   * @details Name "desiredHeight", type Property::INTEGER.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the actual image height is used.
+   * @note For Normal Quad images only.
+   */
+  DESIRED_HEIGHT,
+
+  /**
+   * @brief Whether to load the image synchronously.
+   * @details Name "synchronousLoading", type Property::BOOLEAN.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is false, i.e. the image is loaded asynchronously.
+   * @note For Normal Quad images only.
+   */
+  SYNCHRONOUS_LOADING,
+
+  /**
+   * @brief If true, only draws the borders.
+   * @details Name "borderOnly", type Property::BOOLEAN.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is false.
+   * @note For N-Patch images only.
+   */
+  BORDER_ONLY,
+
+  /**
+   * @brief The image area to be displayed.
+   * @details Name "pixelArea", type Property::VECTOR4.
+   *          It is a rectangular area.
+   *          The first two elements indicate the top-left position of the area, and the last two elements are the area width and height respectively.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default value is [0.0, 0.0, 1.0, 1.0], i.e. the entire area of the image.
+   * @note For Normal Quad images only.
+   */
+  PIXEL_AREA,
+
+  /**
+   * @brief The wrap mode for u coordinate.
+   * @details Name "wrapModeU", type Dali::WrapMode::Type (Property::INTEGER) or Property::STRING.
+   *          It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default is CLAMP.
+   * @note For Normal QUAD image only.
+   */
+  WRAP_MODE_U,
+
+  /**
+   * @brief The wrap mode for v coordinate.
+   * @details Name "wrapModeV", type Dali::WrapMode::Type (Property::INTEGER) or Property::STRING.
+   *          it decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.
+   * @SINCE_1_2.1
+   * @note Optional. If not specified, the default is CLAMP.
+   * @note For Normal QUAD image only.
+   */
+  WRAP_MODE_V,
+
+  /**
+   * @brief The border of the image.
+   * @details Name "border", type Property::RECTANGLE or Property::VECTOR4.
+   *          The border of the image in the order: left, right, bottom, top.
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @note For N-Patch images only.
+   */
+  BORDER,
+
+  /**
+   * @brief Whether to use the texture atlas
+   * @details Name "atlasing", type Property::BOOLEAN.
+   * @SINCE_1_2.60
+   * @note Optional. By default atlasing is off.
+   */
+  ATLASING,
+
+  /**
+   * @brief URL of a masking image
+   * @details Name "alphaMaskUrl", type Property::STRING, URL of image to apply as
+   * a mask after image loading. If set after the main URL has finished loading, this
+   * may necessitate a re-load of the main image. The alpha mask image will be scaled
+   * on load to match the size of the main image, then applied to the pixel data
+   * before uploading to GL.
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  ALPHA_MASK_URL,
+
+  /**
+   * @brief Defines the batch size for pre-loading images in the AnimatedImageVisual
+   * @details Name "batchSize", type Property::INTEGER, number of images to pre-load
+   * before starting to play. Default value: 1
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  BATCH_SIZE,
+
+  /**
+   * @brief Defines the cache size for loading images in the AnimatedImageVisual
+   * @details Name "cacheSize", type Property::INTEGER, number of images to keep
+   * cached ahead during playback. Default value: 1
+   *
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @note, cacheSize should be >= batchSize.
+   * If it isn't, then the cache will automatically be changed to batchSize.
+   * @note, because of the defaults, it is expected that the application developer
+   * tune the batch and cache sizes to their particular use case.
+   */
+  CACHE_SIZE,
+
+  /**
+   * @brief The number of milliseconds between each frame in the AnimatedImageVisual
+   * @details Name "frameDelay", type Property::INTEGER, The number of milliseconds between each frame.
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @note This is only used when multiple URLs are provided.
+   */
+  FRAME_DELAY,
+
+  /**
+   * @brief The scale factor to apply to the content image before masking
+   * @details Name "maskContentScale", type Property::FLOAT, The scale factor
+   * to apply to the content before masking. Note, scaled images are cropped to
+   * the same size as the alpha mask.
+   * @SINCE_1_2.60
+   * @note Optional.
+   */
+  MASK_CONTENT_SCALE,
+
+  /**
+   * @brief Whether to crop image to mask or scale mask to fit image
+   * @details Name "cropToMask", type Property::BOOLEAN, True if the image should
+   * be cropped to match the mask size, or false if the image should remain the same size.
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @note If this is false, then the mask is scaled to fit the image before being applied.
+   */
+  CROP_TO_MASK,
+
+  /**
+   * @brief The policy to determine when an image should be loaded.
+   * @details Name "loadPolicy",  Type LoadPolicy::Type (Property::INTEGER)or Property::STRING.
+   * @SINCE_1_3_5
+   * @note Default LoadPolicy::ATTACHED
+   * @see LoadPolicy::Type
+   */
+
+  LOAD_POLICY,
+
+  /**
+   * @brief The policy to determine when an image should no longer be cached.
+   * @details Name "releasePolicy", Type ReleasePolicy::Type (Property::INTEGER) or Property::STRING
+   * @SINCE_1_3_5
+   * @note Default ReleasePolicy::DESTROYED
+   * @see ReleasePolicy::Type
+   */
+  RELEASE_POLICY,
+
+  /**
+   * @brief Determines if image orientation should be corrected so the image displays as it was intended.
+   * @details Name "orientationCorrection", Type Property::BOOLEAN, if true the image's orientation will be corrected.
+   * @SINCE_1_3_5
+   * @note Default true
+   */
+  ORIENTATION_CORRECTION,
+
+};
+
+} // namespace Property
+
+/**
+ * @brief The policy determining if the image is loaded when the visual is staged or created.
+ * @SINCE_1_3_5
+ */
+namespace LoadPolicy
+{
+
+/**
+ * @brief The available named elements that define the LoadPolicy.
+ * @SINCE_1_3_5
+ */
+enum Type
+{
+  IMMEDIATE = 0,  ///< The image is loaded when the ImageVisual is created.
+  ATTACHED        ///< The image is loaded when the ImageVisual is attached to the stage.
+};
+
+} // namespace LoadPolicy
+
+/**
+ * @brief The policy determining when a image is deleted from the cache in relation to the ImageVisual lifetime.
+ * @SINCE_1_3_5
+ * @note If the texture is being shared by another visual it persist if still required.
+ */
+namespace ReleasePolicy
+{
+
+/**
+ * @brief The available named elements that define the ReleasePolicy.
+ * @SINCE_1_3_5
+ */
+enum Type
+{
+  DETACHED = 0,  ///<  Image deleted from cache when ImageVisual detached from stage.
+  DESTROYED,     ///<  Image deleted from cache when ImageVisual destroyed.
+  NEVER          ///<  Image is never deleted, will survive the lifetime of the application.
+};
+
+} // namespace ReleasePolicy;
+
+} // namespace ImageVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_IMAGE_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/mesh-visual-properties.h b/dali-toolkit/public-api/visuals/mesh-visual-properties.h
new file mode 100644 (file)
index 0000000..f431207
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_TOOLKIT_MESH_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_MESH_VISUAL_PROPERTIES_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief MeshVisual is to render a mesh using a .obj file, optionally with textures provided by a mtl file.
+ * @SINCE_1_1.45
+ */
+namespace MeshVisual
+{
+
+/**
+ * @brief MeshVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the MeshVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The location of the ".obj" file.
+   * @details Name "objectUrl", type Property::STRING.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   */
+  OBJECT_URL = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The location of the ".mtl" file.
+   * @details Name "materialUrl", type Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, then a textureless object is assumed.
+   */
+  MATERIAL_URL,
+
+  /**
+   * @brief Path to the directory the textures (including gloss and normal) are stored in.
+   * @details Name "texturesPath", type Property::STRING.
+   * @SINCE_1_1.45
+   * @note Mandatory if using material.
+   */
+  TEXTURES_PATH,
+
+  /**
+   * @brief Sets the type of shading mode that the mesh will use.
+   * @details Name "shadingMode", type ShadingMode::Value (Property::INTEGER) or Property::STRING.
+   * If anything the specified shading mode requires is missing, a simpler mode that can be handled with what has been supplied will be used instead.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, it will use the best it can support (will try ShadingMode::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING first).
+   * @see ShadingMode::Value
+   */
+  SHADING_MODE,
+
+  /**
+   * @brief Whether to use mipmaps for textures or not.
+   * @details Name "useMipmapping", type Property::BOOLEAN.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is true.
+   */
+  USE_MIPMAPPING,
+
+  /**
+   * @brief Whether to average normals at each point to smooth textures or not.
+   * @details Name "useSoftNormals", type Property::BOOLEAN.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is true.
+   */
+  USE_SOFT_NORMALS,
+
+  /**
+   * @brief The position, in stage space, of the point light that applies lighting to the model.
+   * @details Name "lightPosition", type Property::VECTOR3.
+   * This is based off the stage's dimensions, so using the width and height of the stage halved will correspond to the center,
+   * and using all zeroes will place the light at the top left corner.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is an offset outwards from the center of the screen.
+   */
+  LIGHT_POSITION,
+};
+
+} // namespace Property
+
+/**
+ * @brief The shading mode used by MeshVisual.
+ * @SINCE_1_1.45
+ */
+namespace ShadingMode
+{
+
+/**
+ * @brief The shading mode used by MeshVisual.
+ * @SINCE_1_1.45
+ */
+enum Value
+{
+  TEXTURELESS_WITH_DIFFUSE_LIGHTING, ///< *Simplest*. One color that is lit by ambient and diffuse lighting. @SINCE_1_1.45
+  TEXTURED_WITH_SPECULAR_LIGHTING, ///< Uses only the visual image textures provided with specular lighting in addition to ambient and diffuse lighting. @SINCE_1_1.45
+  TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING ///< Uses all textures provided including a gloss, normal and texture map along with specular, ambient and diffuse lighting. @SINCE_1_1.45
+};
+
+} // namespace ShadingMode
+
+} // namespace MeshVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_MESH_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/primitive-visual-properties.h b/dali-toolkit/public-api/visuals/primitive-visual-properties.h
new file mode 100644 (file)
index 0000000..1e3afcf
--- /dev/null
@@ -0,0 +1,231 @@
+#ifndef DALI_TOOLKIT_PRIMITIVE_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_PRIMITIVE_VISUAL_PROPERTIES_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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief PrimitiveVisual is to render a simple 3D shape, such as a cube or sphere.
+ * @SINCE_1_1.45
+ */
+namespace PrimitiveVisual
+{
+
+/**
+ * @brief PrimitiveVisual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the PrimitiveVisual.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The specific shape to render.
+   * @details Name "shape", type Shape::Type (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is Shape::SPHERE.
+   * @see Shape::Type
+   */
+  SHAPE = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The color of the shape.
+   * @details Name "mixColor", type Property::VECTOR4.
+   * @SINCE_1_2_4
+   * @note Optional. If not specified, the default is Vector4(0.5, 0.5, 0.5, 1.0).
+   * @note Applies to ALL shapes.
+   */
+  MIX_COLOR,
+
+  /**
+   * @brief The number of slices as you go around the shape.
+   * @details Name "slices", type Property::INTEGER.
+   * For spheres and conical frustums, this determines how many divisions there are as you go around the object.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 128.
+   * @note Applies to:
+   *      - Shape::SPHERE
+   *      - Shape::CONICAL_FRUSTUM
+   *      - Shape::CONE
+   *      - Shape::CYLINDER
+   * @note The range is from 1 to 255.
+   */
+  SLICES,
+
+  /**
+   * @brief The number of stacks as you go down the shape.
+   * @details Name "stacks", type Property::INTEGER.
+   * For spheres, 'stacks' determines how many layers there are as you go down the object.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 128.
+   * @note Applies to:
+   *      - Shape::SPHERE
+   * @note The range is from 1 to 255.
+   */
+  STACKS,
+
+  /**
+   * @brief The scale of the radius of the top circle of a conical frustum.
+   * @details Name "scaleTopRadius", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 1.0f.
+   * @note Applies to:
+   *      - Shape::CONICAL_FRUSTUM
+   * @note Only values greater than or equal to 0.0f are accepted.
+   */
+  SCALE_TOP_RADIUS,
+
+  /**
+   * @brief The scale of the radius of the bottom circle of a conical frustum.
+   * @details Name "scaleBottomRadius", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 1.5f.
+   * @note Applies to:
+   *      - Shape::CONICAL_FRUSTUM
+   *      - Shape::CONE
+   * @note Only values greater than or equal to 0.0f are accepted.
+   */
+  SCALE_BOTTOM_RADIUS,
+
+  /**
+   * @brief The scale of the height of a conic.
+   * @details Name "scaleHeight", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 3.0f.
+   * @note Applies to:
+   *      - Shape::CONICAL_FRUSTUM
+   *      - Shape::CONE
+   *      - Shape::CYLINDER
+   * @note Only values greater than or equal to 0.0f are accepted.
+   */
+  SCALE_HEIGHT,
+
+  /**
+   * @brief The scale of the radius of a cylinder.
+   * @details Name "scaleRadius", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 1.0f.
+   * @note Applies to:
+   *      - Shape::CYLINDER
+   * @note Only values greater than or equal to 0.0f are accepted.
+   */
+  SCALE_RADIUS,
+
+  /**
+   * @brief The dimensions of a cuboid. Scales in the same fashion as a 9-patch image.
+   * @details Name "scaleDimensions", type Property::VECTOR3.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is Vector3::ONE.
+   * @note Applies to:
+   *      - Shape::CUBE
+   *      - Shape::OCTAHEDRON
+   *      - Shape::BEVELLED_CUBE
+   * @note Each vector3 parameter should be greater than or equal to 0.0f.
+   */
+  SCALE_DIMENSIONS,
+
+  /**
+   * @brief Determines how bevelled the cuboid should be, based off the smallest dimension.
+   * @details Name "bevelPercentage", type Property::FLOAT.
+   * Bevel percentage ranges from 0.0 to 1.0. It affects the ratio of the outer face widths to the width of the overall cube.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 0.0f (no bevel).
+   * @note Applies to:
+   *      - Shape::BEVELLED_CUBE
+   * @note The range is from 0.0f to 1.0f.
+   */
+  BEVEL_PERCENTAGE,
+
+  /**
+   * @brief Defines how smooth the bevelled edges should be.
+   * @details Name "bevelSmoothness", type Property::FLOAT.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is 0.0f (sharp edges).
+   * @note Applies to:
+   *      - Shape::BEVELLED_CUBE
+   * @note The range is from 0.0f to 1.0f.
+   */
+  BEVEL_SMOOTHNESS,
+
+  /**
+   * @brief The position, in stage space, of the point light that applies lighting to the model.
+   * @details Name "lightPosition", type Property::VECTOR3.
+   * This is based off the stage's dimensions, so using the width and height of the stage halved will correspond to the center,
+   * and using all zeroes will place the light at the top left corner.
+   * @SINCE_1_1.45
+   * @note Optional. If not specified, the default is an offset outwards from the center of the screen.
+   * @note Applies to ALL shapes.
+   */
+  LIGHT_POSITION,
+};
+
+} // namespace Property
+
+/**
+ * @brief The primitive shape to render as a PrimitiveVisual.
+ * @SINCE_1_1.45
+ */
+namespace Shape
+{
+
+/**
+ * @brief The primitive shape to render as a PrimitiveVisual.
+ * @SINCE_1_1.45
+ */
+enum Type
+{
+  SPHERE, ///< A perfectly round geometrical object in three-dimensional space. @SINCE_1_1.45
+  CONICAL_FRUSTRUM, ///< @DEPRECATED_1_3.15, use CONICAL_FRUSTUM instead. The area bound between two circles, i.e. a cone with the tip removed. @SINCE_1_1.45
+  CONE, ///< Equivalent to a conical frustum with top radius of zero. @SINCE_1_1.45
+  CYLINDER, ///< Equivalent to a conical frustum with equal radii for the top and bottom circles. @SINCE_1_1.45
+  CUBE, ///< Equivalent to a bevelled cube with a bevel percentage of zero. @SINCE_1_1.45
+  OCTAHEDRON, ///< Equivalent to a bevelled cube with a bevel percentage of one. @SINCE_1_1.45
+  BEVELLED_CUBE, ///< A cube/cuboid with all edges flattened to some degree. @SINCE_1_1.45
+  CONICAL_FRUSTUM ///< The area bound between two circles, i.e. a cone with the tip removed. @SINCE_1_3.15
+};
+}
+
+} // namespace PrimitiveVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_PRIMITIVE_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/text-visual-properties.h b/dali-toolkit/public-api/visuals/text-visual-properties.h
new file mode 100644 (file)
index 0000000..0eb7fba
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_TOOLKIT_TEXT_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_TEXT_VISUAL_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief TextVisual is to render a text.
+ * @SINCE_1_2.60
+ */
+namespace TextVisual
+{
+
+/**
+ * @brief TextVisual Property.
+ * @SINCE_1_2.60
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the TextVisual.
+ * @SINCE_1_2.60
+ */
+enum
+{
+  /**
+   * @brief The text to display in UTF-8 format.
+   * @details name "text", type Property::STRING.
+   * @SINCE_1_2.60
+   */
+  TEXT = VISUAL_PROPERTY_START_INDEX,
+
+  /**
+   * @brief The requested font family to use.
+   * @details name "fontFamily", type Property::STRING.
+   * @SINCE_1_2.60
+   */
+  FONT_FAMILY,
+
+  /**
+   * @brief The requested font style to use.
+   * @details name "fontStyle", type Property::MAP.
+   * @SINCE_1_2.60
+   */
+  FONT_STYLE,
+
+  /**
+   * @brief The size of font in points.
+   * @details name "pointSize", type Property::FLOAT.
+   * @SINCE_1_2.60
+   */
+  POINT_SIZE,
+
+  /**
+   * @brief The single-line or multi-line layout option.
+   * @details name "multiLine", type Property::BOOLEAN, default false.
+   * @SINCE_1_2.60
+   */
+  MULTI_LINE,
+
+  /**
+   * @brief The line horizontal alignment.
+   * @details Name "horizontalAlignment", type HorizontalAlignment::Type (Property::INTEGER) or Property::STRING.
+   * @note Optional. If not specified, the default is HorizontalAlignment::BEGIN
+   * @note Return type is HorizontalAlignment::Type (Property::INTEGER)
+   * @SINCE_1_2.60
+   */
+  HORIZONTAL_ALIGNMENT,
+
+  /**
+   * @brief The line vertical alignment.
+   * @details name "verticalAlignment", VerticalAlignment::Type (Property::INTEGER) or  Property::STRING
+   * @note Optional. If not specified, the default is VerticalAlignment::TOP
+   * @note Return type is VerticalAlignment::Type (Property::INTEGER)`
+   * @SINCE_1_2.60
+   */
+  VERTICAL_ALIGNMENT,
+
+  /**
+   * @brief The color of the text.
+   * @details name "textColor", type Property::VECTOR4.
+   * @SINCE_1_2.60
+   */
+  TEXT_COLOR,
+
+  /**
+   * @brief  Whether the mark-up processing is enabled.
+   * @details name "enableMarkup", type Property::BOOLEAN.
+   * @SINCE_1_2.60
+   */
+  ENABLE_MARKUP,
+
+  /**
+   * @brief The shadow parameters.
+   * @details name "shadow", type Property::MAP.
+   * @SINCE_1_2.60
+   */
+  SHADOW,
+
+  /**
+   * @brief The default underline parameters.
+   * @details name "underline", type Property::MAP.
+   * @SINCE_1_2.60
+   */
+  UNDERLINE,
+};
+
+} // namespace Property
+
+} // namespace TextVisual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/public-api/visuals/visual-properties.h b/dali-toolkit/public-api/visuals/visual-properties.h
new file mode 100644 (file)
index 0000000..dd1447b
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef DALI_TOOLKIT_VISUAL_PROPERTIES_H
+#define DALI_TOOLKIT_VISUAL_PROPERTIES_H
+
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/toolkit-property-index-ranges.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+/**
+ * @addtogroup dali_toolkit_visuals
+ * @{
+ */
+
+/**
+ * @brief All the visual types.
+ * @SINCE_1_1.45
+ */
+namespace Visual
+{
+
+/**
+ * @brief All the visual types.
+ * @SINCE_1_1.45
+ */
+enum Type
+{
+  BORDER,           ///< Renders a solid color as an internal border to the control's quad. @SINCE_1_1.45
+  COLOR,            ///< Renders a solid color to the control's quad. @SINCE_1_1.45
+  GRADIENT,         ///< Renders a smooth transition of colors to the control's quad. @SINCE_1_1.45
+  IMAGE,            ///< Renders an image into the control's quad. @SINCE_1_1.45
+  MESH,             ///< Renders a mesh using an "obj" file, optionally with textures provided by an "mtl" file. @SINCE_1_1.45
+  PRIMITIVE,        ///< Renders a simple 3D shape, such as a cube or sphere. @SINCE_1_1.45
+  WIREFRAME,        ///< Renders a simple wire-frame outlining a quad. @SINCE_1_2_2
+  TEXT,             ///< Renders text @SINCE_1_2.60
+  N_PATCH,          ///< Renders an n-patch image. @SINCE_1_2.60
+  SVG,              ///< Renders an SVG image. @SINCE_1_2.60
+  ANIMATED_IMAGE,   ///< Renders a animated image. @SINCE_1_2.60
+};
+
+/**
+ * @brief Visual Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the instance of properties belonging to the Visual Property.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The index for the visual type.
+   * @details Name "visualType", type [Type](Dali::Toolkit::Visual::Type) (Property::INTEGER) or Property::STRING.
+   * @SINCE_1_1.45
+   * @note Mandatory.
+   * @see Type
+   */
+  TYPE = VISUAL_PROPERTY_BASE_START_INDEX,
+
+  /**
+   * @brief The shader to use in the visual.
+   * @details Name "shader", type Property::MAP.
+   * @SINCE_1_1.45
+   * @note Optional.
+   * @note Will override the existing shaders.
+   * @see Shader::Property
+   */
+  SHADER,
+
+  /**
+   * @brief The transform used by the visual.
+   * @details Name "transform", type Property::MAP.
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @see Toolkit::Visual::Transform::Property
+   */
+  TRANSFORM,
+
+  /**
+   * @brief Enables/disables premultiplied alpha.
+   * @details Name "premultipliedAlpha", type Property::BOOLEAN.
+   * @SINCE_1_2.60
+   * @note Optional.
+   * @note The premultiplied alpha is false by default unless this behaviour is modified
+   * by the derived Visual type.
+   */
+  PREMULTIPLIED_ALPHA,
+
+  /**
+   * @brief Mix color is a blend color for any visual.
+   * @details Name "mixColor", type Property::VECTOR3 or Property::VECTOR4.
+   * @SINCE_1_2.60
+   * @note Optional
+   */
+  MIX_COLOR,
+
+  /**
+   * @brief Opacity is the alpha component of the mixColor, above.
+   * @details Name "opacity", type Property::FLOAT.
+   * @SINCE_1_2.60
+   * @note Optional
+   */
+  OPACITY,
+};
+
+} // namespace Property
+
+/**
+ * @brief Visual Transform for the offset or size.
+ * @SINCE_1_2.60
+ */
+namespace Transform
+{
+
+/**
+ * @brief Policies used by the transform for the offset or size.
+ * @SINCE_1_2.60
+ */
+namespace Policy
+{
+
+/**
+ * @brief Enumeration for the type of Transform Policy.
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  RELATIVE = 0,   ///< Relative to the control (percentage [0.0f to 1.0f] of the control). @SINCE_1_2.60
+  ABSOLUTE = 1    ///< Absolute value in world units. @SINCE_1_2.60
+};
+
+} // namespace Policy
+
+/**
+ * @brief Visual Transform Property.
+ * @SINCE_1_2.60
+ */
+namespace Property
+{
+
+/**
+ * @brief Enumeration for the type of Transform Property.
+ * @SINCE_1_2.60
+ */
+enum Type
+{
+  /**
+   * @brief Offset of the visual, which can be either relative (percentage [0.0f to 1.0f] of the parent) or absolute (in world units).
+   * @details Name "offset", type Property::VECTOR2.
+   * @SINCE_1_2.60
+   *
+   * @see OFFSET_POLICY
+   */
+  OFFSET,
+
+  /**
+   * @brief Size of the visual, which can be either relative (percentage [0.0f to 1.0f] of the parent) or absolute (in world units).
+   * @details Name "size", type Property::VECTOR2.
+   * @see SIZE_POLICY
+   */
+  SIZE,
+
+  /**
+   * @brief The origin of the visual within its control area.
+   * @details Name "origin", type Align::Type (Property::INTEGER) or Property::STRING.
+   * @see Toolkit::Align
+   * @SINCE_1_2.60
+   * @note The default is Align::TOP_BEGIN.
+   */
+  ORIGIN,
+
+  /**
+   * @brief The anchor-point of the visual
+   * @details Name "anchorPoint", type Align::Type (Property::INTEGER) or Property::STRING.
+   * @see Toolkit::Align
+   * @SINCE_1_2.60
+   * @note The default is Align::TOP_BEGIN.
+   */
+  ANCHOR_POINT,
+
+  /**
+   * @brief Whether the x or y OFFSET values are relative (percentage [0.0f to 1.0f] of the control) or absolute (in world units).
+   * @details Name "offsetPolicy", type Vector2 or Property::ARRAY of Property::STRING.
+   *          If Property::ARRAY then 2 strings expected for the x and y.
+   *
+   * C++:
+   * @code
+   * control.SetProperty( ..., // Some visual based property
+   *                      Property::Map().Add( ... ) // Properties to set up visual
+   *                                     .Add( Visual::Property::TRANSFORM,
+   *                                           Property::Array().Add( Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2( Policy::ABSOLUTE, Policy::RELATIVE ) ) )
+   *                                                            .Add( Toolkit::Visual::Transform::Property::OFFSET, Vector2( 10, 1.0f ) ) );
+   * @endcode
+   *
+   * JSON:
+   * @code
+   * {
+   *   ...
+   *   "transition":
+   *   {
+   *     "offsetPolicy" : [ "ABSOLUTE", "RELATIVE" ],
+   *     "offset" : [ 10, 1.0 ]
+   *   }
+   *   ...
+   * }
+   *
+   * @endcode
+   * @see Policy::Type
+   * @SINCE_1_2.60
+   * @note By default, both the x and the y offset is RELATIVE.
+   */
+  OFFSET_POLICY,
+
+  /**
+   * @brief Whether the width or height SIZE values are relative (percentage [0.0f to 1.0f] of the control) or absolute (in world units).
+   * @details Name "sizePolicy", type Vector2 or Property::ARRAY of Property::STRING.
+   *          If Property::ARRAY then 2 strings expected for the width and height.
+   *
+   * @see Policy::Type
+   * @see OFFSET_POLICY for example
+   * @SINCE_1_2.60
+   * @note By default, both the width and the height is RELATIVE to the control's size.
+   */
+  SIZE_POLICY,
+};
+
+} // namespace Property
+
+} // namespace Transform
+
+/**
+ * @brief Shader for Visuals.
+ * @SINCE_1_1.45
+ */
+namespace Shader
+{
+
+/**
+ * @brief Shader Property.
+ * @SINCE_1_1.45
+ */
+namespace Property
+{
+
+/**
+ * @brief The type of Shader.
+ * @SINCE_1_1.45
+ */
+enum
+{
+  /**
+   * @brief The vertex shader.
+   * @details Name "vertexShader", type Property::STRING or Property::ARRAY of Property::STRING.
+   *          A Property::ARRAY of Property::STRING values can be used to split the shader string over multiple lines.
+   * @SINCE_1_1.45
+   * @note Optional
+   * @note If not supplied, the visual's already set vertex shader is used.
+   */
+  VERTEX_SHADER,
+
+  /**
+   * @brief The fragment shader.
+   * @details Name "fragmentShader", type Property::STRING or Property::ARRAY of Property::STRING.
+   *          A Property::ARRAY of Property::STRING values can be used to split the shader string over multiple lines.
+   * @SINCE_1_1.45
+   * @note Optional
+   * @note If not supplied, the visual's already set fragment shader is used.
+   */
+  FRAGMENT_SHADER,
+
+  /**
+   * @brief How to subdivide the grid along the X-Axis.
+   * @details Name "subdivideGridX", type Property::INTEGER.
+   * @SINCE_1_1.45
+   * @note Optional
+   * @note If not supplied, the default is 1.
+   * @note Value should be greater than or equal to 1.
+   */
+  SUBDIVIDE_GRID_X,
+
+  /**
+   * @brief How to subdivide the grid along the Y-Axis.
+   * @details Name "subdivideGridY", type Property::INTEGER.
+   * @SINCE_1_1.45
+   * @note Optional
+   * @note If not supplied, the default is 1.
+   * @note Value should be greater than or equal to 1.
+   */
+  SUBDIVIDE_GRID_Y,
+
+  /**
+   * @brief Hints for rendering.
+   * @details Name "hints", type Dali::Shader::Hint (Property::INTEGER), Property::STRING or Property::ARRAY of Property::STRING.
+   * @SINCE_1_1.45
+   * @note Optional
+   * @note If not supplied, the default is Dali::Shader::Hint::NONE.
+   */
+  HINTS,
+};
+
+} // namespace Property
+
+} // namespace Shader
+
+
+/**
+ * @brief Status of resource which is used for visual.
+ * @SINCE_1_3_5
+ */
+enum class ResourceStatus
+{
+  PREPARING, /// Resource is prepared.    @SINCE_1_3_5
+  READY,     /// Resource is ready.       @SINCE_1_3_5
+  FAILED     /// Resource is fail to load @SINCE_1_3_5
+};
+
+} // namespace Visual
+
+/**
+ * @}
+ */
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_VISUAL_PROPERTIES_H
diff --git a/dali-toolkit/sounds/End_of_List.ogg b/dali-toolkit/sounds/End_of_List.ogg
new file mode 100644 (file)
index 0000000..3777683
Binary files /dev/null and b/dali-toolkit/sounds/End_of_List.ogg differ
diff --git a/dali-toolkit/sounds/Focus.ogg b/dali-toolkit/sounds/Focus.ogg
new file mode 100644 (file)
index 0000000..aec6d44
Binary files /dev/null and b/dali-toolkit/sounds/Focus.ogg differ
diff --git a/dali-toolkit/sounds/List_scroll.ogg b/dali-toolkit/sounds/List_scroll.ogg
new file mode 100644 (file)
index 0000000..c40fd6a
Binary files /dev/null and b/dali-toolkit/sounds/List_scroll.ogg differ
diff --git a/dali-toolkit/sounds/file.list b/dali-toolkit/sounds/file.list
new file mode 100644 (file)
index 0000000..2b6b3d5
--- /dev/null
@@ -0,0 +1,5 @@
+# Files to install here
+SET( dali_toolkit_sound_files
+  ${toolkit_sounds_dir}/*.ogg
+)
+
diff --git a/dali-toolkit/styles/1920x1080/dali-toolkit-default-theme.json b/dali-toolkit/styles/1920x1080/dali-toolkit-default-theme.json
new file mode 100755 (executable)
index 0000000..43bd4e5
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * 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.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 1920x1080 resolution, The values determined by UX design specification.
+// This file can be copied to a new folder within the styles/ directory and amended with new default values.
+// Can be overriden if StyleManager applies another style sheet.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png",
+    "alwaysShowFocus":true,
+    "clearFocusOnEscape":false
+  },
+  "styles":
+  {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":42
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
+    "TextLabel":
+    {
+      "pointSize":54,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80,
+      "ignoreSpacesAfterText":false
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":42
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":48
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":54
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":60
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":66
+    },
+
+    "TextField":
+    {
+      "pointSize":60,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":false
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":60
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":60
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":60
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":60
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":60
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[1700,100],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "rendererType": "image",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":60
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[1920.0,130.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png"
+      },
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[1920.0,130.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[1920.0,130.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "TextEditor":
+    {
+      "pointSize":60,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":false
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 12.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "styles":["Tooltip"],
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "styles":["Button"],
+      "autoRepeating":false,
+      "togglable":false,
+      "labelPadding":[ 12.0, 12.0, 12.0, 12.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "horizontalAlignment": "CENTER",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-up.9.png"
+       },
+       "selectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down.9.png"
+       },
+       "disabledSelectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down-disabled.9.png"
+       },
+       "disabledUnselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-disabled.9.png"
+       }
+    },
+    "ToggleButton":
+    {
+      "styles":["Button"]
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/1920x1080/images/cursor_handler_drop_center.png b/dali-toolkit/styles/1920x1080/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/1920x1080/images/selection_handle_drop_left.png b/dali-toolkit/styles/1920x1080/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/1920x1080/images/selection_handle_drop_right.png b/dali-toolkit/styles/1920x1080/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/1920x1080/images/selection_handle_drop_right.png differ
diff --git a/dali-toolkit/styles/2048x1080/dali-toolkit-default-theme.json b/dali-toolkit/styles/2048x1080/dali-toolkit-default-theme.json
new file mode 100755 (executable)
index 0000000..2028c16
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * 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.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 2048x1080 (2K) resolution, Andriod xxxhdpi DPI.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png",
+    "alwaysShowFocus":true,
+    "clearFocusOnEscape":false
+  },
+  "styles":
+  {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":6
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
+    "TextLabel":
+    {
+      "pointSize":8,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80,
+      "ignoreSpacesAfterText":false
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":4
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":6
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":8
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":10
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":12
+    },
+
+    "TextField":
+    {
+      "pointSize":8,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":false
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":10
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[1700,100],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "rendererType": "image",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":10
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[2048.0,130.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png"
+      },
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[2048.0,130.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":960.0,
+      "overshootSize":[2048.0,130.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "TextEditor":
+    {
+      "pointSize":8,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":6,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":false
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 10.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "styles":["Tooltip"],
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "styles":["Button"],
+      "autoRepeating":false,
+      "togglable":false,
+      "labelPadding":[ 12.0, 12.0, 12.0, 12.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "horizontalAlignment": "CENTER",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-up.9.png"
+       },
+       "selectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down.9.png"
+       },
+       "disabledSelectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down-disabled.9.png"
+       },
+       "disabledUnselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-disabled.9.png"
+       }
+    },
+    "ToggleButton":
+    {
+      "styles":["Button"]
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/2048x1080/images/cursor_handler_drop_center.png b/dali-toolkit/styles/2048x1080/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/2048x1080/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/2048x1080/images/selection_handle_drop_left.png b/dali-toolkit/styles/2048x1080/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/2048x1080/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/2048x1080/images/selection_handle_drop_right.png b/dali-toolkit/styles/2048x1080/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..244096f
Binary files /dev/null and b/dali-toolkit/styles/2048x1080/images/selection_handle_drop_right.png differ
diff --git a/dali-toolkit/styles/360x360/dali-toolkit-default-theme.json b/dali-toolkit/styles/360x360/dali-toolkit-default-theme.json
new file mode 100644 (file)
index 0000000..36db9a1
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * 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.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 480x800 resolution, The values determined by UX design specification.
+// This file can be copied to a new folder within the styles/ directory and amended with new default values.
+// Can be overriden if StyleManager applies another style sheet.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "alwaysShowFocus":false,
+    "clearFocusOnEscape":true
+  },
+  "styles":
+  {
+    "TextLabel":
+    {
+      "pointSize":18,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":8
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":19
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":25
+    },
+    "TextField":
+    {
+      "pointSize":10,
+      "primaryCursorColor":[0.07,0.70,1.0,1.0],
+      "secondaryCursorColor":[0.07,0.70,1.0,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":true,
+      "textColor":[0.99,0.99,0.99,1.0],
+      "background": {
+        "visualType": "COLOR",
+        "mixColor":[0.0,0.0,0.0,1.0]
+        },
+      "textBackground":[0.0,0.0,0.0,1.0]
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":10
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[656,72],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":8
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[720.0,130.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png"
+      },
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "TextEditor":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":true
+    },
+    "Popup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "ConfirmationPopup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "Slider":
+    {
+      "showPopup": true,
+      "showValue": true,
+      "valuePrecision": 0,
+      "trackVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin.9.png",
+        "size":[27,27]
+      },
+      "progressVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-progress.9.png",
+        "size":[27,27]
+      },
+      "handleVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-handle.png",
+        "size":[72,72]
+      },
+      "popupVisual":"{DALI_IMAGE_DIR}slider-popup.9.png",
+      "popupArrowVisual":"{DALI_IMAGE_DIR}slider-popup-arrow.9.png",
+      "disableColor":[0.5, 0.5, 0.5, 1.0],
+      "popupTextColor":[0.5,0.5,0.5,1.0],
+      "hitRegion":[0, 72],
+      "marks":[],
+      "snapToMarks":false,
+      "markTolerance":0.05
+    },
+    "SliderHandleTextLabel":
+    {
+      "textColor":[0.8,0.8,1,1]
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 12.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "anchorPoint": [ 0.5, 1.0, 0.5 ],
+      "parentOrigin": [ 0.5, 1.0, 0,5 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "text" : "BOTTOM_BTN",
+         "horizontalAlignment": "CENTER",
+         "verticalAlignment": "CENTER",
+         "pointSize" : 6.0,
+         "textColor": [0.98,0.98,0.98,1.0]
+       },
+      "background":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_STYLE_IMAGE_DIR}tw_bottom_btn_bg.png",
+         "mixColor": [0.0,0.21,0.29,0.9]
+       },
+       "selectedStateImage":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_STYLE_IMAGE_DIR}tw_bottom_btn_bg.png",
+         "mixColor": [0.0,0.57,0.8,0.3]
+       }
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/360x360/images/cursor_handler_drop_center.png b/dali-toolkit/styles/360x360/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..a9a2b9e
Binary files /dev/null and b/dali-toolkit/styles/360x360/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/360x360/images/selection_handle_drop_left.png b/dali-toolkit/styles/360x360/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..d9ed8b8
Binary files /dev/null and b/dali-toolkit/styles/360x360/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/360x360/images/selection_handle_drop_right.png b/dali-toolkit/styles/360x360/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..f66b26b
Binary files /dev/null and b/dali-toolkit/styles/360x360/images/selection_handle_drop_right.png differ
diff --git a/dali-toolkit/styles/360x360/images/tw_bottom_btn_bg.png b/dali-toolkit/styles/360x360/images/tw_bottom_btn_bg.png
new file mode 100755 (executable)
index 0000000..55522be
Binary files /dev/null and b/dali-toolkit/styles/360x360/images/tw_bottom_btn_bg.png differ
diff --git a/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json b/dali-toolkit/styles/480x800/dali-toolkit-default-theme.json
new file mode 100644 (file)
index 0000000..f35f988
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * 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.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 480x800 resolution, The values determined by UX design specification.
+// This file can be copied to a new folder within the styles/ directory and amended with new default values.
+// Can be overriden if StyleManager applies another style sheet.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png",
+    "alwaysShowFocus":false,
+    "clearFocusOnEscape":true
+  },
+  "styles":
+  {
+    "Tooltip":
+    {
+      "tooltip":
+      {
+        "content":
+        {
+          "pointSize":12
+        },
+        "waitTime":0.5,
+        "background":
+        {
+          "visual":"{DALI_IMAGE_DIR}tooltip.9.png",
+          "border":[1,5,5,1]
+        },
+        "tail":
+        {
+          "visibility":false,
+          "aboveVisual":"{DALI_IMAGE_DIR}tooltip-tail-above.png",
+          "belowVisual":"{DALI_IMAGE_DIR}tooltip-tail-below.png"
+        },
+        "position":"BELOW",
+        "hoverPointOffset":[10,10],
+        "movementThreshold":5,
+        "disappearOnMovement":false
+      }
+    },
+    "TextLabel":
+    {
+      "pointSize":18,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":8
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":19
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":25
+    },
+    "TextField":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":1,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":true
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":10
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[400,100],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":8
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":120.0,
+        "overshootSize":[480.0,42.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png" // designed for HD resolution
+      },
+      "color":[0.0,0.72,0.9,0.7],
+      "scale":[0.625,1.0,1.0] // Note: This reduces height for WVGA resolution
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":120.0,
+      "overshootSize":[480.0,42.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":120.0,
+      "overshootSize":[480.0,42.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25
+    },
+    "ScrollBarIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}popup_scroll.9.png"
+      }
+    },
+    "TextEditor":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":1,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":true
+    },
+    "Popup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "ConfirmationPopup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "Slider":
+    {
+      "showPopup": true,
+      "showValue": true,
+      "valuePrecision": 0,
+      "trackVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin.9.png",
+        "size":[27,27]
+      },
+      "progressVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-progress.9.png",
+        "size":[27,27]
+      },
+      "handleVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-handle.png",
+        "size":[72,72]
+      },
+      "popupVisual":"{DALI_IMAGE_DIR}slider-popup.9.png",
+      "popupArrowVisual":"{DALI_IMAGE_DIR}slider-popup-arrow.9.png",
+      "disableColor":[0.5, 0.5, 0.5, 1.0],
+      "popupTextColor":[0.5,0.5,0.5,1.0],
+      "hitRegion":[0, 72],
+      "marks":[],
+      "snapToMarks":false,
+      "markTolerance":0.05
+    },
+    "SliderHandleTextLabel":
+    {
+      "textColor":[0.8,0.8,1,1]
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 12.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "styles":["Tooltip"],
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "styles":["Button"],
+      "autoRepeating":false,
+      "togglable":false,
+      "labelPadding":[ 12.0, 12.0, 12.0, 12.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "horizontalAlignment": "CENTER",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-up.9.png"
+       },
+       "selectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down.9.png"
+       },
+       "disabledSelectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down-disabled.9.png"
+       },
+       "disabledUnselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-disabled.9.png"
+       }
+    },
+    "ToggleButton":
+    {
+      "styles":["Button"]
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 15.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png b/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..a9a2b9e
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png b/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..d9ed8b8
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png b/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..f66b26b
Binary files /dev/null and b/dali-toolkit/styles/480x800/images/selection_handle_drop_right.png differ
diff --git a/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json b/dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json
new file mode 100644 (file)
index 0000000..1a9d7ab
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This file is part of Dali Toolkit
+ *
+ * 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.
+ */
+
+
+//******************************************************************************
+//
+// Default Reference style theme for a 720x1280 resolution, The values determined by UX design specification.
+// This file can be copied to a new folder within the styles/ directory and amended with new default values.
+// Can be overriden if StyleManager applies another style sheet.
+//
+//******************************************************************************
+
+{
+  "config":
+  {
+    "brokenImageUrl":"{DALI_IMAGE_DIR}broken.png",
+    "alwaysShowFocus":false,
+    "clearFocusOnEscape":true
+  },
+  "styles":
+  {
+    "TextLabel":
+    {
+      "pointSize":18,
+      "enableAutoScroll":false,
+      "autoScrollLoopCount":2,
+      "autoScrollGap":50,
+      "autoScrollSpeed":80
+    },
+
+    "TextLabelFontSize0":
+    {
+      "pointSize":8
+    },
+    "TextLabelFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextLabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "TextLabelFontSize3":
+    {
+      "pointSize":19
+    },
+    "TextLabelFontSize4":
+    {
+      "pointSize":25
+    },
+    "TextField":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableSelection":true
+    },
+
+    "TextFieldFontSize0":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize1":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize2":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize3":
+    {
+      "pointSize":10
+    },
+    "TextFieldFontSize4":
+    {
+      "pointSize":10
+    },
+    "TextSelectionPopup":
+    {
+      "popupMaxSize":[656,72],
+      "optionDividerSize":[2,0],
+      "popupDividerColor":[0.23,0.72,0.8,0.11],
+      "popupIconColor":[1.0,1.0,1.0,1.0],
+      "popupPressedColor":[0.24,0.72,0.8,0.11],
+      "background": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-background.9.png"
+        },
+      "backgroundBorder": {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}selection-popup-border.9.png",
+        "mixColor":[0.24,0.72,0.8,1.0]
+        },
+      "popupFadeInDuration":0.25,
+      "popupFadeOutDuration":0.25
+    },
+    "TextSelectionPopupButton":
+    {
+      "label":
+      {
+        "visualType":"TEXT",
+        "pointSize":8
+      },
+      "unselectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      },
+      "selectedBackgroundVisual":
+      {
+        "visualType": "IMAGE",
+        "url": ""
+      }
+    },
+    "TextSelectionToolbar":
+    {
+      "enableOvershoot":true,
+      "enableScrollBar":true,
+      "scrollView":
+      {
+        "overshootAnimationSpeed":360.0,
+        "overshootSize":[720.0,130.0]
+      }
+    },
+    "TextSelectionScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "indicatorTransientDuration":1.0
+    },
+    "TextSelectionScrollIndicator":
+    {
+      "image":
+      {
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}text_selection_scroll_indicator.9.png"
+      },
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "ScrollView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "ItemView":
+    {
+      "overshootEffectColor":"B018",
+      "overshootAnimationSpeed":360.0,
+      "overshootSize":[720.0,130.0]
+    },
+    "ScrollBar":
+    {
+      "indicatorShowDuration":0.25,
+      "indicatorHideDuration":0.25,
+      "color":[0.0,0.72,0.9,0.7]
+    },
+    "TextEditor":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":3,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" },
+      "enableScrollBar":true,
+      "scrollBarShowDuration":0.8,
+      "scrollBarFadeDuration":0.5,
+      "enableSelection":true
+    },
+    "Popup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "ConfirmationPopup":
+    {
+      "popupBackgroundImage":"{DALI_IMAGE_DIR}00_popup_bg.9.png",
+      "tailUpImage":"{DALI_IMAGE_DIR}popup_tail_up.png",
+      "tailDownImage":"{DALI_IMAGE_DIR}popup_tail_down.png",
+      "tailLeftImage":"{DALI_IMAGE_DIR}popup_tail_left.png",
+      "tailRightImage":"{DALI_IMAGE_DIR}popup_tail_right.png",
+      "popupBackgroundBorder":[17,17,13,13]
+    },
+    "Slider":
+    {
+      "showPopup": true,
+      "showValue": true,
+      "valuePrecision": 0,
+      "trackVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin.9.png",
+        "size":[27,27]
+      },
+      "progressVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-progress.9.png",
+        "size":[27,27]
+      },
+      "handleVisual":{
+        "url":"{DALI_IMAGE_DIR}slider-skin-handle.png",
+        "size":[72,72]
+      },
+      "popupVisual":"{DALI_IMAGE_DIR}slider-popup.9.png",
+      "popupArrowVisual":"{DALI_IMAGE_DIR}slider-popup-arrow.9.png",
+      "disableColor":[0.5, 0.5, 0.5, 1.0],
+      "popupTextColor":[0.5,0.5,0.5,1.0],
+      "hitRegion":[0, 72],
+      "marks":[],
+      "snapToMarks":false,
+      "markTolerance":0.05
+    },
+    "SliderHandleTextLabel":
+    {
+      "textColor":[0.8,0.8,1,1]
+    },
+    "ProgressBar":
+    {
+      "trackVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-track.9.png"
+      },
+      "progressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-progress.9.png"
+      },
+      "secondaryProgressVisual":{
+        "visualType":"IMAGE",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-secondary-progress.9.png"
+      },
+      "indeterminateVisual":{
+        "visualType":"IMAGE",
+        "pixelArea":[0.0, 0.0, 10.0, 1.0],
+        "wrapModeU":"REPEAT",
+        "url":"{DALI_IMAGE_DIR}progress-bar-skin-indeterminate.png"
+      },
+      "indeterminateVisualAnimation":
+      [
+        {
+          "target":"indeterminateVisual",
+          "property":"pixelArea",
+          "initialValue":[0.0, 0.0, 10.0, 1.0],
+          "targetValue":[-1.0, 0.0, 10.0, 1.0],
+          "animator":
+          {
+            "alphaFunction":"DEFAULT",
+            "timePeriod":
+            {
+              "duration":0.8,
+              "delay":0
+            }
+          }
+        }
+      ],
+      "labelVisual":{
+        "visualType": "TEXT",
+        "textColor": [ 1.0, 1.0, 1.0, 1.0 ],
+        "pointSize" : 12.0, // Point size must always be provided to Text Visual
+        "horizontalAlignment": "CENTER",
+        "verticalAlignment": "CENTER"
+      },
+      "progressValue": 0.0,
+      "secondaryProgressValue":0.0,
+      "indeterminate": false
+    },
+    "Button":
+    {
+      "initialAutoRepeatingDelay":2.0,
+      "nextAutoRepeatingDelay":0.9
+      // Note: Visuals added to Button will be used in all derived buttons unless overridden.
+    },
+    "PushButton":
+    {
+      "styles":["Button"],
+      "autoRepeating":false,
+      "togglable":false,
+      "labelPadding":[ 12.0, 12.0, 12.0, 12.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "horizontalAlignment": "CENTER",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-up.9.png"
+       },
+       "selectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down.9.png"
+       },
+       "disabledSelectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-down-disabled.9.png"
+       },
+       "disabledUnselectedBackgroundVisual":
+       {
+         "visualType": "IMAGE",
+         "url": "{DALI_IMAGE_DIR}button-disabled.9.png"
+       }
+    },
+    "CheckBoxButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}checkbox-selected-disabled.png"
+      }
+    },
+    "RadioButton":
+    {
+      "styles":["Button"],
+      "labelPadding":[ 12.0, 12.0, 0.0, 0.0 ],
+      "label":
+       {
+         "visualType": "TEXT",
+         "pointSize" : 10.0, // Point size must always be provided to Text Visual
+         "verticalAlignment": "CENTER"
+       },
+      "unselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected.png"
+      },
+      "selectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected.png"
+      },
+      "disabledUnselectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-unselected-disabled.png"
+      },
+      "disabledSelectedVisual":
+      {
+        "visualType": "IMAGE",
+        "url": "{DALI_IMAGE_DIR}radio-button-selected-disabled.png"
+      }
+    }
+  }
+}
diff --git a/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png b/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png
new file mode 100644 (file)
index 0000000..15c937a
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/cursor_handler_drop_center.png differ
diff --git a/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png b/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png
new file mode 100644 (file)
index 0000000..149becb
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/selection_handle_drop_left.png differ
diff --git a/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png b/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png
new file mode 100644 (file)
index 0000000..75035bc
Binary files /dev/null and b/dali-toolkit/styles/720x1280/images/selection_handle_drop_right.png differ
diff --git a/dali-toolkit/styles/default-feedback-theme.json b/dali-toolkit/styles/default-feedback-theme.json
new file mode 100644 (file)
index 0000000..5b6c9b9
--- /dev/null
@@ -0,0 +1,20 @@
+//******************************************************************************
+//
+// Default feedback theme for dali-toolkit
+//
+//******************************************************************************
+{
+  "style":
+  {
+    "PushButton":
+    {
+      "signals":
+      [
+        {
+          "type": "clicked",
+          "soundFeedbackPattern": "FEEDBACK_PATTERN_TAP"
+        }
+      ]
+    }
+  }
+}
diff --git a/dali-toolkit/styles/file.list b/dali-toolkit/styles/file.list
new file mode 100644 (file)
index 0000000..bd9360d
--- /dev/null
@@ -0,0 +1,10 @@
+# Files to install here
+SET( dali_toolkit_style_files
+    ${toolkit_styles_base_dir}/*.json
+    ${toolkit_styles_dir}/*.json
+)
+
+SET( dali_toolkit_style_images
+    ${toolkit_style_images_dir}/*.png
+)
+
diff --git a/dali-toolkit/styles/images-common/00_popup_bg.9.png b/dali-toolkit/styles/images-common/00_popup_bg.9.png
new file mode 100644 (file)
index 0000000..825dd98
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_bg.9.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_bg.png b/dali-toolkit/styles/images-common/00_popup_bg.png
new file mode 100644 (file)
index 0000000..cc300fa
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_bg.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_bottom_bg.png b/dali-toolkit/styles/images-common/00_popup_bottom_bg.png
new file mode 100755 (executable)
index 0000000..c595eec
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_bottom_bg.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_bubble_bg.png b/dali-toolkit/styles/images-common/00_popup_bubble_bg.png
new file mode 100755 (executable)
index 0000000..ad3740b
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_bubble_bg.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_bubble_tail_bottom.png b/dali-toolkit/styles/images-common/00_popup_bubble_tail_bottom.png
new file mode 100755 (executable)
index 0000000..c1e6d8b
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_bubble_tail_bottom.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_button_bg.png b/dali-toolkit/styles/images-common/00_popup_button_bg.png
new file mode 100644 (file)
index 0000000..10c7466
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_button_bg.png differ
diff --git a/dali-toolkit/styles/images-common/00_popup_button_pressed.png b/dali-toolkit/styles/images-common/00_popup_button_pressed.png
new file mode 100755 (executable)
index 0000000..faa5cea
Binary files /dev/null and b/dali-toolkit/styles/images-common/00_popup_button_pressed.png differ
diff --git a/dali-toolkit/styles/images-common/B16-8_TTS_focus.9.png b/dali-toolkit/styles/images-common/B16-8_TTS_focus.9.png
new file mode 100644 (file)
index 0000000..535d0e9
Binary files /dev/null and b/dali-toolkit/styles/images-common/B16-8_TTS_focus.9.png differ
diff --git a/dali-toolkit/styles/images-common/brdfLUT.png b/dali-toolkit/styles/images-common/brdfLUT.png
new file mode 100644 (file)
index 0000000..5f6541b
Binary files /dev/null and b/dali-toolkit/styles/images-common/brdfLUT.png differ
diff --git a/dali-toolkit/styles/images-common/broken.png b/dali-toolkit/styles/images-common/broken.png
new file mode 100644 (file)
index 0000000..2d1c272
Binary files /dev/null and b/dali-toolkit/styles/images-common/broken.png differ
diff --git a/dali-toolkit/styles/images-common/button-disabled.9.png b/dali-toolkit/styles/images-common/button-disabled.9.png
new file mode 100644 (file)
index 0000000..36b3908
Binary files /dev/null and b/dali-toolkit/styles/images-common/button-disabled.9.png differ
diff --git a/dali-toolkit/styles/images-common/button-down-disabled.9.png b/dali-toolkit/styles/images-common/button-down-disabled.9.png
new file mode 100644 (file)
index 0000000..21084b2
Binary files /dev/null and b/dali-toolkit/styles/images-common/button-down-disabled.9.png differ
diff --git a/dali-toolkit/styles/images-common/button-down.9.png b/dali-toolkit/styles/images-common/button-down.9.png
new file mode 100644 (file)
index 0000000..f6e25ab
Binary files /dev/null and b/dali-toolkit/styles/images-common/button-down.9.png differ
diff --git a/dali-toolkit/styles/images-common/button-up.9.png b/dali-toolkit/styles/images-common/button-up.9.png
new file mode 100644 (file)
index 0000000..a2e2e01
Binary files /dev/null and b/dali-toolkit/styles/images-common/button-up.9.png differ
diff --git a/dali-toolkit/styles/images-common/checkbox-selected-disabled.png b/dali-toolkit/styles/images-common/checkbox-selected-disabled.png
new file mode 100644 (file)
index 0000000..a6517b8
Binary files /dev/null and b/dali-toolkit/styles/images-common/checkbox-selected-disabled.png differ
diff --git a/dali-toolkit/styles/images-common/checkbox-selected.png b/dali-toolkit/styles/images-common/checkbox-selected.png
new file mode 100644 (file)
index 0000000..e3a8c43
Binary files /dev/null and b/dali-toolkit/styles/images-common/checkbox-selected.png differ
diff --git a/dali-toolkit/styles/images-common/checkbox-unselected-disabled.png b/dali-toolkit/styles/images-common/checkbox-unselected-disabled.png
new file mode 100644 (file)
index 0000000..022c1cf
Binary files /dev/null and b/dali-toolkit/styles/images-common/checkbox-unselected-disabled.png differ
diff --git a/dali-toolkit/styles/images-common/checkbox-unselected.png b/dali-toolkit/styles/images-common/checkbox-unselected.png
new file mode 100644 (file)
index 0000000..58e9390
Binary files /dev/null and b/dali-toolkit/styles/images-common/checkbox-unselected.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_clipboard.png b/dali-toolkit/styles/images-common/copy_paste_icon_clipboard.png
new file mode 100644 (file)
index 0000000..d158872
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_clipboard.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_copy.png b/dali-toolkit/styles/images-common/copy_paste_icon_copy.png
new file mode 100644 (file)
index 0000000..c79fa99
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_copy.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_cut.png b/dali-toolkit/styles/images-common/copy_paste_icon_cut.png
new file mode 100644 (file)
index 0000000..f819fc6
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_cut.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_paste.png b/dali-toolkit/styles/images-common/copy_paste_icon_paste.png
new file mode 100644 (file)
index 0000000..139695f
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_paste.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_select.png b/dali-toolkit/styles/images-common/copy_paste_icon_select.png
new file mode 100644 (file)
index 0000000..d4585d2
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_select.png differ
diff --git a/dali-toolkit/styles/images-common/copy_paste_icon_select_all.png b/dali-toolkit/styles/images-common/copy_paste_icon_select_all.png
new file mode 100644 (file)
index 0000000..9506c04
Binary files /dev/null and b/dali-toolkit/styles/images-common/copy_paste_icon_select_all.png differ
diff --git a/dali-toolkit/styles/images-common/cursor_handler_ball_center.png b/dali-toolkit/styles/images-common/cursor_handler_ball_center.png
new file mode 100755 (executable)
index 0000000..d9841f8
Binary files /dev/null and b/dali-toolkit/styles/images-common/cursor_handler_ball_center.png differ
diff --git a/dali-toolkit/styles/images-common/file.list b/dali-toolkit/styles/images-common/file.list
new file mode 100644 (file)
index 0000000..e581739
--- /dev/null
@@ -0,0 +1,5 @@
+# Files to install here
+SET( dali_toolkit_image_files
+    ${toolkit_images_dir}/*.png
+)
+
diff --git a/dali-toolkit/styles/images-common/insertpoint-icon-pressed.png b/dali-toolkit/styles/images-common/insertpoint-icon-pressed.png
new file mode 100644 (file)
index 0000000..171b737
Binary files /dev/null and b/dali-toolkit/styles/images-common/insertpoint-icon-pressed.png differ
diff --git a/dali-toolkit/styles/images-common/insertpoint-icon.png b/dali-toolkit/styles/images-common/insertpoint-icon.png
new file mode 100644 (file)
index 0000000..61ab852
Binary files /dev/null and b/dali-toolkit/styles/images-common/insertpoint-icon.png differ
diff --git a/dali-toolkit/styles/images-common/keyboard_focus.9.png b/dali-toolkit/styles/images-common/keyboard_focus.9.png
new file mode 100644 (file)
index 0000000..5590f15
Binary files /dev/null and b/dali-toolkit/styles/images-common/keyboard_focus.9.png differ
diff --git a/dali-toolkit/styles/images-common/magnifier.png b/dali-toolkit/styles/images-common/magnifier.png
new file mode 100644 (file)
index 0000000..1846be2
Binary files /dev/null and b/dali-toolkit/styles/images-common/magnifier.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bg.png b/dali-toolkit/styles/images-common/popup_bg.png
new file mode 100644 (file)
index 0000000..3b2ff97
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bg.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_bg.#.png b/dali-toolkit/styles/images-common/popup_bubble_bg.#.png
new file mode 100644 (file)
index 0000000..202ecec
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_bg.#.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_bg_ef.#.png b/dali-toolkit/styles/images-common/popup_bubble_bg_ef.#.png
new file mode 100644 (file)
index 0000000..462c9db
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_bg_ef.#.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_bg_line.#.png b/dali-toolkit/styles/images-common/popup_bubble_bg_line.#.png
new file mode 100644 (file)
index 0000000..92aee52
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_bg_line.#.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_bottom.png b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom.png
new file mode 100644 (file)
index 0000000..2ca1593
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_ef.png b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_ef.png
new file mode 100644 (file)
index 0000000..53b87fe
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_ef.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_line.png b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_line.png
new file mode 100644 (file)
index 0000000..99a9c23
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_bottom_line.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_top.png b/dali-toolkit/styles/images-common/popup_bubble_tail_top.png
new file mode 100755 (executable)
index 0000000..6e635fc
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_top.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_top_ef.png b/dali-toolkit/styles/images-common/popup_bubble_tail_top_ef.png
new file mode 100755 (executable)
index 0000000..1ace985
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_top_ef.png differ
diff --git a/dali-toolkit/styles/images-common/popup_bubble_tail_top_line.png b/dali-toolkit/styles/images-common/popup_bubble_tail_top_line.png
new file mode 100755 (executable)
index 0000000..3b1ad65
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_bubble_tail_top_line.png differ
diff --git a/dali-toolkit/styles/images-common/popup_scroll.9.png b/dali-toolkit/styles/images-common/popup_scroll.9.png
new file mode 100644 (file)
index 0000000..2ffc3a7
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_scroll.9.png differ
diff --git a/dali-toolkit/styles/images-common/popup_tail_down.png b/dali-toolkit/styles/images-common/popup_tail_down.png
new file mode 100755 (executable)
index 0000000..806ba0e
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_tail_down.png differ
diff --git a/dali-toolkit/styles/images-common/popup_tail_left.png b/dali-toolkit/styles/images-common/popup_tail_left.png
new file mode 100644 (file)
index 0000000..b2ed047
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_tail_left.png differ
diff --git a/dali-toolkit/styles/images-common/popup_tail_right.png b/dali-toolkit/styles/images-common/popup_tail_right.png
new file mode 100644 (file)
index 0000000..16b28e0
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_tail_right.png differ
diff --git a/dali-toolkit/styles/images-common/popup_tail_up.png b/dali-toolkit/styles/images-common/popup_tail_up.png
new file mode 100644 (file)
index 0000000..599cf17
Binary files /dev/null and b/dali-toolkit/styles/images-common/popup_tail_up.png differ
diff --git a/dali-toolkit/styles/images-common/progress-bar-skin-indeterminate.png b/dali-toolkit/styles/images-common/progress-bar-skin-indeterminate.png
new file mode 100644 (file)
index 0000000..df99c15
Binary files /dev/null and b/dali-toolkit/styles/images-common/progress-bar-skin-indeterminate.png differ
diff --git a/dali-toolkit/styles/images-common/progress-bar-skin-progress.9.png b/dali-toolkit/styles/images-common/progress-bar-skin-progress.9.png
new file mode 100644 (file)
index 0000000..b77b29d
Binary files /dev/null and b/dali-toolkit/styles/images-common/progress-bar-skin-progress.9.png differ
diff --git a/dali-toolkit/styles/images-common/progress-bar-skin-secondary-progress.9.png b/dali-toolkit/styles/images-common/progress-bar-skin-secondary-progress.9.png
new file mode 100644 (file)
index 0000000..54184e5
Binary files /dev/null and b/dali-toolkit/styles/images-common/progress-bar-skin-secondary-progress.9.png differ
diff --git a/dali-toolkit/styles/images-common/progress-bar-skin-track.9.png b/dali-toolkit/styles/images-common/progress-bar-skin-track.9.png
new file mode 100644 (file)
index 0000000..92a1dee
Binary files /dev/null and b/dali-toolkit/styles/images-common/progress-bar-skin-track.9.png differ
diff --git a/dali-toolkit/styles/images-common/radio-button-selected-disabled.png b/dali-toolkit/styles/images-common/radio-button-selected-disabled.png
new file mode 100644 (file)
index 0000000..5c40e4b
Binary files /dev/null and b/dali-toolkit/styles/images-common/radio-button-selected-disabled.png differ
diff --git a/dali-toolkit/styles/images-common/radio-button-selected.png b/dali-toolkit/styles/images-common/radio-button-selected.png
new file mode 100644 (file)
index 0000000..d49cbb5
Binary files /dev/null and b/dali-toolkit/styles/images-common/radio-button-selected.png differ
diff --git a/dali-toolkit/styles/images-common/radio-button-unselected-disabled.png b/dali-toolkit/styles/images-common/radio-button-unselected-disabled.png
new file mode 100644 (file)
index 0000000..0c5fa5f
Binary files /dev/null and b/dali-toolkit/styles/images-common/radio-button-unselected-disabled.png differ
diff --git a/dali-toolkit/styles/images-common/radio-button-unselected.png b/dali-toolkit/styles/images-common/radio-button-unselected.png
new file mode 100644 (file)
index 0000000..6f647e8
Binary files /dev/null and b/dali-toolkit/styles/images-common/radio-button-unselected.png differ
diff --git a/dali-toolkit/styles/images-common/selection-popup-background.9.png b/dali-toolkit/styles/images-common/selection-popup-background.9.png
new file mode 100644 (file)
index 0000000..0b59668
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection-popup-background.9.png differ
diff --git a/dali-toolkit/styles/images-common/selection-popup-bg.9.png b/dali-toolkit/styles/images-common/selection-popup-bg.9.png
new file mode 100755 (executable)
index 0000000..bd91191
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection-popup-bg.9.png differ
diff --git a/dali-toolkit/styles/images-common/selection-popup-border.9.png b/dali-toolkit/styles/images-common/selection-popup-border.9.png
new file mode 100644 (file)
index 0000000..d7454f5
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection-popup-border.9.png differ
diff --git a/dali-toolkit/styles/images-common/selection_handle_ball_left.png b/dali-toolkit/styles/images-common/selection_handle_ball_left.png
new file mode 100755 (executable)
index 0000000..dea269c
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection_handle_ball_left.png differ
diff --git a/dali-toolkit/styles/images-common/selection_handle_ball_right.png b/dali-toolkit/styles/images-common/selection_handle_ball_right.png
new file mode 100755 (executable)
index 0000000..ea5ac91
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection_handle_ball_right.png differ
diff --git a/dali-toolkit/styles/images-common/selection_marker_left.png b/dali-toolkit/styles/images-common/selection_marker_left.png
new file mode 100644 (file)
index 0000000..3472053
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection_marker_left.png differ
diff --git a/dali-toolkit/styles/images-common/selection_marker_right.png b/dali-toolkit/styles/images-common/selection_marker_right.png
new file mode 100644 (file)
index 0000000..cd41114
Binary files /dev/null and b/dali-toolkit/styles/images-common/selection_marker_right.png differ
diff --git a/dali-toolkit/styles/images-common/slider-popup-arrow.png b/dali-toolkit/styles/images-common/slider-popup-arrow.png
new file mode 100644 (file)
index 0000000..0675a57
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-popup-arrow.png differ
diff --git a/dali-toolkit/styles/images-common/slider-popup.9.png b/dali-toolkit/styles/images-common/slider-popup.9.png
new file mode 100644 (file)
index 0000000..010cce7
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-popup.9.png differ
diff --git a/dali-toolkit/styles/images-common/slider-popup.png b/dali-toolkit/styles/images-common/slider-popup.png
new file mode 100644 (file)
index 0000000..1c123aa
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-popup.png differ
diff --git a/dali-toolkit/styles/images-common/slider-skin-handle.png b/dali-toolkit/styles/images-common/slider-skin-handle.png
new file mode 100644 (file)
index 0000000..af8f7b6
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-skin-handle.png differ
diff --git a/dali-toolkit/styles/images-common/slider-skin-progress.9.png b/dali-toolkit/styles/images-common/slider-skin-progress.9.png
new file mode 100644 (file)
index 0000000..4663335
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-skin-progress.9.png differ
diff --git a/dali-toolkit/styles/images-common/slider-skin-progress.png b/dali-toolkit/styles/images-common/slider-skin-progress.png
new file mode 100644 (file)
index 0000000..4da9e7f
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-skin-progress.png differ
diff --git a/dali-toolkit/styles/images-common/slider-skin.9.png b/dali-toolkit/styles/images-common/slider-skin.9.png
new file mode 100644 (file)
index 0000000..e1c2ca0
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-skin.9.png differ
diff --git a/dali-toolkit/styles/images-common/slider-skin.png b/dali-toolkit/styles/images-common/slider-skin.png
new file mode 100644 (file)
index 0000000..b006bdd
Binary files /dev/null and b/dali-toolkit/styles/images-common/slider-skin.png differ
diff --git a/dali-toolkit/styles/images-common/text-input-selection-handle-left-press.png b/dali-toolkit/styles/images-common/text-input-selection-handle-left-press.png
new file mode 100644 (file)
index 0000000..b5ae3a8
Binary files /dev/null and b/dali-toolkit/styles/images-common/text-input-selection-handle-left-press.png differ
diff --git a/dali-toolkit/styles/images-common/text-input-selection-handle-left.png b/dali-toolkit/styles/images-common/text-input-selection-handle-left.png
new file mode 100644 (file)
index 0000000..ba10440
Binary files /dev/null and b/dali-toolkit/styles/images-common/text-input-selection-handle-left.png differ
diff --git a/dali-toolkit/styles/images-common/text-input-selection-handle-right-press.png b/dali-toolkit/styles/images-common/text-input-selection-handle-right-press.png
new file mode 100644 (file)
index 0000000..8acc177
Binary files /dev/null and b/dali-toolkit/styles/images-common/text-input-selection-handle-right-press.png differ
diff --git a/dali-toolkit/styles/images-common/text-input-selection-handle-right.png b/dali-toolkit/styles/images-common/text-input-selection-handle-right.png
new file mode 100644 (file)
index 0000000..3ab7a43
Binary files /dev/null and b/dali-toolkit/styles/images-common/text-input-selection-handle-right.png differ
diff --git a/dali-toolkit/styles/images-common/text_selection_scroll_indicator.9.png b/dali-toolkit/styles/images-common/text_selection_scroll_indicator.9.png
new file mode 100644 (file)
index 0000000..5bf5b3f
Binary files /dev/null and b/dali-toolkit/styles/images-common/text_selection_scroll_indicator.9.png differ
diff --git a/dali-toolkit/styles/images-common/tooltip-tail-above.png b/dali-toolkit/styles/images-common/tooltip-tail-above.png
new file mode 100644 (file)
index 0000000..9695929
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip-tail-above.png differ
diff --git a/dali-toolkit/styles/images-common/tooltip-tail-below.png b/dali-toolkit/styles/images-common/tooltip-tail-below.png
new file mode 100644 (file)
index 0000000..3b4a0f9
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip-tail-below.png differ
diff --git a/dali-toolkit/styles/images-common/tooltip.9.png b/dali-toolkit/styles/images-common/tooltip.9.png
new file mode 100644 (file)
index 0000000..bd4b6e8
Binary files /dev/null and b/dali-toolkit/styles/images-common/tooltip.9.png differ
diff --git a/dali-toolkit/third-party/base-n/basen.hpp b/dali-toolkit/third-party/base-n/basen.hpp
new file mode 100644 (file)
index 0000000..7954e5b
--- /dev/null
@@ -0,0 +1,321 @@
+/**
+ * base-n, 1.0
+ * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+**/
+
+/*
+ * In the original file, static analysis complains about return type from decode methods
+ * not being testable against Error constant (due to difference of type sizes).
+ *
+ * Modified decode methods to return error through an out parameter instead.
+ */
+
+#ifndef BASEN_HPP
+#define BASEN_HPP
+
+#include <algorithm>
+#include <cctype>
+#include <cassert>
+#include <cstring>
+
+namespace bn
+{
+
+template<class Iter1, class Iter2>
+void encode_b16(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void encode_b32(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void encode_b64(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b16(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b32(Iter1 start, Iter1 end, Iter2 out);
+
+template<class Iter1, class Iter2>
+void decode_b64(Iter1 start, Iter1 end, Iter2 out);
+
+namespace impl
+{
+
+const int Error = -1;
+
+namespace {
+
+char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
+{
+    assert(start_bit + bits_count < 8);
+    // shift extracted bits to the beginning of the byte
+    char t1 = value >> (8 - bits_count - start_bit);
+    // mask out bits on the left
+    char t2 = t1 & ~(0xff << bits_count);
+    return t2;
+}
+
+char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
+{
+    assert(start_bit + bits_count < 16);
+    size_t bits_count_in_previous = 8 - start_bit;
+    size_t bits_count_in_next = bits_count - bits_count_in_previous;
+    char t1 = previous << bits_count_in_next;
+    char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
+    return (t1 | t2) & ~(0xff << bits_count);
+}
+
+}
+
+struct b16_conversion_traits
+{
+    static size_t group_length()
+    {
+       return 4;
+    }
+
+    static char encode(unsigned int index)
+    {
+        const char* const dictionary = "0123456789ABCDEF";
+        assert(index < strlen(dictionary));
+        return dictionary[index];
+    }
+
+    /*
+     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
+     * Separated error value from return value by using out parameter.
+     */
+    static char decode(char c, bool& error)
+    {
+        error=false;
+        if (c >= '0' && c <= '9') {
+            return c - '0';
+        } else if (c >= 'A' && c <= 'F') {
+            return c - 'A' + 10;
+        }
+        error=true;
+        return 0;
+    }
+};
+
+struct b32_conversion_traits
+{
+    static size_t group_length()
+    {
+       return 5;
+    }
+
+    static char encode(unsigned int index)
+    {
+        const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+        assert(index < strlen(dictionary));
+        return dictionary[index];
+    }
+
+    /*
+     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
+     * Separated error value from return value by using out parameter.
+     */
+    static char decode(char c, bool& error)
+    {
+        error=false;
+        if (c >= 'A' && c <= 'Z') {
+            return c - 'A';
+        } else if (c >= '2' && c <= '7') {
+            return c - '2' + 26;
+        }
+        error=true;
+        return 0;
+    }
+};
+
+struct b64_conversion_traits
+{
+    static size_t group_length()
+    {
+       return 6;
+    }
+
+    static char encode(unsigned int index)
+    {
+        const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+        assert(index < strlen(dictionary));
+        return dictionary[index];
+    }
+
+    /*
+     * In the original file, error code was passed through return value, but used int -1 (out of range of char).
+     * Separated error value from return value by using out parameter.
+     */
+    static char decode(char c, bool& error)
+    {
+        error=false;
+        const int alph_len = 26;
+        if (c >= 'A' && c <= 'Z') {
+            return c - 'A';
+        } else if (c >= 'a' && c <= 'z') {
+            return c - 'a' + alph_len * 1;
+        } else if (c >= '0' && c <= '9') {
+            return c - '0' + alph_len * 2;
+        } else if (c == '+') {
+            return c - '+' + alph_len * 2 + 10;
+        } else if (c == '/') {
+            return c - '/' + alph_len * 2 + 11;
+        }
+        error=true;
+        return 0;
+    }
+};
+
+template<class ConversionTraits, class Iter1, class Iter2>
+void decode(Iter1 start, Iter1 end, Iter2 out)
+{
+    Iter1 iter = start;
+    size_t output_current_bit = 0;
+    char buffer = 0;
+
+    while (iter != end) {
+        if (std::isspace(*iter)) {
+            ++iter;
+            continue;
+        }
+
+        /*
+         * In the original file, error value was out of range of return type.
+         * Separated error value from return value by using out parameter.
+         */
+        bool error=false;
+        char value = ConversionTraits::decode(*iter, error);
+        if (error) {
+            // malformed data, but let's go on...
+            ++iter;
+            continue;
+        }
+        size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
+        if (bits_in_current_byte == ConversionTraits::group_length()) {
+            // the value fits within current byte, so we can extract it directly
+            buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
+            output_current_bit += ConversionTraits::group_length();
+            // check if we filled up current byte completely; in such case we flush output and continue
+            if (output_current_bit == 8) {
+                *out++ = buffer;
+                buffer = 0;
+                output_current_bit = 0;
+            }
+        } else {
+            // the value spans across the current and the next byte
+            size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
+            // fill the current byte and flush it to our output
+            buffer |= value >> bits_in_next_byte;
+            *out++ = buffer;
+            buffer = 0;
+            // save the remainder of our value in the buffer; it will be flushed
+            // during next iterations
+            buffer |= value << (8 - bits_in_next_byte);
+            output_current_bit = bits_in_next_byte;
+        }
+        ++iter;
+    }
+}
+
+template<class ConversionTraits, class Iter1, class Iter2>
+void encode(Iter1 start, Iter1 end, Iter2 out)
+{
+    Iter1 iter = start;
+    size_t start_bit = 0;
+    bool has_backlog = false;
+    char backlog = 0;
+
+    while (has_backlog || iter != end) {
+        if (!has_backlog) {
+            if (start_bit + ConversionTraits::group_length() < 8) {
+                // the value fits within single byte, so we can extract it
+                // directly
+                char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
+                *out++ = ConversionTraits::encode(v);
+                // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
+                // to the next byte
+                start_bit += ConversionTraits::group_length();
+            } else {
+                // our bits are spanning across byte border; we need to keep the
+                // starting point and move over to next byte.
+                backlog = *iter++;
+                has_backlog = true;
+            }
+        } else {
+            // encode value which is made from bits spanning across byte
+            // boundary
+            char v;
+            if (iter == end)
+                 v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
+            else
+                 v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
+            *out++ = ConversionTraits::encode(v);
+            has_backlog = false;
+            start_bit = (start_bit + ConversionTraits::group_length()) % 8;
+        }
+    }
+}
+
+} // impl
+
+using namespace bn::impl;
+
+template<class Iter1, class Iter2>
+void encode_b16(Iter1 start, Iter1 end, Iter2 out)
+{
+    encode<b16_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void encode_b32(Iter1 start, Iter1 end, Iter2 out)
+{
+    encode<b32_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void encode_b64(Iter1 start, Iter1 end, Iter2 out)
+{
+    encode<b64_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b16(Iter1 start, Iter1 end, Iter2 out)
+{
+    decode<b16_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b32(Iter1 start, Iter1 end, Iter2 out)
+{
+    decode<b32_conversion_traits>(start, end, out);
+}
+
+template<class Iter1, class Iter2>
+void decode_b64(Iter1 start, Iter1 end, Iter2 out)
+{
+    decode<b64_conversion_traits>(start, end, out);
+}
+
+} // bn
+
+#endif // BASEN_HPP
diff --git a/dali-toolkit/third-party/file.list b/dali-toolkit/third-party/file.list
new file mode 100644 (file)
index 0000000..81eea7d
--- /dev/null
@@ -0,0 +1,20 @@
+# Set the source directory
+SET( third_party_src_dir ${ROOT_SRC_DIR}/dali-toolkit/third-party )
+
+SET( third_party_src_files
+   ${third_party_src_dir}/nanosvg/nanosvg.cc
+   ${third_party_src_dir}/nanosvg/nanosvgrast.cc
+   ${third_party_src_dir}/yoga/Utils.cpp
+   ${third_party_src_dir}/yoga/YGConfig.cpp
+   ${third_party_src_dir}/yoga/YGEnums.cpp
+   ${third_party_src_dir}/yoga/YGFloatOptional.cpp
+   ${third_party_src_dir}/yoga/YGLayout.cpp
+   ${third_party_src_dir}/yoga/YGNode.cpp
+   ${third_party_src_dir}/yoga/YGNodePrint.cpp
+   ${third_party_src_dir}/yoga/YGStyle.cpp
+   ${third_party_src_dir}/yoga/Yoga.cpp
+)
+
+SET( SOURCES ${SOURCES}
+  ${third_party_src_files}
+)
diff --git a/dali-toolkit/third-party/nanosvg/nanosvg.cc b/dali-toolkit/third-party/nanosvg/nanosvg.cc
new file mode 100755 (executable)
index 0000000..31f5f44
--- /dev/null
@@ -0,0 +1,2855 @@
+/*
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
+ * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
+ *
+ * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
+ *
+ * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
+ *
+ */
+
+#include "nanosvg.h"
+
+/**
+ * In the original software, The nanosvg implementation was included in the header file.
+ * We have separated the implementation to source file here.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define NSVG_PI (3.14159265358979323846264338327f)
+#define NSVG_KAPPA90 (0.5522847493f)   // Length proportional to radius of a cubic bezier handle for 90deg arcs.
+
+#define NSVG_ALIGN_MIN 0
+#define NSVG_ALIGN_MID 1
+#define NSVG_ALIGN_MAX 2
+#define NSVG_ALIGN_NONE 0
+#define NSVG_ALIGN_MEET 1
+#define NSVG_ALIGN_SLICE 2
+
+#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
+#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
+
+#ifdef _MSC_VER
+       #pragma warning (disable: 4996) // Switch off security warnings
+       #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
+       #ifdef __cplusplus
+       #define NSVG_INLINE inline
+       #else
+       #define NSVG_INLINE
+       #endif
+#else
+       #define NSVG_INLINE inline
+#endif
+
+
+static int nsvg__isspace(char c)
+{
+       return strchr(" \t\n\v\f\r", c) != 0;
+}
+
+static int nsvg__isdigit(char c)
+{
+       return c >= '0' && c <= '9';
+}
+
+static int nsvg__isnum(char c)
+{
+       return strchr("0123456789+-.eE", c) != 0;
+}
+
+static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
+static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
+
+
+// Simple XML parser
+
+#define NSVG_XML_TAG 1
+#define NSVG_XML_CONTENT 2
+#define NSVG_XML_MAX_ATTRIBS 256
+
+static void nsvg__parseContent(char* s,
+                                                          void (*contentCb)(void* ud, const char* s),
+                                                          void* ud)
+{
+       // Trim start white spaces
+       while (*s && nsvg__isspace(*s)) s++;
+       if (!*s) return;
+
+       if (contentCb)
+               (*contentCb)(ud, s);
+}
+
+static void nsvg__parseElement(char* s,
+                                                          void (*startelCb)(void* ud, const char* el, const char** attr),
+                                                          void (*endelCb)(void* ud, const char* el),
+                                                          void* ud)
+{
+       const char* attr[NSVG_XML_MAX_ATTRIBS];
+       int nattr = 0;
+       char* name;
+       int start = 0;
+       int end = 0;
+       char quote;
+
+       // Skip white space after the '<'
+       while (*s && nsvg__isspace(*s)) s++;
+
+       // Check if the tag is end tag
+       if (*s == '/') {
+               s++;
+               end = 1;
+       } else {
+               start = 1;
+       }
+
+       // Skip comments, data and preprocessor stuff.
+       if (!*s || *s == '?' || *s == '!')
+               return;
+
+       // Get tag name
+       name = s;
+       while (*s && !nsvg__isspace(*s)) s++;
+       if (*s) { *s++ = '\0'; }
+
+       // Get attribs
+       while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
+               char* name = NULL;
+               char* value = NULL;
+
+               // Skip white space before the attrib name
+               while (*s && nsvg__isspace(*s)) s++;
+               if (!*s) break;
+               if (*s == '/') {
+                       end = 1;
+                       break;
+               }
+               name = s;
+               // Find end of the attrib name.
+               while (*s && !nsvg__isspace(*s) && *s != '=') s++;
+               if (*s) { *s++ = '\0'; }
+               // Skip until the beginning of the value.
+               while (*s && *s != '\"' && *s != '\'') s++;
+               if (!*s) break;
+               quote = *s;
+               s++;
+               // Store value and find the end of it.
+               value = s;
+               while (*s && *s != quote) s++;
+               if (*s) { *s++ = '\0'; }
+
+               // Store only well formed attributes
+               if (name && value) {
+                       attr[nattr++] = name;
+                       attr[nattr++] = value;
+               }
+       }
+
+       // List terminator
+       attr[nattr++] = 0;
+       attr[nattr++] = 0;
+
+       // Call callbacks.
+       if (start && startelCb)
+               (*startelCb)(ud, name, attr);
+       if (end && endelCb)
+               (*endelCb)(ud, name);
+}
+
+int nsvg__parseXML(char* input,
+                                  void (*startelCb)(void* ud, const char* el, const char** attr),
+                                  void (*endelCb)(void* ud, const char* el),
+                                  void (*contentCb)(void* ud, const char* s),
+                                  void* ud)
+{
+       char* s = input;
+       char* mark = s;
+       int state = NSVG_XML_CONTENT;
+       while (*s) {
+               if (*s == '<' && state == NSVG_XML_CONTENT) {
+                       // Start of a tag
+                       *s++ = '\0';
+                       nsvg__parseContent(mark, contentCb, ud);
+                       mark = s;
+                       state = NSVG_XML_TAG;
+               } else if (*s == '>' && state == NSVG_XML_TAG) {
+                       // Start of a content or new tag.
+                       *s++ = '\0';
+                       nsvg__parseElement(mark, startelCb, endelCb, ud);
+                       mark = s;
+                       state = NSVG_XML_CONTENT;
+               } else {
+                       s++;
+               }
+       }
+
+       return 1;
+}
+
+
+/* Simple SVG parser. */
+
+#define NSVG_MAX_ATTR 128
+
+enum NSVGgradientUnits {
+       NSVG_USER_SPACE = 0,
+       NSVG_OBJECT_SPACE = 1
+};
+
+#define NSVG_MAX_DASHES 8
+
+enum NSVGunits {
+       NSVG_UNITS_USER,
+       NSVG_UNITS_PX,
+       NSVG_UNITS_PT,
+       NSVG_UNITS_PC,
+       NSVG_UNITS_MM,
+       NSVG_UNITS_CM,
+       NSVG_UNITS_IN,
+       NSVG_UNITS_PERCENT,
+       NSVG_UNITS_EM,
+       NSVG_UNITS_EX
+};
+
+typedef struct NSVGcoordinate {
+       float value;
+       int units;
+} NSVGcoordinate;
+
+typedef struct NSVGlinearData {
+       NSVGcoordinate x1, y1, x2, y2;
+} NSVGlinearData;
+
+typedef struct NSVGradialData {
+       NSVGcoordinate cx, cy, r, fx, fy;
+} NSVGradialData;
+
+typedef struct NSVGgradientData
+{
+       char id[64];
+       char ref[64];
+  /**
+   * In the original file, using char type (without signed or unsigned) can be interpreted
+   * as 'unsigned char' in some build environments, like ARM architecture.
+   * To prevent the unexpected behavior, we replace 'char type' with 'signed char type' here.
+   */
+    signed char type;
+       union {
+               NSVGlinearData linear;
+               NSVGradialData radial;
+       };
+       char spread;
+       /**
+        * In the original file, using char type (without signed or unsigned) can be interpreted
+        * as 'unsigned char' in some build environments, like ARM architecture.
+        * To prevent the unexpected behavior, we replace 'char units' with 'signed char units' here.
+        */
+    signed char units;
+       float xform[6];
+       int nstops;
+       NSVGgradientStop* stops;
+       struct NSVGgradientData* next;
+} NSVGgradientData;
+
+typedef struct NSVGattrib
+{
+       char id[64];
+       float xform[6];
+       unsigned int fillColor;
+       unsigned int strokeColor;
+       float opacity;
+       float fillOpacity;
+       float strokeOpacity;
+       char fillGradient[64];
+       char strokeGradient[64];
+       float strokeWidth;
+       float strokeDashOffset;
+       float strokeDashArray[NSVG_MAX_DASHES];
+       int strokeDashCount;
+       char strokeLineJoin;
+       char strokeLineCap;
+       float miterLimit;
+       char fillRule;
+       float fontSize;
+       unsigned int stopColor;
+       float stopOpacity;
+       float stopOffset;
+       char hasFill;
+       char hasStroke;
+       char visible;
+} NSVGattrib;
+
+typedef struct NSVGparser
+{
+       NSVGattrib attr[NSVG_MAX_ATTR];
+       int attrHead;
+       float* pts;
+       int npts;
+       int cpts;
+       NSVGpath* plist;
+       NSVGimage* image;
+       NSVGgradientData* gradients;
+       NSVGshape* shapesTail;
+       float viewMinx, viewMiny, viewWidth, viewHeight;
+       int alignX, alignY, alignType;
+       float dpi;
+       char pathFlag;
+       char defsFlag;
+} NSVGparser;
+
+static void nsvg__xformIdentity(float* t)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetTranslation(float* t, float tx, float ty)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = tx; t[5] = ty;
+}
+
+static void nsvg__xformSetScale(float* t, float sx, float sy)
+{
+       t[0] = sx; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = sy;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetSkewX(float* t, float a)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = tanf(a); t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetSkewY(float* t, float a)
+{
+       t[0] = 1.0f; t[1] = tanf(a);
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetRotation(float* t, float a)
+{
+       float cs = cosf(a), sn = sinf(a);
+       t[0] = cs; t[1] = sn;
+       t[2] = -sn; t[3] = cs;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformMultiply(float* t, float* s)
+{
+       float t0 = t[0] * s[0] + t[1] * s[2];
+       float t2 = t[2] * s[0] + t[3] * s[2];
+       float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
+       t[1] = t[0] * s[1] + t[1] * s[3];
+       t[3] = t[2] * s[1] + t[3] * s[3];
+       t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
+       t[0] = t0;
+       t[2] = t2;
+       t[4] = t4;
+}
+
+static void nsvg__xformInverse(float* inv, float* t)
+{
+       double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
+       if (det > -1e-6 && det < 1e-6) {
+               nsvg__xformIdentity(t);
+               return;
+       }
+       invdet = 1.0 / det;
+       inv[0] = (float)(t[3] * invdet);
+       inv[2] = (float)(-t[2] * invdet);
+       inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
+       inv[1] = (float)(-t[1] * invdet);
+       inv[3] = (float)(t[0] * invdet);
+       inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
+}
+
+static void nsvg__xformPremultiply(float* t, float* s)
+{
+       float s2[6];
+       memcpy(s2, s, sizeof(float)*6);
+       nsvg__xformMultiply(s2, t);
+       memcpy(t, s2, sizeof(float)*6);
+}
+
+static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
+{
+       *dx = x*t[0] + y*t[2] + t[4];
+       *dy = x*t[1] + y*t[3] + t[5];
+}
+
+static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
+{
+       *dx = x*t[0] + y*t[2];
+       *dy = x*t[1] + y*t[3];
+}
+
+#define NSVG_EPSILON (1e-12)
+
+static int nsvg__ptInBounds(float* pt, float* bounds)
+{
+       return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
+}
+
+
+static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
+{
+       double it = 1.0-t;
+       return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
+}
+
+static void nsvg__curveBounds(float* bounds, float* curve)
+{
+       int i, j, count;
+       double roots[2], a, b, c, b2ac, t, v;
+       float* v0 = &curve[0];
+       float* v1 = &curve[2];
+       float* v2 = &curve[4];
+       float* v3 = &curve[6];
+
+       // Start the bounding box by end points
+       bounds[0] = nsvg__minf(v0[0], v3[0]);
+       bounds[1] = nsvg__minf(v0[1], v3[1]);
+       bounds[2] = nsvg__maxf(v0[0], v3[0]);
+       bounds[3] = nsvg__maxf(v0[1], v3[1]);
+
+       // Bezier curve fits inside the convex hull of it's control points.
+       // If control points are inside the bounds, we're done.
+       if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
+               return;
+
+       // Add bezier curve inflection points in X and Y.
+       for (i = 0; i < 2; i++) {
+               a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
+               b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
+               c = 3.0 * v1[i] - 3.0 * v0[i];
+               count = 0;
+               if (fabs(a) < NSVG_EPSILON) {
+                       if (fabs(b) > NSVG_EPSILON) {
+                               t = -c / b;
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                       }
+               } else {
+                       b2ac = b*b - 4.0*c*a;
+                       if (b2ac > NSVG_EPSILON) {
+                               t = (-b + sqrt(b2ac)) / (2.0 * a);
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                               t = (-b - sqrt(b2ac)) / (2.0 * a);
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                       }
+               }
+               for (j = 0; j < count; j++) {
+                       v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
+                       bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
+                       bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
+               }
+       }
+}
+
+static NSVGparser* nsvg__createParser()
+{
+       NSVGparser* p;
+       p = (NSVGparser*)malloc(sizeof(NSVGparser));
+       if (p == NULL) goto error;
+       memset(p, 0, sizeof(NSVGparser));
+
+       p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
+       if (p->image == NULL) goto error;
+       memset(p->image, 0, sizeof(NSVGimage));
+
+       // Init style
+       nsvg__xformIdentity(p->attr[0].xform);
+       memset(p->attr[0].id, 0, sizeof p->attr[0].id);
+       p->attr[0].fillColor = NSVG_RGB(0,0,0);
+       p->attr[0].strokeColor = NSVG_RGB(0,0,0);
+       p->attr[0].opacity = 1;
+       p->attr[0].fillOpacity = 1;
+       p->attr[0].strokeOpacity = 1;
+       p->attr[0].stopOpacity = 1;
+       p->attr[0].strokeWidth = 1;
+       p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
+       p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
+       p->attr[0].miterLimit = 4;
+       p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
+       p->attr[0].hasFill = 1;
+       p->attr[0].visible = 1;
+
+       return p;
+
+error:
+       if (p) {
+               if (p->image) free(p->image);
+               free(p);
+       }
+       return NULL;
+}
+
+static void nsvg__deletePaths(NSVGpath* path)
+{
+       while (path) {
+               NSVGpath *next = path->next;
+               if (path->pts != NULL)
+                       free(path->pts);
+               free(path);
+               path = next;
+       }
+}
+
+static void nsvg__deletePaint(NSVGpaint* paint)
+{
+       if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
+               free(paint->gradient);
+}
+
+static void nsvg__deleteGradientData(NSVGgradientData* grad)
+{
+       NSVGgradientData* next;
+       while (grad != NULL) {
+               next = grad->next;
+               free(grad->stops);
+               free(grad);
+               grad = next;
+       }
+}
+
+static void nsvg__deleteParser(NSVGparser* p)
+{
+       if (p != NULL) {
+               nsvg__deletePaths(p->plist);
+               nsvg__deleteGradientData(p->gradients);
+               nsvgDelete(p->image);
+               free(p->pts);
+               free(p);
+       }
+}
+
+static void nsvg__resetPath(NSVGparser* p)
+{
+       p->npts = 0;
+}
+
+static void nsvg__addPoint(NSVGparser* p, float x, float y)
+{
+       if (p->npts+1 > p->cpts) {
+               p->cpts = p->cpts ? p->cpts*2 : 8;
+               p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
+               if (!p->pts) return;
+       }
+       p->pts[p->npts*2+0] = x;
+       p->pts[p->npts*2+1] = y;
+       p->npts++;
+}
+
+static void nsvg__moveTo(NSVGparser* p, float x, float y)
+{
+       if (p->npts > 0) {
+               p->pts[(p->npts-1)*2+0] = x;
+               p->pts[(p->npts-1)*2+1] = y;
+       } else {
+               nsvg__addPoint(p, x, y);
+       }
+}
+
+static void nsvg__lineTo(NSVGparser* p, float x, float y)
+{
+       float px,py, dx,dy;
+       if (p->npts > 0) {
+               px = p->pts[(p->npts-1)*2+0];
+               py = p->pts[(p->npts-1)*2+1];
+               dx = x - px;
+               dy = y - py;
+               nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
+               nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
+               nsvg__addPoint(p, x, y);
+       }
+}
+
+static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
+{
+       nsvg__addPoint(p, cpx1, cpy1);
+       nsvg__addPoint(p, cpx2, cpy2);
+       nsvg__addPoint(p, x, y);
+}
+
+static NSVGattrib* nsvg__getAttr(NSVGparser* p)
+{
+       return &p->attr[p->attrHead];
+}
+
+static void nsvg__pushAttr(NSVGparser* p)
+{
+       if (p->attrHead < NSVG_MAX_ATTR-1) {
+               p->attrHead++;
+               memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
+       }
+}
+
+static void nsvg__popAttr(NSVGparser* p)
+{
+       if (p->attrHead > 0)
+               p->attrHead--;
+}
+
+static float nsvg__actualOrigX(NSVGparser* p)
+{
+       return p->viewMinx;
+}
+
+static float nsvg__actualOrigY(NSVGparser* p)
+{
+       return p->viewMiny;
+}
+
+static float nsvg__actualWidth(NSVGparser* p)
+{
+       return p->viewWidth;
+}
+
+static float nsvg__actualHeight(NSVGparser* p)
+{
+       return p->viewHeight;
+}
+
+static float nsvg__actualLength(NSVGparser* p)
+{
+       float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
+       return sqrtf(w*w + h*h) / sqrtf(2.0f);
+}
+
+static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       switch (c.units) {
+               case NSVG_UNITS_USER:           return c.value;
+               case NSVG_UNITS_PX:                     return c.value;
+               case NSVG_UNITS_PT:                     return c.value / 72.0f * p->dpi;
+               case NSVG_UNITS_PC:                     return c.value / 6.0f * p->dpi;
+               case NSVG_UNITS_MM:                     return c.value / 25.4f * p->dpi;
+               case NSVG_UNITS_CM:                     return c.value / 2.54f * p->dpi;
+               case NSVG_UNITS_IN:                     return c.value * p->dpi;
+               case NSVG_UNITS_EM:                     return c.value * attr->fontSize;
+               case NSVG_UNITS_EX:                     return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
+               case NSVG_UNITS_PERCENT:        return orig + c.value / 100.0f * length;
+               default:                                        return c.value;
+       }
+       return c.value;
+}
+
+static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
+{
+       NSVGgradientData* grad = p->gradients;
+       while (grad) {
+               if (strcmp(grad->id, id) == 0)
+                       return grad;
+               grad = grad->next;
+       }
+       return NULL;
+}
+
+/**
+ * In the original file, using char type (without signed or unsigned) can be interpreted
+ * as 'unsigned char' in some build environments, like ARM architecture.
+ * To prevent the unexpected behavior, we replace 'char paintType' with 'signed char paintType' here.
+ */
+static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, signed char* paintType)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       NSVGgradientData* data = NULL;
+       NSVGgradientData* ref = NULL;
+       NSVGgradientStop* stops = NULL;
+       NSVGgradient* grad;
+       float ox, oy, sw, sh, sl;
+       int nstops = 0;
+
+       data = nsvg__findGradientData(p, id);
+       if (data == NULL) return NULL;
+
+       // TODO: use ref to fill in all unset values too.
+       ref = data;
+       while (ref != NULL) {
+               if (stops == NULL && ref->stops != NULL) {
+                       stops = ref->stops;
+                       nstops = ref->nstops;
+                       break;
+               }
+               ref = nsvg__findGradientData(p, ref->ref);
+       }
+       if (stops == NULL) return NULL;
+
+       grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
+       if (grad == NULL) return NULL;
+
+       // The shape width and height.
+       if (data->units == NSVG_OBJECT_SPACE) {
+               ox = localBounds[0];
+               oy = localBounds[1];
+               sw = localBounds[2] - localBounds[0];
+               sh = localBounds[3] - localBounds[1];
+       } else {
+               ox = nsvg__actualOrigX(p);
+               oy = nsvg__actualOrigY(p);
+               sw = nsvg__actualWidth(p);
+               sh = nsvg__actualHeight(p);
+       }
+       sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
+
+       if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
+               float x1, y1, x2, y2, dx, dy;
+               x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
+               y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
+               x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
+               y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
+               // Calculate transform aligned to the line
+               dx = x2 - x1;
+               dy = y2 - y1;
+               grad->xform[0] = dy; grad->xform[1] = -dx;
+               grad->xform[2] = dx; grad->xform[3] = dy;
+               grad->xform[4] = x1; grad->xform[5] = y1;
+       } else {
+               float cx, cy, fx, fy, r;
+               cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
+               cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
+               fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
+               fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
+               r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
+               // Calculate transform aligned to the circle
+               grad->xform[0] = r; grad->xform[1] = 0;
+               grad->xform[2] = 0; grad->xform[3] = r;
+               grad->xform[4] = cx; grad->xform[5] = cy;
+               grad->fx = fx / r;
+               grad->fy = fy / r;
+       }
+
+       nsvg__xformMultiply(grad->xform, data->xform);
+       nsvg__xformMultiply(grad->xform, attr->xform);
+
+       grad->spread = data->spread;
+       memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
+       grad->nstops = nstops;
+
+       *paintType = data->type;
+
+       return grad;
+}
+
+static float nsvg__getAverageScale(float* t)
+{
+       float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
+       float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
+       return (sx + sy) * 0.5f;
+}
+
+static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
+{
+       NSVGpath* path;
+       float curve[4*2], curveBounds[4];
+       int i, first = 1;
+       for (path = shape->paths; path != NULL; path = path->next) {
+               nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
+               for (i = 0; i < path->npts-1; i += 3) {
+                       nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
+                       nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
+                       nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
+                       nsvg__curveBounds(curveBounds, curve);
+                       if (first) {
+                               bounds[0] = curveBounds[0];
+                               bounds[1] = curveBounds[1];
+                               bounds[2] = curveBounds[2];
+                               bounds[3] = curveBounds[3];
+                               first = 0;
+                       } else {
+                               bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
+                               bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
+                               bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
+                               bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
+                       }
+                       curve[0] = curve[6];
+                       curve[1] = curve[7];
+               }
+       }
+}
+
+static void nsvg__addShape(NSVGparser* p)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       float scale = 1.0f;
+       NSVGshape* shape;
+       NSVGpath* path;
+       int i;
+
+       if (p->plist == NULL)
+               return;
+
+       shape = (NSVGshape*)malloc(sizeof(NSVGshape));
+       if (shape == NULL) goto error;
+       memset(shape, 0, sizeof(NSVGshape));
+
+       memcpy(shape->id, attr->id, sizeof shape->id);
+       scale = nsvg__getAverageScale(attr->xform);
+       shape->strokeWidth = attr->strokeWidth * scale;
+       shape->strokeDashOffset = attr->strokeDashOffset * scale;
+       shape->strokeDashCount = (char)attr->strokeDashCount;
+       for (i = 0; i < attr->strokeDashCount; i++)
+               shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
+       shape->strokeLineJoin = attr->strokeLineJoin;
+       shape->strokeLineCap = attr->strokeLineCap;
+       shape->miterLimit = attr->miterLimit;
+       shape->fillRule = attr->fillRule;
+       shape->opacity = attr->opacity;
+
+       shape->paths = p->plist;
+       p->plist = NULL;
+
+       // Calculate shape bounds
+       shape->bounds[0] = shape->paths->bounds[0];
+       shape->bounds[1] = shape->paths->bounds[1];
+       shape->bounds[2] = shape->paths->bounds[2];
+       shape->bounds[3] = shape->paths->bounds[3];
+       for (path = shape->paths->next; path != NULL; path = path->next) {
+               shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
+               shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
+               shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
+               shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
+       }
+
+       // Set fill
+       if (attr->hasFill == 0) {
+               shape->fill.type = NSVG_PAINT_NONE;
+       } else if (attr->hasFill == 1) {
+               shape->fill.type = NSVG_PAINT_COLOR;
+               shape->fill.color = attr->fillColor;
+               shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
+       } else if (attr->hasFill == 2) {
+               float inv[6], localBounds[4];
+               nsvg__xformInverse(inv, attr->xform);
+               nsvg__getLocalBounds(localBounds, shape, inv);
+               shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);
+               if (shape->fill.gradient == NULL) {
+                       shape->fill.type = NSVG_PAINT_NONE;
+               }
+       }
+
+       // Set stroke
+       if (attr->hasStroke == 0) {
+               shape->stroke.type = NSVG_PAINT_NONE;
+       } else if (attr->hasStroke == 1) {
+               shape->stroke.type = NSVG_PAINT_COLOR;
+               shape->stroke.color = attr->strokeColor;
+               shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
+       } else if (attr->hasStroke == 2) {
+               float inv[6], localBounds[4];
+               nsvg__xformInverse(inv, attr->xform);
+               nsvg__getLocalBounds(localBounds, shape, inv);
+               shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);
+               if (shape->stroke.gradient == NULL)
+                       shape->stroke.type = NSVG_PAINT_NONE;
+       }
+
+       // Set flags
+       shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
+
+       // Add to tail
+       if (p->image->shapes == NULL)
+               p->image->shapes = shape;
+       else
+               p->shapesTail->next = shape;
+       p->shapesTail = shape;
+
+       return;
+
+error:
+       if (shape) free(shape);
+}
+
+static void nsvg__addPath(NSVGparser* p, char closed)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       NSVGpath* path = NULL;
+       float bounds[4];
+       float* curve;
+       int i;
+
+       if (p->npts < 4)
+               return;
+
+       if (closed)
+               nsvg__lineTo(p, p->pts[0], p->pts[1]);
+
+       path = (NSVGpath*)malloc(sizeof(NSVGpath));
+       if (path == NULL) goto error;
+       memset(path, 0, sizeof(NSVGpath));
+
+       path->pts = (float*)malloc(p->npts*2*sizeof(float));
+       if (path->pts == NULL) goto error;
+       path->closed = closed;
+       path->npts = p->npts;
+
+       // Transform path.
+       for (i = 0; i < p->npts; ++i)
+               nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
+
+       // Find bounds
+       for (i = 0; i < path->npts-1; i += 3) {
+               curve = &path->pts[i*2];
+               nsvg__curveBounds(bounds, curve);
+               if (i == 0) {
+                       path->bounds[0] = bounds[0];
+                       path->bounds[1] = bounds[1];
+                       path->bounds[2] = bounds[2];
+                       path->bounds[3] = bounds[3];
+               } else {
+                       path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
+                       path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
+                       path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
+                       path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
+               }
+       }
+
+       path->next = p->plist;
+       p->plist = path;
+
+       return;
+
+error:
+       if (path != NULL) {
+               if (path->pts != NULL) free(path->pts);
+               free(path);
+       }
+}
+
+// We roll our own string to float because the std library one uses locale and messes things up.
+static double nsvg__atof(const char* s)
+{
+       char* cur = (char*)s;
+       char* end = NULL;
+       double res = 0.0, sign = 1.0;
+       long long intPart = 0, fracPart = 0;
+       char hasIntPart = 0, hasFracPart = 0;
+
+       // Parse optional sign
+       if (*cur == '+') {
+               cur++;
+       } else if (*cur == '-') {
+               sign = -1;
+               cur++;
+       }
+
+       // Parse integer part
+       if (nsvg__isdigit(*cur)) {
+               // Parse digit sequence
+               intPart = strtoll(cur, &end, 10);
+               if (cur != end) {
+                       res = (double)intPart;
+                       hasIntPart = 1;
+                       cur = end;
+               }
+       }
+
+       // Parse fractional part.
+       if (*cur == '.') {
+               cur++; // Skip '.'
+               if (nsvg__isdigit(*cur)) {
+                       // Parse digit sequence
+                       fracPart = strtoll(cur, &end, 10);
+                       if (cur != end) {
+                               res += (double)fracPart / pow(10.0, (double)(end - cur));
+                               hasFracPart = 1;
+                               cur = end;
+                       }
+               }
+       }
+
+       // A valid number should have integer or fractional part.
+       if (!hasIntPart && !hasFracPart)
+               return 0.0;
+
+       // Parse optional exponent
+       if (*cur == 'e' || *cur == 'E') {
+               long expPart = 0;
+               cur++; // skip 'E'
+               expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
+               if (cur != end) {
+                       res *= pow(10.0, (double)expPart);
+               }
+       }
+
+       return res * sign;
+}
+
+
+static const char* nsvg__parseNumber(const char* s, char* it, const int size)
+{
+       const int last = size-1;
+       int i = 0;
+
+       // sign
+       if (*s == '-' || *s == '+') {
+               if (i < last) it[i++] = *s;
+               s++;
+       }
+       // integer part
+       while (*s && nsvg__isdigit(*s)) {
+               if (i < last) it[i++] = *s;
+               s++;
+       }
+       if (*s == '.') {
+               // decimal point
+               if (i < last) it[i++] = *s;
+               s++;
+               // fraction part
+               while (*s && nsvg__isdigit(*s)) {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+       }
+       // exponent
+       if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
+               if (i < last) it[i++] = *s;
+               s++;
+               if (*s == '-' || *s == '+') {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+               while (*s && nsvg__isdigit(*s)) {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+       }
+       it[i] = '\0';
+
+       return s;
+}
+
+static const char* nsvg__getNextPathItem(const char* s, char* it)
+{
+       it[0] = '\0';
+       // Skip white spaces and commas
+       while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
+       if (!*s) return s;
+       if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
+               s = nsvg__parseNumber(s, it, 64);
+       } else {
+               // Parse command
+               it[0] = *s++;
+               it[1] = '\0';
+               return s;
+       }
+
+       return s;
+}
+
+static unsigned int nsvg__parseColorHex(const char* str)
+{
+       unsigned int c = 0, r = 0, g = 0, b = 0;
+       int n = 0;
+       str++; // skip #
+       // Calculate number of characters.
+       while(str[n] && !nsvg__isspace(str[n]))
+               n++;
+       if (n == 6) {
+               sscanf(str, "%x", &c);
+       } else if (n == 3) {
+               sscanf(str, "%x", &c);
+               c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8);
+               c |= c<<4;
+       }
+       r = (c >> 16) & 0xff;
+       g = (c >> 8) & 0xff;
+       b = c & 0xff;
+       return NSVG_RGB(r,g,b);
+}
+
+static unsigned int nsvg__parseColorRGB(const char* str)
+{
+       int r = -1, g = -1, b = -1;
+       char s1[33]="", s2[33]="";
+       /**
+        * 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 + 4, "%d%32[%%, \t]%d%32[%%, \t]%d", &r, s1, &g, s2, &b);
+       if (strchr(s1, '%')) {
+               return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100);
+       } else {
+               return NSVG_RGB(r,g,b);
+       }
+}
+
+typedef struct NSVGNamedColor {
+       const char* name;
+       unsigned int color;
+} NSVGNamedColor;
+
+NSVGNamedColor nsvg__colors[] = {
+
+       { "red", NSVG_RGB(255, 0, 0) },
+       { "green", NSVG_RGB( 0, 128, 0) },
+       { "blue", NSVG_RGB( 0, 0, 255) },
+       { "yellow", NSVG_RGB(255, 255, 0) },
+       { "cyan", NSVG_RGB( 0, 255, 255) },
+       { "magenta", NSVG_RGB(255, 0, 255) },
+       { "black", NSVG_RGB( 0, 0, 0) },
+       { "grey", NSVG_RGB(128, 128, 128) },
+       { "gray", NSVG_RGB(128, 128, 128) },
+       { "white", NSVG_RGB(255, 255, 255) },
+
+/**
+ * In the original software, it needs to define "NANOSVG_ALL_COLOR_KEYWORDS" in order to support
+ * the following colors. We have removed this because we want to support all the colors.
+ */
+       { "aliceblue", NSVG_RGB(240, 248, 255) },
+       { "antiquewhite", NSVG_RGB(250, 235, 215) },
+       { "aqua", NSVG_RGB( 0, 255, 255) },
+       { "aquamarine", NSVG_RGB(127, 255, 212) },
+       { "azure", NSVG_RGB(240, 255, 255) },
+       { "beige", NSVG_RGB(245, 245, 220) },
+       { "bisque", NSVG_RGB(255, 228, 196) },
+       { "blanchedalmond", NSVG_RGB(255, 235, 205) },
+       { "blueviolet", NSVG_RGB(138, 43, 226) },
+       { "brown", NSVG_RGB(165, 42, 42) },
+       { "burlywood", NSVG_RGB(222, 184, 135) },
+       { "cadetblue", NSVG_RGB( 95, 158, 160) },
+       { "chartreuse", NSVG_RGB(127, 255, 0) },
+       { "chocolate", NSVG_RGB(210, 105, 30) },
+       { "coral", NSVG_RGB(255, 127, 80) },
+       { "cornflowerblue", NSVG_RGB(100, 149, 237) },
+       { "cornsilk", NSVG_RGB(255, 248, 220) },
+       { "crimson", NSVG_RGB(220, 20, 60) },
+       { "darkblue", NSVG_RGB( 0, 0, 139) },
+       { "darkcyan", NSVG_RGB( 0, 139, 139) },
+       { "darkgoldenrod", NSVG_RGB(184, 134, 11) },
+       { "darkgray", NSVG_RGB(169, 169, 169) },
+       { "darkgreen", NSVG_RGB( 0, 100, 0) },
+       { "darkgrey", NSVG_RGB(169, 169, 169) },
+       { "darkkhaki", NSVG_RGB(189, 183, 107) },
+       { "darkmagenta", NSVG_RGB(139, 0, 139) },
+       { "darkolivegreen", NSVG_RGB( 85, 107, 47) },
+       { "darkorange", NSVG_RGB(255, 140, 0) },
+       { "darkorchid", NSVG_RGB(153, 50, 204) },
+       { "darkred", NSVG_RGB(139, 0, 0) },
+       { "darksalmon", NSVG_RGB(233, 150, 122) },
+       { "darkseagreen", NSVG_RGB(143, 188, 143) },
+       { "darkslateblue", NSVG_RGB( 72, 61, 139) },
+       { "darkslategray", NSVG_RGB( 47, 79, 79) },
+       { "darkslategrey", NSVG_RGB( 47, 79, 79) },
+       { "darkturquoise", NSVG_RGB( 0, 206, 209) },
+       { "darkviolet", NSVG_RGB(148, 0, 211) },
+       { "deeppink", NSVG_RGB(255, 20, 147) },
+       { "deepskyblue", NSVG_RGB( 0, 191, 255) },
+       { "dimgray", NSVG_RGB(105, 105, 105) },
+       { "dimgrey", NSVG_RGB(105, 105, 105) },
+       { "dodgerblue", NSVG_RGB( 30, 144, 255) },
+       { "firebrick", NSVG_RGB(178, 34, 34) },
+       { "floralwhite", NSVG_RGB(255, 250, 240) },
+       { "forestgreen", NSVG_RGB( 34, 139, 34) },
+       { "fuchsia", NSVG_RGB(255, 0, 255) },
+       { "gainsboro", NSVG_RGB(220, 220, 220) },
+       { "ghostwhite", NSVG_RGB(248, 248, 255) },
+       { "gold", NSVG_RGB(255, 215, 0) },
+       { "goldenrod", NSVG_RGB(218, 165, 32) },
+       { "greenyellow", NSVG_RGB(173, 255, 47) },
+       { "honeydew", NSVG_RGB(240, 255, 240) },
+       { "hotpink", NSVG_RGB(255, 105, 180) },
+       { "indianred", NSVG_RGB(205, 92, 92) },
+       { "indigo", NSVG_RGB( 75, 0, 130) },
+       { "ivory", NSVG_RGB(255, 255, 240) },
+       { "khaki", NSVG_RGB(240, 230, 140) },
+       { "lavender", NSVG_RGB(230, 230, 250) },
+       { "lavenderblush", NSVG_RGB(255, 240, 245) },
+       { "lawngreen", NSVG_RGB(124, 252, 0) },
+       { "lemonchiffon", NSVG_RGB(255, 250, 205) },
+       { "lightblue", NSVG_RGB(173, 216, 230) },
+       { "lightcoral", NSVG_RGB(240, 128, 128) },
+       { "lightcyan", NSVG_RGB(224, 255, 255) },
+       { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
+       { "lightgray", NSVG_RGB(211, 211, 211) },
+       { "lightgreen", NSVG_RGB(144, 238, 144) },
+       { "lightgrey", NSVG_RGB(211, 211, 211) },
+       { "lightpink", NSVG_RGB(255, 182, 193) },
+       { "lightsalmon", NSVG_RGB(255, 160, 122) },
+       { "lightseagreen", NSVG_RGB( 32, 178, 170) },
+       { "lightskyblue", NSVG_RGB(135, 206, 250) },
+       { "lightslategray", NSVG_RGB(119, 136, 153) },
+       { "lightslategrey", NSVG_RGB(119, 136, 153) },
+       { "lightsteelblue", NSVG_RGB(176, 196, 222) },
+       { "lightyellow", NSVG_RGB(255, 255, 224) },
+       { "lime", NSVG_RGB( 0, 255, 0) },
+       { "limegreen", NSVG_RGB( 50, 205, 50) },
+       { "linen", NSVG_RGB(250, 240, 230) },
+       { "maroon", NSVG_RGB(128, 0, 0) },
+       { "mediumaquamarine", NSVG_RGB(102, 205, 170) },
+       { "mediumblue", NSVG_RGB( 0, 0, 205) },
+       { "mediumorchid", NSVG_RGB(186, 85, 211) },
+       { "mediumpurple", NSVG_RGB(147, 112, 219) },
+       { "mediumseagreen", NSVG_RGB( 60, 179, 113) },
+       { "mediumslateblue", NSVG_RGB(123, 104, 238) },
+       { "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
+       { "mediumturquoise", NSVG_RGB( 72, 209, 204) },
+       { "mediumvioletred", NSVG_RGB(199, 21, 133) },
+       { "midnightblue", NSVG_RGB( 25, 25, 112) },
+       { "mintcream", NSVG_RGB(245, 255, 250) },
+       { "mistyrose", NSVG_RGB(255, 228, 225) },
+       { "moccasin", NSVG_RGB(255, 228, 181) },
+       { "navajowhite", NSVG_RGB(255, 222, 173) },
+       { "navy", NSVG_RGB( 0, 0, 128) },
+       { "oldlace", NSVG_RGB(253, 245, 230) },
+       { "olive", NSVG_RGB(128, 128, 0) },
+       { "olivedrab", NSVG_RGB(107, 142, 35) },
+       { "orange", NSVG_RGB(255, 165, 0) },
+       { "orangered", NSVG_RGB(255, 69, 0) },
+       { "orchid", NSVG_RGB(218, 112, 214) },
+       { "palegoldenrod", NSVG_RGB(238, 232, 170) },
+       { "palegreen", NSVG_RGB(152, 251, 152) },
+       { "paleturquoise", NSVG_RGB(175, 238, 238) },
+       { "palevioletred", NSVG_RGB(219, 112, 147) },
+       { "papayawhip", NSVG_RGB(255, 239, 213) },
+       { "peachpuff", NSVG_RGB(255, 218, 185) },
+       { "peru", NSVG_RGB(205, 133, 63) },
+       { "pink", NSVG_RGB(255, 192, 203) },
+       { "plum", NSVG_RGB(221, 160, 221) },
+       { "powderblue", NSVG_RGB(176, 224, 230) },
+       { "purple", NSVG_RGB(128, 0, 128) },
+       { "rosybrown", NSVG_RGB(188, 143, 143) },
+       { "royalblue", NSVG_RGB( 65, 105, 225) },
+       { "saddlebrown", NSVG_RGB(139, 69, 19) },
+       { "salmon", NSVG_RGB(250, 128, 114) },
+       { "sandybrown", NSVG_RGB(244, 164, 96) },
+       { "seagreen", NSVG_RGB( 46, 139, 87) },
+       { "seashell", NSVG_RGB(255, 245, 238) },
+       { "sienna", NSVG_RGB(160, 82, 45) },
+       { "silver", NSVG_RGB(192, 192, 192) },
+       { "skyblue", NSVG_RGB(135, 206, 235) },
+       { "slateblue", NSVG_RGB(106, 90, 205) },
+       { "slategray", NSVG_RGB(112, 128, 144) },
+       { "slategrey", NSVG_RGB(112, 128, 144) },
+       { "snow", NSVG_RGB(255, 250, 250) },
+       { "springgreen", NSVG_RGB( 0, 255, 127) },
+       { "steelblue", NSVG_RGB( 70, 130, 180) },
+       { "tan", NSVG_RGB(210, 180, 140) },
+       { "teal", NSVG_RGB( 0, 128, 128) },
+       { "thistle", NSVG_RGB(216, 191, 216) },
+       { "tomato", NSVG_RGB(255, 99, 71) },
+       { "turquoise", NSVG_RGB( 64, 224, 208) },
+       { "violet", NSVG_RGB(238, 130, 238) },
+       { "wheat", NSVG_RGB(245, 222, 179) },
+       { "whitesmoke", NSVG_RGB(245, 245, 245) },
+       { "yellowgreen", NSVG_RGB(154, 205, 50) },
+};
+
+static unsigned int nsvg__parseColorName(const char* str)
+{
+       int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
+
+       for (i = 0; i < ncolors; i++) {
+               if (strcmp(nsvg__colors[i].name, str) == 0) {
+                       return nsvg__colors[i].color;
+               }
+       }
+
+       return NSVG_RGB(128, 128, 128);
+}
+
+static unsigned int nsvg__parseColor(const char* str)
+{
+       size_t len = 0;
+       while(*str == ' ') ++str;
+       len = strlen(str);
+       if (len >= 1 && *str == '#')
+               return nsvg__parseColorHex(str);
+       else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
+               return nsvg__parseColorRGB(str);
+       return nsvg__parseColorName(str);
+}
+
+static float nsvg__parseOpacity(const char* str)
+{
+       float val = nsvg__atof(str);
+       if (val < 0.0f) val = 0.0f;
+       if (val > 1.0f) val = 1.0f;
+       return val;
+}
+
+static float nsvg__parseMiterLimit(const char* str)
+{
+       float val = nsvg__atof(str);
+       if (val < 0.0f) val = 0.0f;
+       return val;
+}
+
+static int nsvg__parseUnits(const char* units)
+{
+       if (units[0] == 'p' && units[1] == 'x')
+               return NSVG_UNITS_PX;
+       else if (units[0] == 'p' && units[1] == 't')
+               return NSVG_UNITS_PT;
+       else if (units[0] == 'p' && units[1] == 'c')
+               return NSVG_UNITS_PC;
+       else if (units[0] == 'm' && units[1] == 'm')
+               return NSVG_UNITS_MM;
+       else if (units[0] == 'c' && units[1] == 'm')
+               return NSVG_UNITS_CM;
+       else if (units[0] == 'i' && units[1] == 'n')
+               return NSVG_UNITS_IN;
+       else if (units[0] == '%')
+               return NSVG_UNITS_PERCENT;
+       else if (units[0] == 'e' && units[1] == 'm')
+               return NSVG_UNITS_EM;
+       else if (units[0] == 'e' && units[1] == 'x')
+               return NSVG_UNITS_EX;
+       return NSVG_UNITS_USER;
+}
+
+static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
+{
+       NSVGcoordinate coord = {0, NSVG_UNITS_USER};
+       char buf[64];
+       coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
+       coord.value = nsvg__atof(buf);
+       return coord;
+}
+
+static NSVGcoordinate nsvg__coord(float v, int units)
+{
+       NSVGcoordinate coord = {v, units};
+       return coord;
+}
+
+static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
+{
+       NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
+       return nsvg__convertToPixels(p, coord, orig, length);
+}
+
+static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
+{
+       const char* end;
+       const char* ptr;
+       char it[64];
+
+       *na = 0;
+       ptr = str;
+       while (*ptr && *ptr != '(') ++ptr;
+       if (*ptr == 0)
+               return 1;
+       end = ptr;
+       while (*end && *end != ')') ++end;
+       if (*end == 0)
+               return 1;
+
+       while (ptr < end) {
+               if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
+                       if (*na >= maxNa) return 0;
+                       ptr = nsvg__parseNumber(ptr, it, 64);
+                       args[(*na)++] = (float)nsvg__atof(it);
+               } else {
+                       ++ptr;
+               }
+       }
+       return (int)(end - str);
+}
+
+
+static int nsvg__parseMatrix(float* xform, const char* str)
+{
+       float t[6];
+       int na = 0;
+       int len = nsvg__parseTransformArgs(str, t, 6, &na);
+       if (na != 6) return len;
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseTranslate(float* xform, const char* str)
+{
+       float args[2];
+       float t[6];
+       int na = 0;
+       int len = nsvg__parseTransformArgs(str, args, 2, &na);
+       if (na == 1) args[1] = 0.0;
+
+       nsvg__xformSetTranslation(t, args[0], args[1]);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseScale(float* xform, const char* str)
+{
+       float args[2];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 2, &na);
+       if (na == 1) args[1] = args[0];
+       nsvg__xformSetScale(t, args[0], args[1]);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseSkewX(float* xform, const char* str)
+{
+       float args[1];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 1, &na);
+       nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseSkewY(float* xform, const char* str)
+{
+       float args[1];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 1, &na);
+       nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseRotate(float* xform, const char* str)
+{
+       float args[3];
+       int na = 0;
+       float m[6];
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 3, &na);
+       if (na == 1)
+               args[1] = args[2] = 0.0f;
+       nsvg__xformIdentity(m);
+
+       if (na > 1) {
+               nsvg__xformSetTranslation(t, -args[1], -args[2]);
+               nsvg__xformMultiply(m, t);
+       }
+
+       nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
+       nsvg__xformMultiply(m, t);
+
+       if (na > 1) {
+               nsvg__xformSetTranslation(t, args[1], args[2]);
+               nsvg__xformMultiply(m, t);
+       }
+
+       memcpy(xform, m, sizeof(float)*6);
+
+       return len;
+}
+
+static void nsvg__parseTransform(float* xform, const char* str)
+{
+       float t[6];
+       nsvg__xformIdentity(xform);
+       while (*str)
+       {
+               if (strncmp(str, "matrix", 6) == 0)
+                       str += nsvg__parseMatrix(t, str);
+               else if (strncmp(str, "translate", 9) == 0)
+                       str += nsvg__parseTranslate(t, str);
+               else if (strncmp(str, "scale", 5) == 0)
+                       str += nsvg__parseScale(t, str);
+               else if (strncmp(str, "rotate", 6) == 0)
+                       str += nsvg__parseRotate(t, str);
+               else if (strncmp(str, "skewX", 5) == 0)
+                       str += nsvg__parseSkewX(t, str);
+               else if (strncmp(str, "skewY", 5) == 0)
+                       str += nsvg__parseSkewY(t, str);
+               else{
+                       ++str;
+                       continue;
+               }
+
+               nsvg__xformPremultiply(xform, t);
+       }
+}
+
+static void nsvg__parseUrl(char* id, const char* str)
+{
+       int i = 0;
+       str += 4; // "url(";
+       if (*str == '#')
+               str++;
+       while (i < 63 && *str != ')') {
+               id[i] = *str++;
+               i++;
+       }
+       id[i] = '\0';
+}
+
+static char nsvg__parseLineCap(const char* str)
+{
+       if (strcmp(str, "butt") == 0)
+               return NSVG_CAP_BUTT;
+       else if (strcmp(str, "round") == 0)
+               return NSVG_CAP_ROUND;
+       else if (strcmp(str, "square") == 0)
+               return NSVG_CAP_SQUARE;
+       // TODO: handle inherit.
+       return NSVG_CAP_BUTT;
+}
+
+static char nsvg__parseLineJoin(const char* str)
+{
+       if (strcmp(str, "miter") == 0)
+               return NSVG_JOIN_MITER;
+       else if (strcmp(str, "round") == 0)
+               return NSVG_JOIN_ROUND;
+       else if (strcmp(str, "bevel") == 0)
+               return NSVG_JOIN_BEVEL;
+       // TODO: handle inherit.
+       return NSVG_JOIN_MITER;
+}
+
+static char nsvg__parseFillRule(const char* str)
+{
+       if (strcmp(str, "nonzero") == 0)
+               return NSVG_FILLRULE_NONZERO;
+       else if (strcmp(str, "evenodd") == 0)
+               return NSVG_FILLRULE_EVENODD;
+       // TODO: handle inherit.
+       return NSVG_FILLRULE_NONZERO;
+}
+
+static const char* nsvg__getNextDashItem(const char* s, char* it)
+{
+       int n = 0;
+       it[0] = '\0';
+       // Skip white spaces and commas
+       while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
+       // Advance until whitespace, comma or end.
+       while (*s && (!nsvg__isspace(*s) && *s != ',')) {
+               if (n < 63)
+                       it[n++] = *s;
+               s++;
+       }
+       it[n++] = '\0';
+       return s;
+}
+
+static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
+{
+       char item[64];
+       int count = 0, i;
+       float sum = 0.0f;
+
+       // Handle "none"
+       if (str[0] == 'n')
+               return 0;
+
+       // Parse dashes
+       while (*str) {
+               str = nsvg__getNextDashItem(str, item);
+               if (!*item) break;
+               if (count < NSVG_MAX_DASHES)
+                       strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
+       }
+
+       for (i = 0; i < count; i++)
+               sum += strokeDashArray[i];
+       if (sum <= 1e-6f)
+               count = 0;
+
+       return count;
+}
+
+static void nsvg__parseStyle(NSVGparser* p, const char* str);
+
+static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
+{
+       float xform[6];
+       NSVGattrib* attr = nsvg__getAttr(p);
+       if (!attr) return 0;
+
+       if (strcmp(name, "style") == 0) {
+               nsvg__parseStyle(p, value);
+       } else if (strcmp(name, "display") == 0) {
+               if (strcmp(value, "none") == 0)
+                       attr->visible = 0;
+               // Don't reset ->visible on display:inline, one display:none hides the whole subtree
+
+       } else if (strcmp(name, "fill") == 0) {
+               if (strcmp(value, "none") == 0) {
+                       attr->hasFill = 0;
+               } else if (strncmp(value, "url(", 4) == 0) {
+                       attr->hasFill = 2;
+                       nsvg__parseUrl(attr->fillGradient, value);
+               } else {
+                       attr->hasFill = 1;
+                       attr->fillColor = nsvg__parseColor(value);
+               }
+       } else if (strcmp(name, "opacity") == 0) {
+               attr->opacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "fill-opacity") == 0) {
+               attr->fillOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "stroke") == 0) {
+               if (strcmp(value, "none") == 0) {
+                       attr->hasStroke = 0;
+               } else if (strncmp(value, "url(", 4) == 0) {
+                       attr->hasStroke = 2;
+                       nsvg__parseUrl(attr->strokeGradient, value);
+               } else {
+                       attr->hasStroke = 1;
+                       attr->strokeColor = nsvg__parseColor(value);
+               }
+       } else if (strcmp(name, "stroke-width") == 0) {
+               attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
+       } else if (strcmp(name, "stroke-dasharray") == 0) {
+               attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
+       } else if (strcmp(name, "stroke-dashoffset") == 0) {
+               attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
+       } else if (strcmp(name, "stroke-opacity") == 0) {
+               attr->strokeOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "stroke-linecap") == 0) {
+               attr->strokeLineCap = nsvg__parseLineCap(value);
+       } else if (strcmp(name, "stroke-linejoin") == 0) {
+               attr->strokeLineJoin = nsvg__parseLineJoin(value);
+       } else if (strcmp(name, "stroke-miterlimit") == 0) {
+               attr->miterLimit = nsvg__parseMiterLimit(value);
+       } else if (strcmp(name, "fill-rule") == 0) {
+               attr->fillRule = nsvg__parseFillRule(value);
+       } else if (strcmp(name, "font-size") == 0) {
+               attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
+       } else if (strcmp(name, "transform") == 0) {
+               nsvg__parseTransform(xform, value);
+               nsvg__xformPremultiply(attr->xform, xform);
+       } else if (strcmp(name, "stop-color") == 0) {
+               attr->stopColor = nsvg__parseColor(value);
+       } else if (strcmp(name, "stop-opacity") == 0) {
+               attr->stopOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "offset") == 0) {
+               attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
+       } else if (strcmp(name, "id") == 0) {
+               strncpy(attr->id, value, 63);
+               attr->id[63] = '\0';
+       } else {
+               return 0;
+       }
+       return 1;
+}
+
+static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
+{
+       const char* str;
+       const char* val;
+       char name[512];
+       char value[512];
+       int n;
+
+       str = start;
+       while (str < end && *str != ':') ++str;
+
+       val = str;
+
+       // Right Trim
+       while (str > start &&  (*str == ':' || nsvg__isspace(*str))) --str;
+       ++str;
+
+       n = (int)(str - start);
+       if (n > 511) n = 511;
+       if (n) memcpy(name, start, n);
+       name[n] = 0;
+
+       while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
+
+       n = (int)(end - val);
+       if (n > 511) n = 511;
+       if (n) memcpy(value, val, n);
+       value[n] = 0;
+
+       return nsvg__parseAttr(p, name, value);
+}
+
+static void nsvg__parseStyle(NSVGparser* p, const char* str)
+{
+       const char* start;
+       const char* end;
+
+       while (*str) {
+               // Left Trim
+               while(*str && nsvg__isspace(*str)) ++str;
+               start = str;
+               while(*str && *str != ';') ++str;
+               end = str;
+
+               // Right Trim
+               while (end > start &&  (*end == ';' || nsvg__isspace(*end))) --end;
+               ++end;
+
+               nsvg__parseNameValue(p, start, end);
+               if (*str) ++str;
+       }
+}
+
+static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
+{
+       int i;
+       for (i = 0; attr[i]; i += 2)
+       {
+               if (strcmp(attr[i], "style") == 0)
+                       nsvg__parseStyle(p, attr[i + 1]);
+               else
+                       nsvg__parseAttr(p, attr[i], attr[i + 1]);
+       }
+}
+
+static int nsvg__getArgsPerElement(char cmd)
+{
+       switch (cmd) {
+               case 'v':
+               case 'V':
+               case 'h':
+               case 'H':
+                       return 1;
+               case 'm':
+               case 'M':
+               case 'l':
+               case 'L':
+               case 't':
+               case 'T':
+                       return 2;
+               case 'q':
+               case 'Q':
+               case 's':
+               case 'S':
+                       return 4;
+               case 'c':
+               case 'C':
+                       return 6;
+               case 'a':
+               case 'A':
+                       return 7;
+       }
+       return 0;
+}
+
+static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
+{
+       if (rel) {
+               *cpx += args[0];
+               *cpy += args[1];
+       } else {
+               *cpx = args[0];
+               *cpy = args[1];
+       }
+       nsvg__moveTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
+{
+       if (rel) {
+               *cpx += args[0];
+               *cpy += args[1];
+       } else {
+               *cpx = args[0];
+               *cpy = args[1];
+       }
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
+{
+       if (rel)
+               *cpx += args[0];
+       else
+               *cpx = args[0];
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
+{
+       if (rel)
+               *cpy += args[0];
+       else
+               *cpy = args[0];
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                float* cpx2, float* cpy2, float* args, int rel)
+{
+       float x2, y2, cx1, cy1, cx2, cy2;
+
+       if (rel) {
+               cx1 = *cpx + args[0];
+               cy1 = *cpy + args[1];
+               cx2 = *cpx + args[2];
+               cy2 = *cpy + args[3];
+               x2 = *cpx + args[4];
+               y2 = *cpy + args[5];
+       } else {
+               cx1 = args[0];
+               cy1 = args[1];
+               cx2 = args[2];
+               cy2 = args[3];
+               x2 = args[4];
+               y2 = args[5];
+       }
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx2;
+       *cpy2 = cy2;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                         float* cpx2, float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               cx2 = *cpx + args[0];
+               cy2 = *cpy + args[1];
+               x2 = *cpx + args[2];
+               y2 = *cpy + args[3];
+       } else {
+               cx2 = args[0];
+               cy2 = args[1];
+               x2 = args[2];
+               y2 = args[3];
+       }
+
+       cx1 = 2*x1 - *cpx2;
+       cy1 = 2*y1 - *cpy2;
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx2;
+       *cpy2 = cy2;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
+                                                               float* cpx2, float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx, cy;
+       float cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               cx = *cpx + args[0];
+               cy = *cpy + args[1];
+               x2 = *cpx + args[2];
+               y2 = *cpy + args[3];
+       } else {
+               cx = args[0];
+               cy = args[1];
+               x2 = args[2];
+               y2 = args[3];
+       }
+
+       // Convert to cubic bezier
+       cx1 = x1 + 2.0f/3.0f*(cx - x1);
+       cy1 = y1 + 2.0f/3.0f*(cy - y1);
+       cx2 = x2 + 2.0f/3.0f*(cx - x2);
+       cy2 = y2 + 2.0f/3.0f*(cy - y2);
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx;
+       *cpy2 = cy;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                        float* cpx2, float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx, cy;
+       float cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               x2 = *cpx + args[0];
+               y2 = *cpy + args[1];
+       } else {
+               x2 = args[0];
+               y2 = args[1];
+       }
+
+       cx = 2*x1 - *cpx2;
+       cy = 2*y1 - *cpy2;
+
+       // Convert to cubix bezier
+       cx1 = x1 + 2.0f/3.0f*(cx - x1);
+       cy1 = y1 + 2.0f/3.0f*(cy - y1);
+       cx2 = x2 + 2.0f/3.0f*(cx - x2);
+       cy2 = y2 + 2.0f/3.0f*(cy - y2);
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx;
+       *cpy2 = cy;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static float nsvg__sqr(float x) { return x*x; }
+static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
+
+static float nsvg__vecrat(float ux, float uy, float vx, float vy)
+{
+       return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
+}
+
+static float nsvg__vecang(float ux, float uy, float vx, float vy)
+{
+       float r = nsvg__vecrat(ux,uy, vx,vy);
+       if (r < -1.0f) r = -1.0f;
+       if (r > 1.0f) r = 1.0f;
+       return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
+}
+
+static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
+{
+       // Ported from canvg (https://code.google.com/p/canvg/)
+       float rx, ry, rotx;
+       float x1, y1, x2, y2, cx, cy, dx, dy, d;
+       float x1p, y1p, cxp, cyp, s, sa, sb;
+       float ux, uy, vx, vy, a1, da;
+       float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
+       float sinrx, cosrx;
+       int fa, fs;
+       int i, ndivs;
+       float hda, kappa;
+
+       rx = fabsf(args[0]);                            // y radius
+       ry = fabsf(args[1]);                            // x radius
+       rotx = args[2] / 180.0f * NSVG_PI;              // x rotation angle
+       fa = fabsf(args[3]) > 1e-6 ? 1 : 0;     // Large arc
+       fs = fabsf(args[4]) > 1e-6 ? 1 : 0;     // Sweep direction
+       x1 = *cpx;                                                      // start point
+       y1 = *cpy;
+       if (rel) {                                                      // end point
+               x2 = *cpx + args[5];
+               y2 = *cpy + args[6];
+       } else {
+               x2 = args[5];
+               y2 = args[6];
+       }
+
+       dx = x1 - x2;
+       dy = y1 - y2;
+       d = sqrtf(dx*dx + dy*dy);
+       if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
+               // The arc degenerates to a line
+               nsvg__lineTo(p, x2, y2);
+               *cpx = x2;
+               *cpy = y2;
+               return;
+       }
+
+       sinrx = sinf(rotx);
+       cosrx = cosf(rotx);
+
+       // Convert to center point parameterization.
+       // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+       // 1) Compute x1', y1'
+       x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
+       y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
+       d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
+       if (d > 1) {
+               d = sqrtf(d);
+               rx *= d;
+               ry *= d;
+       }
+       // 2) Compute cx', cy'
+       s = 0.0f;
+       sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
+       sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
+       if (sa < 0.0f) sa = 0.0f;
+       if (sb > 0.0f)
+               s = sqrtf(sa / sb);
+       if (fa == fs)
+               s = -s;
+       cxp = s * rx * y1p / ry;
+       cyp = s * -ry * x1p / rx;
+
+       // 3) Compute cx,cy from cx',cy'
+       cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
+       cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
+
+       // 4) Calculate theta1, and delta theta.
+       ux = (x1p - cxp) / rx;
+       uy = (y1p - cyp) / ry;
+       vx = (-x1p - cxp) / rx;
+       vy = (-y1p - cyp) / ry;
+       a1 = nsvg__vecang(1.0f,0.0f, ux,uy);    // Initial angle
+       da = nsvg__vecang(ux,uy, vx,vy);                // Delta angle
+
+//     if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
+//     if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
+
+       if (fs == 0 && da > 0)
+               da -= 2 * NSVG_PI;
+       else if (fs == 1 && da < 0)
+               da += 2 * NSVG_PI;
+
+       // Approximate the arc using cubic spline segments.
+       t[0] = cosrx; t[1] = sinrx;
+       t[2] = -sinrx; t[3] = cosrx;
+       t[4] = cx; t[5] = cy;
+
+       // Split arc into max 90 degree segments.
+       // The loop assumes an iteration per end point (including start and end), this +1.
+       ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
+       hda = (da / (float)ndivs) / 2.0f;
+       kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
+       if (da < 0.0f)
+               kappa = -kappa;
+
+       for (i = 0; i <= ndivs; i++) {
+               a = a1 + da * ((float)i/(float)ndivs);
+               dx = cosf(a);
+               dy = sinf(a);
+               nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
+               nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
+               if (i > 0)
+                       nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
+               px = x;
+               py = y;
+               ptanx = tanx;
+               ptany = tany;
+       }
+
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__parsePath(NSVGparser* p, const char** attr)
+{
+       const char* s = NULL;
+       char cmd = '\0';
+       float args[10];
+       int nargs;
+       int rargs = 0;
+       float cpx, cpy, cpx2, cpy2;
+       const char* tmp[4];
+       char closedFlag;
+       int i;
+       char item[64];
+
+       for (i = 0; attr[i]; i += 2) {
+               if (strcmp(attr[i], "d") == 0) {
+                       s = attr[i + 1];
+               } else {
+                       tmp[0] = attr[i];
+                       tmp[1] = attr[i + 1];
+                       tmp[2] = 0;
+                       tmp[3] = 0;
+                       nsvg__parseAttribs(p, tmp);
+               }
+       }
+
+       if (s) {
+               nsvg__resetPath(p);
+               cpx = 0; cpy = 0;
+               cpx2 = 0; cpy2 = 0;
+               closedFlag = 0;
+               nargs = 0;
+
+               while (*s) {
+                       s = nsvg__getNextPathItem(s, item);
+                       if (!*item) break;
+                       if (nsvg__isnum(item[0])) {
+                               if (nargs < 10)
+                                       args[nargs++] = (float)nsvg__atof(item);
+                               if (nargs >= rargs) {
+                                       switch (cmd) {
+                                               case 'm':
+                                               case 'M':
+                                                       nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
+                                                       // Moveto can be followed by multiple coordinate pairs,
+                                                       // which should be treated as linetos.
+                                                       cmd = (cmd == 'm') ? 'l' : 'L';
+                                                       rargs = nsvg__getArgsPerElement(cmd);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'l':
+                                               case 'L':
+                                                       nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'H':
+                                               case 'h':
+                                                       nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'V':
+                                               case 'v':
+                                                       nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'C':
+                                               case 'c':
+                                                       nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
+                                                       break;
+                                               case 'S':
+                                               case 's':
+                                                       nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
+                                                       break;
+                                               case 'Q':
+                                               case 'q':
+                                                       nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
+                                                       break;
+                                               case 'T':
+                                               case 't':
+                                                       nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
+                                                       break;
+                                               case 'A':
+                                               case 'a':
+                                                       nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               default:
+                                                       if (nargs >= 2) {
+                                                               cpx = args[nargs-2];
+                                                               cpy = args[nargs-1];
+                                                               cpx2 = cpx; cpy2 = cpy;
+                                                       }
+                                                       break;
+                                       }
+                                       nargs = 0;
+                               }
+                       } else {
+                               cmd = item[0];
+                               rargs = nsvg__getArgsPerElement(cmd);
+                               if (cmd == 'M' || cmd == 'm') {
+                                       // Commit path.
+                                       if (p->npts > 0)
+                                               nsvg__addPath(p, closedFlag);
+                                       // Start new subpath.
+                                       nsvg__resetPath(p);
+                                       closedFlag = 0;
+                                       nargs = 0;
+                               } else if (cmd == 'Z' || cmd == 'z') {
+                                       closedFlag = 1;
+                                       // Commit path.
+                                       if (p->npts > 0) {
+                                               // Move current point to first point
+                                               cpx = p->pts[0];
+                                               cpy = p->pts[1];
+                                               cpx2 = cpx; cpy2 = cpy;
+                                               nsvg__addPath(p, closedFlag);
+                                       }
+                                       // Start new subpath.
+                                       nsvg__resetPath(p);
+                                       nsvg__moveTo(p, cpx, cpy);
+                                       closedFlag = 0;
+                                       nargs = 0;
+                               }
+                       }
+               }
+               // Commit path.
+               if (p->npts)
+                       nsvg__addPath(p, closedFlag);
+       }
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parseRect(NSVGparser* p, const char** attr)
+{
+       float x = 0.0f;
+       float y = 0.0f;
+       float w = 0.0f;
+       float h = 0.0f;
+       float rx = -1.0f; // marks not set
+       float ry = -1.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
+                       if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
+               }
+       }
+
+       if (rx < 0.0f && ry > 0.0f) rx = ry;
+       if (ry < 0.0f && rx > 0.0f) ry = rx;
+       if (rx < 0.0f) rx = 0.0f;
+       if (ry < 0.0f) ry = 0.0f;
+       if (rx > w/2.0f) rx = w/2.0f;
+       if (ry > h/2.0f) ry = h/2.0f;
+
+       if (w != 0.0f && h != 0.0f) {
+               nsvg__resetPath(p);
+
+               if (rx < 0.00001f || ry < 0.0001f) {
+                       nsvg__moveTo(p, x, y);
+                       nsvg__lineTo(p, x+w, y);
+                       nsvg__lineTo(p, x+w, y+h);
+                       nsvg__lineTo(p, x, y+h);
+               } else {
+                       // Rounded rectangle
+                       nsvg__moveTo(p, x+rx, y);
+                       nsvg__lineTo(p, x+w-rx, y);
+                       nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
+                       nsvg__lineTo(p, x+w, y+h-ry);
+                       nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
+                       nsvg__lineTo(p, x+rx, y+h);
+                       nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
+                       nsvg__lineTo(p, x, y+ry);
+                       nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
+               }
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseCircle(NSVGparser* p, const char** attr)
+{
+       float cx = 0.0f;
+       float cy = 0.0f;
+       float r = 0.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
+               }
+       }
+
+       if (r > 0.0f) {
+               nsvg__resetPath(p);
+
+               nsvg__moveTo(p, cx+r, cy);
+               nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
+               nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
+               nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
+               nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
+{
+       float cx = 0.0f;
+       float cy = 0.0f;
+       float rx = 0.0f;
+       float ry = 0.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
+                       if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
+               }
+       }
+
+       if (rx > 0.0f && ry > 0.0f) {
+
+               nsvg__resetPath(p);
+
+               nsvg__moveTo(p, cx+rx, cy);
+               nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
+               nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
+               nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
+               nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseLine(NSVGparser* p, const char** attr)
+{
+       float x1 = 0.0;
+       float y1 = 0.0;
+       float x2 = 0.0;
+       float y2 = 0.0;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
+               }
+       }
+
+       nsvg__resetPath(p);
+
+       nsvg__moveTo(p, x1, y1);
+       nsvg__lineTo(p, x2, y2);
+
+       nsvg__addPath(p, 0);
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
+{
+       int i;
+       const char* s;
+       float args[2];
+       int nargs, npts = 0;
+       char item[64];
+
+       nsvg__resetPath(p);
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "points") == 0) {
+                               s = attr[i + 1];
+                               nargs = 0;
+                               while (*s) {
+                                       s = nsvg__getNextPathItem(s, item);
+                                       args[nargs++] = (float)nsvg__atof(item);
+                                       if (nargs >= 2) {
+                                               if (npts == 0)
+                                                       nsvg__moveTo(p, args[0], args[1]);
+                                               else
+                                                       nsvg__lineTo(p, args[0], args[1]);
+                                               nargs = 0;
+                                               npts++;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       nsvg__addPath(p, (char)closeFlag);
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parseSVG(NSVGparser* p, const char** attr)
+{
+       int i;
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "width") == 0) {
+                               p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
+                       } else if (strcmp(attr[i], "height") == 0) {
+                               p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
+                       } else if (strcmp(attr[i], "viewBox") == 0) {
+                               const char *s = attr[i + 1];
+                               char buf[64];
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewMinx = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewMiny = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewWidth = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewHeight = nsvg__atof(buf);
+                       } else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
+                               if (strstr(attr[i + 1], "none") != 0) {
+                                       // No uniform scaling
+                                       p->alignType = NSVG_ALIGN_NONE;
+                               } else {
+                                       // Parse X align
+                                       if (strstr(attr[i + 1], "xMin") != 0)
+                                               p->alignX = NSVG_ALIGN_MIN;
+                                       else if (strstr(attr[i + 1], "xMid") != 0)
+                                               p->alignX = NSVG_ALIGN_MID;
+                                       else if (strstr(attr[i + 1], "xMax") != 0)
+                                               p->alignX = NSVG_ALIGN_MAX;
+                                       // Parse X align
+                                       if (strstr(attr[i + 1], "yMin") != 0)
+                                               p->alignY = NSVG_ALIGN_MIN;
+                                       else if (strstr(attr[i + 1], "yMid") != 0)
+                                               p->alignY = NSVG_ALIGN_MID;
+                                       else if (strstr(attr[i + 1], "yMax") != 0)
+                                               p->alignY = NSVG_ALIGN_MAX;
+                                       // Parse meet/slice
+                                       p->alignType = NSVG_ALIGN_MEET;
+                                       if (strstr(attr[i + 1], "slice") != 0)
+                                               p->alignType = NSVG_ALIGN_SLICE;
+                               }
+                       }
+               }
+       }
+}
+
+static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
+{
+       int i;
+       NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
+       if (grad == NULL) return;
+       memset(grad, 0, sizeof(NSVGgradientData));
+       grad->units = NSVG_OBJECT_SPACE;
+       grad->type = type;
+       if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
+               grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+               grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+               grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
+               grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+       } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
+               grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+               grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+               grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+       }
+
+       nsvg__xformIdentity(grad->xform);
+
+       for (i = 0; attr[i]; i += 2) {
+               if (strcmp(attr[i], "id") == 0) {
+                       strncpy(grad->id, attr[i+1], 63);
+                       grad->id[63] = '\0';
+               } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "gradientUnits") == 0) {
+                               if (strcmp(attr[i+1], "objectBoundingBox") == 0)
+                                       grad->units = NSVG_OBJECT_SPACE;
+                               else
+                                       grad->units = NSVG_USER_SPACE;
+                       } else if (strcmp(attr[i], "gradientTransform") == 0) {
+                               nsvg__parseTransform(grad->xform, attr[i + 1]);
+                       } else if (strcmp(attr[i], "cx") == 0) {
+                               grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "cy") == 0) {
+                               grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "r") == 0) {
+                               grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "fx") == 0) {
+                               grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "fy") == 0) {
+                               grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "x1") == 0) {
+                               grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "y1") == 0) {
+                               grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "x2") == 0) {
+                               grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "y2") == 0) {
+                               grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "spreadMethod") == 0) {
+                               if (strcmp(attr[i+1], "pad") == 0)
+                                       grad->spread = NSVG_SPREAD_PAD;
+                               else if (strcmp(attr[i+1], "reflect") == 0)
+                                       grad->spread = NSVG_SPREAD_REFLECT;
+                               else if (strcmp(attr[i+1], "repeat") == 0)
+                                       grad->spread = NSVG_SPREAD_REPEAT;
+                       } else if (strcmp(attr[i], "xlink:href") == 0) {
+                               const char *href = attr[i+1];
+                               strncpy(grad->ref, href+1, 62);
+                               grad->ref[62] = '\0';
+                       }
+               }
+       }
+
+       grad->next = p->gradients;
+       p->gradients = grad;
+}
+
+static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
+{
+       NSVGattrib* curAttr = nsvg__getAttr(p);
+       NSVGgradientData* grad;
+       NSVGgradientStop* stop;
+       int i, idx;
+
+       curAttr->stopOffset = 0;
+       curAttr->stopColor = 0;
+       curAttr->stopOpacity = 1.0f;
+
+       for (i = 0; attr[i]; i += 2) {
+               nsvg__parseAttr(p, attr[i], attr[i + 1]);
+       }
+
+       // Add stop to the last gradient.
+       grad = p->gradients;
+       if (grad == NULL) return;
+
+       grad->nstops++;
+       grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
+       if (grad->stops == NULL) return;
+
+       // Insert
+       idx = grad->nstops-1;
+       for (i = 0; i < grad->nstops-1; i++) {
+               if (curAttr->stopOffset < grad->stops[i].offset) {
+                       idx = i;
+                       break;
+               }
+       }
+       if (idx != grad->nstops-1) {
+               for (i = grad->nstops-1; i > idx; i--)
+                       grad->stops[i] = grad->stops[i-1];
+       }
+
+       stop = &grad->stops[idx];
+       stop->color = curAttr->stopColor;
+       stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
+       stop->offset = curAttr->stopOffset;
+}
+
+static void nsvg__startElement(void* ud, const char* el, const char** attr)
+{
+       NSVGparser* p = (NSVGparser*)ud;
+
+       if (p->defsFlag) {
+               // Skip everything but gradients in defs
+               if (strcmp(el, "linearGradient") == 0) {
+                       nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
+               } else if (strcmp(el, "radialGradient") == 0) {
+                       nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
+               } else if (strcmp(el, "stop") == 0) {
+                       nsvg__parseGradientStop(p, attr);
+               }
+               return;
+       }
+
+       if (strcmp(el, "g") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseAttribs(p, attr);
+       } else if (strcmp(el, "path") == 0) {
+               if (p->pathFlag)        // Do not allow nested paths.
+                       return;
+               nsvg__pushAttr(p);
+               nsvg__parsePath(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "rect") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseRect(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "circle") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseCircle(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "ellipse") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseEllipse(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "line") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parseLine(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "polyline") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parsePoly(p, attr, 0);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "polygon") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parsePoly(p, attr, 1);
+               nsvg__popAttr(p);
+       } else  if (strcmp(el, "linearGradient") == 0) {
+               nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
+       } else if (strcmp(el, "radialGradient") == 0) {
+               nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
+       } else if (strcmp(el, "stop") == 0) {
+               nsvg__parseGradientStop(p, attr);
+       } else if (strcmp(el, "defs") == 0) {
+               p->defsFlag = 1;
+       } else if (strcmp(el, "svg") == 0) {
+               nsvg__parseSVG(p, attr);
+       }
+}
+
+static void nsvg__endElement(void* ud, const char* el)
+{
+       NSVGparser* p = (NSVGparser*)ud;
+
+       if (strcmp(el, "g") == 0) {
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "path") == 0) {
+               p->pathFlag = 0;
+       } else if (strcmp(el, "defs") == 0) {
+               p->defsFlag = 0;
+       }
+}
+
+static void nsvg__content(void* ud, const char* s)
+{
+       NSVG_NOTUSED(ud);
+       NSVG_NOTUSED(s);
+       // empty
+}
+
+static void nsvg__imageBounds(NSVGparser* p, float* bounds)
+{
+       NSVGshape* shape;
+       shape = p->image->shapes;
+       if (shape == NULL) {
+               bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
+               return;
+       }
+       bounds[0] = shape->bounds[0];
+       bounds[1] = shape->bounds[1];
+       bounds[2] = shape->bounds[2];
+       bounds[3] = shape->bounds[3];
+       for (shape = shape->next; shape != NULL; shape = shape->next) {
+               bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
+               bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
+               bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
+               bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
+       }
+}
+
+static float nsvg__viewAlign(float content, float container, int type)
+{
+       if (type == NSVG_ALIGN_MIN)
+               return 0;
+       else if (type == NSVG_ALIGN_MAX)
+               return container - content;
+       // mid
+       return (container - content) * 0.5f;
+}
+
+static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
+{
+       float t[6];
+       nsvg__xformSetTranslation(t, tx, ty);
+       nsvg__xformMultiply (grad->xform, t);
+
+       nsvg__xformSetScale(t, sx, sy);
+       nsvg__xformMultiply (grad->xform, t);
+}
+
+static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
+{
+       NSVGshape* shape;
+       NSVGpath* path;
+       float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
+       int i;
+       float* pt;
+
+       // Guess image size if not set completely.
+       nsvg__imageBounds(p, bounds);
+
+       if (p->viewWidth == 0) {
+               if (p->image->width > 0) {
+                       p->viewWidth = p->image->width;
+               } else {
+                       p->viewMinx = bounds[0];
+                       p->viewWidth = bounds[2] - bounds[0];
+               }
+       }
+       if (p->viewHeight == 0) {
+               if (p->image->height > 0) {
+                       p->viewHeight = p->image->height;
+               } else {
+                       p->viewMiny = bounds[1];
+                       p->viewHeight = bounds[3] - bounds[1];
+               }
+       }
+
+       /**
+        * We have sample images with the width and height set to 1, whereas the viewbox aspect ratio 
+        * is not square. Use the viewbox in this case.
+        */
+       if (p->image->width <= 1)
+               p->image->width = p->viewWidth;
+       if (p->image->height <= 1)
+               p->image->height = p->viewHeight;
+
+       tx = -p->viewMinx;
+       ty = -p->viewMiny;
+       sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
+       sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
+       // Unit scaling
+       us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
+
+       // Fix aspect ratio
+       if (p->alignType == NSVG_ALIGN_MEET) {
+               // fit whole image into viewbox
+               sx = sy = nsvg__minf(sx, sy);
+               tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
+               ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
+       } else if (p->alignType == NSVG_ALIGN_SLICE) {
+               // fill whole viewbox with image
+               sx = sy = nsvg__maxf(sx, sy);
+               tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
+               ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
+       }
+
+       // Transform
+       sx *= us;
+       sy *= us;
+       avgs = (sx+sy) / 2.0f;
+       for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
+               shape->bounds[0] = (shape->bounds[0] + tx) * sx;
+               shape->bounds[1] = (shape->bounds[1] + ty) * sy;
+               shape->bounds[2] = (shape->bounds[2] + tx) * sx;
+               shape->bounds[3] = (shape->bounds[3] + ty) * sy;
+               for (path = shape->paths; path != NULL; path = path->next) {
+                       path->bounds[0] = (path->bounds[0] + tx) * sx;
+                       path->bounds[1] = (path->bounds[1] + ty) * sy;
+                       path->bounds[2] = (path->bounds[2] + tx) * sx;
+                       path->bounds[3] = (path->bounds[3] + ty) * sy;
+                       for (i =0; i < path->npts; i++) {
+                               pt = &path->pts[i*2];
+                               pt[0] = (pt[0] + tx) * sx;
+                               pt[1] = (pt[1] + ty) * sy;
+                       }
+               }
+
+               if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
+                       nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
+                       memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
+                       nsvg__xformInverse(shape->fill.gradient->xform, t);
+               }
+               if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
+                       nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
+                       memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
+                       nsvg__xformInverse(shape->stroke.gradient->xform, t);
+               }
+
+               shape->strokeWidth *= avgs;
+               shape->strokeDashOffset *= avgs;
+               for (i = 0; i < shape->strokeDashCount; i++)
+                       shape->strokeDashArray[i] *= avgs;
+       }
+}
+
+NSVGimage* nsvgParse(char* input, const char* units, float dpi)
+{
+       NSVGparser* p;
+       NSVGimage* ret = 0;
+
+       p = nsvg__createParser();
+       if (p == NULL) {
+               return NULL;
+       }
+       p->dpi = dpi;
+
+       nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
+
+       // Scale to viewBox
+       nsvg__scaleToViewbox(p, units);
+
+       ret = p->image;
+       p->image = NULL;
+
+       nsvg__deleteParser(p);
+
+       return ret;
+}
+
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
+{
+       FILE* fp = NULL;
+       size_t size = 0;
+       long value = 0;
+       char* data = NULL;
+       NSVGimage* image = NULL;
+
+       fp = fopen(filename, "rb");
+       if (!fp) goto error;
+       fseek(fp, 0, SEEK_END);
+       value = ftell(fp);
+       /**
+        * In the original file, unsigned long type 'size' gets a return value. But, the return value of 'ftell()' is
+        * signed long type. To prevent interpreting an unexpected large value, we put the comparitive condition here.
+        */
+       if( value < 0 ) goto error;
+       size = value;
+       fseek(fp, 0, SEEK_SET);
+       data = (char*)malloc(size+1);
+       if (data == NULL) goto error;
+       if (fread(data, 1, size, fp) != size) goto error;
+       data[size] = '\0';      // Must be null terminated.
+       fclose(fp);
+       image = nsvgParse(data, units, dpi);
+       free(data);
+
+       return image;
+
+error:
+       if (fp) fclose(fp);
+       if (data) free(data);
+       if (image) nsvgDelete(image);
+       return NULL;
+}
+
+NSVGpath* nsvgDuplicatePath(NSVGpath* p)
+{
+    NSVGpath* res = NULL;
+
+    if (p == NULL)
+        return NULL;
+
+    res = (NSVGpath*)malloc(sizeof(NSVGpath));
+    if (res == NULL) goto error;
+    memset(res, 0, sizeof(NSVGpath));
+
+    res->pts = (float*)malloc(p->npts*2*sizeof(float));
+    if (res->pts == NULL) goto error;
+    memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
+    res->npts = p->npts;
+
+    memcpy(res->bounds, p->bounds, sizeof(p->bounds));
+
+    res->closed = p->closed;
+
+    return res;
+
+error:
+    if (res != NULL) {
+        free(res->pts);
+        free(res);
+    }
+    return NULL;
+}
+
+void nsvgDelete(NSVGimage* image)
+{
+       NSVGshape *snext, *shape;
+       if (image == NULL) return;
+       shape = image->shapes;
+       while (shape != NULL) {
+               snext = shape->next;
+               nsvg__deletePaths(shape->paths);
+               nsvg__deletePaint(&shape->fill);
+               nsvg__deletePaint(&shape->stroke);
+               free(shape);
+               shape = snext;
+       }
+       free(image);
+}
diff --git a/dali-toolkit/third-party/nanosvg/nanosvg.h b/dali-toolkit/third-party/nanosvg/nanosvg.h
new file mode 100644 (file)
index 0000000..27f8ac0
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
+ * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
+ *
+ * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
+ *
+ * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
+ *
+ */
+
+#ifndef NANOSVG_H
+#define NANOSVG_H
+
+// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
+//
+// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
+//
+// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
+//
+// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
+// That is, you should get the same looking data as your designed in your favorite app.
+//
+// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
+// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
+//
+// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
+// DPI (dots-per-inch) controls how the unit conversion is done.
+//
+// If you don't know or care about the units stuff, "px" and 96 should get you going.
+
+
+/* Example Usage:
+  // Load SVG
+  NSVGimage* image;
+  image = nsvgParseFromFile("test.svg", "px", 96);
+  printf("size: %f x %f\n", image->width, image->height);
+  // Use...
+  for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
+    for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
+      for (int i = 0; i < path->npts-1; i += 3) {
+        float* p = &path->pts[i*2];
+        drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
+      }
+    }
+  }
+  // Delete
+  nsvgDelete(image);
+*/
+
+enum NSVGpaintType {
+  NSVG_PAINT_NONE = 0,
+  NSVG_PAINT_COLOR = 1,
+  NSVG_PAINT_LINEAR_GRADIENT = 2,
+  NSVG_PAINT_RADIAL_GRADIENT = 3
+};
+
+enum NSVGspreadType {
+  NSVG_SPREAD_PAD = 0,
+  NSVG_SPREAD_REFLECT = 1,
+  NSVG_SPREAD_REPEAT = 2
+};
+
+enum NSVGlineJoin {
+  NSVG_JOIN_MITER = 0,
+  NSVG_JOIN_ROUND = 1,
+  NSVG_JOIN_BEVEL = 2
+};
+
+enum NSVGlineCap {
+  NSVG_CAP_BUTT = 0,
+  NSVG_CAP_ROUND = 1,
+  NSVG_CAP_SQUARE = 2
+};
+
+enum NSVGfillRule {
+  NSVG_FILLRULE_NONZERO = 0,
+  NSVG_FILLRULE_EVENODD = 1
+};
+
+enum NSVGflags {
+  NSVG_FLAGS_VISIBLE = 0x01
+};
+
+typedef struct NSVGgradientStop {
+  unsigned int color;
+  float offset;
+} NSVGgradientStop;
+
+typedef struct NSVGgradient {
+  float xform[6];
+  char spread;
+  float fx, fy;
+  int nstops;
+  NSVGgradientStop stops[1];
+} NSVGgradient;
+
+typedef struct NSVGpaint {
+  /**
+   * In the original file, using char type (without signed or unsigned) can be interpreted
+   * as 'unsigned char' in some build environments, like ARM architecture.
+   * To prevent the unexpected behavior, we replace 'char type' with 'signed char type' here.
+   */
+  signed char type;
+  union {
+    unsigned int  color;
+    NSVGgradient* gradient;
+  };
+} NSVGpaint;
+
+typedef struct NSVGpath
+{
+  float*           pts;         // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
+  int              npts;        // Total number of bezier points.
+  char             closed;      // Flag indicating if shapes should be treated as closed.
+  float            bounds[4];   // Tight bounding box of the shape [minx,miny,maxx,maxy].
+  struct NSVGpath* next;        // Pointer to next path, or NULL if last element.
+} NSVGpath;
+
+typedef struct NSVGshape
+{
+  char              id[64];     // Optional 'id' attr of the shape or its group
+  NSVGpaint         fill;       // Fill paint
+  NSVGpaint         stroke;     // Stroke paint
+  float             opacity;    // Opacity of the shape.
+  float             strokeWidth; // Stroke width (scaled).
+  float             strokeDashOffset; // Stroke dash offset (scaled).
+  float             strokeDashArray[8]; // Stroke dash array (scaled).
+  char              strokeDashCount; // Number of dash values in dash array.
+  char              strokeLineJoin; // Stroke join type.
+  char              strokeLineCap; // Stroke cap type.
+  float             miterLimit; // Miter limit
+  char              fillRule;   // Fill rule, see NSVGfillRule.
+  unsigned char     flags;      // Logical or of NSVG_FLAGS_* flags
+  float             bounds[4];  // Tight bounding box of the shape [minx,miny,maxx,maxy].
+  NSVGpath*         paths;      // Linked list of paths in the image.
+  struct NSVGshape* next;       // Pointer to next shape, or NULL if last element.
+} NSVGshape;
+
+typedef struct NSVGimage
+{
+  float      width;             // Width of the image.
+  float      height;            // Height of the image.
+  NSVGshape* shapes;            // Linked list of shapes in the image.
+} NSVGimage;
+
+// Parses SVG file from a file, returns SVG image as paths.
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
+
+// Parses SVG file from a null terminated string, returns SVG image as paths.
+// Important note: changes the string.
+NSVGimage* nsvgParse(char* input, const char* units, float dpi);
+
+// Duplicates a path.
+NSVGpath* nsvgDuplicatePath(NSVGpath* p);
+
+// Deletes an image.
+void nsvgDelete(NSVGimage* image);
+
+#endif // NANOSVG_H
+
+/**
+ * In the original software, The nanosvg implementation was followed here.
+ * We have moved the implementation to nanosvg.cc.
+ */
diff --git a/dali-toolkit/third-party/nanosvg/nanosvgrast.cc b/dali-toolkit/third-party/nanosvg/nanosvgrast.cc
new file mode 100644 (file)
index 0000000..259f695
--- /dev/null
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * The polygon rasterization is heavily based on stb_truetype rasterizer
+ * by Sean Barrett - http://nothings.org/
+ *
+ */
+
+#include "nanosvgrast.h"
+
+/**
+ * In the original software, The nanosvgrast implementation was included in the header file.
+ * We have separated the implementation to source file here.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define NSVG__SUBSAMPLES    5
+#define NSVG__FIXSHIFT      10
+#define NSVG__FIX           (1 << NSVG__FIXSHIFT)
+#define NSVG__FIXMASK       (NSVG__FIX-1)
+#define NSVG__MEMPAGE_SIZE  1024
+
+typedef struct NSVGedge {
+       float x0,y0, x1,y1;
+       int dir;
+       struct NSVGedge* next;
+} NSVGedge;
+
+typedef struct NSVGpoint {
+       float x, y;
+       float dx, dy;
+       float len;
+       float dmx, dmy;
+       unsigned char flags;
+} NSVGpoint;
+
+typedef struct NSVGactiveEdge {
+       int x,dx;
+       float ey;
+       int dir;
+       struct NSVGactiveEdge *next;
+} NSVGactiveEdge;
+
+typedef struct NSVGmemPage {
+       unsigned char mem[NSVG__MEMPAGE_SIZE];
+       int size;
+       struct NSVGmemPage* next;
+} NSVGmemPage;
+
+typedef struct NSVGcachedPaint {
+  /**
+   * In the original file, using char type (without signed or unsigned) can be interpreted
+   * as 'unsigned char' in some build environments, like ARM architecture.
+   * To prevent the unexpected behavior, we replace 'char type' with 'signed char type' here.
+   */
+  signed char type;
+       char spread;
+       float xform[6];
+       unsigned int colors[256];
+} NSVGcachedPaint;
+
+struct NSVGrasterizer
+{
+       float px, py;
+
+       float tessTol;
+       float distTol;
+
+       NSVGedge* edges;
+       int nedges;
+       int cedges;
+
+       NSVGpoint* points;
+       int npoints;
+       int cpoints;
+
+       NSVGpoint* points2;
+       int npoints2;
+       int cpoints2;
+
+       NSVGactiveEdge* freelist;
+       NSVGmemPage* pages;
+       NSVGmemPage* curpage;
+
+       unsigned char* scanline;
+       int cscanline;
+
+       unsigned char* bitmap;
+       int width, height, stride;
+};
+
+NSVGrasterizer* nsvgCreateRasterizer()
+{
+       NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
+       if (r == NULL) goto error;
+       memset(r, 0, sizeof(NSVGrasterizer));
+
+       r->tessTol = 0.25f;
+       r->distTol = 0.01f;
+
+       return r;
+
+error:
+       nsvgDeleteRasterizer(r);
+       return NULL;
+}
+
+void nsvgDeleteRasterizer(NSVGrasterizer* r)
+{
+       NSVGmemPage* p;
+
+       if (r == NULL) return;
+
+       p = r->pages;
+       while (p != NULL) {
+               NSVGmemPage* next = p->next;
+               free(p);
+               p = next;
+       }
+
+       if (r->edges) free(r->edges);
+       if (r->points) free(r->points);
+       if (r->points2) free(r->points2);
+       if (r->scanline) free(r->scanline);
+
+       free(r);
+}
+
+static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
+{
+       NSVGmemPage *newp;
+
+       // If using existing chain, return the next page in chain
+       if (cur != NULL && cur->next != NULL) {
+               return cur->next;
+       }
+
+       // Alloc new page
+       newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
+       if (newp == NULL) return NULL;
+       memset(newp, 0, sizeof(NSVGmemPage));
+
+       // Add to linked list
+       if (cur != NULL)
+               cur->next = newp;
+       else
+               r->pages = newp;
+
+       return newp;
+}
+
+static void nsvg__resetPool(NSVGrasterizer* r)
+{
+       NSVGmemPage* p = r->pages;
+       while (p != NULL) {
+               p->size = 0;
+               p = p->next;
+       }
+       r->curpage = r->pages;
+}
+
+static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
+{
+       unsigned char* buf;
+       if (size > NSVG__MEMPAGE_SIZE) return NULL;
+       if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
+               r->curpage = nsvg__nextPage(r, r->curpage);
+       }
+       buf = &r->curpage->mem[r->curpage->size];
+       r->curpage->size += size;
+       return buf;
+}
+
+static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
+{
+       float dx = x2 - x1;
+       float dy = y2 - y1;
+       return dx*dx + dy*dy < tol*tol;
+}
+
+static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
+{
+       NSVGpoint* pt;
+
+       if (r->npoints > 0) {
+               pt = &r->points[r->npoints-1];
+               if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
+                       pt->flags = (unsigned char)(pt->flags | flags);
+                       return;
+               }
+       }
+
+       if (r->npoints+1 > r->cpoints) {
+               r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
+               r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
+               if (r->points == NULL) return;
+       }
+
+       pt = &r->points[r->npoints];
+       pt->x = x;
+       pt->y = y;
+       pt->flags = (unsigned char)flags;
+       r->npoints++;
+}
+
+static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
+{
+       if (r->npoints+1 > r->cpoints) {
+               r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
+               r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
+               if (r->points == NULL) return;
+       }
+       r->points[r->npoints] = pt;
+       r->npoints++;
+}
+
+static void nsvg__duplicatePoints(NSVGrasterizer* r)
+{
+       if (r->npoints > r->cpoints2) {
+               r->cpoints2 = r->npoints;
+               r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
+               if (r->points2 == NULL) return;
+       }
+
+       memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
+       r->npoints2 = r->npoints;
+}
+
+static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
+{
+       NSVGedge* e;
+
+       // Skip horizontal edges
+       if (y0 == y1)
+               return;
+
+       if (r->nedges+1 > r->cedges) {
+               r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
+               r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
+               if (r->edges == NULL) return;
+       }
+
+       e = &r->edges[r->nedges];
+       r->nedges++;
+
+       if (y0 < y1) {
+               e->x0 = x0;
+               e->y0 = y0;
+               e->x1 = x1;
+               e->y1 = y1;
+               e->dir = 1;
+       } else {
+               e->x0 = x1;
+               e->y0 = y1;
+               e->x1 = x0;
+               e->y1 = y0;
+               e->dir = -1;
+       }
+}
+
+static float nsvg__normalize(float *x, float* y)
+{
+       float d = sqrtf((*x)*(*x) + (*y)*(*y));
+       if (d > 1e-6f) {
+               float id = 1.0f / d;
+               *x *= id;
+               *y *= id;
+       }
+       return d;
+}
+
+static float nsvg__absf(float x) { return x < 0 ? -x : x; }
+
+static void nsvg__flattenCubicBez(NSVGrasterizer* r,
+                                                                 float x1, float y1, float x2, float y2,
+                                                                 float x3, float y3, float x4, float y4,
+                                                                 int level, int type)
+{
+       float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
+       float dx,dy,d2,d3;
+
+       if (level > 10) return;
+
+       x12 = (x1+x2)*0.5f;
+       y12 = (y1+y2)*0.5f;
+       x23 = (x2+x3)*0.5f;
+       y23 = (y2+y3)*0.5f;
+       x34 = (x3+x4)*0.5f;
+       y34 = (y3+y4)*0.5f;
+       x123 = (x12+x23)*0.5f;
+       y123 = (y12+y23)*0.5f;
+
+       dx = x4 - x1;
+       dy = y4 - y1;
+       d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
+       d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
+
+       if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
+               nsvg__addPathPoint(r, x4, y4, type);
+               return;
+       }
+
+       x234 = (x23+x34)*0.5f;
+       y234 = (y23+y34)*0.5f;
+       x1234 = (x123+x234)*0.5f;
+       y1234 = (y123+y234)*0.5f;
+
+       nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
+       nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
+}
+
+static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
+{
+       int i, j;
+       NSVGpath* path;
+
+       for (path = shape->paths; path != NULL; path = path->next) {
+               r->npoints = 0;
+               // Flatten path
+               nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
+               for (i = 0; i < path->npts-1; i += 3) {
+                       float* p = &path->pts[i*2];
+                       nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
+               }
+               // Close path
+               nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
+               // Build edges
+               for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
+                       nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
+       }
+}
+
+enum NSVGpointFlags
+{
+       NSVG_PT_CORNER = 0x01,
+       NSVG_PT_BEVEL = 0x02,
+       NSVG_PT_LEFT = 0x04
+};
+
+static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
+{
+       float w = lineWidth * 0.5f;
+       float dx = p1->x - p0->x;
+       float dy = p1->y - p0->y;
+       float len = nsvg__normalize(&dx, &dy);
+       float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
+       float dlx = dy, dly = -dx;
+       float lx = px - dlx*w, ly = py - dly*w;
+       float rx = px + dlx*w, ry = py + dly*w;
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
+{
+       float w = lineWidth * 0.5f;
+       float px = p->x, py = p->y;
+       float dlx = dy, dly = -dx;
+       float lx = px - dlx*w, ly = py - dly*w;
+       float rx = px + dlx*w, ry = py + dly*w;
+
+       nsvg__addEdge(r, lx, ly, rx, ry);
+
+       if (connect) {
+               nsvg__addEdge(r, left->x, left->y, lx, ly);
+               nsvg__addEdge(r, rx, ry, right->x, right->y);
+       }
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
+{
+       float w = lineWidth * 0.5f;
+       float px = p->x - dx*w, py = p->y - dy*w;
+       float dlx = dy, dly = -dx;
+       float lx = px - dlx*w, ly = py - dly*w;
+       float rx = px + dlx*w, ry = py + dly*w;
+
+       nsvg__addEdge(r, lx, ly, rx, ry);
+
+       if (connect) {
+               nsvg__addEdge(r, left->x, left->y, lx, ly);
+               nsvg__addEdge(r, rx, ry, right->x, right->y);
+       }
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+#ifndef NSVG_PI
+#define NSVG_PI (3.14159265358979323846264338327f)
+#endif
+
+static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
+{
+       int i;
+       float w = lineWidth * 0.5f;
+       float px = p->x, py = p->y;
+       float dlx = dy, dly = -dx;
+       float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
+
+       for (i = 0; i < ncap; i++) {
+               float a = (float)i/(float)(ncap-1)*NSVG_PI;
+               float ax = cosf(a) * w, ay = sinf(a) * w;
+               float x = px - dlx*ax - dx*ay;
+               float y = py - dly*ax - dy*ay;
+
+               if (i > 0)
+                       nsvg__addEdge(r, prevx, prevy, x, y);
+
+               prevx = x;
+               prevy = y;
+
+               if (i == 0) {
+                       lx = x; ly = y;
+               } else if (i == ncap-1) {
+                       rx = x; ry = y;
+               }
+       }
+
+       if (connect) {
+               nsvg__addEdge(r, left->x, left->y, lx, ly);
+               nsvg__addEdge(r, rx, ry, right->x, right->y);
+       }
+
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
+{
+       float w = lineWidth * 0.5f;
+       float dlx0 = p0->dy, dly0 = -p0->dx;
+       float dlx1 = p1->dy, dly1 = -p1->dx;
+       float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
+       float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
+       float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
+       float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
+
+       nsvg__addEdge(r, lx0, ly0, left->x, left->y);
+       nsvg__addEdge(r, lx1, ly1, lx0, ly0);
+
+       nsvg__addEdge(r, right->x, right->y, rx0, ry0);
+       nsvg__addEdge(r, rx0, ry0, rx1, ry1);
+
+       left->x = lx1; left->y = ly1;
+       right->x = rx1; right->y = ry1;
+}
+
+static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
+{
+       float w = lineWidth * 0.5f;
+       float dlx0 = p0->dy, dly0 = -p0->dx;
+       float dlx1 = p1->dy, dly1 = -p1->dx;
+       float lx0, rx0, lx1, rx1;
+       float ly0, ry0, ly1, ry1;
+
+       if (p1->flags & NSVG_PT_LEFT) {
+               lx0 = lx1 = p1->x - p1->dmx * w;
+               ly0 = ly1 = p1->y - p1->dmy * w;
+               nsvg__addEdge(r, lx1, ly1, left->x, left->y);
+
+               rx0 = p1->x + (dlx0 * w);
+               ry0 = p1->y + (dly0 * w);
+               rx1 = p1->x + (dlx1 * w);
+               ry1 = p1->y + (dly1 * w);
+               nsvg__addEdge(r, right->x, right->y, rx0, ry0);
+               nsvg__addEdge(r, rx0, ry0, rx1, ry1);
+       } else {
+               lx0 = p1->x - (dlx0 * w);
+               ly0 = p1->y - (dly0 * w);
+               lx1 = p1->x - (dlx1 * w);
+               ly1 = p1->y - (dly1 * w);
+               nsvg__addEdge(r, lx0, ly0, left->x, left->y);
+               nsvg__addEdge(r, lx1, ly1, lx0, ly0);
+
+               rx0 = rx1 = p1->x + p1->dmx * w;
+               ry0 = ry1 = p1->y + p1->dmy * w;
+               nsvg__addEdge(r, right->x, right->y, rx1, ry1);
+       }
+
+       left->x = lx1; left->y = ly1;
+       right->x = rx1; right->y = ry1;
+}
+
+static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
+{
+       int i, n;
+       float w = lineWidth * 0.5f;
+       float dlx0 = p0->dy, dly0 = -p0->dx;
+       float dlx1 = p1->dy, dly1 = -p1->dx;
+       float a0 = atan2f(dly0, dlx0);
+       float a1 = atan2f(dly1, dlx1);
+       float da = a1 - a0;
+       float lx, ly, rx, ry;
+
+       if (da < NSVG_PI) da += NSVG_PI*2;
+       if (da > NSVG_PI) da -= NSVG_PI*2;
+
+       n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
+       if (n < 2) n = 2;
+       if (n > ncap) n = ncap;
+
+       lx = left->x;
+       ly = left->y;
+       rx = right->x;
+       ry = right->y;
+
+       for (i = 0; i < n; i++) {
+               float u = (float)i/(float)(n-1);
+               float a = a0 + u*da;
+               float ax = cosf(a) * w, ay = sinf(a) * w;
+               float lx1 = p1->x - ax, ly1 = p1->y - ay;
+               float rx1 = p1->x + ax, ry1 = p1->y + ay;
+
+               nsvg__addEdge(r, lx1, ly1, lx, ly);
+               nsvg__addEdge(r, rx, ry, rx1, ry1);
+
+               lx = lx1; ly = ly1;
+               rx = rx1; ry = ry1;
+       }
+
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
+{
+       float w = lineWidth * 0.5f;
+       float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
+       float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
+
+       nsvg__addEdge(r, lx, ly, left->x, left->y);
+       nsvg__addEdge(r, right->x, right->y, rx, ry);
+
+       left->x = lx; left->y = ly;
+       right->x = rx; right->y = ry;
+}
+
+static int nsvg__curveDivs(float r, float arc, float tol)
+{
+       float da = acosf(r / (r + tol)) * 2.0f;
+       int divs = (int)ceilf(arc / da);
+       if (divs < 2) divs = 2;
+       return divs;
+}
+
+static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
+{
+       int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol);        // Calculate divisions per half circle.
+       NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
+       NSVGpoint* p0, *p1;
+       int j, s, e;
+
+       // Build stroke edges
+       if (closed) {
+               // Looping
+               p0 = &points[npoints-1];
+               p1 = &points[0];
+               s = 0;
+               e = npoints;
+       } else {
+               // Add cap
+               p0 = &points[0];
+               p1 = &points[1];
+               s = 1;
+               e = npoints-1;
+       }
+
+       if (closed) {
+               nsvg__initClosed(&left, &right, p0, p1, lineWidth);
+               firstLeft = left;
+               firstRight = right;
+       } else {
+               // Add cap
+               float dx = p1->x - p0->x;
+               float dy = p1->y - p0->y;
+               nsvg__normalize(&dx, &dy);
+               if (lineCap == NSVG_CAP_BUTT)
+                       nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
+               else if (lineCap == NSVG_CAP_SQUARE)
+                       nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
+               else if (lineCap == NSVG_CAP_ROUND)
+                       nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
+       }
+
+       for (j = s; j < e; ++j) {
+               if (p1->flags & NSVG_PT_CORNER) {
+                       if (lineJoin == NSVG_JOIN_ROUND)
+                               nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
+                       else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
+                               nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
+                       else
+                               nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
+               } else {
+                       nsvg__straightJoin(r, &left, &right, p1, lineWidth);
+               }
+               p0 = p1++;
+       }
+
+       if (closed) {
+               // Loop it
+               nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
+               nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
+       } else {
+               // Add cap
+               float dx = p1->x - p0->x;
+               float dy = p1->y - p0->y;
+               nsvg__normalize(&dx, &dy);
+               if (lineCap == NSVG_CAP_BUTT)
+                       nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
+               else if (lineCap == NSVG_CAP_SQUARE)
+                       nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
+               else if (lineCap == NSVG_CAP_ROUND)
+                       nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
+       }
+}
+
+static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
+{
+       int i, j;
+       NSVGpoint* p0, *p1;
+
+       p0 = &r->points[r->npoints-1];
+       p1 = &r->points[0];
+       for (i = 0; i < r->npoints; i++) {
+               // Calculate segment direction and length
+               p0->dx = p1->x - p0->x;
+               p0->dy = p1->y - p0->y;
+               p0->len = nsvg__normalize(&p0->dx, &p0->dy);
+               // Advance
+               p0 = p1++;
+       }
+
+       // calculate joins
+       p0 = &r->points[r->npoints-1];
+       p1 = &r->points[0];
+       for (j = 0; j < r->npoints; j++) {
+               float dlx0, dly0, dlx1, dly1, dmr2, cross;
+               dlx0 = p0->dy;
+               dly0 = -p0->dx;
+               dlx1 = p1->dy;
+               dly1 = -p1->dx;
+               // Calculate extrusions
+               p1->dmx = (dlx0 + dlx1) * 0.5f;
+               p1->dmy = (dly0 + dly1) * 0.5f;
+               dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
+               if (dmr2 > 0.000001f) {
+                       float s2 = 1.0f / dmr2;
+                       if (s2 > 600.0f) {
+                               s2 = 600.0f;
+                       }
+                       p1->dmx *= s2;
+                       p1->dmy *= s2;
+               }
+
+               // Clear flags, but keep the corner.
+               p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
+
+               // Keep track of left turns.
+               cross = p1->dx * p0->dy - p0->dx * p1->dy;
+               if (cross > 0.0f)
+                       p1->flags |= NSVG_PT_LEFT;
+
+               // Check to see if the corner needs to be beveled.
+               if (p1->flags & NSVG_PT_CORNER) {
+                       if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
+                               p1->flags |= NSVG_PT_BEVEL;
+                       }
+               }
+
+               p0 = p1++;
+       }
+}
+
+static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
+{
+       int i, j, closed;
+       NSVGpath* path;
+       NSVGpoint* p0, *p1;
+       float miterLimit = shape->miterLimit;
+       int lineJoin = shape->strokeLineJoin;
+       int lineCap = shape->strokeLineCap;
+       float lineWidth = shape->strokeWidth * scale;
+
+       for (path = shape->paths; path != NULL; path = path->next) {
+               // Flatten path
+               r->npoints = 0;
+               nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
+               for (i = 0; i < path->npts-1; i += 3) {
+                       float* p = &path->pts[i*2];
+                       nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
+               }
+               if (r->npoints < 2)
+                       continue;
+
+               closed = path->closed;
+
+               // If the first and last points are the same, remove the last, mark as closed path.
+               p0 = &r->points[r->npoints-1];
+               p1 = &r->points[0];
+               if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
+                       r->npoints--;
+                       p0 = &r->points[r->npoints-1];
+                       closed = 1;
+               }
+
+               if (shape->strokeDashCount > 0) {
+                       int idash = 0, dashState = 1;
+                       float totalDist = 0, dashLen, allDashLen, dashOffset;
+                       NSVGpoint cur;
+
+                       if (closed)
+                               nsvg__appendPathPoint(r, r->points[0]);
+
+                       // Duplicate points -> points2.
+                       nsvg__duplicatePoints(r);
+
+                       r->npoints = 0;
+                       cur = r->points2[0];
+                       nsvg__appendPathPoint(r, cur);
+
+                       // Figure out dash offset.
+                       allDashLen = 0;
+                       for (j = 0; j < shape->strokeDashCount; j++)
+                               allDashLen += shape->strokeDashArray[j];
+                       if (shape->strokeDashCount & 1)
+                               allDashLen *= 2.0f;
+                       // Find location inside pattern
+                       dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
+                       if (dashOffset < 0.0f)
+                               dashOffset += allDashLen;
+
+                       while (dashOffset > shape->strokeDashArray[idash]) {
+                               dashOffset -= shape->strokeDashArray[idash];
+                               idash = (idash + 1) % shape->strokeDashCount;
+                       }
+                       dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
+
+                       for (j = 1; j < r->npoints2; ) {
+                               float dx = r->points2[j].x - cur.x;
+                               float dy = r->points2[j].y - cur.y;
+                               float dist = sqrtf(dx*dx + dy*dy);
+
+                               if ((totalDist + dist) > dashLen) {
+                                       // Calculate intermediate point
+                                       float d = (dashLen - totalDist) / dist;
+                                       float x = cur.x + dx * d;
+                                       float y = cur.y + dy * d;
+                                       nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
+
+                                       // Stroke
+                                       if (r->npoints > 1 && dashState) {
+                                               nsvg__prepareStroke(r, miterLimit, lineJoin);
+                                               nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
+                                       }
+                                       // Advance dash pattern
+                                       dashState = !dashState;
+                                       idash = (idash+1) % shape->strokeDashCount;
+                                       dashLen = shape->strokeDashArray[idash] * scale;
+                                       // Restart
+                                       cur.x = x;
+                                       cur.y = y;
+                                       cur.flags = NSVG_PT_CORNER;
+                                       totalDist = 0.0f;
+                                       r->npoints = 0;
+                                       nsvg__appendPathPoint(r, cur);
+                               } else {
+                                       totalDist += dist;
+                                       cur = r->points2[j];
+                                       nsvg__appendPathPoint(r, cur);
+                                       j++;
+                               }
+                       }
+                       // Stroke any leftover path
+                       if (r->npoints > 1 && dashState)
+                               nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
+               } else {
+                       nsvg__prepareStroke(r, miterLimit, lineJoin);
+                       nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
+               }
+       }
+}
+
+static int nsvg__cmpEdge(const void *p, const void *q)
+{
+       const NSVGedge* a = (const NSVGedge*)p;
+       const NSVGedge* b = (const NSVGedge*)q;
+
+       if (a->y0 < b->y0) return -1;
+       if (a->y0 > b->y0) return  1;
+       return 0;
+}
+
+
+static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
+{
+        NSVGactiveEdge* z;
+
+       if (r->freelist != NULL) {
+               // Restore from freelist.
+               z = r->freelist;
+               r->freelist = z->next;
+       } else {
+               // Alloc new edge.
+               z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
+               if (z == NULL) return NULL;
+       }
+
+       float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
+//     STBTT_assert(e->y0 <= start_point);
+       // round dx down to avoid going too far
+       if (dxdy < 0)
+               z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
+       else
+               z->dx = (int)floorf(NSVG__FIX * dxdy);
+       z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
+//     z->x -= off_x * FIX;
+       z->ey = e->y1;
+       z->next = 0;
+       z->dir = e->dir;
+
+       return z;
+}
+
+static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
+{
+       z->next = r->freelist;
+       r->freelist = z;
+}
+
+static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
+{
+       int i = x0 >> NSVG__FIXSHIFT;
+       int j = x1 >> NSVG__FIXSHIFT;
+       if (i < *xmin) *xmin = i;
+       if (j > *xmax) *xmax = j;
+       if (i < len && j >= 0) {
+               if (i == j) {
+                       // x0,x1 are the same pixel, so compute combined coverage
+                       scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
+               } else {
+                       if (i >= 0) // add antialiasing for x0
+                               scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
+                       else
+                               i = -1; // clip
+
+                       if (j < len) // add antialiasing for x1
+                               scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
+                       else
+                               j = len; // clip
+
+                       for (++i; i < j; ++i) // fill pixels between x0 and x1
+                               scanline[i] = (unsigned char)(scanline[i] + maxWeight);
+               }
+       }
+}
+
+// note: this routine clips fills that extend off the edges... ideally this
+// wouldn't happen, but it could happen if the truetype glyph bounding boxes
+// are wrong, or if the user supplies a too-small bitmap
+
+/**
+ * In the original file, using char type (without signed or unsigned) can be interpreted
+ * as 'unsigned char' in some build environments, like ARM architecture.
+ * To prevent the unexpected behavior, we replace 'char fillRule' with 'signed char fillRule' here.
+ */
+static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, signed char fillRule)
+{
+       // non-zero winding fill
+       int x0 = 0, w = 0;
+
+       if (fillRule == NSVG_FILLRULE_NONZERO) {
+               // Non-zero
+               while (e != NULL) {
+                       if (w == 0) {
+                               // if we're currently at zero, we need to record the edge start point
+                               x0 = e->x; w += e->dir;
+                       } else {
+                               int x1 = e->x; w += e->dir;
+                               // if we went to zero, we need to draw
+                               if (w == 0)
+                                       nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
+                       }
+                       e = e->next;
+               }
+       } else if (fillRule == NSVG_FILLRULE_EVENODD) {
+               // Even-odd
+               while (e != NULL) {
+                       if (w == 0) {
+                               // if we're currently at zero, we need to record the edge start point
+                               x0 = e->x; w = 1;
+                       } else {
+                               int x1 = e->x; w = 0;
+                               nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
+                       }
+                       e = e->next;
+               }
+       }
+}
+
+static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
+
+static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+       return (r) | (g << 8) | (b << 16) | (a << 24);
+}
+
+static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
+{
+       int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
+       int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
+       int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
+       int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
+       int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
+       return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
+}
+
+static unsigned int nsvg__applyOpacity(unsigned int c, float u)
+{
+       int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
+       int r = (c) & 0xff;
+       int g = (c>>8) & 0xff;
+       int b = (c>>16) & 0xff;
+       int a = (((c>>24) & 0xff)*iu) >> 8;
+       return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
+}
+
+static inline int nsvg__div255(int x)
+{
+    return ((x+1) * 257) >> 16;
+}
+
+static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
+                                                               float tx, float ty, float scale, NSVGcachedPaint* cache)
+{
+
+       if (cache->type == NSVG_PAINT_COLOR) {
+               int i, cr, cg, cb, ca;
+               cr = cache->colors[0] & 0xff;
+               cg = (cache->colors[0] >> 8) & 0xff;
+               cb = (cache->colors[0] >> 16) & 0xff;
+               ca = (cache->colors[0] >> 24) & 0xff;
+
+               for (i = 0; i < count; i++) {
+                       int r,g,b;
+                       int a = nsvg__div255((int)cover[0] * ca);
+                       int ia = 255 - a;
+                       // Premultiply
+                       r = nsvg__div255(cr * a);
+                       g = nsvg__div255(cg * a);
+                       b = nsvg__div255(cb * a);
+
+                       // Blend over
+                       r += nsvg__div255(ia * (int)dst[0]);
+                       g += nsvg__div255(ia * (int)dst[1]);
+                       b += nsvg__div255(ia * (int)dst[2]);
+                       a += nsvg__div255(ia * (int)dst[3]);
+
+                       dst[0] = (unsigned char)r;
+                       dst[1] = (unsigned char)g;
+                       dst[2] = (unsigned char)b;
+                       dst[3] = (unsigned char)a;
+
+                       cover++;
+                       dst += 4;
+               }
+       } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
+               // TODO: spread modes.
+               // TODO: plenty of opportunities to optimize.
+               float fx, fy, dx, gy;
+               float* t = cache->xform;
+               int i, cr, cg, cb, ca;
+               unsigned int c;
+
+               fx = ((float)x - tx) / scale;
+               fy = ((float)y - ty) / scale;
+               dx = 1.0f / scale;
+
+               for (i = 0; i < count; i++) {
+                       int r,g,b,a,ia;
+                       gy = fx*t[1] + fy*t[3] + t[5];
+                       c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
+                       cr = (c) & 0xff;
+                       cg = (c >> 8) & 0xff;
+                       cb = (c >> 16) & 0xff;
+                       ca = (c >> 24) & 0xff;
+
+                       a = nsvg__div255((int)cover[0] * ca);
+                       ia = 255 - a;
+
+                       // Premultiply
+                       r = nsvg__div255(cr * a);
+                       g = nsvg__div255(cg * a);
+                       b = nsvg__div255(cb * a);
+
+                       // Blend over
+                       r += nsvg__div255(ia * (int)dst[0]);
+                       g += nsvg__div255(ia * (int)dst[1]);
+                       b += nsvg__div255(ia * (int)dst[2]);
+                       a += nsvg__div255(ia * (int)dst[3]);
+
+                       dst[0] = (unsigned char)r;
+                       dst[1] = (unsigned char)g;
+                       dst[2] = (unsigned char)b;
+                       dst[3] = (unsigned char)a;
+
+                       cover++;
+                       dst += 4;
+                       fx += dx;
+               }
+       } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
+               // TODO: spread modes.
+               // TODO: plenty of opportunities to optimize.
+               // TODO: focus (fx,fy)
+               float fx, fy, dx, gx, gy, gd;
+               float* t = cache->xform;
+               int i, cr, cg, cb, ca;
+               unsigned int c;
+
+               fx = ((float)x - tx) / scale;
+               fy = ((float)y - ty) / scale;
+               dx = 1.0f / scale;
+
+               for (i = 0; i < count; i++) {
+                       int r,g,b,a,ia;
+                       gx = fx*t[0] + fy*t[2] + t[4];
+                       gy = fx*t[1] + fy*t[3] + t[5];
+                       gd = sqrtf(gx*gx + gy*gy);
+                       c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
+                       cr = (c) & 0xff;
+                       cg = (c >> 8) & 0xff;
+                       cb = (c >> 16) & 0xff;
+                       ca = (c >> 24) & 0xff;
+
+                       a = nsvg__div255((int)cover[0] * ca);
+                       ia = 255 - a;
+
+                       // Premultiply
+                       r = nsvg__div255(cr * a);
+                       g = nsvg__div255(cg * a);
+                       b = nsvg__div255(cb * a);
+
+                       // Blend over
+                       r += nsvg__div255(ia * (int)dst[0]);
+                       g += nsvg__div255(ia * (int)dst[1]);
+                       b += nsvg__div255(ia * (int)dst[2]);
+                       a += nsvg__div255(ia * (int)dst[3]);
+
+                       dst[0] = (unsigned char)r;
+                       dst[1] = (unsigned char)g;
+                       dst[2] = (unsigned char)b;
+                       dst[3] = (unsigned char)a;
+
+                       cover++;
+                       dst += 4;
+                       fx += dx;
+               }
+       }
+}
+
+static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)
+{
+       NSVGactiveEdge *active = NULL;
+       int y, s;
+       int e = 0;
+       int maxWeight = (255 / NSVG__SUBSAMPLES);  // weight per vertical scanline
+       int xmin, xmax;
+
+       for (y = 0; y < r->height; y++) {
+               memset(r->scanline, 0, r->width);
+               xmin = r->width;
+               xmax = 0;
+               for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
+                       // find center of pixel for this scanline
+                       float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
+                       NSVGactiveEdge **step = &active;
+
+                       // update all active edges;
+                       // remove all active edges that terminate before the center of this scanline
+                       while (*step) {
+                               NSVGactiveEdge *z = *step;
+                               if (z->ey <= scany) {
+                                       *step = z->next; // delete from list
+//                                     NSVG__assert(z->valid);
+                                       nsvg__freeActive(r, z);
+                               } else {
+                                       z->x += z->dx; // advance to position for current scanline
+                                       step = &((*step)->next); // advance through list
+                               }
+                       }
+
+                       // resort the list if needed
+                       for (;;) {
+                               int changed = 0;
+                               step = &active;
+                               while (*step && (*step)->next) {
+                                       if ((*step)->x > (*step)->next->x) {
+                                               NSVGactiveEdge* t = *step;
+                                               NSVGactiveEdge* q = t->next;
+                                               t->next = q->next;
+                                               q->next = t;
+                                               *step = q;
+                                               changed = 1;
+                                       }
+                                       step = &(*step)->next;
+                               }
+                               if (!changed) break;
+                       }
+
+                       // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
+                       while (e < r->nedges && r->edges[e].y0 <= scany) {
+                               if (r->edges[e].y1 > scany) {
+                                       NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
+                                       if (z == NULL) break;
+                                       // find insertion point
+                                       if (active == NULL) {
+                                               active = z;
+                                       } else if (z->x < active->x) {
+                                               // insert at front
+                                               z->next = active;
+                                               active = z;
+                                       } else {
+                                               // find thing to insert AFTER
+                                               NSVGactiveEdge* p = active;
+                                               while (p->next && p->next->x < z->x)
+                                                       p = p->next;
+                                               // at this point, p->next->x is NOT < z->x
+                                               z->next = p->next;
+                                               p->next = z;
+                                       }
+                               }
+                               e++;
+                       }
+
+                       // now process all active edges in non-zero fashion
+                       if (active != NULL)
+                               nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
+               }
+               // Blit
+               if (xmin < 0) xmin = 0;
+               if (xmax > r->width-1) xmax = r->width-1;
+               if (xmin <= xmax) {
+                       nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
+               }
+       }
+
+}
+
+/**
+ * In the original software, an function 'static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)' is implemented here.
+ * We removed this function, as our renderer renders the pre-multiplied alpha format directly, so this process is not required.
+ */
+
+
+static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
+{
+       int i, j;
+       NSVGgradient* grad;
+
+       cache->type = paint->type;
+
+       if (paint->type == NSVG_PAINT_COLOR) {
+               cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
+               return;
+       }
+
+       grad = paint->gradient;
+
+       cache->spread = grad->spread;
+       memcpy(cache->xform, grad->xform, sizeof(float)*6);
+
+       if (grad->nstops == 0) {
+               for (i = 0; i < 256; i++)
+                       cache->colors[i] = 0;
+       } if (grad->nstops == 1) {
+               for (i = 0; i < 256; i++)
+                       cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
+       } else {
+               unsigned int ca, cb = 0;
+               float ua, ub, du, u;
+               int ia, ib, count;
+
+               ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
+               ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
+               ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
+               ia = (int)(ua * 255.0f);
+               ib = (int)(ub * 255.0f);
+               for (i = 0; i < ia; i++) {
+                       cache->colors[i] = ca;
+               }
+
+               for (i = 0; i < grad->nstops-1; i++) {
+                       ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
+                       cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
+                       ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
+                       ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
+                       ia = (int)(ua * 255.0f);
+                       ib = (int)(ub * 255.0f);
+                       count = ib - ia;
+                       if (count <= 0) continue;
+                       u = 0;
+                       du = 1.0f / (float)count;
+                       for (j = 0; j < count; j++) {
+                               cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
+                               u += du;
+                       }
+               }
+
+               for (i = ib; i < 256; i++)
+                       cache->colors[i] = cb;
+       }
+
+}
+
+void nsvgRasterize(NSVGrasterizer* r,
+                                  NSVGimage* image, float tx, float ty, float scale,
+                                  unsigned char* dst, int w, int h, int stride)
+{
+       NSVGshape *shape = NULL;
+       NSVGedge *e = NULL;
+       NSVGcachedPaint cache;
+       int i;
+
+       r->bitmap = dst;
+       r->width = w;
+       r->height = h;
+       r->stride = stride;
+
+       if (w > r->cscanline) {
+               r->cscanline = w;
+               r->scanline = (unsigned char*)realloc(r->scanline, w);
+               if (r->scanline == NULL) return;
+       }
+
+       for (i = 0; i < h; i++)
+               memset(&dst[i*stride], 0, w*4);
+
+       for (shape = image->shapes; shape != NULL; shape = shape->next) {
+               if (!(shape->flags & NSVG_FLAGS_VISIBLE))
+                       continue;
+
+               if (shape->fill.type != NSVG_PAINT_NONE) {
+                       nsvg__resetPool(r);
+                       r->freelist = NULL;
+                       r->nedges = 0;
+
+                       nsvg__flattenShape(r, shape, scale);
+
+                       // Scale and translate edges
+                       for (i = 0; i < r->nedges; i++) {
+                               e = &r->edges[i];
+                               e->x0 = tx + e->x0;
+                               e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
+                               e->x1 = tx + e->x1;
+                               e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
+                       }
+
+                       // Rasterize edges
+                       qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
+
+                       // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+                       nsvg__initPaint(&cache, &shape->fill, shape->opacity);
+
+                       nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
+               }
+               if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
+                       nsvg__resetPool(r);
+                       r->freelist = NULL;
+                       r->nedges = 0;
+
+                       nsvg__flattenShapeStroke(r, shape, scale);
+
+//                     dumpEdges(r, "edge.svg");
+
+                       // Scale and translate edges
+                       for (i = 0; i < r->nedges; i++) {
+                               e = &r->edges[i];
+                               e->x0 = tx + e->x0;
+                               e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
+                               e->x1 = tx + e->x1;
+                               e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
+                       }
+
+                       // Rasterize edges
+                       qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
+
+                       // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+                       nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
+
+                       nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
+               }
+       }
+
+    /**
+     * In the original file, the pre-multiplied alpha format is transformed to the convertional non-pre format.
+     * We skip this process here, and render the pre-multiplied alpha format directly in our svg renderer.
+     */
+
+       r->bitmap = NULL;
+       r->width = 0;
+       r->height = 0;
+       r->stride = 0;
+}
diff --git a/dali-toolkit/third-party/nanosvg/nanosvgrast.h b/dali-toolkit/third-party/nanosvg/nanosvgrast.h
new file mode 100644 (file)
index 0000000..4d6ea47
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * The polygon rasterization is heavily based on stb_truetype rasterizer
+ * by Sean Barrett - http://nothings.org/
+ *
+ */
+
+#ifndef NANOSVGRAST_H
+#define NANOSVGRAST_H
+
+#include "nanosvg.h"
+
+typedef struct NSVGrasterizer NSVGrasterizer;
+
+/* Example Usage:
+  // Load SVG
+  NSVGimage* image;
+  image = nsvgParseFromFile("test.svg", "px", 96);
+
+  // Create rasterizer (can be used to render multiple images).
+  struct NSVGrasterizer* rast = nsvgCreateRasterizer();
+  // Allocate memory for image
+  unsigned char* img = malloc(w*h*4);
+  // Rasterize
+  nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
+*/
+
+// Allocated rasterizer context.
+NSVGrasterizer* nsvgCreateRasterizer();
+
+// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
+//   r - pointer to rasterizer context
+//   image - pointer to image to rasterize
+//   tx,ty - image offset (applied after scaling)
+//   scale - image scale
+//   dst - pointer to destination image data, 4 bytes per pixel (RGBA)
+//   w - width of the image to render
+//   h - height of the image to render
+//   stride - number of bytes per scaleline in the destination buffer
+void nsvgRasterize(NSVGrasterizer* r,
+                   NSVGimage* image, float tx, float ty, float scale,
+                   unsigned char* dst, int w, int h, int stride);
+
+// Deletes rasterizer context.
+void nsvgDeleteRasterizer(NSVGrasterizer*);
+
+
+#endif // NANOSVGRAST_H
+
+/**
+ * In the original software, The nanosvgrast implementation was followed here.
+ * We have moved the implementation to nanosvgrast.cc.
+ */
diff --git a/dali-toolkit/third-party/yoga/Utils.cpp b/dali-toolkit/third-party/yoga/Utils.cpp
new file mode 100644 (file)
index 0000000..6fa8df8
--- /dev/null
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "Utils.h"
+
+YGFlexDirection YGFlexDirectionCross(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction) {
+  return YGFlexDirectionIsColumn(flexDirection)
+      ? YGResolveFlexDirection(YGFlexDirectionRow, direction)
+      : YGFlexDirectionColumn;
+}
+
+float YGFloatMax(const float a, const float b) {
+  if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
+    return fmaxf(a, b);
+  }
+  return YGFloatIsUndefined(a) ? b : a;
+}
+
+float YGFloatMin(const float a, const float b) {
+  if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
+    return fminf(a, b);
+  }
+
+  return YGFloatIsUndefined(a) ? b : a;
+}
+
+bool YGValueEqual(const YGValue a, const YGValue b) {
+  if (a.unit != b.unit) {
+    return false;
+  }
+
+  if (a.unit == YGUnitUndefined ||
+      (YGFloatIsUndefined(a.value) && YGFloatIsUndefined(b.value))) {
+    return true;
+  }
+
+  return fabs(a.value - b.value) < 0.0001f;
+}
+
+bool YGFloatsEqual(const float a, const float b) {
+  if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
+    return fabs(a - b) < 0.0001f;
+  }
+  return YGFloatIsUndefined(a) && YGFloatIsUndefined(b);
+}
+
+float YGFloatSanitize(const float& val) {
+  return YGFloatIsUndefined(val) ? 0 : val;
+}
+
+float YGUnwrapFloatOptional(const YGFloatOptional& op) {
+  return op.isUndefined() ? YGUndefined : op.getValue();
+}
+
+YGFloatOptional YGFloatOptionalMax(
+    const YGFloatOptional& op1,
+    const YGFloatOptional& op2) {
+  if (!op1.isUndefined() && !op2.isUndefined()) {
+    return op1.getValue() > op2.getValue() ? op1 : op2;
+  }
+  return op1.isUndefined() ? op2 : op1;
+}
diff --git a/dali-toolkit/third-party/yoga/Utils.h b/dali-toolkit/third-party/yoga/Utils.h
new file mode 100644 (file)
index 0000000..6c95b1e
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include "YGNode.h"
+#include "Yoga-internal.h"
+
+// This struct is an helper model to hold the data for step 4 of flexbox
+// algo, which is collecting the flex items in a line.
+//
+// - itemsOnLine: Number of items which can fit in a line considering the
+// available Inner dimension, the flex items computed flexbasis and their
+// margin. It may be different than the difference between start and end
+// indicates because we skip over absolute-positioned items.
+//
+// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
+// of all the children on the current line. This will be used in order to either
+// set the dimensions of the node if none already exist or to compute the
+// remaining space left for the flexible children.
+//
+// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
+// layed in the current line
+//
+// - totalFlexShrinkFactors: total flex shrink factors of flex items which are
+// to be layed in the current line
+//
+// - endOfLineIndex: Its the end index of the last flex item which was examined
+// and it may or may not be part of the current line(as it may be absolutely
+// positioned or inculding it may have caused to overshoot availableInnerDim)
+//
+// - relativeChildren: Maintain a vector of the child nodes that can shrink
+// and/or grow.
+
+struct YGCollectFlexItemsRowValues {
+  uint32_t itemsOnLine;
+  float sizeConsumedOnCurrentLine;
+  float totalFlexGrowFactors;
+  float totalFlexShrinkScaledFactors;
+  uint32_t endOfLineIndex;
+  std::vector<YGNodeRef> relativeChildren;
+  float remainingFreeSpace;
+  // The size of the mainDim for the row after considering size, padding, margin
+  // and border of flex items. This is used to calculate maxLineDim after going
+  // through all the rows to decide on the main axis size of owner.
+  float mainDim;
+  // The size of the crossDim for the row after considering size, padding,
+  // margin and border of flex items. Used for calculating containers crossSize.
+  float crossDim;
+};
+
+bool YGValueEqual(const YGValue a, const YGValue b);
+
+// This custom float equality function returns true if either absolute
+// difference between two floats is less than 0.0001f or both are undefined.
+bool YGFloatsEqual(const float a, const float b);
+
+// We need custom max function, since we want that, if one argument is
+// YGUndefined then the max funtion should return the other argument as the max
+// value. We wouldn't have needed a custom max function if YGUndefined was NAN
+// as fmax has the same behaviour, but with NAN we cannot use `-ffast-math`
+// compiler flag.
+float YGFloatMax(const float a, const float b);
+
+YGFloatOptional YGFloatOptionalMax(
+    const YGFloatOptional& op1,
+    const YGFloatOptional& op2);
+
+// We need custom min function, since we want that, if one argument is
+// YGUndefined then the min funtion should return the other argument as the min
+// value. We wouldn't have needed a custom min function if YGUndefined was NAN
+// as fmin has the same behaviour, but with NAN we cannot use `-ffast-math`
+// compiler flag.
+float YGFloatMin(const float a, const float b);
+
+// This custom float comparision function compares the array of float with
+// YGFloatsEqual, as the default float comparision operator will not work(Look
+// at the comments of YGFloatsEqual function).
+template <std::size_t size>
+bool YGFloatArrayEqual(
+    const std::array<float, size>& val1,
+    const std::array<float, size>& val2) {
+  bool areEqual = true;
+  for (std::size_t i = 0; i < size && areEqual; ++i) {
+    areEqual = YGFloatsEqual(val1[i], val2[i]);
+  }
+  return areEqual;
+}
+
+// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise
+float YGFloatSanitize(const float& val);
+
+// This function unwraps optional and returns YGUndefined if not defined or
+// op.value otherwise
+// TODO: Get rid off this function
+float YGUnwrapFloatOptional(const YGFloatOptional& op);
+
+YGFlexDirection YGFlexDirectionCross(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction);
+
+inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) {
+  return flexDirection == YGFlexDirectionRow ||
+      flexDirection == YGFlexDirectionRowReverse;
+}
+
+inline YGFloatOptional YGResolveValue(const YGValue value, const float ownerSize) {
+  switch (value.unit) {
+    case YGUnitUndefined:
+    case YGUnitAuto:
+      return YGFloatOptional();
+    case YGUnitPoint:
+      return YGFloatOptional(value.value);
+    case YGUnitPercent:
+      return YGFloatOptional(
+          static_cast<float>(value.value * ownerSize * 0.01));
+  }
+  return YGFloatOptional();
+}
+
+inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
+  return flexDirection == YGFlexDirectionColumn ||
+      flexDirection == YGFlexDirectionColumnReverse;
+}
+
+inline YGFlexDirection YGResolveFlexDirection(
+    const YGFlexDirection flexDirection,
+    const YGDirection direction) {
+  if (direction == YGDirectionRTL) {
+    if (flexDirection == YGFlexDirectionRow) {
+      return YGFlexDirectionRowReverse;
+    } else if (flexDirection == YGFlexDirectionRowReverse) {
+      return YGFlexDirectionRow;
+    }
+  }
+
+  return flexDirection;
+}
+
+static inline YGFloatOptional YGResolveValueMargin(
+    const YGValue value,
+    const float ownerSize) {
+  return value.unit == YGUnitAuto ? YGFloatOptional(0)
+                                  : YGResolveValue(value, ownerSize);
+}
diff --git a/dali-toolkit/third-party/yoga/YGConfig.cpp b/dali-toolkit/third-party/yoga/YGConfig.cpp
new file mode 100644 (file)
index 0000000..5cee527
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGConfig.h"
+
+const std::array<bool, YGExperimentalFeatureCount>
+    kYGDefaultExperimentalFeatures = {{false}};
+
+YGConfig::YGConfig(YGLogger logger)
+    : experimentalFeatures(kYGDefaultExperimentalFeatures),
+      useWebDefaults(false),
+      useLegacyStretchBehaviour(false),
+      shouldDiffLayoutWithoutLegacyStretchBehaviour(false),
+      pointScaleFactor(1.0f), logger(logger), cloneNodeCallback(nullptr),
+      context(nullptr) {}
diff --git a/dali-toolkit/third-party/yoga/YGConfig.h b/dali-toolkit/third-party/yoga/YGConfig.h
new file mode 100644 (file)
index 0000000..0f655d1
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include "Yoga-internal.h"
+#include "Yoga.h"
+
+struct YGConfig {
+  std::array<bool, YGExperimentalFeatureCount> experimentalFeatures;
+  bool useWebDefaults;
+  bool useLegacyStretchBehaviour;
+  bool shouldDiffLayoutWithoutLegacyStretchBehaviour;
+  float pointScaleFactor;
+  YGLogger logger;
+  YGCloneNodeFunc cloneNodeCallback;
+  void* context;
+
+  YGConfig(YGLogger logger);
+};
diff --git a/dali-toolkit/third-party/yoga/YGEnums.cpp b/dali-toolkit/third-party/yoga/YGEnums.cpp
new file mode 100644 (file)
index 0000000..7f16628
--- /dev/null
@@ -0,0 +1,226 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGEnums.h"
+
+const char *YGAlignToString(const YGAlign value){
+  switch(value){
+    case YGAlignAuto:
+      return "auto";
+    case YGAlignFlexStart:
+      return "flex-start";
+    case YGAlignCenter:
+      return "center";
+    case YGAlignFlexEnd:
+      return "flex-end";
+    case YGAlignStretch:
+      return "stretch";
+    case YGAlignBaseline:
+      return "baseline";
+    case YGAlignSpaceBetween:
+      return "space-between";
+    case YGAlignSpaceAround:
+      return "space-around";
+  }
+  return "unknown";
+}
+
+const char *YGDimensionToString(const YGDimension value){
+  switch(value){
+    case YGDimensionWidth:
+      return "width";
+    case YGDimensionHeight:
+      return "height";
+  }
+  return "unknown";
+}
+
+const char *YGDirectionToString(const YGDirection value){
+  switch(value){
+    case YGDirectionInherit:
+      return "inherit";
+    case YGDirectionLTR:
+      return "ltr";
+    case YGDirectionRTL:
+      return "rtl";
+  }
+  return "unknown";
+}
+
+const char *YGDisplayToString(const YGDisplay value){
+  switch(value){
+    case YGDisplayFlex:
+      return "flex";
+    case YGDisplayNone:
+      return "none";
+  }
+  return "unknown";
+}
+
+const char *YGEdgeToString(const YGEdge value){
+  switch(value){
+    case YGEdgeLeft:
+      return "left";
+    case YGEdgeTop:
+      return "top";
+    case YGEdgeRight:
+      return "right";
+    case YGEdgeBottom:
+      return "bottom";
+    case YGEdgeStart:
+      return "start";
+    case YGEdgeEnd:
+      return "end";
+    case YGEdgeHorizontal:
+      return "horizontal";
+    case YGEdgeVertical:
+      return "vertical";
+    case YGEdgeAll:
+      return "all";
+  }
+  return "unknown";
+}
+
+const char *YGExperimentalFeatureToString(const YGExperimentalFeature value){
+  switch(value){
+    case YGExperimentalFeatureWebFlexBasis:
+      return "web-flex-basis";
+  }
+  return "unknown";
+}
+
+const char *YGFlexDirectionToString(const YGFlexDirection value){
+  switch(value){
+    case YGFlexDirectionColumn:
+      return "column";
+    case YGFlexDirectionColumnReverse:
+      return "column-reverse";
+    case YGFlexDirectionRow:
+      return "row";
+    case YGFlexDirectionRowReverse:
+      return "row-reverse";
+  }
+  return "unknown";
+}
+
+const char *YGJustifyToString(const YGJustify value){
+  switch(value){
+    case YGJustifyFlexStart:
+      return "flex-start";
+    case YGJustifyCenter:
+      return "center";
+    case YGJustifyFlexEnd:
+      return "flex-end";
+    case YGJustifySpaceBetween:
+      return "space-between";
+    case YGJustifySpaceAround:
+      return "space-around";
+    case YGJustifySpaceEvenly:
+      return "space-evenly";
+  }
+  return "unknown";
+}
+
+const char *YGLogLevelToString(const YGLogLevel value){
+  switch(value){
+    case YGLogLevelError:
+      return "error";
+    case YGLogLevelWarn:
+      return "warn";
+    case YGLogLevelInfo:
+      return "info";
+    case YGLogLevelDebug:
+      return "debug";
+    case YGLogLevelVerbose:
+      return "verbose";
+    case YGLogLevelFatal:
+      return "fatal";
+  }
+  return "unknown";
+}
+
+const char *YGMeasureModeToString(const YGMeasureMode value){
+  switch(value){
+    case YGMeasureModeUndefined:
+      return "undefined";
+    case YGMeasureModeExactly:
+      return "exactly";
+    case YGMeasureModeAtMost:
+      return "at-most";
+  }
+  return "unknown";
+}
+
+const char *YGNodeTypeToString(const YGNodeType value){
+  switch(value){
+    case YGNodeTypeDefault:
+      return "default";
+    case YGNodeTypeText:
+      return "text";
+  }
+  return "unknown";
+}
+
+const char *YGOverflowToString(const YGOverflow value){
+  switch(value){
+    case YGOverflowVisible:
+      return "visible";
+    case YGOverflowHidden:
+      return "hidden";
+    case YGOverflowScroll:
+      return "scroll";
+  }
+  return "unknown";
+}
+
+const char *YGPositionTypeToString(const YGPositionType value){
+  switch(value){
+    case YGPositionTypeRelative:
+      return "relative";
+    case YGPositionTypeAbsolute:
+      return "absolute";
+  }
+  return "unknown";
+}
+
+const char *YGPrintOptionsToString(const YGPrintOptions value){
+  switch(value){
+    case YGPrintOptionsLayout:
+      return "layout";
+    case YGPrintOptionsStyle:
+      return "style";
+    case YGPrintOptionsChildren:
+      return "children";
+  }
+  return "unknown";
+}
+
+const char *YGUnitToString(const YGUnit value){
+  switch(value){
+    case YGUnitUndefined:
+      return "undefined";
+    case YGUnitPoint:
+      return "point";
+    case YGUnitPercent:
+      return "percent";
+    case YGUnitAuto:
+      return "auto";
+  }
+  return "unknown";
+}
+
+const char *YGWrapToString(const YGWrap value){
+  switch(value){
+    case YGWrapNoWrap:
+      return "no-wrap";
+    case YGWrapWrap:
+      return "wrap";
+    case YGWrapWrapReverse:
+      return "wrap-reverse";
+  }
+  return "unknown";
+}
diff --git a/dali-toolkit/third-party/yoga/YGEnums.h b/dali-toolkit/third-party/yoga/YGEnums.h
new file mode 100644 (file)
index 0000000..0976d78
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+#define YGAlignCount 8
+typedef YG_ENUM_BEGIN(YGAlign) {
+  YGAlignAuto,
+  YGAlignFlexStart,
+  YGAlignCenter,
+  YGAlignFlexEnd,
+  YGAlignStretch,
+  YGAlignBaseline,
+  YGAlignSpaceBetween,
+  YGAlignSpaceAround,
+} YG_ENUM_END(YGAlign);
+WIN_EXPORT const char *YGAlignToString(const YGAlign value);
+
+#define YGDimensionCount 2
+typedef YG_ENUM_BEGIN(YGDimension) {
+  YGDimensionWidth,
+  YGDimensionHeight,
+} YG_ENUM_END(YGDimension);
+WIN_EXPORT const char *YGDimensionToString(const YGDimension value);
+
+#define YGDirectionCount 3
+typedef YG_ENUM_BEGIN(YGDirection) {
+  YGDirectionInherit,
+  YGDirectionLTR,
+  YGDirectionRTL,
+} YG_ENUM_END(YGDirection);
+WIN_EXPORT const char *YGDirectionToString(const YGDirection value);
+
+#define YGDisplayCount 2
+typedef YG_ENUM_BEGIN(YGDisplay) {
+  YGDisplayFlex,
+  YGDisplayNone,
+} YG_ENUM_END(YGDisplay);
+WIN_EXPORT const char *YGDisplayToString(const YGDisplay value);
+
+#define YGEdgeCount 9
+typedef YG_ENUM_BEGIN(YGEdge) {
+  YGEdgeLeft,
+  YGEdgeTop,
+  YGEdgeRight,
+  YGEdgeBottom,
+  YGEdgeStart,
+  YGEdgeEnd,
+  YGEdgeHorizontal,
+  YGEdgeVertical,
+  YGEdgeAll,
+} YG_ENUM_END(YGEdge);
+WIN_EXPORT const char *YGEdgeToString(const YGEdge value);
+
+#define YGExperimentalFeatureCount 1
+typedef YG_ENUM_BEGIN(YGExperimentalFeature) {
+  YGExperimentalFeatureWebFlexBasis,
+} YG_ENUM_END(YGExperimentalFeature);
+WIN_EXPORT const char *YGExperimentalFeatureToString(const YGExperimentalFeature value);
+
+#define YGFlexDirectionCount 4
+typedef YG_ENUM_BEGIN(YGFlexDirection) {
+  YGFlexDirectionColumn,
+  YGFlexDirectionColumnReverse,
+  YGFlexDirectionRow,
+  YGFlexDirectionRowReverse,
+} YG_ENUM_END(YGFlexDirection);
+WIN_EXPORT const char *YGFlexDirectionToString(const YGFlexDirection value);
+
+#define YGJustifyCount 6
+typedef YG_ENUM_BEGIN(YGJustify){
+    YGJustifyFlexStart,
+    YGJustifyCenter,
+    YGJustifyFlexEnd,
+    YGJustifySpaceBetween,
+    YGJustifySpaceAround,
+    YGJustifySpaceEvenly,
+} YG_ENUM_END(YGJustify);
+WIN_EXPORT const char *YGJustifyToString(const YGJustify value);
+
+#define YGLogLevelCount 6
+typedef YG_ENUM_BEGIN(YGLogLevel) {
+  YGLogLevelError,
+  YGLogLevelWarn,
+  YGLogLevelInfo,
+  YGLogLevelDebug,
+  YGLogLevelVerbose,
+  YGLogLevelFatal,
+} YG_ENUM_END(YGLogLevel);
+WIN_EXPORT const char *YGLogLevelToString(const YGLogLevel value);
+
+#define YGMeasureModeCount 3
+typedef YG_ENUM_BEGIN(YGMeasureMode) {
+  YGMeasureModeUndefined,
+  YGMeasureModeExactly,
+  YGMeasureModeAtMost,
+} YG_ENUM_END(YGMeasureMode);
+WIN_EXPORT const char *YGMeasureModeToString(const YGMeasureMode value);
+
+#define YGNodeTypeCount 2
+typedef YG_ENUM_BEGIN(YGNodeType) {
+  YGNodeTypeDefault,
+  YGNodeTypeText,
+} YG_ENUM_END(YGNodeType);
+WIN_EXPORT const char *YGNodeTypeToString(const YGNodeType value);
+
+#define YGOverflowCount 3
+typedef YG_ENUM_BEGIN(YGOverflow) {
+  YGOverflowVisible,
+  YGOverflowHidden,
+  YGOverflowScroll,
+} YG_ENUM_END(YGOverflow);
+WIN_EXPORT const char *YGOverflowToString(const YGOverflow value);
+
+#define YGPositionTypeCount 2
+typedef YG_ENUM_BEGIN(YGPositionType) {
+  YGPositionTypeRelative,
+  YGPositionTypeAbsolute,
+} YG_ENUM_END(YGPositionType);
+WIN_EXPORT const char *YGPositionTypeToString(const YGPositionType value);
+
+#define YGPrintOptionsCount 3
+typedef YG_ENUM_BEGIN(YGPrintOptions) {
+  YGPrintOptionsLayout = 1,
+  YGPrintOptionsStyle = 2,
+  YGPrintOptionsChildren = 4,
+} YG_ENUM_END(YGPrintOptions);
+WIN_EXPORT const char *YGPrintOptionsToString(const YGPrintOptions value);
+
+#define YGUnitCount 4
+typedef YG_ENUM_BEGIN(YGUnit) {
+  YGUnitUndefined,
+  YGUnitPoint,
+  YGUnitPercent,
+  YGUnitAuto,
+} YG_ENUM_END(YGUnit);
+WIN_EXPORT const char *YGUnitToString(const YGUnit value);
+
+#define YGWrapCount 3
+typedef YG_ENUM_BEGIN(YGWrap) {
+  YGWrapNoWrap,
+  YGWrapWrap,
+  YGWrapWrapReverse,
+} YG_ENUM_END(YGWrap);
+WIN_EXPORT const char *YGWrapToString(const YGWrap value);
+
+YG_EXTERN_C_END
diff --git a/dali-toolkit/third-party/yoga/YGFloatOptional.cpp b/dali-toolkit/third-party/yoga/YGFloatOptional.cpp
new file mode 100644 (file)
index 0000000..00bfc71
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGFloatOptional.h"
+#include <cstdlib>
+#include <iostream>
+#include "Yoga.h"
+
+YGFloatOptional::YGFloatOptional(const float& value) {
+  if (YGFloatIsUndefined(value)) {
+    isUndefined_ = true;
+    value_ = 0;
+  } else {
+    value_ = value;
+    isUndefined_ = false;
+  }
+}
+
+YGFloatOptional::YGFloatOptional() : value_(0), isUndefined_(true) {}
+
+const float& YGFloatOptional::getValue() const {
+  if (isUndefined_) {
+    // Abort, accessing a value of an undefined float optional
+    std::cerr << "Tried to get value of an undefined YGFloatOptional\n";
+    std::exit(EXIT_FAILURE);
+  }
+  return value_;
+}
+
+void YGFloatOptional::setValue(const float& val) {
+  value_ = val;
+  isUndefined_ = false;
+}
+
+const bool& YGFloatOptional::isUndefined() const {
+  return isUndefined_;
+}
+
+bool YGFloatOptional::operator==(const YGFloatOptional& op) const {
+  if (isUndefined_ == op.isUndefined()) {
+    return isUndefined_ ? true : value_ == op.getValue();
+  }
+  return false;
+}
+
+bool YGFloatOptional::operator!=(const YGFloatOptional& op) const {
+  return !(*this == op);
+}
+
+bool YGFloatOptional::operator==(const float& val) const {
+  if (YGFloatIsUndefined(val) == isUndefined_) {
+    return isUndefined_ ? true : val == value_;
+  }
+  return false;
+}
+
+bool YGFloatOptional::operator!=(const float& val) const {
+  return !(*this == val);
+}
+
+YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) {
+  if (!isUndefined_ && !op.isUndefined_) {
+    return YGFloatOptional(value_ + op.value_);
+  }
+  return YGFloatOptional();
+}
+
+bool YGFloatOptional::operator>(const YGFloatOptional& op) const {
+  if (isUndefined_ || op.isUndefined_) {
+    return false;
+  }
+  return value_ > op.value_;
+}
+
+bool YGFloatOptional::operator<(const YGFloatOptional& op) const {
+  if (isUndefined_ || op.isUndefined_) {
+    return false;
+  }
+  return value_ < op.value_;
+}
+
+bool YGFloatOptional::operator>=(const YGFloatOptional& op) const {
+  return *this == op ? true : *this > op;
+}
+
+bool YGFloatOptional::operator<=(const YGFloatOptional& op) const {
+  return *this == op ? true : *this < op;
+}
diff --git a/dali-toolkit/third-party/yoga/YGFloatOptional.h b/dali-toolkit/third-party/yoga/YGFloatOptional.h
new file mode 100644 (file)
index 0000000..21af2a8
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+struct YGFloatOptional {
+ private:
+  float value_;
+  bool isUndefined_;
+
+ public:
+  explicit YGFloatOptional(const float& value);
+  explicit YGFloatOptional();
+
+  // Program will terminate if the value of an undefined is accessed. Please
+  // make sure to check if the optional is defined before calling this function.
+  // To check if float optional is defined, use `isUndefined()`.
+  const float& getValue() const;
+
+  // Sets the value of float optional, and thus isUndefined is assigned false.
+  void setValue(const float& val);
+
+  const bool& isUndefined() const;
+
+  YGFloatOptional operator+(const YGFloatOptional& op);
+  bool operator>(const YGFloatOptional& op) const;
+  bool operator<(const YGFloatOptional& op) const;
+  bool operator>=(const YGFloatOptional& op) const;
+  bool operator<=(const YGFloatOptional& op) const;
+  bool operator==(const YGFloatOptional& op) const;
+  bool operator!=(const YGFloatOptional& op) const;
+
+  bool operator==(const float& val) const;
+  bool operator!=(const float& val) const;
+};
diff --git a/dali-toolkit/third-party/yoga/YGLayout.cpp b/dali-toolkit/third-party/yoga/YGLayout.cpp
new file mode 100644 (file)
index 0000000..86eaff5
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGLayout.h"
+#include "Utils.h"
+
+const std::array<float, 2> kYGDefaultDimensionValues = {
+    {YGUndefined, YGUndefined}};
+
+YGLayout::YGLayout()
+    : position(),
+      dimensions(kYGDefaultDimensionValues),
+      margin(),
+      border(),
+      padding(),
+      direction(YGDirectionInherit),
+      computedFlexBasisGeneration(0),
+      computedFlexBasis(YGFloatOptional()),
+      hadOverflow(false),
+      generationCount(0),
+      lastOwnerDirection((YGDirection)-1),
+      nextCachedMeasurementsIndex(0),
+      cachedMeasurements(),
+      measuredDimensions(kYGDefaultDimensionValues),
+      cachedLayout(YGCachedMeasurement()),
+      didUseLegacyFlag(false),
+      doesLegacyStretchFlagAffectsLayout(false) {}
+
+bool YGLayout::operator==(const YGLayout& layout) const {
+  bool isEqual = YGFloatArrayEqual(position, layout.position) &&
+      YGFloatArrayEqual(dimensions, layout.dimensions) &&
+      YGFloatArrayEqual(margin, layout.margin) &&
+      YGFloatArrayEqual(border, layout.border) &&
+      YGFloatArrayEqual(padding, layout.padding) &&
+      direction == layout.direction && hadOverflow == layout.hadOverflow &&
+      lastOwnerDirection == layout.lastOwnerDirection &&
+      nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
+      cachedLayout == layout.cachedLayout &&
+      computedFlexBasis == layout.computedFlexBasis;
+
+  for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
+    isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
+  }
+
+  if (!YGFloatIsUndefined(measuredDimensions[0]) ||
+      !YGFloatIsUndefined(layout.measuredDimensions[0])) {
+    isEqual =
+        isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
+  }
+  if (!YGFloatIsUndefined(measuredDimensions[1]) ||
+      !YGFloatIsUndefined(layout.measuredDimensions[1])) {
+    isEqual =
+        isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
+  }
+
+  return isEqual;
+}
+
+bool YGLayout::operator!=(const YGLayout& layout) const {
+  return !(*this == layout);
+}
diff --git a/dali-toolkit/third-party/yoga/YGLayout.h b/dali-toolkit/third-party/yoga/YGLayout.h
new file mode 100644 (file)
index 0000000..a820746
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include "YGFloatOptional.h"
+#include "Yoga-internal.h"
+
+struct YGLayout {
+  std::array<float, 4> position;
+  std::array<float, 2> dimensions;
+  std::array<float, 6> margin;
+  std::array<float, 6> border;
+  std::array<float, 6> padding;
+  YGDirection direction;
+
+  uint32_t computedFlexBasisGeneration;
+  YGFloatOptional computedFlexBasis;
+  bool hadOverflow;
+
+  // Instead of recomputing the entire layout every single time, we
+  // cache some information to break early when nothing changed
+  uint32_t generationCount;
+  YGDirection lastOwnerDirection;
+
+  uint32_t nextCachedMeasurementsIndex;
+  std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
+      cachedMeasurements;
+  std::array<float, 2> measuredDimensions;
+
+  YGCachedMeasurement cachedLayout;
+  bool didUseLegacyFlag;
+  bool doesLegacyStretchFlagAffectsLayout;
+
+  YGLayout();
+
+  bool operator==(const YGLayout& layout) const;
+  bool operator!=(const YGLayout& layout) const;
+};
diff --git a/dali-toolkit/third-party/yoga/YGMacros.h b/dali-toolkit/third-party/yoga/YGMacros.h
new file mode 100644 (file)
index 0000000..15ed81d
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+#define YG_EXTERN_C_BEGIN extern "C" {
+#define YG_EXTERN_C_END }
+#else
+#define YG_EXTERN_C_BEGIN
+#define YG_EXTERN_C_END
+#endif
+
+#ifdef _WINDLL
+#define WIN_EXPORT __declspec(dllexport)
+#else
+#define WIN_EXPORT
+#endif
+
+#ifdef WINARMDLL
+#define WIN_STRUCT(type) type *
+#define WIN_STRUCT_REF(value) &value
+#else
+#define WIN_STRUCT(type) type
+#define WIN_STRUCT_REF(value) value
+#endif
+
+#ifdef NS_ENUM
+// Cannot use NSInteger as NSInteger has a different size than int (which is the default type of a
+// enum).
+// Therefor when linking the Yoga C library into obj-c the header is a missmatch for the Yoga ABI.
+#define YG_ENUM_BEGIN(name) NS_ENUM(int, name)
+#define YG_ENUM_END(name)
+#else
+#define YG_ENUM_BEGIN(name) enum name
+#define YG_ENUM_END(name) name
+#endif
diff --git a/dali-toolkit/third-party/yoga/YGNode.cpp b/dali-toolkit/third-party/yoga/YGNode.cpp
new file mode 100644 (file)
index 0000000..6ebc69c
--- /dev/null
@@ -0,0 +1,768 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGNode.h"
+#include <iostream>
+#include "Utils.h"
+
+void* YGNode::getContext() const {
+  return context_;
+}
+
+YGPrintFunc YGNode::getPrintFunc() const {
+  return print_;
+}
+
+bool YGNode::getHasNewLayout() const {
+  return hasNewLayout_;
+}
+
+YGNodeType YGNode::getNodeType() const {
+  return nodeType_;
+}
+
+YGMeasureFunc YGNode::getMeasure() const {
+  return measure_;
+}
+
+YGBaselineFunc YGNode::getBaseline() const {
+  return baseline_;
+}
+
+YGDirtiedFunc YGNode::getDirtied() const {
+  return dirtied_;
+}
+
+YGStyle& YGNode::getStyle() {
+  return style_;
+}
+
+YGLayout& YGNode::getLayout() {
+  return layout_;
+}
+
+uint32_t YGNode::getLineIndex() const {
+  return lineIndex_;
+}
+
+YGNodeRef YGNode::getOwner() const {
+  return owner_;
+}
+
+YGVector YGNode::getChildren() const {
+  return children_;
+}
+
+uint32_t YGNode::getChildrenCount() const {
+  return static_cast<uint32_t>(children_.size());
+}
+
+YGNodeRef YGNode::getChild(uint32_t index) const {
+  return children_.at(index);
+}
+
+YGNodeRef YGNode::getNextChild() const {
+  return nextChild_;
+}
+
+YGConfigRef YGNode::getConfig() const {
+  return config_;
+}
+
+bool YGNode::isDirty() const {
+  return isDirty_;
+}
+
+YGValue YGNode::getResolvedDimension(int index) {
+  return resolvedDimensions_[index];
+}
+
+std::array<YGValue, 2> YGNode::getResolvedDimensions() const {
+  return resolvedDimensions_;
+}
+
+YGFloatOptional YGNode::getLeadingPosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (YGFlexDirectionIsRow(axis)) {
+    const YGValue* leadingPosition =
+        YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
+    if (leadingPosition->unit != YGUnitUndefined) {
+      return YGResolveValue(*leadingPosition, axisSize);
+    }
+  }
+
+  const YGValue* leadingPosition =
+      YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined);
+
+  return leadingPosition->unit == YGUnitUndefined
+      ? YGFloatOptional(0)
+      : YGResolveValue(*leadingPosition, axisSize);
+}
+
+YGFloatOptional YGNode::getTrailingPosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (YGFlexDirectionIsRow(axis)) {
+    const YGValue* trailingPosition =
+        YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
+    if (trailingPosition->unit != YGUnitUndefined) {
+      return YGResolveValue(*trailingPosition, axisSize);
+    }
+  }
+
+  const YGValue* trailingPosition =
+      YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined);
+
+  return trailingPosition->unit == YGUnitUndefined
+      ? YGFloatOptional(0)
+      : YGResolveValue(*trailingPosition, axisSize);
+}
+
+bool YGNode::isLeadingPositionDefined(const YGFlexDirection& axis) const {
+  return (YGFlexDirectionIsRow(axis) &&
+          YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
+                  ->unit != YGUnitUndefined) ||
+      YGComputedEdgeValue(style_.position, leading[axis], &YGValueUndefined)
+          ->unit != YGUnitUndefined;
+}
+
+bool YGNode::isTrailingPosDefined(const YGFlexDirection& axis) const {
+  return (YGFlexDirectionIsRow(axis) &&
+          YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
+                  ->unit != YGUnitUndefined) ||
+      YGComputedEdgeValue(style_.position, trailing[axis], &YGValueUndefined)
+          ->unit != YGUnitUndefined;
+}
+
+YGFloatOptional YGNode::getLeadingMargin(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+    return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
+  }
+
+  return YGResolveValueMargin(
+      *YGComputedEdgeValue(style_.margin, leading[axis], &YGValueZero),
+      widthSize);
+}
+
+YGFloatOptional YGNode::getTrailingMargin(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+    return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
+  }
+
+  return YGResolveValueMargin(
+      *YGComputedEdgeValue(style_.margin, trailing[axis], &YGValueZero),
+      widthSize);
+}
+
+YGFloatOptional YGNode::getMarginForAxis(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
+}
+
+// Setters
+
+void YGNode::setContext(void* context) {
+  context_ = context;
+}
+
+void YGNode::setPrintFunc(YGPrintFunc printFunc) {
+  print_ = printFunc;
+}
+
+void YGNode::setHasNewLayout(bool hasNewLayout) {
+  hasNewLayout_ = hasNewLayout;
+}
+
+void YGNode::setNodeType(YGNodeType nodeType) {
+  nodeType_ = nodeType;
+}
+
+void YGNode::setStyleFlexDirection(YGFlexDirection direction) {
+  style_.flexDirection = direction;
+}
+
+void YGNode::setStyleAlignContent(YGAlign alignContent) {
+  style_.alignContent = alignContent;
+}
+
+void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
+  if (measureFunc == nullptr) {
+    measure_ = nullptr;
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    nodeType_ = YGNodeTypeDefault;
+  } else {
+    YGAssertWithNode(
+        this,
+        children_.size() == 0,
+        "Cannot set measure function: Nodes with measure functions cannot have children.");
+    measure_ = measureFunc;
+    // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
+    // places in Litho
+    setNodeType(YGNodeTypeText);
+  }
+
+  measure_ = measureFunc;
+}
+
+void YGNode::setBaseLineFunc(YGBaselineFunc baseLineFunc) {
+  baseline_ = baseLineFunc;
+}
+
+void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
+  dirtied_ = dirtiedFunc;
+}
+
+void YGNode::setStyle(const YGStyle& style) {
+  style_ = style;
+}
+
+void YGNode::setLayout(const YGLayout& layout) {
+  layout_ = layout;
+}
+
+void YGNode::setLineIndex(uint32_t lineIndex) {
+  lineIndex_ = lineIndex;
+}
+
+void YGNode::setOwner(YGNodeRef owner) {
+  owner_ = owner;
+}
+
+void YGNode::setChildren(const YGVector& children) {
+  children_ = children;
+}
+
+void YGNode::setNextChild(YGNodeRef nextChild) {
+  nextChild_ = nextChild;
+}
+
+void YGNode::replaceChild(YGNodeRef child, uint32_t index) {
+  children_[index] = child;
+}
+
+void YGNode::replaceChild(YGNodeRef oldChild, YGNodeRef newChild) {
+  std::replace(children_.begin(), children_.end(), oldChild, newChild);
+}
+
+void YGNode::insertChild(YGNodeRef child, uint32_t index) {
+  children_.insert(children_.begin() + index, child);
+}
+
+void YGNode::setConfig(YGConfigRef config) {
+  config_ = config;
+}
+
+void YGNode::setDirty(bool isDirty) {
+  if (isDirty == isDirty_) {
+    return;
+  }
+  isDirty_ = isDirty;
+  if (isDirty && dirtied_) {
+    dirtied_(this);
+  }
+}
+
+bool YGNode::removeChild(YGNodeRef child) {
+  std::vector<YGNodeRef>::iterator p =
+      std::find(children_.begin(), children_.end(), child);
+  if (p != children_.end()) {
+    children_.erase(p);
+    return true;
+  }
+  return false;
+}
+
+void YGNode::removeChild(uint32_t index) {
+  children_.erase(children_.begin() + index);
+}
+
+void YGNode::setLayoutDirection(YGDirection direction) {
+  layout_.direction = direction;
+}
+
+void YGNode::setLayoutMargin(float margin, int index) {
+  layout_.margin[index] = margin;
+}
+
+void YGNode::setLayoutBorder(float border, int index) {
+  layout_.border[index] = border;
+}
+
+void YGNode::setLayoutPadding(float padding, int index) {
+  layout_.padding[index] = padding;
+}
+
+void YGNode::setLayoutLastOwnerDirection(YGDirection direction) {
+  layout_.lastOwnerDirection = direction;
+}
+
+void YGNode::setLayoutComputedFlexBasis(
+    const YGFloatOptional& computedFlexBasis) {
+  layout_.computedFlexBasis = computedFlexBasis;
+}
+
+void YGNode::setLayoutPosition(float position, int index) {
+  layout_.position[index] = position;
+}
+
+void YGNode::setLayoutComputedFlexBasisGeneration(
+    uint32_t computedFlexBasisGeneration) {
+  layout_.computedFlexBasisGeneration = computedFlexBasisGeneration;
+}
+
+void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
+  layout_.measuredDimensions[index] = measuredDimension;
+}
+
+void YGNode::setLayoutHadOverflow(bool hadOverflow) {
+  layout_.hadOverflow = hadOverflow;
+}
+
+void YGNode::setLayoutDimension(float dimension, int index) {
+  layout_.dimensions[index] = dimension;
+}
+
+// If both left and right are defined, then use left. Otherwise return
+// +left or -right depending on which is defined.
+YGFloatOptional YGNode::relativePosition(
+    const YGFlexDirection& axis,
+    const float& axisSize) const {
+  if (isLeadingPositionDefined(axis)) {
+    return getLeadingPosition(axis, axisSize);
+  }
+
+  YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize);
+  if (!trailingPosition.isUndefined()) {
+    trailingPosition.setValue(-1 * trailingPosition.getValue());
+  }
+  return trailingPosition;
+}
+
+void YGNode::setPosition(
+    const YGDirection direction,
+    const float mainSize,
+    const float crossSize,
+    const float ownerWidth) {
+  /* Root nodes should be always layouted as LTR, so we don't return negative
+   * values. */
+  const YGDirection directionRespectingRoot =
+      owner_ != nullptr ? direction : YGDirectionLTR;
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(style_.flexDirection, directionRespectingRoot);
+  const YGFlexDirection crossAxis =
+      YGFlexDirectionCross(mainAxis, directionRespectingRoot);
+
+  const YGFloatOptional relativePositionMain =
+      relativePosition(mainAxis, mainSize);
+  const YGFloatOptional relativePositionCross =
+      relativePosition(crossAxis, crossSize);
+
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain),
+      leading[mainAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain),
+      trailing[mainAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross),
+      leading[crossAxis]);
+  setLayoutPosition(
+      YGUnwrapFloatOptional(
+          getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross),
+      trailing[crossAxis]);
+}
+
+YGNode::YGNode()
+    : context_(nullptr),
+      print_(nullptr),
+      hasNewLayout_(true),
+      nodeType_(YGNodeTypeDefault),
+      measure_(nullptr),
+      baseline_(nullptr),
+      dirtied_(nullptr),
+      style_(YGStyle()),
+      layout_(YGLayout()),
+      lineIndex_(0),
+      owner_(nullptr),
+      children_(YGVector()),
+      nextChild_(nullptr),
+      config_(nullptr),
+      isDirty_(false),
+      resolvedDimensions_({{YGValueUndefined, YGValueUndefined}}) {}
+
+YGNode::YGNode(const YGNode& node)
+    : context_(node.context_),
+      print_(node.print_),
+      hasNewLayout_(node.hasNewLayout_),
+      nodeType_(node.nodeType_),
+      measure_(node.measure_),
+      baseline_(node.baseline_),
+      dirtied_(node.dirtied_),
+      style_(node.style_),
+      layout_(node.layout_),
+      lineIndex_(node.lineIndex_),
+      owner_(node.owner_),
+      children_(node.children_),
+      nextChild_(node.nextChild_),
+      config_(node.config_),
+      isDirty_(node.isDirty_),
+      resolvedDimensions_(node.resolvedDimensions_) {}
+
+YGNode::YGNode(const YGConfigRef newConfig) : YGNode() {
+  config_ = newConfig;
+}
+
+YGNode::YGNode(
+    void* context,
+    YGPrintFunc print,
+    bool hasNewLayout,
+    YGNodeType nodeType,
+    YGMeasureFunc measure,
+    YGBaselineFunc baseline,
+    YGDirtiedFunc dirtied,
+    const YGStyle& style,
+    const YGLayout& layout,
+    uint32_t lineIndex,
+    YGNodeRef owner,
+    const YGVector& children,
+    YGNodeRef nextChild,
+    YGConfigRef config,
+    bool isDirty,
+    std::array<YGValue, 2> resolvedDimensions)
+    : context_(context),
+      print_(print),
+      hasNewLayout_(hasNewLayout),
+      nodeType_(nodeType),
+      measure_(measure),
+      baseline_(baseline),
+      dirtied_(dirtied),
+      style_(style),
+      layout_(layout),
+      lineIndex_(lineIndex),
+      owner_(owner),
+      children_(children),
+      nextChild_(nextChild),
+      config_(config),
+      isDirty_(isDirty),
+      resolvedDimensions_(resolvedDimensions) {}
+
+YGNode& YGNode::operator=(const YGNode& node) {
+  if (&node == this) {
+    return *this;
+  }
+
+  for (auto child : children_) {
+    delete child;
+  }
+
+  context_ = node.getContext();
+  print_ = node.getPrintFunc();
+  hasNewLayout_ = node.getHasNewLayout();
+  nodeType_ = node.getNodeType();
+  measure_ = node.getMeasure();
+  baseline_ = node.getBaseline();
+  dirtied_ = node.getDirtied();
+  style_ = node.style_;
+  layout_ = node.layout_;
+  lineIndex_ = node.getLineIndex();
+  owner_ = node.getOwner();
+  children_ = node.getChildren();
+  nextChild_ = node.getNextChild();
+  config_ = node.getConfig();
+  isDirty_ = node.isDirty();
+  resolvedDimensions_ = node.getResolvedDimensions();
+
+  return *this;
+}
+
+YGValue YGNode::marginLeadingValue(const YGFlexDirection axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
+    return style_.margin[YGEdgeStart];
+  } else {
+    return style_.margin[leading[axis]];
+  }
+}
+
+YGValue YGNode::marginTrailingValue(const YGFlexDirection axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
+    return style_.margin[YGEdgeEnd];
+  } else {
+    return style_.margin[trailing[axis]];
+  }
+}
+
+YGValue YGNode::resolveFlexBasisPtr() const {
+  YGValue flexBasis = style_.flexBasis;
+  if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
+    return flexBasis;
+  }
+  if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
+    return config_->useWebDefaults ? YGValueAuto : YGValueZero;
+  }
+  return YGValueAuto;
+}
+
+void YGNode::resolveDimension() {
+  for (uint32_t dim = YGDimensionWidth; dim < YGDimensionCount; dim++) {
+    if (getStyle().maxDimensions[dim].unit != YGUnitUndefined &&
+        YGValueEqual(
+            getStyle().maxDimensions[dim], style_.minDimensions[dim])) {
+      resolvedDimensions_[dim] = style_.maxDimensions[dim];
+    } else {
+      resolvedDimensions_[dim] = style_.dimensions[dim];
+    }
+  }
+}
+
+YGDirection YGNode::resolveDirection(const YGDirection ownerDirection) {
+  if (style_.direction == YGDirectionInherit) {
+    return ownerDirection > YGDirectionInherit ? ownerDirection
+                                                : YGDirectionLTR;
+  } else {
+    return style_.direction;
+  }
+}
+
+void YGNode::clearChildren() {
+  children_.clear();
+  children_.shrink_to_fit();
+}
+
+YGNode::~YGNode() {
+  // All the member variables are deallocated externally, so no need to
+  // deallocate here
+}
+
+// Other Methods
+
+void YGNode::cloneChildrenIfNeeded() {
+  // YGNodeRemoveChild in yoga.cpp has a forked variant of this algorithm
+  // optimized for deletions.
+
+  const uint32_t childCount = static_cast<uint32_t>(children_.size());
+  if (childCount == 0) {
+    // This is an empty set. Nothing to clone.
+    return;
+  }
+
+  const YGNodeRef firstChild = children_.front();
+  if (firstChild->getOwner() == this) {
+    // If the first child has this node as its owner, we assume that it is
+    // already unique. We can do this because if we have it has a child, that
+    // means that its owner was at some point cloned which made that subtree
+    // immutable. We also assume that all its sibling are cloned as well.
+    return;
+  }
+
+  const YGCloneNodeFunc cloneNodeCallback = config_->cloneNodeCallback;
+  for (uint32_t i = 0; i < childCount; ++i) {
+    const YGNodeRef oldChild = children_[i];
+    YGNodeRef newChild = nullptr;
+    if (cloneNodeCallback) {
+      newChild = cloneNodeCallback(oldChild, this, i);
+    }
+    if (newChild == nullptr) {
+      newChild = YGNodeClone(oldChild);
+    }
+    replaceChild(newChild, i);
+    newChild->setOwner(this);
+  }
+}
+
+void YGNode::markDirtyAndPropogate() {
+  if (!isDirty_) {
+    setDirty(true);
+    setLayoutComputedFlexBasis(YGFloatOptional());
+    if (owner_) {
+      owner_->markDirtyAndPropogate();
+    }
+  }
+}
+
+void YGNode::markDirtyAndPropogateDownwards() {
+  isDirty_ = true;
+  for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
+    childNode->markDirtyAndPropogateDownwards();
+  });
+}
+
+float YGNode::resolveFlexGrow() {
+  // Root nodes flexGrow should always be 0
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (!style_.flexGrow.isUndefined()) {
+    return style_.flexGrow.getValue();
+  }
+  if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
+    return style_.flex.getValue();
+  }
+  return kDefaultFlexGrow;
+}
+
+float YGNode::resolveFlexShrink() {
+  if (owner_ == nullptr) {
+    return 0.0;
+  }
+  if (!style_.flexShrink.isUndefined()) {
+    return style_.flexShrink.getValue();
+  }
+  if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
+      style_.flex.getValue() < 0.0f) {
+    return -style_.flex.getValue();
+  }
+  return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
+}
+
+bool YGNode::isNodeFlexible() {
+  return (
+      (style_.positionType == YGPositionTypeRelative) &&
+      (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
+}
+
+float YGNode::getLeadingBorder(const YGFlexDirection& axis) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.border[YGEdgeStart].unit != YGUnitUndefined &&
+      !YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
+      style_.border[YGEdgeStart].value >= 0.0f) {
+    return style_.border[YGEdgeStart].value;
+  }
+
+  float computedEdgeValue =
+      YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
+  return YGFloatMax(computedEdgeValue, 0.0f);
+}
+
+float YGNode::getTrailingBorder(const YGFlexDirection& flexDirection) const {
+  if (YGFlexDirectionIsRow(flexDirection) &&
+      style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
+      !YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
+      style_.border[YGEdgeEnd].value >= 0.0f) {
+    return style_.border[YGEdgeEnd].value;
+  }
+
+  float computedEdgeValue =
+      YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
+          ->value;
+  return YGFloatMax(computedEdgeValue, 0.0f);
+}
+
+YGFloatOptional YGNode::getLeadingPadding(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  const YGFloatOptional& paddingEdgeStart =
+      YGResolveValue(style_.padding[YGEdgeStart], widthSize);
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
+      !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() > 0.0f) {
+    return paddingEdgeStart;
+  }
+
+  YGFloatOptional resolvedValue = YGResolveValue(
+      *YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
+      widthSize);
+  return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
+}
+
+YGFloatOptional YGNode::getTrailingPadding(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  if (YGFlexDirectionIsRow(axis) &&
+      style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
+      !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
+      YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) {
+    return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
+  }
+
+  YGFloatOptional resolvedValue = YGResolveValue(
+      *YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
+      widthSize);
+
+  return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
+}
+
+YGFloatOptional YGNode::getLeadingPaddingAndBorder(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getLeadingPadding(axis, widthSize) +
+      YGFloatOptional(getLeadingBorder(axis));
+}
+
+YGFloatOptional YGNode::getTrailingPaddingAndBorder(
+    const YGFlexDirection& axis,
+    const float& widthSize) const {
+  return getTrailingPadding(axis, widthSize) +
+      YGFloatOptional(getTrailingBorder(axis));
+}
+
+bool YGNode::didUseLegacyFlag() {
+  bool didUseLegacyFlag = layout_.didUseLegacyFlag;
+  if (didUseLegacyFlag) {
+    return true;
+  }
+  for (const auto& child : children_) {
+    if (child->layout_.didUseLegacyFlag) {
+      didUseLegacyFlag = true;
+      break;
+    }
+  }
+  return didUseLegacyFlag;
+}
+
+void YGNode::setAndPropogateUseLegacyFlag(bool useLegacyFlag) {
+  config_->useLegacyStretchBehaviour = useLegacyFlag;
+  for_each(children_.begin(), children_.end(), [=](YGNodeRef childNode) {
+    childNode->getConfig()->useLegacyStretchBehaviour = useLegacyFlag;
+  });
+}
+
+void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
+    bool doesLegacyFlagAffectsLayout) {
+  layout_.doesLegacyStretchFlagAffectsLayout = doesLegacyFlagAffectsLayout;
+}
+
+void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
+  layout_.didUseLegacyFlag = didUseLegacyFlag;
+}
+
+bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
+  if (children_.size() != node.children_.size()) {
+    return false;
+  }
+  if (layout_ != node.layout_) {
+    return false;
+  }
+  if (children_.size() == 0) {
+    return true;
+  }
+
+  bool isLayoutTreeEqual = true;
+  YGNodeRef otherNodeChildren = nullptr;
+  for (std::vector<YGNodeRef>::size_type i = 0; i < children_.size(); ++i) {
+    otherNodeChildren = node.children_[i];
+    isLayoutTreeEqual =
+        children_[i]->isLayoutTreeEqualToNode(*otherNodeChildren);
+    if (!isLayoutTreeEqual) {
+      return false;
+    }
+  }
+  return isLayoutTreeEqual;
+}
diff --git a/dali-toolkit/third-party/yoga/YGNode.h b/dali-toolkit/third-party/yoga/YGNode.h
new file mode 100644 (file)
index 0000000..186798b
--- /dev/null
@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include <stdio.h>
+#include "YGConfig.h"
+#include "YGLayout.h"
+#include "YGStyle.h"
+#include "Yoga-internal.h"
+
+struct YGNode {
+ private:
+  void* context_;
+  YGPrintFunc print_;
+  bool hasNewLayout_;
+  YGNodeType nodeType_;
+  YGMeasureFunc measure_;
+  YGBaselineFunc baseline_;
+  YGDirtiedFunc dirtied_;
+  YGStyle style_;
+  YGLayout layout_;
+  uint32_t lineIndex_;
+  YGNodeRef owner_;
+  YGVector children_;
+  YGNodeRef nextChild_;
+  YGConfigRef config_;
+  bool isDirty_;
+  std::array<YGValue, 2> resolvedDimensions_;
+
+  YGFloatOptional relativePosition(
+      const YGFlexDirection& axis,
+      const float& axisSize) const;
+
+ public:
+  YGNode();
+  ~YGNode();
+  explicit YGNode(const YGConfigRef newConfig);
+  YGNode(const YGNode& node);
+  YGNode& operator=(const YGNode& node);
+  YGNode(
+      void* context,
+      YGPrintFunc print,
+      bool hasNewLayout,
+      YGNodeType nodeType,
+      YGMeasureFunc measure,
+      YGBaselineFunc baseline,
+      YGDirtiedFunc dirtied,
+      const YGStyle& style,
+      const YGLayout& layout,
+      uint32_t lineIndex,
+      YGNodeRef owner,
+      const YGVector& children,
+      YGNodeRef nextChild,
+      YGConfigRef config,
+      bool isDirty,
+      std::array<YGValue, 2> resolvedDimensions);
+
+  // Getters
+  void* getContext() const;
+  YGPrintFunc getPrintFunc() const;
+  bool getHasNewLayout() const;
+  YGNodeType getNodeType() const;
+  YGMeasureFunc getMeasure() const;
+  YGBaselineFunc getBaseline() const;
+  YGDirtiedFunc getDirtied() const;
+  // For Performance reasons passing as reference.
+  YGStyle& getStyle();
+  // For Performance reasons passing as reference.
+  YGLayout& getLayout();
+  uint32_t getLineIndex() const;
+  // returns the YGNodeRef that owns this YGNode. An owner is used to identify
+  // the YogaTree that a YGNode belongs to.
+  // This method will return the parent of the YGNode when a YGNode only belongs
+  // to one YogaTree or nullptr when the YGNode is shared between two or more
+  // YogaTrees.
+  YGNodeRef getOwner() const;
+  YGVector getChildren() const;
+  uint32_t getChildrenCount() const;
+  YGNodeRef getChild(uint32_t index) const;
+  YGNodeRef getNextChild() const;
+  YGConfigRef getConfig() const;
+  bool isDirty() const;
+  std::array<YGValue, 2> getResolvedDimensions() const;
+  YGValue getResolvedDimension(int index);
+
+  // Methods related to positions, margin, padding and border
+  YGFloatOptional getLeadingPosition(const YGFlexDirection& axis,
+      const float& axisSize) const;
+  bool isLeadingPositionDefined(const YGFlexDirection& axis) const;
+  bool isTrailingPosDefined(const YGFlexDirection& axis) const;
+  YGFloatOptional getTrailingPosition(
+      const YGFlexDirection& axis,
+      const float& axisSize) const;
+  YGFloatOptional getLeadingMargin(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingMargin(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  float getLeadingBorder(const YGFlexDirection& flexDirection) const;
+  float getTrailingBorder(const YGFlexDirection& flexDirection) const;
+  YGFloatOptional getLeadingPadding(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingPadding(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getLeadingPaddingAndBorder(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getTrailingPaddingAndBorder(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  YGFloatOptional getMarginForAxis(
+      const YGFlexDirection& axis,
+      const float& widthSize) const;
+  // Setters
+
+  void setContext(void* context);
+  void setPrintFunc(YGPrintFunc printFunc);
+  void setHasNewLayout(bool hasNewLayout);
+  void setNodeType(YGNodeType nodeTye);
+  void setMeasureFunc(YGMeasureFunc measureFunc);
+  void setBaseLineFunc(YGBaselineFunc baseLineFunc);
+  void setDirtiedFunc(YGDirtiedFunc dirtiedFunc);
+  void setStyle(const YGStyle& style);
+  void setStyleFlexDirection(YGFlexDirection direction);
+  void setStyleAlignContent(YGAlign alignContent);
+  void setLayout(const YGLayout& layout);
+  void setLineIndex(uint32_t lineIndex);
+  void setOwner(YGNodeRef owner);
+  void setChildren(const YGVector& children);
+  void setNextChild(YGNodeRef nextChild);
+  void setConfig(YGConfigRef config);
+  void setDirty(bool isDirty);
+  void setLayoutLastOwnerDirection(YGDirection direction);
+  void setLayoutComputedFlexBasis(const YGFloatOptional& computedFlexBasis);
+  void setLayoutComputedFlexBasisGeneration(
+      uint32_t computedFlexBasisGeneration);
+  void setLayoutMeasuredDimension(float measuredDimension, int index);
+  void setLayoutHadOverflow(bool hadOverflow);
+  void setLayoutDimension(float dimension, int index);
+  void setLayoutDirection(YGDirection direction);
+  void setLayoutMargin(float margin, int index);
+  void setLayoutBorder(float border, int index);
+  void setLayoutPadding(float padding, int index);
+  void setLayoutPosition(float position, int index);
+  void setPosition(
+      const YGDirection direction,
+      const float mainSize,
+      const float crossSize,
+      const float ownerWidth);
+  void setAndPropogateUseLegacyFlag(bool useLegacyFlag);
+  void setLayoutDoesLegacyFlagAffectsLayout(bool doesLegacyFlagAffectsLayout);
+  void setLayoutDidUseLegacyFlag(bool didUseLegacyFlag);
+  void markDirtyAndPropogateDownwards();
+
+  // Other methods
+  YGValue marginLeadingValue(const YGFlexDirection axis) const;
+  YGValue marginTrailingValue(const YGFlexDirection axis) const;
+  YGValue resolveFlexBasisPtr() const;
+  void resolveDimension();
+  YGDirection resolveDirection(const YGDirection ownerDirection);
+  void clearChildren();
+  /// Replaces the occurrences of oldChild with newChild
+  void replaceChild(YGNodeRef oldChild, YGNodeRef newChild);
+  void replaceChild(YGNodeRef child, uint32_t index);
+  void insertChild(YGNodeRef child, uint32_t index);
+  /// Removes the first occurrence of child
+  bool removeChild(YGNodeRef child);
+  void removeChild(uint32_t index);
+
+  void cloneChildrenIfNeeded();
+  void markDirtyAndPropogate();
+  float resolveFlexGrow();
+  float resolveFlexShrink();
+  bool isNodeFlexible();
+  bool didUseLegacyFlag();
+  bool isLayoutTreeEqualToNode(const YGNode& node) const;
+};
diff --git a/dali-toolkit/third-party/yoga/YGNodePrint.cpp b/dali-toolkit/third-party/yoga/YGNodePrint.cpp
new file mode 100644 (file)
index 0000000..ab3aa7c
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2017-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGNodePrint.h"
+#include <stdarg.h>
+#include "YGEnums.h"
+#include "YGNode.h"
+#include "Yoga-internal.h"
+
+namespace facebook {
+namespace yoga {
+typedef std::string string;
+
+static void indent(string* base, uint32_t level) {
+  for (uint32_t i = 0; i < level; ++i) {
+    base->append("  ");
+  }
+}
+
+static bool areFourValuesEqual(const std::array<YGValue, YGEdgeCount>& four) {
+  return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) &&
+      YGValueEqual(four[0], four[3]);
+}
+
+static void appendFormatedString(string* str, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  va_list argsCopy;
+  va_copy(argsCopy, args);
+  std::vector<char> buf(1 + vsnprintf(NULL, 0, fmt, args));
+  va_end(args);
+  vsnprintf(buf.data(), buf.size(), fmt, argsCopy);
+  va_end(argsCopy);
+  string result = string(buf.begin(), buf.end() - 1);
+  str->append(result);
+}
+
+static void appendFloatOptionalIfDefined(
+    string* base,
+    const string key,
+    const YGFloatOptional num) {
+  if (!num.isUndefined()) {
+    appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue());
+  }
+}
+
+static void appendNumberIfNotUndefined(
+    string* base,
+    const string key,
+    const YGValue number) {
+  if (number.unit != YGUnitUndefined) {
+    if (number.unit == YGUnitAuto) {
+      base->append(key + ": auto; ");
+    } else {
+      string unit = number.unit == YGUnitPoint ? "px" : "%%";
+      appendFormatedString(
+          base, "%s: %g%s; ", key.c_str(), number.value, unit.c_str());
+    }
+  }
+}
+
+static void
+appendNumberIfNotAuto(string* base, const string& key, const YGValue number) {
+  if (number.unit != YGUnitAuto) {
+    appendNumberIfNotUndefined(base, key, number);
+  }
+}
+
+static void
+appendNumberIfNotZero(string* base, const string& str, const YGValue number) {
+
+  if (number.unit == YGUnitAuto) {
+    base->append(str + ": auto; ");
+  } else if (!YGFloatsEqual(number.value, 0)) {
+    appendNumberIfNotUndefined(base, str, number);
+  }
+}
+
+static void appendEdges(
+    string* base,
+    const string& key,
+    const std::array<YGValue, YGEdgeCount>& edges) {
+  if (areFourValuesEqual(edges)) {
+    appendNumberIfNotZero(base, key, edges[YGEdgeLeft]);
+  } else {
+    for (int edge = YGEdgeLeft; edge != YGEdgeAll; ++edge) {
+      string str = key + "-" + YGEdgeToString(static_cast<YGEdge>(edge));
+      appendNumberIfNotZero(base, str, edges[edge]);
+    }
+  }
+}
+
+static void appendEdgeIfNotUndefined(
+    string* base,
+    const string& str,
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge) {
+  appendNumberIfNotUndefined(
+      base, str, *YGComputedEdgeValue(edges, edge, &YGValueUndefined));
+}
+
+void YGNodeToString(
+    std::string* str,
+    YGNodeRef node,
+    YGPrintOptions options,
+    uint32_t level) {
+  indent(str, level);
+  appendFormatedString(str, "<div ");
+  if (node->getPrintFunc() != nullptr) {
+    node->getPrintFunc()(node);
+  }
+
+  if (options & YGPrintOptionsLayout) {
+    appendFormatedString(str, "layout=\"");
+    appendFormatedString(
+        str, "width: %g; ", node->getLayout().dimensions[YGDimensionWidth]);
+    appendFormatedString(
+        str, "height: %g; ", node->getLayout().dimensions[YGDimensionHeight]);
+    appendFormatedString(
+        str, "top: %g; ", node->getLayout().position[YGEdgeTop]);
+    appendFormatedString(
+        str, "left: %g;", node->getLayout().position[YGEdgeLeft]);
+    appendFormatedString(str, "\" ");
+  }
+
+  if (options & YGPrintOptionsStyle) {
+    appendFormatedString(str, "style=\"");
+    if (node->getStyle().flexDirection != YGNode().getStyle().flexDirection) {
+      appendFormatedString(
+          str,
+          "flex-direction: %s; ",
+          YGFlexDirectionToString(node->getStyle().flexDirection));
+    }
+    if (node->getStyle().justifyContent != YGNode().getStyle().justifyContent) {
+      appendFormatedString(
+          str,
+          "justify-content: %s; ",
+          YGJustifyToString(node->getStyle().justifyContent));
+    }
+    if (node->getStyle().alignItems != YGNode().getStyle().alignItems) {
+      appendFormatedString(
+          str,
+          "align-items: %s; ",
+          YGAlignToString(node->getStyle().alignItems));
+    }
+    if (node->getStyle().alignContent != YGNode().getStyle().alignContent) {
+      appendFormatedString(
+          str,
+          "align-content: %s; ",
+          YGAlignToString(node->getStyle().alignContent));
+    }
+    if (node->getStyle().alignSelf != YGNode().getStyle().alignSelf) {
+      appendFormatedString(
+          str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf));
+    }
+    appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow);
+    appendFloatOptionalIfDefined(
+        str, "flex-shrink", node->getStyle().flexShrink);
+    appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis);
+    appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex);
+
+    if (node->getStyle().flexWrap != YGNode().getStyle().flexWrap) {
+      appendFormatedString(
+          str, "flexWrap: %s; ", YGWrapToString(node->getStyle().flexWrap));
+    }
+
+    if (node->getStyle().overflow != YGNode().getStyle().overflow) {
+      appendFormatedString(
+          str, "overflow: %s; ", YGOverflowToString(node->getStyle().overflow));
+    }
+
+    if (node->getStyle().display != YGNode().getStyle().display) {
+      appendFormatedString(
+          str, "display: %s; ", YGDisplayToString(node->getStyle().display));
+    }
+    appendEdges(str, "margin", node->getStyle().margin);
+    appendEdges(str, "padding", node->getStyle().padding);
+    appendEdges(str, "border", node->getStyle().border);
+
+    appendNumberIfNotAuto(
+        str, "width", node->getStyle().dimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "height", node->getStyle().dimensions[YGDimensionHeight]);
+    appendNumberIfNotAuto(
+        str, "max-width", node->getStyle().maxDimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "max-height", node->getStyle().maxDimensions[YGDimensionHeight]);
+    appendNumberIfNotAuto(
+        str, "min-width", node->getStyle().minDimensions[YGDimensionWidth]);
+    appendNumberIfNotAuto(
+        str, "min-height", node->getStyle().minDimensions[YGDimensionHeight]);
+
+    if (node->getStyle().positionType != YGNode().getStyle().positionType) {
+      appendFormatedString(
+          str,
+          "position: %s; ",
+          YGPositionTypeToString(node->getStyle().positionType));
+    }
+
+    appendEdgeIfNotUndefined(
+        str, "left", node->getStyle().position, YGEdgeLeft);
+    appendEdgeIfNotUndefined(
+        str, "right", node->getStyle().position, YGEdgeRight);
+    appendEdgeIfNotUndefined(str, "top", node->getStyle().position, YGEdgeTop);
+    appendEdgeIfNotUndefined(
+        str, "bottom", node->getStyle().position, YGEdgeBottom);
+    appendFormatedString(str, "\" ");
+
+    if (node->getMeasure() != nullptr) {
+      appendFormatedString(str, "has-custom-measure=\"true\"");
+    }
+  }
+  appendFormatedString(str, ">");
+
+  const uint32_t childCount = static_cast<uint32_t>(node->getChildren().size());
+  if (options & YGPrintOptionsChildren && childCount > 0) {
+    for (uint32_t i = 0; i < childCount; i++) {
+      appendFormatedString(str, "\n");
+      YGNodeToString(str, YGNodeGetChild(node, i), options, level + 1);
+    }
+    appendFormatedString(str, "\n");
+    indent(str, level);
+  }
+  appendFormatedString(str, "</div>");
+}
+} // namespace yoga
+} // namespace facebook
diff --git a/dali-toolkit/third-party/yoga/YGNodePrint.h b/dali-toolkit/third-party/yoga/YGNodePrint.h
new file mode 100644 (file)
index 0000000..16259fc
--- /dev/null
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+#pragma once
+#include <string>
+
+#include "Yoga.h"
+
+namespace facebook {
+namespace yoga {
+
+void YGNodeToString(
+    std::string* str,
+    YGNodeRef node,
+    YGPrintOptions options,
+    uint32_t level);
+
+} // namespace yoga
+} // namespace facebook
diff --git a/dali-toolkit/third-party/yoga/YGStyle.cpp b/dali-toolkit/third-party/yoga/YGStyle.cpp
new file mode 100644 (file)
index 0000000..c11dc4e
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "YGStyle.h"
+
+const YGValue kYGValueUndefined = {0, YGUnitUndefined};
+
+const YGValue kYGValueAuto = {0, YGUnitAuto};
+
+const std::array<YGValue, YGEdgeCount> kYGDefaultEdgeValuesUnit = {
+    {kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined,
+     kYGValueUndefined}};
+
+const std::array<YGValue, 2> kYGDefaultDimensionValuesAutoUnit = {
+    {kYGValueAuto, kYGValueAuto}};
+
+const std::array<YGValue, 2> kYGDefaultDimensionValuesUnit = {
+    {kYGValueUndefined, kYGValueUndefined}};
+
+YGStyle::YGStyle()
+    : direction(YGDirectionInherit),
+      flexDirection(YGFlexDirectionColumn),
+      justifyContent(YGJustifyFlexStart),
+      alignContent(YGAlignFlexStart),
+      alignItems(YGAlignStretch),
+      alignSelf(YGAlignAuto),
+      positionType(YGPositionTypeRelative),
+      flexWrap(YGWrapNoWrap),
+      overflow(YGOverflowVisible),
+      display(YGDisplayFlex),
+      flex(YGFloatOptional()),
+      flexGrow(YGFloatOptional()),
+      flexShrink(YGFloatOptional()),
+      flexBasis(kYGValueAuto),
+      margin(kYGDefaultEdgeValuesUnit),
+      position(kYGDefaultEdgeValuesUnit),
+      padding(kYGDefaultEdgeValuesUnit),
+      border(kYGDefaultEdgeValuesUnit),
+      dimensions(kYGDefaultDimensionValuesAutoUnit),
+      minDimensions(kYGDefaultDimensionValuesUnit),
+      maxDimensions(kYGDefaultDimensionValuesUnit),
+      aspectRatio(YGFloatOptional()) {}
+
+// Yoga specific properties, not compatible with flexbox specification
+bool YGStyle::operator==(const YGStyle& style) {
+  bool areNonFloatValuesEqual = direction == style.direction &&
+      flexDirection == style.flexDirection &&
+      justifyContent == style.justifyContent &&
+      alignContent == style.alignContent && alignItems == style.alignItems &&
+      alignSelf == style.alignSelf && positionType == style.positionType &&
+      flexWrap == style.flexWrap && overflow == style.overflow &&
+      display == style.display && YGValueEqual(flexBasis, style.flexBasis) &&
+      YGValueArrayEqual(margin, style.margin) &&
+      YGValueArrayEqual(position, style.position) &&
+      YGValueArrayEqual(padding, style.padding) &&
+      YGValueArrayEqual(border, style.border) &&
+      YGValueArrayEqual(dimensions, style.dimensions) &&
+      YGValueArrayEqual(minDimensions, style.minDimensions) &&
+      YGValueArrayEqual(maxDimensions, style.maxDimensions);
+
+  areNonFloatValuesEqual =
+      areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined();
+  if (areNonFloatValuesEqual && !flex.isUndefined() &&
+      !style.flex.isUndefined()) {
+    areNonFloatValuesEqual =
+        areNonFloatValuesEqual && flex.getValue() == style.flex.getValue();
+  }
+
+  areNonFloatValuesEqual = areNonFloatValuesEqual &&
+      flexGrow.isUndefined() == style.flexGrow.isUndefined();
+  if (areNonFloatValuesEqual && !flexGrow.isUndefined()) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        flexGrow.getValue() == style.flexGrow.getValue();
+  }
+
+  areNonFloatValuesEqual = areNonFloatValuesEqual &&
+      flexShrink.isUndefined() == style.flexShrink.isUndefined();
+  if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        flexShrink.getValue() == style.flexShrink.getValue();
+  }
+
+  if (!(aspectRatio.isUndefined() && style.aspectRatio.isUndefined())) {
+    areNonFloatValuesEqual = areNonFloatValuesEqual &&
+        aspectRatio.getValue() == style.aspectRatio.getValue();
+  }
+
+  return areNonFloatValuesEqual;
+}
+
+bool YGStyle::operator!=(const YGStyle& style) {
+  return !(*this == style);
+}
+
+YGStyle::~YGStyle() {}
diff --git a/dali-toolkit/third-party/yoga/YGStyle.h b/dali-toolkit/third-party/yoga/YGStyle.h
new file mode 100644 (file)
index 0000000..0aaba54
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include "YGFloatOptional.h"
+#include "Yoga-internal.h"
+#include "Yoga.h"
+
+struct YGStyle {
+  YGDirection direction;
+  YGFlexDirection flexDirection;
+  YGJustify justifyContent;
+  YGAlign alignContent;
+  YGAlign alignItems;
+  YGAlign alignSelf;
+  YGPositionType positionType;
+  YGWrap flexWrap;
+  YGOverflow overflow;
+  YGDisplay display;
+  YGFloatOptional flex;
+  YGFloatOptional flexGrow;
+  YGFloatOptional flexShrink;
+  YGValue flexBasis;
+  std::array<YGValue, YGEdgeCount> margin;
+  std::array<YGValue, YGEdgeCount> position;
+  std::array<YGValue, YGEdgeCount> padding;
+  std::array<YGValue, YGEdgeCount> border;
+  std::array<YGValue, 2> dimensions;
+  std::array<YGValue, 2> minDimensions;
+  std::array<YGValue, 2> maxDimensions;
+  YGFloatOptional aspectRatio;
+
+  YGStyle();
+  // Yoga specific properties, not compatible with flexbox specification
+  bool operator==(const YGStyle& style);
+
+  bool operator!=(const YGStyle& style);
+  ~YGStyle();
+};
diff --git a/dali-toolkit/third-party/yoga/Yoga-internal.h b/dali-toolkit/third-party/yoga/Yoga-internal.h
new file mode 100644 (file)
index 0000000..17dd9ef
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+#include <algorithm>
+#include <array>
+#include <cmath>
+#include <vector>
+#include "Yoga.h"
+
+using YGVector = std::vector<YGNodeRef>;
+
+YG_EXTERN_C_BEGIN
+
+WIN_EXPORT float YGRoundValueToPixelGrid(const float value,
+                                         const float pointScaleFactor,
+                                         const bool forceCeil,
+                                         const bool forceFloor);
+
+YG_EXTERN_C_END
+
+extern const std::array<YGEdge, 4> trailing;
+extern const std::array<YGEdge, 4> leading;
+extern bool YGValueEqual(const YGValue a, const YGValue b);
+extern const YGValue YGValueUndefined;
+extern const YGValue YGValueAuto;
+extern const YGValue YGValueZero;
+
+template <std::size_t size>
+bool YGValueArrayEqual(
+    const std::array<YGValue, size> val1,
+    const std::array<YGValue, size> val2) {
+  bool areEqual = true;
+  for (uint32_t i = 0; i < size && areEqual; ++i) {
+    areEqual = YGValueEqual(val1[i], val2[i]);
+  }
+  return areEqual;
+}
+
+struct YGCachedMeasurement {
+  float availableWidth;
+  float availableHeight;
+  YGMeasureMode widthMeasureMode;
+  YGMeasureMode heightMeasureMode;
+
+  float computedWidth;
+  float computedHeight;
+
+  YGCachedMeasurement()
+      : availableWidth(0),
+        availableHeight(0),
+        widthMeasureMode((YGMeasureMode)-1),
+        heightMeasureMode((YGMeasureMode)-1),
+        computedWidth(-1),
+        computedHeight(-1) {}
+
+  bool operator==(const YGCachedMeasurement& measurement) const {
+    bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
+        heightMeasureMode == measurement.heightMeasureMode;
+
+    if (!YGFloatIsUndefined(availableWidth) ||
+        !YGFloatIsUndefined(measurement.availableWidth)) {
+      isEqual = isEqual && availableWidth == measurement.availableWidth;
+    }
+    if (!YGFloatIsUndefined(availableHeight) ||
+        !YGFloatIsUndefined(measurement.availableHeight)) {
+      isEqual = isEqual && availableHeight == measurement.availableHeight;
+    }
+    if (!YGFloatIsUndefined(computedWidth) ||
+        !YGFloatIsUndefined(measurement.computedWidth)) {
+      isEqual = isEqual && computedWidth == measurement.computedWidth;
+    }
+    if (!YGFloatIsUndefined(computedHeight) ||
+        !YGFloatIsUndefined(measurement.computedHeight)) {
+      isEqual = isEqual && computedHeight == measurement.computedHeight;
+    }
+
+    return isEqual;
+  }
+};
+
+// This value was chosen based on empiracle data. Even the most complicated
+// layouts should not require more than 16 entries to fit within the cache.
+#define YG_MAX_CACHED_RESULT_COUNT 16
+
+
+static const float kDefaultFlexGrow = 0.0f;
+static const float kDefaultFlexShrink = 0.0f;
+static const float kWebDefaultFlexShrink = 1.0f;
+
+extern bool YGFloatsEqual(const float a, const float b);
+extern bool YGValueEqual(const YGValue a, const YGValue b);
+extern const YGValue* YGComputedEdgeValue(
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge,
+    const YGValue* const defaultValue);
diff --git a/dali-toolkit/third-party/yoga/Yoga.cpp b/dali-toolkit/third-party/yoga/Yoga.cpp
new file mode 100644 (file)
index 0000000..a927ef5
--- /dev/null
@@ -0,0 +1,4054 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#include "Yoga.h"
+#include <float.h>
+#include <string.h>
+#include <algorithm>
+#include "Utils.h"
+#include "YGNode.h"
+#include "YGNodePrint.h"
+#include "Yoga-internal.h"
+#ifdef _MSC_VER
+#include <float.h>
+
+/* define fmaxf if < VC12 */
+#if _MSC_VER < 1800
+__forceinline const float fmaxf(const float a, const float b) {
+  if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
+    return (a > b) ? a : b;
+  }
+  return YGFloatIsUndefined(a) ? b : a;
+}
+#endif
+#endif
+
+#ifdef ANDROID
+static int YGAndroidLog(const YGConfigRef config,
+                        const YGNodeRef node,
+                        YGLogLevel level,
+                        const char *format,
+                        va_list args);
+#else
+static int YGDefaultLog(const YGConfigRef config,
+                        const YGNodeRef node,
+                        YGLogLevel level,
+                        const char *format,
+                        va_list args);
+#endif
+
+const YGValue YGValueZero = {0, YGUnitPoint};
+const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
+const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
+
+#ifdef ANDROID
+#include <android/log.h>
+static int YGAndroidLog(const YGConfigRef config,
+                        const YGNodeRef node,
+                        YGLogLevel level,
+                        const char *format,
+                        va_list args) {
+  int androidLevel = YGLogLevelDebug;
+  switch (level) {
+    case YGLogLevelFatal:
+      androidLevel = ANDROID_LOG_FATAL;
+      break;
+    case YGLogLevelError:
+      androidLevel = ANDROID_LOG_ERROR;
+      break;
+    case YGLogLevelWarn:
+      androidLevel = ANDROID_LOG_WARN;
+      break;
+    case YGLogLevelInfo:
+      androidLevel = ANDROID_LOG_INFO;
+      break;
+    case YGLogLevelDebug:
+      androidLevel = ANDROID_LOG_DEBUG;
+      break;
+    case YGLogLevelVerbose:
+      androidLevel = ANDROID_LOG_VERBOSE;
+      break;
+  }
+  const int result = __android_log_vprint(androidLevel, "yoga", format, args);
+  return result;
+}
+#else
+#define YG_UNUSED(x) (void)(x);
+
+static int YGDefaultLog(const YGConfigRef config,
+                        const YGNodeRef node,
+                        YGLogLevel level,
+                        const char *format,
+                        va_list args) {
+  YG_UNUSED(config);
+  YG_UNUSED(node);
+  switch (level) {
+    case YGLogLevelError:
+    case YGLogLevelFatal:
+      return vfprintf(stderr, format, args);
+    case YGLogLevelWarn:
+    case YGLogLevelInfo:
+    case YGLogLevelDebug:
+    case YGLogLevelVerbose:
+    default:
+      return vprintf(format, args);
+  }
+}
+
+#undef YG_UNUSED
+#endif
+
+bool YGFloatIsUndefined(const float value) {
+  // Value of a float in the case of it being not defined is 10.1E20. Earlier
+  // it used to be NAN, the benefit of which was that if NAN is involved in any
+  // mathematical expression the result was NAN. But since we want to have
+  // `-ffast-math` flag being used by compiler which assumes that the floating
+  // point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
+  // now if YGUndefined is involved in any mathematical operations this
+  // value(10.1E20) would change. So the following check makes sure that if the
+  // value is outside a range (-10E8, 10E8) then it is undefined.
+  return value >= 10E8 || value <= -10E8;
+}
+
+const YGValue* YGComputedEdgeValue(
+    const std::array<YGValue, YGEdgeCount>& edges,
+    const YGEdge edge,
+    const YGValue* const defaultValue) {
+  if (edges[edge].unit != YGUnitUndefined) {
+    return &edges[edge];
+  }
+
+  if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
+      edges[YGEdgeVertical].unit != YGUnitUndefined) {
+    return &edges[YGEdgeVertical];
+  }
+
+  if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || edge == YGEdgeEnd) &&
+      edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
+    return &edges[YGEdgeHorizontal];
+  }
+
+  if (edges[YGEdgeAll].unit != YGUnitUndefined) {
+    return &edges[YGEdgeAll];
+  }
+
+  if (edge == YGEdgeStart || edge == YGEdgeEnd) {
+    return &YGValueUndefined;
+  }
+
+  return defaultValue;
+}
+
+void* YGNodeGetContext(YGNodeRef node) {
+  return node->getContext();
+}
+
+void YGNodeSetContext(YGNodeRef node, void* context) {
+  return node->setContext(context);
+}
+
+YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) {
+  return node->getMeasure();
+}
+
+void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
+  node->setMeasureFunc(measureFunc);
+}
+
+YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) {
+  return node->getBaseline();
+}
+
+void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
+  node->setBaseLineFunc(baselineFunc);
+}
+
+YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) {
+  return node->getDirtied();
+}
+
+void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
+  node->setDirtiedFunc(dirtiedFunc);
+}
+
+YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) {
+  return node->getPrintFunc();
+}
+
+void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
+  node->setPrintFunc(printFunc);
+}
+
+bool YGNodeGetHasNewLayout(YGNodeRef node) {
+  return node->getHasNewLayout();
+}
+
+void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
+  node->setHasNewLayout(hasNewLayout);
+}
+
+YGNodeType YGNodeGetNodeType(YGNodeRef node) {
+  return node->getNodeType();
+}
+
+void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
+  return node->setNodeType(nodeType);
+}
+
+bool YGNodeIsDirty(YGNodeRef node) {
+  return node->isDirty();
+}
+
+bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
+  return node->didUseLegacyFlag();
+}
+
+void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
+  return node->markDirtyAndPropogateDownwards();
+}
+
+int32_t gNodeInstanceCount = 0;
+int32_t gConfigInstanceCount = 0;
+
+WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
+  const YGNodeRef node = new YGNode();
+  YGAssertWithConfig(
+      config, node != nullptr, "Could not allocate memory for node");
+  gNodeInstanceCount++;
+
+  if (config->useWebDefaults) {
+    node->setStyleFlexDirection(YGFlexDirectionRow);
+    node->setStyleAlignContent(YGAlignStretch);
+  }
+  node->setConfig(config);
+  return node;
+}
+
+YGConfigRef YGConfigGetDefault() {
+  static YGConfigRef defaultConfig = YGConfigNew();
+  return defaultConfig;
+}
+
+YGNodeRef YGNodeNew(void) {
+  return YGNodeNewWithConfig(YGConfigGetDefault());
+}
+
+YGNodeRef YGNodeClone(YGNodeRef oldNode) {
+  YGNodeRef node = new YGNode(*oldNode);
+  YGAssertWithConfig(
+      oldNode->getConfig(),
+      node != nullptr,
+      "Could not allocate memory for node");
+  gNodeInstanceCount++;
+  node->setOwner(nullptr);
+  return node;
+}
+
+static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
+  const YGConfigRef config = new YGConfig(oldConfig);
+  YGAssert(config != nullptr, "Could not allocate memory for config");
+  if (config == nullptr) {
+    abort();
+  }
+  gConfigInstanceCount++;
+  return config;
+}
+
+static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
+  YGNodeRef node = YGNodeClone(oldNode);
+  YGVector vec = YGVector();
+  vec.reserve(oldNode->getChildren().size());
+  YGNodeRef childNode = nullptr;
+  for (auto& item : oldNode->getChildren()) {
+    childNode = YGNodeDeepClone(item);
+    childNode->setOwner(node);
+    vec.push_back(childNode);
+  }
+  node->setChildren(vec);
+
+  if (oldNode->getConfig() != nullptr) {
+    node->setConfig(YGConfigClone(*(oldNode->getConfig())));
+  }
+
+  if (oldNode->getNextChild() != nullptr) {
+    node->setNextChild(YGNodeDeepClone(oldNode->getNextChild()));
+  }
+
+  return node;
+}
+
+void YGNodeFree(const YGNodeRef node) {
+  if (YGNodeRef owner = node->getOwner()) {
+    owner->removeChild(node);
+    node->setOwner(nullptr);
+  }
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    child->setOwner(nullptr);
+  }
+
+  node->clearChildren();
+  delete node;
+  gNodeInstanceCount--;
+}
+
+static void YGConfigFreeRecursive(const YGNodeRef root) {
+  if (root->getConfig() != nullptr) {
+    gConfigInstanceCount--;
+    delete root->getConfig();
+  }
+  // Delete configs recursively for childrens
+  for (uint32_t i = 0; i < root->getChildrenCount(); ++i) {
+    YGConfigFreeRecursive(root->getChild(i));
+  }
+}
+
+void YGNodeFreeRecursive(const YGNodeRef root) {
+  while (YGNodeGetChildCount(root) > 0) {
+    const YGNodeRef child = YGNodeGetChild(root, 0);
+    if (child->getOwner() != root) {
+      // Don't free shared nodes that we don't own.
+      break;
+    }
+    YGNodeRemoveChild(root, child);
+    YGNodeFreeRecursive(child);
+  }
+  YGNodeFree(root);
+}
+
+void YGNodeReset(const YGNodeRef node) {
+  YGAssertWithNode(node,
+                   YGNodeGetChildCount(node) == 0,
+                   "Cannot reset a node which still has children attached");
+  YGAssertWithNode(
+      node,
+      node->getOwner() == nullptr,
+      "Cannot reset a node still attached to a owner");
+
+  node->clearChildren();
+
+  const YGConfigRef config = node->getConfig();
+  *node = YGNode();
+  if (config->useWebDefaults) {
+    node->setStyleFlexDirection(YGFlexDirectionRow);
+    node->setStyleAlignContent(YGAlignStretch);
+  }
+  node->setConfig(config);
+}
+
+int32_t YGNodeGetInstanceCount(void) {
+  return gNodeInstanceCount;
+}
+
+int32_t YGConfigGetInstanceCount(void) {
+  return gConfigInstanceCount;
+}
+
+YGConfigRef YGConfigNew(void) {
+  #ifdef ANDROID
+  const YGConfigRef config = new YGConfig(YGAndroidLog);
+  #else
+  const YGConfigRef config = new YGConfig(YGDefaultLog);
+  #endif
+  gConfigInstanceCount++;
+  return config;
+}
+
+void YGConfigFree(const YGConfigRef config) {
+  free(config);
+  gConfigInstanceCount--;
+}
+
+void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
+  memcpy(dest, src, sizeof(YGConfig));
+}
+
+void YGNodeInsertChild(const YGNodeRef node, const YGNodeRef child, const uint32_t index) {
+  YGAssertWithNode(
+      node,
+      child->getOwner() == nullptr,
+      "Child already has a owner, it must be removed first.");
+
+  YGAssertWithNode(
+      node,
+      node->getMeasure() == nullptr,
+      "Cannot add child: Nodes with measure functions cannot have children.");
+
+  node->cloneChildrenIfNeeded();
+  node->insertChild(child, index);
+  YGNodeRef owner = child->getOwner() ? nullptr : node;
+  child->setOwner(owner);
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeInsertSharedChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() == nullptr,
+      "Cannot add child: Nodes with measure functions cannot have children.");
+
+  node->insertChild(child, index);
+  child->setOwner(nullptr);
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
+  // This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
+  // that excludes a child.
+  const uint32_t childCount = YGNodeGetChildCount(owner);
+
+  if (childCount == 0) {
+    // This is an empty set. Nothing to remove.
+    return;
+  }
+  const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
+  if (firstChild->getOwner() == owner) {
+    // If the first child has this node as its owner, we assume that it is already unique.
+    // We can now try to delete a child in this list.
+    if (owner->removeChild(excludedChild)) {
+      excludedChild->setLayout(
+          YGNode().getLayout()); // layout is no longer valid
+      excludedChild->setOwner(nullptr);
+      owner->markDirtyAndPropogate();
+    }
+    return;
+  }
+  // Otherwise we have to clone the node list except for the child we're trying to delete.
+  // We don't want to simply clone all children, because then the host will need to free
+  // the clone of the child that was just deleted.
+  const YGCloneNodeFunc cloneNodeCallback =
+      owner->getConfig()->cloneNodeCallback;
+  uint32_t nextInsertIndex = 0;
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef oldChild = owner->getChild(i);
+    if (excludedChild == oldChild) {
+      // Ignore the deleted child. Don't reset its layout or owner since it is still valid
+      // in the other owner. However, since this owner has now changed, we need to mark it
+      // as dirty.
+      owner->markDirtyAndPropogate();
+      continue;
+    }
+    YGNodeRef newChild = nullptr;
+    if (cloneNodeCallback) {
+      newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex);
+    }
+    if (newChild == nullptr) {
+      newChild = YGNodeClone(oldChild);
+    }
+    owner->replaceChild(newChild, nextInsertIndex);
+    newChild->setOwner(owner);
+
+    nextInsertIndex++;
+  }
+  while (nextInsertIndex < childCount) {
+    owner->removeChild(nextInsertIndex);
+    nextInsertIndex++;
+  }
+}
+
+void YGNodeRemoveAllChildren(const YGNodeRef owner) {
+  const uint32_t childCount = YGNodeGetChildCount(owner);
+  if (childCount == 0) {
+    // This is an empty set already. Nothing to do.
+    return;
+  }
+  const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
+  if (firstChild->getOwner() == owner) {
+    // If the first child has this node as its owner, we assume that this child set is unique.
+    for (uint32_t i = 0; i < childCount; i++) {
+      const YGNodeRef oldChild = YGNodeGetChild(owner, i);
+      oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid
+      oldChild->setOwner(nullptr);
+    }
+    owner->clearChildren();
+    owner->markDirtyAndPropogate();
+    return;
+  }
+  // Otherwise, we are not the owner of the child set. We don't have to do anything to clear it.
+  owner->setChildren(YGVector());
+  owner->markDirtyAndPropogate();
+}
+
+static void YGNodeSetChildrenInternal(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
+{
+  if (!owner) {
+    return;
+  }
+  if (children.size() == 0) {
+    if (YGNodeGetChildCount(owner) > 0) {
+      for (YGNodeRef const child : owner->getChildren()) {
+        child->setLayout(YGLayout());
+        child->setOwner(nullptr);
+      }
+      owner->setChildren(YGVector());
+      owner->markDirtyAndPropogate();
+    }
+  } else {
+    if (YGNodeGetChildCount(owner) > 0) {
+      for (YGNodeRef const oldChild : owner->getChildren()) {
+        // Our new children may have nodes in common with the old children. We don't reset these common nodes.
+        if (std::find(children.begin(), children.end(), oldChild) == children.end()) {
+          oldChild->setLayout(YGLayout());
+          oldChild->setOwner(nullptr);
+        }
+      }
+    }
+    owner->setChildren(children);
+    for (YGNodeRef child : children) {
+      child->setOwner(owner);
+    }
+    owner->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeSetChildren(YGNodeRef const owner, const YGNodeRef c[], const uint32_t count) {
+  const YGVector children = {c, c + count};
+  YGNodeSetChildrenInternal(owner, children);
+}
+
+void YGNodeSetChildren(YGNodeRef const owner, const std::vector<YGNodeRef> &children)
+{
+  YGNodeSetChildrenInternal(owner, children);
+}
+
+YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
+  if (index < node->getChildren().size()) {
+    return node->getChild(index);
+  }
+  return nullptr;
+}
+
+uint32_t YGNodeGetChildCount(const YGNodeRef node) {
+  return static_cast<uint32_t>(node->getChildren().size());
+}
+
+YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
+  return node->getOwner();
+}
+
+void YGNodeMarkDirty(const YGNodeRef node) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() != nullptr,
+      "Only leaf nodes with custom measure functions"
+      "should manually mark themselves as dirty");
+
+  node->markDirtyAndPropogate();
+}
+
+void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
+  if (!(dstNode->getStyle() == srcNode->getStyle())) {
+    dstNode->setStyle(srcNode->getStyle());
+    dstNode->markDirtyAndPropogate();
+  }
+}
+
+float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
+  return node->getStyle().flexGrow.isUndefined()
+      ? kDefaultFlexGrow
+      : node->getStyle().flexGrow.getValue();
+}
+
+float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
+  return node->getStyle().flexShrink.isUndefined()
+      ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
+                                           : kDefaultFlexShrink)
+      : node->getStyle().flexShrink.getValue();
+}
+
+#define YG_NODE_STYLE_PROPERTY_SETTER_IMPL(                               \
+    type, name, paramName, instanceName)                                  \
+  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
+    if (node->getStyle().instanceName != paramName) {                     \
+      YGStyle style = node->getStyle();                                   \
+      style.instanceName = paramName;                                     \
+      node->setStyle(style);                                              \
+      node->markDirtyAndPropogate();                                      \
+    }                                                                     \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(                          \
+    type, name, paramName, instanceName)                                  \
+  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
+    YGValue value = {                                                     \
+        YGFloatSanitize(paramName),                                       \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint,    \
+    };                                                                    \
+    if ((node->getStyle().instanceName.value != value.value &&            \
+         value.unit != YGUnitUndefined) ||                                \
+        node->getStyle().instanceName.unit != value.unit) {               \
+      YGStyle style = node->getStyle();                                   \
+      style.instanceName = value;                                         \
+      node->setStyle(style);                                              \
+      node->markDirtyAndPropogate();                                      \
+    }                                                                     \
+  }                                                                       \
+                                                                          \
+  void YGNodeStyleSet##name##Percent(                                     \
+      const YGNodeRef node, const type paramName) {                       \
+    YGValue value = {                                                     \
+        YGFloatSanitize(paramName),                                       \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent,  \
+    };                                                                    \
+    if ((node->getStyle().instanceName.value != value.value &&            \
+         value.unit != YGUnitUndefined) ||                                \
+        node->getStyle().instanceName.unit != value.unit) {               \
+      YGStyle style = node->getStyle();                                   \
+                                                                          \
+      style.instanceName = value;                                         \
+      node->setStyle(style);                                              \
+      node->markDirtyAndPropogate();                                      \
+    }                                                                     \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(                        \
+    type, name, paramName, instanceName)                                     \
+  void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) {    \
+    YGValue value = {                                                        \
+        YGFloatSanitize(paramName),                                          \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint,       \
+    };                                                                       \
+    if ((node->getStyle().instanceName.value != value.value &&               \
+         value.unit != YGUnitUndefined) ||                                   \
+        node->getStyle().instanceName.unit != value.unit) {                  \
+      YGStyle style = node->getStyle();                                      \
+      style.instanceName = value;                                            \
+      node->setStyle(style);                                                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  void YGNodeStyleSet##name##Percent(                                        \
+      const YGNodeRef node, const type paramName) {                          \
+    if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
+        node->getStyle().instanceName.unit != YGUnitPercent) {               \
+      YGStyle style = node->getStyle();                                      \
+      style.instanceName.value = YGFloatSanitize(paramName);                 \
+      style.instanceName.unit =                                              \
+          YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent;        \
+      node->setStyle(style);                                                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  void YGNodeStyleSet##name##Auto(const YGNodeRef node) {                    \
+    if (node->getStyle().instanceName.unit != YGUnitAuto) {                  \
+      YGStyle style = node->getStyle();                                      \
+      style.instanceName.value = 0;                                          \
+      style.instanceName.unit = YGUnitAuto;                                  \
+      node->setStyle(style);                                                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName)  \
+  YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \
+                                                                          \
+  type YGNodeStyleGet##name(const YGNodeRef node) {                       \
+    return node->getStyle().instanceName;                                 \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \
+  YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(                                    \
+      float, name, paramName, instanceName)                                   \
+                                                                              \
+  type YGNodeStyleGet##name(const YGNodeRef node) {                           \
+    YGValue value = node->getStyle().instanceName;                            \
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {          \
+      value.value = YGUndefined;                                              \
+    }                                                                         \
+    return value;                                                             \
+  }
+
+#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(                       \
+    type, name, paramName, instanceName)                             \
+  YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL(                      \
+      float, name, paramName, instanceName)                          \
+                                                                     \
+  type YGNodeStyleGet##name(const YGNodeRef node) {                  \
+    YGValue value = node->getStyle().instanceName;                   \
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
+      value.value = YGUndefined;                                     \
+    }                                                                \
+    return value;                                                    \
+  }
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
+  void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
+    if (node->getStyle().instanceName[edge].unit != YGUnitAuto) {            \
+      YGStyle style = node->getStyle();                                      \
+      style.instanceName[edge].value = 0;                                    \
+      style.instanceName[edge].unit = YGUnitAuto;                            \
+      node->setStyle(style);                                                 \
+      node->markDirtyAndPropogate();                                         \
+    }                                                                        \
+  }
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(                           \
+    type, name, paramName, instanceName)                                 \
+  void YGNodeStyleSet##name(                                             \
+      const YGNodeRef node, const YGEdge edge, const float paramName) {  \
+    YGValue value = {                                                    \
+        YGFloatSanitize(paramName),                                      \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint,   \
+    };                                                                   \
+    if ((node->getStyle().instanceName[edge].value != value.value &&     \
+         value.unit != YGUnitUndefined) ||                               \
+        node->getStyle().instanceName[edge].unit != value.unit) {        \
+      YGStyle style = node->getStyle();                                  \
+      style.instanceName[edge] = value;                                  \
+      node->setStyle(style);                                             \
+      node->markDirtyAndPropogate();                                     \
+    }                                                                    \
+  }                                                                      \
+                                                                         \
+  void YGNodeStyleSet##name##Percent(                                    \
+      const YGNodeRef node, const YGEdge edge, const float paramName) {  \
+    YGValue value = {                                                    \
+        YGFloatSanitize(paramName),                                      \
+        YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
+    };                                                                   \
+    if ((node->getStyle().instanceName[edge].value != value.value &&     \
+         value.unit != YGUnitUndefined) ||                               \
+        node->getStyle().instanceName[edge].unit != value.unit) {        \
+      YGStyle style = node->getStyle();                                  \
+      style.instanceName[edge] = value;                                  \
+      node->setStyle(style);                                             \
+      node->markDirtyAndPropogate();                                     \
+    }                                                                    \
+  }                                                                      \
+                                                                         \
+  WIN_STRUCT(type)                                                       \
+  YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) {        \
+    YGValue value = node->getStyle().instanceName[edge];                 \
+    if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) {     \
+      value.value = YGUndefined;                                         \
+    }                                                                    \
+    return WIN_STRUCT_REF(value);                                        \
+  }
+
+#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
+  type YGNodeLayoutGet##name(const YGNodeRef node) {           \
+    return node->getLayout().instanceName;                     \
+  }
+
+#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
+  type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
+    YGAssertWithNode(                                                   \
+        node,                                                           \
+        edge <= YGEdgeEnd,                                              \
+        "Cannot get layout properties of multi-edge shorthands");       \
+                                                                        \
+    if (edge == YGEdgeLeft) {                                           \
+      if (node->getLayout().direction == YGDirectionRTL) {              \
+        return node->getLayout().instanceName[YGEdgeEnd];               \
+      } else {                                                          \
+        return node->getLayout().instanceName[YGEdgeStart];             \
+      }                                                                 \
+    }                                                                   \
+                                                                        \
+    if (edge == YGEdgeRight) {                                          \
+      if (node->getLayout().direction == YGDirectionRTL) {              \
+        return node->getLayout().instanceName[YGEdgeStart];             \
+      } else {                                                          \
+        return node->getLayout().instanceName[YGEdgeEnd];               \
+      }                                                                 \
+    }                                                                   \
+                                                                        \
+    return node->getLayout().instanceName[edge];                        \
+  }
+
+// YG_NODE_PROPERTY_IMPL(void *, Context, context, context);
+// YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print);
+// YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout);
+// YG_NODE_PROPERTY_IMPL(YGNodeType, NodeType, nodeType, nodeType);
+
+YG_NODE_STYLE_PROPERTY_IMPL(YGDirection, Direction, direction, direction);
+YG_NODE_STYLE_PROPERTY_IMPL(YGFlexDirection, FlexDirection, flexDirection, flexDirection);
+YG_NODE_STYLE_PROPERTY_IMPL(YGJustify, JustifyContent, justifyContent, justifyContent);
+YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignContent, alignContent, alignContent);
+YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignItems, alignItems, alignItems);
+YG_NODE_STYLE_PROPERTY_IMPL(YGAlign, AlignSelf, alignSelf, alignSelf);
+YG_NODE_STYLE_PROPERTY_IMPL(YGPositionType, PositionType, positionType, positionType);
+YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap);
+YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow);
+YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display);
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
+  if (node->getStyle().flex != flex) {
+    YGStyle style = node->getStyle();
+    if (YGFloatIsUndefined(flex)) {
+      style.flex = YGFloatOptional();
+    } else {
+      style.flex = YGFloatOptional(flex);
+    }
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+float YGNodeStyleGetFlex(const YGNodeRef node) {
+  return node->getStyle().flex.isUndefined() ? YGUndefined
+                                             : node->getStyle().flex.getValue();
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
+  if (node->getStyle().flexGrow != flexGrow) {
+    YGStyle style = node->getStyle();
+    if (YGFloatIsUndefined(flexGrow)) {
+      style.flexGrow = YGFloatOptional();
+    } else {
+      style.flexGrow = YGFloatOptional(flexGrow);
+    }
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
+  if (node->getStyle().flexShrink != flexShrink) {
+    YGStyle style = node->getStyle();
+    if (YGFloatIsUndefined(flexShrink)) {
+      style.flexShrink = YGFloatOptional();
+    } else {
+      style.flexShrink = YGFloatOptional(flexShrink);
+    }
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
+  YGValue flexBasis = node->getStyle().flexBasis;
+  if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
+    // TODO(T26792433): Get rid off the use of YGUndefined at client side
+    flexBasis.value = YGUndefined;
+  }
+  return flexBasis;
+}
+
+void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
+  YGValue value = {
+      YGFloatSanitize(flexBasis),
+      YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
+  };
+  if ((node->getStyle().flexBasis.value != value.value &&
+       value.unit != YGUnitUndefined) ||
+      node->getStyle().flexBasis.unit != value.unit) {
+    YGStyle style = node->getStyle();
+    style.flexBasis = value;
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeStyleSetFlexBasisPercent(
+    const YGNodeRef node,
+    const float flexBasisPercent) {
+  if (node->getStyle().flexBasis.value != flexBasisPercent ||
+      node->getStyle().flexBasis.unit != YGUnitPercent) {
+    YGStyle style = node->getStyle();
+    style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
+    style.flexBasis.unit =
+        YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
+  if (node->getStyle().flexBasis.unit != YGUnitAuto) {
+    YGStyle style = node->getStyle();
+    style.flexBasis.value = 0;
+    style.flexBasis.unit = YGUnitAuto;
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetBorder(
+    const YGNodeRef node,
+    const YGEdge edge,
+    const float border) {
+  YGValue value = {
+      YGFloatSanitize(border),
+      YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
+  };
+  if ((node->getStyle().border[edge].value != value.value &&
+       value.unit != YGUnitUndefined) ||
+      node->getStyle().border[edge].unit != value.unit) {
+    YGStyle style = node->getStyle();
+    style.border[edge] = value;
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
+  if (node->getStyle().border[edge].unit == YGUnitUndefined ||
+      node->getStyle().border[edge].unit == YGUnitAuto) {
+    // TODO(T26792433): Rather than returning YGUndefined, change the api to
+    // return YGFloatOptional.
+    return YGUndefined;
+  }
+
+  return node->getStyle().border[edge].value;
+}
+
+// Yoga specific properties, not compatible with flexbox specification
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
+  const YGFloatOptional op = node->getStyle().aspectRatio;
+  return op.isUndefined() ? YGUndefined : op.getValue();
+}
+
+// TODO(T26792433): Change the API to accept YGFloatOptional.
+void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
+  if (node->getStyle().aspectRatio != aspectRatio) {
+    YGStyle style = node->getStyle();
+    style.aspectRatio = YGFloatOptional(aspectRatio);
+    node->setStyle(style);
+    node->markDirtyAndPropogate();
+  }
+}
+
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]);
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]);
+YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]);
+YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]);
+YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]);
+YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
+YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
+YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
+
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
+YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
+
+bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
+  return node->getLayout().doesLegacyStretchFlagAffectsLayout;
+}
+
+uint32_t gCurrentGenerationCount = 0;
+
+bool YGLayoutNodeInternal(const YGNodeRef node,
+                          const float availableWidth,
+                          const float availableHeight,
+                          const YGDirection ownerDirection,
+                          const YGMeasureMode widthMeasureMode,
+                          const YGMeasureMode heightMeasureMode,
+                          const float ownerWidth,
+                          const float ownerHeight,
+                          const bool performLayout,
+                          const char *reason,
+                          const YGConfigRef config);
+
+static void YGNodePrintInternal(const YGNodeRef node,
+                                const YGPrintOptions options) {
+  std::string str;
+  facebook::yoga::YGNodeToString(&str, node, options, 0);
+  YGLog(node, YGLogLevelDebug, str.c_str());
+}
+
+void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
+  YGNodePrintInternal(node, options);
+}
+
+const std::array<YGEdge, 4> leading = {
+    {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}};
+
+const std::array<YGEdge, 4> trailing = {
+    {YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}};
+static const std::array<YGEdge, 4> pos = {{
+    YGEdgeTop,
+    YGEdgeBottom,
+    YGEdgeLeft,
+    YGEdgeRight,
+}};
+
+static const std::array<YGDimension, 4> dim = {
+    {YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
+
+static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node,
+                                                  const YGFlexDirection axis,
+                                                  const float widthSize) {
+  return YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(axis, widthSize) +
+      node->getTrailingPaddingAndBorder(axis, widthSize));
+}
+
+static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) {
+  const YGAlign align = child->getStyle().alignSelf == YGAlignAuto
+      ? node->getStyle().alignItems
+      : child->getStyle().alignSelf;
+  if (align == YGAlignBaseline &&
+      YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
+    return YGAlignFlexStart;
+  }
+  return align;
+}
+
+static float YGBaseline(const YGNodeRef node) {
+  if (node->getBaseline() != nullptr) {
+    const float baseline = node->getBaseline()(
+        node,
+        node->getLayout().measuredDimensions[YGDimensionWidth],
+        node->getLayout().measuredDimensions[YGDimensionHeight]);
+    YGAssertWithNode(node,
+                     !YGFloatIsUndefined(baseline),
+                     "Expect custom baseline function to not return NaN");
+    return baseline;
+  }
+
+  YGNodeRef baselineChild = nullptr;
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    if (child->getLineIndex() > 0) {
+      break;
+    }
+    if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
+      baselineChild = child;
+      break;
+    }
+
+    if (baselineChild == nullptr) {
+      baselineChild = child;
+    }
+  }
+
+  if (baselineChild == nullptr) {
+    return node->getLayout().measuredDimensions[YGDimensionHeight];
+  }
+
+  const float baseline = YGBaseline(baselineChild);
+  return baseline + baselineChild->getLayout().position[YGEdgeTop];
+}
+
+static bool YGIsBaselineLayout(const YGNodeRef node) {
+  if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
+    return false;
+  }
+  if (node->getStyle().alignItems == YGAlignBaseline) {
+    return true;
+  }
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = YGNodeGetChild(node, i);
+    if (child->getStyle().positionType == YGPositionTypeRelative &&
+        child->getStyle().alignSelf == YGAlignBaseline) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static inline float YGNodeDimWithMargin(const YGNodeRef node,
+                                        const YGFlexDirection axis,
+                                        const float widthSize) {
+  return node->getLayout().measuredDimensions[dim[axis]] +
+      YGUnwrapFloatOptional(
+             node->getLeadingMargin(axis, widthSize) +
+             node->getTrailingMargin(axis, widthSize));
+}
+
+static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node,
+                                           const YGFlexDirection axis,
+                                           const float ownerSize) {
+  bool isUndefined =
+      YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
+  return !(
+      node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
+      node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
+      (node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
+       !isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
+      (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
+       !isUndefined &&
+       (node->getResolvedDimension(dim[axis]).value < 0.0f ||
+        YGFloatIsUndefined(ownerSize))));
+}
+
+static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) {
+  const float value = node->getLayout().measuredDimensions[dim[axis]];
+  return !YGFloatIsUndefined(value) && value >= 0.0f;
+}
+
+static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
+    const YGNodeRef node,
+    const YGFlexDirection& axis,
+    const float& value,
+    const float& axisSize) {
+  YGFloatOptional min;
+  YGFloatOptional max;
+
+  if (YGFlexDirectionIsColumn(axis)) {
+    min = YGResolveValue(
+        node->getStyle().minDimensions[YGDimensionHeight], axisSize);
+    max = YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
+  } else if (YGFlexDirectionIsRow(axis)) {
+    min = YGResolveValue(
+        node->getStyle().minDimensions[YGDimensionWidth], axisSize);
+    max = YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
+  }
+
+  if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
+    return max;
+  }
+
+  if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
+    return min;
+  }
+
+  return YGFloatOptional(value);
+}
+
+// Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go
+// below the
+// padding and border amount.
+static inline float YGNodeBoundAxis(const YGNodeRef node,
+                                    const YGFlexDirection axis,
+                                    const float value,
+                                    const float axisSize,
+                                    const float widthSize) {
+  return YGFloatMax(
+      YGUnwrapFloatOptional(
+          YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
+      YGNodePaddingAndBorderForAxis(node, axis, widthSize));
+}
+
+static void YGNodeSetChildTrailingPosition(const YGNodeRef node,
+                                           const YGNodeRef child,
+                                           const YGFlexDirection axis) {
+  const float size = child->getLayout().measuredDimensions[dim[axis]];
+  child->setLayoutPosition(
+      node->getLayout().measuredDimensions[dim[axis]] - size -
+          child->getLayout().position[pos[axis]],
+      trailing[axis]);
+}
+
+static void YGConstrainMaxSizeForMode(const YGNodeRef node,
+                                      const enum YGFlexDirection axis,
+                                      const float ownerAxisSize,
+                                      const float ownerWidth,
+                                      YGMeasureMode *mode,
+                                      float *size) {
+  const YGFloatOptional maxSize =
+      YGResolveValue(
+          node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) +
+      YGFloatOptional(node->getMarginForAxis(axis, ownerWidth));
+  switch (*mode) {
+    case YGMeasureModeExactly:
+    case YGMeasureModeAtMost:
+      *size = (maxSize.isUndefined() || *size < maxSize.getValue())
+          ? *size
+          : maxSize.getValue();
+      break;
+    case YGMeasureModeUndefined:
+      if (!maxSize.isUndefined()) {
+        *mode = YGMeasureModeAtMost;
+        *size = maxSize.getValue();
+      }
+      break;
+  }
+}
+
+static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
+                                           const YGNodeRef child,
+                                           const float width,
+                                           const YGMeasureMode widthMode,
+                                           const float height,
+                                           const float ownerWidth,
+                                           const float ownerHeight,
+                                           const YGMeasureMode heightMode,
+                                           const YGDirection direction,
+                                           const YGConfigRef config) {
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const float mainAxisSize = isMainAxisRow ? width : height;
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+
+  float childWidth;
+  float childHeight;
+  YGMeasureMode childWidthMeasureMode;
+  YGMeasureMode childHeightMeasureMode;
+
+  const YGFloatOptional resolvedFlexBasis =
+      YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize);
+  const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth);
+  const bool isColumnStyleDimDefined =
+      YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight);
+
+  if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) {
+    if (child->getLayout().computedFlexBasis.isUndefined() ||
+        (YGConfigIsExperimentalFeatureEnabled(
+             child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
+         child->getLayout().computedFlexBasisGeneration !=
+             gCurrentGenerationCount)) {
+      const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+          YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
+      child->setLayoutComputedFlexBasis(
+          YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
+    }
+  } else if (isMainAxisRow && isRowStyleDimDefined) {
+    // The width is definite, so use that as the flex basis.
+    const YGFloatOptional& paddingAndBorder = YGFloatOptional(
+        YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
+
+    child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
+        YGResolveValue(
+            child->getResolvedDimension(YGDimensionWidth), ownerWidth),
+        paddingAndBorder));
+  } else if (!isMainAxisRow && isColumnStyleDimDefined) {
+    // The height is definite, so use that as the flex basis.
+    const YGFloatOptional& paddingAndBorder =
+        YGFloatOptional(YGNodePaddingAndBorderForAxis(
+            child, YGFlexDirectionColumn, ownerWidth));
+    child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
+        YGResolveValue(
+            child->getResolvedDimension(YGDimensionHeight), ownerHeight),
+        paddingAndBorder));
+  } else {
+    // Compute the flex basis and hypothetical main size (i.e. the clamped
+    // flex basis).
+    childWidth = YGUndefined;
+    childHeight = YGUndefined;
+    childWidthMeasureMode = YGMeasureModeUndefined;
+    childHeightMeasureMode = YGMeasureModeUndefined;
+
+    const float& marginRow = YGUnwrapFloatOptional(
+        child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    const float& marginColumn = YGUnwrapFloatOptional(
+        child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+    if (isRowStyleDimDefined) {
+      childWidth =
+          YGUnwrapFloatOptional(YGResolveValue(
+              child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
+          marginRow;
+      childWidthMeasureMode = YGMeasureModeExactly;
+    }
+    if (isColumnStyleDimDefined) {
+      childHeight =
+          YGUnwrapFloatOptional(YGResolveValue(
+              child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
+          marginColumn;
+      childHeightMeasureMode = YGMeasureModeExactly;
+    }
+
+    // The W3C spec doesn't say anything about the 'overflow' property,
+    // but all major browsers appear to implement the following logic.
+    if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
+        node->getStyle().overflow != YGOverflowScroll) {
+      if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
+        childWidth = width;
+        childWidthMeasureMode = YGMeasureModeAtMost;
+      }
+    }
+
+    if ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
+        node->getStyle().overflow != YGOverflowScroll) {
+      if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
+        childHeight = height;
+        childHeightMeasureMode = YGMeasureModeAtMost;
+      }
+    }
+
+    if (!child->getStyle().aspectRatio.isUndefined()) {
+      if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+        childHeightMeasureMode = YGMeasureModeExactly;
+      } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) *
+                child->getStyle().aspectRatio.getValue();
+        childWidthMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    // If child has no defined size in the cross axis and is set to stretch,
+    // set the cross
+    // axis to be measured exactly with the available inner width
+
+    const bool hasExactWidth = !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
+    const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
+                                   childWidthMeasureMode != YGMeasureModeExactly;
+    if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) {
+      childWidth = width;
+      childWidthMeasureMode = YGMeasureModeExactly;
+      if (!child->getStyle().aspectRatio.isUndefined()) {
+        childHeight =
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+        childHeightMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    const bool hasExactHeight = !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
+    const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch &&
+                                    childHeightMeasureMode != YGMeasureModeExactly;
+    if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) {
+      childHeight = height;
+      childHeightMeasureMode = YGMeasureModeExactly;
+
+      if (!child->getStyle().aspectRatio.isUndefined()) {
+        childWidth = (childHeight - marginColumn) *
+            child->getStyle().aspectRatio.getValue();
+        childWidthMeasureMode = YGMeasureModeExactly;
+      }
+    }
+
+    YGConstrainMaxSizeForMode(
+        child, YGFlexDirectionRow, ownerWidth, ownerWidth, &childWidthMeasureMode, &childWidth);
+    YGConstrainMaxSizeForMode(child,
+                              YGFlexDirectionColumn,
+                              ownerHeight,
+                              ownerWidth,
+                              &childHeightMeasureMode,
+                              &childHeight);
+
+    // Measure the child
+    YGLayoutNodeInternal(child,
+                         childWidth,
+                         childHeight,
+                         direction,
+                         childWidthMeasureMode,
+                         childHeightMeasureMode,
+                         ownerWidth,
+                         ownerHeight,
+                         false,
+                         "measure",
+                         config);
+
+    child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
+        child->getLayout().measuredDimensions[dim[mainAxis]],
+        YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
+  }
+  child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
+}
+
+static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
+                                      const YGNodeRef child,
+                                      const float width,
+                                      const YGMeasureMode widthMode,
+                                      const float height,
+                                      const YGDirection direction,
+                                      const YGConfigRef config) {
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+
+  float childWidth = YGUndefined;
+  float childHeight = YGUndefined;
+  YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
+  YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
+
+  const float& marginRow =
+      YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
+  const float& marginColumn = YGUnwrapFloatOptional(
+      child->getMarginForAxis(YGFlexDirectionColumn, width));
+
+  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
+    childWidth =
+        YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) +
+        marginRow;
+  } else {
+    // If the child doesn't have a specified width, compute the width based
+    // on the left/right
+    // offsets if they're defined.
+    if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
+        child->isTrailingPosDefined(YGFlexDirectionRow)) {
+      childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
+          (node->getLeadingBorder(YGFlexDirectionRow) +
+           node->getTrailingBorder(YGFlexDirectionRow)) -
+          YGUnwrapFloatOptional(
+                       child->getLeadingPosition(YGFlexDirectionRow, width) +
+                       child->getTrailingPosition(YGFlexDirectionRow, width));
+      childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
+    }
+  }
+
+  if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
+    childHeight =
+        YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) +
+        marginColumn;
+  } else {
+    // If the child doesn't have a specified height, compute the height
+    // based on the top/bottom
+    // offsets if they're defined.
+    if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
+        child->isTrailingPosDefined(YGFlexDirectionColumn)) {
+      childHeight =
+          node->getLayout().measuredDimensions[YGDimensionHeight] -
+          (node->getLeadingBorder(YGFlexDirectionColumn) +
+           node->getTrailingBorder(YGFlexDirectionColumn)) -
+          YGUnwrapFloatOptional(
+              child->getLeadingPosition(YGFlexDirectionColumn, height) +
+              child->getTrailingPosition(YGFlexDirectionColumn, height));
+      childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width);
+    }
+  }
+
+  // Exactly one dimension needs to be defined for us to be able to do aspect ratio
+  // calculation. One dimension being the anchor and the other being flexible.
+  if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
+    if (!child->getStyle().aspectRatio.isUndefined()) {
+      if (YGFloatIsUndefined(childWidth)) {
+        childWidth = marginRow +
+            (childHeight - marginColumn) *
+                child->getStyle().aspectRatio.getValue();
+      } else if (YGFloatIsUndefined(childHeight)) {
+        childHeight = marginColumn +
+            (childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
+      }
+    }
+  }
+
+  // If we're still missing one or the other dimension, measure the content.
+  if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
+    childWidthMeasureMode =
+        YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly;
+    childHeightMeasureMode =
+        YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly;
+
+    // If the size of the owner is defined then try to constrain the absolute child to that size
+    // as well. This allows text within the absolute child to wrap to the size of its owner.
+    // This is the same behavior as many browsers implement.
+    if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
+        widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
+        width > 0) {
+      childWidth = width;
+      childWidthMeasureMode = YGMeasureModeAtMost;
+    }
+
+    YGLayoutNodeInternal(child,
+                         childWidth,
+                         childHeight,
+                         direction,
+                         childWidthMeasureMode,
+                         childHeightMeasureMode,
+                         childWidth,
+                         childHeight,
+                         false,
+                         "abs-measure",
+                         config);
+    childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
+        YGUnwrapFloatOptional(
+                     child->getMarginForAxis(YGFlexDirectionRow, width));
+    childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
+        YGUnwrapFloatOptional(
+                      child->getMarginForAxis(YGFlexDirectionColumn, width));
+  }
+
+  YGLayoutNodeInternal(child,
+                       childWidth,
+                       childHeight,
+                       direction,
+                       YGMeasureModeExactly,
+                       YGMeasureModeExactly,
+                       childWidth,
+                       childHeight,
+                       true,
+                       "abs-layout",
+                       config);
+
+  if (child->isTrailingPosDefined(mainAxis) &&
+      !child->isLeadingPositionDefined(mainAxis)) {
+    child->setLayoutPosition(
+        node->getLayout().measuredDimensions[dim[mainAxis]] -
+            child->getLayout().measuredDimensions[dim[mainAxis]] -
+            node->getTrailingBorder(mainAxis) -
+            YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
+            YGUnwrapFloatOptional(child->getTrailingPosition(
+                mainAxis, isMainAxisRow ? width : height)),
+        leading[mainAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(mainAxis) &&
+      node->getStyle().justifyContent == YGJustifyCenter) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[mainAxis]] -
+         child->getLayout().measuredDimensions[dim[mainAxis]]) /
+            2.0f,
+        leading[mainAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(mainAxis) &&
+      node->getStyle().justifyContent == YGJustifyFlexEnd) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[mainAxis]] -
+         child->getLayout().measuredDimensions[dim[mainAxis]]),
+        leading[mainAxis]);
+  }
+
+  if (child->isTrailingPosDefined(crossAxis) &&
+      !child->isLeadingPositionDefined(crossAxis)) {
+    child->setLayoutPosition(
+        node->getLayout().measuredDimensions[dim[crossAxis]] -
+            child->getLayout().measuredDimensions[dim[crossAxis]] -
+            node->getTrailingBorder(crossAxis) -
+            YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
+            YGUnwrapFloatOptional(child->getTrailingPosition(
+                crossAxis, isMainAxisRow ? height : width)),
+        leading[crossAxis]);
+
+  } else if (
+      !child->isLeadingPositionDefined(crossAxis) &&
+      YGNodeAlignItem(node, child) == YGAlignCenter) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[crossAxis]] -
+         child->getLayout().measuredDimensions[dim[crossAxis]]) /
+            2.0f,
+        leading[crossAxis]);
+  } else if (
+      !child->isLeadingPositionDefined(crossAxis) &&
+      ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
+       (node->getStyle().flexWrap == YGWrapWrapReverse))) {
+    child->setLayoutPosition(
+        (node->getLayout().measuredDimensions[dim[crossAxis]] -
+         child->getLayout().measuredDimensions[dim[crossAxis]]),
+        leading[crossAxis]);
+  }
+}
+
+static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
+                                                       const float availableWidth,
+                                                       const float availableHeight,
+                                                       const YGMeasureMode widthMeasureMode,
+                                                       const YGMeasureMode heightMeasureMode,
+                                                       const float ownerWidth,
+                                                       const float ownerHeight) {
+  YGAssertWithNode(
+      node,
+      node->getMeasure() != nullptr,
+      "Expected node to have custom measure function");
+
+  const float paddingAndBorderAxisRow =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
+  const float paddingAndBorderAxisColumn =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth);
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
+
+  // We want to make sure we don't call measure with negative size
+  const float innerWidth = YGFloatIsUndefined(availableWidth)
+      ? availableWidth
+      : YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
+  const float innerHeight = YGFloatIsUndefined(availableHeight)
+      ? availableHeight
+      : YGFloatMax(
+            0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
+
+  if (widthMeasureMode == YGMeasureModeExactly &&
+      heightMeasureMode == YGMeasureModeExactly) {
+    // Don't bother sizing the text if both dimensions are already defined.
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+  } else {
+    // Measure the text under the current constraints.
+    const YGSize measuredSize = node->getMeasure()(
+        node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            (widthMeasureMode == YGMeasureModeUndefined ||
+             widthMeasureMode == YGMeasureModeAtMost)
+                ? measuredSize.width + paddingAndBorderAxisRow
+                : availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            (heightMeasureMode == YGMeasureModeUndefined ||
+             heightMeasureMode == YGMeasureModeAtMost)
+                ? measuredSize.height + paddingAndBorderAxisColumn
+                : availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+  }
+}
+
+// For nodes with no children, use the available values if they were provided,
+// or the minimum size as indicated by the padding and border sizes.
+static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node,
+                                                      const float availableWidth,
+                                                      const float availableHeight,
+                                                      const YGMeasureMode widthMeasureMode,
+                                                      const YGMeasureMode heightMeasureMode,
+                                                      const float ownerWidth,
+                                                      const float ownerHeight) {
+  const float paddingAndBorderAxisRow =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
+  const float paddingAndBorderAxisColumn =
+      YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionRow,
+          (widthMeasureMode == YGMeasureModeUndefined ||
+           widthMeasureMode == YGMeasureModeAtMost)
+              ? paddingAndBorderAxisRow
+              : availableWidth - marginAxisRow,
+          ownerWidth,
+          ownerWidth),
+      YGDimensionWidth);
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionColumn,
+          (heightMeasureMode == YGMeasureModeUndefined ||
+           heightMeasureMode == YGMeasureModeAtMost)
+              ? paddingAndBorderAxisColumn
+              : availableHeight - marginAxisColumn,
+          ownerHeight,
+          ownerWidth),
+      YGDimensionHeight);
+}
+
+static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
+                                                 const float availableWidth,
+                                                 const float availableHeight,
+                                                 const YGMeasureMode widthMeasureMode,
+                                                 const YGMeasureMode heightMeasureMode,
+                                                 const float ownerWidth,
+                                                 const float ownerHeight) {
+  if ((!YGFloatIsUndefined(availableWidth) &&
+       widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
+      (!YGFloatIsUndefined(availableHeight) &&
+       heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
+      (widthMeasureMode == YGMeasureModeExactly &&
+       heightMeasureMode == YGMeasureModeExactly)) {
+    const float& marginAxisColumn = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+    const float& marginAxisRow = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionRow,
+            YGFloatIsUndefined(availableWidth) ||
+                    (widthMeasureMode == YGMeasureModeAtMost &&
+                     availableWidth < 0.0f)
+                ? 0.0f
+                : availableWidth - marginAxisRow,
+            ownerWidth,
+            ownerWidth),
+        YGDimensionWidth);
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            YGFlexDirectionColumn,
+            YGFloatIsUndefined(availableHeight) ||
+                    (heightMeasureMode == YGMeasureModeAtMost &&
+                     availableHeight < 0.0f)
+                ? 0.0f
+                : availableHeight - marginAxisColumn,
+            ownerHeight,
+            ownerWidth),
+        YGDimensionHeight);
+    return true;
+  }
+
+  return false;
+}
+
+static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
+  memset(&(node->getLayout()), 0, sizeof(YGLayout));
+  node->setHasNewLayout(true);
+  node->cloneChildrenIfNeeded();
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    const YGNodeRef child = node->getChild(i);
+    YGZeroOutLayoutRecursivly(child);
+  }
+}
+
+static float YGNodeCalculateAvailableInnerDim(
+    const YGNodeRef node,
+    YGFlexDirection axis,
+    float availableDim,
+    float ownerDim) {
+  YGFlexDirection direction =
+      YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn;
+  YGDimension dimension =
+      YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
+
+  const float margin =
+      YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
+  const float paddingAndBorder =
+      YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
+
+  float availableInnerDim = availableDim - margin - paddingAndBorder;
+  // Max dimension overrides predefined dimension value; Min dimension in turn
+  // overrides both of the above
+  if (!YGFloatIsUndefined(availableInnerDim)) {
+    // We want to make sure our available height does not violate min and max
+    // constraints
+    const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
+    const float minInnerDim = minDimensionOptional.isUndefined()
+        ? 0.0f
+        : minDimensionOptional.getValue() - paddingAndBorder;
+
+    const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim) ;
+
+    const float maxInnerDim = maxDimensionOptional.isUndefined()
+        ? FLT_MAX
+        : maxDimensionOptional.getValue() - paddingAndBorder;
+    availableInnerDim =
+        YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
+  }
+
+  return availableInnerDim;
+}
+
+static void YGNodeComputeFlexBasisForChildren(
+    const YGNodeRef node,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    YGMeasureMode widthMeasureMode,
+    YGMeasureMode heightMeasureMode,
+    YGDirection direction,
+    YGFlexDirection mainAxis,
+    const YGConfigRef config,
+    bool performLayout,
+    float& totalOuterFlexBasis) {
+  YGNodeRef singleFlexChild = nullptr;
+  YGVector children = node->getChildren();
+  YGMeasureMode measureModeMainDim =
+      YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
+  // If there is only one child with flexGrow + flexShrink it means we can set
+  // the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
+  // child to exactly match the remaining space
+  if (measureModeMainDim == YGMeasureModeExactly) {
+    for (auto child : children) {
+      if (singleFlexChild != nullptr) {
+        if (child->isNodeFlexible()) {
+          // There is already a flexible child, abort
+          singleFlexChild = nullptr;
+          break;
+        }
+      } else if (
+          child->resolveFlexGrow() > 0.0f &&
+          child->resolveFlexShrink() > 0.0f) {
+        singleFlexChild = child;
+      }
+    }
+  }
+
+  for (auto child : children) {
+    child->resolveDimension();
+    if (child->getStyle().display == YGDisplayNone) {
+      YGZeroOutLayoutRecursivly(child);
+      child->setHasNewLayout(true);
+      child->setDirty(false);
+      continue;
+    }
+    if (performLayout) {
+      // Set the initial position (relative to the owner).
+      const YGDirection childDirection = child->resolveDirection(direction);
+      const float mainDim = YGFlexDirectionIsRow(mainAxis)
+          ? availableInnerWidth
+          : availableInnerHeight;
+      const float crossDim = YGFlexDirectionIsRow(mainAxis)
+          ? availableInnerHeight
+          : availableInnerWidth;
+      child->setPosition(
+          childDirection, mainDim, crossDim, availableInnerWidth);
+    }
+
+    if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    if (child == singleFlexChild) {
+      child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
+      child->setLayoutComputedFlexBasis(YGFloatOptional(0));
+    } else {
+      YGNodeComputeFlexBasisForChild(
+          node,
+          child,
+          availableInnerWidth,
+          widthMeasureMode,
+          availableInnerHeight,
+          availableInnerWidth,
+          availableInnerHeight,
+          heightMeasureMode,
+          direction,
+          config);
+    }
+
+    totalOuterFlexBasis += YGUnwrapFloatOptional(
+        child->getLayout().computedFlexBasis +
+        child->getMarginForAxis(mainAxis, availableInnerWidth));
+  }
+}
+
+// This function assumes that all the children of node have their
+// computedFlexBasis properly computed(To do this use
+// YGNodeComputeFlexBasisForChildren function).
+// This function calculates YGCollectFlexItemsRowMeasurement
+static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
+    const YGNodeRef& node,
+    const YGDirection ownerDirection,
+    const float mainAxisownerSize,
+    const float availableInnerWidth,
+    const float availableInnerMainDim,
+    const uint32_t startOfLineIndex,
+    const uint32_t lineCount) {
+  YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
+  flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
+
+  float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
+  const YGFlexDirection mainAxis = YGResolveFlexDirection(
+      node->getStyle().flexDirection, node->resolveDirection(ownerDirection));
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  // Add items to the current line until it's full or we run out of items.
+  uint32_t endOfLineIndex = startOfLineIndex;
+  for (; endOfLineIndex < node->getChildrenCount(); endOfLineIndex++) {
+    const YGNodeRef child = node->getChild(endOfLineIndex);
+    if (child->getStyle().display == YGDisplayNone ||
+        child->getStyle().positionType == YGPositionTypeAbsolute) {
+      continue;
+    }
+    child->setLineIndex(lineCount);
+    const float childMarginMainAxis = YGUnwrapFloatOptional(
+        child->getMarginForAxis(mainAxis, availableInnerWidth));
+    const float flexBasisWithMinAndMaxConstraints =
+        YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+            child,
+            mainAxis,
+            YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
+            mainAxisownerSize));
+
+    // If this is a multi-line flow and this item pushes us over the
+    // available size, we've
+    // hit the end of the current line. Break out of the loop and lay out
+    // the current line.
+    if (sizeConsumedOnCurrentLineIncludingMinConstraint +
+                flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
+            availableInnerMainDim &&
+        isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
+      break;
+    }
+
+    sizeConsumedOnCurrentLineIncludingMinConstraint +=
+        flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
+    flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
+        flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
+    flexAlgoRowMeasurement.itemsOnLine++;
+
+    if (child->isNodeFlexible()) {
+      flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
+
+      // Unlike the grow factor, the shrink factor is scaled relative to the
+      // child dimension.
+      flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
+          -child->resolveFlexShrink() *
+          YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
+    }
+
+    flexAlgoRowMeasurement.relativeChildren.push_back(child);
+  }
+
+  // The total flex factor needs to be floored to 1.
+  if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
+      flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
+    flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
+  }
+
+  // The total flex shrink factor needs to be floored to 1.
+  if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
+      flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
+    flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
+  }
+  flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
+  return flexAlgoRowMeasurement;
+}
+
+// It distributes the free space to the flexible items and ensures that the size
+// of the flex items abide the min and max constraints. At the end of this
+// function the child nodes would have proper size. Prior using this function
+// please ensure that YGDistributeFreeSpaceFirstPass is called.
+static float YGDistributeFreeSpaceSecondPass(
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGNodeRef node,
+    const YGFlexDirection mainAxis,
+    const YGFlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool flexBasisOverflows,
+    const YGMeasureMode measureModeCrossDim,
+    const bool performLayout,
+    const YGConfigRef config) {
+  float childFlexBasis = 0;
+  float flexShrinkScaledFactor = 0;
+  float flexGrowFactor = 0;
+  float deltaFreeSpace = 0;
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
+    childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+        currentRelativeChild,
+        mainAxis,
+        YGUnwrapFloatOptional(
+            currentRelativeChild->getLayout().computedFlexBasis),
+        mainAxisownerSize));
+    float updatedMainSize = childFlexBasis;
+
+    if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
+      // Is this child able to shrink?
+      if (flexShrinkScaledFactor != 0) {
+        float childSize;
+
+        if (!YGFloatIsUndefined(
+                collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
+            collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
+          childSize = childFlexBasis + flexShrinkScaledFactor;
+        } else {
+          childSize = childFlexBasis +
+              (collectedFlexItemsValues.remainingFreeSpace /
+               collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
+                  flexShrinkScaledFactor;
+        }
+
+        updatedMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            childSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    } else if (
+        !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace > 0) {
+      flexGrowFactor = currentRelativeChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
+        updatedMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            childFlexBasis +
+                collectedFlexItemsValues.remainingFreeSpace /
+                    collectedFlexItemsValues.totalFlexGrowFactors *
+                    flexGrowFactor,
+            availableInnerMainDim,
+            availableInnerWidth);
+      }
+    }
+
+    deltaFreeSpace += updatedMainSize - childFlexBasis;
+
+    const float marginMain = YGUnwrapFloatOptional(
+        currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
+    const float marginCross = YGUnwrapFloatOptional(
+        currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
+
+    float childCrossSize;
+    float childMainSize = updatedMainSize + marginMain;
+    YGMeasureMode childCrossMeasureMode;
+    YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
+
+    if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
+      childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
+              currentRelativeChild->getStyle().aspectRatio.getValue()
+                                     : (childMainSize - marginMain) *
+              currentRelativeChild->getStyle().aspectRatio.getValue();
+      childCrossMeasureMode = YGMeasureModeExactly;
+
+      childCrossSize += marginCross;
+    } else if (
+        !YGFloatIsUndefined(availableInnerCrossDim) &&
+        !YGNodeIsStyleDimDefined(
+            currentRelativeChild, crossAxis, availableInnerCrossDim) &&
+        measureModeCrossDim == YGMeasureModeExactly &&
+        !(isNodeFlexWrap && flexBasisOverflows) &&
+        YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
+        currentRelativeChild->marginLeadingValue(crossAxis).unit !=
+            YGUnitAuto &&
+        currentRelativeChild->marginTrailingValue(crossAxis).unit !=
+            YGUnitAuto) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossMeasureMode = YGMeasureModeExactly;
+    } else if (!YGNodeIsStyleDimDefined(
+                   currentRelativeChild, crossAxis, availableInnerCrossDim)) {
+      childCrossSize = availableInnerCrossDim;
+      childCrossMeasureMode = YGFloatIsUndefined(childCrossSize)
+          ? YGMeasureModeUndefined
+          : YGMeasureModeAtMost;
+    } else {
+      childCrossSize =
+          YGUnwrapFloatOptional(YGResolveValue(
+              currentRelativeChild->getResolvedDimension(dim[crossAxis]),
+              availableInnerCrossDim)) +
+          marginCross;
+      const bool isLoosePercentageMeasurement =
+          currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
+              YGUnitPercent &&
+          measureModeCrossDim != YGMeasureModeExactly;
+      childCrossMeasureMode =
+          YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
+          ? YGMeasureModeUndefined
+          : YGMeasureModeExactly;
+    }
+
+    YGConstrainMaxSizeForMode(
+        currentRelativeChild,
+        mainAxis,
+        availableInnerMainDim,
+        availableInnerWidth,
+        &childMainMeasureMode,
+        &childMainSize);
+    YGConstrainMaxSizeForMode(
+        currentRelativeChild,
+        crossAxis,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        &childCrossMeasureMode,
+        &childCrossSize);
+
+    const bool requiresStretchLayout =
+        !YGNodeIsStyleDimDefined(
+            currentRelativeChild, crossAxis, availableInnerCrossDim) &&
+        YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
+        currentRelativeChild->marginLeadingValue(crossAxis).unit !=
+            YGUnitAuto &&
+        currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
+
+    const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
+    const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
+
+    const YGMeasureMode childWidthMeasureMode =
+        isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
+    const YGMeasureMode childHeightMeasureMode =
+        !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
+
+    // Recursively call the layout algorithm for this child with the updated
+    // main size.
+    YGLayoutNodeInternal(
+        currentRelativeChild,
+        childWidth,
+        childHeight,
+        node->getLayout().direction,
+        childWidthMeasureMode,
+        childHeightMeasureMode,
+        availableInnerWidth,
+        availableInnerHeight,
+        performLayout && !requiresStretchLayout,
+        "flex",
+        config);
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow |
+        currentRelativeChild->getLayout().hadOverflow);
+  }
+  return deltaFreeSpace;
+}
+
+// It distributes the free space to the flexible items.For those flexible items
+// whose min and max constraints are triggered, those flex item's clamped size
+// is removed from the remaingfreespace.
+static void YGDistributeFreeSpaceFirstPass(
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGFlexDirection mainAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerWidth) {
+  float flexShrinkScaledFactor = 0;
+  float flexGrowFactor = 0;
+  float baseMainSize = 0;
+  float boundMainSize = 0;
+  float deltaFreeSpace = 0;
+
+  for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
+    float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+        currentRelativeChild,
+        mainAxis,
+        YGUnwrapFloatOptional(
+            currentRelativeChild->getLayout().computedFlexBasis),
+        mainAxisownerSize));
+
+    if (collectedFlexItemsValues.remainingFreeSpace < 0) {
+      flexShrinkScaledFactor =
+          -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
+
+      // Is this child able to shrink?
+      if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
+          flexShrinkScaledFactor != 0) {
+        baseMainSize = childFlexBasis +
+            collectedFlexItemsValues.remainingFreeSpace /
+                collectedFlexItemsValues.totalFlexShrinkScaledFactors *
+                flexShrinkScaledFactor;
+        boundMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+        if (!YGFloatIsUndefined(baseMainSize) &&
+            !YGFloatIsUndefined(boundMainSize) &&
+            baseMainSize != boundMainSize) {
+          // By excluding this item's size and flex factor from remaining,
+          // this item's
+          // min/max constraints should also trigger in the second pass
+          // resulting in the
+          // item's size calculation being identical in the first and second
+          // passes.
+          deltaFreeSpace += boundMainSize - childFlexBasis;
+          collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
+              flexShrinkScaledFactor;
+        }
+      }
+    } else if (
+        !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
+        collectedFlexItemsValues.remainingFreeSpace > 0) {
+      flexGrowFactor = currentRelativeChild->resolveFlexGrow();
+
+      // Is this child able to grow?
+      if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
+        baseMainSize = childFlexBasis +
+            collectedFlexItemsValues.remainingFreeSpace /
+                collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
+        boundMainSize = YGNodeBoundAxis(
+            currentRelativeChild,
+            mainAxis,
+            baseMainSize,
+            availableInnerMainDim,
+            availableInnerWidth);
+
+        if (!YGFloatIsUndefined(baseMainSize) &&
+            !YGFloatIsUndefined(boundMainSize) &&
+            baseMainSize != boundMainSize) {
+          // By excluding this item's size and flex factor from remaining,
+          // this item's
+          // min/max constraints should also trigger in the second pass
+          // resulting in the
+          // item's size calculation being identical in the first and second
+          // passes.
+          deltaFreeSpace += boundMainSize - childFlexBasis;
+          collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
+        }
+      }
+    }
+  }
+  collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
+}
+
+// Do two passes over the flex items to figure out how to distribute the
+// remaining space.
+// The first pass finds the items whose min/max constraints trigger,
+// freezes them at those
+// sizes, and excludes those sizes from the remaining space. The second
+// pass sets the size
+// of each flexible item. It distributes the remaining space amongst the
+// items whose min/max
+// constraints didn't trigger in pass 1. For the other items, it sets
+// their sizes by forcing
+// their min/max constraints to trigger again.
+//
+// This two pass approach for resolving min/max constraints deviates from
+// the spec. The
+// spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
+// describes a process
+// that needs to be repeated a variable number of times. The algorithm
+// implemented here
+// won't handle all cases but it was simpler to implement and it mitigates
+// performance
+// concerns because we know exactly how many passes it'll do.
+//
+// At the end of this function the child nodes would have the proper size
+// assigned to them.
+//
+static void YGResolveFlexibleLength(
+    const YGNodeRef node,
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const YGFlexDirection mainAxis,
+    const YGFlexDirection crossAxis,
+    const float mainAxisownerSize,
+    const float availableInnerMainDim,
+    const float availableInnerCrossDim,
+    const float availableInnerWidth,
+    const float availableInnerHeight,
+    const bool flexBasisOverflows,
+    const YGMeasureMode measureModeCrossDim,
+    const bool performLayout,
+    const YGConfigRef config) {
+  const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
+  // First pass: detect the flex items whose min/max constraints trigger
+  YGDistributeFreeSpaceFirstPass(
+      collectedFlexItemsValues,
+      mainAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerWidth);
+
+  // Second pass: resolve the sizes of the flexible items
+  const float distributedFreeSpace = YGDistributeFreeSpaceSecondPass(
+      collectedFlexItemsValues,
+      node,
+      mainAxis,
+      crossAxis,
+      mainAxisownerSize,
+      availableInnerMainDim,
+      availableInnerCrossDim,
+      availableInnerWidth,
+      availableInnerHeight,
+      flexBasisOverflows,
+      measureModeCrossDim,
+      performLayout,
+      config);
+
+  collectedFlexItemsValues.remainingFreeSpace =
+      originalFreeSpace - distributedFreeSpace;
+}
+
+static void YGJustifyMainAxis(
+    const YGNodeRef node,
+    YGCollectFlexItemsRowValues& collectedFlexItemsValues,
+    const uint32_t& startOfLineIndex,
+    const YGFlexDirection& mainAxis,
+    const YGFlexDirection& crossAxis,
+    const YGMeasureMode& measureModeMainDim,
+    const YGMeasureMode& measureModeCrossDim,
+    const float& mainAxisownerSize,
+    const float& ownerWidth,
+    const float& availableInnerMainDim,
+    const float& availableInnerCrossDim,
+    const float& availableInnerWidth,
+    const bool& performLayout) {
+  const YGStyle style = node->getStyle();
+
+  // If we are using "at most" rules in the main axis. Calculate the remaining
+  // space when constraint by the min size defined for the main axis.
+  if (measureModeMainDim == YGMeasureModeAtMost &&
+      collectedFlexItemsValues.remainingFreeSpace > 0) {
+    if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
+        !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
+             .isUndefined()) {
+      collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
+          0,
+          YGUnwrapFloatOptional(YGResolveValue(
+              style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
+              (availableInnerMainDim -
+               collectedFlexItemsValues.remainingFreeSpace));
+    } else {
+      collectedFlexItemsValues.remainingFreeSpace = 0;
+    }
+  }
+
+  int numberOfAutoMarginsOnCurrentLine = 0;
+  for (uint32_t i = startOfLineIndex;
+       i < collectedFlexItemsValues.endOfLineIndex;
+       i++) {
+    const YGNodeRef child = node->getChild(i);
+    if (child->getStyle().positionType == YGPositionTypeRelative) {
+      if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
+        numberOfAutoMarginsOnCurrentLine++;
+      }
+      if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
+        numberOfAutoMarginsOnCurrentLine++;
+      }
+    }
+  }
+
+  // In order to position the elements in the main axis, we have two
+  // controls. The space between the beginning and the first element
+  // and the space between each two elements.
+  float leadingMainDim = 0;
+  float betweenMainDim = 0;
+  const YGJustify justifyContent = node->getStyle().justifyContent;
+
+  if (numberOfAutoMarginsOnCurrentLine == 0) {
+    switch (justifyContent) {
+      case YGJustifyCenter:
+        leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
+        break;
+      case YGJustifyFlexEnd:
+        leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
+        break;
+      case YGJustifySpaceBetween:
+        if (collectedFlexItemsValues.itemsOnLine > 1) {
+          betweenMainDim =
+              YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
+              (collectedFlexItemsValues.itemsOnLine - 1);
+        } else {
+          betweenMainDim = 0;
+        }
+        break;
+      case YGJustifySpaceEvenly:
+        // Space is distributed evenly across all elements
+        betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
+            (collectedFlexItemsValues.itemsOnLine + 1);
+        leadingMainDim = betweenMainDim;
+        break;
+      case YGJustifySpaceAround:
+        // Space on the edges is half of the space between elements
+        betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
+            collectedFlexItemsValues.itemsOnLine;
+        leadingMainDim = betweenMainDim / 2;
+        break;
+      case YGJustifyFlexStart:
+        break;
+    }
+  }
+
+  const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
+  collectedFlexItemsValues.mainDim =
+      leadingPaddingAndBorderMain + leadingMainDim;
+  collectedFlexItemsValues.crossDim = 0;
+
+  for (uint32_t i = startOfLineIndex;
+       i < collectedFlexItemsValues.endOfLineIndex;
+       i++) {
+    const YGNodeRef child = node->getChild(i);
+    const YGStyle childStyle = child->getStyle();
+    const YGLayout childLayout = child->getLayout();
+    if (childStyle.display == YGDisplayNone) {
+      continue;
+    }
+    if (childStyle.positionType == YGPositionTypeAbsolute &&
+        child->isLeadingPositionDefined(mainAxis)) {
+      if (performLayout) {
+        // In case the child is position absolute and has left/top being
+        // defined, we override the position to whatever the user said
+        // (and margin/border).
+        child->setLayoutPosition(
+            YGUnwrapFloatOptional(
+                child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
+                node->getLeadingBorder(mainAxis) +
+                YGUnwrapFloatOptional(
+                    child->getLeadingMargin(mainAxis, availableInnerWidth)),
+            pos[mainAxis]);
+      }
+    } else {
+      // Now that we placed the element, we need to update the variables.
+      // We need to do that only for relative elements. Absolute elements
+      // do not take part in that phase.
+      if (childStyle.positionType == YGPositionTypeRelative) {
+        if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
+          collectedFlexItemsValues.mainDim +=
+              collectedFlexItemsValues.remainingFreeSpace /
+              numberOfAutoMarginsOnCurrentLine;
+        }
+
+        if (performLayout) {
+          child->setLayoutPosition(
+              childLayout.position[pos[mainAxis]] +
+                  collectedFlexItemsValues.mainDim,
+              pos[mainAxis]);
+        }
+
+        if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
+          collectedFlexItemsValues.mainDim +=
+              collectedFlexItemsValues.remainingFreeSpace /
+              numberOfAutoMarginsOnCurrentLine;
+        }
+        bool canSkipFlex =
+            !performLayout && measureModeCrossDim == YGMeasureModeExactly;
+        if (canSkipFlex) {
+          // If we skipped the flex step, then we can't rely on the
+          // measuredDims because
+          // they weren't computed. This means we can't call
+          // YGNodeDimWithMargin.
+          collectedFlexItemsValues.mainDim += betweenMainDim +
+              YGUnwrapFloatOptional(child->getMarginForAxis(
+                  mainAxis, availableInnerWidth)) +
+              YGUnwrapFloatOptional(childLayout.computedFlexBasis);
+          collectedFlexItemsValues.crossDim = availableInnerCrossDim;
+        } else {
+          // The main dimension is the sum of all the elements dimension plus
+          // the spacing.
+          collectedFlexItemsValues.mainDim += betweenMainDim +
+              YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
+
+          // The cross dimension is the max of the elements dimension since
+          // there can only be one element in that cross dimension.
+          collectedFlexItemsValues.crossDim = YGFloatMax(
+              collectedFlexItemsValues.crossDim,
+              YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
+        }
+      } else if (performLayout) {
+        child->setLayoutPosition(
+            childLayout.position[pos[mainAxis]] +
+                node->getLeadingBorder(mainAxis) + leadingMainDim,
+            pos[mainAxis]);
+      }
+    }
+  }
+  collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional(
+      node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
+}
+
+//
+// This is the main routine that implements a subset of the flexbox layout
+// algorithm
+// described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
+//
+// Limitations of this algorithm, compared to the full standard:
+//  * Display property is always assumed to be 'flex' except for Text nodes,
+//  which
+//    are assumed to be 'inline-flex'.
+//  * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
+//  are
+//    stacked in document order.
+//  * The 'order' property is not supported. The order of flex items is always
+//  defined
+//    by document order.
+//  * The 'visibility' property is always assumed to be 'visible'. Values of
+//  'collapse'
+//    and 'hidden' are not supported.
+//  * There is no support for forced breaks.
+//  * It does not support vertical inline directions (top-to-bottom or
+//  bottom-to-top text).
+//
+// Deviations from standard:
+//  * Section 4.5 of the spec indicates that all flex items have a default
+//  minimum
+//    main size. For text blocks, for example, this is the width of the widest
+//    word.
+//    Calculating the minimum width is expensive, so we forego it and assume a
+//    default
+//    minimum main size of 0.
+//  * Min/Max sizes in the main axis are not honored when resolving flexible
+//  lengths.
+//  * The spec indicates that the default value for 'flexDirection' is 'row',
+//  but
+//    the algorithm below assumes a default of 'column'.
+//
+// Input parameters:
+//    - node: current node to be sized and layed out
+//    - availableWidth & availableHeight: available size to be used for sizing
+//    the node
+//      or YGUndefined if the size is not available; interpretation depends on
+//      layout
+//      flags
+//    - ownerDirection: the inline (text) direction within the owner
+//    (left-to-right or
+//      right-to-left)
+//    - widthMeasureMode: indicates the sizing rules for the width (see below
+//    for explanation)
+//    - heightMeasureMode: indicates the sizing rules for the height (see below
+//    for explanation)
+//    - performLayout: specifies whether the caller is interested in just the
+//    dimensions
+//      of the node or it requires the entire node and its subtree to be layed
+//      out
+//      (with final positions)
+//
+// Details:
+//    This routine is called recursively to lay out subtrees of flexbox
+//    elements. It uses the
+//    information in node.style, which is treated as a read-only input. It is
+//    responsible for
+//    setting the layout.direction and layout.measuredDimensions fields for the
+//    input node as well
+//    as the layout.position and layout.lineIndex fields for its child nodes.
+//    The
+//    layout.measuredDimensions field includes any border or padding for the
+//    node but does
+//    not include margins.
+//
+//    The spec describes four different layout modes: "fill available", "max
+//    content", "min
+//    content",
+//    and "fit content". Of these, we don't use "min content" because we don't
+//    support default
+//    minimum main sizes (see above for details). Each of our measure modes maps
+//    to a layout mode
+//    from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
+//      - YGMeasureModeUndefined: max content
+//      - YGMeasureModeExactly: fill available
+//      - YGMeasureModeAtMost: fit content
+//
+//    When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller passes
+//    an available size of
+//    undefined then it must also pass a measure mode of YGMeasureModeUndefined
+//    in that dimension.
+//
+static void YGNodelayoutImpl(const YGNodeRef node,
+                             const float availableWidth,
+                             const float availableHeight,
+                             const YGDirection ownerDirection,
+                             const YGMeasureMode widthMeasureMode,
+                             const YGMeasureMode heightMeasureMode,
+                             const float ownerWidth,
+                             const float ownerHeight,
+                             const bool performLayout,
+                             const YGConfigRef config) {
+  YGAssertWithNode(node,
+                   YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined
+                                                      : true,
+                   "availableWidth is indefinite so widthMeasureMode must be "
+                   "YGMeasureModeUndefined");
+  YGAssertWithNode(node,
+                   YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined
+                                                       : true,
+                   "availableHeight is indefinite so heightMeasureMode must be "
+                   "YGMeasureModeUndefined");
+
+  // Set the resolved resolution in the node's layout.
+  const YGDirection direction = node->resolveDirection(ownerDirection);
+  node->setLayoutDirection(direction);
+
+  const YGFlexDirection flexRowDirection = YGResolveFlexDirection(YGFlexDirectionRow, direction);
+  const YGFlexDirection flexColumnDirection =
+      YGResolveFlexDirection(YGFlexDirectionColumn, direction);
+
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getLeadingMargin(flexRowDirection, ownerWidth)),
+      YGEdgeStart);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getTrailingMargin(flexRowDirection, ownerWidth)),
+      YGEdgeEnd);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getLeadingMargin(flexColumnDirection, ownerWidth)),
+      YGEdgeTop);
+  node->setLayoutMargin(
+      YGUnwrapFloatOptional(
+          node->getTrailingMargin(flexColumnDirection, ownerWidth)),
+      YGEdgeBottom);
+
+  node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
+  node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd);
+  node->setLayoutBorder(node->getLeadingBorder(flexColumnDirection), YGEdgeTop);
+  node->setLayoutBorder(
+      node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
+
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getLeadingPadding(flexRowDirection, ownerWidth)),
+      YGEdgeStart);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getTrailingPadding(flexRowDirection, ownerWidth)),
+      YGEdgeEnd);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getLeadingPadding(flexColumnDirection, ownerWidth)),
+      YGEdgeTop);
+  node->setLayoutPadding(
+      YGUnwrapFloatOptional(
+          node->getTrailingPadding(flexColumnDirection, ownerWidth)),
+      YGEdgeBottom);
+
+  if (node->getMeasure() != nullptr) {
+    YGNodeWithMeasureFuncSetMeasuredDimensions(node,
+                                               availableWidth,
+                                               availableHeight,
+                                               widthMeasureMode,
+                                               heightMeasureMode,
+                                               ownerWidth,
+                                               ownerHeight);
+    return;
+  }
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  if (childCount == 0) {
+    YGNodeEmptyContainerSetMeasuredDimensions(node,
+                                              availableWidth,
+                                              availableHeight,
+                                              widthMeasureMode,
+                                              heightMeasureMode,
+                                              ownerWidth,
+                                              ownerHeight);
+    return;
+  }
+
+  // If we're not being asked to perform a full layout we can skip the algorithm if we already know
+  // the size
+  if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions(node,
+                                                             availableWidth,
+                                                             availableHeight,
+                                                             widthMeasureMode,
+                                                             heightMeasureMode,
+                                                             ownerWidth,
+                                                             ownerHeight)) {
+    return;
+  }
+
+  // At this point we know we're going to perform work. Ensure that each child has a mutable copy.
+  node->cloneChildrenIfNeeded();
+  // Reset layout flags, as they could have changed.
+  node->setLayoutHadOverflow(false);
+
+  // STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
+  const YGFlexDirection mainAxis =
+      YGResolveFlexDirection(node->getStyle().flexDirection, direction);
+  const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
+  const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
+  const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
+
+  const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
+  const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
+
+  const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
+      node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
+  const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
+  const float paddingAndBorderAxisCross =
+      YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth);
+
+  YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
+  YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
+
+  const float paddingAndBorderAxisRow =
+      isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
+  const float paddingAndBorderAxisColumn =
+      isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
+
+  const float marginAxisRow = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+  const float marginAxisColumn = YGUnwrapFloatOptional(
+      node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+  const float minInnerWidth =
+      YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
+      paddingAndBorderAxisRow;
+  const float maxInnerWidth =
+      YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
+      paddingAndBorderAxisRow;
+  const float minInnerHeight =
+      YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
+      paddingAndBorderAxisColumn;
+  const float maxInnerHeight =
+      YGUnwrapFloatOptional(YGResolveValue(
+          node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
+      paddingAndBorderAxisColumn;
+
+  const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
+  const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
+
+  // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
+
+  float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
+      node, YGFlexDirectionRow, availableWidth, ownerWidth);
+  float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
+      node, YGFlexDirectionColumn, availableHeight, ownerHeight);
+
+  float availableInnerMainDim =
+      isMainAxisRow ? availableInnerWidth : availableInnerHeight;
+  const float availableInnerCrossDim =
+      isMainAxisRow ? availableInnerHeight : availableInnerWidth;
+
+  float totalOuterFlexBasis = 0;
+
+  // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
+
+  YGNodeComputeFlexBasisForChildren(
+      node,
+      availableInnerWidth,
+      availableInnerHeight,
+      widthMeasureMode,
+      heightMeasureMode,
+      direction,
+      mainAxis,
+      config,
+      performLayout,
+      totalOuterFlexBasis);
+
+  const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
+      ? false
+      : totalOuterFlexBasis > availableInnerMainDim;
+  if (isNodeFlexWrap && flexBasisOverflows &&
+      measureModeMainDim == YGMeasureModeAtMost) {
+    measureModeMainDim = YGMeasureModeExactly;
+  }
+  // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
+
+  // Indexes of children that represent the first and last items in the line.
+  uint32_t startOfLineIndex = 0;
+  uint32_t endOfLineIndex = 0;
+
+  // Number of lines.
+  uint32_t lineCount = 0;
+
+  // Accumulated cross dimensions of all lines so far.
+  float totalLineCrossDim = 0;
+
+  // Max main dimension of all the lines.
+  float maxLineMainDim = 0;
+  YGCollectFlexItemsRowValues collectedFlexItemsValues;
+  for (; endOfLineIndex < childCount;
+       lineCount++, startOfLineIndex = endOfLineIndex) {
+    collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
+        node,
+        ownerDirection,
+        mainAxisownerSize,
+        availableInnerWidth,
+        availableInnerMainDim,
+        startOfLineIndex,
+        lineCount);
+    endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
+
+    // If we don't need to measure the cross axis, we can skip the entire flex
+    // step.
+    const bool canSkipFlex =
+        !performLayout && measureModeCrossDim == YGMeasureModeExactly;
+
+    // STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
+    // Calculate the remaining available space that needs to be allocated.
+    // If the main dimension size isn't known, it is computed based on
+    // the line length, so there's no more space left to distribute.
+
+    bool sizeBasedOnContent = false;
+    // If we don't measure with exact main dimension we want to ensure we don't violate min and max
+    if (measureModeMainDim != YGMeasureModeExactly) {
+      if (!YGFloatIsUndefined(minInnerMainDim) &&
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine <
+              minInnerMainDim) {
+        availableInnerMainDim = minInnerMainDim;
+      } else if (
+          !YGFloatIsUndefined(maxInnerMainDim) &&
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine >
+              maxInnerMainDim) {
+        availableInnerMainDim = maxInnerMainDim;
+      } else {
+        if (!node->getConfig()->useLegacyStretchBehaviour &&
+            ((YGFloatIsUndefined(
+                  collectedFlexItemsValues.totalFlexGrowFactors) &&
+              collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
+             (YGFloatIsUndefined(node->resolveFlexGrow()) &&
+              node->resolveFlexGrow() == 0))) {
+          // If we don't have any children to flex or we can't flex the node
+          // itself, space we've used is all space we need. Root node also
+          // should be shrunk to minimum
+          availableInnerMainDim =
+              collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+        }
+
+        if (node->getConfig()->useLegacyStretchBehaviour) {
+          node->setLayoutDidUseLegacyFlag(true);
+        }
+        sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
+      }
+    }
+
+    if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
+      collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
+          collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+    } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
+      // availableInnerMainDim is indefinite which means the node is being sized based on its
+      // content.
+      // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
+      // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
+      collectedFlexItemsValues.remainingFreeSpace =
+          -collectedFlexItemsValues.sizeConsumedOnCurrentLine;
+    }
+
+    if (!canSkipFlex) {
+      YGResolveFlexibleLength(
+          node,
+          collectedFlexItemsValues,
+          mainAxis,
+          crossAxis,
+          mainAxisownerSize,
+          availableInnerMainDim,
+          availableInnerCrossDim,
+          availableInnerWidth,
+          availableInnerHeight,
+          flexBasisOverflows,
+          measureModeCrossDim,
+          performLayout,
+          config);
+    }
+
+    node->setLayoutHadOverflow(
+        node->getLayout().hadOverflow |
+        (collectedFlexItemsValues.remainingFreeSpace < 0));
+
+    // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
+
+    // At this point, all the children have their dimensions set in the main
+    // axis.
+    // Their dimensions are also set in the cross axis with the exception of
+    // items
+    // that are aligned "stretch". We need to compute these stretch values and
+    // set the final positions.
+
+    YGJustifyMainAxis(
+        node,
+        collectedFlexItemsValues,
+        startOfLineIndex,
+        mainAxis,
+        crossAxis,
+        measureModeMainDim,
+        measureModeCrossDim,
+        mainAxisownerSize,
+        ownerWidth,
+        availableInnerMainDim,
+        availableInnerCrossDim,
+        availableInnerWidth,
+        performLayout);
+
+    float containerCrossAxis = availableInnerCrossDim;
+    if (measureModeCrossDim == YGMeasureModeUndefined ||
+        measureModeCrossDim == YGMeasureModeAtMost) {
+      // Compute the cross axis from the max cross dimension of the children.
+      containerCrossAxis =
+          YGNodeBoundAxis(
+              node,
+              crossAxis,
+              collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
+              crossAxisownerSize,
+              ownerWidth) -
+          paddingAndBorderAxisCross;
+    }
+
+    // If there's no flex wrap, the cross dimension is defined by the container.
+    if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
+      collectedFlexItemsValues.crossDim = availableInnerCrossDim;
+    }
+
+    // Clamp to the min/max size specified on the container.
+    collectedFlexItemsValues.crossDim =
+        YGNodeBoundAxis(
+            node,
+            crossAxis,
+            collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
+            crossAxisownerSize,
+            ownerWidth) -
+        paddingAndBorderAxisCross;
+
+    // STEP 7: CROSS-AXIS ALIGNMENT
+    // We can skip child alignment if we're just measuring the container.
+    if (performLayout) {
+      for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
+        const YGNodeRef child = node->getChild(i);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (child->getStyle().positionType == YGPositionTypeAbsolute) {
+          // If the child is absolutely positioned and has a
+          // top/left/bottom/right set, override
+          // all the previously computed positions to set it correctly.
+          const bool isChildLeadingPosDefined =
+              child->isLeadingPositionDefined(crossAxis);
+          if (isChildLeadingPosDefined) {
+            child->setLayoutPosition(
+                YGUnwrapFloatOptional(child->getLeadingPosition(
+                    crossAxis, availableInnerCrossDim)) +
+                    node->getLeadingBorder(crossAxis) +
+                    YGUnwrapFloatOptional(child->getLeadingMargin(
+                        crossAxis, availableInnerWidth)),
+                pos[crossAxis]);
+          }
+          // If leading position is not defined or calculations result in Nan, default to border + margin
+          if (!isChildLeadingPosDefined ||
+              YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
+            child->setLayoutPosition(
+                node->getLeadingBorder(crossAxis) +
+                    YGUnwrapFloatOptional(child->getLeadingMargin(
+                        crossAxis, availableInnerWidth)),
+                pos[crossAxis]);
+          }
+        } else {
+          float leadingCrossDim = leadingPaddingAndBorderCross;
+
+          // For a relative children, we're either using alignItems (owner) or
+          // alignSelf (child) in order to determine the position in the cross
+          // axis
+          const YGAlign alignItem = YGNodeAlignItem(node, child);
+
+          // If the child uses align stretch, we need to lay it out one more
+          // time, this time
+          // forcing the cross-axis size to be the computed cross size for the
+          // current line.
+          if (alignItem == YGAlignStretch &&
+              child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
+              child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
+            // If the child defines a definite size for its cross axis, there's
+            // no need to stretch.
+            if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
+              float childMainSize =
+                  child->getLayout().measuredDimensions[dim[mainAxis]];
+              float childCrossSize =
+                  !child->getStyle().aspectRatio.isUndefined()
+                  ? ((YGUnwrapFloatOptional(child->getMarginForAxis(
+                          crossAxis, availableInnerWidth)) +
+                      (isMainAxisRow ? childMainSize /
+                               child->getStyle().aspectRatio.getValue()
+                                     : childMainSize *
+                               child->getStyle().aspectRatio.getValue())))
+                  : collectedFlexItemsValues.crossDim;
+
+              childMainSize += YGUnwrapFloatOptional(
+                  child->getMarginForAxis(mainAxis, availableInnerWidth));
+
+              YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
+              YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
+              YGConstrainMaxSizeForMode(child,
+                                        mainAxis,
+                                        availableInnerMainDim,
+                                        availableInnerWidth,
+                                        &childMainMeasureMode,
+                                        &childMainSize);
+              YGConstrainMaxSizeForMode(child,
+                                        crossAxis,
+                                        availableInnerCrossDim,
+                                        availableInnerWidth,
+                                        &childCrossMeasureMode,
+                                        &childCrossSize);
+
+              const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
+              const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
+
+              const YGMeasureMode childWidthMeasureMode =
+                  YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined
+                                                 : YGMeasureModeExactly;
+              const YGMeasureMode childHeightMeasureMode =
+                  YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined
+                                                  : YGMeasureModeExactly;
+
+              YGLayoutNodeInternal(
+                  child,
+                  childWidth,
+                  childHeight,
+                  direction,
+                  childWidthMeasureMode,
+                  childHeightMeasureMode,
+                  availableInnerWidth,
+                  availableInnerHeight,
+                  true,
+                  "stretch",
+                  config);
+            }
+          } else {
+            const float remainingCrossDim = containerCrossAxis -
+                YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
+
+            if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
+                child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
+              leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
+            } else if (
+                child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
+              // No-Op
+            } else if (
+                child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
+              leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
+            } else if (alignItem == YGAlignFlexStart) {
+              // No-Op
+            } else if (alignItem == YGAlignCenter) {
+              leadingCrossDim += remainingCrossDim / 2;
+            } else {
+              leadingCrossDim += remainingCrossDim;
+            }
+          }
+          // And we apply the position
+          child->setLayoutPosition(
+              child->getLayout().position[pos[crossAxis]] + totalLineCrossDim +
+                  leadingCrossDim,
+              pos[crossAxis]);
+        }
+      }
+    }
+
+    totalLineCrossDim += collectedFlexItemsValues.crossDim;
+    maxLineMainDim =
+        YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
+  }
+
+  // STEP 8: MULTI-LINE CONTENT ALIGNMENT
+  if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
+      !YGFloatIsUndefined(availableInnerCrossDim)) {
+    const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
+
+    float crossDimLead = 0;
+    float currentLead = leadingPaddingAndBorderCross;
+
+    switch (node->getStyle().alignContent) {
+      case YGAlignFlexEnd:
+        currentLead += remainingAlignContentDim;
+        break;
+      case YGAlignCenter:
+        currentLead += remainingAlignContentDim / 2;
+        break;
+      case YGAlignStretch:
+        if (availableInnerCrossDim > totalLineCrossDim) {
+          crossDimLead = remainingAlignContentDim / lineCount;
+        }
+        break;
+      case YGAlignSpaceAround:
+        if (availableInnerCrossDim > totalLineCrossDim) {
+          currentLead += remainingAlignContentDim / (2 * lineCount);
+          if (lineCount > 1) {
+            crossDimLead = remainingAlignContentDim / lineCount;
+          }
+        } else {
+          currentLead += remainingAlignContentDim / 2;
+        }
+        break;
+      case YGAlignSpaceBetween:
+        if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
+          crossDimLead = remainingAlignContentDim / (lineCount - 1);
+        }
+        break;
+      case YGAlignAuto:
+      case YGAlignFlexStart:
+      case YGAlignBaseline:
+        break;
+    }
+
+    uint32_t endIndex = 0;
+    for (uint32_t i = 0; i < lineCount; i++) {
+      const uint32_t startIndex = endIndex;
+      uint32_t ii;
+
+      // compute the line's height and find the endIndex
+      float lineHeight = 0;
+      float maxAscentForCurrentLine = 0;
+      float maxDescentForCurrentLine = 0;
+      for (ii = startIndex; ii < childCount; ii++) {
+        const YGNodeRef child = node->getChild(ii);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (child->getStyle().positionType == YGPositionTypeRelative) {
+          if (child->getLineIndex() != i) {
+            break;
+          }
+          if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
+            lineHeight = YGFloatMax(
+                lineHeight,
+                child->getLayout().measuredDimensions[dim[crossAxis]] +
+                    YGUnwrapFloatOptional(child->getMarginForAxis(
+                        crossAxis, availableInnerWidth)));
+          }
+          if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
+            const float ascent = YGBaseline(child) +
+                YGUnwrapFloatOptional(child->getLeadingMargin(
+                    YGFlexDirectionColumn, availableInnerWidth));
+            const float descent =
+                child->getLayout().measuredDimensions[YGDimensionHeight] +
+                YGUnwrapFloatOptional(child->getMarginForAxis(
+                    YGFlexDirectionColumn, availableInnerWidth)) -
+                ascent;
+            maxAscentForCurrentLine =
+                YGFloatMax(maxAscentForCurrentLine, ascent);
+            maxDescentForCurrentLine =
+                YGFloatMax(maxDescentForCurrentLine, descent);
+            lineHeight = YGFloatMax(
+                lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
+          }
+        }
+      }
+      endIndex = ii;
+      lineHeight += crossDimLead;
+
+      if (performLayout) {
+        for (ii = startIndex; ii < endIndex; ii++) {
+          const YGNodeRef child = node->getChild(ii);
+          if (child->getStyle().display == YGDisplayNone) {
+            continue;
+          }
+          if (child->getStyle().positionType == YGPositionTypeRelative) {
+            switch (YGNodeAlignItem(node, child)) {
+              case YGAlignFlexStart: {
+                child->setLayoutPosition(
+                    currentLead +
+                        YGUnwrapFloatOptional(child->getLeadingMargin(
+                            crossAxis, availableInnerWidth)),
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignFlexEnd: {
+                child->setLayoutPosition(
+                    currentLead + lineHeight -
+                        YGUnwrapFloatOptional(child->getTrailingMargin(
+                            crossAxis, availableInnerWidth)) -
+                        child->getLayout().measuredDimensions[dim[crossAxis]],
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignCenter: {
+                float childHeight =
+                    child->getLayout().measuredDimensions[dim[crossAxis]];
+
+                child->setLayoutPosition(
+                    currentLead + (lineHeight - childHeight) / 2,
+                    pos[crossAxis]);
+                break;
+              }
+              case YGAlignStretch: {
+                child->setLayoutPosition(
+                    currentLead +
+                        YGUnwrapFloatOptional(child->getLeadingMargin(
+                            crossAxis, availableInnerWidth)),
+                    pos[crossAxis]);
+
+                // Remeasure child with the line height as it as been only measured with the
+                // owners height yet.
+                if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
+                  const float childWidth = isMainAxisRow
+                      ? (child->getLayout()
+                             .measuredDimensions[YGDimensionWidth] +
+                         YGUnwrapFloatOptional(child->getMarginForAxis(
+                             mainAxis, availableInnerWidth)))
+                      : lineHeight;
+
+                  const float childHeight = !isMainAxisRow
+                      ? (child->getLayout()
+                             .measuredDimensions[YGDimensionHeight] +
+                         YGUnwrapFloatOptional(child->getMarginForAxis(
+                             crossAxis, availableInnerWidth)))
+                      : lineHeight;
+
+                  if (!(YGFloatsEqual(
+                            childWidth,
+                            child->getLayout()
+                                .measuredDimensions[YGDimensionWidth]) &&
+                        YGFloatsEqual(
+                            childHeight,
+                            child->getLayout()
+                                .measuredDimensions[YGDimensionHeight]))) {
+                    YGLayoutNodeInternal(child,
+                                         childWidth,
+                                         childHeight,
+                                         direction,
+                                         YGMeasureModeExactly,
+                                         YGMeasureModeExactly,
+                                         availableInnerWidth,
+                                         availableInnerHeight,
+                                         true,
+                                         "multiline-stretch",
+                                         config);
+                  }
+                }
+                break;
+              }
+              case YGAlignBaseline: {
+                child->setLayoutPosition(
+                    currentLead + maxAscentForCurrentLine - YGBaseline(child) +
+                        YGUnwrapFloatOptional(child->getLeadingPosition(
+                            YGFlexDirectionColumn, availableInnerCrossDim)),
+                    YGEdgeTop);
+
+                break;
+              }
+              case YGAlignAuto:
+              case YGAlignSpaceBetween:
+              case YGAlignSpaceAround:
+                break;
+            }
+          }
+        }
+      }
+
+      currentLead += lineHeight;
+    }
+  }
+
+  // STEP 9: COMPUTING FINAL DIMENSIONS
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionRow,
+          availableWidth - marginAxisRow,
+          ownerWidth,
+          ownerWidth),
+      YGDimensionWidth);
+
+  node->setLayoutMeasuredDimension(
+      YGNodeBoundAxis(
+          node,
+          YGFlexDirectionColumn,
+          availableHeight - marginAxisColumn,
+          ownerHeight,
+          ownerWidth),
+      YGDimensionHeight);
+
+  // If the user didn't specify a width or height for the node, set the
+  // dimensions based on the children.
+  if (measureModeMainDim == YGMeasureModeUndefined ||
+      (node->getStyle().overflow != YGOverflowScroll &&
+       measureModeMainDim == YGMeasureModeAtMost)) {
+    // Clamp the size to the min/max size, if specified, and make sure it
+    // doesn't go below the padding and border amount.
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
+        dim[mainAxis]);
+
+  } else if (
+      measureModeMainDim == YGMeasureModeAtMost &&
+      node->getStyle().overflow == YGOverflowScroll) {
+    node->setLayoutMeasuredDimension(
+        YGFloatMax(
+            YGFloatMin(
+                availableInnerMainDim + paddingAndBorderAxisMain,
+                YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+                    node, mainAxis, maxLineMainDim, mainAxisownerSize))),
+            paddingAndBorderAxisMain),
+        dim[mainAxis]);
+  }
+
+  if (measureModeCrossDim == YGMeasureModeUndefined ||
+      (node->getStyle().overflow != YGOverflowScroll &&
+       measureModeCrossDim == YGMeasureModeAtMost)) {
+    // Clamp the size to the min/max size, if specified, and make sure it
+    // doesn't go below the padding and border amount.
+
+    node->setLayoutMeasuredDimension(
+        YGNodeBoundAxis(
+            node,
+            crossAxis,
+            totalLineCrossDim + paddingAndBorderAxisCross,
+            crossAxisownerSize,
+            ownerWidth),
+        dim[crossAxis]);
+
+  } else if (
+      measureModeCrossDim == YGMeasureModeAtMost &&
+      node->getStyle().overflow == YGOverflowScroll) {
+    node->setLayoutMeasuredDimension(
+        YGFloatMax(
+            YGFloatMin(
+                availableInnerCrossDim + paddingAndBorderAxisCross,
+                YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
+                    node,
+                    crossAxis,
+                    totalLineCrossDim + paddingAndBorderAxisCross,
+                    crossAxisownerSize))),
+            paddingAndBorderAxisCross),
+        dim[crossAxis]);
+  }
+
+  // As we only wrapped in normal direction yet, we need to reverse the positions on wrap-reverse.
+  if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {
+    for (uint32_t i = 0; i < childCount; i++) {
+      const YGNodeRef child = YGNodeGetChild(node, i);
+      if (child->getStyle().positionType == YGPositionTypeRelative) {
+        child->setLayoutPosition(
+            node->getLayout().measuredDimensions[dim[crossAxis]] -
+                child->getLayout().position[pos[crossAxis]] -
+                child->getLayout().measuredDimensions[dim[crossAxis]],
+            pos[crossAxis]);
+      }
+    }
+  }
+
+  if (performLayout) {
+    // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
+    for (auto child : node->getChildren()) {
+      if (child->getStyle().positionType != YGPositionTypeAbsolute) {
+        continue;
+      }
+      YGNodeAbsoluteLayoutChild(
+          node,
+          child,
+          availableInnerWidth,
+          isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
+          availableInnerHeight,
+          direction,
+          config);
+    }
+
+    // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
+    const bool needsMainTrailingPos =
+        mainAxis == YGFlexDirectionRowReverse || mainAxis == YGFlexDirectionColumnReverse;
+    const bool needsCrossTrailingPos =
+        crossAxis == YGFlexDirectionRowReverse || crossAxis == YGFlexDirectionColumnReverse;
+
+    // Set trailing position if necessary.
+    if (needsMainTrailingPos || needsCrossTrailingPos) {
+      for (uint32_t i = 0; i < childCount; i++) {
+        const YGNodeRef child = node->getChild(i);
+        if (child->getStyle().display == YGDisplayNone) {
+          continue;
+        }
+        if (needsMainTrailingPos) {
+          YGNodeSetChildTrailingPosition(node, child, mainAxis);
+        }
+
+        if (needsCrossTrailingPos) {
+          YGNodeSetChildTrailingPosition(node, child, crossAxis);
+        }
+      }
+    }
+  }
+}
+
+uint32_t gDepth = 0;
+bool gPrintTree = false;
+bool gPrintChanges = false;
+bool gPrintSkips = false;
+
+static const char *spacer = "                                                            ";
+
+static const char *YGSpacer(const unsigned long level) {
+  const size_t spacerLen = strlen(spacer);
+  if (level > spacerLen) {
+    return &spacer[0];
+  } else {
+    return &spacer[spacerLen - level];
+  }
+}
+
+static const char *YGMeasureModeName(const YGMeasureMode mode, const bool performLayout) {
+  const char *kMeasureModeNames[YGMeasureModeCount] = {"UNDEFINED", "EXACTLY", "AT_MOST"};
+  const char *kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
+                                                      "LAY_EXACTLY",
+                                                      "LAY_AT_"
+                                                      "MOST"};
+
+  if (mode >= YGMeasureModeCount) {
+    return "";
+  }
+
+  return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
+}
+
+static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(YGMeasureMode sizeMode,
+                                                                     float size,
+                                                                     float lastComputedSize) {
+  return sizeMode == YGMeasureModeExactly && YGFloatsEqual(size, lastComputedSize);
+}
+
+static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(YGMeasureMode sizeMode,
+                                                                 float size,
+                                                                 YGMeasureMode lastSizeMode,
+                                                                 float lastComputedSize) {
+  return sizeMode == YGMeasureModeAtMost && lastSizeMode == YGMeasureModeUndefined &&
+         (size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
+}
+
+static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureMode sizeMode,
+                                                                      float size,
+                                                                      YGMeasureMode lastSizeMode,
+                                                                      float lastSize,
+                                                                      float lastComputedSize) {
+  return lastSizeMode == YGMeasureModeAtMost &&
+      sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
+      !YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
+      lastSize > size &&
+      (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
+}
+
+float YGRoundValueToPixelGrid(const float value,
+                              const float pointScaleFactor,
+                              const bool forceCeil,
+                              const bool forceFloor) {
+  float scaledValue = value * pointScaleFactor;
+  float fractial = fmodf(scaledValue, 1.0f);
+  if (YGFloatsEqual(fractial, 0)) {
+    // First we check if the value is already rounded
+    scaledValue = scaledValue - fractial;
+  } else if (YGFloatsEqual(fractial, 1.0f)) {
+    scaledValue = scaledValue - fractial + 1.0f;
+  } else if (forceCeil) {
+    // Next we check if we need to use forced rounding
+    scaledValue = scaledValue - fractial + 1.0f;
+  } else if (forceFloor) {
+    scaledValue = scaledValue - fractial;
+  } else {
+    // Finally we just round the value
+    scaledValue = scaledValue - fractial +
+        (!YGFloatIsUndefined(fractial) &&
+                 (fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
+             ? 1.0f
+             : 0.0f);
+  }
+  return (YGFloatIsUndefined(scaledValue) ||
+          YGFloatIsUndefined(pointScaleFactor))
+      ? YGUndefined
+      : scaledValue / pointScaleFactor;
+}
+
+bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
+                                   const float width,
+                                   const YGMeasureMode heightMode,
+                                   const float height,
+                                   const YGMeasureMode lastWidthMode,
+                                   const float lastWidth,
+                                   const YGMeasureMode lastHeightMode,
+                                   const float lastHeight,
+                                   const float lastComputedWidth,
+                                   const float lastComputedHeight,
+                                   const float marginRow,
+                                   const float marginColumn,
+                                   const YGConfigRef config) {
+  if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
+      (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
+    return false;
+  }
+  bool useRoundedComparison =
+      config != nullptr && config->pointScaleFactor != 0;
+  const float effectiveWidth =
+      useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
+                           : width;
+  const float effectiveHeight =
+      useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
+                           : height;
+  const float effectiveLastWidth =
+      useRoundedComparison
+          ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false)
+          : lastWidth;
+  const float effectiveLastHeight =
+      useRoundedComparison
+          ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false)
+          : lastHeight;
+
+  const bool hasSameWidthSpec =
+      lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth);
+  const bool hasSameHeightSpec =
+      lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight);
+
+  const bool widthIsCompatible =
+      hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode,
+                                                                            width - marginRow,
+                                                                            lastComputedWidth) ||
+      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(widthMode,
+                                                    width - marginRow,
+                                                    lastWidthMode,
+                                                    lastComputedWidth) ||
+      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
+          widthMode, width - marginRow, lastWidthMode, lastWidth, lastComputedWidth);
+
+  const bool heightIsCompatible =
+      hasSameHeightSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(heightMode,
+                                                                             height - marginColumn,
+                                                                             lastComputedHeight) ||
+      YGMeasureModeOldSizeIsUnspecifiedAndStillFits(heightMode,
+                                                    height - marginColumn,
+                                                    lastHeightMode,
+                                                    lastComputedHeight) ||
+      YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
+          heightMode, height - marginColumn, lastHeightMode, lastHeight, lastComputedHeight);
+
+  return widthIsCompatible && heightIsCompatible;
+}
+
+//
+// This is a wrapper around the YGNodelayoutImpl function. It determines
+// whether the layout request is redundant and can be skipped.
+//
+// Parameters:
+//  Input parameters are the same as YGNodelayoutImpl (see above)
+//  Return parameter is true if layout was performed, false if skipped
+//
+bool YGLayoutNodeInternal(const YGNodeRef node,
+                          const float availableWidth,
+                          const float availableHeight,
+                          const YGDirection ownerDirection,
+                          const YGMeasureMode widthMeasureMode,
+                          const YGMeasureMode heightMeasureMode,
+                          const float ownerWidth,
+                          const float ownerHeight,
+                          const bool performLayout,
+                          const char *reason,
+                          const YGConfigRef config) {
+  YGLayout* layout = &node->getLayout();
+
+  gDepth++;
+
+  const bool needToVisitNode =
+      (node->isDirty() && layout->generationCount != gCurrentGenerationCount) ||
+      layout->lastOwnerDirection != ownerDirection;
+
+  if (needToVisitNode) {
+    // Invalidate the cached results.
+    layout->nextCachedMeasurementsIndex = 0;
+    layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1;
+    layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1;
+    layout->cachedLayout.computedWidth = -1;
+    layout->cachedLayout.computedHeight = -1;
+  }
+
+  YGCachedMeasurement* cachedResults = nullptr;
+
+  // Determine whether the results are already cached. We maintain a separate
+  // cache for layouts and measurements. A layout operation modifies the
+  // positions
+  // and dimensions for nodes in the subtree. The algorithm assumes that each
+  // node
+  // gets layed out a maximum of one time per tree layout, but multiple
+  // measurements
+  // may be required to resolve all of the flex dimensions.
+  // We handle nodes with measure functions specially here because they are the
+  // most
+  // expensive to measure, so it's worth avoiding redundant measurements if at
+  // all possible.
+  if (node->getMeasure() != nullptr) {
+    const float marginAxisRow = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    const float marginAxisColumn = YGUnwrapFloatOptional(
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+
+    // First, try to use the layout cache.
+    if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
+                                      availableWidth,
+                                      heightMeasureMode,
+                                      availableHeight,
+                                      layout->cachedLayout.widthMeasureMode,
+                                      layout->cachedLayout.availableWidth,
+                                      layout->cachedLayout.heightMeasureMode,
+                                      layout->cachedLayout.availableHeight,
+                                      layout->cachedLayout.computedWidth,
+                                      layout->cachedLayout.computedHeight,
+                                      marginAxisRow,
+                                      marginAxisColumn,
+                                      config)) {
+      cachedResults = &layout->cachedLayout;
+    } else {
+      // Try to use the measurement cache.
+      for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+        if (YGNodeCanUseCachedMeasurement(widthMeasureMode,
+                                          availableWidth,
+                                          heightMeasureMode,
+                                          availableHeight,
+                                          layout->cachedMeasurements[i].widthMeasureMode,
+                                          layout->cachedMeasurements[i].availableWidth,
+                                          layout->cachedMeasurements[i].heightMeasureMode,
+                                          layout->cachedMeasurements[i].availableHeight,
+                                          layout->cachedMeasurements[i].computedWidth,
+                                          layout->cachedMeasurements[i].computedHeight,
+                                          marginAxisRow,
+                                          marginAxisColumn,
+                                          config)) {
+          cachedResults = &layout->cachedMeasurements[i];
+          break;
+        }
+      }
+    }
+  } else if (performLayout) {
+    if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
+        YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
+        layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
+        layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
+      cachedResults = &layout->cachedLayout;
+    }
+  } else {
+    for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
+      if (YGFloatsEqual(layout->cachedMeasurements[i].availableWidth, availableWidth) &&
+          YGFloatsEqual(layout->cachedMeasurements[i].availableHeight, availableHeight) &&
+          layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
+          layout->cachedMeasurements[i].heightMeasureMode == heightMeasureMode) {
+        cachedResults = &layout->cachedMeasurements[i];
+        break;
+      }
+    }
+  }
+
+  if (!needToVisitNode && cachedResults != nullptr) {
+    layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
+    layout->measuredDimensions[YGDimensionHeight] = cachedResults->computedHeight;
+
+    if (gPrintChanges && gPrintSkips) {
+      YGLog(node, YGLogLevelVerbose, "%s%d.{[skipped] ", YGSpacer(gDepth), gDepth);
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          availableWidth,
+          availableHeight,
+          cachedResults->computedWidth,
+          cachedResults->computedHeight,
+          reason);
+    }
+  } else {
+    if (gPrintChanges) {
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "%s%d.{%s",
+          YGSpacer(gDepth),
+          gDepth,
+          needToVisitNode ? "*" : "");
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, aw: %f ah: %f %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          availableWidth,
+          availableHeight,
+          reason);
+    }
+
+    YGNodelayoutImpl(node,
+                     availableWidth,
+                     availableHeight,
+                     ownerDirection,
+                     widthMeasureMode,
+                     heightMeasureMode,
+                     ownerWidth,
+                     ownerHeight,
+                     performLayout,
+                     config);
+
+    if (gPrintChanges) {
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "%s%d.}%s",
+          YGSpacer(gDepth),
+          gDepth,
+          needToVisitNode ? "*" : "");
+      if (node->getPrintFunc() != nullptr) {
+        node->getPrintFunc()(node);
+      }
+      YGLog(
+          node,
+          YGLogLevelVerbose,
+          "wm: %s, hm: %s, d: (%f, %f) %s\n",
+          YGMeasureModeName(widthMeasureMode, performLayout),
+          YGMeasureModeName(heightMeasureMode, performLayout),
+          layout->measuredDimensions[YGDimensionWidth],
+          layout->measuredDimensions[YGDimensionHeight],
+          reason);
+    }
+
+    layout->lastOwnerDirection = ownerDirection;
+
+    if (cachedResults == nullptr) {
+      if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
+        if (gPrintChanges) {
+          YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
+        }
+        layout->nextCachedMeasurementsIndex = 0;
+      }
+
+      YGCachedMeasurement *newCacheEntry;
+      if (performLayout) {
+        // Use the single layout cache entry.
+        newCacheEntry = &layout->cachedLayout;
+      } else {
+        // Allocate a new measurement cache entry.
+        newCacheEntry = &layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
+        layout->nextCachedMeasurementsIndex++;
+      }
+
+      newCacheEntry->availableWidth = availableWidth;
+      newCacheEntry->availableHeight = availableHeight;
+      newCacheEntry->widthMeasureMode = widthMeasureMode;
+      newCacheEntry->heightMeasureMode = heightMeasureMode;
+      newCacheEntry->computedWidth = layout->measuredDimensions[YGDimensionWidth];
+      newCacheEntry->computedHeight = layout->measuredDimensions[YGDimensionHeight];
+    }
+  }
+
+  if (performLayout) {
+    node->setLayoutDimension(
+        node->getLayout().measuredDimensions[YGDimensionWidth],
+        YGDimensionWidth);
+    node->setLayoutDimension(
+        node->getLayout().measuredDimensions[YGDimensionHeight],
+        YGDimensionHeight);
+
+    node->setHasNewLayout(true);
+    node->setDirty(false);
+  }
+
+  gDepth--;
+  layout->generationCount = gCurrentGenerationCount;
+  return (needToVisitNode || cachedResults == nullptr);
+}
+
+void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint) {
+  YGAssertWithConfig(config, pixelsInPoint >= 0.0f, "Scale factor should not be less than zero");
+
+  // We store points for Pixel as we will use it for rounding
+  if (pixelsInPoint == 0.0f) {
+    // Zero is used to skip rounding
+    config->pointScaleFactor = 0.0f;
+  } else {
+    config->pointScaleFactor = pixelsInPoint;
+  }
+}
+
+static void YGRoundToPixelGrid(const YGNodeRef node,
+                               const float pointScaleFactor,
+                               const float absoluteLeft,
+                               const float absoluteTop) {
+  if (pointScaleFactor == 0.0f) {
+    return;
+  }
+
+  const float nodeLeft = node->getLayout().position[YGEdgeLeft];
+  const float nodeTop = node->getLayout().position[YGEdgeTop];
+
+  const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
+  const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
+
+  const float absoluteNodeLeft = absoluteLeft + nodeLeft;
+  const float absoluteNodeTop = absoluteTop + nodeTop;
+
+  const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
+  const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
+
+  // If a node has a custom measure function we never want to round down its size as this could
+  // lead to unwanted text truncation.
+  const bool textRounding = node->getNodeType() == YGNodeTypeText;
+
+  node->setLayoutPosition(
+      YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
+      YGEdgeLeft);
+
+  node->setLayoutPosition(
+      YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
+      YGEdgeTop);
+
+  // We multiply dimension by scale factor and if the result is close to the whole number, we don't
+  // have any fraction
+  // To verify if the result is close to whole number we want to check both floor and ceil numbers
+  const bool hasFractionalWidth = !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
+                                  !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
+  const bool hasFractionalHeight = !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
+                                   !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
+
+  node->setLayoutDimension(
+      YGRoundValueToPixelGrid(
+          absoluteNodeRight,
+          pointScaleFactor,
+          (textRounding && hasFractionalWidth),
+          (textRounding && !hasFractionalWidth)) -
+          YGRoundValueToPixelGrid(
+              absoluteNodeLeft, pointScaleFactor, false, textRounding),
+      YGDimensionWidth);
+
+  node->setLayoutDimension(
+      YGRoundValueToPixelGrid(
+          absoluteNodeBottom,
+          pointScaleFactor,
+          (textRounding && hasFractionalHeight),
+          (textRounding && !hasFractionalHeight)) -
+          YGRoundValueToPixelGrid(
+              absoluteNodeTop, pointScaleFactor, false, textRounding),
+      YGDimensionHeight);
+
+  const uint32_t childCount = YGNodeGetChildCount(node);
+  for (uint32_t i = 0; i < childCount; i++) {
+    YGRoundToPixelGrid(
+        YGNodeGetChild(node, i),
+        pointScaleFactor,
+        absoluteNodeLeft,
+        absoluteNodeTop);
+  }
+}
+
+void YGNodeCalculateLayout(
+    const YGNodeRef node,
+    const float ownerWidth,
+    const float ownerHeight,
+    const YGDirection ownerDirection) {
+  // Increment the generation count. This will force the recursive routine to
+  // visit
+  // all dirty nodes at least once. Subsequent visits will be skipped if the
+  // input
+  // parameters don't change.
+  gCurrentGenerationCount++;
+  node->resolveDimension();
+  float width = YGUndefined;
+  YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
+  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
+    width = YGUnwrapFloatOptional(
+        YGResolveValue(
+            node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
+        node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
+    widthMeasureMode = YGMeasureModeExactly;
+  } else if (!YGResolveValue(
+                  node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
+                  .isUndefined()) {
+    width = YGUnwrapFloatOptional(YGResolveValue(
+        node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
+    widthMeasureMode = YGMeasureModeAtMost;
+  } else {
+    width = ownerWidth;
+    widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
+                                                 : YGMeasureModeExactly;
+  }
+
+  float height = YGUndefined;
+  YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
+  if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
+    height = YGUnwrapFloatOptional(
+        YGResolveValue(
+            node->getResolvedDimension(dim[YGFlexDirectionColumn]),
+            ownerHeight) +
+        node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
+    heightMeasureMode = YGMeasureModeExactly;
+  } else if (!YGResolveValue(
+                  node->getStyle().maxDimensions[YGDimensionHeight],
+                  ownerHeight)
+                  .isUndefined()) {
+    height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
+    heightMeasureMode = YGMeasureModeAtMost;
+  } else {
+    height = ownerHeight;
+    heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
+                                                   : YGMeasureModeExactly;
+  }
+  if (YGLayoutNodeInternal(
+          node,
+          width,
+          height,
+          ownerDirection,
+          widthMeasureMode,
+          heightMeasureMode,
+          ownerWidth,
+          ownerHeight,
+          true,
+          "initial",
+          node->getConfig())) {
+    node->setPosition(
+        node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
+    YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
+
+    if (gPrintTree) {
+      YGNodePrint(
+          node,
+          (YGPrintOptions)(
+              YGPrintOptionsLayout | YGPrintOptionsChildren |
+              YGPrintOptionsStyle));
+    }
+  }
+
+  // We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
+  // aren't sure whether client's of yoga have gotten rid off this flag or not.
+  // So logging this in YGLayout would help to find out the call sites depending
+  // on this flag. This check would be removed once we are sure no one is
+  // dependent on this flag anymore. The flag
+  // `shouldDiffLayoutWithoutLegacyStretchBehaviour` in YGConfig will help to
+  // run experiments.
+  if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour &&
+      node->didUseLegacyFlag()) {
+    const YGNodeRef originalNode = YGNodeDeepClone(node);
+    originalNode->resolveDimension();
+    // Recursively mark nodes as dirty
+    originalNode->markDirtyAndPropogateDownwards();
+    gCurrentGenerationCount++;
+    // Rerun the layout, and calculate the diff
+    originalNode->setAndPropogateUseLegacyFlag(false);
+    if (YGLayoutNodeInternal(
+            originalNode,
+            width,
+            height,
+            ownerDirection,
+            widthMeasureMode,
+            heightMeasureMode,
+            ownerWidth,
+            ownerHeight,
+            true,
+            "initial",
+            originalNode->getConfig())) {
+      originalNode->setPosition(
+          originalNode->getLayout().direction,
+          ownerWidth,
+          ownerHeight,
+          ownerWidth);
+      YGRoundToPixelGrid(
+          originalNode,
+          originalNode->getConfig()->pointScaleFactor,
+          0.0f,
+          0.0f);
+
+      // Set whether the two layouts are different or not.
+      node->setLayoutDoesLegacyFlagAffectsLayout(
+          !originalNode->isLayoutTreeEqualToNode(*node));
+
+      if (gPrintTree) {
+        YGNodePrint(
+            originalNode,
+            (YGPrintOptions)(
+                YGPrintOptionsLayout | YGPrintOptionsChildren |
+                YGPrintOptionsStyle));
+      }
+    }
+    YGConfigFreeRecursive(originalNode);
+    YGNodeFreeRecursive(originalNode);
+  }
+}
+
+void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
+  if (logger != nullptr) {
+    config->logger = logger;
+  } else {
+#ifdef ANDROID
+    config->logger = &YGAndroidLog;
+#else
+    config->logger = &YGDefaultLog;
+#endif
+  }
+}
+
+void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool shouldDiffLayout) {
+  config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
+}
+
+static void YGVLog(const YGConfigRef config,
+                   const YGNodeRef node,
+                   YGLogLevel level,
+                   const char *format,
+                   va_list args) {
+  const YGConfigRef logConfig = config != nullptr ? config : YGConfigGetDefault();
+  logConfig->logger(logConfig, node, level, format, args);
+
+  if (level == YGLogLevelFatal) {
+    abort();
+  }
+}
+
+void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  YGVLog(config, nullptr, level, format, args);
+  va_end(args);
+}
+
+void YGLog(const YGNodeRef node, YGLogLevel level, const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  YGVLog(
+      node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
+  va_end(args);
+}
+
+void YGAssert(const bool condition, const char *message) {
+  if (!condition) {
+    YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message) {
+  if (!condition) {
+    YGLog(node, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGAssertWithConfig(const YGConfigRef config, const bool condition, const char *message) {
+  if (!condition) {
+    YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
+  }
+}
+
+void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
+                                           const YGExperimentalFeature feature,
+                                           const bool enabled) {
+  config->experimentalFeatures[feature] = enabled;
+}
+
+inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
+                                                 const YGExperimentalFeature feature) {
+  return config->experimentalFeatures[feature];
+}
+
+void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
+  config->useWebDefaults = enabled;
+}
+
+void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
+                                          const bool useLegacyStretchBehaviour) {
+  config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
+}
+
+bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
+  return config->useWebDefaults;
+}
+
+void YGConfigSetContext(const YGConfigRef config, void *context) {
+  config->context = context;
+}
+
+void *YGConfigGetContext(const YGConfigRef config) {
+  return config->context;
+}
+
+void YGConfigSetCloneNodeFunc(const YGConfigRef config, const YGCloneNodeFunc callback) {
+  config->cloneNodeCallback = callback;
+}
+
+static void YGTraverseChildrenPreOrder(const YGVector& children, const std::function<void(YGNodeRef node)>& f) {
+  for (YGNodeRef node : children) {
+    f(node);
+    YGTraverseChildrenPreOrder(node->getChildren(), f);
+  }
+}
+
+void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f) {
+  if (!node) {
+    return;
+  }
+  f(node);
+  YGTraverseChildrenPreOrder(node->getChildren(), f);
+}
diff --git a/dali-toolkit/third-party/yoga/Yoga.h b/dali-toolkit/third-party/yoga/Yoga.h
new file mode 100644 (file)
index 0000000..25eb0eb
--- /dev/null
@@ -0,0 +1,327 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+#pragma once
+
+#include <assert.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+/** Large positive number signifies that the property(float) is undefined.
+ *Earlier we used to have YGundefined as NAN, but the downside of this is that
+ *we can't use -ffast-math compiler flag as it assumes all floating-point
+ *calculation involve and result into finite numbers. For more information
+ *regarding -ffast-math compiler flag in clang, have a look at
+ *https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
+ **/
+#define YGUndefined 10E20F
+
+#include "YGEnums.h"
+#include "YGMacros.h"
+
+YG_EXTERN_C_BEGIN
+
+typedef struct YGSize {
+  float width;
+  float height;
+} YGSize;
+
+typedef struct YGValue {
+  float value;
+  YGUnit unit;
+} YGValue;
+
+extern const YGValue YGValueUndefined;
+extern const YGValue YGValueAuto;
+
+typedef struct YGConfig *YGConfigRef;
+
+typedef struct YGNode* YGNodeRef;
+
+typedef YGSize (*YGMeasureFunc)(YGNodeRef node,
+                                float width,
+                                YGMeasureMode widthMode,
+                                float height,
+                                YGMeasureMode heightMode);
+typedef float (*YGBaselineFunc)(YGNodeRef node, const float width, const float height);
+typedef void (*YGDirtiedFunc)(YGNodeRef node);
+typedef void (*YGPrintFunc)(YGNodeRef node);
+typedef int (*YGLogger)(const YGConfigRef config,
+                        const YGNodeRef node,
+                        YGLogLevel level,
+                        const char *format,
+                        va_list args);
+typedef YGNodeRef (
+    *YGCloneNodeFunc)(YGNodeRef oldNode, YGNodeRef owner, int childIndex);
+
+// YGNode
+WIN_EXPORT YGNodeRef YGNodeNew(void);
+WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config);
+WIN_EXPORT YGNodeRef YGNodeClone(const YGNodeRef node);
+WIN_EXPORT void YGNodeFree(const YGNodeRef node);
+WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node);
+WIN_EXPORT void YGNodeReset(const YGNodeRef node);
+WIN_EXPORT int32_t YGNodeGetInstanceCount(void);
+
+WIN_EXPORT void YGNodeInsertChild(const YGNodeRef node,
+                                  const YGNodeRef child,
+                                  const uint32_t index);
+
+// This function inserts the child YGNodeRef as a children of the node received
+// by parameter and set the Owner of the child object to null. This function is
+// expected to be called when using Yoga in persistent mode in order to share a
+// YGNodeRef object as a child of two different Yoga trees. The child YGNodeRef
+// is expected to be referenced from its original owner and from a clone of its
+// original owner.
+WIN_EXPORT void YGNodeInsertSharedChild(
+    const YGNodeRef node,
+    const YGNodeRef child,
+    const uint32_t index);
+WIN_EXPORT void YGNodeRemoveChild(const YGNodeRef node, const YGNodeRef child);
+WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node);
+WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index);
+WIN_EXPORT YGNodeRef YGNodeGetOwner(const YGNodeRef node);
+WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node);
+WIN_EXPORT void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const YGNodeRef children[],
+    const uint32_t count);
+
+WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node,
+                                      const float availableWidth,
+                                      const float availableHeight,
+                                      const YGDirection ownerDirection);
+
+// Mark a node as dirty. Only valid for nodes with a custom measure function
+// set.
+// YG knows when to mark all other nodes as dirty but because nodes with
+// measure functions
+// depends on information not known to YG they must perform this dirty
+// marking manually.
+WIN_EXPORT void YGNodeMarkDirty(const YGNodeRef node);
+
+// This function marks the current node and all its descendants as dirty. This function is added to test yoga benchmarks.
+// This function is not expected to be used in production as calling `YGCalculateLayout` will cause the recalculation of each and every node.
+WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node);
+
+WIN_EXPORT void YGNodePrint(const YGNodeRef node, const YGPrintOptions options);
+
+WIN_EXPORT bool YGFloatIsUndefined(const float value);
+
+WIN_EXPORT bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
+                                              const float width,
+                                              const YGMeasureMode heightMode,
+                                              const float height,
+                                              const YGMeasureMode lastWidthMode,
+                                              const float lastWidth,
+                                              const YGMeasureMode lastHeightMode,
+                                              const float lastHeight,
+                                              const float lastComputedWidth,
+                                              const float lastComputedHeight,
+                                              const float marginRow,
+                                              const float marginColumn,
+                                              const YGConfigRef config);
+
+WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode);
+
+#define YG_NODE_PROPERTY(type, name, paramName)                          \
+  WIN_EXPORT void YGNodeSet##name(const YGNodeRef node, type paramName); \
+  WIN_EXPORT type YGNodeGet##name(const YGNodeRef node);
+
+#define YG_NODE_STYLE_PROPERTY(type, name, paramName)                               \
+  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const type paramName); \
+  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node);
+
+#define YG_NODE_STYLE_PROPERTY_UNIT(type, name, paramName)                                    \
+  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const float paramName);          \
+  WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node, const float paramName); \
+  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node);
+
+#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO(type, name, paramName) \
+  YG_NODE_STYLE_PROPERTY_UNIT(type, name, paramName)            \
+  WIN_EXPORT void YGNodeStyleSet##name##Auto(const YGNodeRef node);
+
+#define YG_NODE_STYLE_EDGE_PROPERTY(type, name, paramName)    \
+  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node,  \
+                                       const YGEdge edge,     \
+                                       const type paramName); \
+  WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge);
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT(type, name, paramName)         \
+  WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node,            \
+                                       const YGEdge edge,               \
+                                       const float paramName);          \
+  WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node,   \
+                                                const YGEdge edge,      \
+                                                const float paramName); \
+  WIN_EXPORT WIN_STRUCT(type) YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge);
+
+#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO(type, name) \
+  WIN_EXPORT void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge);
+
+#define YG_NODE_LAYOUT_PROPERTY(type, name) \
+  WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node);
+
+#define YG_NODE_LAYOUT_EDGE_PROPERTY(type, name) \
+  WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge);
+
+void* YGNodeGetContext(YGNodeRef node);
+void YGNodeSetContext(YGNodeRef node, void* context);
+YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node);
+void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
+YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node);
+void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
+YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node);
+void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc);
+YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node);
+void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc);
+bool YGNodeGetHasNewLayout(YGNodeRef node);
+void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout);
+YGNodeType YGNodeGetNodeType(YGNodeRef node);
+void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType);
+bool YGNodeIsDirty(YGNodeRef node);
+bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node);
+
+YG_NODE_STYLE_PROPERTY(YGDirection, Direction, direction);
+YG_NODE_STYLE_PROPERTY(YGFlexDirection, FlexDirection, flexDirection);
+YG_NODE_STYLE_PROPERTY(YGJustify, JustifyContent, justifyContent);
+YG_NODE_STYLE_PROPERTY(YGAlign, AlignContent, alignContent);
+YG_NODE_STYLE_PROPERTY(YGAlign, AlignItems, alignItems);
+YG_NODE_STYLE_PROPERTY(YGAlign, AlignSelf, alignSelf);
+YG_NODE_STYLE_PROPERTY(YGPositionType, PositionType, positionType);
+YG_NODE_STYLE_PROPERTY(YGWrap, FlexWrap, flexWrap);
+YG_NODE_STYLE_PROPERTY(YGOverflow, Overflow, overflow);
+YG_NODE_STYLE_PROPERTY(YGDisplay, Display, display);
+YG_NODE_STYLE_PROPERTY(float, Flex, flex);
+YG_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow);
+YG_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink);
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, FlexBasis, flexBasis);
+
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Position, position);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Margin, margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO(YGValue, Margin);
+YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Padding, padding);
+YG_NODE_STYLE_EDGE_PROPERTY(float, Border, border);
+
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, Width, width);
+YG_NODE_STYLE_PROPERTY_UNIT_AUTO(YGValue, Height, height);
+YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinWidth, minWidth);
+YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinHeight, minHeight);
+YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxWidth, maxWidth);
+YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxHeight, maxHeight);
+
+// Yoga specific properties, not compatible with flexbox specification
+// Aspect ratio control the size of the undefined dimension of a node.
+// Aspect ratio is encoded as a floating point value width/height. e.g. A value of 2 leads to a node
+// with a width twice the size of its height while a value of 0.5 gives the opposite effect.
+//
+// - On a node with a set width/height aspect ratio control the size of the unset dimension
+// - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis if
+// unset
+// - On a node with a measure function aspect ratio works as though the measure function measures
+// the flex basis
+// - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis if
+// unset
+// - Aspect ratio takes min/max dimensions into account
+YG_NODE_STYLE_PROPERTY(float, AspectRatio, aspectRatio);
+
+YG_NODE_LAYOUT_PROPERTY(float, Left);
+YG_NODE_LAYOUT_PROPERTY(float, Top);
+YG_NODE_LAYOUT_PROPERTY(float, Right);
+YG_NODE_LAYOUT_PROPERTY(float, Bottom);
+YG_NODE_LAYOUT_PROPERTY(float, Width);
+YG_NODE_LAYOUT_PROPERTY(float, Height);
+YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction);
+YG_NODE_LAYOUT_PROPERTY(bool, HadOverflow);
+bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node);
+
+// Get the computed values for these nodes after performing layout. If they were set using
+// point values then the returned value will be the same as YGNodeStyleGetXXX. However if
+// they were set using a percentage value then the returned value is the computed value used
+// during layout.
+YG_NODE_LAYOUT_EDGE_PROPERTY(float, Margin);
+YG_NODE_LAYOUT_EDGE_PROPERTY(float, Border);
+YG_NODE_LAYOUT_EDGE_PROPERTY(float, Padding);
+
+WIN_EXPORT void YGConfigSetLogger(const YGConfigRef config, YGLogger logger);
+WIN_EXPORT void YGLog(const YGNodeRef node, YGLogLevel level, const char *message, ...);
+WIN_EXPORT void YGLogWithConfig(const YGConfigRef config, YGLogLevel level, const char *format, ...);
+WIN_EXPORT void YGAssert(const bool condition, const char *message);
+WIN_EXPORT void YGAssertWithNode(const YGNodeRef node, const bool condition, const char *message);
+WIN_EXPORT void YGAssertWithConfig(const YGConfigRef config,
+                                   const bool condition,
+                                   const char *message);
+// Set this to number of pixels in 1 point to round calculation results
+// If you want to avoid rounding - set PointScaleFactor to 0
+WIN_EXPORT void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint);
+void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
+    const YGConfigRef config,
+    const bool shouldDiffLayout);
+
+// Yoga previously had an error where containers would take the maximum space possible instead of
+// the minimum
+// like they are supposed to. In practice this resulted in implicit behaviour similar to align-self:
+// stretch;
+// Because this was such a long-standing bug we must allow legacy users to switch back to this
+// behaviour.
+WIN_EXPORT void YGConfigSetUseLegacyStretchBehaviour(const YGConfigRef config,
+                                                     const bool useLegacyStretchBehaviour);
+
+// YGConfig
+WIN_EXPORT YGConfigRef YGConfigNew(void);
+WIN_EXPORT void YGConfigFree(const YGConfigRef config);
+WIN_EXPORT void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src);
+WIN_EXPORT int32_t YGConfigGetInstanceCount(void);
+
+WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config,
+                                                      const YGExperimentalFeature feature,
+                                                      const bool enabled);
+WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config,
+                                                     const YGExperimentalFeature feature);
+
+// Using the web defaults is the prefered configuration for new projects.
+// Usage of non web defaults should be considered as legacy.
+WIN_EXPORT void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled);
+WIN_EXPORT bool YGConfigGetUseWebDefaults(const YGConfigRef config);
+
+WIN_EXPORT void YGConfigSetCloneNodeFunc(const YGConfigRef config,
+                                          const YGCloneNodeFunc callback);
+
+// Export only for C#
+WIN_EXPORT YGConfigRef YGConfigGetDefault(void);
+
+WIN_EXPORT void YGConfigSetContext(const YGConfigRef config, void *context);
+WIN_EXPORT void *YGConfigGetContext(const YGConfigRef config);
+
+WIN_EXPORT float YGRoundValueToPixelGrid(
+    const float value,
+    const float pointScaleFactor,
+    const bool forceCeil,
+    const bool forceFloor);
+
+YG_EXTERN_C_END
+
+#ifdef __cplusplus
+
+#include <functional>
+#include <vector>
+
+// Calls f on each node in the tree including the given node argument.
+extern void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f);
+
+extern void YGNodeSetChildren(
+    YGNodeRef const owner,
+    const std::vector<YGNodeRef>& children);
+
+#endif
diff --git a/doc/dali-toolkit-doc.h b/doc/dali-toolkit-doc.h
new file mode 100755 (executable)
index 0000000..5765d9c
--- /dev/null
@@ -0,0 +1,232 @@
+#ifndef DALI_TOOLKIT_DOC_H
+#define DALI_TOOLKIT_DOC_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+/**
+ * @defgroup dali DALi
+ * @ingroup CAPI_UI_FRAMEWORK
+ *
+ * @brief DALi is a cross-platform 3D UI Toolkit for embedded systems.
+ *
+ * @section dali-overview Overview
+ *
+ * DALi's 3D user interface engine enables you to create rich and high-performance
+ * UI applications. DALi is based on OpenGL ES 2.0, but provides a clean
+ * cross-platform C++ framework.
+ * This means that you can use high-level DALi APIs instead of accessing
+ * low-level OpenGL APIs directly.
+ *
+ * DALi consists of the following modules:
+ * <table>
+ * <tr>
+ *    <th>Module</th>
+ *    <th>Description</th>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_core</td>
+ *    <td>DALi Core provides core functionalities such as scene graph-based rendering, animation, and event handling.</td>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_adaptor</td>
+ *    <td>DALi Adaptor is a platform adaptation layer.</td>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_toolkit</td>
+ *    <td>DALi Toolkit provides UI components and various effects on top of the DALi Core.</td>
+ * </tr>
+ * </table>
+ *
+ * The layer diagram for DALi modules is shown below:
+ * @image html dali-modules.png "Figure: DALi modules"
+ *
+ * @defgroup dali_toolkit DALi Toolkit
+ *
+ * @brief DALi Toolkit provides UI components and various effects on top of the DALi Core.
+ *
+ * @section dali_toolkit_overview Overview
+ *
+ * DALi Toolkit consists of the following groups of API:
+ *
+ * <table>
+ * <tr>
+ *    <th>API Group</th>
+ *    <th>Description</th>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_toolkit_controls</td>
+ *    <td>Controls are interactive components for layouting the user interface.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_alignment</td>
+ *    <td>Alignment is a container which provides an easy way to align other actors inside its boundary.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_buttons</td>
+ *    <td>Button is a small object on UI that you can press.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_gaussian_blur_view</td>
+ *    <td>GaussianBlurView provides a render process that blurs an image.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_image_view</td>
+ *    <td>ImageView is a control displaying an image.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_model3d_view</td>
+ *    <td>Model3dView is a control for displaying 3d geometry.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_scroll_bar</td>
+ *    <td>ScrollBar is a component that can be linked to the scrollable objects.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_scrollable</td>
+ *    <td>Scrollable contains scrolled controls.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:2em">@ref dali_toolkit_controls_item_view</td>
+ *    <td>ItemView class is a scrollable container that can contain many items.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:2em">@ref dali_toolkit_controls_scroll_view</td>
+ *    <td>ScrollView class provides scrollable view which contains actors and can be scrolled automatically or manually by panning.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_table_view</td>
+ *    <td>TableView class is a layout container for aligning child actors in a grid like layout.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_text_controls</td>
+ *    <td>Controls for displaying text or text input.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_flex_container</td>
+ *    <td>FlexContainer is a container for Flexbox layout.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_video_view</td>
+ *    <td>VideoView is a control for video playback and display.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_slider</td>
+ *    <td>Slider is a control to enable sliding an indicator between two values.</td>
+ * </tr>
+ * <tr>
+ *    <td style="padding-left:1em">@ref dali_toolkit_controls_progress_bar</td>
+ *    <td>ProgressBar is a control to give the user an indication of the progress of an operation.</td>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_toolkit_managers</td>
+ *    <td>Singleton classes for managing application-wide functionalities.</td>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_toolkit_visuals</td>
+ *    <td>Visuals can control rendering the contents as using Property.</td>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_toolkit_image_loader</td>
+ *    <td>The ImageLoader is used to load pixel data from a URL.</td>
+ * </tr>
+ * </table>
+ *
+ * \ifnot show_tizen_feature
+ *
+ * @section dali_toolkit_feature Related Features
+ * This API is related with the following features:\n
+ *    - http://tizen.org/feature/opengles.version.2_0\n
+ *
+ * It is recommended to design feature related codes in your application for reliability.\n
+ *
+ * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n
+ *
+ * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
+ *
+ * More details on featuring your application can be found from <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
+ *
+ * \endif
+ *
+ * @ingroup dali
+ * @{
+ *   @defgroup dali_toolkit_controls Controls
+ *   @brief Controls are interactive components for layouting the user interface.
+
+ *   @{
+ *     @defgroup dali_toolkit_controls_alignment Alignment
+ *     @brief Alignment is a container which provides an easy way to align other actors inside its boundary.
+
+ *     @defgroup dali_toolkit_controls_buttons Buttons
+ *     @brief Button is a small object on UI that you can press.
+
+ *     @defgroup dali_toolkit_controls_gaussian_blur_view Gaussian Blur View
+ *     @brief GaussianBlurView provides a render process that blurs an image.
+
+ *     @defgroup dali_toolkit_controls_image_view Image View
+ *     @brief ImageView is a control displaying an image.
+
+ *     @defgroup dali_toolkit_controls_model3d_view Model3dView
+ *     @brief Model3dView is a control for displaying 3d geometry.
+
+ *     @defgroup dali_toolkit_controls_scroll_bar Scroll Bar
+ *     @brief ScrollBar is a component that can be linked to the scrollable objects.
+
+ *     @defgroup dali_toolkit_controls_scrollable Scrollable
+ *     @brief Scrollable contains scrolled controls.
+
+ *     @{
+ *       @defgroup dali_toolkit_controls_item_view Item View
+ *       @brief ItemView class is a scrollable container that can contain many items.
+
+ *       @defgroup dali_toolkit_controls_scroll_view Scroll View
+ *       @brief ScrollView class provides scrollable view which contains actors and can be scrolled automatically or manually by panning.
+
+ *     @}
+ *     @defgroup dali_toolkit_controls_table_view Table View
+ *     @brief TableView class is a layout container for aligning child actors in a grid like layout.
+
+ *     @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_controls_video_view Video View
+ *     @brief VideoView is a control for video playback and display.
+
+ *     @defgroup dali_toolkit_controls_slider Slider
+ *     @brief Slider is a control to enable sliding an indicator between two values.
+
+ *     @defgroup dali_toolkit_controls_progress_bar Progress Bar
+ *     @brief ProgressBar is a control to give the user an indication of the progress of an operation.
+
+ *   @}
+
+ *   @defgroup dali_toolkit_managers Managers
+ *   @brief Singleton classes for managing application-wide functionalities.
+
+ *   @defgroup dali_toolkit_visuals Visuals
+ *   @brief Visuals can control rendering the contents as using Property.
+
+ *   @defgroup dali_toolkit_image_loader Image Loader
+ *   @brief The ImageLoader is used to load pixel data from a URL.
+
+ * @}
+ */
+
+#endif // DALI_TOOLKIT_DOC_H
diff --git a/doc/file.list b/doc/file.list
new file mode 100644 (file)
index 0000000..f9b5116
--- /dev/null
@@ -0,0 +1,5 @@
+# Files to install here
+SET( package_doxy_files
+  ${package_doxy_dir}/dali-toolkit-doc.h
+)
+
diff --git a/doc/images/dali-modules.png b/doc/images/dali-modules.png
new file mode 100755 (executable)
index 0000000..d85303c
Binary files /dev/null and b/doc/images/dali-modules.png differ
diff --git a/docs/DaliLayout.xml b/docs/DaliLayout.xml
new file mode 100644 (file)
index 0000000..beff399
--- /dev/null
@@ -0,0 +1,188 @@
+<doxygenlayout version="1.0">
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="mainpage" visible="yes" title=""/>
+    <tab type="pages" visible="yes" title="" intro=""/>
+    <tab type="modules" visible="yes" title="" intro=""/>
+    <tab type="namespaces" visible="yes" title="">
+      <tab type="namespacelist" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="yes" title="">
+      <tab type="classlist" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="">
+      <tab type="filelist" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="examples" visible="yes" title="" intro=""/>
+    <tab type="user" visible="yes" title="Deprecated" intro="" url="deprecated.html"/>
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <allmemberslink visible="yes"/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <nestedgroups visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/docs/README b/docs/README
new file mode 100644 (file)
index 0000000..7acb25f
--- /dev/null
@@ -0,0 +1,9 @@
+To build the documentation from a Desktop build environment
+
+On the desktop:
+- cd dali-toolkit/build/tizen/docs
+- doxygen dali.doxy
+  or
+  make
+
+To view the output: firefox docs/generated/html/index.html
diff --git a/docs/api_footer.html b/docs/api_footer.html
new file mode 100644 (file)
index 0000000..0179c50
--- /dev/null
@@ -0,0 +1,2 @@
+<hr>\r
+<a href="http://www.samsung.com">Copyright (c) 2008-2015 Samsung Electronics, Co., Ltd.</a></body></html>\r
diff --git a/docs/content/example-code/CMakeLists.txt b/docs/content/example-code/CMakeLists.txt
new file mode 100644 (file)
index 0000000..133ab59
--- /dev/null
@@ -0,0 +1,22 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+SET(PKG_LIST dali-core
+             dali-adaptor
+             dali-toolkit)
+INCLUDE(FindPkgConfig)
+PKG_CHECK_MODULES(REQUIRED_PKGS REQUIRED ${PKG_LIST})
+
+FOREACH(flag ${REQUIRED_PKGS_CFLAGS})
+        SET(REQUIRED_CFLAGS "${REQUIRED_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${REQUIRED_CFLAGS} -Werror -Wall")
+SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")
+
+FILE(GLOB SRCS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.cpp")
+
+FOREACH(EXAMPLE ${SRCS})
+  STRING(REGEX REPLACE ".cpp" "" EXECUTABLE "${EXAMPLE}")
+  ADD_EXECUTABLE (${EXECUTABLE}.example ${EXAMPLE})
+  TARGET_LINK_LIBRARIES(${EXECUTABLE}.example ${REQUIRED_PKGS_LDFLAGS})
+ENDFOREACH(EXAMPLE)
diff --git a/docs/content/example-code/images/cards.jpg b/docs/content/example-code/images/cards.jpg
new file mode 100644 (file)
index 0000000..11bd590
Binary files /dev/null and b/docs/content/example-code/images/cards.jpg differ
diff --git a/docs/content/example-code/properties.cpp b/docs/content/example-code/properties.cpp
new file mode 100644 (file)
index 0000000..a68bb02
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017 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/dali.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <sstream>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+
+// The name we will use to register our custom property by.
+const char* const TAG_PROPERTY_NAME = "tagIdentifier";
+
+// The image for our image view
+const char* const IMAGE_CARDS = "images/cards.jpg";
+}  // namespace
+
+/**
+ * This example shows how to set properties in C++ and how to register and look-up custom properties.
+ * An image is added to the screen which changes and a custom property is added to the image-view.
+ * This value is incremented every time the image is touched and the text-label is updated.
+ */
+class PropertyController: public ConnectionTracker
+{
+public:
+
+  PropertyController( Application& application )
+  : mTagText(),
+    mTagPropertyIndex( Property::INVALID_INDEX )
+  {
+    // Connect to the Application's Init signal
+    application.InitSignal().Connect( this, &PropertyController::Create );
+  }
+
+  ~PropertyController()
+  {
+  }
+
+  // C++ EXAMPLE
+  void Create( Application& application )
+  {
+    // Get the stage handle
+    Stage stage = Stage::GetCurrent();
+
+    mImageView = ImageView::New();
+
+    // Set the property to move to the center
+    mImageView.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
+
+    // Set another property to set the image-map
+    Property::Map imageMap;
+    imageMap[ Visual::Property::TYPE ] = Visual::IMAGE;
+    imageMap[ ImageVisual::Property::URL ] = IMAGE_CARDS;
+    imageMap[ ImageVisual::Property::DESIRED_WIDTH ] = 100;
+    imageMap[ ImageVisual::Property::DESIRED_HEIGHT ] = 100;
+    mImageView.SetProperty( ImageView::Property::IMAGE, imageMap );
+
+    // Add the image view to the stage
+    stage.Add( mImageView );
+
+    // Register a custom float property on mImageView and use it to store the number of times we are tapped
+    mTagPropertyIndex = mImageView.RegisterProperty( TAG_PROPERTY_NAME, 0, Property::READ_WRITE /* Event-side only, i.e. not animatable */ );
+
+    // Connect to the touch-event
+    mImageView.TouchSignal().Connect( this, &PropertyController::OnTouched );
+
+    // Create text label
+    mTagText = Toolkit::TextLabel::New( "0" );
+    mTagText.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+    mTagText.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
+    mTagText.SetProperty( TextLabel::Property::TEXT_COLOR, Color::WHITE );
+    mTagText.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+    stage.Add( mTagText );
+  }
+
+  /**
+   * Called when the image view is touched
+   * param[in] touch The touch-event
+   * return Set to true if the signal was consumed correctly
+   */
+  bool OnTouched( Actor actor, const TouchData& touch )
+  {
+    int touchedCount = 0;
+
+    // Look up the tag property by the cached property index.
+    // Note: If the property belongs to a control in another library, or we do not know the index, we can look the index up first with:
+    // Property::Index index = actor.GetPropertyIndex( TAG_PROPERTY_NAME );
+    actor.GetProperty( mTagPropertyIndex ).Get( touchedCount );
+
+    // Increment and set back again
+    ++touchedCount;
+    actor.SetProperty( mTagPropertyIndex, touchedCount );
+
+    // Set the text in the text-label
+    std::stringstream valueText;
+    valueText << touchedCount;
+    mTagText.SetProperty( TextLabel::Property::TEXT, valueText.str() );
+
+    return true; // Consumed
+  }
+  // C++ EXAMPLE END
+
+private:
+
+  ImageView mImageView;              ///< An image view to show an image
+  TextLabel mTagText;                 ///< A text label used to show the last button pressed.
+  Property::Index mTagPropertyIndex;  ///< A cached property index of our custom tag property.
+};
+
+// Entry point for applications.
+int main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv );
+
+  PropertyController test( application );
+  application.MainLoop();
+
+  return 0;
+}
diff --git a/docs/content/figures/image-scaling/cards.jpg b/docs/content/figures/image-scaling/cards.jpg
new file mode 100644 (file)
index 0000000..9af5d02
Binary files /dev/null and b/docs/content/figures/image-scaling/cards.jpg differ
diff --git a/docs/content/figures/image-scaling/concept-rectangles.svg b/docs/content/figures/image-scaling/concept-rectangles.svg
new file mode 100644 (file)
index 0000000..0b4cebc
--- /dev/null
@@ -0,0 +1,909 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="concept-rectangles.svg"
+   inkscape:export-filename="/tmp/page.png"
+   inkscape:export-xdpi="89.269394"
+   inkscape:export-ydpi="89.269394">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="DotL"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="DotL"
+       style="overflow:visible">
+      <path
+         id="path4335"
+         d="M -2.5,-1.0 C -2.5,1.7600000 -4.7400000,4.0 -7.5,4.0 C -10.260000,4.0 -12.5,1.7600000 -12.5,-1.0 C -12.5,-3.7600000 -10.260000,-6.0 -7.5,-6.0 C -4.7400000,-6.0 -2.5,-3.7600000 -2.5,-1.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         transform="scale(0.8) translate(7.4, 1)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Mend"
+       style="overflow:visible;">
+      <path
+         id="path4301"
+         style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(0.6) rotate(180) translate(0,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow2Lend"
+       style="overflow:visible;">
+      <path
+         id="path4295"
+         style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+         transform="scale(1.1) rotate(180) translate(1,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lend"
+       style="overflow:visible;">
+      <path
+         id="path4277"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <linearGradient
+       id="linearGradient5404"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5406" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5408" />
+    </linearGradient>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-0"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4301-1"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-1"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4301-7"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-2"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4301-75"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-08"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4301-71"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend-5"
+       style="overflow:visible">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4301-6"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.45254834"
+     inkscape:cx="743.41974"
+     inkscape:cy="837.71772"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1158"
+     inkscape:window-x="1200"
+     inkscape:window-y="418"
+     inkscape:window-maximized="1"
+     objecttolerance="4"
+     gridtolerance="4">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3181"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="32px"
+       spacingy="32px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-308.2677)">
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/image-scaling/cards.jpg"
+       xlink:href="cards.jpg"
+       y="-387.63782"
+       x="160"
+       id="image4157"
+       height="256"
+       width="256"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30"
+       width="128"
+       height="192.00003"
+       x="128"
+       y="636.36212"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-3"
+       width="1.0498172e-05"
+       height="192"
+       x="191.99998"
+       y="188.36218"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.63730645;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-0"
+       width="96.000015"
+       height="1.7800441e-05"
+       x="143.99998"
+       y="508.36218"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-31"
+       width="192"
+       height="192"
+       x="512"
+       y="188.36212"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.14999795;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-34"
+       width="95.999939"
+       height="95.999954"
+       x="560"
+       y="460.36221"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-4"
+       width="128"
+       height="192.00003"
+       x="544"
+       y="636.36212"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.27617979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 224,284.36215 c 256,0 256,0 256,0"
+       id="path4268"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 288,732.36221 c 224,0 224,0 224,0"
+       id="path4268-0"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 280.67645,508.36215 c 224,0 247.40075,3e-5 247.40075,3e-5"
+       id="path4268-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-mid:none;marker-end:none"
+       d="m 352,-99.6378 c 0,159.99998 0,383.99998 0,383.99998"
+       id="path5307"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-mid:url(#DotL)"
+       d="m 320,-99.6378 0,607.99998"
+       id="path5879"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 688.3995,508.36218 c 224,0 239.6005,0 239.6005,0"
+       id="path4268-4-4"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 704,732.36218 96,0 0,-224"
+       id="path6099"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 736,284.36218 64,0 0,224 0,0 0,0"
+       id="path6101"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-4-1"
+       width="96"
+       height="96"
+       x="960"
+       y="460.32184"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-31-3"
+       width="256"
+       height="256"
+       x="160"
+       y="-387.63782"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 864,508.36218 c 0,-511.9999802 0,-735.99998 0,-735.99998 l -416,0"
+       id="path6157"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/image-scaling/cards.jpg"
+       xlink:href="cards.jpg"
+       y="636.36243"
+       x="1423.9999"
+       id="image4157-4-5"
+       height="96.000244"
+       width="96.000244"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 1088,508.36218 c 72.8302,0 192,0 192,0"
+       id="path4268-4-4-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6201"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(128,1044.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6203"><rect
+           id="rect6205"
+           width="132.37465"
+           height="33.093662"
+           x="1085.7874"
+           y="-436.24619" /></flowRegion><flowPara
+         id="flowPara6207" /></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6415"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(128,1044.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6417"><rect
+           id="rect6419"
+           width="129.22287"
+           height="96.129211"
+           x="-3.1517775"
+           y="-119.49255" /></flowRegion><flowPara
+         id="flowPara6421" /></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6423"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(128,1044.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6425"><rect
+           id="rect6427"
+           width="129.22287"
+           height="111.8881"
+           x="0"
+           y="-117.91666" /></flowRegion><flowPara
+         id="flowPara6429"
+         style="font-weight:normal">Requested Size</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6431"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(-44.87499,5.9402098)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6433"><rect
+           id="rect6435"
+           width="168.25861"
+           height="49.914528"
+           x="193.83432"
+           y="-119.49255" /></flowRegion><flowPara
+         id="flowPara6437">Raw size (e.)</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6439"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(128,1044.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6441"><rect
+           id="rect6443"
+           width="256"
+           height="89.944725"
+           x="352"
+           y="-119.90552"
+           ry="0" /></flowRegion><flowPara
+         id="flowPara6445">Target for fitting</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6447"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(114.89062,696.48284)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6449"><rect
+           id="rect6451"
+           width="130.3277"
+           height="34.676437"
+           x="830.49335"
+           y="-116.34077" /></flowRegion><flowPara
+         id="flowPara6453">Fitted Size</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6455"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(285.45703,886.12794)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6457"><rect
+           id="rect6459"
+           width="192"
+           height="52.511868"
+           x="1090.3438"
+           y="-113.69655" /></flowRegion><flowPara
+         id="flowPara6461">Scaled Pixels</flowPara></flowRoot>    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:6.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-3-0"
+       width="1.4271966"
+       height="8.0063074e-11"
+       x="192"
+       y="-3.6378176"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-30-31-3-4"
+       width="256"
+       height="256"
+       x="480"
+       y="-131.63782"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.35555581;stroke-dasharray:4.19999981, 12.59999943;stroke-dashoffset:0"
+       id="rect6501-6"
+       width="320"
+       height="1184"
+       x="448"
+       y="-163.63782"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:4.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.35555581000000003;stroke-dasharray:4.2,12.6;stroke-dashoffset:0"
+       id="rect6501"
+       width="192"
+       height="1024"
+       x="96"
+       y="-35.637817"
+       ry="0"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot6521"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(128,1044.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion6523"><rect
+           id="rect6525"
+           width="16.714825"
+           height="34.543972"
+           x="603.96234"
+           y="-92.761055" /></flowRegion><flowPara
+         id="flowPara6527" /></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:4.27617979;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
+       d="m 224,-3.6378202 c 192,0 199.26801,0 199.26801,0"
+       id="path4268-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-mid:none;marker-end:none"
+       d="m 384,-99.63782 c 0,95.9999998 0,95.9999998 0,95.9999998"
+       id="path5307-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 800,284.36218 c 0,-287.9999802 0,-287.9999802 0,-287.9999802 l -32,0"
+       id="path6571"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-mid:none;marker-end:none"
+       d="m 448,-291.6378 c 832,0 736,-2e-5 736,-2e-5 l 0,800"
+       id="path6573"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccc"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/image-scaling/cards.jpg"
+       xlink:href="cards.jpg"
+       y="444.36243"
+       x="1407.9999"
+       id="image4157-0"
+       height="128.00024"
+       width="128.00024"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/image-scaling/cards.jpg"
+       xlink:href="cards.jpg"
+       y="124.36218"
+       x="1344"
+       id="image4157-4"
+       height="256"
+       width="256"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot7007"
+       style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Sans;font-style:normal;font-weight:normal;font-size:24px;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;text-align:center"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion7009"><rect
+           id="rect7011"
+           width="14.182999"
+           height="64.611435"
+           x="1279.6217"
+           y="594.38507" /></flowRegion><flowPara
+         id="flowPara7013" /></flowRoot>    <rect
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.35555581;stroke-dasharray:4.2, 12.6;stroke-dashoffset:0"
+       id="rect6501-6-0"
+       width="320"
+       height="736.00024"
+       x="1312"
+       y="92.362183"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot7035"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(-34.212099,300.28395)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion7037"><rect
+           id="rect7039"
+           width="128.02527"
+           height="133.95055"
+           x="1151.9747"
+           y="361.1535" /></flowRegion><flowPara
+         id="flowPara7041">SamplingMode</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:4.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 1184,328.09448 c 0,-128 0,-128 0,-128"
+       id="path7439"
+       inkscape:connector-curvature="0"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot7035-9"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(-351.98437,301.85984)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion7037-2"><rect
+           id="rect7039-7"
+           width="128.02527"
+           height="133.95055"
+           x="1151.9747"
+           y="361.1535" /></flowRegion><flowPara
+         id="flowPara7041-2">Fitting Mode</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 864,636.36218 c 0,-128 0,-128 0,-128"
+       id="path7439-2"
+       inkscape:connector-curvature="0"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.35555576;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect7524"
+       width="88.249771"
+       height="73.972183"
+       x="821.03802"
+       y="350.12228"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       ry="20.057787" />
+    <rect
+       style="fill:none;stroke:#000000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.3555557;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect7526"
+       width="128"
+       height="77.123962"
+       x="1120"
+       y="346.97052"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       ry="23.400755" />
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="1482.6659"
+       y="403.63452"
+       id="text7530"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532"
+         x="1482.6659"
+         y="403.63452">k.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="1472"
+       y="604.36218"
+       id="text7534"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7536"
+         x="1472"
+         y="604.36218">l.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="1472"
+       y="753.48798"
+       id="text7538"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7540"
+         x="1472"
+         y="753.48798">m.</tspan></text>
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:none"
+       id="path7542"
+       sodipodi:cx="1424"
+       sodipodi:cy="-327.90552"
+       sodipodi:rx="16"
+       sodipodi:ry="16"
+       d="m 1440,-327.90552 c 0,8.83656 -7.1634,16 -16,16 -8.8366,0 -16,-7.16344 -16,-16 0,-8.83655 7.1634,-16 16,-16 8.8366,0 16,7.16345 16,16 z"
+       transform="matrix(0.5,0,0,0.5,472,672.43994)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:none"
+       id="path7542-2"
+       sodipodi:cx="1424"
+       sodipodi:cy="-327.90552"
+       sodipodi:rx="16"
+       sodipodi:ry="16"
+       d="m 1440,-327.90552 c 0,8.83656 -7.1634,16 -16,16 -8.8366,0 -16,-7.16344 -16,-16 0,-8.83655 7.1634,-16 16,-16 8.8366,0 16,7.16345 16,16 z"
+       transform="matrix(0.5,0,0,0.5,152,672.43994)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       sodipodi:type="arc"
+       style="fill:#000000;fill-opacity:1;stroke:none"
+       id="path7542-1"
+       sodipodi:cx="1424"
+       sodipodi:cy="-327.90552"
+       sodipodi:rx="16"
+       sodipodi:ry="16"
+       d="m 1440,-327.90552 c 0,8.83656 -7.1634,16 -16,16 -8.8366,0 -16,-7.16344 -16,-16 0,-8.83655 7.1634,-16 16,-16 8.8366,0 16,7.16345 16,16 z"
+       transform="matrix(0.5,0,0,0.5,88,672.51025)"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="192"
+       y="34.160557"
+       id="text7530-8"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7"
+         x="192"
+         y="34.160557">a.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="192"
+       y="414.78287"
+       id="text7530-8-1"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-2"
+         x="192"
+         y="414.78287">b.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="192"
+       y="546.16058"
+       id="text7530-8-6"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-9"
+         x="192"
+         y="546.16058">c.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="192"
+       y="866.16058"
+       id="text7530-8-7"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-4"
+         x="192"
+         y="866.16058">d.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="608"
+       y="162.16058"
+       id="text7530-8-3"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-6"
+         x="608"
+         y="162.16058">f.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="608"
+       y="418.16058"
+       id="text7530-8-33"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-48"
+         x="608"
+         y="418.16058">g.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="608"
+       y="596.53143"
+       id="text7530-8-0"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-0"
+         x="608"
+         y="596.53143">h.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="608"
+       y="866.16058"
+       id="text7530-8-68"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-66"
+         x="608"
+         y="866.16058">i.</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="1003.7878"
+       y="632.43921"
+       id="text7530-8-2"
+       sodipodi:linespacing="125%"
+       inkscape:export-filename="/tmp/concept-rectangles.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><tspan
+         sodipodi:role="line"
+         id="tspan7532-7-68"
+         x="1003.7878"
+         y="632.43921">j.</tspan></text>
+  </g>
+</svg>
diff --git a/docs/content/figures/image-scaling/dog.jpg b/docs/content/figures/image-scaling/dog.jpg
new file mode 100644 (file)
index 0000000..f7d2cc4
Binary files /dev/null and b/docs/content/figures/image-scaling/dog.jpg differ
diff --git a/docs/content/figures/image-scaling/door.jpg b/docs/content/figures/image-scaling/door.jpg
new file mode 100644 (file)
index 0000000..7317ea5
Binary files /dev/null and b/docs/content/figures/image-scaling/door.jpg differ
diff --git a/docs/content/figures/image-scaling/example-fitting-mode-options.svg b/docs/content/figures/image-scaling/example-fitting-mode-options.svg
new file mode 100644 (file)
index 0000000..17b4c6f
--- /dev/null
@@ -0,0 +1,547 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="example-fitting-mode-options.svg"
+   inkscape:export-filename="1.png"
+   inkscape:export-xdpi="89.269394"
+   inkscape:export-ydpi="89.269394">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient5404"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5406" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5408" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.63456256"
+     inkscape:cx="704.49723"
+     inkscape:cy="501.75416"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1158"
+     inkscape:window-x="1200"
+     inkscape:window-y="418"
+     inkscape:window-maximized="1"
+     objecttolerance="4"
+     gridtolerance="4">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3181"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="32px"
+       spacingy="32px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-308.2677)">
+    <image
+       sodipodi:absref="door.jpg"
+       xlink:href="door.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="256"
+       height="256"
+       id="image6106"
+       x="32"
+       y="92.362183" />
+    <g
+       id="g6199"
+       transform="matrix(0.75,0,0,0.75,158.83024,-448.90946)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="door.jpg"
+         xlink:href="door.jpg"
+         inkscape:export-ydpi="89.269394"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-filename="door-scale-to-fill2.png"
+         y="764.36218"
+         x="512"
+         id="image6106-0"
+         height="256"
+         width="256" />
+      <rect
+         y="764.36218"
+         x="719.81006"
+         height="258.6265"
+         width="51.309372"
+         id="rect6179"
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         inkscape:export-filename="door-scale-to-fill.png"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-ydpi="89.269394" />
+      <rect
+         y="764.36218"
+         x="512"
+         height="259.15176"
+         width="48.189934"
+         id="rect6179-2"
+         style="fill:#ffffff;fill-opacity:1;stroke:none"
+         inkscape:export-filename="door-scale-to-fill.png"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-ydpi="89.269394" />
+      <rect
+         inkscape:export-ydpi="89.269394"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-filename="door-scale-to-fill2.png"
+         y="764.36218"
+         x="560"
+         height="256.00003"
+         width="160"
+         id="rect3183-1-9-1-6"
+         style="fill:none;stroke:#ff0000;stroke-width:4.28426027;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.21319532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1"
+       width="120"
+       height="192.00003"
+       x="356"
+       y="124.36218"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="door.jpg"
+       xlink:href="door.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="120"
+       height="135.85014"
+       id="image6106-5"
+       x="804"
+       y="152.43707" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.21319532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-4"
+       width="120"
+       height="192.00003"
+       x="804"
+       y="124.36212"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="door.jpg"
+       xlink:href="door.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="120"
+       height="135.85014"
+       id="image6106-5-3"
+       x="1030.3395"
+       y="152.43707" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.21319532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-4-1"
+       width="120"
+       height="192.00003"
+       x="1030.3395"
+       y="124.36212"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="door.jpg"
+       xlink:href="door.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="192"
+       height="192"
+       id="image6106-4"
+       x="1218.3396"
+       y="124.36218" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.21319532;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-3"
+       width="120"
+       height="192.00003"
+       x="1254.3396"
+       y="124.36218"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="dog.jpg"
+       xlink:href="dog.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="256"
+       height="256"
+       id="image6359"
+       x="32"
+       y="412.36218" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.31857371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-0"
+       width="128.00003"
+       height="192"
+       x="-604.36218"
+       y="320"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       transform="matrix(0,-1,1,0,0,0)" />
+    <g
+       id="g6476"
+       transform="translate(-7.128906e-7,-384.82965)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="dog.jpg"
+         xlink:href="dog.jpg"
+         y="829.19183"
+         x="544"
+         id="image6359-2"
+         height="192"
+         width="192" />
+      <rect
+         transform="translate(0,308.2677)"
+         y="520.09448"
+         x="544"
+         height="32"
+         width="192"
+         id="rect6470"
+         style="fill:#ffffff;fill-opacity:1;stroke:none" />
+      <rect
+         transform="translate(0,308.2677)"
+         y="680.09448"
+         x="541.66046"
+         height="33.94965"
+         width="196.67912"
+         id="rect6474"
+         style="fill:#ffffff;fill-opacity:1;stroke:none" />
+      <rect
+         transform="matrix(0,-1,1,0,0,0)"
+         inkscape:export-ydpi="89.269394"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-filename="example-scale-to-fill-sequence.png"
+         y="544"
+         x="-989.19183"
+         height="192"
+         width="128.00003"
+         id="rect3183-1-9-1-0-2"
+         style="fill:none;stroke:#ff0000;stroke-width:3.31857371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <image
+       sodipodi:absref="dog.jpg"
+       xlink:href="dog.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="192"
+       height="192"
+       id="image6359-2-2"
+       x="994.33954"
+       y="445.19183" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.31857371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-0-4"
+       width="128.00003"
+       height="192"
+       x="-605.19183"
+       y="994.33954"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       transform="matrix(0,-1,1,0,0,0)" />
+    <image
+       sodipodi:absref="dog.jpg"
+       xlink:href="dog.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="128"
+       height="128"
+       id="image6359-2-2-2"
+       x="1250.3396"
+       y="477.19183" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.31857371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-0-0"
+       width="128.00003"
+       height="192"
+       x="-605.19183"
+       y="1218.3396"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       transform="matrix(0,-1,1,0,0,0)" />
+    <image
+       sodipodi:absref="dog.jpg"
+       xlink:href="dog.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="128"
+       height="128"
+       id="image6359-2-2-2-1"
+       x="800"
+       y="476.36218" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:3.31857371;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9-1-0-0-6"
+       width="128.00003"
+       height="192"
+       x="-604.36218"
+       y="768"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"
+       transform="matrix(0,-1,1,0,0,0)" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3024"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3026"><rect
+           id="rect3028"
+           width="256.29398"
+           height="127.03266"
+           x="33.429649"
+           y="746.32312" /></flowRegion><flowPara
+         id="flowPara3030">Raw Image</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3032"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3034"><rect
+           id="rect3036"
+           width="192.25842"
+           height="96.91716"
+           x="318.32953"
+           y="744.09448" /></flowRegion><flowPara
+         id="flowPara3038">Fitting Target</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3040"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3042"><rect
+           id="rect3044"
+           width="192.25842"
+           height="91.40155"
+           x="542.89368"
+           y="744.88245" /></flowRegion><flowPara
+         id="flowPara3046">SCALE_TO_FILL</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3048"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3050"><rect
+           id="rect3052"
+           width="193.83432"
+           height="96.91716"
+           x="767.45782"
+           y="744.09448" /></flowRegion><flowPara
+         id="flowPara3054">SHRINK_TO_FIT</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3056"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3058"><rect
+           id="rect3060"
+           width="193.83432"
+           height="126.85905"
+           x="990.44611"
+           y="745.67035" /></flowRegion><flowPara
+         id="flowPara3062">FIT_WIDTH</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3064"
+       style="font-size:24px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       transform="translate(0,244.2677)"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394"><flowRegion
+         id="flowRegion3066"><rect
+           id="rect3068"
+           width="193.04637"
+           height="100.06894"
+           x="1215.7982"
+           y="744.88245" /></flowRegion><flowPara
+         id="flowPara3070">FIT_HEIGHT</flowPara></flowRoot>    <image
+       sodipodi:absref="liberty.jpg"
+       xlink:href="liberty.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="fitting-mode-options.png"
+       width="256"
+       height="256"
+       id="image3239"
+       x="32"
+       y="700.36218" />
+    <g
+       id="g4034"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <rect
+         y="764.36218"
+         x="352"
+         height="128"
+         width="128"
+         id="rect3244"
+         style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+         inkscape:export-filename="fitting-mode-options.png"
+         inkscape:export-xdpi="89.269394"
+         inkscape:export-ydpi="89.269394" />
+    </g>
+    <g
+       transform="translate(224,-1.9531262e-7)"
+       id="g4034-5"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="liberty.jpg"
+         xlink:href="liberty.jpg"
+         y="764.36218"
+         x="352"
+         id="image3239-9-8"
+         height="128"
+         width="128" />
+      <rect
+         y="764.36218"
+         x="352"
+         height="128"
+         width="128"
+         id="rect3244-5"
+         style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <g
+       transform="translate(448,-1.9531262e-7)"
+       id="g4034-4"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="liberty.jpg"
+         xlink:href="liberty.jpg"
+         y="764.36218"
+         x="352"
+         id="image3239-9-88"
+         height="128"
+         width="128" />
+      <rect
+         y="764.36218"
+         x="352"
+         height="128"
+         width="128"
+         id="rect3244-9"
+         style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <g
+       transform="translate(672,-1.9531262e-7)"
+       id="g4034-3"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="liberty.jpg"
+         xlink:href="liberty.jpg"
+         y="764.36218"
+         x="352"
+         id="image3239-9-85"
+         height="128"
+         width="128" />
+      <rect
+         y="764.36218"
+         x="352"
+         height="128"
+         width="128"
+         id="rect3244-8"
+         style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+    <g
+       transform="translate(896,-1.9531262e-7)"
+       id="g4034-2"
+       inkscape:export-filename="fitting-mode-options.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394">
+      <image
+         sodipodi:absref="liberty.jpg"
+         xlink:href="liberty.jpg"
+         y="764.36218"
+         x="352"
+         id="image3239-9-7"
+         height="128"
+         width="128" />
+      <rect
+         y="764.36218"
+         x="352"
+         height="128"
+         width="128"
+         id="rect3244-95"
+         style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    </g>
+  </g>
+</svg>
diff --git a/docs/content/figures/image-scaling/example-scale-to-fill-problem.svg b/docs/content/figures/image-scaling/example-scale-to-fill-problem.svg
new file mode 100644 (file)
index 0000000..fcdde97
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="example-scale-to-fill-problem.svg"
+   inkscape:export-filename="/tmp/example-scale-to-fill-sequence.png"
+   inkscape:export-xdpi="89.269394"
+   inkscape:export-ydpi="89.269394">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient5404"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5406" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5408" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.94173904"
+     inkscape:cx="330.62812"
+     inkscape:cy="291.60912"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1158"
+     inkscape:window-x="1200"
+     inkscape:window-y="418"
+     inkscape:window-maximized="1"
+     objecttolerance="4"
+     gridtolerance="4">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3181"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="32px"
+       spacingy="32px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-308.2677)">
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/phone.png"
+       xlink:href="phone.png"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="/tmp/image3087.png"
+       width="187"
+       height="348"
+       id="image3087"
+       x="736"
+       y="608.36218" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/gallery-large-12.jpg"
+       xlink:href="gallery-large-12.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="/tmp/image3087.png"
+       width="512"
+       height="512"
+       id="image3178"
+       x="32"
+       y="508.36218" />
+    <rect
+       style="fill:#ffffff;fill-opacity:1;stroke-width:4.19999980999999956;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ff0000;stroke-opacity:1"
+       id="rect3183"
+       width="154.95831"
+       height="254.03409"
+       x="753.73383"
+       y="347.32999"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/image3087.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:4.19999980999999956;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3957"
+       width="512"
+       height="512"
+       x="32"
+       y="200.09448"
+       transform="translate(0,308.2677)"
+       ry="0"
+       inkscape:export-filename="/tmp/image3087.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#ff0000;stroke-width:4.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 554.87974,200.09448 C 736,345.39199 736,346.14284 736,346.14284"
+       id="path5414"
+       inkscape:connector-curvature="0"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/image3087.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <path
+       style="fill:none;stroke:#ff0000;stroke-width:4.20000000000000018;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 553.37804,712.09448 C 736,604.43598 736,604.43598 736,604.43598"
+       id="path5416"
+       inkscape:connector-curvature="0"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/image3087.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+  </g>
+</svg>
diff --git a/docs/content/figures/image-scaling/example-scale-to-fill-sequence.svg b/docs/content/figures/image-scaling/example-scale-to-fill-sequence.svg
new file mode 100644 (file)
index 0000000..12d0eec
--- /dev/null
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="example-scale-to-fill-sequence.svg"
+   inkscape:export-filename="/tmp/example-scale-to-fill-problem.png"
+   inkscape:export-xdpi="89.269394"
+   inkscape:export-ydpi="89.269394">
+  <defs
+     id="defs4">
+    <linearGradient
+       id="linearGradient5404"
+       osb:paint="gradient">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop5406" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop5408" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.94173902"
+     inkscape:cx="676.6218"
+     inkscape:cy="430.48889"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1158"
+     inkscape:window-x="1200"
+     inkscape:window-y="418"
+     inkscape:window-maximized="1"
+     objecttolerance="4"
+     gridtolerance="4">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3181"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="32px"
+       spacingy="32px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-308.2677)">
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:4.19999980999999956;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3957"
+       width="512"
+       height="512"
+       x="32"
+       y="200.09448"
+       transform="translate(0,308.2677)"
+       ry="0"
+       inkscape:export-filename="/tmp/rect3957.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/gallery-large-12.jpg"
+       xlink:href="gallery-large-12.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="/tmp/rect3957.png"
+       width="512"
+       height="512"
+       id="image3178"
+       x="32"
+       y="508.36218" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/gallery-large-12.jpg"
+       xlink:href="gallery-large-12.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="/tmp/rect3957.png"
+       width="256"
+       height="256"
+       id="image3178-6"
+       x="640"
+       y="636.36218" />
+    <rect
+       style="fill:none;stroke:#ff0000;stroke-width:4.19999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect5513"
+       width="256"
+       height="256"
+       x="640"
+       y="636.36218"
+       inkscape:export-filename="/tmp/rect3957.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <image
+       sodipodi:absref="/home/SERILOCAL/andrew.cox/git/opendali-features/dali-toolkit/docs/content/figures/gallery-large-12.jpg"
+       xlink:href="gallery-large-12.jpg"
+       inkscape:export-ydpi="89.269394"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-filename="/tmp/rect3957.png"
+       width="256"
+       height="256"
+       id="image3178-6-5"
+       x="992"
+       y="636.36218" />
+    <rect
+       style="fill:#000000;fill-opacity:0.74666664;stroke:none"
+       id="rect5554"
+       width="50.182735"
+       height="256"
+       x="992"
+       y="328.09448"
+       transform="translate(0,308.2677)"
+       inkscape:export-filename="/tmp/rect3957.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:#000000;fill-opacity:0.74666628;stroke:none"
+       id="rect5554-1"
+       width="50.182735"
+       height="256"
+       x="1197.8173"
+       y="636.36218"
+       inkscape:export-filename="/tmp/rect3957.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:4.19999980999999956;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3183-1-9"
+       width="154.95831"
+       height="254.03409"
+       x="1043.3221"
+       y="637.48846"
+       inkscape:export-filename="/tmp/rect3957.png"
+       inkscape:export-xdpi="89.269394"
+       inkscape:export-ydpi="89.269394" />
+  </g>
+</svg>
diff --git a/docs/content/figures/image-scaling/gallery-large-12.jpg b/docs/content/figures/image-scaling/gallery-large-12.jpg
new file mode 100644 (file)
index 0000000..7173b85
Binary files /dev/null and b/docs/content/figures/image-scaling/gallery-large-12.jpg differ
diff --git a/docs/content/figures/image-scaling/liberty.jpg b/docs/content/figures/image-scaling/liberty.jpg
new file mode 100644 (file)
index 0000000..e42dba7
Binary files /dev/null and b/docs/content/figures/image-scaling/liberty.jpg differ
diff --git a/docs/content/figures/image-scaling/phone-transparent-screen.png b/docs/content/figures/image-scaling/phone-transparent-screen.png
new file mode 100644 (file)
index 0000000..e8a988b
Binary files /dev/null and b/docs/content/figures/image-scaling/phone-transparent-screen.png differ
diff --git a/docs/content/figures/image-scaling/phone.png b/docs/content/figures/image-scaling/phone.png
new file mode 100644 (file)
index 0000000..250b881
Binary files /dev/null and b/docs/content/figures/image-scaling/phone.png differ
diff --git a/docs/content/images/accessibility/accessibility-focus-group.png b/docs/content/images/accessibility/accessibility-focus-group.png
new file mode 100644 (file)
index 0000000..5b175dc
Binary files /dev/null and b/docs/content/images/accessibility/accessibility-focus-group.png differ
diff --git a/docs/content/images/accessibility/accessibility-focus-order.png b/docs/content/images/accessibility/accessibility-focus-order.png
new file mode 100644 (file)
index 0000000..f85e5a5
Binary files /dev/null and b/docs/content/images/accessibility/accessibility-focus-order.png differ
diff --git a/docs/content/images/accessibility/accessibility-focus.png b/docs/content/images/accessibility/accessibility-focus.png
new file mode 100644 (file)
index 0000000..f745218
Binary files /dev/null and b/docs/content/images/accessibility/accessibility-focus.png differ
diff --git a/docs/content/images/actor-position.png b/docs/content/images/actor-position.png
new file mode 100644 (file)
index 0000000..f591fdc
Binary files /dev/null and b/docs/content/images/actor-position.png differ
diff --git a/docs/content/images/actors/Image-Actor.png b/docs/content/images/actors/Image-Actor.png
new file mode 100644 (file)
index 0000000..7c21ff8
Binary files /dev/null and b/docs/content/images/actors/Image-Actor.png differ
diff --git a/docs/content/images/actors/Text-Label.png b/docs/content/images/actors/Text-Label.png
new file mode 100644 (file)
index 0000000..cc2dc30
Binary files /dev/null and b/docs/content/images/actors/Text-Label.png differ
diff --git a/docs/content/images/actors/scale-none.png b/docs/content/images/actors/scale-none.png
new file mode 100644 (file)
index 0000000..0766dee
Binary files /dev/null and b/docs/content/images/actors/scale-none.png differ
diff --git a/docs/content/images/actors/scale-to-fill-keep-aspect.png b/docs/content/images/actors/scale-to-fill-keep-aspect.png
new file mode 100644 (file)
index 0000000..d6c20e8
Binary files /dev/null and b/docs/content/images/actors/scale-to-fill-keep-aspect.png differ
diff --git a/docs/content/images/actors/scale-to-fill.png b/docs/content/images/actors/scale-to-fill.png
new file mode 100644 (file)
index 0000000..1d7c88b
Binary files /dev/null and b/docs/content/images/actors/scale-to-fill.png differ
diff --git a/docs/content/images/actors/scale-to-fit-keep-aspect.png b/docs/content/images/actors/scale-to-fit-keep-aspect.png
new file mode 100644 (file)
index 0000000..9d6b91a
Binary files /dev/null and b/docs/content/images/actors/scale-to-fit-keep-aspect.png differ
diff --git a/docs/content/images/actors/shrink-to-fit-2.png b/docs/content/images/actors/shrink-to-fit-2.png
new file mode 100644 (file)
index 0000000..4796387
Binary files /dev/null and b/docs/content/images/actors/shrink-to-fit-2.png differ
diff --git a/docs/content/images/actors/shrink-to-fit-keep-aspect.png b/docs/content/images/actors/shrink-to-fit-keep-aspect.png
new file mode 100644 (file)
index 0000000..a832726
Binary files /dev/null and b/docs/content/images/actors/shrink-to-fit-keep-aspect.png differ
diff --git a/docs/content/images/actors/shrink-to-fit.png b/docs/content/images/actors/shrink-to-fit.png
new file mode 100644 (file)
index 0000000..b414fac
Binary files /dev/null and b/docs/content/images/actors/shrink-to-fit.png differ
diff --git a/docs/content/images/anchor-point.png b/docs/content/images/anchor-point.png
new file mode 100644 (file)
index 0000000..1db87e5
Binary files /dev/null and b/docs/content/images/anchor-point.png differ
diff --git a/docs/content/images/animation/anim1.png b/docs/content/images/animation/anim1.png
new file mode 100644 (file)
index 0000000..bf2f7ac
Binary files /dev/null and b/docs/content/images/animation/anim1.png differ
diff --git a/docs/content/images/animation/anim2.png b/docs/content/images/animation/anim2.png
new file mode 100644 (file)
index 0000000..05efa57
Binary files /dev/null and b/docs/content/images/animation/anim2.png differ
diff --git a/docs/content/images/animation/anim3.png b/docs/content/images/animation/anim3.png
new file mode 100644 (file)
index 0000000..ce12dde
Binary files /dev/null and b/docs/content/images/animation/anim3.png differ
diff --git a/docs/content/images/animation/animated-path.png b/docs/content/images/animation/animated-path.png
new file mode 100644 (file)
index 0000000..04ae2a6
Binary files /dev/null and b/docs/content/images/animation/animated-path.png differ
diff --git a/docs/content/images/animation/keyframe-animation.png b/docs/content/images/animation/keyframe-animation.png
new file mode 100644 (file)
index 0000000..37c3ebc
Binary files /dev/null and b/docs/content/images/animation/keyframe-animation.png differ
diff --git a/docs/content/images/animation/multi-threaded-animation-2.png b/docs/content/images/animation/multi-threaded-animation-2.png
new file mode 100644 (file)
index 0000000..2d481f1
Binary files /dev/null and b/docs/content/images/animation/multi-threaded-animation-2.png differ
diff --git a/docs/content/images/animation/multi-threaded-animation.png b/docs/content/images/animation/multi-threaded-animation.png
new file mode 100644 (file)
index 0000000..ebe0bef
Binary files /dev/null and b/docs/content/images/animation/multi-threaded-animation.png differ
diff --git a/docs/content/images/animation/set-position-vs-animation.png b/docs/content/images/animation/set-position-vs-animation.png
new file mode 100644 (file)
index 0000000..a6c61be
Binary files /dev/null and b/docs/content/images/animation/set-position-vs-animation.png differ
diff --git a/docs/content/images/architecture.png b/docs/content/images/architecture.png
new file mode 100644 (file)
index 0000000..d9aaa26
Binary files /dev/null and b/docs/content/images/architecture.png differ
diff --git a/docs/content/images/background/BackgroundBorder.png b/docs/content/images/background/BackgroundBorder.png
new file mode 100644 (file)
index 0000000..e580281
Binary files /dev/null and b/docs/content/images/background/BackgroundBorder.png differ
diff --git a/docs/content/images/background/BackgroundControlColor.png b/docs/content/images/background/BackgroundControlColor.png
new file mode 100644 (file)
index 0000000..2a2e2fc
Binary files /dev/null and b/docs/content/images/background/BackgroundControlColor.png differ
diff --git a/docs/content/images/background/BackgroundImage.png b/docs/content/images/background/BackgroundImage.png
new file mode 100644 (file)
index 0000000..5771d48
Binary files /dev/null and b/docs/content/images/background/BackgroundImage.png differ
diff --git a/docs/content/images/background/BackgroundImageColor.png b/docs/content/images/background/BackgroundImageColor.png
new file mode 100644 (file)
index 0000000..ba6a075
Binary files /dev/null and b/docs/content/images/background/BackgroundImageColor.png differ
diff --git a/docs/content/images/background/BackgroundTextLabel.png b/docs/content/images/background/BackgroundTextLabel.png
new file mode 100644 (file)
index 0000000..6bfe77f
Binary files /dev/null and b/docs/content/images/background/BackgroundTextLabel.png differ
diff --git a/docs/content/images/coordinate-system-and-stage.png b/docs/content/images/coordinate-system-and-stage.png
new file mode 100644 (file)
index 0000000..83c72fe
Binary files /dev/null and b/docs/content/images/coordinate-system-and-stage.png differ
diff --git a/docs/content/images/creating-custom-controls/control-handle-body.png b/docs/content/images/creating-custom-controls/control-handle-body.png
new file mode 100644 (file)
index 0000000..14cfeb2
Binary files /dev/null and b/docs/content/images/creating-custom-controls/control-handle-body.png differ
diff --git a/docs/content/images/creating-custom-controls/popup-normal.png b/docs/content/images/creating-custom-controls/popup-normal.png
new file mode 100644 (file)
index 0000000..ce06133
Binary files /dev/null and b/docs/content/images/creating-custom-controls/popup-normal.png differ
diff --git a/docs/content/images/creating-custom-controls/popup-styled.png b/docs/content/images/creating-custom-controls/popup-styled.png
new file mode 100644 (file)
index 0000000..831950a
Binary files /dev/null and b/docs/content/images/creating-custom-controls/popup-styled.png differ
diff --git a/docs/content/images/creating-custom-controls/rendering.png b/docs/content/images/creating-custom-controls/rendering.png
new file mode 100644 (file)
index 0000000..4ec4e1d
Binary files /dev/null and b/docs/content/images/creating-custom-controls/rendering.png differ
diff --git a/docs/content/images/dali-modules.png b/docs/content/images/dali-modules.png
new file mode 100644 (file)
index 0000000..d85303c
Binary files /dev/null and b/docs/content/images/dali-modules.png differ
diff --git a/docs/content/images/dali-threads.png b/docs/content/images/dali-threads.png
new file mode 100644 (file)
index 0000000..997d238
Binary files /dev/null and b/docs/content/images/dali-threads.png differ
diff --git a/docs/content/images/debug-rendering/debug-blocks.png b/docs/content/images/debug-rendering/debug-blocks.png
new file mode 100644 (file)
index 0000000..5c86f29
Binary files /dev/null and b/docs/content/images/debug-rendering/debug-blocks.png differ
diff --git a/docs/content/images/dynamics/dynamics-joint.png b/docs/content/images/dynamics/dynamics-joint.png
new file mode 100644 (file)
index 0000000..d564603
Binary files /dev/null and b/docs/content/images/dynamics/dynamics-joint.png differ
diff --git a/docs/content/images/dynamics/dynamics-joint2.png b/docs/content/images/dynamics/dynamics-joint2.png
new file mode 100644 (file)
index 0000000..e5cda99
Binary files /dev/null and b/docs/content/images/dynamics/dynamics-joint2.png differ
diff --git a/docs/content/images/dynamics/dynamics-rigid.png b/docs/content/images/dynamics/dynamics-rigid.png
new file mode 100644 (file)
index 0000000..5bce543
Binary files /dev/null and b/docs/content/images/dynamics/dynamics-rigid.png differ
diff --git a/docs/content/images/dynamics/dynamics-shapes.png b/docs/content/images/dynamics/dynamics-shapes.png
new file mode 100644 (file)
index 0000000..0f6e76d
Binary files /dev/null and b/docs/content/images/dynamics/dynamics-shapes.png differ
diff --git a/docs/content/images/dynamics/dynamics-soft.png b/docs/content/images/dynamics/dynamics-soft.png
new file mode 100644 (file)
index 0000000..d073581
Binary files /dev/null and b/docs/content/images/dynamics/dynamics-soft.png differ
diff --git a/docs/content/images/emscripten/emscripten-dali-toy.png b/docs/content/images/emscripten/emscripten-dali-toy.png
new file mode 100644 (file)
index 0000000..fb79223
Binary files /dev/null and b/docs/content/images/emscripten/emscripten-dali-toy.png differ
diff --git a/docs/content/images/emscripten/emscripten-live-doc.png b/docs/content/images/emscripten/emscripten-live-doc.png
new file mode 100644 (file)
index 0000000..b14831a
Binary files /dev/null and b/docs/content/images/emscripten/emscripten-live-doc.png differ
diff --git a/docs/content/images/emscripten/emscripten-tests.png b/docs/content/images/emscripten/emscripten-tests.png
new file mode 100644 (file)
index 0000000..ad5c2ae
Binary files /dev/null and b/docs/content/images/emscripten/emscripten-tests.png differ
diff --git a/docs/content/images/flex-container/align-content.jpg b/docs/content/images/flex-container/align-content.jpg
new file mode 100755 (executable)
index 0000000..6f99507
Binary files /dev/null and b/docs/content/images/flex-container/align-content.jpg differ
diff --git a/docs/content/images/flex-container/align-items.jpg b/docs/content/images/flex-container/align-items.jpg
new file mode 100755 (executable)
index 0000000..a9ccb17
Binary files /dev/null and b/docs/content/images/flex-container/align-items.jpg differ
diff --git a/docs/content/images/flex-container/align-self.jpg b/docs/content/images/flex-container/align-self.jpg
new file mode 100755 (executable)
index 0000000..ea29610
Binary files /dev/null and b/docs/content/images/flex-container/align-self.jpg differ
diff --git a/docs/content/images/flex-container/content-direction-ltr.jpg b/docs/content/images/flex-container/content-direction-ltr.jpg
new file mode 100755 (executable)
index 0000000..2758670
Binary files /dev/null and b/docs/content/images/flex-container/content-direction-ltr.jpg differ
diff --git a/docs/content/images/flex-container/content-direction-rtl.jpg b/docs/content/images/flex-container/content-direction-rtl.jpg
new file mode 100755 (executable)
index 0000000..1dd4856
Binary files /dev/null and b/docs/content/images/flex-container/content-direction-rtl.jpg differ
diff --git a/docs/content/images/flex-container/flex-container.jpg b/docs/content/images/flex-container/flex-container.jpg
new file mode 100755 (executable)
index 0000000..55eb4aa
Binary files /dev/null and b/docs/content/images/flex-container/flex-container.jpg differ
diff --git a/docs/content/images/flex-container/flex-direction.jpg b/docs/content/images/flex-container/flex-direction.jpg
new file mode 100755 (executable)
index 0000000..bd7541c
Binary files /dev/null and b/docs/content/images/flex-container/flex-direction.jpg differ
diff --git a/docs/content/images/flex-container/flex-margin.jpg b/docs/content/images/flex-container/flex-margin.jpg
new file mode 100755 (executable)
index 0000000..2430513
Binary files /dev/null and b/docs/content/images/flex-container/flex-margin.jpg differ
diff --git a/docs/content/images/flex-container/flex-wrap.jpg b/docs/content/images/flex-container/flex-wrap.jpg
new file mode 100755 (executable)
index 0000000..aca0f40
Binary files /dev/null and b/docs/content/images/flex-container/flex-wrap.jpg differ
diff --git a/docs/content/images/flex-container/flex.jpg b/docs/content/images/flex-container/flex.jpg
new file mode 100755 (executable)
index 0000000..bd5574f
Binary files /dev/null and b/docs/content/images/flex-container/flex.jpg differ
diff --git a/docs/content/images/flex-container/flexbox-demo.jpg b/docs/content/images/flex-container/flexbox-demo.jpg
new file mode 100644 (file)
index 0000000..bfe9545
Binary files /dev/null and b/docs/content/images/flex-container/flexbox-demo.jpg differ
diff --git a/docs/content/images/flex-container/justify-content.jpg b/docs/content/images/flex-container/justify-content.jpg
new file mode 100755 (executable)
index 0000000..5163a30
Binary files /dev/null and b/docs/content/images/flex-container/justify-content.jpg differ
diff --git a/docs/content/images/focus-manager/focus-manager.png b/docs/content/images/focus-manager/focus-manager.png
new file mode 100644 (file)
index 0000000..8320dd9
Binary files /dev/null and b/docs/content/images/focus-manager/focus-manager.png differ
diff --git a/docs/content/images/image-scaling/demo-fitting-sampling.png b/docs/content/images/image-scaling/demo-fitting-sampling.png
new file mode 100644 (file)
index 0000000..2626c03
Binary files /dev/null and b/docs/content/images/image-scaling/demo-fitting-sampling.png differ
diff --git a/docs/content/images/image-scaling/demo-sampling-modes.jpg b/docs/content/images/image-scaling/demo-sampling-modes.jpg
new file mode 100644 (file)
index 0000000..ffe94a8
Binary files /dev/null and b/docs/content/images/image-scaling/demo-sampling-modes.jpg differ
diff --git a/docs/content/images/image-scaling/example-scale-to-fill-problem.jpg b/docs/content/images/image-scaling/example-scale-to-fill-problem.jpg
new file mode 100644 (file)
index 0000000..7c54656
Binary files /dev/null and b/docs/content/images/image-scaling/example-scale-to-fill-problem.jpg differ
diff --git a/docs/content/images/image-scaling/example-scale-to-fill-sequence.jpg b/docs/content/images/image-scaling/example-scale-to-fill-sequence.jpg
new file mode 100644 (file)
index 0000000..5c2520c
Binary files /dev/null and b/docs/content/images/image-scaling/example-scale-to-fill-sequence.jpg differ
diff --git a/docs/content/images/image-scaling/fitting-mode-options.png b/docs/content/images/image-scaling/fitting-mode-options.png
new file mode 100644 (file)
index 0000000..bfc9b22
Binary files /dev/null and b/docs/content/images/image-scaling/fitting-mode-options.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_box.png b/docs/content/images/image-scaling/sampling_modes_box.png
new file mode 100644 (file)
index 0000000..9e54e89
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_box.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_box_then_linear.png b/docs/content/images/image-scaling/sampling_modes_box_then_linear.png
new file mode 100644 (file)
index 0000000..cc32253
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_box_then_linear.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_box_then_nearest.png b/docs/content/images/image-scaling/sampling_modes_box_then_nearest.png
new file mode 100644 (file)
index 0000000..a1792f6
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_box_then_nearest.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_linear.png b/docs/content/images/image-scaling/sampling_modes_linear.png
new file mode 100644 (file)
index 0000000..a51c346
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_linear.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_nearest.png b/docs/content/images/image-scaling/sampling_modes_nearest.png
new file mode 100644 (file)
index 0000000..02d3391
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_nearest.png differ
diff --git a/docs/content/images/image-scaling/sampling_modes_no_filter.png b/docs/content/images/image-scaling/sampling_modes_no_filter.png
new file mode 100644 (file)
index 0000000..4825696
Binary files /dev/null and b/docs/content/images/image-scaling/sampling_modes_no_filter.png differ
diff --git a/docs/content/images/image-scaling/scaling-fitting-target-dimensions.png b/docs/content/images/image-scaling/scaling-fitting-target-dimensions.png
new file mode 100644 (file)
index 0000000..f0d8ca7
Binary files /dev/null and b/docs/content/images/image-scaling/scaling-fitting-target-dimensions.png differ
diff --git a/docs/content/images/image-scaling/workflow-1.png b/docs/content/images/image-scaling/workflow-1.png
new file mode 100644 (file)
index 0000000..757cc67
Binary files /dev/null and b/docs/content/images/image-scaling/workflow-1.png differ
diff --git a/docs/content/images/image-scaling/workflow-2.png b/docs/content/images/image-scaling/workflow-2.png
new file mode 100644 (file)
index 0000000..8c9c28a
Binary files /dev/null and b/docs/content/images/image-scaling/workflow-2.png differ
diff --git a/docs/content/images/image-scaling/workflow-3.png b/docs/content/images/image-scaling/workflow-3.png
new file mode 100644 (file)
index 0000000..c69789d
Binary files /dev/null and b/docs/content/images/image-scaling/workflow-3.png differ
diff --git a/docs/content/images/image-scaling/workflow-4.png b/docs/content/images/image-scaling/workflow-4.png
new file mode 100644 (file)
index 0000000..8f5ef37
Binary files /dev/null and b/docs/content/images/image-scaling/workflow-4.png differ
diff --git a/docs/content/images/image-scaling/workflow-main.png b/docs/content/images/image-scaling/workflow-main.png
new file mode 100644 (file)
index 0000000..2a8630a
Binary files /dev/null and b/docs/content/images/image-scaling/workflow-main.png differ
diff --git a/docs/content/images/item-view/depth.png b/docs/content/images/item-view/depth.png
new file mode 100644 (file)
index 0000000..86c879d
Binary files /dev/null and b/docs/content/images/item-view/depth.png differ
diff --git a/docs/content/images/item-view/grid.png b/docs/content/images/item-view/grid.png
new file mode 100644 (file)
index 0000000..398da01
Binary files /dev/null and b/docs/content/images/item-view/grid.png differ
diff --git a/docs/content/images/item-view/list.png b/docs/content/images/item-view/list.png
new file mode 100755 (executable)
index 0000000..d588929
Binary files /dev/null and b/docs/content/images/item-view/list.png differ
diff --git a/docs/content/images/item-view/spiral.png b/docs/content/images/item-view/spiral.png
new file mode 100644 (file)
index 0000000..1825a11
Binary files /dev/null and b/docs/content/images/item-view/spiral.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/adding-function.png b/docs/content/images/javascript-wrapping-guide/adding-function.png
new file mode 100644 (file)
index 0000000..9d1c311
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/adding-function.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/base-wrapped-types.png b/docs/content/images/javascript-wrapping-guide/base-wrapped-types.png
new file mode 100644 (file)
index 0000000..6fd2707
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/base-wrapped-types.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/constructors.png b/docs/content/images/javascript-wrapping-guide/constructors.png
new file mode 100644 (file)
index 0000000..07c4111
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/constructors.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/folder-view.png b/docs/content/images/javascript-wrapping-guide/folder-view.png
new file mode 100644 (file)
index 0000000..2e12028
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/folder-view.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/high-level-design.png b/docs/content/images/javascript-wrapping-guide/high-level-design.png
new file mode 100644 (file)
index 0000000..e1acc8f
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/high-level-design.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/plugin-creation.png b/docs/content/images/javascript-wrapping-guide/plugin-creation.png
new file mode 100644 (file)
index 0000000..e9f26be
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/plugin-creation.png differ
diff --git a/docs/content/images/javascript-wrapping-guide/plugin-execution.png b/docs/content/images/javascript-wrapping-guide/plugin-execution.png
new file mode 100644 (file)
index 0000000..8f3006c
Binary files /dev/null and b/docs/content/images/javascript-wrapping-guide/plugin-execution.png differ
diff --git a/docs/content/images/layer/layer2d.png b/docs/content/images/layer/layer2d.png
new file mode 100644 (file)
index 0000000..fc04d38
Binary files /dev/null and b/docs/content/images/layer/layer2d.png differ
diff --git a/docs/content/images/layer/layers.png b/docs/content/images/layer/layers.png
new file mode 100644 (file)
index 0000000..01ce975
Binary files /dev/null and b/docs/content/images/layer/layers.png differ
diff --git a/docs/content/images/layer/layers3d.png b/docs/content/images/layer/layers3d.png
new file mode 100644 (file)
index 0000000..29a9faf
Binary files /dev/null and b/docs/content/images/layer/layers3d.png differ
diff --git a/docs/content/images/layer/transSort.png b/docs/content/images/layer/transSort.png
new file mode 100644 (file)
index 0000000..dd405dd
Binary files /dev/null and b/docs/content/images/layer/transSort.png differ
diff --git a/docs/content/images/list-view/coverflow.png b/docs/content/images/list-view/coverflow.png
new file mode 100644 (file)
index 0000000..6fba44d
Binary files /dev/null and b/docs/content/images/list-view/coverflow.png differ
diff --git a/docs/content/images/list-view/grid.png b/docs/content/images/list-view/grid.png
new file mode 100644 (file)
index 0000000..d9253f8
Binary files /dev/null and b/docs/content/images/list-view/grid.png differ
diff --git a/docs/content/images/list-view/list.png b/docs/content/images/list-view/list.png
new file mode 100644 (file)
index 0000000..17795f1
Binary files /dev/null and b/docs/content/images/list-view/list.png differ
diff --git a/docs/content/images/list-view/tunnel.png b/docs/content/images/list-view/tunnel.png
new file mode 100644 (file)
index 0000000..88da139
Binary files /dev/null and b/docs/content/images/list-view/tunnel.png differ
diff --git a/docs/content/images/parent-origin.png b/docs/content/images/parent-origin.png
new file mode 100644 (file)
index 0000000..0317fe4
Binary files /dev/null and b/docs/content/images/parent-origin.png differ
diff --git a/docs/content/images/path/path.png b/docs/content/images/path/path.png
new file mode 100644 (file)
index 0000000..3671f73
Binary files /dev/null and b/docs/content/images/path/path.png differ
diff --git a/docs/content/images/performance/update-render.png b/docs/content/images/performance/update-render.png
new file mode 100644 (file)
index 0000000..018f6a8
Binary files /dev/null and b/docs/content/images/performance/update-render.png differ
diff --git a/docs/content/images/popup/popup-example.png b/docs/content/images/popup/popup-example.png
new file mode 100644 (file)
index 0000000..352a2e0
Binary files /dev/null and b/docs/content/images/popup/popup-example.png differ
diff --git a/docs/content/images/popup/popup-fields.png b/docs/content/images/popup/popup-fields.png
new file mode 100644 (file)
index 0000000..8555dcf
Binary files /dev/null and b/docs/content/images/popup/popup-fields.png differ
diff --git a/docs/content/images/popup/popup-image-content.png b/docs/content/images/popup/popup-image-content.png
new file mode 100644 (file)
index 0000000..7876811
Binary files /dev/null and b/docs/content/images/popup/popup-image-content.png differ
diff --git a/docs/content/images/popup/popup-toast.png b/docs/content/images/popup/popup-toast.png
new file mode 100644 (file)
index 0000000..25e07b1
Binary files /dev/null and b/docs/content/images/popup/popup-toast.png differ
diff --git a/docs/content/images/resource/9-patch-full.png b/docs/content/images/resource/9-patch-full.png
new file mode 100644 (file)
index 0000000..3895bc8
Binary files /dev/null and b/docs/content/images/resource/9-patch-full.png differ
diff --git a/docs/content/images/resource/9-patch-zoomed.png b/docs/content/images/resource/9-patch-zoomed.png
new file mode 100644 (file)
index 0000000..2196d66
Binary files /dev/null and b/docs/content/images/resource/9-patch-zoomed.png differ
diff --git a/docs/content/images/resource/9-patch.png b/docs/content/images/resource/9-patch.png
new file mode 100644 (file)
index 0000000..7a20d38
Binary files /dev/null and b/docs/content/images/resource/9-patch.png differ
diff --git a/docs/content/images/screen-shot.png b/docs/content/images/screen-shot.png
new file mode 100644 (file)
index 0000000..25659d9
Binary files /dev/null and b/docs/content/images/screen-shot.png differ
diff --git a/docs/content/images/scroll-view/scroll-view.png b/docs/content/images/scroll-view/scroll-view.png
new file mode 100755 (executable)
index 0000000..fe2d409
Binary files /dev/null and b/docs/content/images/scroll-view/scroll-view.png differ
diff --git a/docs/content/images/shaders/BendyEffect1.png b/docs/content/images/shaders/BendyEffect1.png
new file mode 100644 (file)
index 0000000..1df68e8
Binary files /dev/null and b/docs/content/images/shaders/BendyEffect1.png differ
diff --git a/docs/content/images/shaders/BendyEffect2.png b/docs/content/images/shaders/BendyEffect2.png
new file mode 100644 (file)
index 0000000..605a065
Binary files /dev/null and b/docs/content/images/shaders/BendyEffect2.png differ
diff --git a/docs/content/images/shaders/RippleEffect1.png b/docs/content/images/shaders/RippleEffect1.png
new file mode 100644 (file)
index 0000000..bbfaf2b
Binary files /dev/null and b/docs/content/images/shaders/RippleEffect1.png differ
diff --git a/docs/content/images/shaders/fragment-shader-color.png b/docs/content/images/shaders/fragment-shader-color.png
new file mode 100644 (file)
index 0000000..2e38b24
Binary files /dev/null and b/docs/content/images/shaders/fragment-shader-color.png differ
diff --git a/docs/content/images/shaders/fragment-shader-reveal.png b/docs/content/images/shaders/fragment-shader-reveal.png
new file mode 100644 (file)
index 0000000..8855ba6
Binary files /dev/null and b/docs/content/images/shaders/fragment-shader-reveal.png differ
diff --git a/docs/content/images/shaders/shader-animation.png b/docs/content/images/shaders/shader-animation.png
new file mode 100644 (file)
index 0000000..0512a01
Binary files /dev/null and b/docs/content/images/shaders/shader-animation.png differ
diff --git a/docs/content/images/shaders/shader-effect-ripple.png b/docs/content/images/shaders/shader-effect-ripple.png
new file mode 100644 (file)
index 0000000..2c5056f
Binary files /dev/null and b/docs/content/images/shaders/shader-effect-ripple.png differ
diff --git a/docs/content/images/shaders/shader-grid-hint.png b/docs/content/images/shaders/shader-grid-hint.png
new file mode 100644 (file)
index 0000000..a0982f8
Binary files /dev/null and b/docs/content/images/shaders/shader-grid-hint.png differ
diff --git a/docs/content/images/shaders/vertex-shader.png b/docs/content/images/shaders/vertex-shader.png
new file mode 100644 (file)
index 0000000..96009d2
Binary files /dev/null and b/docs/content/images/shaders/vertex-shader.png differ
diff --git a/docs/content/images/size-negotiation/Popup.png b/docs/content/images/size-negotiation/Popup.png
new file mode 100644 (file)
index 0000000..f5d9b7f
Binary files /dev/null and b/docs/content/images/size-negotiation/Popup.png differ
diff --git a/docs/content/images/size-negotiation/PopupExample.png b/docs/content/images/size-negotiation/PopupExample.png
new file mode 100644 (file)
index 0000000..531622d
Binary files /dev/null and b/docs/content/images/size-negotiation/PopupExample.png differ
diff --git a/docs/content/images/size-negotiation/ResizePolicies.png b/docs/content/images/size-negotiation/ResizePolicies.png
new file mode 100644 (file)
index 0000000..7b8350e
Binary files /dev/null and b/docs/content/images/size-negotiation/ResizePolicies.png differ
diff --git a/docs/content/images/size-negotiation/ResizePoliciesExample.png b/docs/content/images/size-negotiation/ResizePoliciesExample.png
new file mode 100644 (file)
index 0000000..19b806f
Binary files /dev/null and b/docs/content/images/size-negotiation/ResizePoliciesExample.png differ
diff --git a/docs/content/images/size-negotiation/SizeNegotiationExample_After.png b/docs/content/images/size-negotiation/SizeNegotiationExample_After.png
new file mode 100644 (file)
index 0000000..3a64d36
Binary files /dev/null and b/docs/content/images/size-negotiation/SizeNegotiationExample_After.png differ
diff --git a/docs/content/images/size-negotiation/SizeNegotiationExample_Before.png b/docs/content/images/size-negotiation/SizeNegotiationExample_Before.png
new file mode 100644 (file)
index 0000000..30251d2
Binary files /dev/null and b/docs/content/images/size-negotiation/SizeNegotiationExample_Before.png differ
diff --git a/docs/content/images/spinner.gif b/docs/content/images/spinner.gif
new file mode 100644 (file)
index 0000000..44f96ba
Binary files /dev/null and b/docs/content/images/spinner.gif differ
diff --git a/docs/content/images/stage-hand/blocks.png b/docs/content/images/stage-hand/blocks.png
new file mode 100644 (file)
index 0000000..fc5a28d
Binary files /dev/null and b/docs/content/images/stage-hand/blocks.png differ
diff --git a/docs/content/images/stage-hand/inner-workings.png b/docs/content/images/stage-hand/inner-workings.png
new file mode 100644 (file)
index 0000000..f77f16f
Binary files /dev/null and b/docs/content/images/stage-hand/inner-workings.png differ
diff --git a/docs/content/images/stage-hand/netstat.png b/docs/content/images/stage-hand/netstat.png
new file mode 100644 (file)
index 0000000..905f2c1
Binary files /dev/null and b/docs/content/images/stage-hand/netstat.png differ
diff --git a/docs/content/images/stage-hand/stagehand-logo.png b/docs/content/images/stage-hand/stagehand-logo.png
new file mode 100644 (file)
index 0000000..bdd1104
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-logo.png differ
diff --git a/docs/content/images/stage-hand/stagehand-mainscreen.png b/docs/content/images/stage-hand/stagehand-mainscreen.png
new file mode 100644 (file)
index 0000000..64ac3ea
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-mainscreen.png differ
diff --git a/docs/content/images/stage-hand/stagehand-modify.png b/docs/content/images/stage-hand/stagehand-modify.png
new file mode 100644 (file)
index 0000000..f1c2b48
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-modify.png differ
diff --git a/docs/content/images/stage-hand/stagehand-netcat.png b/docs/content/images/stage-hand/stagehand-netcat.png
new file mode 100644 (file)
index 0000000..c6d8cb8
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-netcat.png differ
diff --git a/docs/content/images/stage-hand/stagehand-performance.png b/docs/content/images/stage-hand/stagehand-performance.png
new file mode 100644 (file)
index 0000000..4f1d518
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-performance.png differ
diff --git a/docs/content/images/stage-hand/stagehand-refesh.png b/docs/content/images/stage-hand/stagehand-refesh.png
new file mode 100644 (file)
index 0000000..d7f77c4
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-refesh.png differ
diff --git a/docs/content/images/stage-hand/stagehand-save.png b/docs/content/images/stage-hand/stagehand-save.png
new file mode 100644 (file)
index 0000000..326fc0c
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-save.png differ
diff --git a/docs/content/images/stage-hand/stagehand-screenshot.png b/docs/content/images/stage-hand/stagehand-screenshot.png
new file mode 100644 (file)
index 0000000..bedbeac
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-screenshot.png differ
diff --git a/docs/content/images/stage-hand/stagehand-settings.png b/docs/content/images/stage-hand/stagehand-settings.png
new file mode 100644 (file)
index 0000000..f3b434d
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-settings.png differ
diff --git a/docs/content/images/stage-hand/stagehand-tizen-connection.png b/docs/content/images/stage-hand/stagehand-tizen-connection.png
new file mode 100644 (file)
index 0000000..fa4243a
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-tizen-connection.png differ
diff --git a/docs/content/images/stage-hand/stagehand-ubuntu-connection.png b/docs/content/images/stage-hand/stagehand-ubuntu-connection.png
new file mode 100644 (file)
index 0000000..cf824b9
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-ubuntu-connection.png differ
diff --git a/docs/content/images/stage-hand/stagehand-zoom.png b/docs/content/images/stage-hand/stagehand-zoom.png
new file mode 100644 (file)
index 0000000..e509acd
Binary files /dev/null and b/docs/content/images/stage-hand/stagehand-zoom.png differ
diff --git a/docs/content/images/stage/stage.png b/docs/content/images/stage/stage.png
new file mode 100644 (file)
index 0000000..67e0dc5
Binary files /dev/null and b/docs/content/images/stage/stage.png differ
diff --git a/docs/content/images/text-controls/ArabicBegin.png b/docs/content/images/text-controls/ArabicBegin.png
new file mode 100644 (file)
index 0000000..56dcec1
Binary files /dev/null and b/docs/content/images/text-controls/ArabicBegin.png differ
diff --git a/docs/content/images/text-controls/ArabicCenter.png b/docs/content/images/text-controls/ArabicCenter.png
new file mode 100644 (file)
index 0000000..cbc77d3
Binary files /dev/null and b/docs/content/images/text-controls/ArabicCenter.png differ
diff --git a/docs/content/images/text-controls/ArabicEnd.png b/docs/content/images/text-controls/ArabicEnd.png
new file mode 100644 (file)
index 0000000..e35e1a8
Binary files /dev/null and b/docs/content/images/text-controls/ArabicEnd.png differ
diff --git a/docs/content/images/text-controls/AutoScroll.gif b/docs/content/images/text-controls/AutoScroll.gif
new file mode 100644 (file)
index 0000000..663cd3b
Binary files /dev/null and b/docs/content/images/text-controls/AutoScroll.gif differ
diff --git a/docs/content/images/text-controls/EmptyTextAndNoContentToPaste.png b/docs/content/images/text-controls/EmptyTextAndNoContentToPaste.png
new file mode 100644 (file)
index 0000000..5a007c1
Binary files /dev/null and b/docs/content/images/text-controls/EmptyTextAndNoContentToPaste.png differ
diff --git a/docs/content/images/text-controls/EmptyTextClipboardHasContent.png b/docs/content/images/text-controls/EmptyTextClipboardHasContent.png
new file mode 100644 (file)
index 0000000..5f29f75
Binary files /dev/null and b/docs/content/images/text-controls/EmptyTextClipboardHasContent.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-Default-BEGIN.png b/docs/content/images/text-controls/HelloWorld-Default-BEGIN.png
new file mode 100755 (executable)
index 0000000..ca9d860
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-Default-BEGIN.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-Default-CENTER.png b/docs/content/images/text-controls/HelloWorld-Default-CENTER.png
new file mode 100755 (executable)
index 0000000..cb28206
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-Default-CENTER.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-Default-END.png b/docs/content/images/text-controls/HelloWorld-Default-END.png
new file mode 100755 (executable)
index 0000000..204ba94
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-Default-END.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-HeightForWidth.png b/docs/content/images/text-controls/HelloWorld-HeightForWidth.png
new file mode 100644 (file)
index 0000000..915862c
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-HeightForWidth.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-NaturalSize.png b/docs/content/images/text-controls/HelloWorld-NaturalSize.png
new file mode 100644 (file)
index 0000000..28d24d1
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-NaturalSize.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-System-BEGIN.png b/docs/content/images/text-controls/HelloWorld-System-BEGIN.png
new file mode 100755 (executable)
index 0000000..11c8eda
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-System-BEGIN.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-System-CENTER.png b/docs/content/images/text-controls/HelloWorld-System-CENTER.png
new file mode 100755 (executable)
index 0000000..cb28206
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-System-CENTER.png differ
diff --git a/docs/content/images/text-controls/HelloWorld-System-END.png b/docs/content/images/text-controls/HelloWorld-System-END.png
new file mode 100755 (executable)
index 0000000..d8c674b
Binary files /dev/null and b/docs/content/images/text-controls/HelloWorld-System-END.png differ
diff --git a/docs/content/images/text-controls/LTR_RTL.png b/docs/content/images/text-controls/LTR_RTL.png
new file mode 100755 (executable)
index 0000000..d9defc3
Binary files /dev/null and b/docs/content/images/text-controls/LTR_RTL.png differ
diff --git a/docs/content/images/text-controls/LTR_order.png b/docs/content/images/text-controls/LTR_order.png
new file mode 100755 (executable)
index 0000000..6e8a3c1
Binary files /dev/null and b/docs/content/images/text-controls/LTR_order.png differ
diff --git a/docs/content/images/text-controls/LatinBegin.png b/docs/content/images/text-controls/LatinBegin.png
new file mode 100644 (file)
index 0000000..bec2507
Binary files /dev/null and b/docs/content/images/text-controls/LatinBegin.png differ
diff --git a/docs/content/images/text-controls/LatinCenter.png b/docs/content/images/text-controls/LatinCenter.png
new file mode 100644 (file)
index 0000000..ef5aa57
Binary files /dev/null and b/docs/content/images/text-controls/LatinCenter.png differ
diff --git a/docs/content/images/text-controls/LatinEnd.png b/docs/content/images/text-controls/LatinEnd.png
new file mode 100644 (file)
index 0000000..4e22cbc
Binary files /dev/null and b/docs/content/images/text-controls/LatinEnd.png differ
diff --git a/docs/content/images/text-controls/PlainText.png b/docs/content/images/text-controls/PlainText.png
new file mode 100644 (file)
index 0000000..5ef9ff1
Binary files /dev/null and b/docs/content/images/text-controls/PlainText.png differ
diff --git a/docs/content/images/text-controls/RTL_order.png b/docs/content/images/text-controls/RTL_order.png
new file mode 100755 (executable)
index 0000000..b97e0f8
Binary files /dev/null and b/docs/content/images/text-controls/RTL_order.png differ
diff --git a/docs/content/images/text-controls/RedText.png b/docs/content/images/text-controls/RedText.png
new file mode 100644 (file)
index 0000000..f2fe9fe
Binary files /dev/null and b/docs/content/images/text-controls/RedText.png differ
diff --git a/docs/content/images/text-controls/SelectAllWhitespace.png b/docs/content/images/text-controls/SelectAllWhitespace.png
new file mode 100644 (file)
index 0000000..30e326a
Binary files /dev/null and b/docs/content/images/text-controls/SelectAllWhitespace.png differ
diff --git a/docs/content/images/text-controls/SelectWhitespaceAfterText.png b/docs/content/images/text-controls/SelectWhitespaceAfterText.png
new file mode 100644 (file)
index 0000000..c0d2fad
Binary files /dev/null and b/docs/content/images/text-controls/SelectWhitespaceAfterText.png differ
diff --git a/docs/content/images/text-controls/SelectingText.png b/docs/content/images/text-controls/SelectingText.png
new file mode 100644 (file)
index 0000000..44a2ccb
Binary files /dev/null and b/docs/content/images/text-controls/SelectingText.png differ
diff --git a/docs/content/images/text-controls/SpecialCharacter1.png b/docs/content/images/text-controls/SpecialCharacter1.png
new file mode 100755 (executable)
index 0000000..6515a8b
Binary files /dev/null and b/docs/content/images/text-controls/SpecialCharacter1.png differ
diff --git a/docs/content/images/text-controls/SpecialCharacters.png b/docs/content/images/text-controls/SpecialCharacters.png
new file mode 100755 (executable)
index 0000000..0e9ecca
Binary files /dev/null and b/docs/content/images/text-controls/SpecialCharacters.png differ
diff --git a/docs/content/images/text-controls/TapAfterCopyingText.png b/docs/content/images/text-controls/TapAfterCopyingText.png
new file mode 100644 (file)
index 0000000..eaa260b
Binary files /dev/null and b/docs/content/images/text-controls/TapAfterCopyingText.png differ
diff --git a/docs/content/images/text-controls/TextLabelCenter.png b/docs/content/images/text-controls/TextLabelCenter.png
new file mode 100644 (file)
index 0000000..07558e3
Binary files /dev/null and b/docs/content/images/text-controls/TextLabelCenter.png differ
diff --git a/docs/content/images/text-controls/TextLabelTopLeft.png b/docs/content/images/text-controls/TextLabelTopLeft.png
new file mode 100644 (file)
index 0000000..ad8f492
Binary files /dev/null and b/docs/content/images/text-controls/TextLabelTopLeft.png differ
diff --git a/docs/content/images/text-controls/TextWith1pxUnderline.png b/docs/content/images/text-controls/TextWith1pxUnderline.png
new file mode 100644 (file)
index 0000000..082d19e
Binary files /dev/null and b/docs/content/images/text-controls/TextWith1pxUnderline.png differ
diff --git a/docs/content/images/text-controls/TextWithBiggerShadow.png b/docs/content/images/text-controls/TextWithBiggerShadow.png
new file mode 100644 (file)
index 0000000..921f745
Binary files /dev/null and b/docs/content/images/text-controls/TextWithBiggerShadow.png differ
diff --git a/docs/content/images/text-controls/TextWithColorShadow.png b/docs/content/images/text-controls/TextWithColorShadow.png
new file mode 100644 (file)
index 0000000..a82635d
Binary files /dev/null and b/docs/content/images/text-controls/TextWithColorShadow.png differ
diff --git a/docs/content/images/text-controls/TextWithColorUnderline.png b/docs/content/images/text-controls/TextWithColorUnderline.png
new file mode 100644 (file)
index 0000000..42ec4ff
Binary files /dev/null and b/docs/content/images/text-controls/TextWithColorUnderline.png differ
diff --git a/docs/content/images/text-controls/TextWithShadow.png b/docs/content/images/text-controls/TextWithShadow.png
new file mode 100644 (file)
index 0000000..1cde8d2
Binary files /dev/null and b/docs/content/images/text-controls/TextWithShadow.png differ
diff --git a/docs/content/images/text-controls/TextWithUnderline.png b/docs/content/images/text-controls/TextWithUnderline.png
new file mode 100644 (file)
index 0000000..530920a
Binary files /dev/null and b/docs/content/images/text-controls/TextWithUnderline.png differ
diff --git a/docs/content/images/text-controls/XHTML_entity.png b/docs/content/images/text-controls/XHTML_entity.png
new file mode 100755 (executable)
index 0000000..b656a5f
Binary files /dev/null and b/docs/content/images/text-controls/XHTML_entity.png differ
diff --git a/docs/content/images/viewing-modes/google-cardboard.png b/docs/content/images/viewing-modes/google-cardboard.png
new file mode 100644 (file)
index 0000000..b931339
Binary files /dev/null and b/docs/content/images/viewing-modes/google-cardboard.png differ
diff --git a/docs/content/images/viewing-modes/stereo-projection.png b/docs/content/images/viewing-modes/stereo-projection.png
new file mode 100755 (executable)
index 0000000..b012524
Binary files /dev/null and b/docs/content/images/viewing-modes/stereo-projection.png differ
diff --git a/docs/content/images/visuals/HelloWorld.png b/docs/content/images/visuals/HelloWorld.png
new file mode 100644 (file)
index 0000000..aa40f20
Binary files /dev/null and b/docs/content/images/visuals/HelloWorld.png differ
diff --git a/docs/content/images/visuals/animated-image-visual.gif b/docs/content/images/visuals/animated-image-visual.gif
new file mode 100644 (file)
index 0000000..ddc3312
Binary files /dev/null and b/docs/content/images/visuals/animated-image-visual.gif differ
diff --git a/docs/content/images/visuals/bevelled-cube-high.png b/docs/content/images/visuals/bevelled-cube-high.png
new file mode 100644 (file)
index 0000000..d6676db
Binary files /dev/null and b/docs/content/images/visuals/bevelled-cube-high.png differ
diff --git a/docs/content/images/visuals/bevelled-cube-low.png b/docs/content/images/visuals/bevelled-cube-low.png
new file mode 100644 (file)
index 0000000..d76c836
Binary files /dev/null and b/docs/content/images/visuals/bevelled-cube-low.png differ
diff --git a/docs/content/images/visuals/border-visual.png b/docs/content/images/visuals/border-visual.png
new file mode 100644 (file)
index 0000000..05834f7
Binary files /dev/null and b/docs/content/images/visuals/border-visual.png differ
diff --git a/docs/content/images/visuals/color-visual.png b/docs/content/images/visuals/color-visual.png
new file mode 100644 (file)
index 0000000..2bfe28f
Binary files /dev/null and b/docs/content/images/visuals/color-visual.png differ
diff --git a/docs/content/images/visuals/cone.png b/docs/content/images/visuals/cone.png
new file mode 100644 (file)
index 0000000..6437a0e
Binary files /dev/null and b/docs/content/images/visuals/cone.png differ
diff --git a/docs/content/images/visuals/conical-frustrum.png b/docs/content/images/visuals/conical-frustrum.png
new file mode 100644 (file)
index 0000000..000c74b
Binary files /dev/null and b/docs/content/images/visuals/conical-frustrum.png differ
diff --git a/docs/content/images/visuals/cube.png b/docs/content/images/visuals/cube.png
new file mode 100644 (file)
index 0000000..af04b30
Binary files /dev/null and b/docs/content/images/visuals/cube.png differ
diff --git a/docs/content/images/visuals/cylinder.png b/docs/content/images/visuals/cylinder.png
new file mode 100644 (file)
index 0000000..d4efd00
Binary files /dev/null and b/docs/content/images/visuals/cylinder.png differ
diff --git a/docs/content/images/visuals/image-visual.png b/docs/content/images/visuals/image-visual.png
new file mode 100644 (file)
index 0000000..a09f92b
Binary files /dev/null and b/docs/content/images/visuals/image-visual.png differ
diff --git a/docs/content/images/visuals/linear-gradient-visual.png b/docs/content/images/visuals/linear-gradient-visual.png
new file mode 100644 (file)
index 0000000..1d8074a
Binary files /dev/null and b/docs/content/images/visuals/linear-gradient-visual.png differ
diff --git a/docs/content/images/visuals/mesh-visual.png b/docs/content/images/visuals/mesh-visual.png
new file mode 100644 (file)
index 0000000..d5e8ca0
Binary files /dev/null and b/docs/content/images/visuals/mesh-visual.png differ
diff --git a/docs/content/images/visuals/n-patch-visual.png b/docs/content/images/visuals/n-patch-visual.png
new file mode 100644 (file)
index 0000000..530efd3
Binary files /dev/null and b/docs/content/images/visuals/n-patch-visual.png differ
diff --git a/docs/content/images/visuals/octahedron.png b/docs/content/images/visuals/octahedron.png
new file mode 100644 (file)
index 0000000..9ad5704
Binary files /dev/null and b/docs/content/images/visuals/octahedron.png differ
diff --git a/docs/content/images/visuals/radial-gradient-visual.png b/docs/content/images/visuals/radial-gradient-visual.png
new file mode 100644 (file)
index 0000000..5b7ac5e
Binary files /dev/null and b/docs/content/images/visuals/radial-gradient-visual.png differ
diff --git a/docs/content/images/visuals/slices.png b/docs/content/images/visuals/slices.png
new file mode 100644 (file)
index 0000000..8747577
Binary files /dev/null and b/docs/content/images/visuals/slices.png differ
diff --git a/docs/content/images/visuals/sphere.png b/docs/content/images/visuals/sphere.png
new file mode 100644 (file)
index 0000000..3efd4a0
Binary files /dev/null and b/docs/content/images/visuals/sphere.png differ
diff --git a/docs/content/images/visuals/stacks.png b/docs/content/images/visuals/stacks.png
new file mode 100644 (file)
index 0000000..fb3cb84
Binary files /dev/null and b/docs/content/images/visuals/stacks.png differ
diff --git a/docs/content/images/visuals/svg-visual.svg b/docs/content/images/visuals/svg-visual.svg
new file mode 100755 (executable)
index 0000000..b7d5476
--- /dev/null
@@ -0,0 +1,491 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   id="Layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 306.90988 416.79828"
+   xml:space="preserve"
+   inkscape:version="0.48.4 r9939"
+   width="100%"
+   height="100%"
+   sodipodi:docname="Kid1.svg"><metadata
+     id="metadata185"><rdf:RDF><cc:Work
+         rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+     id="defs183" /><sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="640"
+     inkscape:window-height="480"
+     id="namedview181"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:zoom="0.28032166"
+     inkscape:cx="152.20465"
+     inkscape:cy="184.87264"
+     inkscape:window-x="75"
+     inkscape:window-y="34"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="Layer_1" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 192.28065,343.14765 c 0,0 -4.5,75.5 37.5,71 42,-4.5 11.5,-75.5 11.5,-75.5 l -49,4.5 z"
+     id="path3"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 229.78065,414.14765 c 24.024,-2.574 24.325,-26.903 20.184,-47.259 l -56.117,5.805 c 3.172,20.614 12.003,44.018 35.933,41.454 z"
+     id="path5"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 113.60765,343.14765 c 0,0 -23.087995,69 14,73 37.088,4 48,-73 48,-73 h -62 z"
+     id="path7"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 169.15465,370.76265 -60.625,-7.118 c -3.745,20.685 -4.689,49.94 19.078,52.503 21.993,2.372 34.78,-23.738 41.547,-45.385 z"
+     id="path9"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 117.10565,371.73465 39.895,2.68 c 0,0 -7.065,27.803 -23.798,24.788 -16.733,-3.015 -16.097,-27.468 -16.097,-27.468 z"
+     id="path11"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 206.27865,381.65765 35.399,-5.164 c 0,0 2.531,26.234 -10.49,26.241 -18.543,0.011 -24.909,-21.077 -24.909,-21.077 z"
+     id="path13"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 121.49165,210.92765 c -24.560995,5.263 -52.631995,5.263 -52.631995,5.263 l 5.354,60.772 25.859995,-5.032 c 0,0 64.328,-18.197 62.574,-34.16 -2.104,-19.138 -16.595,-32.106 -41.156,-26.843 z"
+     id="path15"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#c1272d;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 231.14065,228.64765 c -10.143,-34.251 -65.789,-51.053 -65.789,-51.053 0,0 -19.298,28.07 -43.86,33.333 -1.209,0.259 -2.428,0.502 -3.65,0.736 l -20.035995,60.709 2.267995,-0.441 -16.300995,80.54 184.714995,-4.731 c 0,10e-4 -25.566,-79.313 -37.347,-119.093 z"
+     id="path17"
+     inkscape:connector-curvature="0" /><line
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="110.72466"
+     y1="311.29565"
+     x2="104.40065"
+     y2="352.30963"
+     id="line19" /><polygon
+     style="fill:#666666;stroke:#000000;stroke-miterlimit:10"
+     points="390.823,464.081 392.798,470.374 237.225,476.667 237.225,468.729 "
+     id="polygon21"
+     transform="translate(-145.43535,-189.01935)" /><linearGradient
+     id="SVGID_1_"
+     gradientUnits="userSpaceOnUse"
+     x1="317.35651"
+     y1="383.66669"
+     x2="317.35651"
+     y2="199.5519"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0"
+       style="stop-color:#402A04"
+       id="stop24" /><stop
+       offset="1"
+       style="stop-color:#7F5100"
+       id="stop26" /></linearGradient><path
+     style="fill:url(#SVGID_1_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="M 172.97165,196.01565 H 63.267655 c 0,0 -54.6040005,-192.1050008 109.704995,-188.5960008 164.309,3.5089998 106.414,188.5960008 106.414,188.5960008 h -106.415 z"
+     id="path28"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_2_"
+     gradientUnits="userSpaceOnUse"
+     x1="317.6879"
+     y1="298.16669"
+     x2="317.6879"
+     y2="399.66791"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop31" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop33" /></linearGradient><path
+     style="fill:url(#SVGID_2_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 93.798655,65.647649 c 0,0 -48.605,145.281001 77.692995,145.281001 126.298,0 80.202,-145.281001 80.202,-145.281001 H 93.798655 z"
+     id="path35"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_3_"
+     gradientUnits="userSpaceOnUse"
+     x1="316.33801"
+     y1="383.66669"
+     x2="316.33801"
+     y2="199.5519"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0"
+       style="stop-color:#402A04"
+       id="stop38" /><stop
+       offset="1"
+       style="stop-color:#7F5100"
+       id="stop40" /></linearGradient><path
+     style="fill:url(#SVGID_3_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 108.82665,29.573649 c 0,0 -37.535995,22.859 -34.316995,82.359001 h 62.920995 c 0,0 7.255,-35.965001 7.255,-31.786001 0,4.179 3.509,31.786001 3.509,31.786001 h 48.246 V 87.833649 l 8.772,24.099001 h 62.281 c 0,0 0,-53.553001 -28.63,-82.359001 -28.072,0.877 -130.037,0 -130.037,0 z"
+     id="path42"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_4_"
+     gradientUnits="userSpaceOnUse"
+     x1="195.0862"
+     y1="372.3811"
+     x2="217.894"
+     y2="516.99213"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0"
+       style="stop-color:#006178"
+       id="stop45" /><stop
+       offset="1"
+       style="stop-color:#00495C"
+       id="stop47" /></linearGradient><path
+     style="fill:url(#SVGID_4_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 111.64765,331.69965 -70.387995,13.196 c -6.487,1.216 -12.79,-3.096 -14.006,-9.583 L 1.8536545,199.83065 c -1.21599995,-6.487 3.096,-12.79 9.5830005,-14.006 l 70.388,-13.196 c 6.487,-1.216 12.79,3.096 14.006,9.583 l 25.399995,135.482 c 1.217,6.487 -3.096,12.79 -9.583,14.006 z"
+     id="path49"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_5_"
+     gradientUnits="userSpaceOnUse"
+     x1="197.17931"
+     y1="393.6586"
+     x2="218.5313"
+     y2="505.75641"><stop
+       offset="0"
+       style="stop-color:#6BBBD0"
+       id="stop52" /><stop
+       offset="1"
+       style="stop-color:#ACCCD4"
+       id="stop54" /></linearGradient><polygon
+     style="fill:url(#SVGID_5_);stroke:#000000;stroke-miterlimit:10"
+     points="179.836,514.167 159.336,399.948 236.336,387.667 254.336,498.167 "
+     id="polygon56"
+     transform="translate(-145.43535,-189.01935)" /><linearGradient
+     id="SVGID_6_"
+     gradientUnits="userSpaceOnUse"
+     x1="207.9456"
+     y1="466.41"
+     x2="201.4173"
+     y2="399.4946"><stop
+       offset="0"
+       style="stop-color:#FBCA51"
+       id="stop59" /><stop
+       offset="1"
+       style="stop-color:#FFECBF"
+       id="stop61" /></linearGradient><ellipse
+     style="fill:url(#SVGID_6_);stroke:#000000;stroke-miterlimit:10"
+     cx="205.43201"
+     cy="440.64801"
+     rx="28.959"
+     ry="28.080999"
+     id="ellipse63"
+     sodipodi:cx="205.43201"
+     sodipodi:cy="440.64801"
+     sodipodi:rx="28.959"
+     sodipodi:ry="28.080999"
+     transform="translate(-145.43535,-189.01935)" /><linearGradient
+     id="SVGID_7_"
+     gradientUnits="userSpaceOnUse"
+     x1="190.9269"
+     y1="427.96649"
+     x2="192.52139"
+     y2="436.33749"><stop
+       offset="0"
+       style="stop-color:#6BBBD0"
+       id="stop66" /><stop
+       offset="1"
+       style="stop-color:#ACCCD4"
+       id="stop68" /></linearGradient><line
+     style="fill:url(#SVGID_7_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="44.983662"
+     y1="238.97565"
+     x2="47.595661"
+     y2="247.29865"
+     id="line70" /><linearGradient
+     id="SVGID_8_"
+     gradientUnits="userSpaceOnUse"
+     x1="211.39799"
+     y1="423.5397"
+     x2="213.01559"
+     y2="432.0325"><stop
+       offset="0"
+       style="stop-color:#6BBBD0"
+       id="stop73" /><stop
+       offset="1"
+       style="stop-color:#ACCCD4"
+       id="stop75" /></linearGradient><line
+     style="fill:url(#SVGID_8_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="66.200653"
+     y1="234.40564"
+     x2="67.343658"
+     y2="243.13666"
+     id="line77" /><path
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 47.595655,260.51865 c 0,0 0.653,13.22 15.831,9.14 15.178,-4.08 11.229,-15.994 11.229,-15.994"
+     id="path79"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_9_"
+     gradientUnits="userSpaceOnUse"
+     x1="247.2587"
+     y1="416.16669"
+     x2="247.2587"
+     y2="464.19009"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop82" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop84" /></linearGradient><path
+     style="fill:url(#SVGID_9_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 125.03565,225.81865 c 0,0 -54.844995,-4.046 -54.589995,5.391 0.255,9.437 21.359,3.668 20.849,8.259 -0.51,4.591 -10.173,3.424 -8.763,9.166 1.335,5.436 9.891,0.337 10.485,4.399 0.594,4.062 -7.944,4.738 -7.2,9.587 0.744,4.849 9.437,1.275 9.947,4.081 0.51,2.806 -5.959,4.099 -3.664,7.415 2.296,3.316 25.481995,4.532 36.820995,-0.784 11.531,-5.406 -3.885,-47.514 -3.885,-47.514 z"
+     id="path86"
+     inkscape:connector-curvature="0" /><path
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 108.82665,147.75265 c 0,0 0.464,-21.64 21.464,-21.14 21,0.5 22,21.14 22,21.14"
+     id="path88"
+     inkscape:connector-curvature="0" /><path
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 194.78965,147.75265 c 0,0 5.5,-23.64 25,-23.64 19.5,0 21.571,21 21.571,21"
+     id="path90"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="M 154.28965,177.59465"
+     id="path92"
+     inkscape:connector-curvature="0" /><path
+     style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 154.28965,177.59465 c 0,0 0.715,18.789 16.607,18.421 15.893,-0.368 12.893,-18.421 12.893,-18.421"
+     id="path94"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 228.94765,254.13365 c -2.38,6.629 -9.604,20.319 -44.933,26.513 -37.922,6.649 -56.122,-3.11 -56.122,-3.11 l -10.787,-59.329 c 0,0 37.312,5.696 53.792,4.439 16.48,-1.257 33.346,-5.764 33.346,-5.764 0,0 18.324,-4.366 23.904,8.074 5.579,12.439 3.538,21.552 0.8,29.177 z"
+     id="path96"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_10_"
+     gradientUnits="userSpaceOnUse"
+     x1="316.32571"
+     y1="383.66669"
+     x2="316.32571"
+     y2="199.5519"><stop
+       offset="0"
+       style="stop-color:#402A04"
+       id="stop99" /><stop
+       offset="1"
+       style="stop-color:#7F5100"
+       id="stop101" /></linearGradient><polygon
+     style="fill:url(#SVGID_10_)"
+     points="408.426,250.667 394.198,218.593 358.725,207.167 262.541,210.167 237.725,225.136 224.225,247.667 "
+     id="polygon103"
+     transform="translate(-145.43535,-189.01935)" /><polygon
+     style="fill:#c1272d;stroke:#000000;stroke-miterlimit:10"
+     points="399.167,290.713 428.616,269.855 394.694,225.136 365.225,225.136 354.191,247.667 404.225,254.667 "
+     id="polygon105"
+     transform="translate(-145.43535,-189.01935)" /><path
+     style="fill:#c1272d;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 245.96865,0.64764917 c -6.811,-2.50199997 -41.178,27.49999983 -36.678,36.49999983 4.5,9 39,21.5 39,21.5 l 13.209,-17.558 c -10e-4,0 -4.031,-36.2179998 -15.531,-40.44199983 z"
+     id="path107"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#c1272d;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 272.19765,55.502649 -13.408,15.144 c 0,0 9,36.500001 17.5,35.500001 8.5,-1 32,-21.720001 30,-31.408001 -2,-9.688 -34.092,-19.236 -34.092,-19.236 z"
+     id="path109"
+     inkscape:connector-curvature="0" /><path
+     style="fill:#c1272d;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 243.78965,58.647649 c 0,0 13.418,-23.5 17.709,-22.5 4.291,1 15.093,16.043 15.791,19.356 0.698,3.313 -13,20.644 -18.5,19.144 -5.5,-1.5 -12.5,-10 -15,-16 z"
+     id="path111"
+     inkscape:connector-curvature="0" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="215.78966"
+     y1="36.11665"
+     x2="245.96864"
+     y2="54.967648"
+     id="line113" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="262.99066"
+     y1="73.483643"
+     x2="277.31567"
+     y2="96.647644"
+     id="line115" /><circle
+     style="opacity:0.2;fill:#d86d44"
+     cx="262.54099"
+     cy="357.16699"
+     r="19.249001"
+     id="circle117"
+     sodipodi:cx="262.54099"
+     sodipodi:cy="357.16699"
+     sodipodi:rx="19.249001"
+     sodipodi:ry="19.249001"
+     transform="translate(-145.43535,-189.01935)" /><circle
+     style="opacity:0.2;fill:#d86d44"
+     cx="372.72501"
+     cy="357.16699"
+     r="19.249001"
+     id="circle119"
+     sodipodi:cx="372.72501"
+     sodipodi:cy="357.16699"
+     sodipodi:rx="19.249001"
+     sodipodi:ry="19.249001"
+     transform="translate(-145.43535,-189.01935)" /><path
+     style="fill:#c1272d;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="M 231.14065,228.64765"
+     id="path121"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_11_"
+     gradientUnits="userSpaceOnUse"
+     x1="218.8582"
+     y1="511.4505"
+     x2="220.60651"
+     y2="520.62927"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0"
+       style="stop-color:#006178"
+       id="stop124" /><stop
+       offset="1"
+       style="stop-color:#00495C"
+       id="stop126" /></linearGradient><path
+     style="fill:url(#SVGID_11_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 61.249655,330.25265 c 0.7,3.23 4.623,2.704 4.623,2.704 0,0 14.196,-2.268 16.856,-2.704 2.66,-0.436 5.413,-2.183 4.802,-5.501 -0.611,-3.318 -2.578,-4.334 -4.977,-4.104 -2.143,0.206 -17.811,4.016 -17.811,4.016 0,0 -4.628,0.35 -3.493,5.589 z"
+     id="path128"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_12_"
+     gradientUnits="userSpaceOnUse"
+     x1="196.34351"
+     y1="377.0275"
+     x2="197.17529"
+     y2="381.39441"><stop
+       offset="0"
+       style="stop-color:#006178"
+       id="stop131" /><stop
+       offset="1"
+       style="stop-color:#00495C"
+       id="stop133" /></linearGradient><polygon
+     style="fill:url(#SVGID_12_);stroke:#000000;stroke-miterlimit:10"
+     points="186.437,382.911 186.437,379.506 206.978,374.966 207.302,379.506 "
+     id="polygon135"
+     transform="translate(-145.43535,-189.01935)" /><linearGradient
+     id="SVGID_13_"
+     gradientUnits="userSpaceOnUse"
+     x1="152.85809"
+     y1="432.1676"
+     x2="155.30721"
+     y2="445.02539"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop138" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop140" /></linearGradient><path
+     style="fill:url(#SVGID_13_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 2.5626545,251.52265 c 0.949,7.344 13.9770005,5.843 12.4400005,-2.53 -1.537,-8.373 -13.8540005,-8.404 -12.4400005,2.53 z"
+     id="path142"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_14_"
+     gradientUnits="userSpaceOnUse"
+     x1="150.90849"
+     y1="418.1373"
+     x2="153.3576"
+     y2="430.99509"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop145" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop147" /></linearGradient><path
+     style="fill:url(#SVGID_14_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 0.61265455,237.49265 c 0.94899995,7.344 13.97700045,5.843 12.44000045,-2.53 -1.537,-8.373 -13.85300045,-8.404 -12.44000045,2.53 z"
+     id="path149"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_15_"
+     gradientUnits="userSpaceOnUse"
+     x1="155.52521"
+     y1="446.19681"
+     x2="157.7338"
+     y2="457.79221"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop152" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop154" /></linearGradient><path
+     style="fill:url(#SVGID_15_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 5.7066545,264.72965 c 0.856,6.623 12.6050005,5.269 11.2180005,-2.281 -1.387,-7.55 -12.4920005,-7.58 -11.2180005,2.281 z"
+     id="path156"
+     inkscape:connector-curvature="0" /><linearGradient
+     id="SVGID_16_"
+     gradientUnits="userSpaceOnUse"
+     x1="153.2876"
+     y1="459.8923"
+     x2="155.15581"
+     y2="469.70059"
+     gradientTransform="translate(-145.43535,-189.01935)"><stop
+       offset="0.0019"
+       style="stop-color:#FFCA94"
+       id="stop159" /><stop
+       offset="1"
+       style="stop-color:#E2A380"
+       id="stop161" /></linearGradient><path
+     style="fill:url(#SVGID_16_);stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     d="m 14.738655,269.81365 c 0,0 -14.45200045,0.644 -13.0900005,6.785 1.362,6.141 15.1240005,2.806 15.1240005,2.806 l -2.034,-9.591 z"
+     id="path163"
+     inkscape:connector-curvature="0" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="103.19666"
+     y1="134.52966"
+     x2="111.07164"
+     y2="138.28766"
+     id="line165" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="116.44066"
+     y1="121.91666"
+     x2="119.95366"
+     y2="128.63864"
+     id="line167" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="231.53465"
+     y1="117.39664"
+     x2="227.96065"
+     y2="125.27765"
+     id="line169" /><line
+     style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="249.61266"
+     y1="127.38266"
+     x2="237.84065"
+     y2="134.52966"
+     id="line171" /><line
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="243.72664"
+     y1="311.64764"
+     x2="251.97566"
+     y2="348.16364"
+     id="line173" /><line
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="184.01564"
+     y1="310.31366"
+     x2="184.01564"
+     y2="349.90466"
+     id="line175" /><line
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="146.45665"
+     y1="311.64764"
+     x2="143.12267"
+     y2="350.95166"
+     id="line177" /><line
+     style="fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:10"
+     x1="218.07564"
+     y1="311.29565"
+     x2="222.05864"
+     y2="348.93066"
+     id="line179" /></svg>
diff --git a/docs/content/images/visuals/wireframe-visual.png b/docs/content/images/visuals/wireframe-visual.png
new file mode 100644 (file)
index 0000000..b22bd94
Binary files /dev/null and b/docs/content/images/visuals/wireframe-visual.png differ
diff --git a/docs/content/main.md b/docs/content/main.md
new file mode 100644 (file)
index 0000000..b54806b
--- /dev/null
@@ -0,0 +1,93 @@
+# DALi Introduction ajskdfajksd fhksja
+
+### Introduction
+ + [What is DALi?](@ref dali-introduction)
+ + [Features](@ref dali-features)
+ + [High Level Design](@ref dali-hld)
+  + [Components](@ref dali-components)
+  + [Main, Update & Render Threads](@ref dali-threads)
+ + [DALi Fundamentals](@ref fundamentals)
+  + [Actors & Stage](@ref actors-and-stage)
+  + [Layers and draw order](@ref layer)
+  + [Coordinate System](@ref coordinate-system)
+  + [Scene Graph](@ref scene-graph)
+  + [Handle / Body Idiom](@ref handle-body-idiom)
+  + [Signals](@ref signals)
+  + [Properties](@ref properties)
+  + [Actions](@ref actions)
+ + [Tutorial: Hello World](@ref hello-world)
+
+### Getting Started
+ + [How to build DALi on Ubuntu Desktop](@ref build-ubuntu)
+
+### Programming Guide
+ + [Programming Languages:](@ref programming-languages)
+  + [C++](@ref c-plus-plus)
+  + [JSON](@ref json-support)
+ + [Application](@ref dali-application)
+ + [Actors](@ref actors-and-stage)
+  + [Positioning](@ref positioning-actors)
+  + [Event Handling](@ref event-system)
+  + [Layouting](@ref size-negotiation)
+ + [Animation](@ref animation)
+  + [Basic Framework](@ref animation-basics)
+  + [Key Frame Animations](@ref animation-key-frame)
+  + [Path Animations](@ref animation-paths)
+  + [Constraints](@ref constraints)
+   + [Equal To Constraint](@ref constraints-equal-to)
+   + [Relative To Constraint](@ref constraints-relative-to)
+  + [Multi-threading Notes](@ref animation-multi-threading-notes)
+ + [Styling](@ref styling)
+
+### Resources
+ + [Resource Image](@ref resource-image)
+ + [9 Patch Image](@ref resource-9-patch)
+ + [Buffer Image](@ref resource-buffer)
+
+### Control Base Class & Visuals
+ + [Background Feature](@ref background)
+ + Keyboard Focus
+ + [Accessibility](@ref accessibility)
+ + [Visuals](@ref visuals)
+
+### UI Components
+ + Buttons
+ + [FlexContainer](@ref flex-container)
+ + [ItemView](@ref item-view)
+ + [Popup](@ref popup)
+ + [Scroll View](@ref scroll-view)
+ + TableView
+ + [Text Editor](@ref text-editor)
+ + [Text Field](@ref text-field)
+ + [Text Label](@ref text-label)
+
+### RenderTasks
+
+### Shader Effects
+ + [Overview](@ref shader-intro)
+
+### Scripting
+ + [JSON Overview](@ref scriptoverview)
+ + [JSON Syntax](@ref script-json-specification)
+ + [Scripting Hello World](@ref script-hello)
+
+### Tools
+ + Environment Variables
+ + [Resource Tracking](@ref resourcetracking)
+ + Logging
+ + [Visual Debug Rendering](@ref debugrendering)
+ + [Stagehand - DALi Visual Debugger](@ref stagehand)
+
+### Extending DALi
+ + [How to write Custom UI Components](@ref creating-custom-controls)
+  + [Size Negotiation for Controls](@ref size-negotiation-controls)
+  + [Type Registration](@ref type-registration)
+ + [Automated Tests](@ref auto_testing)
+ + [Programming Guide](@ref documentationguide)
+
+### Application Optimization Guide
+ + [Rescaling Images](@ref resourceimagescaling)
+ + Performance & Debugging
+ + [Performance Tips](@ref performancetips)
+ + [Performance Profiling](@ref performanceprofiling)
+
diff --git a/docs/content/programming-guide/accessibility.md b/docs/content/programming-guide/accessibility.md
new file mode 100644 (file)
index 0000000..5351682
--- /dev/null
@@ -0,0 +1,272 @@
+<!--
+/**-->
+
+[TOC]
+
+# Accessibility{#accessibility}
+
+
+## Introduction - What is Accessibility? {#accessibilityintroduction}
+
+Accessibility describes functionality designed to aid usage by the visually impaired.
+  
+This includes:
+- Reading out selections or other on-screen items via text-to-speech.
+- Item selection being controlled with gestures to aid selecting other small hard to select entities.
+  
+
+## Accessibility within DALi {#accessibilitydali}
+
+DALi will pick up the system's current accessibility state (and subsequent changes to it) and enable its internal accessibility mode based on this.
+  
+DALi includes an Accessibility Manager which provides public API control of the order of object selection by gesture, and text to be read out per actor or control.
+  
+It further provides many signals that represent accessibility gestures. These gestures can range from a simple actor selection through to a more control-specific concept like "page-up", which an application developer may want to provide an implementation for.
+  
+Furthermore, these APIs can be used not only with existing actors and controls, but also when creating a custom control.
+  
+The AccessibilityManager lives within DALi Toolkit. Please see accessibility-manager.h for the full API.
+
+
+## Accessibility Focus {#accessibilityfocus}
+
+<!-- Float image to the right of the text -->
+<div style="float: right">
+    ![ ](./accessibility-focus.png)
+</div>
+
+Visibly, when enabled, accessibility will typically show an actor (or actors) as focused. This is represented by default with yellow rectangular frame around the actor. See this section for [modifying the appearance of the accessibility focus](#accessibilityfocusappearance).
+  
+Once in accessibility mode, normal control is disabled and accessibility gestures must be used to access content.
+DALi actors and controls will no longer receive tap gestures or click events when they are touched once (as they normally would).
+  
+Note: The accessibility focus is also referred to as the Focus Indicator.
+
+
+### Moving the focus with gestures {#accessibilitygestures}
+
+Accessibility recognizes many gesture types to move the accessibility focus from actor to actor.
+  
+Note:
+  
+- Some of these gestures have pre-defined, automatic behaviour.
+- Some gestures require an specific implementation to be added to use.
+- All can be caught as signals if extra control is needed.
+  
+To test (and understand) this behaviour, you can use the Tizen adaptor which uses the following gestures to perform basic operation:
+  
+Note: The gestures that perform these actions are platform specific. These are the gestures implemented in the Tizen adaptor for example only.
+  
+- Swiping right and left will move the focus forward and backward one item.
+- Doing a left or right swipe-return (where a direction is swiped forwards and backwards quickly) will move to the previous or next page - DALi cannot know what a page is within your application so these gestures can only work if implemented manually.
+  
+
+![ ](./accessibility-focus-order.png)
+
+### Activation {#accessibilityactivation}
+
+Activation describes an operation performed on a selected actor, typically an on-tap or on-click event.
+  
+Activating an actor in accessibility mode will call a virtual function, as well as signal, for that actor.
+Depending on the platform this can be triggered in different ways.
+When activated, the built in actor types (like PushButton) will do the equivalent of a tap.
+  
+Custom-built actor types will need to implement activation in order to perform a specific behaviour. See the [Custom Controls](#accessibilitycustomcontrol) section.
+  
+Therefore, to tap an actor (EG. Click a button) in accessibility mode, the following must be done:
+  
+- The actor needs to be selected first (using gestures specific to the platform).
+- Then activated, by using the activation gesture.
+  
+## Scrolling {#accessibilityscrolling}
+
+Scrolling around a view outside of accessibility is normally performed by simply holding one finger and dragging (in the appropriate direction).
+Within accessibility this can be overridden and performed with a different gesture type to achieve the same effect.
+  
+Example: For the Tizen platform scrolling is performed with a two-finger drag.
+
+
+## Basic functionality {#accessibilitybasicfunctionality}
+
+### Using the Accessibility Manager functionality {#accessibilityfunctionality}
+
+Accessibility information is stored within the accessibility manager itself rather than within actors.
+This allows the manager to have a global view of focusable actors and their order.
+  
+The Accessibility Manager is a singleton (owned by the singleton service) and can be accessed via its static Get() method:
+  
+~~~{.cpp}
+// Get the accessibility manager singleton.
+accessibilityManager accessibilityManager = AccessibilityManager::Get();
+~~~
+
+
+### Controlling where the focus will move {#accessibilitymovingfocus}
+
+In order to provide automatic focus movement, the accessibility manager must be told the focus order of any actors to be selected.
+This order is a linear order. It can move forwards or backwards only (there is no concept of "up" or "down").
+  
+The order of a particular actor can be set with a call to the accessibility manager like so:
+  
+~~~{.cpp}
+// 6 is an int representing this actor's position in the focus chain.
+accessibilityManager.SetFocusOrder( actor, 6 );
+~~~
+  
+The focus order of each actor in the focus chain is unique. If there is another actor assigned with the same focus order already, the new actor will be inserted to the focus chain with that focus order, and the focus order of the original actor and all the actors followed in the focus chain will be increased accordingly.
+  
+If the focus order assigned to the actor is 0, it means that actor's focus order is undefined (e.g. the actor has a description but with no focus order being set yet) and therefore that actor is not focusable.
+  
+Moving focus to a particular actor directly can be done with SetCurrentFocusActor like so:
+  
+~~~{.cpp}
+// Move focus to the first item on our applications page.
+AccessibilityManager accessibilityManager = AccessibilityManager::Get();
+  
+accessibilityManager.SetCurrentFocusActor( table.GetChildAt( 0 ) );
+~~~
+
+### Modifying the appearance of the accessibility focus {#accessibilityfocusappearance}
+
+The focus graphic itself can be customized.
+It can be an image (EG. A nine-patch border) or any other type of actor.
+  
+It can be set using this method within C++:
+  
+~~~{.cpp}
+accessibilityManager.SetFocusIndicatorActor( myCustomIndicatorActor );
+~~~
+
+
+### Using activation {#accessibilityusingactivation}
+
+If the application would like to perform specific behaviour when an entity is activated, it can catch the activation by connecting to a signal like this:
+  
+~~~{.cpp}
+AccessibilityManager::Get().FocusedActorActivatedSignal().Connect( this, &MyClass::OnFocusedActorActivated );
+~~~
+  
+Controlling the activation behaviour within a custom control is covered in the [custom control section](#accessibilitycustomcontrol)
+
+
+## Focus groups {#accessibilityfocusgroups}
+
+<!-- Float image to the right of the text -->
+<div style="float: right">
+    ![ ](./accessibility-focus-group.png)
+</div>
+
+Group mode allows the limiting of focusable actors.
+  
+Example: If a popup appears, you may want the focus to be limited to only the OK and Cancel buttons. You can do this by setting the popup as a focus group and turning on group mode, the focus will be limited.
+  
+~~~{.cpp}
+// Create a parent actor and add two children to it.
+Actor groupActor = Actor::New();
+
+Actor child1 = Actor::New();
+groupActor.Add( child1 );
+
+Actor child2 = Actor::New();
+groupActor.Add( child2 );
+
+AccessibilityManager accessibilityManager = AccessibilityManager::Get();
+
+// Mark the parent as a focus group. Now focus movement *can* be limited to the children of this actor.
+// Note: That this is not enabled until specified.
+accessibilityManager.SetFocusGroup( groupActor, true );
+
+// Enable the focus group mode.
+accessibilityManager.SetGroupMode( true );
+~~~
+
+
+### Wrap mode {#accessibilitywrapmode}
+
+Wrap mode allows the focus to wrap back to the beginning once the end is reached.
+  
+In group mode this will move to the beginning of the current focus group.
+  
+~~~{.cpp}
+AccessibilityManager accessibilityManager = AccessibilityManager::Get();
+
+// Enable wrap mode.
+accessibilityManager.SetWrapMode( true );
+~~~
+
+
+## Using Accessibility {#accessibilityusage}
+
+### Using accessibility with existing actors {#accessibilityactors}
+
+This example sets up a 3 by 3 grid of actors with the following accessibility functionality:
+  
+  - They have a focus order that moves from top left to bottom right (when using the accessibility next and previous gestures).
+  - They contain text that will be spoken out loud (via text-to-speech) when the focus changes.
+  
+Note that all the above is set via the AccessibilityManager and not as properties within the actors.
+  
+The text spoken per tile will be the LABEL, TRAIT and HINT (in that order).
+  
+~~~{.cpp}
+Toolkit::TableView table = Toolkit::TableView::New( 3, 3 );
+int tileNumber = 0;
+for( int row = 0; row < 3; ++row )
+{
+  for( int column = 0; column < 3; ++column )
+  {
+    // Create a solid color actor, with some text.
+    Actor tile = Toolkit::CreateSolidColorActor( Vector4( 1.0f, 1.0f, 0.0f, 1.0f ) );
+    Toolkit::TextLabel text = Toolkit::TextLabel::New( tileNames[tileNumber] );
+    tile.Add( text );
+
+    // Get the accessibility manager singleton.
+    accessibilityManager accessibilityManager = AccessibilityManager::Get();
+
+    // Set the focus order of this actor.
+    accessibilityManager.SetFocusOrder( tile, tileNumber );
+
+    // Set up the accessibility information for this actor (this will be read out with text-to-speech).
+    accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL, tileNames[tileNumber] );
+    accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_TRAIT, "Tile" );
+    accessibilityManager.SetAccessibilityAttribute( tile, Dali::Toolkit::AccessibilityManager::ACCESSIBILITY_HINT, "You can run this example");
+
+    // Lay out our actor within the table view.
+    table.AddChild( tile, Toolkit::TableView::CellPosition( row, column ) );
+
+    tileNumber++;
+  }
+}
+Stage::GetCurrent().Add( table );
+~~~
+
+### Using accessibility within a custom control (C++) {#accessibilitycustomcontrol}
+
+Accessibility behaviour can be customized in a custom UI control by overriding all or some of the following methods.
+
+| Method                     | Description                                                                                                                                                                |
+|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| OnAccessibilityActivated   | When the control is *activated* or selected, in accessibility mode.                                                                                                        |
+| OnAccessibilityPan         | When an accessibility pan gesture occurs while this control is focused.                                                                                                   |
+| OnAccessibilityTouch       | Touch events are delivered differently in Accessibility mode. This method should be overridden if some special behaviour is required when these touch events are received. |
+| OnAccessibilityValueChange | When a value is changed while this control is focused (e.g. value change of a slider control).                                                                            |
+| OnAccessibilityZoom        | Should be overridden if behaviour is required when the magnification level changes when this control is focused.                                                          |
+If these events are consumed, then the method should return true.
+The default behaviour in the control base classes returns false, i.e. not consumed.
+### Using accessibility signals for extra control {#accessibilitysignals}
+
+For more specific control of functionality when accessibility is enabled, there are several signals within the accessibility manager's public API that can be connected to.
+  
+The main categories of signals are:
+  
+- The signal when the accessibility status is detected as being toggled on or off: StatusChangedSignal()
+- Focus changes can cause FocusChangedSignal() and FocusOvershotSignal(). These can be connected to in order to provide custom actions when the focus is moved around the screen.
+- The activated signal when an actor has been activated (typically by a focus, then double tap): ActionActivateSignal()
+- Gesture received signals: There are many of these. They are each linked to the many accessibility gestures that can be received by the system.
+  
+Please see accessibility-manager.h within DALi Toolkit for the full API.
+
+
+*/
diff --git a/docs/content/programming-guide/animation-multi-threading-notes.h b/docs/content/programming-guide/animation-multi-threading-notes.h
new file mode 100644 (file)
index 0000000..4c06450
--- /dev/null
@@ -0,0 +1,64 @@
+/*! \page animation-multi-threading-notes Animation: Multi-threading Notes
+ *
+
+<h2 class="pg">Multi-threaded Architecture</h2>
+
+DALi animations and rendering occur in a dedicated rendering thread.  This allows animations to run smoothly, regardless of the time taken to process inputs events etc. in application code.
+
+Internally DALi contains a scene-graph, which mirrors the Actor hierachy.  The scene-graph objects perform the actual animation & rendering, whilst Actors provide thread-safe access.
+
+An example actor hierachy is shown below, in which one of the actors is being animated.  The objects in green are created by the application code, whilst the private objects in blue are used in the dedicated rendering thread.
+
+\image html multi-threaded-animation.png
+
+<h2 class="pg">Reading an animated value</h2>
+
+When a property is animatable, it can only be modified in the rendering thread.  The value returned from a getter method, is the value used when the previous frame was rendered.
+
+For example \ref Dali::Actor::GetCurrentPosition "Dali::Actor::GetCurrentPosition" returns the position at which the Actor was last rendered.  Since \ref Dali::Actor::SetPosition "Dali::Actor::SetPosition" is asynchronous, a call to \ref Dali::Actor::GetCurrentPosition "Dali::Actor::GetCurrentPosition" won't immediately return the same value.
+
+@code
+// Whilst handling an event...
+
+Actor actor = Actor::New();
+Stage::GetCurrent().Add(actor); // initial position is 0,0,0
+
+actor.SetPosition(Vector3(10,10,10));
+
+Vector3 current;
+current = actor.GetCurrentPosition();
+std::cout << "Current position: " << current.x << ", " << current.y << ", " << current.z << std::endl;
+
+std::cout << "..." << std::endl;
+
+// Whilst handling another event...
+
+current = actor.GetCurrentPosition();
+std::cout << "Current position: " << current.x << ", " << current.y << ", " << current.z << std::endl;
+
+@endcode
+
+The example code above would likely output:
+
+@code
+"Current position: 0,0,0"
+"..."
+"Current position: 10,10,10"
+@endcode
+
+<h2 class="pg">Setting a property during an animation</h2>
+
+When a property is being animated, the Animation will override any values set e.g. with Actor::SetPosition()
+
+\image html multi-threaded-animation-2.png
+
+The order of execution in the render thread is:
+
+@code
+1) Process message => SetPosition
+2) Apply animation => SetPosition
+3) Render frame
+@endcode
+
+*
+*/
diff --git a/docs/content/programming-guide/animation.md b/docs/content/programming-guide/animation.md
new file mode 100644 (file)
index 0000000..f979870
--- /dev/null
@@ -0,0 +1,152 @@
+<!--
+/**-->
+
+# Animation {#animation}
+
+DALi provides a rich and easy to use animation framework which allows the creation of visually rich applications.
+Dali::Animation can be used to animate the properties of any number of objects, typically Actors.
+
+## Creating a basic Animation {#animation-basics}
+
+Create an animation object that will take place over 3 seconds:
+~~~{.cpp}
+Dali::Animation animation = Animation::New( 3.0f );
+~~~
+
+### Animating Properties
+
+There are two distinct ways in which properties can be animated within DALi:
+- **AnimateTo:** The property will animate **TO** the value in the given time.
+- **AnimateBy:** The property will animate **BY** the value in the given time.
+
+(Assume actor1 & actor2 are at position 10.0f, 10.0f, 0.0f at the start of the animation)
+~~~{.cpp}
+// Animate the position of actor1 TO 10.0f, 50.0f, 0.0f
+animation.AnimateTo( Property( actor1, Dali::Actor::Property::POSITION ), Vector3(10.0f, 50.0f, 0.0f) ); // End Position: 10.0f, 50.0f, 0.0f
+
+// Animate the position of actor2 BY 10.0f, 50.0f, 0.0f
+animation.AnimateBy( Property( actor2, Dali::Actor::Property::POSITION ), Vector3(10.0f, 50.0f, 0.0f) ); // End Position: 20.0f, 60.0f, 0.0f
+~~~
+
+Note, for rotations, AnimateTo uses spherical linear interpolation to animate to the new orientation (i.e. it will take the shortest path). Because of this, the number of complete revolutions in any given angle will be reduced to 0. For example,
+
+(Assume actor1 is at orientation 0 degrees about Z-Axis at the start of the animation)
+~~~{.cpp}
+// Animate the orientation of actor1 to 390 degrees about the Z-AXIS
+animation.AnimateTo( Property( actor1, Dali::Actor::Property::ORIENTATION ), AngleAxis( Degree( 390 ), Vector3::ZAXIS ) );
+~~~
+
+will only rotate 30 degrees about the Z axis, as that is the shortest path to the final orientation.
+
+AnimateBy will preserve the full revolution count of any angle passed in using AngleAxis, for example, AngleAxis( Degree( 770 ), Vector3::ZAXIS ) will revolve 2 full times before reaching the final angle of 50 degrees from the original orientation.
+
+However, because Quaternions do not preserve the revolution count, AnimateBy will only rotate 50 degrees if the relative value is constructed using a Quaternion. For example,
+
+(Assume actor1 and actor 2 are at orientation 0 degrees about Z-Axis at the start of the animation)
+~~~{.cpp}
+// Animate the orientation of actor1 3.5 times about the Z-AXIS
+animation.AnimateBy( Property( actor1, Dali::Actor::Property::ORIENTATION ), AngleAxis( Degree( 360 * 3.5 ), Vector3::ZAXIS ) );
+
+// But the same degree value will only rotate 180 degrees if a Quaternion is used instead:
+animation.AnimateBy( Property( actor2, Dali::Actor::Property::ORIENTATION ), Quaternion( Degree( 360 * 3.5 ), Vector3::ZAXIS ) );
+~~~
+
+### Playback Control
+
+When an animation is created, it can be played:
+~~~{.cpp}
+animation.Play();
+~~~
+
+Stop and Pause are also supported.
+~~~{.cpp}
+animation.Stop();
+animation.Pause();
+~~~
+
+### Notifications
+
+Using DALi's signal framework, applications can be notified when the animation finishes:
+
+~~~{.cpp}
+
+void ExampleCallback( Animation& source )
+{
+  std::cout << "Animation has finished" << std::endl;
+}
+...
+animation.FinishedSignal().Connect( &ExampleCallback );
+~~~
+
+### Alpha Functions
+
+Alpha functions are used in animations to specify the rate of change of the animation parameter over time.
+The built in supported functions can be viewed in Dali::AlphaFunction::BuiltinFunction.
+
+It is possible to specify a different alpha function for each animator in an Animation object:
+~~~{.cpp}
+animation.AnimateTo( Property( actor1, Dali::Actor::Property::POSITION ), Vector3(10.0f, 50.0f, 0.0f), Dali::AlphaFunction::EASE_IN );
+~~~
+
+### Other Actions
+
+An animation can be looped:
+~~~{.cpp}
+animation.SetLooping( true );
+~~~
+
+By default, when an animation ends, the properties that it was animating are BAKED.
+However, the property changes can be **discarded** when the animation ends (or is stopped):
+~~~{.cpp}
+animation.SetEndAction( Animation::Discard );
+~~~
+
+## Key-Frame Animation {#animation-key-frame}
+
+DALi provides support for animating between several different values, i.e. key-frames.
+A key frame takes a progress value between 0.0f and 1.0f (0 and 100% respectively) and portrays the value of the property when the animation has progressed that much.
+You can create several key frames:
+~~~{.cpp}
+Dali::KeyFrames keyFrames = Dali::KeyFrames::New();
+keyFrames.Add( 0.0f, Vector3( 10.0f, 10.0f, 10.0f ) );
+keyFrames.Add( 0.7f, Vector3( 200.0f, 200.0f, 200.0f ) );
+keyFrames.Add( 1.0f, Vector3( 100.0f, 100.0f, 100.0f ) );
+~~~
+And then add them to your animation.
+~~~{.cpp}
+animation.AnimateBetween( Property( actor1, Dali::Actor::Property::POSITION ), keyFrames );
+~~~
+When you play the animation, DALi will animate the position of actor1 between the key-frames specified.
+'actor1' will animate from (10.0f, 10.0f, 10.0f) to (200.0f, 200.f, 200.0f) by 70% of the animation time,
+and then spend the remaining time animating back to (100.0f, 100.0f, 100.0f).
+
+The advantage of specifying a key-frame at 0% is that regardless of where 'actor1' is, it will start from position (10.0f, 10.0f, 10.0f).
+If AnimateTo was used, then the start position would have been actor1's current position.
+
+## Path Animations {#animation-paths}
+
+A Dali::Path can be used to animate the position and orientation of actors.
+
+![ ](animation/animated-path.png)
+
+The black points in the diagram are points where the DALi logo will travel to.
+The red points are the control points which express the curvature of the path on the black points.
+
+This, in code will be represented as follows:
+~~~{.cpp}
+Path path = Path::New();
+path.AddPoint( Vector3( 50.0f, 10.0f, 0.0f ));
+path.AddPoint( Vector3( 90.0f, 50.0f, 0.0f ));
+path.AddPoint( Vector3( 10.0f, 90.0f, 0.0f ));
+~~~
+The control points can be added manually using Dali::Path::AddControlPoint or Path can auto-generate them for you:
+~~~{.cpp}
+path.GenerateControlPoints(0.25f);
+~~~
+Here 0.25f represents the curvature of the path you require. Please see Dali::Path::GenerateControlPoints for more information.
+
+To animate actor1 along this path:
+~~~{.cpp}
+animation.Animate( actor1, path, Vector3::ZERO );
+~~~
+The third parameter is the forward vector (in local space coordinate system) that will be oriented with the path's tangent direction.
diff --git a/docs/content/programming-guide/background.h b/docs/content/programming-guide/background.h
new file mode 100644 (file)
index 0000000..10073cb
--- /dev/null
@@ -0,0 +1,80 @@
+/*! \page background Background
+ *
+@section background-color Background Color
+
+It is possible to set a background color for a DALi control.  If the application writer wishes to
+set a control with a red background:
+
+@code
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+control.SetBackgroundColor( Dali::Color::RED );
+@endcode
+
+<table border=0 cellpadding=10><tr>
+<td>
+\image html BackgroundControlColor.png
+</td>
+</table>
+
+This can be used for ALL existing controls like TextLabel as well:
+@code
+Dali::Toolkit::TextLabel label = Dali::Toolkit::TextLabel::New( "Hello World" );
+label.SetBackgroundColor( Dali::Color::RED );
+@endcode
+
+<table border=0 cellpadding=10><tr>
+<td>
+\image html BackgroundTextLabel.png
+</td>
+</table>
+
+@section background-image Background Image
+
+If required, the user can also set a background image as a DALi control:
+
+@code
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+Dali::Image image = Dali::Image::New( "image.png" );
+control.SetBackgroundImage( image );
+@endcode
+
+<table border=0 cellpadding=10><tr>
+<td>
+\image html BackgroundImage.png
+</td>
+</table>
+
+The background image is blended with the background color. If a red background color is set on the
+control:
+@code
+control.SetBackgroundColor( Dali::Color::RED );
+@endcode
+then the above image will look like:
+
+<table border=0 cellpadding=10><tr>
+<td>
+\image html BackgroundImageColor.png
+</td>
+</table>
+
+@section background-visual Background Visual
+
+The background can be set to use a specified visual, e.g the border visual
+@code
+Property::Map visual;
+visual.Insert( Visual::Property::Type,Visual::BORDER );
+visual.Insert( BorderVisual::Property::COLOR, COLOR::RED );
+visual.Insert( BorderVisual::Property::SIZE, 20.f );
+
+control.SetProperty( Control::Property::BACKGROUND, visual);
+@endcode
+
+then the above image will look like:
+<table border=0 cellpadding=10><tr>
+<td>
+\image html BackgroundBorder.png
+</td>
+</table>
+
+*
+*/
diff --git a/docs/content/programming-guide/build-guide.md b/docs/content/programming-guide/build-guide.md
new file mode 100644 (file)
index 0000000..9a35da8
--- /dev/null
@@ -0,0 +1,80 @@
+<!--
+/**-->
+# Build Guide {#build-guide}
+
+## Ubuntu {#build-ubuntu}
+
+These instructions explain how to build the DALi library for the Ubuntu 14.04 desktop environment.
+
+### Minimum Requirements
+
++ Ubuntu 14.04
++ Ensure ALL sources are selected:
+ + Go to Ubuntu Settings and then to "Software & Updates".
+ + In the "Ubuntu Software" tab, ensure ALL software sources are ticked. (This is required because we install some community-maintained free & open-source software).
+
+### Creating a DALi environment
+
+DALi provides a script to set up your desktop environment. This script can be found in the dali-core repository.
+
++ Fetch ALL 4 repositories from tizen.org.
++ In the parent directory of these repositories, run the following command:
+  ~~~{.sh}
+  dali-core/build/scripts/dali_env -c
+  ~~~
+  This will also download any dependencies that the dali repositories require.
+
++ You can save the environment variables to a file:
+  ~~~{.sh}
+  dali-env/opt/bin/dali_env -s > setenv
+  ~~~
+
+The last few steps only need to be done once.
+
+You will have to source your environment variables every time you open up a new terminal (or you can add to .bashrc if you prefer).
+You can do this by sourcing the '''setenv''' script you created above:
+~~~{.sh}
+. setenv
+~~~
+
+### Building the repositories
+
+#### dali-core
+~~~{.sh}
+cd dali-core/build/tizen
+autoreconf --install
+./configure --prefix=$DESKTOP_PREFIX
+make install -j8
+~~~
+
+#### dali-adaptor
+~~~{.sh}
+cd dali-adaptor/build/tizen
+autoreconf --install
+./configure --prefix=$DESKTOP_PREFIX --enable-profile=UBUNTU
+make install -j8
+~~~
+
+#### dali-toolkit
+~~~{.sh}
+cd dali-toolkit/build/tizen
+autoreconf --install
+./configure --prefix=$DESKTOP_PREFIX
+make install -j8
+~~~
+
+#### dali-demo
+~~~{.sh}
+cd dali-demo/build/tizen
+cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX .
+make install -j8
+~~~
+
+### Running dali-demo
+
+Ensure you have sourced your environment as mentioned above and then just run:
+~~~{.sh}
+dali-demo
+~~~
+
+*/
diff --git a/docs/content/programming-guide/constraints.h b/docs/content/programming-guide/constraints.h
new file mode 100644 (file)
index 0000000..6c4f194
--- /dev/null
@@ -0,0 +1,251 @@
+/*! \page constraints Constraints
+ *
+
+<h1 class="pg">Introduction</h1>
+
+Constraints are used to modify the property of an actor, based on other properties of the same actor; properties of the actor's parent; or properties of another actor altogether, when the modification needs to be at run-time.
+Custom functions or functors can be supplied, where the desired value of the property can be calculated.
+These functions (or functors) are called in every frame so should be fast and not too complex otherwise it will hit performance.
+
+Multiple constraints can be applied to the same actor at the same time.
+The order in which constraints are applied is important as this is the order in which they are processed in the update thread.
+
+Constraints are applied after animations have been applied.
+This means that Constraints override the values set by Animations.
+
+Not all properties can be used as a constraint input, please see Dali::Handle::IsPropertyAConstraintInput() for more details.
+
+<h1 class="pg">When to use a Constraint</h1>
+
+Constraints are designed as a way of modifying properties that cannot be modified by any existing built in functionality; Like Animations, Size negotiation or Parent anchor, origin settings.
+As they provide the ability for the application developer to execute their own code within the update thread, DALi can no-longer guarantee the timeliness of this code, or how optimised it may be.
+
+Generally, you should not use constraints with the SIZE property as constraining the size and size negotiation are mutually exclusive.
+Consider the following use cases as an example of when and when not to use a constraint:
+
+<table>
+  <tr>
+    <td><b>Requirement:</b></td>
+    <td><b>Desired Solution:</b></td>
+  </tr>
+  <tr>
+    <td>Need a child to be 50% the size of it's parent.</td>
+    <td>Use Size negotiation.</td>
+  </tr>
+  <tr>
+    <td>Need to zoom an actor in to the screen via it's scale property.</td>
+    <td>Use an Animation.</td>
+  </tr>
+  <tr>
+    <td>Need an actor to appear centered around the bottom-right corner of it's parent.</td>
+    <td>Use ParentOrigin & AnchorPoint.</td>
+  </tr>
+  <tr>
+    <td>Need to lay out a series of controls with various alignment requirements.</td>
+    <td>Use either Anchor & origin settings, or a TableView.</td>
+  </tr>
+  <tr>
+    <td>Need to automatically modify the position property of one actor based on the position property of another actor, that is neither a parent OR a child.</td>
+    <td>Use a Constraint.</td>
+  </tr>
+  <tr>
+    <td>Need to position an actor relative to it's parent actor in a NON-UNIFORM way, IE. a non-linear calculation needs to be performed that requires a functor.</td>
+    <td>Use a Constraint.</td>
+  </tr>
+  <tr>
+    <td>Need to modify an actor's property in real time based on some calculations that require additional data to be stored in-between frames.</td>
+    <td>Use a Constraint. The constraint functor can hold any variables within it that need to be preserved frame-to-frame.</td>
+  </tr>
+</table>
+
+For most general cases, the position and size requirements of a child or parent actor (from it's child or parent) can be calculated with Size Negotiation.
+
+<h1 class="pg">Constraint Sources</h1>
+
+These are properties of this (or another actor) that are used as inputs into the constraint.
+The constraint will take these values, optionally perform a calculation on them (if using a custom functor) and write the result to the specified property of the target actor.
+The source actor is specified as either the same actor, it's parent or another actor.
+
+<h2 class="pg">Local Source</h2>
+
+A local source is based on the local properties (i.e. size, position, scale, orientation, color) of an actor.
+For example, the actor's orientation could be used as a constraint input source.
+
+@code
+Dali::ConstraintSource source( Dali::LocalSource( Dali::Actor::Property::ORIENTATION ) );
+@endcode
+
+<h2 class="pg">Parent Source</h2>
+
+A parent source is based on properties of the actor's parent.
+For example, a parent's position can be used as a constraint input source.
+
+@code
+Dali::ConstraintSource source( Dali::ParentSource( Dali::Actor::Property::POSITION ) );
+@endcode
+
+<h2 class="pg">Source</h2>
+
+Finally, you can base your source on the properties of another handle altogether.
+For example, a sibling actor's color could be used as a constraint input source.
+
+@code
+Dali::ConstraintSource source( Dali::Source( anotherHandle, Dali::Actor::Property::COLOR ) );
+@endcode
+
+<h1 class="pg">The Constraint Function</h1>
+
+The signature of the constraint function is:
+
+@code
+void Function( PropertyType& current, const Dali::PropertyInputContainer& inputs );
+@endcode
+
+Here 'current' is a reference to the target property type, e.g. float, Vector2, Vector3 etc.
+This is an in/out parameter.
+It represents the current value of the property and the expectation is that it will be modified by the function to the desired value.
+
+The 'inputs' parameter holds all the constraint input sources.
+Each element is a pointer to the property-input and can be accessed using the indexing operator[].
+The order in which the sources are added is the order in which the property-inputs are sorted in the container. For example:
+
+@code
+constraint.AddSource( Dali::LocalSource( Dali::Actor::Property::POSITION ) );
+constraint.AddSource( Dali::LocalSource( Dali::Actor::Property::SIZE ) );
+constraint.AddSource( Dali::ParentSource( Dali::Actor::Property::POSITION ) );
+constraint.AddSource( Dali::ParentSource( Dali::Actor::Property::SIZE ) );
+@endcode
+
+In the constraint function this equates to:
+@code
+const Dali::Vector3& position( inputs[0]->GetVector3() );
+const Dali::Vector3& size( inputs[1]->GetVector3() );
+const Dali::Vector3& parentPosition( inputs[2]->GetVector3() );
+const Dali::Vector3& parentSize( inputs[3]->GetVector3() );
+@endcode
+
+<h1 class="pg">Creating a Constraint</h1>
+
+<h2 class="pg">Using C Functions</h2>
+
+If you do not have any data that is changed at runtime, then C functions should be used.
+For example, the color of an actor could be changed based on its position along the x-axis till a preset distance of 100, beyond which it is transparent.
+
+@code
+Dali::Actor actor = Actor::New();
+
+Dali::Constraint constraint = Dali::Constraint::New< Vector4 >( actor, Dali::Actor::Property::COLOR, MyConstraintFunction ); // Creates a constraint that targets actor
+constraint.AddSource( Dali::LocalSource( Dali::Actor::Property::POSITION ) ); // Adds the POSITION property as a constraint input
+constraint.Apply(); // The constraint is applied
+@endcode
+
+And the actual C Function:
+
+@code
+void MyConstraintFunction( Dali::Vector4& current, const Dali::PropertyInputContainer& inputs )
+{
+  const Dali::Vector3& position( inputs[0]->GetVector3() );
+
+  float distance = fabs( position.x );
+
+  // More than 100.0f away, opacity is 0.0f
+  if ( distance > 100.0f )
+  {
+    current.a = 0.0f;
+  }
+  else
+  {
+    // Otherwise it will blend between fully opaque and transparent
+    current.a = ( 100.0f - distance ) / 100.0f;
+  }
+}
+@endcode
+
+Please have a look at Dali::Constraint::New() for more details.
+
+<h2 class="pg">Using Functors</h2>
+
+If you need to store some data in a struct/class, then a functor can be used.
+Reusing the last example, the color of an actor is changed based on its position along the x-axis, but the distance when it is transparent is different for each applied constraint.
+
+@code
+Dali::Actor actor = Actor::New();
+
+Dali::Constraint constraint = Dali::Constraint::New< Vector4 >( actor, Dali::Actor::Property::COLOR, MyFunctor( 200 ) ); // Creates a constraint that targets actor, and uses MyFunctor with a distance of 200
+constraint.AddSource( Dali::LocalSource( Dali::Actor::Property::POSITION ) ); // Adds the POSITION property as a constraint input
+constraint.Apply(); // The constraint is applied
+@endcode
+
+And the struct:
+
+@code
+struct MyFunctor
+{
+  /// Constructor which takes the distance at which the actor will be fully transparent
+  MyFunctor( float distance )
+  : mDistance( distance )
+  {
+  }
+
+  /// Functor
+  void operator()( Dali::Vector4& current, const Dali::PropertyInputContainer& inputs )
+  {
+    const Dali::Vector3& position( inputs[0]->GetVector3() );
+
+    float distance = fabs( position.x );
+
+    // More than mDistance away, opacity is 0.0f
+    if ( distance > mDistance )
+    {
+      current.a = 0.0f;
+    }
+    else
+    {
+      // Otherwise it will blend between fully opaque and transparent
+      current.a = ( mDistance - distance ) / mDistance;
+    }
+  }
+
+  // Data
+  const float mDistance;
+};
+@endcode
+
+MyFunctor could then be used with another constraint with a different distance.
+
+Please have a look at Dali::Constraint::New(Handle, Property::Index, const T&) for more details.
+
+Instead of using the default functor, another method can be declared in the class or struct and used as the constraint function.
+Please have a look at the appropriate Dali::Constraint::New() method for more details.
+
+<h1 class="pg">Removing Constraints</h1>
+
+The actor's constraints can later be removed in several ways:
+
+@code
+mConstraint.Remove(); // mConstraint is a base-handle to a constraint
+actor.RemoveConstraints(); // Removes ALL constraints applied to an actor
+actor.RemoveConstraint( tag ); // All constraints with the tag are removed from the actor (tag can be set using SetTag)
+@endcode
+
+\section constraints-equal-to Equal To Constraint
+
+The built in Dali::EqualToConstraint can be used if all that is required is setting a property equal to another property:
+@code
+Dali::Constraint constraint = Dali::Constraint::New< Vector3 >( actor, Dali::Actor::Property::POSITION, Dali::EqualToConstraint() );
+constraint.AddSource( Dali::Source( anotherActor, Dali::Actor::Property::POSITION ) );
+constraint.Apply();
+@endcode
+Here actor's position is set to equal the position of anotherActor.
+
+\section constraints-relative-to Relative To Constraint
+
+The built in Dali::RelativeToConstraint and Dali::RelativeToConstraintFloat can be used if all that is required is setting a property relative to another property:
+@code
+Dali::Constraint constraint = Dali::Constraint::New< Vector3 >( actor, Dali::Actor::Property::POSITION, Dali::RelativeToConstraint( 2.0f ) );
+constraint.AddSource( Dali::Source( anotherActor, Dali::Actor::Property::POSITION ) );
+constraint.Apply();
+@endcode
+Here actor's position is relative to the position of anotherActor, i.e., if anotherActor is at (10.0f, 20.0f, 30.0f), actor will be at (20.0f, 40.0f, 60.0f).
+*
+*/
diff --git a/docs/content/programming-guide/copy-and-paste.md b/docs/content/programming-guide/copy-and-paste.md
new file mode 100644 (file)
index 0000000..54a60fa
--- /dev/null
@@ -0,0 +1,27 @@
+<!--
+/**-->
+
+# Copy and Paste  (Selection) {#copy-n-paste}
+
+Text can be selected by a long press or double tapping it.   Depending on certain conditions a popup could be shown giving options including [CUT][COPY][PASTE], [SELECT ALL] or [CLIPBOARD]. Below these conditions will be explained.
+
+[CUT] or [COPY] send the selected text to the clipboard ready to be pasted directly or via the clipboard UI.   Pressing [PASTE] will paste the top item from the clipboard (what has just been copied, possibly from another application).  If the system supports a clipboard UI this can be displayed by pressing the [CLIPBOARD] button.
+
+Empty text means the user has not inputted any text, a text-control containing special characters or purely whitespace is not empty.
+
+Below shows how the popup will look depending on the state of the text-control.
+
+|  |  |
+|--|--|
+| Condition: Long press/double tap when empty text but clipboard has content  |  Condition: Long press/double tap when text-control contains text |
+|[PASTE][CLIPBOARD] buttons shown| [CUT][COPY], [SELECT ALL] unless all text selected and [PASTE][CLIPBOARD] if content to paste. |
+|    ![ ](./EmptyTextClipboardHasContent.png) |  ![ ](./SelectingText.png) |
+| Condition: Long press/double tap popup when text-control contains just whitespace | Condition: Empty text & clipboard empty |
+| Whitespace treated as regular text, [CUT][COPY] shown and [PASTE][CLIPBOARD] if content to paste. As all text is selected there is no need for [SELECT ALL] |  No popup shown after long press/double tap|
+|  ![ ](./SelectAllWhitespace.png) | ![ ](./EmptyTextAndNoContentToPaste.png)|
+| Condition: Long press/(double tap) on whitespace which is following text | Condition: Tapping text or panning grab handle |
+| [PASTE][CLIPBOARD] shown if something to paste. [SELECT ALL] as more text to select | If content in clipboard [PASTE][CLIPBOARD] popup will be shown. |
+| ![ ](./SelectWhitespaceAfterText.png) | ![ ](./TapAfterCopyingText.png) |
+
+
+*/
diff --git a/docs/content/programming-guide/creating-custom-controls.md b/docs/content/programming-guide/creating-custom-controls.md
new file mode 100644 (file)
index 0000000..da7e857
--- /dev/null
@@ -0,0 +1,497 @@
+<!--
+/**-->
+
+[TOC]
+
+# Creating Custom UI Controls {#creating-custom-controls}
+
+DALi provides the ability to create custom UI controls.
+This can be done by extending Dali::Toolkit::Control and Dali::Toolkit::Internal::Control classes.
+Custom controls are created using the [handle/body idiom](@ref handle-body-idiom) used in DALi.
+![ ](creating-custom-controls/control-handle-body.png)
+Namespaces are important
++ The handle & body classes should have the same name but in different namespaces
++ TypeRegistry relies on this convention
++ Here our custom control requires
+  + MyUIControl
+  + Internal::MyUIControl
+### General Guidelines:
++ Try to avoid adding C++ APIs as they become difficult to maintain.
+  + Use **properties** as much as possible as Controls should be data driven.
+  + These controls will be used through JSON files so need to be compatible.
++ Bear in mind that the Control can be updated when the properties change (e.g. style change)
+  + Ensure control deals with these property changes gracefully
+  + Not just the first time they are set
++ Use Visuals rather than creating several child Actors
+  + DALi rendering pipeline more efficient
++ Accessibility actions should be considered when designing the Control.
++ Consider using signals if the application needs to be react to changes in the control state.
++ Use of Gestures should be preferred over analysing raw touch events
++ Check if you need to chain up to base class if overriding certain methods
+___________________________________________________________________________________________________
+
+## Rendering Content {#creating-controls-rendering-content}
+
+To render content, the required actors can be created and added to the control itself as its children.
+However, this solution is not fully optimised and means extra actors will be added, and thus, need to be processed by DALi.
+Controls should be as generic as possible so the recommendation is to re-use visuals to create the content required as described in the [Visuals](@ref visuals) section.
+Currently, this is devel-api though, so is subject to change.
+![ ](creating-custom-controls/rendering.png)
+
+To add a visual to a control, first create a Property for the visual of type MAP, and ensure the name has a suffix of "_VISUAL". Then the visual is normally defined in the stylesheet, and the definition sent via SetProperty(), where you would then create the visual:
+
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value )
+{
+  MyUIControl control = MyUIControl::DownCast( Dali::BaseHandle( object ) );
+  switch( index )
+  {
+    case MyUIControl::Property::MY_VISUAL:
+    {
+      Toolkit::VisualFactory visualFactory = Toolkit::VisualFactory::Get();
+      const Property::Map *map = value.GetMap();
+      if( map && !map->Empty() )
+      {
+        Toolkit::Visual::Base visual = visualFactory.CreateVisual( *map );
+        GetImplementation( control ).RegisterVisual( index, visual );
+      }
+      break;
+    }
+    //...
+  }
+}
+~~~
+
+The [Visuals](@ref visuals) section describes the property maps that can be used for each visual type.
+
+___________________________________________________________________________________________________
+
+## Ensuring Control is Stylable {#creating-controls-stylable}
+
+DALi's property system allows custom controls to be easily styled.
+The [JSON Syntax](@ref script-json-specification) is used in the stylesheets:
+**JSON Styling Syntax Example:**
+~~~
+{
+  "styles":
+  {
+    "textfield":
+    {
+      "pointSize":18,
+      "primaryCursorColor":[0.0,0.72,0.9,1.0],
+      "secondaryCursorColor":[0.0,0.72,0.9,1.0],
+      "cursorWidth":1,
+      "selectionHighlightColor":[0.75,0.96,1.0,1.0],
+      "grabHandleImage" : "{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png",
+      "selectionHandleImageLeft" : {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png" },
+      "selectionHandleImageRight": {"filename":"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png" }
+    }
+  }
+}
+~~~
+Styling gives the UI designer the ability to change the look and feel of the control without any code changes.
+| Normal Style | Customized Style |
+|:------------:|:----------------:|
+|![ ](creating-custom-controls/popup-normal.png) | ![ ](creating-custom-controls/popup-styled.png)|
+More information regarding styling can be found in the [Styling](@ref styling) section.
+___________________________________________________________________________________________________
+
+### Type Registration {#creating-controls-type-registration}
+
+The TypeRegistry is used to register your custom control.
+This allows the creation of the control via a JSON file, as well as registering properties, signals and actions.
+To ensure your control is stylable, the process described in [Type Registration](@ref type-registration) should be followed.
+
+#### Properties
+To aid development, some macros are provided for registering properties which are described in the [Property](@ref properties) section.
+Control properties can be one of three types:
+ + **Event-side only:** A function is called to set this property or to retrieve the value of this property.
+                        Usually, the value is stored as a member parameter of the Impl class.
+                        Other operations can also be done, as required, in this called function.
+ + **Animatable Properties:** These are double-buffered properties that can be animated.
+ + **Custom Properties:** These are dynamic properties that are created for every single instance of the control.
+                          Therefore, these tend to take a lot of memory and are usually used by applications or other controls to dynamically set certain attributes on their children.
+                          The index for these properties can also be different for every instance.
+Careful consideration must be taken when choosing which property type to use for the properties of the custom control.
+For example, an Animatable property type can be animated but requires a lot more resources (both in its execution and memory footprint) compared to an event-side only property.
+___________________________________________________________________________________________________
+
+## Control Services {#creating-controls-control-services}
+
+### Initialization {#creating-controls-init}
+
+Controls are initialized in two steps: in the constructor, and then in the Initialize() method.
+This is so that a handle/body connection is made within DALi Core.
+See Dali::CustomActor & Dali::CustomActorImpl for more information.
+It is recommended to do provide a New() method in the custom control implementation where the Initialize() method should be called.
+
+~~~{.cpp}
+// C++
+MyUIControl Internal::MyUIControl::New()
+{
+  // Create the implementation, temporarily owned on stack
+  IntrusivePtr< Internal::MyUIControl > controlImpl = new Internal::MyUIControl;
+
+  // Pass ownership to handle
+  MyUIControl handle( *controlImpl );
+
+  // Second-phase init of the implementation
+  controlImpl->Initialize();
+
+  return handle;
+}
+~~~
+Another advantage of using a New() method is that the constructor for MyUIControl can be made private (or protected).
+This will trigger the Dali::Toolkit::Internal::Control Initialize() method which will in-turn, call the virtual method OnInitialize().
+This should be overridden by the custom ui control.
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnInitialize()
+{
+  // Create visuals using the VisualFactory, register events etc.
+  // Register any created visuals with Control base class
+}
+~~~
+___________________________________________________________________________________________________
+
+### Control Behaviour {#creating-controls-behaviour}
+
+Dali::Toolkit::Internal::Control provides several behaviours which are specified through its constructor (@ref Dali::Toolkit::Internal::Control::Control()).
+| Behaviour                            | Description                                                                                                    |
+|--------------------------------------|----------------------------------------------------------------------------------------------------------------|
+| CONTROL_BEHAVIOUR_DEFAULT              | Default behavior (size negotiation is on, style change is monitored, event callbacks are not called.                                      |
+| DISABLE_SIZE_NEGOTIATION             | If our control does not need size negotiation, i.e. control will be skipped by the size negotiation algorithm. |
+| REQUIRES_HOVER_EVENTS                | If our control requires [hover events](@ref creating-controls-events).                                         |
+| REQUIRES_WHEEL_EVENTS                | If our control requires [wheel events](@ref creating-controls-events).                                         |
+| DISABLE_STYLE_CHANGE_SIGNALS         | True if control should not monitor style change signals such as Theme/Font change.                                         |
+| REQUIRES_KEYBOARD_NAVIGATION_SUPPORT | True if need to support keyboard navigation.                                                                   |
+___________________________________________________________________________________________________
+
+### Touch, Hover & Wheel Events {#creating-controls-events}
+
++ A **touch** is when any touch occurs within the bounds of the custom actor. Connect to Dali::Actor::TouchSignal().
++ A **hover event** is when a pointer moves within the bounds of a custom actor (e.g. mouse pointer or hover pointer).
++ A **wheel event** is when the mouse wheel (or similar) is moved while hovering over an actor (via a mouse pointer or hover pointer).
+If the control needs to utilize hover and wheel events, then the correct behaviour flag should be used when constructing the control and then the appropriate method should be overridden.
+~~~{.cpp}
+// C++
+bool Internal::MyUIControl::OnHoverEvent( const HoverEvent& event )
+{
+  bool consumed = false;
+
+  // Handle hover event
+
+  // Return true if handled/consumed, false otherwise
+  return consumed;
+}
+~~~
+~~~{.cpp}
+// C++
+bool Internal::MyUIControl::OnWheelEvent( const WheelEvent& event )
+{
+  bool consumed = false;
+
+  // Handle wheel event
+
+  // Return true if handled/consumed, false otherwise
+  return consumed;
+}
+~~~
+___________________________________________________________________________________________________
+
+### Gestures {#creating-controls-gestures}
+
+DALi has a gesture system which analyses a stream of touch events and attempts to determine the intention of the user.
+The following gesture detectors are provided:
+ + **Pan:** When the user starts panning (or dragging) one or more fingers.
+            The panning should start from within the bounds of the control.
+ + **Pinch:** Detects when two touch points move towards or away from each other.
+              The center point of the pinch should be within the bounds of the control.
+ + **Tap:** When the user taps within the bounds of the control.
+ + **LongPress:** When the user presses and holds on a certain point within the bounds of a control.
+The control base class provides basic set up to detect these gestures.
+If any of these detectors are required then this can be specified in the OnInitialize() method (or as required).
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnInitialize()
+{
+  // Only enable pan gesture detection
+  EnableGestureDetection( Gesture::Pan );
+
+  // Or if several gestures are required
+  EnableGestureDetection( Gesture::Type( Gesture::Pinch | Gesture::Tap | Gesture::LongPress ) );
+}
+~~~
+The above snippet of code will only enable the default gesture detection for each type.
+If customization of the gesture detection is required, then the gesture-detector can be retrieved and set up accordingly in the same method.
+~~~{.cpp}
+// C++
+PanGestureDetector panGestureDetector = GetPanGestureDetector();
+panGestureDetector.AddDirection( PanGestureDetector::DIRECTION_VERTICAL );
+~~~
+Finally, the appropriate method should be overridden:
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnPan( const PanGesture& pan )
+{
+  // Handle pan-gesture
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnPinch( const PinchGesture& pinch )
+{
+  // Handle pinch-event
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnTap( const TapGesture& tap )
+{
+  // Handle tap-gesture
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnLongPress( const LongPressGesture& longPress )
+{
+  // Handle long-press-gesture
+}
+~~~
+___________________________________________________________________________________________________
+
+### Accessibility {#creating-controls-accessibility}
+
+Accessibility is functionality that has been designed to aid usage by the visually impaired.
+More information can be found in the [Accessibility](@ref accessibility) section.
+Accessibility behaviour can be customized in the control by overriding certain virtual methods.
+This is detailed [here](@ref accessibilitycustomcontrol).
+___________________________________________________________________________________________________
+
+### Signals {#creating-controls-signals}
+
+If applications need to react to changes in the control state, controls can inform those applications using Dali::Signal.
+
+First, create a signature of the function the signal will call in the handle header file:
+~~~{.cpp}
+// C++: my-ui-control.h
+typedef Signal< void () > SignalType;
+~~~
+Then Create methods to get to the signal:
+~~~{.cpp}
+// C++: my-ui-control.h
+MyUIControl::SignalType& MyCustomSignal();
+~~~
+
+The source file should just call the impl:
+~~~{.cpp}
+// C++: my-ui-control.cpp
+MyUIControl::SignalType& MyUIControl::MyCustomSignal()
+{
+  return Dali::Toolkit::GetImplementation( *this ).MyCustomSignal();
+}
+~~~
+In the impl file, create an instance of the signal as follows and return it in the appropriate method:
+~~~{.cpp}
+// C++: my-ui-control-impl.h
+public:
+
+  MyUIControl::SignalType MyUIControl::MyCustomSignal()
+  {
+    return mMyCustomSignal;
+  }
+
+private:
+
+  MyUIControl::SignalType mMyCustomSignal;
+~~~
+Then, when you wish to emit this signal:
+~~~{.cpp}
+// C++: my-ui-control-impl.cpp
+mMyCustomSignal.Emit();
+~~~
+There is no need to check if there is anything connected to this signal as this is done by the framework.
+The application can then connect to the signal as follows:
+~~~{.cpp}
+void AppFunction()
+{
+  // Do Something
+}
+
+...
+
+customControl.MyCustomSignal.Connect( this, &AppFunction );
+~~~
+___________________________________________________________________________________________________
+
+### Children Added/Removed {#creating-controls-children}
+
+Methods are provided that can be overridden if notification is required when a child is added or removed from our control.
+An up call to the Control class is necessary if these methods are overridden.
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnChildAdd( Actor& child );
+{
+  // Do any other operations required upon child addition
+
+  // Up call to Control at the end
+  Control::OnChildAdd( child );
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnChildRemove( Actor& child );
+{
+  // Do any other operations required upon child removal
+
+  // Up call to Control at the end
+  Control::OnChildRemove( child );
+}
+~~~
+Avoid adding or removing the child again within these methods.
+___________________________________________________________________________________________________
+
+### Stage Connection {#creating-controls-stage}
+
+Methods are provided that can be overridden if notification is required when our control is connected to or disconnected from the stage.
+An up call to the Control class is necessary if these methods are overridden.
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnStageConnection( int depth )
+{
+  // Do any other operations required upon stage connection
+
+  // Up call to Control at the end
+  Control::OnStageConnection( depth );
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnStageDisconnection()
+{
+  // Do any other operations required upon stage disconnection
+
+  // Up call to Control at the end
+  Control::OnStageDisconnection();
+}
+~~~
+___________________________________________________________________________________________________
+
+### Size Negotiation {#creating-controls-size-negotiation}
+
+The following methods must be overridden for size negotiation to work correctly with a custom control.
+~~~{.cpp}
+// C++
+Vector3 Internal::MyUIControl::GetNaturalSize()
+{
+  // Return the natural size of the control
+  // This depends on our layout
+  // If we have one visual, then we can return the natural size of that
+  // If we have more visuals, then we need to calculate their positions within our control and work out the overall size we would like our control to be
+
+  // After working out the natural size of visuals that belong to this control,
+  // should also chain up to ensure other visuals belonging to the base class are
+  // also taken into account:
+  Vector2 baseSize = Control::GetNaturalSize(); // returns the size of the background.
+}
+~~~
+~~~{.cpp}
+// C++
+float Internal::MyUIControl::GetHeightForWidth( float width )
+{
+  // Called by the size negotiation algorithm if we have a fixed width
+  // We should calculate the height we would like our control to be for that width
+
+  // Should also chain up to determine the base class's preferred height:
+  float baseHeight = Control::GetHeightForWidth( width );
+
+}
+~~~
+~~~{.cpp}
+// C++
+float Internal::MyUIControl::GetWidthForHeight( float height )
+{
+  // Called by the size negotiation algorithm if we have a fixed height
+  // We should calculate the width we would like our control to be for that height
+
+  // Should also chain up to determine the base class's preferred width:
+  float baseWidth = Control::GetWidth( height );
+}
+~~~
+~~~{.cpp}
+// C++
+void Internal::MyUIControl::OnRelayout( const Vector2& size, RelayoutContainer& container )
+{
+  // The size is what we have been given and what our control needs to fit into
+  // Here, we need to set the position and the size of our visuals
+  // If we have other controls/actors as children
+  //  - Add the control/actor to the container paired with the size required
+  //  - To ensure this works, you need to set up the control with a relayout policy of USE_ASSIGNED_SIZE
+  //  - DO NOT CALL SetSize on this control: This will trigger another size negotiation calculation
+  // DO NOT chain up to base class.
+}
+~~~
+More information on size negotiation can be found [here](@ref size-negotiation-controls).
+___________________________________________________________________________________________________
+
+### Clipping Support {#creating-controls-clipping}
+
+When an Actor is set to clip its children, the renderers have to be added manually in order to specify what its children need to clip to.
+The Control base class automates the creation of the visuals when it is set to clip its children.
+This is only done if the application or custom control writer has not
+added any Renderers to the Control or registered any visuals
+(regardless of whether these visuals are enabled or not).
+If custom control writers want to define the clipping visuals themselves, then they should register all required visuals before the control is staged.
+___________________________________________________________________________________________________
+
+### Other Features {#creating-controls-other}
+
+ + [Background](@ref background)
+___________________________________________________________________________________________________
+
+
+*/
diff --git a/docs/content/programming-guide/dali-application.h b/docs/content/programming-guide/dali-application.h
new file mode 100644 (file)
index 0000000..acd37f8
--- /dev/null
@@ -0,0 +1,67 @@
+/*! \page dali-application DALi Application
+ *
+<h2 class="pg">Creating an Application</h2>
+
+The Adaptor framework provides provides a Dali::Application class which initialises and sets up DALi appropriately so that the application writer does not have to.
+This provides many platform related services.
+
+Several signals can be connected to so that the application writer is informed when certain platform related activities occur.
+It also ensures that, upon system events, DALi is called in a thread-safe manner.
+
+The following example shows how to create a Dali::Application instance and connect to its initialise signal (which is where a Dali::Actor hierarchy should be created).
+
+@code
+void CreateProgram(Application& app)
+{
+  // Create DALi components...
+  Dali::Actor actor = Actor::New();
+  ...
+}
+
+int main (int argc, char **argv)
+{
+  Dali::Application app = Application::New(&argc, &argv);
+  app.InitSignal().Connect(&CreateProgram);
+  app.MainLoop();
+}
+@endcode
+
+Please see the Dali::Application class for other signals to which the application can connect.
+
+<h2 class="pg">Window</h2>
+DALi provides a Window class to manage drawing to a default surface. It is also responsible for drawing the Indicator bar if required. The Application class automatically creates a Window which the application author can access after the SignalInit has fired.
+
+@code
+void CreateProgram(Application& app)
+{
+  app.GetWindow().ShowIndicator(Dali::Window::VISIBLE);
+}
+
+int main (int argc, char **argv)
+{
+  Dali::Application app = Application::New(&argc, &argv);
+  app.InitSignal().Connect(&CreateProgram);
+  app.MainLoop();
+}
+@endcode
+
+<h2 class="pg">Timers</h2>
+
+Timers are also provided by the Adaptor Framework so that the application writer can execute a portion of their code periodically or just once, after a delay.  The example below shows how a Dali::Timer can be created and used:
+
+@code
+bool Tick()
+{
+  ...
+  return true; // Timer continues, i.e. this function will be called again after the specified time has elapsed.
+}
+
+...
+
+// Elsewhere
+Dali::Timer timer = Dali::Timer::New(2000); // 2 second timeout
+timer.TickSignal().Connect(&Tick);
+...
+@endcode
+
+ */
diff --git a/docs/content/programming-guide/dali-introduction.md b/docs/content/programming-guide/dali-introduction.md
new file mode 100644 (file)
index 0000000..76d31b4
--- /dev/null
@@ -0,0 +1,31 @@
+<!--
+/**-->
+
+# DALi 3D ( Dynamic Animation Library ) {#dali-introduction}
+
+DALi is a quick and easy way of allowing developers to create Rich UI Applications like:
+
+ + Image & Video galleries
+ + Music players
+ + Games
+ + Maps
+ + Homescreens / launch pads
+ + Advanced watch faces for wearable devices
+
+DALi is based on OpenGL ES 2.0 & 3.0, however it hides the complexity of
+the OpenGL API from developers and provides a clean cross-platform C++ API.
+
+## Features {#dali-features}
+
+ + Create Images & Text
+ + Create shaders using GLSL
+ + Provide multiple cameras and render targets
+ + Provides Layers to aid in 2D UI layout
+ + Easy to use Animation framework
+ + Automatic background loading of resources ( images / text / meshes )
+ + Runs all animations in a separate thread. This helps maintain 60 FPS even if a long operation is being performed holding up the main thread.
+ + Provides keyboard / touch / mouse handling
+
+![ ](screen-shot.png)
+
+*/
diff --git a/docs/content/programming-guide/debug-rendering.md b/docs/content/programming-guide/debug-rendering.md
new file mode 100644 (file)
index 0000000..023045c
--- /dev/null
@@ -0,0 +1,18 @@
+<!--
+/**-->
+
+# Debug rendering {#debugrendering}
+
+Setting DALI_DEBUG_RENDERING environment variable will enable the visual debugging.
+
+Then, every concrete visual ( ColorVisual, BorderVisual, ImageVisual, GradientVisual, etc. ) is replaced with a wireframe visual.
+The wireframe visual renders a simple quad wireframe, so that the control layout and scene structure is clearly displayed.
+
+## Example:
+~~~{.bash}
+sh-4.1$ DALI_DEBUG_RENDERING=1 /usr/apps/com.samsung.dali-demo/bin/blocks.example
+~~~
+
+![ ](debug-blocks.png)
+
+
diff --git a/docs/content/programming-guide/documentation-guide.md b/docs/content/programming-guide/documentation-guide.md
new file mode 100644 (file)
index 0000000..8227fc1
--- /dev/null
@@ -0,0 +1,45 @@
+<!--
+/**-->
+
+# Writing documentation for the DALi programming guide  {#documentationguide}
+
+For documentation, please follow these guidelines:
+
+ - Create a mark down file (.md) using GitHub Flavoured Markdown https://help.github.com/articles/github-flavored-markdown/
+ - Put it into the following folder: dali-toolkit/docs/content/programming-guide/
+ - Include code samples for C++ in the mark down.
+ - See script-overview.md overview in dali-toolkit/docs/content/programming-guide for an example
+ - For DOXYGEN to link to the mark down it currently needs a reference {hash myfile}
+  
+
+#### Images
+ Doxygen copies all images in to the same folder as the HTML generated pages so you can just reference it as follows:
+
+ ~~~
+![ ](screen-shot.png)                  // required for Doxygen
+
+The space between the brackets is the alternative text. This means you will never see a broken image symbol.
+~~~
+  
+## Example
+
+Please have a look at the numerous markdown files to see the header and footer requirements.
+
+You can add tags to your headings as follows:
+~~~{.md}
+# MyChapter {#my-chapter}
+~~~
+Which will allow you to link to this section as follows:
+~~~{.md}
+[Go To MyChapter](@ref my-chapter)
+~~~
+
+Code blocks can be enclosed within 2 blocks of 3 tildes(~).
+
+You can even specify your language type, for example:
+~~~{.md}
+~~~{.cpp}
+...
+
+
+*/
diff --git a/docs/content/programming-guide/event-system.h b/docs/content/programming-guide/event-system.h
new file mode 100644 (file)
index 0000000..98c650d
--- /dev/null
@@ -0,0 +1,85 @@
+/*! \page event-system Event Handling
+
+DALi emits several signals to an application to inform it of user actions.
+
+<h2 class="pg">Touch</h2>
+
+An application can be notified when a user interacts with the touch screen on the device by connecting to the touch signal provided by Dali::Actor.
+This signal will be emitted by DALi whenever the touch occurs within the connected actor's bounds.
+
+Each point on the screen that is currently being touched or where touch has stopped is represented by a point.
+Dali::TouchData stores information about the state of each point (down, up, motion etc.) and the co-ordinates of the touch.
+
+When a multi-touch event occurs, each point represents the points that are currently being touched or the points where touch has stopped.
+
+The following example shows how a connection to a touch event signal can be established:
+
+@code
+bool OnTouch( Dali::Actor actor, const Dali::TouchData& touch )
+{
+  bool handled = false;
+
+  switch( touch.GetPointCount() )
+  {
+    case 1: // Single touch
+      if ( touch.GetState( 0 ) == Dali::PointState::DOWN )
+      {
+        // Do action when first touches the touch screen.
+        ...
+        handled = true;
+      }
+      ...
+      break;
+
+    case 2: // Multi-touch event
+      ...
+      break;
+    ...
+  }
+
+  return handled;  // true if we have handled the touch, false otherwise
+}
+
+// Elsewhere
+Dali::Actor actor = Actor::New();
+actor.TouchSignal().Connect( &OnTouch );
+@endcode
+
+The primary touch point is the first point that the user touches.
+
+The touch signal is first emitted to the actor which is hit by the primary touch point.
+If this hit actor does not handle (consume) the event, then the event is offered to the hit actor's parent.
+Again, if the parent does not handle this event, it is then offered to its parent and so on until the stage is reached or the event is consumed.
+
+If the TouchSignal of both a parent and child are connected to, then the touch event is first offered to the child's listener.
+If it is consumed by the child's listener, then the parent will not be informed.
+
+<h2 class="pg">Gestures</h2>
+
+A Dali::GestureDetector analyses a stream of touch input and attempts to determine the intention of the user.
+An actor is attached to a gesture detector and if the detector recognises a pattern, it will emit a detected signal to the application.
+
+The following gesture detectors are currently supported in DALi:
+
+- Dali::LongPressGestureDetector - When the user presses and holds a particular point on the screen for a specified length of time.
+- Dali::PinchGestureDetector - When the user moves two fingers towards or away from each other.
+- Dali::PanGestureDetector - When the user moves one or more fingers in the same direction.
+- Dali::TapGestureDetector - When the user taps the screen.
+
+The example below shows how an application can be notified of a pinch gesture:
+
+@code
+void OnPinch( Dali::Actor actor, const Dali::PinchGesture& pinch )
+{
+  // Scale your actor according to the pinch scale
+  Vector3 newSize = actor.GetCurrentSize() * pinch.scale;
+  actor.SetSize(newSize);
+}
+
+// Elsewhere
+Dali::PinchGestureDetector detector = Dali::PinchDetector::New();
+detector.Attach( myActor );
+detector.DetectedSignal().Connect( &OnPinch );
+@endcode
+
+*/
diff --git a/docs/content/programming-guide/flex-container.md b/docs/content/programming-guide/flex-container.md
new file mode 100644 (file)
index 0000000..ab0e392
--- /dev/null
@@ -0,0 +1,464 @@
+<!--
+/**-->
+
+# Flex Container  {#flex-container}
+
+Flexbox is a CSS3 web layout model which allows responsive elements within a container, automatically arranged to different size screens or devices.
+FlexContainer implements a subset of the Flexbox spec (defined by W3C) at: https://www.w3.org/TR/css-flexbox-1/
+The flex container has the ability to alter the width and/or height of its children (i.e. flex items) to best fill the available space on any display device.
+The container expands items to fill available free space, or shrinks them to prevent overflow.
+Below is an illustration of the various directions and terms as applied to a flex container with the "flex direction" defined as "row".
+![ ](flex-container/flex-container.jpg)
+DALi supports the following subset of Flexbox properties.
+## Properties supported by flex container:
+
+ + [contentDirection](@ref content-direction)
+ + [flexDirection](@ref flex-direction)
+ + [flexWrap](@ref flex-wrap)
+ + [justifyContent](@ref justify-content)
+ + [alignItems](@ref align-items)
+ + [alignContent](@ref align-content)
+___________________________________________________________________________________________________
+
+## contentDirection {#content-direction}
+contentDirection specifies the primary direction in which content is ordered on a line.
+| LTR (left-to-right) | RTL (right-to-left) |
+|--------|--------|
+| ![ ](flex-container/content-direction-ltr.jpg) | ![ ](flex-container/content-direction-rtl.jpg) |
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| INHERIT        | Inherits the same direction from the parent |
+| LTR            | From left to right                          |
+| RTL            | From right to left                          |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::CONTENT_DIRECTION, Dali::Toolkit::FlexContainer::RTL );
+~~~
+
+___________________________________________________________________________________________________
+
+## flexDirection {#flex-direction}
+flexDirection specifies the direction of the main axis which determines the direction that flex items are laid out.
+![ ](flex-container/flex-direction.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| COLUMN         | The flex items are laid out vertically as a column                          |
+| COLUMN_REVERSE | The flex items are laid out vertically as a column, but in reverse order    |
+| ROW            | The flex items are laid out horizontally as a row                       |
+| ROW_REVERSE    | The flex items are laid out horizontally as a row, but in reverse order |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::ROW_REVERSE );
+~~~
+
+___________________________________________________________________________________________________
+
+## flexWrap {#flex-wrap}
+flexWrap specifies whether the flex items should wrap or not if there is no enough room for them on one flex line.
+![ ](flex-container/flex-wrap.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| NO_WRAP        | Flex items laid out in single line (shrunk to fit the flex container along the main axis) |
+| WRAP           | Flex items laid out in multiple lines if needed                                           |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_WRAP, Dali::Toolkit::FlexContainer::NO_WRAP );
+~~~
+
+___________________________________________________________________________________________________
+
+## justifyContent {#justify-content}
+justifyContent specifies the alignment of flex items when they do not use all available space on the main axis.
+![ ](flex-container/justify-content.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| JUSTIFY_FLEX_START      | Items are positioned at the beginning of the container                     |
+| JUSTIFY_CENTER          | Items are positioned at the center of the container                        |
+| JUSTIFY_FLEX_END        | Items are positioned at the end of the container                           |
+| JUSTIFY_SPACE_BETWEEN   | Items are positioned with equal space between the lines                    |
+| JUSTIFY_SPACE_AROUND    | Items are positioned with equal space before, between, and after the lines |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::JUSTIFY_CONTENT, Dali::Toolkit::FlexContainer::JUSTIFY_SPACE_BETWEEN );
+~~~
+
+___________________________________________________________________________________________________
+
+## alignItems {#align-items}
+alignItems specifies the alignment of flex items when they do not use all available space on the cross axis.
+![ ](flex-container/align-items.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| ALIGN_FLEX_START | Items are aligned at the beginning of the container |
+| ALIGN_CENTER     | Items are aligned at the center of the container    |
+| ALIGN_FLEX_END   | Items are aligned at the end of the container       |
+| ALIGN_STRETCH    | Items are stretched to fit the container            |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::ALIGN_ITEMS, Dali::Toolkit::FlexContainer::ALIGN_FLEX_START );
+~~~
+
+___________________________________________________________________________________________________
+
+## alignContent {#align-content}
+alignContent specifies the alignment of flex lines when they do not use all available space on the cross axis, so only works when there are multiple lines.
+![ ](flex-container/align-content.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| ALIGN_FLEX_START | Items are aligned at the beginning of the container |
+| ALIGN_CENTER     | Items are aligned at the center of the container    |
+| ALIGN_FLEX_END   | Items are aligned at the end of the container       |
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::ALIGN_CONTENT, Dali::Toolkit::FlexContainer::ALIGN_FLEX_END );
+~~~
+
+___________________________________________________________________________________________________
+
+## Custom properties supported by flex item:
+
+ + [flex](@ref flex)
+ + [alignSelf](@ref align-self)
+ + [flexMargin](@ref flex-margin)
+These non-animatable properties are registered dynamically to each child which would be added to the flex container, and once added their values can not be changed.
+When an actor is added to the flex container, these properties are checked to decide how to lay out the actor inside the flex container.
+___________________________________________________________________________________________________
+
+## flex {#flex}
+By default, the items in the flex container are not flexible. If set, this property makes the item flexible, which means the item can alter its width/height in order to receive the specified proportion of the free space in the flex container.
+If all items in the flex container use this pattern, their sizes will be proportional to the specified flex factor.
+Flex items will not shrink below their minimum size (if set using Dali::Actor::SetMinimumSize).
+![ ](flex-container/flex.jpg)
+
+### Usage
+
+Below is the example code for the items to achieve the proportion of free space as illustrated above.
+~~~{.cpp}
+// C++
+
+// Create the flex container
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+
+// Set the flex direction to lay out the items horizontally
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::ROW );
+
+// Create flex items and set the proportion
+Dali::Toolkit::Control item1 = Dali::Toolkit::Control::New();
+item1.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 1.0f );
+flexContainer.Add( item1 );
+
+Dali::Toolkit::Control item2 = Dali::Toolkit::Control::New();
+item2.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 3.0f );
+flexContainer.Add( item2 );
+
+Dali::Toolkit::Control item3 = Dali::Toolkit::Control::New();
+item3.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 1.0f );
+flexContainer.Add( item3 );
+
+Dali::Toolkit::Control item4 = Dali::Toolkit::Control::New();
+item4.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 2.0f );
+flexContainer.Add( item4 );
+
+Dali::Toolkit::Control item5 = Dali::Toolkit::Control::New();
+item5.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 1.0f );
+flexContainer.Add( item5 );
+
+~~~
+
+___________________________________________________________________________________________________
+
+## alignSelf {#align-self}
+alignSelf specifies how the item will align along the cross axis, if set, this overrides the default alignment for all items defined by the container’s [alignItems](@ref align-items) property.
+![ ](flex-container/align-self.jpg)
+The possible values for this property are:
+| Property Value | Description                                 |
+|----------------|---------------------------------------------|
+| ALIGN_AUTO       | Items inherit the same alignment from the parent by default (as specified by the container’s [alignItems](@ref align-items) property) |
+| ALIGN_FLEX_START | Items are aligned at the beginning of the container |
+| ALIGN_CENTER     | Items are aligned at the center of the container    |
+| ALIGN_FLEX_END   | Items are aligned at the end of the container       |
+| ALIGN_STRETCH    | Items are stretched to fit the container            |
+### Usage
+
+Below is the example code for the items to achieve the alignment on the cross axis as illustrated above.
+~~~{.cpp}
+// C++
+
+// Create the flex container
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+
+// Set the flex direction to lay out the items horizontally
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::ROW );
+
+// Set the items to be aligned at the beginning of the container on the cross axis by default
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::ALIGN_ITEMS, Dali::Toolkit::FlexContainer::ALIGN_FLEX_START );
+
+// Create flex items and add them to the flex container
+Dali::Toolkit::Control item1 = Dali::Toolkit::Control::New();
+item1.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::ALIGN_SELF, Dali::Toolkit::FlexContainer::ALIGN_CENTER ); // Align item1 at the center of the container
+flexContainer.Add( item1 );
+
+Dali::Toolkit::Control item2 = Dali::Toolkit::Control::New();
+flexContainer.Add( item2 ); // item2 is aligned at the beginning of the container
+
+Dali::Toolkit::Control item3 = Dali::Toolkit::Control::New();
+item3.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::ALIGN_SELF, Dali::Toolkit::FlexContainer::ALIGN_FLEX_END ); // Align item3 at the bottom of the container
+flexContainer.Add( item3 );
+
+Dali::Toolkit::Control item4 = Dali::Toolkit::Control::New();
+flexContainer.Add( item4 ); // item4 is aligned at the beginning of the container
+
+~~~
+
+___________________________________________________________________________________________________
+
+## flexMargin {#flex-margin}
+Each flex item inside the flex container is treated as a box (in CSS term) which is made up of:
+
+ + content: The content of the item.
+ + padding: The space around the content (inside the border) of the item.
+ + border: The border that goes around the padding and the content of the item.
+ + flexMargin: The space outside the border.
+![ ](flex-container/flex-margin.jpg)
+In DALi, the size of the flex item = content size + padding + border.
+flexMargin specifies the space around the flex item.
+### Usage
+
+~~~{.cpp}
+// C++
+
+// Create the flex container
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+
+// Create flex item
+Dali::Toolkit::Control item = Dali::Toolkit::Control::New();
+
+// Add the margin around the item
+item.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN, Vector4(10.0f, 10.0f, 10.0f, 10.0f) );
+
+// Add the item to the container
+flexContainer.Add( item );
+~~~
+
+___________________________________________________________________________________________________
+
+## Example of creating Flexbox layout using FlexContainer
+
+Now let's see how to create a Gallery like layout (as shown below) using FlexContainer.
+
+![ ](flex-container/flexbox-demo.jpg)
+Firstly, we create a flex container as the whole view and set its resize policy to fill its parent (i.e. the stage).
+
+~~~{.cpp}
+// C++
+
+// Create the main flex container
+Dali::Toolkit::FlexContainer flexContainer = Dali::Toolkit::FlexContainer::New();
+flexContainer.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+flexContainer.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+flexContainer.SetResizePolicy( Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS );
+flexContainer.SetBackgroundColor( Dali::Color::WHITE ); // set the background color to be white
+
+// Add it to the stage
+Dali::Stage::GetCurrent().Add( flexContainer );
+~~~
+
+We want to set the flex direction of this main container to column, as we want the toolbar and the actual content to be displayed vertically.
+~~~{.cpp}
+// C++
+
+// Display toolbar and content vertically
+flexContainer.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::COLUMN );
+~~~
+
+Now we create a flex container as the toolbar and add it to the main container. Because the flex direction in the main container is column, the toolbar will be arranged on the top of the main container.
+~~~{.cpp}
+// C++
+
+// Create the toolbar
+Dali::Toolkit::FlexContainer toolBar = Dali::Toolkit::FlexContainer::New();
+toolBar.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+toolBar.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+toolBar.SetBackgroundColor( Dali::Color::CYAN ); // Set the background color for the toolbar
+
+// Add it to the main container
+flexContainer.Add( toolBar );
+~~~
+
+We want the buttons and title to be displayed horizontally and vertically aligned to the center of the toolbar, so we set its flex direction to row and set its alignItems property to center.
+We also want the toolbar and the actual content to share the height of the main container, so that the toolbar will occupy 10 percent of the whole vertical space and the content will occupy the rest of the vertical space.
+This can be achieved by setting the flex property.
+~~~{.cpp}
+// C++
+
+toolBar.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::ROW ); // display toolbar items horizontally
+toolBar.SetProperty( Dali::Toolkit::FlexContainer::Property::ALIGN_ITEMS, Dali::Toolkit::FlexContainer::ALIGN_CENTER ); // align toolbar items vertically center
+toolBar.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 0.1f ); // 10 percent of available space in the cross axis
+~~~
+
+Then we create another flex container as the content area to display the image, and it will be displayed in the bottom of the main container.
+We want the item inside it to be horizontally and vertically centered, so that the image will always be in the center of the content area.
+
+~~~{.cpp}
+// C++
+
+// Create the content area
+Dali::Toolkit::FlexContainer content = Dali::Toolkit::FlexContainer::New();
+content.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+content.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+content.SetProperty( Dali::Toolkit::FlexContainer::Property::FLEX_DIRECTION, Dali::Toolkit::FlexContainer::ROW ); // display items horizontally
+content.SetProperty( Dali::Toolkit::FlexContainer::Property::JUSTIFY_CONTENT, Dali::Toolkit::FlexContainer::JUSTIFY_CENTER ); // align items horizontally center
+content.SetProperty( Dali::Toolkit::FlexContainer::Property::ALIGN_ITEMS, Dali::Toolkit::FlexContainer::ALIGN_CENTER ); // align items vertically center
+content.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 0.9f ); // 90 percent of available space in the cross axis
+
+// Add it to the main container
+flexContainer.Add( content );
+~~~
+
+Now we start to add items to the toolbar. The toolbar will have one button on the left, one button on the right, and a title always in the center (regardless of the screen size).
+To achieve that, we can simply make the title flexible so that it will automatically take all the available horizontal space left.
+We will also add some space around the items so that the layout looks nicer.
+~~~{.cpp}
+// C++
+
+// Add a button to the left of the toolbar
+Dali::Toolkit::PushButton prevButton = Dali::Toolkit::PushButton::New();
+prevButton.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+prevButton.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+prevButton.SetMinimumSize( Dali::Vector2( 100.0f, 60.0f ) ); // this is the minimum size the button should keep
+prevButton.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN, Dali::Vector4(10.0f, 10.0f, 10.0f, 10.0f) ); // set 10 pixel margin around the button
+toolBar.Add( prevButton );
+
+// Set the button text
+Dali::Property::Map labelMap;
+labelMap[ "text" ]      = "Prev";
+labelMap[ "textColor" ] = Dali::Color::BLACK;
+prevButton.SetProperty( Dali::Toolkit::Button::Property::LABEL, labelMap );
+
+// Add a title to the center of the toolbar
+Dali::Toolkit::TextLabel title = Dali::Toolkit::TextLabel::New( "Gallery" );
+title.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+title.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+title.SetResizePolicy( Dali::ResizePolicy::USE_NATURAL_SIZE, Dali::Dimension::ALL_DIMENSIONS );
+title.SetProperty( Dali::Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+title.SetProperty( Dali::Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
+title.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX, 1.0f ); // take all the available space left apart from the two buttons
+title.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN, Dali::Vector4(10.0f, 10.0f, 10.0f, 10.0f) ); // set 10 pixel margin around the title
+toolBar.Add( title );
+
+// Add a button to the right of the toolbar
+Dali::Toolkit::PushButton nextButton = Dali::Toolkit::PushButton::New();
+nextButton.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+nextButton.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+nextButton.SetMinimumSize( Dali::Vector2( 100.0f, 60.0f ) ); // this is the minimum size the button should keep
+nextButton.SetProperty( Dali::Toolkit::FlexContainer::ChildProperty::FLEX_MARGIN, Dali::Vector4(10.0f, 10.0f, 10.0f, 10.0f) ); // set 10 pixel margin around the button
+toolBar.Add( nextButton );
+
+// Set the button text
+labelMap[ "text" ] = "Next";
+nextButton.SetProperty( Dali::Toolkit::Button::Property::LABEL, labelMap );
+~~~
+
+This is really neat when running on devices with different size or changing from different orientation, because the toolbar will expand or shrink based on the available space and the title will always be in the center, therefore the layout of the toolbar will keep the same.
+Finally, we will add the image to the content area.
+~~~{.cpp}
+// C++
+
+// Add an image to the center of the content area
+Dali::Toolkit::ImageView imageView = Dali::Toolkit::ImageView::New( "image.jpg" );
+imageView.SetParentOrigin( Dali::ParentOrigin::TOP_LEFT );
+imageView.SetAnchorPoint( Dali::AnchorPoint::TOP_LEFT );
+content.Add( imageView );
+~~~
+
+As you can see, it is easy to make flexible containers in DALi. We can use these concepts to create responsive layouts.
+
+*/
diff --git a/docs/content/programming-guide/font-selection.md b/docs/content/programming-guide/font-selection.md
new file mode 100644 (file)
index 0000000..29e4387
--- /dev/null
@@ -0,0 +1,185 @@
+<!--
+/**-->
+
+# Font Selection {#font-selection}
+
+By default TextLabel or TextField will automatically select a suitable font from the platform.
+Typically fonts do not support all scripts, for example Latin fonts often do not provide Arabic glyphs.
+Therefore you should expect the text control to select different fonts for each script.
+
+Alternatively a font may be requested using either or all of FONT_FAMILY, FONT_STYLE, and POINT_SIZE properties:
+
+- FONT_FAMILY
+  Is a string with the font's family name. i.e. *FreeSerif*
+- FONT_STYLE
+  Is a json formatted string with the font's style. Possible *key, value* pairs are:
+  + *width* Modifies the space between glyphs. Possible values are:
+    - *ultraCondensed*
+    - *extraCondensed*
+    - *condensed*
+    - *semiCondensed*
+    - *normal*
+    - *semiExpanded*
+    - *expanded*
+    - *extraExpanded*
+    - *ultraExpanded*
+  + *weight* Modifies the thickness or darkness of the glyphs. Possible values are:
+    - *thin*
+    - *ultraLight*
+    - *extraLight*
+    - *light*
+    - *demiLight*
+    - *semiLight*
+    - *book*
+    - *normal*
+    - *regular*
+    - *medium*
+    - *demiBold*
+    - *semiBold*
+    - *bold*
+    - *ultraBold*
+    - *extraBold*
+    - *black*
+    - *heavy*
+    - *extraBlack*
+  + *slant* Whether to use italics. Usually *italic* is a different font whilst the *oblique* has been generated by slanting the *normal* one. Possible values are:
+    - *normal*
+    - *roman* Same as *normal*
+    - *italic*
+    - *oblique*
+- POINT_SIZE
+  Is a float with the font's size in points. To get the point size from pixels, could use the formula: <em>point_size = 72 * pixels / vertical_dpi</em> where <em>vertical_dpi</em> is the device's vertical resolution in dots per inch.
+
+~~~{.cpp}
+// C++
+
+label.SetProperty( TextLabel::Property::FONT_FAMILY, "FreeSerif" );
+label.SetProperty( TextLabel::Property::FONT_STYLE,
+                   Property::Map().Add( "weight", "bold" )
+                                  .Add( "slant", "italic" ) );
+label.SetProperty( TextLabel::Property::POINT_SIZE,  12.0f );
+~~~
+
+However the text control will fall-back to using the default font, if the requested font does not support the required scripts.
+
+### Font Styles
+
+Setting a font size programmatically is not ideal for applications which support multiple
+screen resolutions and platforms which support multiple logical font sizes.  Also, any
+changes to the platform font settings will override any sizes that have been programmatically
+set.
+
+A more flexible approach is to prepare various JSON stylesheets, and request a different style for each platform:
+
+~~~{.cpp}
+// C++
+StyleManager styleManager = StyleManager::Get();
+styleManager.RequestThemeChange( "example-path/example.json" );
+~~~
+
+To change the font for standard text controls, this JSON syntax can be used:
+
+~~~{.json}
+{
+  "styles":
+  {
+    "textlabel":
+    {
+      "fontFamily":"FreeSerif",
+      "fontStyle":
+      {
+        "weight":"bold",
+        "slant":"italic"
+      },
+      "pointSize":8
+    }
+  }
+}
+~~~
+
+However the same pointSize is unlikely to be suitable for all text controls in an application.
+To define custom styles for existing controls, simply set a style name for each case, and
+then provide a style override in JSON.
+
+To provide flexibility for the end user, the platform offers a mechanism to alter the logical
+font size between 0 and 4 inclusive. This logical size is mapped to a physical size using the
+stylesheets, by appending FontSizeN to the style name. These sections ("textlabelFontSizeN")
+in the style sheet are applied after the base section ("textlabel"), so take precedence.
+
+~~~{.cpp}
+  // C++
+
+  label.SetProperty( Control::Property::STYLE_NAME, "custom" );
+~~~
+~~~{.json}
+{
+  "styles":
+  {
+    "textlabel":
+    {
+      "fontFamily":"FreeSerif",
+      "fontStyle":
+      {
+        "weight":"bold",
+        "slant":"italic"
+      },
+    },
+
+    "textlabelFontSize0":
+    {
+      "pointSize":8
+    },
+    "textlabelFontSize1":
+    {
+      "pointSize":10
+    },
+    "textlabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "textlabelFontSize3":
+    {
+      "pointSize":19
+    },
+    "textlabelFontSize4":
+    {
+      "pointSize":25
+    },
+
+    "customLabel":
+    {
+      "fontFamily":"TimesNewRoman",
+      "fontStyle":
+      {
+        "weight":"regular",
+        "slant":"regular"
+      },
+    },
+    "customLabelFontSize0":
+    {
+      "pointSize":10
+    },
+    "customLabelFontSize1":
+    {
+      "pointSize":12
+    },
+    "customLabelFontSize2":
+    {
+      "pointSize":15
+    },
+    "customLabelFontSize3":
+    {
+      "pointSize":20
+    },
+    "customLabelFontSize4":
+    {
+      "pointSize":28
+    }
+  }
+}
+~~~
+
+In the example above, at platform logical text size 0, standard text labels will have pointSize 8, and custom labels will have pointSize 10.
+
+
+*/
diff --git a/docs/content/programming-guide/fundamentals.md b/docs/content/programming-guide/fundamentals.md
new file mode 100644 (file)
index 0000000..c57e2e8
--- /dev/null
@@ -0,0 +1,85 @@
+<!--
+/**-->
+
+# DALi Fundamentals  {#fundamentals}
+
+## Actors and the Stage {#actors-and-stage}
+
+Actor is the primary object with which DALi applications interact.
+A DALi application uses a hierarchy of Dali::Actor objects to position visible content.
+An actor inherits a position relative to its parent, and can be moved relative to this point.
+UI controls can be built by combining multiple actors.
+
+The Stage is a top-level object used for displaying a tree of Actors.
+To display the contents of an actor, it must be added to the Dali::Stage,
+
+The following example shows how to connect a new actor to the stage:
+
+~~~{.cpp}
+Actor actor = Actor::New();
+Stage::GetCurrent().Add(actor);
+~~~
+
+~~~{.js}
+var actor = new dali.Actor();
+dali.stage.add( actor );
+~~~
+
+## The Coordinate System {#coordinate-system}
+
+The Stage has a 2D size, which matches the size of the application window.
+The default **unit 1 is 1 pixel with default camera and** the default coordinate system in DALi has the **origin at the top-left corner, with positive X to right, and position Y going
+downwards**.  This is intended to be convenient when laying-out 2D views.
+
+![ ](coordinate-system-and-stage.png)
+
+
+## Positioning Actors {#positioning-actors}
+
+An actor inherits its parent's position.  The relative position between the actor & parent is determined by 3 properties:
+
+1) ParentOrigin.  This Vector3 property defines a point within the parent actor's area.
+
+![ ](parent-origin.png)
+
+The default is "top-left", which can be visualized in 2D as (0, 0), but is actually Vector3(0, 0, 0.5) in the 3D DALi world.  The actor's position is relative to this point.
+
+2) AnchorPoint.  This Vector3 property defines a point within the child actor's area.
+
+![ ](anchor-point.png)
+
+The default is "center", which can be visualized in 2D as (0.5, 0.5), but is actually Vector3(0.5, 0.5, 0.5) in the 3D DALi world.  The actor's position is also relative to this point.
+
+3) Position.  This is the position vector between the parent-origin and anchor-point.
+
+![ ](actor-position.png)
+
+The default is (X = 0, Y = 0), so an actor placed directly without modifying the parent origin, anchor point or position would appear centred around the top left corner of its parent.
+
+An actor added directly to the stage with position (X = stageWidth*0.5, Y = stageHeight*0.5), would appear in the center of the screen.  Likewise an actor with position (X = actorWidth*0.5, Y = actorWidth*0.5), would appear at the top-left of the screen. However, basic positioning like that is normally done via changing the parent origin and/or anchor point instead - use ParentOrigin::CENTER and AnchorPoint::CENTER to place the actor in the center of the screen, and ParentOrigin::TOP_LEFT and AnchorPoint::TOP_LEFT to place it inside the screen on the top left.
+
+Note that since DALi is a 3D toolkit, this behaviour is the result of a default perspective camera setup.
+
+## Scene Graph {#scene-graph}
+
+From Wikipedia...
+  
+A scene graph is a collection of nodes in a graph or tree structure.
+A node may have many children but often only a single parent,
+with the effect of a parent applied to all its child nodes;
+an operation performed on a group automatically propagates
+its effect to all of its members. In many programs, associating
+a geometrical transformation matrix (see also transformation and matrix)
+at each group level and concatenating such matrices together is an
+efficient and natural way to process such operations. A common feature,
+for instance, is the ability to group related shapes/objects into a
+compound object that can then be moved, transformed, selected,
+etc. as easily as a single object.
+
+### How does this relate to the DALi public API?
+
+Actors are effectively nodes that receive input (touch events) and act as a
+container for draw-able elements (which are also nodes) and other actors.
+
+
+*/
diff --git a/docs/content/programming-guide/handle-body-idiom.h b/docs/content/programming-guide/handle-body-idiom.h
new file mode 100644 (file)
index 0000000..6ea7dc7
--- /dev/null
@@ -0,0 +1,101 @@
+/*! \page handle-body-idiom Handle – body
+<h2 class="pg">What is the Handle/Body (Pimpl) pattern?</h2>
+It is a technique for hiding implementation details in the header file.
+DALi achieves it by using "handles" in the public API. These handles internally contain a reference counted pointer to the concrete implementation.
+
+<h2 class="pg">Why does Dali::Object use the Handle/Body (Pimpl) pattern?</h2>
+It provides:
+- Better encapsulation
+- Easier memory management
+
+\par Better encapsulation
+Implementation details are hidden, only the required API is visible for the application developer.
+This way the danger of API/ABI breaks is also reduced since the implementation of a class can change without modifying the public API.
+
+\par Easier memory management
+DALi objects have implicit smart-pointer semantics.
+Each Dali::Object contains a single reference counted object which can be intitialized with the static "New" methods in the DALi API.
+This means that C++ new/delete operators do not have to be used (or paired) in the user code (RAII idiom).
+Of course there's no way of stopping users from allocating heap memory, but calls to the new operator can be minimised.
+
+<h2 class="pg">What does 'implicit smart-pointer semantics' mean in the case of DALi?</h2>
+
+Since DALi objects are just handles, they can be copied by value. When a DALi object is copied, both the copy and original will point to the same DALi resource.
+The internal DALi resources are reference counted; copying a DALi object will increase the reference count. A resource will not be deleted until all its Dali::Object handles are destroyed, or reset.
+
+\code
+class AnimationTest
+{
+...
+private:
+  Animation mAnimation; // animation handle
+}
+
+void AnimationTest::Initialize ()
+{
+    mAnimation = Animation::New(10.0f); // ref.count will be 1, animation object stays alive when method returns
+    ...
+}
+
+void AnimationTest::SetAnimation (Animation anim)
+{
+    mAnimation = anim; // ref.count of original animation decreased, 'anim' is referenced instead
+                       // if nobody else had a reference on the initial animation, the object is destroyed
+}
+\endcode
+
+In some cases an internal resource may be referenced by other internal objects.
+A common example is when an actor is added to a container with Dali::Actor::Add() i.e. the container will reference its child.
+
+\code
+// At this point we own a Dali::Actor named "container"
+// Enter a code block
+{
+  // Create an image view
+  Actor actor = Toolkit::ImageView::New(SomeImageFile);
+
+  // Add the image actor to a container
+  container.Add(actor);
+}
+// Exit the code block
+// At this stage the image actor is still alive
+// We don't keep a Dali::Object handle to the image actor, but it can be retrieved from the container
+\endcode
+
+Objects can be implicitly converted to pointer-to-member type for validity checks.
+\code
+// Enter a code block
+{
+  // Create a NULL object
+  Object object;
+  // At this stage we cannot call any of the objects methods
+
+  if (!object) // This test is will pass, since the object is NULL
+  {
+    object = SomeClass::New();
+    ...
+  }
+  ...
+}
+\endcode
+
+Objects can be compared, this actually checks if the handles point to the same resource or not.
+\code
+void AnimationTest::SetAnimation (Animation anim)
+{
+  if (anim != mAnimation)
+  {
+    mAnimation = anim;  // ref.count of original animation decremented (if valid), anim's reference count is increased
+    ...
+  }
+}
+\endcode
+
+To sum up implicit pointer semantics, Objects can be:
+- compared
+- passed by value; this increases the reference count
+- tested as a boolean value
+- used directly as member data
+- returned from functions
+
+*/
diff --git a/docs/content/programming-guide/hello-world.h b/docs/content/programming-guide/hello-world.h
new file mode 100644 (file)
index 0000000..780ad3e
--- /dev/null
@@ -0,0 +1,133 @@
+/*! \page hello-world Hello World - explained
+
+The following steps are required for displaying the sentence 'Hello World' with DALi:
+
+- initialize the DALi library
+- create an Actor showing text
+- add it to the Stage
+
+To understand the basic building blocks of the UI make sure to read the chapter on \link fundamentals DALi Fundamentals\endlink first.
+
+Let's take a look at the code for this test application.
+
+<h2 class="pg"> Example code </h2>
+\code
+
+#include <dali-toolkit/dali-toolkit.h>
+
+using namespace Dali;
+using Dali::Toolkit::TextLabel;
+
+// This example shows how to create and display Hello World! using a simple TextActor
+//
+class HelloWorldController : public ConnectionTracker
+{
+public:
+
+  HelloWorldController( Application& application )
+  : mApplication( application )
+  {
+    // Connect to the Application's Init signal
+    mApplication.InitSignal().Connect( this, &HelloWorldController::Create );
+  }
+
+  ~HelloWorldController()
+  {
+    // Remove Hello World actor from stage
+    Stage::GetCurrent().Remove(mTextLabel);
+  }
+
+  // The Init signal is received once (only) during the Application lifetime
+  void Create( Application& application )
+  {
+    // Get a handle to the stage
+    Stage stage = Stage::GetCurrent();
+
+    mTextLabel = TextLabel::New( "Hello World" );
+    mTextLabel.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+    stage.Add( mTextLabel );
+
+    // Respond to a click anywhere on the stage
+    stage.GetRootLayer().TouchSignal().Connect( this, &HelloWorldController::OnTouch );
+  }
+
+  bool OnTouch( Actor actor, const TouchData& touch )
+  {
+    // quit the application
+    mApplication.Quit();
+    return true;
+  }
+
+private:
+  Application&  mApplication;
+  TextLabel mTextLabel;
+};
+
+void RunTest( Application& application )
+{
+  HelloWorldController test( application );
+
+  application.MainLoop();
+}
+
+// Entry point for Linux & Tizen applications
+//
+int main( int argc, char **argv )
+{
+  Application application = Application::New( &argc, &argv );
+
+  RunTest( application );
+
+  return 0;
+}
+
+\endcode
+
+ There are a couple of steps which are very important to understand.
+
+ <h2 class="pg"> Initializing DALi </h2>
+ The application should not use the DALi library until it has sent the init complete signal!
+ That's why we connect our ExampleApp::Create callback to Dali::Application's SignalInit signal:
+ \code
+   ...
+   app.SignalInit().Connect(this, &ExampleApp::Create);
+   ...
+ \endcode
+
+ <h2 class="pg"> Reference counting </h2>
+ The application should store Actors' and resources' handles.
+ DALi objects are reference counted, which makes sure they exist only as long as they are needed.
+ That's why we store the Actor's handle:
+ \code
+   ...
+   mTextLabel = TextLabel::New("Hello World");
+   ...
+ \endcode
+ Even if the TextLabel is removed from the stage, it will be kept alive through our reference.\n
+ You can read more about implicit smart-pointer semantics in chapter \link handle-body-idiom Handle – body\endlink.
+
+ <h2 class="pg"> Main loop </h2>
+ To 'run' the application, it's main loop should be started.
+ This ensures that images are displayed, events, signals are dispatched and captured and so on.
+ \code
+   ...
+   daliApp.MainLoop();
+   ...
+ \endcode
+ \n \n
+ On X11 platform you can compile the above example with:
+ \code
+ g++ `pkg-config --libs --cflags dali` hello-dali.cpp -o hello
+ \endcode
+
+ After running './hello' this should be visible on the screen:
+
+<table border=0 cellpadding=10>
+<tr>
+  <td>
+  \image html Text-Label.png "Hello world example"
+  </td>
+</tr>
+</table>
+
+*/
diff --git a/docs/content/programming-guide/high-level-design.md b/docs/content/programming-guide/high-level-design.md
new file mode 100644 (file)
index 0000000..05994bd
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+/**-->
+
+# High Level Design {#dali-hld}
+
+## Components {#dali-components}
+
+ + **DALi Core:** Event handling, Scene Graph, Rendering, Resource Management
+ + **DALi Adaptor:** Threading Model, Integration with the main loop.
+ + **DALi Platform Abstraction:** Resource loading & decoding in multiple threads (part of dali-adaptor)
+ + **DALi Toolkit:** Reusable UI Controls, Effects & Scripting Support
+
+![ ](architecture.png)
+
+## Main, Update & Render Threads {#dali-threads}
+
+DALi uses a multithreaded architecture in order to provide the best performance and scalability.
+
+ + **Event Thread:** The main thread in which application code and event handling runs.
+ + **Update Thread:** Updates the nodes on the scene as well as running animations & constraints
+ + **Render Thread:** OpenGL drawing, texture and geometry uploading etc.
+ + **Resource Threads:** Loads images and decodes into bitmaps etc.
+
+![ ](dali-threads.png)
+
+*/
diff --git a/docs/content/programming-guide/image-view.h b/docs/content/programming-guide/image-view.h
new file mode 100644 (file)
index 0000000..9960a3e
--- /dev/null
@@ -0,0 +1,118 @@
+/*! \page image-view Image Views
+ *
+ *
+ * <h1 class="pg">Overview</h1>
+ * The Dali::Toolkit::ImageView inherits from Dali::Toolkit::Control and provide means to display resources like Images on the stage.<br>
+ *
+ * - <b>ImageView:</b> An actor for displaying Images. It allows the developer to display a Dali::Image object or an image from a url path on the stage.<br>
+ *
+ * <h1 class="pg">Image View</h1>
+ *
+ * <h2 class="pg">Construction</h2>
+ * The Image View is constructed by passing a Dali::Image object or by a url path.<br>
+ *
+ * <h3 class="pg">Loading from a url path</h3>
+ * Image View will load a file from a given url path. Using a url path is the prefered way of displaying an image as the DALi engine can do optimisations to
+ * reuse shaders and perform automatic image atlassing.<br>
+ * This can be a path to a image file:
+ * @code
+ * Dali::Toolkit::ImageView myImageView = ImageView::New( "source-image-url.png" );
+ * @endcode
+ *
+ * A path to a nine-patch/n-patch image file:
+ * @code
+ * Dali::Toolkit::ImageView myImageView = ImageView::New( "source-image-url.9.png" );
+ * @endcode
+ *
+ * A path to a svg image file:
+ * @code
+ * Dali::Toolkit::ImageView myImageView = ImageView::New( "source-image-url.svg" );
+ * @endcode
+ *
+ * <h3 class="pg">Loading from a Image handle</h3>
+ * Dali::Image is an abstract base class with multiple derived classes.
+ *
+ * @code
+ * Dali::Image image = BufferImage::New( 100, 100 );
+ * Dali::Toolkit::ImageView myImageView = Toolkit::ImageView::New( image );
+ * @endcode
+ *
+ * <h3 class="pg">The IMAGE property</h3>
+ * the IMAGE property allows you to change many aspects of the image that is rendered.
+ * This property can either be a string for a image url path or a Property::Map that specifies
+ * the image in more detail.
+ *
+ * <h3 class="pg">Visuals</h3>
+ * You can specify a specific visual instead of using the default Image Visual, e.g to use the Border Visual.
+ *
+ * @code
+ * Property::Map visual;
+ * visual.Insert( Visual::Property::Type,Visual::BORDER );
+ * visual.Insert( BorderVisual::Property::COLOR, COLOR::RED );
+ * visual.Insert( BorderVisual::Property::SIZE, 20.f );
+ *
+ * Dali::Toolkit::ImageView myImageView = Dali::Toolkit::ImageView::New();
+ * myImageView.SetProperty( Control::Property::IMAGE, visual );
+ * @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
+ * Property::Map imageProperty;
+ * 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);
+
+ * @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> "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
+ * <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 or as a nine-patch/n-patch image. This is done by using a nine-patch filename naming scheme of ending with
+ * a ".9" or a ".#". There is no special treatment if the file encodes a nine-patch image or n-patch image as long as it has either ".9" or ".#" the image will be correctly loaded.<br>
+ * @code
+ * Dali::Toolkit::ImageView myImageView1 = Dali::Toolkit::ImageView::New("source-to-nine-patch-image.9.png");
+ * Dali::Toolkit::ImageView myImageView2 = Dali::Toolkit::ImageView::New("source-to-nine-patch-image.#.png");
+ * @endcode
+ *
+ * <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
+ * myImageView.SetImage( newImage );
+ * @endcode
+ *
+ */
diff --git a/docs/content/programming-guide/input-style.md b/docs/content/programming-guide/input-style.md
new file mode 100644 (file)
index 0000000..f37f126
--- /dev/null
@@ -0,0 +1,17 @@
+<!--
+/**-->
+
+# Input Style {#input-style}
+
+The input style can be changed through the control properties. All subsequent characters added will be rendered with the new input style.
+
+Note the input style may change if the cursor is updated by tapping in a new position.
+
+Current supported input style properties are:
+
+- *INPUT_COLOR* Sets the input color. The property expects a Vector4 with the red, green, blue and alpha values clamped between 0 and 1.
+- *INPUT_FONT_FAMILY* Sets the input font's family name. The property expects the name of the font. If the new text is not supported by the given font a suitable one will be set.
+- *INPUT_FONT_STYLE* Sets the input font's style. The property expects a json formatted string with the font's style. See the [Font Selection](@ref font-selection) section for more details.
+- *INPUT_POINT_SIZE* Sets the input font's size. The property expects a float with the font's size in points. See the [Font Selection](@ref font-selection) section for more details.
+
+*/
diff --git a/docs/content/programming-guide/item-view.md b/docs/content/programming-guide/item-view.md
new file mode 100644 (file)
index 0000000..0242d19
--- /dev/null
@@ -0,0 +1,81 @@
+<!--
+/**-->
+
+# Item View {#item-view}
+
+An Item view is a scrollable container that contains several items.
+It can have several layouts.
+There are a few built-in layouts that the application writer can use:
+
+|GRID                    |SPIRAL                    |DEPTH                    |
+|:----------------------:|:------------------------:|:-----------------------:|
+|![ ](item-view/grid.png)|![ ](item-view/spiral.png)|![ ](item-view/depth.png)|
+
+The application writer can also create their own custom layout by inheriting from Dali::Toolkit::ItemLayout.
+
+## Item Factory
+
+To create an item-view, the application writer has to provide an item-factory.
+An ItemFactory provides methods to create items and how many items there are among other things.
+
+~~~{.cpp}
+class MyFactory : public Dali::Toolkit::ItemFactory
+{
+public:
+  virtual unsigned int GetNumberOfItems()
+  {
+    // Should return the number of items
+    return MY_ITEM_COUNT;
+  }
+
+  virtual Actor NewItem( unsigned int itemId )
+  {
+    // We should create the actor here that represents our item based on the itemId given.
+
+    // 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
+
+    // Create the Image View from the image and return
+    return Dali::Toolkit::ImageView::New( imageName.str() );
+  }
+};
+~~~
+These overridden methods in our factory will be called by the Item View.
+
+## Creating an ItemView
+
+~~~{.cpp}
+MyFactory factory; // Should store this as a member variable
+Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::New( factory ); // Pass in our factory
+itemView.SetParentOrigin( ParentOrigin::CENTER );
+itemView.SetAnchorPoint( AnchorPoint::CENTER );
+
+// Now create a layout
+Dali::Toolkit::ItemLayoutPtr spiralLayout = Dali::Toolkit::DefaultItemLayout::New( Dali::Toolkit::DefaultItemLayout::SPIRAL );
+
+// ... and add the layout to the item view
+itemView.AddLayout( spiralLayout );
+
+// More layouts can be created and added to the item-view
+
+// Activate the layout
+itemView.ActivateLayout(
+  0,                                   // The layout ID matches the order in which layouts are added
+  Dali::Stage::GetCurrent().GetSize(), // Use the stage's size as our item-view size
+  0 );                                 // We want the item-view to appear straight away
+
+// And add to the stage
+Dali::Stage::GetCurrent().Add( itemView );
+~~~
+
+## Actions
+The item-view provides an action to stop the scroll animation if desired.
+
+~~~{.cpp}
+Property::Map attributes;
+itemView.DoAction( "stopScrolling", attributes );
+~~~
+
+
+*/
\ No newline at end of file
diff --git a/docs/content/programming-guide/layer.md b/docs/content/programming-guide/layer.md
new file mode 100644 (file)
index 0000000..a9627d5
--- /dev/null
@@ -0,0 +1,193 @@
+<!--
+/**-->
+# Layer ( Layer inherits from Actor) {#layer}
+
+ Layers provide a mechanism for overlaying groups of actors on top of each other.
+ Layers can also clip their contents to exclude any content outside a user defined area.
+  
+ ![ ](layers.png)
+  
+ When a layer is added to the stage it is assigned a unique depth value. By default the stage has a root layer with a depth value of 0.
+  
+ Layers are actors and inherit position, orientation and scale of their parent actor.
+ They are drawn in an order determined by a layer depth value.
+ The depth buffer is cleared before each layer is rendered, unless depth
+ test is disabled or there's no need for it based on the layers contents.
+
+**Note: Layers work independently of the actor hierarchy.**
+They can be positioned anywhere in the actor tree, but their draw order is always defined by their layer.getDepth() value.
+  
+  
+~~~{.cpp}
+// C++ example of adding an actor to the root layer
+
+//  using stage.add() will automatically add actor to the root layer
+Stage stage = Stage::GetCurrent();
+stage.add( myActor );
+
+// Or you can explicitly add actor to the root layer.
+Layer rootLayer = stage.GetRootLayer();
+rootLayer.add( myActor );  // adds an actor to the root layer
+
+// rootLayer.getDepth() == 0
+
+~~~
+
+Example To create two new layers on top of the root layer.
+  
+
+### Layer clipping
+
+Clips the contents of the layer to a rectangle.
+
+~~~{.cpp}
+// C++
+
+layer1.SetAnchorPoint( AnchorPoint::CENTER );
+layer1.SetParentOrigin( ParentOrigin::CENTER );
+layer1.SetClipping( true );
+layer1.SetClippingBox( 20, 20, 100, 100 ); // X, Y, Width, Height
+
+~~~
+
+### Re-ordering layers
+
+The following functions can be used to change the draw order of the layers.
+
+
+ - Raise() Raise the layer up by 1
+ - Lower() Lower the layer down by 1
+ - RaiseAbove( layer ) Ensures the layers depth is greater than the target layer
+ - LowerBelow( layer ) Ensures the layers depth is less than the target layer
+ - RaiseToTop() raise the layer to the top
+ - LowerToBottom() lower the layer to the bottom
+ - MoveAbove( layer ) Moves the layer directly above the given layer.
+ - MoveBelow( layer ) Moves the layer directly below the given layer.
+
+Note:
+ - The root layer can be moved above and below other layers. However, stage.add( actor ), will always use the root layer object.
+
+### Rendering order of actors inside of a layer
+
+Layers have two behaviour modes:
+
+ - LAYER_2D ( Default )
+ - LAYER_3D
+
+### Layer_2D
+
+~~~{.cpp}
+// C++
+layer.SetBehavior( Layer::LAYER_2D );
+~~~
+
+#### Background
+
+ - Graphics are drawn in DALi using renderers
+ - Actors can have zero or many renderers
+ - Renderers can be shared by actors
+ - Renderers have a depth index property
+ - In LAYER_2D mode, draw order of a renderer within a layer = Tree depth + renderer depth index
+  
+ When using  Layer_2D mode depth testing is disabled (depth buffer not used).
+  
+  With LAYER_2D, the draw order of the renderers is defined by both:
+
+ - Renderer depth index.
+ - Position of actor in the actor tree
+  
+
+Example:
+  
+We have two layers below. Everything in the root layer is drawn first.
+If we did dali.stage.getRootLayer().raiseToTop(), then the root layer would be drawn last.
+
+  
+![ ](layer2d.png)
+  
+
+The formula for calculating the draw order of a renderer is:  depthIndex + ( TREE_DEPTH_MULTIPLIER * tree depth ).
+Currently Layer::TREE_DEPTH_MULTIPLIER == 1000:
+~~~
+ Root (root layer) ( depth index offset of  0)
+ +->  Actor1    ( depth index offset of 1000)
+ ++-> Actor2    ( depth Index offset of 2000)
+ +++-> Actor3   ( depth Index offset of 3000)
+ +++-> Actor4   ( depth Index offset of 3000)
+ +++-> Actor5   ( depth Index offset of 3000)
+ +++-> Layer1   ( depth Index has no meaning for layers, layer draw order is independent of the hierarchy).
+ ++++-> Actor6   ( depth Index offset of 4000)
+ ++++-> Actor7   ( depth Index offset of 4000)
+ ++++-> Actor8   ( depth Index offset of 4000)
+~~~
+  
+Renderers with higher depth indices are rendered in front of renderers with smaller values.
+  
+Everything in the root layer gets rendered first, actors 1..5
+Then layer 1, actors 6..8
+  
+If we want to determine draw order of actors 6..8, we set the depthIndex on their renderers.
+For example if we want the render draw order to be 8, 7, 6, with 6 being drawn last.
+
+~~~{.js}
+  var rendererForActor6 = new dali.Renderer( geometry, material );
+  var rendererForActor7 = new dali.Renderer( geometry, material );
+  var rendererForActor8 = new dali.Renderer( geometry, material );
+
+  rendererForActor6.depthIndex = 2;   // drawn on top ( last)
+  rendererForActor7.depthIndex = 1;   // draw in the middle
+  rendererForActor8.depthIndex = 0;   // drawn on bottom ( first)
+
+  daliactor6.addRenderer( rendererForActor6 );  // renderer 6 drawn with index of 2 + 4000 = 4002
+  daliactor7.addRenderer( rendererForActor7 );  // renderer 7 drawn with index of 1 + 4000 = 4001
+  daliactor8.addRenderer( rendererForActor8 );  // renderer 8 drawn with depth index of 0 + 4000 = 4000
+
+~~~
+
+### Layer_3D
+
+~~~{.cpp}
+// C++
+layer.SetBehavior( Layer::LAYER_3D );
+~~~
+  
+When using this mode depth testing will be used ( depth buffer enabled ).
+  
+Opaque renderers are drawn first and write to the depth buffer.
+  
+Then transparent renderers are drawn with depth test enabled but depth write switched off.
+  
+ ![ ](layers3d.png)
+
+  
+Transparent renderers are drawn in order of distance
+from the camera ( painter's algorithm ).
+
+ ![ ](transSort.png)
+  
+
+Note:
+
+ - In LAYER_3D mode, actor tree hierarchy makes no difference to draw order
+ - When 2 transparent renderers are the same distance from the camera, you can use depth index to adjust which renderer is drawn first.
+
+  
+### Actor drawMode OVERLAY_2D
+
+Inside a layer it is possible to force a tree actors to be drawn on top everything else in the layer.
+  
+The draw order of the actors inside the tree marked OVERLAY_2D, the draw order is defined by the renderers depth index.
+Depth testing is not used.
+  
+
+### Layer Actor Specific Properties
+
+| Name                   |    Type    | Writable     | Animatable|
+|------------------------|------------|--------------|-----------|
+| clippingEnable         |BOOLEAN     | 0     |  X |
+| clippingBox            | ARRAY [0,0,400,600]) | 0 | X|
+| behaviour              | STRING ( "LAYER_2D" or "LAYER_3D") | 0 | X|
+
+  @extends Actor
+
+*/
diff --git a/docs/content/programming-guide/markup-style.md b/docs/content/programming-guide/markup-style.md
new file mode 100644 (file)
index 0000000..944a670
--- /dev/null
@@ -0,0 +1,142 @@
+<!--
+/**-->
+
+# Mark-up Style {#markup-style}
+
+Mark-up tags can be used within the text to set styles.
+
+By default the text controls don't process the mark-up string. To enable the mark-up string processing the property *ENABLE_MARKUP* must be set to *true*.
+
+~~~{.cpp}
+// C++
+
+TextField field = TextField::New();
+field.SetProperty( TextField::Property::ENABLE_MARKUP, true );
+
+Stage::GetCurrent().Add( field );
+~~~
+
+Note the mark-up processor doesn't check the correctness of the mark-up string. This may
+cause the text to be badly rendered.
+
+The table below describes the priorities when styles are applied while rendering text.
+|  |  |  |  |
+|--|--|--|--|
+| Priority 1 | Style set by markup string. | Will override the style set through the control properties. | i.e The \<color\> tag will override the *TEXT_COLOR* property. |
+| Priority 2 | Style set through the control properties. | Will override the default platform style. |  |
+| Priority 3 | Default platform style. |  |  |
+
+Font size has slightly different priorities - the size provided by the platform is a logical
+size, and can be mapped to physical point sizes using style sheets. There is a default set of
+sizes defined for DALi, and these can be overridden by application specific stylesheets. Thus
+the priorities are:
+
+|  |  |  |
+|--|--|--|
+| Priority 1 | Size set by markup string. | Will override the style set through the stylesheets. |
+| Priority 2 | Physical Size set by application style sheet | |
+| Priority 2 | Logical Size set by application style sheet | Mapping from platform logical to physical |
+| Priority 3 | Logical Size set by DALi style sheet | Mapping from platform logical to physical |
+
+See [Font Selection](@ref font-selection) for more details.
+
+Current supported tags are:
+
+## \<color\>
+
+Sets the color of the characters inside the tag. The *color* tag has a *value* attribute used to set the color. Possible values are: 'red', 'green', 'blue', 'yellow', 'magenta',
+ 'cyan', 'white', 'black' and 'transparent'. Web color and 32 bits hexadecimal 0xAARRGGBB formats are also supported.
+
+Examples below are equivalent, render the text in red. Second example codes the color in 0xAARRGGBB, third and fourth in web color with 3 and 6 characters.
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "<color value='red'>Red Text</color>" ); // Color coded with a text constant.
+~~~
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "<color value='0xFFFF0000'>Red Text</color>" ); // Color packed inside an ARGB hexadecimal value.
+~~~
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "<color value='#F00'>Red Text</color>" ); // Color packed with the web color format (3 characters).
+~~~
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "<color value='#FF0000'>Red Text</color>" ); // Color packed with the web color format (6 characters).
+~~~
+
+## \<font\>
+
+Sets the font values of the characters inside the tag.
+
+Supported attributes are:
+- *family* The name of the font.
+- *size* The size of the font in points.
+- *weight* The weight of the font.
+- *width* The width of the font
+- *slant* The slant of the font.
+
+See the [Font Selection](@ref font-selection) to have a view of the possible values for the *weight*, *width* and *slant* attributes.
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "<font family='SamsungSans' weight='bold'>Hello world</font>" );
+~~~
+
+## XHTML ENTITIES
+
+Single characters can be embedded into text using character entity references. These references have a numeric value as well as a named value.
+You can use either one of them.
+
+XHTML ENTITIES Format:
+- Named reference : "&entity_name;" (i.e. an ampersand, the entity name, and then a semi-colon).
+- Numeric reference:
+- a. Decimal reference : "&#decimal_code;" (i.e. an ampersand, a hash symbol (which signals that a number reference is coming), the character's number, and then a semi colon)
+- b. Hex reference     : "&#xhex-code;" (i.e. an ampersand, a hash symbol (which signals that a number reference is coming), x which indicates the character's number is in hex, and then a semi colon)
+
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextLabel::Property::TEXT, "Named Entity: &amp;  Numeric Entity: Decimal Entity: &#9827;  Hex Entity: &#x2660;" );
+~~~
+
+![ ](XHTML_entity.png)
+
+## SPECIAL CHARACTERS HANDLING IN MARKUP
+
+Three special characters are supported :
+- < : Less Than. It means beginning of tag.
+- > : Greater Than. It means end of tag.
+- & : Ampersand. It means beginning of XHTML Entity.
+
+> "&" usage in markup style changed from Tizen 4.0.
+"To display special character needs as regular, prepend it with two backslashes in the string."
+
+Below are some examples
+
+~~~{.cpp}
+// C++ ( Wrong usage to print text "Testing of < special character" )
+field.SetProperty( TextLabel::Property::TEXT, "Testing of < special character" );
+~~~
+
+![ ](SpecialCharacter1.png)
+
+~~~{.cpp}
+// C++ ( Wrong usage to print text "Testing of & special character" )
+field.SetProperty( TextLabel::Property::TEXT, "Testing of & special character" );
+~~~
+
+![ ](SpecialCharacter1.png)
+
+~~~{.cpp}
+// C++ ( Correct usage to print text "Testing of & < > special characters" )
+field.SetProperty( TextLabel::Property::TEXT, "Testing of \\& \\< \\> special characters" );
+~~~
+
+![ ](SpecialCharacters.png)
+
+*/
diff --git a/docs/content/programming-guide/multi-touch-guide.md b/docs/content/programming-guide/multi-touch-guide.md
new file mode 100644 (file)
index 0000000..dd583b7
--- /dev/null
@@ -0,0 +1,145 @@
+<!--
+/**-->
+
+Multi-Touch Events
+==================
+
+Touch events are received via signals.
+
+For C++ API see Dali::Actor::TouchSignal() and Dali::Actor::HoveredSignal() for more details.
+
+### Hit Testing Rules Summary:
+
+ - An actor is only hittable if the actor's touch signal has a connection.
+ - An actor is only hittable when it is between the camera's near and far planes.
+ - If an actor is made insensitive, then the actor and its children are not hittable; see Dali::Actor::IsSensitive()
+ - If an actor's visibility flag is unset, then none of its children are hittable either; see Dali::Actor::IsVisible()
+ - To be hittable, an actor must have a non-zero size.
+ - If an actor's world color is fully transparent, then it is not hittable; see GetCurrentWorldColor()
+
+### Hit Test Algorithm:
+
+ - RenderTasks
+   - Hit testing is dependent on the camera used, which is specific to each RenderTask.
+
+ - Layers
+   - For each RenderTask, hit testing starts from the top-most layer and we go through all the
+     layers until we have a hit or there are none left.
+   - Before we perform a hit test within a layer, we check if all the layer's parents are visible
+     and sensitive.
+   - If they are not, we skip hit testing the actors in that layer altogether.
+   - If a layer is set to consume all touch, then we do not check any layers behind this layer.
+
+ - Actors
+   - The final part of hit testing is performed by walking through the actor tree within a layer.
+   - The following pseudo-code shows the algorithm used:
+
+
+~~~
+ HIT-TEST-WITHIN-LAYER( ACTOR )
+ {
+   // Only hit-test the actor and its children if it is sensitive and visible
+   IF ( ACTOR-IS-SENSITIVE &&
+           ACTOR-IS-VISIBLE )
+      {
+         // Depth-first traversal within current layer, visiting parent first
+
+         // Check whether current actor should be hit-tested
+         IF ( TOUCH-SIGNAL-NOT-EMPTY &&
+             ACTOR-HAS-NON-ZERO-SIZE &&
+             ACTOR-WORLD-COLOR-IS-NOT-TRANSPARENT )
+         {
+           // Hit-test current actor
+           IF ( ACTOR-HIT )
+           {
+               IF ( ACTOR-IS-OVERLAY || ( DISTANCE-TO-ACTOR < DISTANCE-TO-LAST-HIT-ACTOR ) )
+               {
+                 // The current actor is the closest actor that was underneath the touch
+                 LAST-HIT-ACTOR = CURRENT-ACTOR
+               }
+           }
+         }
+
+       // Keep checking children, in case we hit something closer
+        FOR-EACH CHILD (in order)
+       {
+         IF ( CHILD-IS-NOT-A-LAYER )
+         {
+             // Continue traversal for this child's sub-tree
+             HIT-TEST-WITHIN-LAYER ( CHILD )
+         }
+          // else we skip hit-testing the child's sub-tree altogether
+       }
+     }
+   }
+~~~
+ - Overlays always take priority (i.e. they're considered closer) regardless of distance.
+     The overlay children take priority over their parents, and overlay siblings take priority
+     over their previous siblings (i.e. reverse of rendering order):
+
+~~~
+      1
+     / \
+    /   \
+   2     5
+  / \     \
+ /   \     \
+3     4     6
+
+Hit Priority of above Actor tree (all overlays): 1 - Lowest. 6 - Highest.
+~~~
+
+ - Stencil Actors can be used to influence the result of hits within a layer.
+     If a Stencil Actor exists on a layer and that Actor is marked visible then a successful
+     hit can only take place in the area that the stencil Actor marks as visible.
+     The hit can be in any Stencil Actor in that layer, but must be in the region of one of them.
+     Stencil Actor inheritance behaves as with rendering in that any child of a Stencil Actor will
+     also be considered a Stencil Actor.
+
+ <i>Touch Event Delivery:</i>
+
+ - Delivery
+   - The hit actor's touch signal is emitted first; if it is not consumed by any of the listeners,
+     the parent's touch signal is emitted, and so on.
+   - If there are several touch points, then the delivery is only to the first touch point's hit
+     actor (and its parents).  There will be NO touch signal delivery for the hit actors of the
+     other touch points.
+   - The local coordinates are from the top-left (0.0f, 0.0f, 0.5f) of the hit actor.
+   - The following pseudo-code shows the delivery mechanism:
+
+~~~
+  EMIT-TOUCH-SIGNAL( ACTOR )
+  {
+    IF ( TOUCH-SIGNAL-NOT-EMPTY )
+    {
+      // Only do the emission if touch signal of actor has connections.
+        CONSUMED = TOUCH-SIGNAL( TOUCH-DATA )
+    }
+
+    IF ( NOT-CONSUMED )
+    {
+        // If event is not consumed then deliver it to the parent unless we reach the root actor
+        IF ( ACTOR-PARENT )
+        {
+          EMIT-TOUCH-SIGNAL( ACTOR-PARENT )
+        }
+    }
+  }
+~~~
+ - Leave State
+   - A "Leave" state is set when the first point exits the bounds of the previous first point's
+     hit actor (primary hit actor).
+   - When this happens, the last primary hit actor's touch signal is emitted with a "Leave" state
+     (only if it requires leave signals); see the actor property leaveRequired.
+
+
+ - Interrupted State
+   - If a system event occurs which interrupts the touch processing, then the last primary hit
+     actor's touch signals are emitted with an "Interrupted" state.
+   - If the last primary hit actor, or one of its parents, is no longer touchable, then its
+     touch signals are also emitted with an "Interrupted" state.
+   - If the consumed actor on touch-down is not the same as the consumed actor on touch-up, then
+     touch signals are also emitted from the touch-down actor with an "Interrupted" state.
+
+
+*/
diff --git a/docs/content/programming-guide/performance-profiling.md b/docs/content/programming-guide/performance-profiling.md
new file mode 100644 (file)
index 0000000..9a34b3a
--- /dev/null
@@ -0,0 +1,256 @@
+<!--
+/**-->
+
+# Performance Profiling  {#performanceprofiling}
+
+
+DALi has many mechanisms for analyzing performance including kernel, system and network logging.
+
+
+## Background
+The DALi rendering pipeline has 2 stages.
+
+Each stage is typically run once per frame.
+
+- Update
+  - Run animations
+  - Run constraints
+  - Run physics
+  - Update the scene-graph
+- Render
+  - Upload 3D data using OpenGL ( textures, vertex buffers etc).
+  - Draw the scene using OpenGL
+  
+
+Update produces data - **Writes** final object positions to a buffer
+  
+Render consumes data - **Reads** object positions from a buffer and draws with OpenGL
+
+![ ](update-render.png)
+
+  
+One reason for having 2 buffers is to allow both tasks to overlap and run in parallel in certain situations.
+E.g. if rendering is taking a long time (due to a texture upload), the Update thread can start work producing
+data for the next frame. The aim being to take advantage of multi-core CPU's.
+  
+To run at a solid 60 FPS (16 milliseconds per frame), it is recommended to stay below the following times:
+  
+ - Update: 4 milliseconds
+ - Render: 4 milliseconds
+  
+This will leave enough time for the output to be composited (if the system uses a compositor) and to avoid using
+too much CPU power.
+  
+The main DALi application thread which deals with event processing is independent of the update / render threads.
+This means animations won't stop if the main thread decides to do a long operation like downloading a file from the internet.
+  
+
+## Time Stamp Logging
+
+This type of logging is used for recording individual time stamped events.
+  
+Setting DALI_PERFORMANCE_TIMESTAMP_OUTPUT environment variable will enable time stamps.
+
+Tools such as Tizen dynamic analyzer and StageHand can be used to provide a GUI display of
+the output.
+
+
+The log options are:
+
+|  Bit |  Function                | Example      |
+|------|--------------------------|--------------|
+|   0  |  log markers to DALi log (dlog on Tizen) | DALI_PERFORMANCE_TIMESTAMP_OUTPUT=1 dali-demo |
+|   1  |  log markers to kernel trace ( logs to ftrace )| DALI_PERFORMANCE_TIMESTAMP_OUTPUT=2 dali-demo |
+|   2  |  log markers to system trace ( ttrace on Tizen for Tizen analyzer) | DALI_PERFORMANCE_TIMESTAMP_OUTPUT=4 dali-demo |
+|   3  |  log markers to network client (tcp port 3001+) | DALI_PERFORMANCE_TIMESTAMP_OUTPUT=8 dali-demo |
+
+  
+
+~~~
+DALI_PERFORMANCE_TIMESTAMP_OUTPUT=1 dali-demo
+INFO: DALI: 1134155.500142 (seconds), V_SYNC
+INFO: DALI: 1134155.500167 (seconds), UPDATE_START
+INFO: DALI: 1134155.500214 (seconds), PROCESS_EVENT_END
+INFO: DALI: 1134155.500659 (seconds), UPDATE_END
+INFO: DALI: 1134155.508039 (seconds), PROCESS_EVENT_START
+INFO: DALI: 1134155.508295 (seconds), PROCESS_EVENT_END
+INFO: DALI: 1134155.511109 (seconds), RENDER_START
+INFO: DALI: 1134155.511548 (seconds), RENDER_END
+INFO: DALI: 1134155.516899 (seconds), V_SYNC
+INFO: DALI: 1134155.516945 (seconds), UPDATE_START
+INFO: DALI: 1134155.517462 (seconds), UPDATE_END
+INFO: DALI: 1134155.527884 (seconds), RENDER_START
+INFO: DALI: 1134155.528108 (seconds), PROCESS_EVENT_START
+INFO: DALI: 1134155.528327 (seconds), RENDER_END
+INFO: DALI: 1134155.528358 (seconds), PROCESS_EVENT_END
+INFO: DALI: 1134155.528388 (seconds), PROCESS_EVENT_START
+INFO: DALI: 1134155.528749 (seconds), PROCESS_EVENT_END
+INFO: DALI: 1134155.533672 (seconds), V_SYNC
+~~~
+
+### Markers that are logged
+
+| Marker | Description
+|--------|-------------
+| V_SYNC.| The heart beat which represents DALi should start creating a new frame if anything has changed. Runs at display refresh rate, typically 60Hz |
+| UPDATE_START | DALi update task has started |
+| UPDATE_START | DALi update task has finished |
+| RENDER_START | DALi render task has started |
+| RENDER_END | DALi render task has finished |
+| PROCESS_EVENT_START | DALi main thread processing events (e.g. in response to a touch event or a timer) |
+| PROCESS_EVENT_START | DALi main thread processing events finished |
+| SWAP_START | glSwapBuffers started (todo) |
+| SWAP_END | glSwapBuffers end  (todo) |
+| PAUSE  | Application paused |
+| RESUME | Application resumed |
+
+### Custom time stamps for application developers
+
+A developer can output custom markers using the PerformanceLogger API (C++ only currently)
+
+~~~
+PerformanceLogger logger = PerformanceLogger::New("MyMarker");
+logger.AddMarker(PerformanceLogger::START_EVENT);
+
+// do stuff
+
+logger.AddMarker(PerformanceLogger::END_EVENT);
+~~~
+
+## Statistics logging
+
+Statistics logging uses DALi log output which on Tizen is dlog, but this can also be used on desktop by redirecting stderr to a file.
+
+Setting DALI_LOG_PERFORMANCE_STATS environment variable will enable time stamps.
+
+The log options are:
+
+|  Bit |  Function                | Example      |
+|------|--------------------------|--------------|
+|   0  |  log all statistics to the DALi log | DALI_LOG_PERFORMANCE_STATS=1 dali-demo |
+|   1  |  log update and render statistics to the DALi log| DALI_LOG_PERFORMANCE_STATS=2 dali-demo |
+|   2  |  log event (main) task statistics to the DALi log| DALI_LOG_PERFORMANCE_STATS=4 dali-demo |
+|   3  |  log custom marker statistics to the DALi log | DALI_LOG_PERFORMANCE_STATS=8 dali-demo |
+
+Example output
+~~~
+$ export DALI_LOG_PERFORMANCE_STATS=1
+$ dali-demo
+
+ Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+ Update, min 0.29 ms, max 0.91 ms, total (0.5 secs), avg 0.68 ms, std dev 0.15 ms
+ Render, min 0.33 ms, max 0.97 ms, total (0.6 secs), avg 0.73 ms, std dev 0.17 ms
+ TableViewInit, min 76.55 ms, max 76.55 ms, total (0.1 secs), avg 76.55 ms, std dev 0.00 ms
+~~~
+
+If nothing is animating DALi will enter a paused state to save power. At this
+point nothing will be logged.
+
+### Custom statistics for application developers
+
+This is identical to the custom timestamp example.
+~~~
+PerformanceLogger logger = PerformanceLogger::New("MyMarker");
+logger.AddMarker(PerformanceLogger::START_EVENT);
+
+// do stuff
+
+logger.AddMarker(PerformanceLogger::END_EVENT);
+~~~
+
+
+## Application profiling
+
+ The main application thread in DALi is used to process and respond to events such as touch, key, mouse, gestures and timers.
+
+Example:
+~~~
+$ export DALI_LOG_PERFORMANCE_STATS=4
+$ dali-demo
+$
+$ ...
+$ INFO: DALI:  Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+~~~
+
+Inside the event processing, the application may be listening for certain events.
+For example when an actor is touched, some application code may be run in an OnTouch callback.
+By checking the max times you can check for any spikes that occur when interacting with the application.
+
+Example:
+~~~
+$ INFO: DALI: Event , min 0.10 ms, max 500.01 ms, total (6.4 secs), avg 20.83 ms
+
+- Something has taken 500 ms = 1/2 second during event processing.
+- Need to investigate what the application is doing for 1/2 a second.
+~~~
+
+
+## Using ftrace for timestamp logging
+
+~~~
+DALI_PERFORMANCE_TIMESTAMP_OUTPUT=2 dali-demo
+~~~
+
+Ftrace is a kernel tracer designed to help developers find out what is going on inside the kernel.
+It can be used for analyzing how long DALi takes to perform different tasks and
+what DALi is doing in relation to other system processes / interrupts.
+  
+On Tizen if the kernel has been built with ftrace enabled, then DALi can log out to ftrace.
+This gives exact time stamps of the main events in DALi.
+Current markers that are logged:
+
+
+
+### Checking ftrace is working on Linux
+
+Documentation for ftrace:
+Follow these instructions to ensure the debugfs has been mounted, and the kernel you are using
+has been built with ftrace enabled.
+
+https://www.kernel.org/doc/Documentation/trace/ftrace.txt
+
+To check ftrace is working:
+~~~
+$ cd /sys/kernel/debug/tracing
+$ echo 1 > tracing_enabled    (enabled tracing)
+$ echo "test" > trace_marker
+$ echo 0 > tracing_enabled    (disable tracing)
+$ cat trace
+#
+#          TASK-PID    CPU#    TIMESTAMP  FUNCTION
+#             | |       |          |         |
+         <...>-2539  [001] 267964.345607: tracing_mark_write: test
+
+
+If the message did not get added to the trace, then check the write permissions on trace_marker file. E.g.
+$ chmod ugoa+w trace_marker
+~~~
+To view DALi markers in trace file
+
+~~~
+$ export DALI_LOG_PERFORMANCE=2
+$ dali-demo
+$
+$ cat /sys/kernel/debug/tracing/trace
+
+  <...>-3330  [000] 785155.216611: tracing_mark_write: SPI_EV_DALI_V_SYNC
+  <...>-3328  [003] 785155.216644: tracing_mark_write: SPI_EV_DALI_UPDATE_START
+  <...>-3328  [003] 785155.217045: tracing_mark_write: SPI_EV_DALI_UPDATE_END
+  <...>-3329  [001] 785155.227418: tracing_mark_write: SPI_EV_DALI_RENDER_START
+  <...>-3329  [001] 785155.227807: tracing_mark_write: SPI_EV_DALI_RENDER_END
+  <...>-3330  [000] 785155.233336: tracing_mark_write: SPI_EV_DALI_V_SYNC
+  <...>-3328  [002] 785155.233374: tracing_mark_write: SPI_EV_DALI_UPDATE_START
+  <...>-3328  [002] 785155.233672: tracing_mark_write: SPI_EV_DALI_UPDATE_END
+  <...>-3329  [001] 785155.235161: tracing_mark_write: SPI_EV_DALI_RENDER_START
+  <...>-3329  [001] 785155.235475: tracing_mark_write: SPI_EV_DALI_RENDER_END
+  <...>-3330  [000] 785155.250029: tracing_mark_write: SPI_EV_DALI_V_SYNC
+  <...>-3328  [003] 785155.250065: tracing_mark_write: SPI_EV_DALI_UPDATE_START
+  <...>-3328  [003] 785155.250330: tracing_mark_write: SPI_EV_DALI_UPDATE_END
+  <...>-3329  [001] 785155.252860: tracing_mark_write: SPI_EV_DALI_RENDER_START
+  <...>-3329  [001] 785155.253178: tracing_mark_write: SPI_EV_DALI_RENDER_END
+  <...>-3329  [001] 785155.264508: tracing_mark_write: SPI_EV_DALI_RENDER_START
+  <...>-3329  [001] 785155.265006: tracing_mark_write: SPI_EV_DALI_RENDER_END
+~~~
+*/
+
+
diff --git a/docs/content/programming-guide/performance-tips.md b/docs/content/programming-guide/performance-tips.md
new file mode 100644 (file)
index 0000000..d72ec04
--- /dev/null
@@ -0,0 +1,37 @@
+<!--
+/**-->
+
+# Performance Tips {#performancetips}
+
+## High CPU occupancy
+
+  - Try to reduce actor count ( less actors == less processing)
+  - Delete any actors that are not visible, or move them off stage
+  - Use TextureAtlases ( reduces OpenGL driver calls to glBindTexture
+  - Optimize / reduce any constraints used
+
+## High GPU occupancy
+
+  - Reduce visible actor count ( == less draw calls)
+  - For 2D UI graphics which require no z sorting you can use
+
+~~~{.cpp}
+// C++
+// In this mode depth testing is turned off and order is determined by the hierarchy (depth-first search order).
+// Not always recommended if there is going to be a lot of overdraw ( if lots of actors are on top of each other)
+
+Actor::SetDrawMode( DrawMode::OVERLAY_2D ); // C++
+~~~
+
+  - Use TextureAtlases (reduces state changes in the GPU)
+  - Use compressed textures
+  - Use lower quality textures, e.g. smaller, lower number of bits per pixel
+  - Avoid using too many textures which contain alpha and require blending
+  - Avoid using too many Dali::Layer with depth testing enabled. Otherwise the layer has to clear the depth buffer.
+  - Optimize any shaders used. Pixel shaders should be kept as lean as possible.
+
+
+
+*/
+
+
diff --git a/docs/content/programming-guide/popup.md b/docs/content/programming-guide/popup.md
new file mode 100644 (file)
index 0000000..4ea5dd2
--- /dev/null
@@ -0,0 +1,391 @@
+<!--
+/**-->
+
+[TOC]
+
+# Popup {#popup}
+  
+![ ](./popup-example.png)
+
+## Description {#popupdescription}
+  
+The Popup control provides a generic way of displaying modal content.
+  
+The content is displayed until it is dismissed by hiding the Popup.
+
+While the Popup is visible, it is displayed within a layer that is placed above any other actors.
+
+Content behind the Popup is dimmed by default, although this is configurable.
+  
+
+## Contents {#popupcontents}
+  
+
+The Popup is designed to be generic, but provide the necessary layout functionality to achieve this.
+
+The Popup window is broken down into the following areas:
+  
+PopupBackgroundImage: This is the frame that appears around the edge of the Popup.
+  
+Within the Popup there are three main fields:
+  
+- Title
+- Content
+- Footer
+  
+![ ](./popup-fields.png)
+  
+Each field can contain any Actor.
+  
+Note: All actor properties are optional, allowing any combination of content areas.
+Example: Image only popup (using the content field):
+![ ](./popup-image-content.png)
+  
+### Example content: {#popupfieldexample}
+  
+- Title:   TextLabel
+- Content: ImageView or TextLabel
+- Footer:  PushButton or Actor containing two PushButtons
+  
+## Setting and getting the display state {#popupdisplaystate}
+  
+The popup will not be shown immediately upon parenting it / adding it to the stage. First the display state must be set.
+The display state is represented by the property DISPLAY_STATE. It can be set with SHOWN and HIDDEN to show or hide the Popup.
+However, when getting the state, you will also be told if the Popup is in the process of SHOWING or HIDING.
+  
+ | Value    | Setting the state              | Getting the state              |
+ |----------|--------------------------------|--------------------------------|
+ | SHOWN    | Show the popup                 | The popup is fully shown       |
+ | HIDDEN   | Hide the popup                 | The popup is fully hidden      |
+ | SHOWING  |                                | The popup is transitioning in  |
+ | HIDING   |                                | The popup is transitioning out |
+  
+
+## Signals {#popupsignals}
+  
+### Display State Signals {#popupdisplaystatesignals}
+  
+All four state changes cause notifications via four respective signals that can be connected to.
+  
+### OutsideTouched Signal {#popupoutsidetouched}
+  
+This signal is emitted whenever a touch is received outside of the popups area.
+This is typically used to hide / dismiss the popup, but can be ignored if it is desired to force the user to make a selection using the controls within the Popup.
+  
+
+## Transition effects {#popuptransitioneffects}
+  
+The Popup object has built-in transitional animation effects.
+These can be user-defined by setting ANIMATION_MODE to CUSTOM, and setting the ENTRY_ANIMATION and
+EXIT_ANIMATION properties accordingly.
+  
+The default to fading in and out.
+  
+
+## Types of Popup {#popuptypes}
+  
+The Popup can be configured to a preset type by using named types within the type-registry.
+  
+These types are modifications / specializations of a Popup. They provide the library user with a shortcut way of creating a specific type of Popup.
+  
+
+The Popup control features a "Toast" popup type. This is a Popup that appears at the bottom of the screen, typically with some text. They are normally for informational purposes only.
+  
+
+### Key differences of the Toast popup {#popuptoastdifferences}
+  
+- The Popup will auto-hide itself after a few seconds.
+- It is touch-transparent. This means touch events go through the Popup to Actors below, giving it non-modal behaviour.
+- The backing is not dimmed. This allows the user to continue their actions without distraction.
+  
+Note: All the above features can be set or unset manually on the Popup control if desired.
+  
+Popup types can be created with the TypeRegistry (as they are not separate classes).
+  
+
+### Example: {#popuptoastexample}
+  
+![ ](./popup-toast.png)
+
+Here is the code to produce the above example:
+  
+C++
+~~~{.cpp}
+TypeInfo typeInfo = TypeRegistry::Get().GetTypeInfo( "PopupToast" );
+if( typeInfo )
+{
+  BaseHandle baseHandle = typeInfo.CreateInstance();
+  if( baseHandle )
+  {
+    Toolkit::Popup popup = Toolkit::Popup::DownCast( baseHandle );
+    popup.SetTitle( Toolkit::TextLabel::New( "This is a Toast Popup.\nIt will auto-hide itself" ) );
+    Stage::GetCurrent().Add( popup );
+    popup.SetDisplayState( Toolkit::Popup::SHOWN );
+  }
+}
+~~~
+  
+
+## Contextual Mode {#popupcontextualmode}
+  
+Contextual Mode allows the popup can appear adjacent to it's parent in screen space.
+  
+If disabled, the Popup will ignore it's parent and appear centered on the stage (user positioning can override this).
+
+If enabled, the contextual mode can be set to four directions. The Popup will be made adjacent on the selected axis.
+  
+EG:
+~~~{.cpp}
+myPopup.SetProperty( Toolkit::Popup::Properties::CONTEXTUAL_MODE, "BELOW" );
+~~~
+  
+Will make the top of the Popup appear just below the bottom of the parent object (plus a margin).
+  
+The default is: NON_CONTEXTUAL which means no layout or positioning is performed.
+  
+| ContextualMode    | Layout                                                  |
+|-------------------|---------------------------------------------------------|
+| NON_CONTEXTUAL    | No contextual layout is performed                       |
+| ABOVE             | Popup is above vertically, centered horizontally        |
+| RIGHT             | Popup is to the right horizontally, centered vertically |
+| BELOW             | Popup is below vertically, centered horizontally        |
+| LEFT              | Popup is to the left horizontally, centered vertically  |
+  
+
+## Properties {#popupproperties}
+  
+Various properties provide more configuration on the Popup's styling.
+  
+This is a breakdown of remaining properties not described in detail above.
+  
+
+| Property               | Type    | Description                                                              |
+|------------------------|---------|--------------------------------------------------------------------------|
+| TOUCH_TRANSPARENT      | bool    | If true, allow touch events to travel through the popup.                 |
+| TAIL_VISIBILITY        | bool    | If true, display a tail image on one of the edges of the popup.          |
+| TAIL_POSITION          | Vector3 | Describes the position of the tail image. Orientation is inferred.       |
+| ANIMATION_DURATION     | float   | Duration used for entry and exit transition animations.                  |
+| AUTO_HIDE_DELAY        | int     | If non-zero, the number of milliseconds before the popup will auto-hide. |
+| BACKING_ENABLED        | bool    | True if backing (dimmed background) is enabled.                          |
+| BACKING_COLOR          | Vector4 | The color of the dimmed background.                                      |
+| TAIL_UP_IMAGE          | string  | The image to use for the tail if above the popup.                        |
+| TAIL_DOWN_IMAGE        | string  | The image to use for the tail if below the popup.                        |
+| TAIL_LEFT_IMAGE        | string  | The image to use for the tail if to the left of the popup.               |
+| TAIL_RIGHT_IMAGE       | string  | The image to use for the tail if to the right of the popup.              |
+  
+
+# ConfirmationPopup Control {#popupconfirmation}
+  
+The ConfirmationPopup control provides a simple interface for providing automatic connection to control signals for common-use Popup use-cases.
+  
+ConfirmationPopup will automatically provide signals for 1 or 2 controls.
+Note: The controls do not need to be PushButtons.
+These signals are dynamically created. The controls (typically PushButtons) must be specifically named so the ConfirmationPopup can locate them.
+  
+## Step 1 {#popupconfirmationstep1}
+Name your controls.
+  
+- Name your first control, or OK control:      "controlOk"
+- Name your second control, or Cancel control: "controlCancel"
+  
+## Step 2 {#popupconfirmationstep2}
+Tell the ConfirmationPopup the names of the signals to connect to for each control.
+For example, if we are using PushButtons as controls, the signal name would be "clicked".
+This allows us to use different control types.
+  
+- Set property "connectSignalOkSelected" with the name of the signal to connect to within the first control.
+- Set property "connectSignalCancelSelected" with the name of the signal to connect to within the second control.
+  
+## Step 3 {#popupconfirmationstep3}
+Connect to the following respective signals within ConfirmationPopup:
+  
+- Connect to signal "controlSignalOk" to be signalled for the first control.
+- Connect to signal "controlSignalCancel" to be signalled for the second control.
+  
+The ConfirmationPopup will dynamically make the connection between the signalling control, and your signal handler.
+  
+This allows connection of signals within both C++ APIs and JSON.
+If more manual control or customizable layout is needed, then it is recommended to use the Popup widget directly for full control.
+  
+The JSON code example at the bottom of this document uses the ConfirmationPopup to allow signal connection from within the JSON description.
+  
+
+# C++ example of a Popup with two buttons {#popupexamplec}
+  
+This example creates a Popup with:
+  
+- Title:   TextLabel
+- Content: TextLabel
+- Footer:  ImageView (an image border around the buttons)
+            - PushButton (OK control)
+            - PushButton (Cancel control)
+  
+The example connects signals to the two buttons, and to the OutsideTouched signal.
+  
+~~~{.cpp}
+Toolkit::Popup popup = Toolkit::Popup::New();
+
+Toolkit::TextLabel titleActor = Toolkit::TextLabel::New( "Title" );
+titleActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE );
+titleActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+popup.SetTitle( titleActor );
+
+Toolkit::TextLabel contentActor = Toolkit::TextLabel::New( "Content text" );
+contentActor.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::WHITE );
+contentActor.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true );
+contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
+popup.SetContent( contentActor );
+
+// Create the footer: Two buttons surrounded by an image.
+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 );
+footer.SetAnchorPoint( AnchorPoint::CENTER );
+footer.SetParentOrigin( ParentOrigin::CENTER );
+
+Toolkit::PushButton okButton = Toolkit::PushButton::New();
+okButton.SetLabelText( "OK" );
+okButton.SetParentOrigin( ParentOrigin::CENTER );
+okButton.SetAnchorPoint( AnchorPoint::CENTER );
+okButton.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
+okButton.SetSizeModeFactor( Vector3( -20.0f, -20.0f, 0.0 ) );
+okButton.ClickedSignal().Connect( this, &MyExample::OnOKButtonClicked );
+
+Toolkit::PushButton cancelButton = Toolkit::PushButton::New();
+cancelButton.SetLabelText( "Cancel" );
+cancelButton.SetParentOrigin( ParentOrigin::CENTER );
+cancelButton.SetAnchorPoint( AnchorPoint::CENTER );
+cancelButton.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
+cancelButton.SetSizeModeFactor( Vector3( -20.0f, -20.0f, 0.0 ) );
+cancelButton.ClickedSignal().Connect( this, &MyExample::OnCancelButtonClicked );
+
+// Set up the footer's layout.
+Toolkit::TableView controlLayout = Toolkit::TableView::New( 1, 2 );
+controlLayout.SetParentOrigin( ParentOrigin::CENTER );
+controlLayout.SetAnchorPoint( AnchorPoint::CENTER );
+controlLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+controlLayout.SetCellPadding( Size( 10.0f, 10.0f ) );
+controlLayout.SetRelativeWidth( 0, 0.5f );
+controlLayout.SetRelativeWidth( 1, 0.5f );
+controlLayout.SetCellAlignment( Toolkit::TableView::CellPosition( 0, 0 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
+controlLayout.SetCellAlignment( Toolkit::TableView::CellPosition( 0, 1 ), HorizontalAlignment::CENTER, VerticalAlignment::CENTER );
+controlLayout.AddChild( okButton, Toolkit::TableView::CellPosition( 0, 0 ) );
+controlLayout.AddChild( cancelButton, Toolkit::TableView::CellPosition( 0, 1 ) );
+footer.Add( controlLayout );
+popup.SetFooter( footer );
+
+popup.OutsideTouchedSignal().Connect( this, &MyExample::OnPopupOutsideTouched );
+
+// Add to stage (the popup is still invisible at this point).
+Stage::GetCurrent().Add( popup );
+
+// Display the popup.
+mPopup.SetDisplayState( Toolkit::Popup::SHOWN );
+~~~
+  
+
+# JSON example of a Popup with two buttons {#popupexamplejson}
+  
+This example creates a Popup with:
+  
+- Title:   TextLabel
+- Content: TextLabel
+- Footer:  Control
+            - PushButton (OK control)
+            - PushButton (Cancel control)
+  
+The example connects signals to the two buttons, and to the OutsideTouched signal.
+This time without an image around the buttons. This could be added in the same way as the C++ example however.
+  
+
+~~~{.json}
+{
+  "constants": {
+    "CONFIG_SCRIPT_LOG_LEVEL": "Verbose"
+  },
+  "stage": [
+    {
+      "type": "ConfirmationPopup",
+      "name": "confirmationPopup",
+      "parentOrigin": [0.5, 0.55, 0.5],
+      "anchorPoint": "CENTER",
+      "widthResizePolicy": "SIZE_RELATIVE_TO_PARENT",
+      "heightResizePolicy": "USE_NATURAL_SIZE",
+      "sizeModeFactor": [0.65, 1.0, 1.0],
+      "tailVisibility": false,
+      "displayChangeAnimationDuration": 1.0,
+      "contextualMode": "NON_CONTEXTUAL",
+      "animationMode": "ZOOM",
+      "connectSignalOkSelected": "clicked",
+      "connectSignalCancelSelected": "clicked",
+      "title": {
+        "type": "TextLabel",
+        "text": "Title text",
+        "textColor": [1, 1, 1, 1]
+      },
+      "content": {
+        "type": "TextLabel",
+        "text": "Content text",
+        "padding": [20, 20, 20, 0],
+        "textColor": [1, 1, 1, 1]
+      },
+      "footer": {
+        "type": "Control",
+        "size": [0, 80, 0],
+        "widthResizePolicy": "FILL_TO_PARENT",
+        "heightResizePolicy": "FIXED",
+        "parentOrigin": "CENTER",
+        "anchorPoint": "CENTER",
+        "actors": [
+          {
+            "type": "PushButton",
+            "name": "controlOk",
+            "parentOrigin": "CENTER_LEFT",
+            "anchorPoint": "CENTER_LEFT",
+            "position": [20, 0, 0],
+            "size": [0, 0, 0],
+            "labelText": "OK"
+          },
+          {
+            "type": "PushButton",
+            "name": "controlCancel",
+            "parentOrigin": "CENTER_RIGHT",
+            "anchorPoint": "CENTER_RIGHT",
+            "position": [-20, 0, 0],
+            "size": [0, 0, 0],
+            "labelText": "Cancel"
+          }
+        ]
+      },
+      "signals": [
+        {
+          "name": "controlSignalOk",
+          "action": "set",
+          "actor": "confirmationPopup",
+          "property": "displayState",
+          "value": "HIDDEN"
+        },
+        {
+          "name": "controlSignalCancel",
+          "action": "set",
+          "actor": "confirmationPopup",
+          "property": "displayState",
+          "value": "HIDDEN"
+        },
+        {
+          "name": "touchedOutside",
+          "action": "set",
+          "actor": "confirmationPopup",
+          "property": "displayState",
+          "value": "HIDDEN"
+        }
+      ]
+    }
+  ]
+}
+~~~
+  
+
+*/
+
diff --git a/docs/content/programming-guide/programming-languages.md b/docs/content/programming-guide/programming-languages.md
new file mode 100644 (file)
index 0000000..ea391b2
--- /dev/null
@@ -0,0 +1,61 @@
+<!--
+/**-->
+
+# Programming Languages {#programming-languages}
+
+DALi applications can be written in several different programming languages.
+
+## C++ {#c-plus-plus}
+
+~~~{.cpp}
+Dali::Actor actor = Dali::Actor::New();
+actor.SetParentOrigin( Dali::ParentOrigin::CENTER );
+actor.SetAnchorPoint( Dali::AnchorPoint::CENTER );
+Dali::Stage::GetCurrent().Add( actor );
+...
+bool OnPressed( Dali::Actor, const TouchData& touch )
+{
+  Dali::Animation anim = Dali::Animation::New( 1.5f );
+  anim.AnimateTo( Property( actor, Actor::Property::POSITION ), Vector3( 200, -100, 0 ), AlphaFunctions::Bounce );
+  anim.play();
+  return true; // consume the touch event
+}
+...
+actor.TouchSignal().Connect( &OnPressed );
+~~~
+
+## JSON {#json-support}
+
+~~~{.json}
+{
+ "animations":
+  {
+    "move":
+    {
+      "duration": 1.5,
+      "properties":
+      [
+        {
+          "actor":"image",
+          "property":"position",
+          "value":[200,-100,0],
+          "alphaFunction": "BOUNCE"
+        }
+      ]
+    }
+  },
+  "stage":
+  [
+    {
+      "name":"image",
+      "type":"Actor",
+      "anchorPoint": "CENTER",
+      "parentOrigin": "CENTER",
+      "signals" :
+      [
+        { "name" : "touch", "action": "play", "animation": "move" }
+      ]
+    }
+  ]
+}
+~~~
diff --git a/docs/content/programming-guide/properties.h b/docs/content/programming-guide/properties.h
new file mode 100644 (file)
index 0000000..7f5f327
--- /dev/null
@@ -0,0 +1,246 @@
+/*! \page properties Properties
+ *
+@section what-is-a-property What is a property?
+
+A property is a value used by an object that can be modified or read externally to that object.
+This could be from within DALi or externally by an application.
+
+<h2 class="pg">What is a property used for?</h2>
+
+Properties can be set externally by an application, allowing that application to change the configuration or behaviour of an actor.
+This could include the physical geometry of the actor, or how it is drawn or moves.
+
+Properties can also be read. This feature can be used in conjunction with constraints to allow changes to a property within one actor to cause changes to the property of another actor. For example, an actor following the movement of another separate actor (that it is not a child of).
+
+Properties can be used to expose any useful information or behaviour of an actor.
+Other actor variables that are used to implement this bevahiour, or do not make useful sense from an application developers point of view should not be exposed.
+
+<h2 class="pg">How to implement a property within DALi Core:</h2>
+
+<b>There are two stages:</b>
+
+- Define the properties as an enum in the public-api header file.
+- Define the property details using the pre-defined macros to build up a table of property information.
+
+There are some pre-defined macros designed to help with and standardise the definition of the propery details table per class.
+
+These macros generate an array of property details which allow efficient lookup of flags like "animatable" or "constraint input".
+
+<b>Example: Layer</b>
+
+Within the public-api header file; layer.h:
+
+@code
+  /**
+   * @brief An enumeration of properties belonging to the Layer class.
+   *
+   * Properties additional to Actor.
+   */
+  struct Property
+  {
+    enum
+    {
+      CLIPPING_ENABLE = DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX, ///< name "clippingEnable",   type bool @SINCE_1_0.0
+      CLIPPING_BOX,                                                 ///< name "clippingBox",      type Rect<int> @SINCE_1_0.0
+      BEHAVIOR,                                                     ///< name "behavior",         type String @SINCE_1_0.0
+    };
+  };
+@endcode
+From @ref Dali::Layer::Property
+
+<b>Notes:</b>
+
+- The properties are enumerated within a named struct to give them a namespace.
+- The properties are then refered to as &lt;OBJECT&gt;::%Property::&lt;PROPERTY_NAME&gt;.
+
+Within the internal implementation; <b>layer-impl.cpp</b>:
+
+@code
+namespace // Unnamed namespace
+{
+
+// Properties
+
+//              Name                Type      writable animatable constraint-input  enum for index-checking
+DALI_PROPERTY_TABLE_BEGIN
+DALI_PROPERTY( "clippingEnable",    BOOLEAN,    true,    false,   true,             Dali::Layer::Property::CLIPPING_ENABLE )
+DALI_PROPERTY( "clippingBox",       RECTANGLE,  true,    false,   true,             Dali::Layer::Property::CLIPPING_BOX    )
+DALI_PROPERTY( "behavior",          STRING,     true,    false,   false,            Dali::Layer::Property::BEHAVIOR        )
+DALI_PROPERTY_TABLE_END( DEFAULT_DERIVED_ACTOR_PROPERTY_START_INDEX )
+@endcode
+
+<b>Notes:</b>
+
+- The table lays within an unnamed namespace.
+- The table should be in the same order as the enum.
+- The table should be the only place where the text names of the properties are defined.
+- The information in the table should be used within the classes IsDefaultPropertyWritable / Animatable / ConstraintInput methods for quick lookup.
+- The last entry in the table is optionally used in debug builds for index checking.
+- The parameter to DALI_PROPERTY_TABLE_END should match the start index of the property enumeration.
+
+<br>
+<h2 class="pg">How to implement a property within DALi Toolkit controls and application-side custom controls:</h2>
+
+Macros are used to define properties for the following reasons:
+
+- To standardise the way properties are defined.
+- To handle type-registering for properties, signals and actions in one place.
+- To facilitate the posibility of running the code with the type-registry disabled.
+
+Two different macros are provided depending on whether the property is to be an event-side only property or an animatable property.
+
+<b>There are three stages:</b>
+
+- Define the property ranges as an enum in the public-api header file. There are two ranges, one for event-side only properties, and one for animatable properties. Each range should follow on from the range defined in the parent class.
+- Define the properties as an enum in the public-api header file
+- Define the property details using the pre-defined macros to perform the type-registering of the properties. This is done for signals and actions also.
+
+<b>Example: ImageView</b>
+
+Source file: <b>image-view.h</b>:
+  Note that the “PropertyRange” contents “PROPERTY_START_INDEX” & "ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX" are also used by the macro for order checking, so should always have these names.
+
+@code
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,  ///< @SINCE_1_0.0
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,              ///< Reserve property indices @SINCE_1_0.0
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,        ///< @SINCE_1_1.18
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000  ///< Reserve animatable property indices, @SINCE_1_1.18
+  };
+
+  /**
+   * @brief An enumeration of properties belonging to the Button class.
+   */
+  struct Property
+  {
+    enum
+    {
+      // Event side properties
+
+      /**
+       * @DEPRECATED_1_1.16. Use IMAGE instead.
+       * @brief name "resourceUrl", type string
+       * @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
+       * @pre image must be initialized.
+       */
+      PRE_MULTIPLIED_ALPHA,
+
+      // 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].
+       * @SINCE_1_0.18
+       */
+      PIXEL_AREA = ANIMATABLE_PROPERTY_START_INDEX,
+    };
+  };
+@endcode
+
+Source file: <b>image-view-impl.cpp</b>, within an unnamed namespace:
+
+@code
+#include <dali/public-api/object/type-registry-helper.h>
+@endcode
+
+@clip{"image-view-impl.cpp",DALI_TYPE_REGISTRATION_BEGIN,DALI_TYPE_REGISTRATION_END}
+
+<b>Notes:</b>
+
+- The “Create” parameter to the begin macro is the function pointer to the creation function.
+- Properties should be in the same order as in the enum.
+- Signals and actions are registered likewise in that order.
+- Properties type-registered using these macros will have their order checked at compile time. If you get an indexing compile error, check the order matches the enum order.
+    The error will look like this: " error: invalid application of 'sizeof' to incomplete type 'Dali::CompileTimeAssertBool<false>' "
+- If using the Pimpl design pattern when creating a custom control from within an application, the Handle (public) and Object (internal) classes should have the same name. They can be separated by different namespaces.
+    This requirement is actually due to how the type-registry in DALi looks up properties.
+
+<br>
+<hr>
+@section property-indices Property Indices
+
+The properties are enumerated to give them a unique index. This index can be used to access them.
+The indecies must be unique per flattened derivation heirachy.
+EG:
+- CameraActor derives from Actor. No property indicies in either CameraActor or Actor should collide with each other.
+- ActiveConstraintBase derives from Object. It CAN have property indices that match Actor or CameraActor.
+
+There are some predefined start indecies and ranges that should be used for common cases, these are defined below:
+
+
+DALi has a property system and provides several different kinds of properties. The following table
+shows the index range of the different properties in place.
+
+| Kind                  | Description                                                                                       | Start Index                                                                                                | End Index                                                                                                                          |
+|:----------------------|:--------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------------:|
+| Default               | Properties defined within DALi Core, e.g. Dali::Actor default properties etc.                     | \link Dali::DEFAULT_OBJECT_PROPERTY_START_INDEX DEFAULT_OBJECT_PROPERTY_START_INDEX\endlink                | \link Dali::DEFAULT_PROPERTY_MAX_COUNT DEFAULT_PROPERTY_MAX_COUNT\endlink (9999999)                                                |
+| Registered            | Properties registered using Dali::PropertyRegistration                                            | \link Dali::PROPERTY_REGISTRATION_START_INDEX PROPERTY_REGISTRATION_START_INDEX\endlink (10000000)         | \link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)                                     |
+| Control               | Property range reserved by Dali::Toolkit::Control                                                 | \link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX CONTROL_PROPERTY_START_INDEX\endlink (10000000) | \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX CONTROL_PROPERTY_END_INDEX\endlink (10001000)                             |
+| Derived Control       | Property range for control deriving directly from Dali::Toolkit::Control                          | 10001001                                                                                                   | \link Dali::PROPERTY_REGISTRATION_MAX_INDEX PROPERTY_REGISTRATION_MAX_INDEX\endlink (19999999)                                     |
+| Registered Animatable | Animatable properties registered using Dali::AnimatablePropertyRegistration                       | \link Dali::ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX\endlink (20000000) | \link Dali::ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX\endlink (29999999) |
+| Registered Child      | Child properties (which parent supports in its children) registered using Dali::ChildPropertyRegistration   | \link Dali::CHILD_PROPERTY_REGISTRATION_START_INDEX CHILD_PROPERTY_REGISTRATION_START_INDEX\endlink (45000000) | \link Dali::CHILD_PROPERTY_REGISTRATION_MAX_INDEX CHILD_PROPERTY_REGISTRATION_MAX_INDEX\endlink (49999999) |
+| Custom                | Custom properties added to instance using Dali::Handle::RegisterProperty                          | \link Dali::PROPERTY_CUSTOM_START_INDEX PROPERTY_CUSTOM_START_INDEX\endlink (50000000)                     | Onwards...                                                                                                                         |
+
+<br>
+<hr>
+@section property-use-example-cpp Property use example C++
+
+Common uses for properties are constraints and animations.
+
+An application developer can use an existing property, or, if necessary, register their own.
+
+Here is a code example.
+
+This example shows how to register and look-up custom properties.
+An image is added to the screen which changes and a custom property is added to the image-view.
+This value is incremented every time the image is touched and the text-label is updated.
+When touched, the property is looked up by index (as this is much faster than a text lookup of the property name).
+
+Property lookup via index should always be used unless the indicies cannot be known. If the property reader was completely decoupled from the creation, e.g. A custom control with a custom property being used by external application code, then it may be necessary. In this case the application writer should aim to perform the text lookup once at start-up, and cache the property index locally.
+
+@clip{"properties.cpp", // C++ EXAMPLE, // C++ EXAMPLE END}
+
+<br>
+<hr>
+@section property-use-example-json Property use in JSON
+
+This is a basic example of a button defined in JSON by setting the default properties.
+
+@code
+{
+  "stage":
+  [
+    {
+      "type": "ImageView",
+      "parentOrigin": "CENTER",
+      "anchorPoint": "CENTER",
+      "position": [0, 0, 0],
+      "image":
+      {
+        "visualType" : "IMAGE",
+        "url" : "images/icon-0.png",
+        "desiredWidth" : 100,
+        "desiredHeight" : 100
+      }
+    }
+  ]
+}
+@endcode
+
+*
+*/
diff --git a/docs/content/programming-guide/resource-image-scaling.md b/docs/content/programming-guide/resource-image-scaling.md
new file mode 100644 (file)
index 0000000..8e8c597
--- /dev/null
@@ -0,0 +1,349 @@
+<!--
+/**-->
+
+[TOC]
+
+# Resource Image Scaling {#resourceimagescaling}
+  
+## Introduction {#resourceimagescaling-introduction}
+  
+Resource Image Scaling provides automatic image resizing (without changing aspect) based on settings provided by the developer.
+This operation is performed at load time.
+  
+### Developer options:
+* A target size of the image - this could be the full screen size for example.
+* A Fitting mode - This determines how the image is fitted to the target dimensions. If necessary the image will be cropped, or have borders added automatically.
+* A Sampling Mode - This determines the quality of the scaling (by specifying the type of filtering to use).
+  
+### Benefits of Resource Image Scaling:
+* Scaled image will typically be 1-to-1 size ratio with on screen pixels, giving quality benefits.
+* Scaling performed at load time, so run time speed is improved.
+* Ease of use allows applications handling lots of images of different sizes to be created quickly and easily.
+  
+## Use-Case Example {#resourceimagescaling-basicexample}
+While common uses of images in DALi applications involve fixed sized images under the developer's control, e.g. for button backgrounds, in other cases such as galleries and wallpapers an application must display a variety of images and adapt to different screen sizes and densities.
+
+There are more code examples later in this document under [API usage](#resourceimagescaling-apidetails). For now we will just give one full code example to show how this feature is used..
+  
+Let's say we are writing a home-screen application for a smart phone.
+Here we have a large, square image that we want to set as the wallpaper on a tall and narrow phone screen.
+We want to fill the screen without distorting the image or having black borders, and wasting as few pixels from the source image as possible.
+  
+![ ](example-scale-to-fill-problem.jpg)
+  
+DALi provides the concept of a `FittingMode` to specify how a source image is mapped into a target rectangle, and the one we need here is `FittingMode::SCALE_TO_FILL` as it guarantees to cover all of the pixels of the target dimensions specified.
+A second concept of a `SamplingMode` controls how source image pixels are combined during the scaling and allows the developer to trade speed for quality.
+Since our image is to be loaded once and reused, we use `SamplingMode::BOX_THEN_LINEAR` which is the highest quality option.
+  
+In this case, `SCALE_TO_FILL` will perform this sequence of operations:
+  
+![ ](example-scale-to-fill-sequence.jpg)
+  
+We can pass the stage dimensions to the `ResourceImage` creator function as the desired rectangle and ask it to map the image to the screen as shown here:
+  
+~~~{.cpp}
+ // C++
+ ResourceImage image = ResourceImage::New(
+  "gallery-large-12.jpg",
+  Dali::ImageDimensions( stage.GetSize().x, stage.GetSize().y ),
+  Dali::FittingMode::SCALE_TO_FILL,
+  Dali::SamplingMode::BOX_THEN_LINEAR );
+~~~
+  
+
+## Workflow {#resourceimagescaling-workflow}
+  
+![ ](workflow-main.png)
+  
+The workflow for achieving the final scaled image is (in order):
+  
+- Target Size: Determine target size (from source image size and any user specified target dimensions).
+- Target Image Dimensions: Determine the size the image should be scaled to (taking Fitting Mode into account)
+- Scaling: Perform a scale to target image dimensions using the specified Sampling mode.
+- Crop or Add Borders: Automatically performed as necessary to maintain final target aspect (actual stored data size could be smaller).
+  
+
+
+### Determine Target Dimensions {#resourceimagescaling-targetdimensions}
+  
+![ ](workflow-1.png)
+  
+An application has several options for specifying the target rectangle for the image to be fitted to.
+The application may request dimensions through `ResourceImage::New()`:
+  
+  - `Not specifying either dimension`: IE. Width and Height set to 0 - The target dimensions become the same as the source.
+
+  - `Just one dimension specified, Width OR Height (the other dimension set to 0)`:
+    The unspecified dimension will be derived from the specified one whilst maintaining the aspect of the source image. The specified and calculated dimensions become the target dimensions. See more on this case [below](#resourceimagescalingzerodimensions).
+     
+  - `Width AND Height both specified` The requested dimensions pass straight through to become the target for fitting.
+  
+![ ](scaling-fitting-target-dimensions.png)
+
+The result of this process is an `(x, y)` target size to fit the image in the next step.
+  
+
+
+### Target Image Dimensions {#resourceimagescaling-targetimagedimensions}
+
+![ ](workflow-2.png)
+  
+#### Fitting Mode {#resourceimagescaling-fittingmode}
+  
+DALi provides a number of strategies for mapping the pixels of an image onto the target box derived above.
+It provides a `FittingMode` enumeration to the developer to select a mapping or fitting approach.
+These are `SCALE_TO_FILL`, `SHRINK_TO_FIT`, `FIT_WIDTH`, and `FIT_HEIGHT` and their effect is best appreciated visually:
+  
+The operation of each of these modes is as follows:
+  
+| `FittingMode` | **Operation** |
+| ------------- | ------------- |
+| `SCALE_TO_FILL` | Centers the image on the target box and uniformly scales it so that it matches the target in one dimension and extends outside the target in the other. Chooses the dimension to match that results in the fewest pixels outside the target. Trims away the parts of the image outside the target box so as to match it exactly. This guarantees all of the target area is filled. |
+| `SHRINK_TO_FIT` | Centers the image on the target box and uniformly scales it so that it matches the target in one dimension and fits inside it in the other. This guarantees that all of the source image area is visible. |
+| `FIT_WIDTH` | Centers the image on the target box and uniformly scales it so that it matches the target width without regard for the target height. |
+| `FIT_HEIGHT` | Centers the image on the target box and uniformly scales it so that it matches the target in height without regard for the target width. |
+  
+
+![ ](fitting-mode-options.png)
+  
+<sub> **Fitting modes**: *The top row shows the effect of each mode when a tall target rectangle is applied to a square image. The middle row applies a wide target to a square raw image. The bottom row uses a target with the same aspect ratio as the raw image. This example shows that `SCALE_TO_FILL` is the only option for which the dimensions of the fitted image result fill all the area of the target. Others would be letterboxed with borders. `SHRINK_TO_FIT` is always equal to one of `FIT_WIDTH` or `FIT_HEIGHT`: in each case it is the minimum of them. As a special case, where the aspect ratio of raw image and target match, all fitting modes generate an exact match final image and are equivalent to each other.* </sub>
+  
+
+Note: The image is scaled to the same aspect and shrunk to fit depending on fitting mode. It is not upscaled. See: [Upscaling](#resourceimagescalingupscaling).
+  
+  
+
+### Scaling {#resourceimagescaling-scaling}
+  
+![ ](workflow-3.png)
+  
+To perform the scaling stage, the source image is scaled to a (factor of) the target image size using the specified Sampling Mode/
+  
+The process of scaling an image can be expensive in CPU cycles and add latency to the loading of each resource.
+To allow the developer to trade-off speed against quality for different use cases, DALi provides the `SamplingMode` enum, which can be passed to `ResourceImage::New()`.
+Two of these modes produce bitmaps which differ from the dimensions calculated by the fitting algorithm and so have a memory trade-off as well. The full set of modes is explained below.
+  
+| `SamplingMode` | **Operation** |
+| ------------- | --------- |
+| `NEAREST` | Use simple point sampling when scaling. For each pixel in output image, just one pixel is chosen from the input image. This is the fastest, crudest option but suffers the worst from aliasing artifacts so should only be used for fast previews, or where the source image is known to have very low-frequency features. |
+| `LINEAR` | Uses a weighted bilinear filter with a `(2,2)` footprint when scaling. For each output pixel, four input pixels are averaged from the input image. This is a good quality option, equivalent to the GPU's filtering and works well at least down to a `0.5` scaling. |
+| `BOX` | Uses an iterated `(2,2)` box filter to repeatedly halve the image in both dimensions, averaging adjacent pixels until the the result is approximately right for the fitting target rectangle. For each output pixel some number of pixels from the sequence `[4,16,64,256,1024,...]` are averaged from the input image, where the number averaged depends on the degree of scaling requested. This provides a very high quality result and is free from aliasing artifacts because of the iterated averaging. *The resulting bitmap will not exactly match the dimensions calculated by the fitting mode but it will be within a factor of two of it and have the same aspect ratio as it.*   |
+| `BOX_THEN_NEAREST` | Applies the `BOX` mode to get within a factor of two of the fitted dimensions, and then finishes off with `NEAREST` to reach the exact dimensions. |
+| `BOX_THEN_LINEAR` | Applies the `BOX` mode to get within a factor of two of the fitted dimensions, and then finishes off with `LINEAR` to reach the exact dimensions. This is the slowest option and of equivalent quality to `BOX`. It is superior to `BOX` in that is uses an average of 62% of the memory and exactly matches the dimensions calculated by fitting. **This is the best mode for most use cases**.  |
+| `NO_FILTER` | Disables scaling altogether. In conjunction with `SCALE_TO_FILL` mode this can be useful as the edge trimming of that fitting mode is still applied. An example would be a gallery application, where a database of prescaled thumbnails of approximately the correct size need to be displayed in a regular grid of equal-sized cells, while being loaded at maximum speed. |
+  
+
+Here are all the modes applied to scaling-down a `(640,720)` line art and text JPEG image to a `(218, 227)` thumbnail:
+  
+|  |  | |
+| ---- | ---- | --- |
+| ![ ](sampling_modes_no_filter.png) | ![ ](sampling_modes_nearest.png) | ![ ](sampling_modes_linear.png) |
+| **NO_FILTER** | **NEAREST** | **LINEAR** |
+| ![ ](sampling_modes_box.png) | ![ ](sampling_modes_box_then_nearest.png) | ![ ](sampling_modes_box_then_linear.png) |
+| **BOX** | **BOX_THEN_NEAREST** | **BOX_THEN_LINEAR** |
+  
+These are screenshots, showing how the images are rendered in a DALi demo.
+There is an additional level of GPU bilinear filtering happening at render time.
+The best way to get a feel for the best sampling mode for different image types is to play with the [examples](#resourceimagescaling-samplingmodesdemoexamples).
+  
+  
+
+### Crop or Add Borders {#resourceimagescaling-croporaddborders}
+  
+![ ](workflow-4.png)
+  
+Lastly, the image data will be cropped, or have borders added automatically as necessary.
+This is done to ensure the image correctly fits the aspect of the target window, whilst maintaining the aspect of the source image.
+  
+Images that have an alpha channel will be given transparent borders. Otherwise black is used.
+  
+  
+
+## Using the API (With source code examples) {#resourceimagescaling-apidetails}
+  
+This section contains more detail about using the API to setup the desired behaviour.
+
+`ResourceImage` :: New has the following parameters:
+- **path**: Identifier for the image (allows raw image width and height to be retrieved).
+- **requested dimensions**: These are either `(0,0)`, a width, a height, or a (width, height) pair and either directly, or after reading the image raw dimensions and doing some math, define a target rectangle to fit the image to.
+- **fitting mode**: one of four strategies for mapping images onto the target rectangle.
+- **sampling mode** Different quality options for the scaling.
+  
+### Code Examples {#resourceimagescaling-targetdimensionsexamples}
+If we have a `(320, 240)` image called "flower.jpg", we use these options in code as below.
+  
+**Case 1**: In these two equivalent loads, the target dimensions are not specified, so will be `(320, 240)` so the image will be loaded at its raw dimensions without modification.
+~~~{.cpp}
+// C++
+ResourceImage image1 = ResourceImage::New( "flower.png" );
+ResourceImage image2 = ResourceImage::New( "flower.png", ImageDimensions( 0, 0 ) );
+~~~
+  
+
+**Case 2**: In these loads, the target dimensions will be `(160, 120)` as the zero dimension is derived from the aspect ratio of the raw image.
+~~~{.cpp}
+// C++
+ResourceImage image1 = ResourceImage::New( "flower.png", ImageDimensions( 160, 0 ) );
+ResourceImage image2 = ResourceImage::New( "flower.png", ImageDimensions( 0, 120 ) );
+~~~
+  
+
+**Case 3**: In this load, the target dimensions will be `(111, 233)`.
+~~~{.cpp}
+// C++
+ResourceImage image = ResourceImage::New( "flower.png", ImageDimensions( 111, 233 ) );
+~~~
+  
+
+### Fitting an image's dimensions to the target box {#resourceimagescaling-codeexamplesfittingmodes}
+  
+The result of the fitting modes defined [here](#resourceimagescaling-targetimagedimensions) only differ when the target box has a different aspect ratio than the source image.
+Images may still be scaled down, depending on the target dimensions, but the specified fitting mode will not have an effect.
+  
+EG:
+~~~{.cpp}
+// C++
+// Image on 'disk' is 320x240.
+ResourceImage image = ResourceImage::New( "flower.png", ImageDimensions( 32, 24 ) );
+// Image will be loaded at (32, 24), regardless of fitting mode.
+~~~
+  
+
+### Passing a Zero Dimension {#resourceimagescalingzerodimensions}
+  
+Passing in a single zero dimension is equivalent to specifying `FIT_WIDTH` or `FIT_HEIGHT` `FittingMode`s. When a non-zero width and zero height are specified, the fitting done will be identical to the result using `FittingMode` `FIT_WIDTH`. When passing a zero width and non-zero height, the effect of applying the chosen `FittingMode` to the calculated target dimensions is always identical to applying the `FIT_HEIGHT` mode.
+  
+* `ResourceImage::New( ImageDimensions( x, 0 ), <ANY_FITTING_MODE> )` =
+  `ResourceImage::New( ImageDimensions( x, <ANYTHING> ), FittingMode::FIT_WIDTH )`
+* `ResourceImage::New( ImageDimensions( 0, y ), <ANY_FITTING_MODE> )` =
+  `ResourceImage::New( ImageDimensions( <ANYTHING>, y), FittingMode::FIT_HEIGHT )`
+  
+This falls out of the the fact that the fitting modes are strategies for the case when the aspect ratio of the raw image differs from the aspect ratio of the target dimensions, but the zero dimension behavior always ensures that the target dimensions have the same aspect ratio as the raw image's so the fitting modes are all equivalent.
+  
+Therefore, if `(x!=0, y=0)`, fittingMode = `FIT_WIDTH`,
+and if `(x=0, y=!0)`, fittingMode = `FIT_HEIGHT`, irrespective of fitting mode passed by the application (if any).
+This shortcut is provided as a convenience to the developer and allows FIT_WIDTH or FIT_HEIGHT to be specified compactly:
+~~~{.cpp}
+// C++
+// FIT_WIDTH:
+ResourceImage image = ResourceImage::New("flower.png", ImageDimensions(x, 0));
+// FIT_HEIGHT:
+ResourceImage image = ResourceImage::New("flower.png", ImageDimensions(0, y));
+~~~
+  
+Note:
+- If both values are specified as 0, both dimensions are taken from the source image.
+- If both dimensions are not 0, this value becomes the 'natural size' even if it differs from the actual pixel dimensions loaded. [This requires some care in rendering to avoid distortion](#resourceimagescaling-samplingmodesrendernaturalsize).
+  
+
+### Code Examples for Sampling Modes  {#resourceimagescaling-codeexamplessamplingmodes}
+  
+
+In the following code example an image is loaded to be a thumbnail but with differing quality, speed, and memory implications.
+~~~{.cpp}
+// C++
+ResourceImage image1 = ResourceImage::New( "flower.png",
+    ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::NEAREST );
+  
+ResourceImage image2 = ResourceImage::New( "flower.png",
+    ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER );
+  
+ResourceImage image3 = ResourceImage::New( "flower.png",
+    ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX );
+  
+ResourceImage image4 = ResourceImage::New( "flower.png",
+    ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR );
+~~~
+  
+  
+
+
+### Notes on speed VS quality {#resourceimagescaling-speedvsquality}
+  
+If we imagine flower.jpg is a 560*512 photo with high frequency details, the results of this are (image references are from above example):
+* `image1` loads fast, uses minimal space, has poor quality.
+* `image2` loads even faster, uses 4.6 * minimal space, has good quality.
+* `image3` loads moderately slow, uses 1.3 * minimal space, has good quality.
+* `image4` loads slowest, uses minimal space, has good quality.
+  
+Note that `BOX`, `BOX_THEN_NEAREST` and `BOX_THEN_LINEAR` can work particularly well for JPEG images as they can use fast downscaling typically built-in to the JPEG codec on supported platforms on the fly while decoding. In this case the caveats about using them having a speed trade-off given above do not apply.
+  
+  
+
+
+## Demo Examples {#resourceimagescaling-samplingmodesdemoexamples}
+  
+Load time image scaling is spread throughout the DALi examples.
+Search for `"ImageDimensions"` in the dali-demo project to see it used.
+There is also a specific demo to show all of the fitting and scaling modes.
+which lives in the demo project at `examples/image-scaling-and-filtering`.
+  
+![ ](./demo-fitting-sampling.png)
+  
+Touch the arrows in the top corners to changes image.
+Drag the resize handle in the corner of the image to change the requested size and trigger an immediate image reload.
+Use the buttons at the bottom of the screen to select any of the fitting and sampling modes from the popups which appear.
+This demo does not take any of the special measures [described here](#resourceimagescaling-naturalsizecompensation) to correct for the natural size != pixel dimensions discrepancy so all fitting modes other than `SCALE_TO_FILL` show distortion.
+  
+A second specific demo shows the effect of a filter mode on a single image loaded into various requested rectangles side by side.
+It can be found under `examples/image-scaling-irregular-grid`.
+  
+![ ](./demo-sampling-modes.jpg)
+  
+Touch the button at top-left to change image.
+The button at top-right changes sampling mode.
+You will see strong differences between sampling modes where the image contains high frequency details such as hair and in the large black and white image, but much less in some others such as the Statue of Liberty which is mostly covered by a smooth gradient.
+  
+  
+
+## Further Notes {#resourceimagescaling-furthernotes}
+  
+### Upscaling {#resourceimagescaling-upscaling}
+  
+DALi refuses to upscale images at load time in order to conserve memory.
+If the application requests an image size the specified fitting mode) would require scaling up, DALi will instead return an image with the same aspect ratio but limited to the largest dimensions that do not exceed the raw ones.
+EG. The actual image could be a fraction of the size of the target image dimensions.
+Upscaling can still be effected at render time by setting the size of an actor to the desired size.
+  
+  
+
+### 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 `ImageView` for scaling at render time instead.
+  
+  
+
+### Compensation for Natural Size != Pixel Width / Height {#resourceimagescaling-naturalsizecompensation}
+  
+Because the *natural size* of an image is
+[taken from the requested dimensions](#resourceimagescaling-samplingmodesdimensionflow)
+passed to `ResourceImage::New()` rather than passing through the same calculations that result in the eventual pixel width and height loaded,
+the *natural size* and pixel dimensions of an image will differ when loaded with scaling.
+It is inherent in the definition of fitting modes other than `SCALE_TO_FILL` not to match the requested dimensions, so in general, images loaded with them must have this mismatch between *natural size* and actual pixel width.
+  
+It is not possible in general to draw a scaled resource image using its natural size as the `ImageView`'s size without it appearing stretched in one dimension.
+This is the case for example by default with size negotiation in effect or when an image is simply passed to an actor at creation time.
+  
+There are circumstance, however, in which the the natural size of a resource image loaded will exactly match its post-load pixel dimensions:
+  
+- No scaling is requested.
+- The application chooses a combination of requested dimensions, fitting mode, and sampling mode which the scaling sub-system can match exactly. This is the case:
+   *  For all downscaling using `SCALE_TO_FILL` fitting mode and not using `BOX` or `NO_FILTER` sampling modes.
+   * The app uses `SHRINK_TO_FIT`, `FIT_WIDTH`, or `FIT_HEIGHT` and the requested dimensions passed-in are both smaller than the raw ones and have the same aspect ratio as them, and it is not using `BOX` or `NO_FILTER` sampling modes.
+  
+In these cases the image may be used freely in layouts controlled by size negotiation.
+Additionally, if the requested size has the same aspect ratio as the eventual pixel array loaded, and the fitting mode is `SCALE_TO_FILL` or `BOX` and `NO_FILTER` sampling modes are avoided, even if they don't match in dimensions exactly, the eventual image will be drawn without aspect ratio distortion although it will be scaled at render time.
+  
+The fitting and scaling modes [demo](#resourceimagescalingsamplingmodesdemoexamples) allows this behavior to be be explored dynamically when the fitting mode is changed from `SCALE_TO_FILL`.
+  
+The application can of course only pass dimensions which are just right if it happens to know the raw dimensions or if it accesses the the image resource and reads the raw dimensions from its header.
+  
+The application can get a scaled resource image rendered correctly to screen with one of three strategies:
+  
+  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 `ImageView` to that size explicitly rather than relying on the *natural size* of the image.
+  
+
+
+*/
diff --git a/docs/content/programming-guide/resource-tracking.md b/docs/content/programming-guide/resource-tracking.md
new file mode 100644 (file)
index 0000000..d4635a9
--- /dev/null
@@ -0,0 +1,56 @@
+<!--
+/**-->
+
+# Resource Tracking {#resourcetracking}
+
+## Enable Logging
+
+Setting DALI_ENABLE_LOG environment variable to RESOURCE_LOG will enable resource usage logging in DALi applications.
+On target resource logging utilizes dlog, but this can also be used on desktop by redirecting stderr to a file.
+The generated information includes any image files that are loaded with their dimensions,
+GPU memory consumption, CPU RAM used and details of texture atlases created.
+
+## Viewing Resource Logs
+
+dalireslog.sh is installed as part of the DALi Adaptor package and can be found in the adaptors/tizen/scripts folder.
+The script shows a summary of memory used by resources.
+USAGE:
+./dalireslog.sh [FILE]
+if FILE isn't specified, the script will try to use dlogutil.
+
+### Example:
+~~~{.bash}
+sh-4.1$ ./dalireslog.sh
+
+**On a separate terminal:**
+
+sh-4.1$ DALI_ENABLE_LOG=RESOURCE_LOG /opt/apps/com.samsung.dali-demo/bin/album.example
+~~~
+Example on desktop:
+~~~{.bash}
+jon-doe\@ws-1234$ DALI_ENABLE_LOG=RESOURCE_LOG blind-effect.example 2>/home/SERILOCAL/john.doe/log.txt
+
+**On a separate terminal:**
+
+dalireslog.sh ~/log.txt
+
+~~~
+
+### Displayed information:
+
+|  | |
+|--|-|
+| 3D | amount of GPU memory used by application |
+| MEM Atlas | amount of GPU memory used by texture atlases (usually this refers to font atlases)
+| Number of atlases | how many texture atlases are present in memory.|
+
+A list of files is displayed in the main view, with different color codes representing different states:
+
+| | |
+|-|-|
+|CPU | resource is in memory, but hasn't been uploaded to a GL texture.|
+|GPU | resource has been uploaded to a GL texture, bitmap buffer discarded.|
+|CPUGPU | resource has been uploaded to a GL texture, but still present in CPU memory as well.|
+|DISCARDED | resource has been discarded, memory freed up |
+
+ */
diff --git a/docs/content/programming-guide/resources.md b/docs/content/programming-guide/resources.md
new file mode 100644 (file)
index 0000000..4dc718d
--- /dev/null
@@ -0,0 +1,62 @@
+<!--
+/**-->
+# Resources {#resources}
+
+## Resource Image {#resource-image}
+
+A resource image is an image that is loaded using a file path or a URL.
+
+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. ImageView).
+
+Resources are loaded in separate threads.
+The application can connect to the Dali::ResourceImage::LoadingFinishedSignal() to get notified when the image has loaded.
+
+By default, resource images start loading immediately and the data is released only when the ResourceImage handle is destroyed.
+To optimize an application's memory footprint, the application can ask resources to be only loaded when actually required and
+their data to be released automatically when they are no longer being used (not being used by Actors).
+~~~{.cpp}
+Dali::ResourceImage image = Dali::ResourceImage::New( "/my-path/my-image.png", Dali::ResourceImage::ON_DEMAND, Dali::Image::UNUSED );
+~~~
+If Dali::Image::UNUSED is used, then when the ResourceImage is used again, the resource data is reloaded automatically.
+
+If the application requires the image dimensions immediately, then they can be retrieved synchronously:
+~~~{.cpp}
+Dali::ImageDimensions dimensions = Dali::ResourceImage::GetImageSize( "/my-path/my-image.png" );
+~~~
+This is a disk read which can be slow and will block the event thread, so should only be used if absolutely necessary.
+
+## 9-Patch Image {#resource-9-patch}
+
+DALi has support for 9-patch images.
+These are stretchable, repeatable images which are reduced to their smallest size.
+Essentially, an image is sliced up into 9 squares and the four corners do not change size at all.
+The other 5 segments are stretched (or repeated) to allow the whole image to scale appropriately.
+
+DALi has inbuilt support for *.9.png, *.9.jpg etc. images as well.
+More information about these images can be found here: http://developer.android.com/tools/help/draw9patch.html
+
+The following is an example of a *.9.png image:
+![ ](resource/9-patch.png)
+
+Zoomed in, the red section shows the part that will be repeated.
+The four corners areas remain static.
+The one pixel border will also be stripped out.
+![ ](resource/9-patch-zoomed.png)
+
+And if the image is given a 200 by 200 size, it will look like the following:
+![ ](resource/9-patch-full.png)
+
+## Buffer Image {#resource-buffer}
+
+A BufferImage represents an image resource in the form of a pixel buffer data that can be provided by the application developer.
+The application can then write to this buffer as required and the image is updated on the screen.
+
+~~~{.cpp}
+Dali::BufferImage image = Dali::BufferImage::New( 200, 200 ); // Creates a 200 by 200 pixel buffer with a color-depth of 32-bits (with alpha)
+~~~
+
+*/
diff --git a/docs/content/programming-guide/script-hello.md b/docs/content/programming-guide/script-hello.md
new file mode 100644 (file)
index 0000000..f1fc87e
--- /dev/null
@@ -0,0 +1,35 @@
+<!--
+/**-->
+
+ # Hello World - JSON layout{#script-hello}
+
+ The following JSON code is the minimum required to put the sentence "Hello World" on the screen.
+
+~~~{.json}
+{
+ // a tree of actors
+ "stage": [{
+   "name": "text-label",
+   "type": "TextLabel",
+   "text": "Hello World",
+   "parentOrigin": "CENTER"
+ }]
+}
+~~~
+
+ The following code loads the JSON file
+
+~~~{.cpp}
+ // C++
+ Builder builder = Builder::New();
+
+ std::string json_data(ReadFile("layout.json"));
+
+ builder.LoadFromString(json_data);
+
+ builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+
+ ~~~
+
+
+*/
diff --git a/docs/content/programming-guide/script-json-specification.md b/docs/content/programming-guide/script-json-specification.md
new file mode 100644 (file)
index 0000000..f689518
--- /dev/null
@@ -0,0 +1,456 @@
+<!--
+/**-->
+
+[TOC]
+
+# DALi JSON Specification  {#script-json-specification}
+
+## Overview {#overview}
+
+This document describes the DALi JSON specification.
+The format is not yet formally versioned within the JSON.
+
+# General format {#format}
+
+The JSON format supports
+
+- Named templates for on demand creation of
+ - Actors/ Controls
+ - Animations
+- Style sets
+ - Dynamically change the style of Actor hierarchies
+ - Animate to a style set
+- Includes
+ - Build style sets up by merging JSON
+- Creating Scene content on load
+ - Controls created without any code
+
+
+Concrete Actors and Controls can be created from types registered in the
+DALi Type Registry.
+
+Template, style and scene sections all configure Actors and Controls via
+the DALi property system.
+
+The JSON format deviates from the formal JSON specification and allows C style comments.
+
+~~~
+    {                                        //
+      "version": 0,                          // Version Number
+      "includes":                            // Include section
+      [                                      //
+       "base-theme.json"                     // Include file to merge into the
+                                             // JSON
+      ]                                      //
+      "constants":                           // Constant replacement section
+      {                                      //
+        ...                                  //
+      },                                     //
+      "templates":                           // Template library section
+      {                                      //
+        "basic-text":                        // A named template
+        {                                    // } key value properties
+         ...                                 //
+         "actors":                           // A tree of sub actors
+         [                                   //
+         ...                                 //
+         ]                                   //
+        }                                    //
+        },                                   //
+        "styles":                            // Named Style set section
+        {                                    //
+        "light-theme":                       // Style set name
+        {                                    //
+         ...                                 //
+        },                                   //
+        dark-theme":                         //
+        {                                    //
+         ...                                 //
+        },                                   //
+      }                                      //
+      "stage":                               // Stage section
+      [                                      //
+       {                                     // Actors|Controls to create on JSON file load
+       "type": "basic-text",                 // A DALi Control or a template name
+       "styles":["base-theme","light-theme"] // Style list to apply to this instance
+       }                                     //
+      ]                                      //
+    }                                        //
+~~~
+
+# Top level sections {#sections}
+
+## Includes {#includes}
+
+The "includes" section is an array of file names to be merged in order to
+create a final in memory JSON tree.
+
+The merge process will walk key, value attributes from the root JSON
+node and overwrite previous values with the newer values.
+
+- If the key does not exist then it will be created.
+- If the newer value is a different type then the newer type will persist.
+- Where both values are objects the merge will descend into the object.
+- Where both values are arrays the merge will replace the old array entirely.
+
+The merge is relatively simple and is expected to be used to build up
+from base themes to custom themes where there are few conflicts and
+simple direct replacements are desired.
+
+### Constants {#constants}
+
+The merge behaviour when a file has constants and includes is
+
+1. Constants are loaded first
+2. Includes file list is merged in order
+3. All other (non constant) data is merged
+
+The include merge is recursive, so step (2) above will cause the
+constants in the first included file to be merged first.
+
+## Constants {#constantdetail}
+
+The constants section supports sub-string and full property replacement.
+
+~~~
+    {
+    "constants":                        // Constant replacement section
+    {                                   //
+      "IMAGES": "/usr/share/images/",   // Constants can be set here or in code.
+      "SIZE": [100,100,1]               //
+    },                                  //
+    ...                                 //
+    {                                   //
+      "type":"ImageView"               // An DALi type or a template name
+      "image":                          //
+      {                                 //
+        "url":"{IMAGES}b.jpg"      // Image filename substring replacement
+      },                                //
+      "size": "{SIZE}"                  //
+    }                                   //  Property replacement
+    }                                   //
+~~~
+
+The type of the constant should match the expected type of the property.
+
+A property constant cannot be used for sub string replacement; a string
+constant should be used.
+
+With a property replacement, the replace site must contain a string
+where the first and last positions are braces.
+
+## Templates {#templates}
+
+The template section supports the creation of actor instances. The
+template name can be used in code to create an actor tree.
+
+~~~{.cpp}
+// C++
+
+Builder builder = Builder::New();
+std::string jsonData = loadFile("my-app.json");
+builder.LoadFromString( jsonData );
+
+actorTree = builder.Create("basic-text");
+~~~
+
+Templates consist of a name, multiple property-value configurations and
+an optional actor sub hierarchy.
+
+~~~{.json}
+   {                                    //
+   "templates":                         //  Template library section
+   {                                    //
+   "basic-text":                        //  The template name
+   {                                    //
+     "type":"ImageView",               //  Concrete DALi Type/Class to create
+     "styles":["base-style"],           //  Style list to apply
+     "name":"image",                    //  }
+     "image":                           //  } property name : value
+     {                                  //  }
+     "url":"{IMAGES}/b.jpg"        //
+     },                                 //
+     "parentOrigin": "CENTER"           //
+     ...                                //
+     "actors":                          //  A tree of sub actors
+     [                                  //
+     {                                  //
+     "type":"TextView"                  //
+     "name":"text",                     //
+     "text":"Hello World",              //
+     "parentOrigin": "CENTER",          //
+     }                                  //
+     ]                                  //
+   }                                    //
+   }                                    //
+~~~
+
+A template has a special 'type' property which must contain a concrete
+DALi Actor or Control type name.
+
+A template has a special 'styles' property which contains a list of
+styles to apply when creating using the template.
+
+## Styles {#styles}
+
+The styles section supports a named set of properties that can be
+applied to an actor or actor tree.
+
+~~~{.cpp}
+// C++
+
+Builder.ApplyStyle("light-theme", myActor);
+~~~
+
+The styles can also be applied as an animation.
+
+~~~{.cpp}
+Builder.AnimateTo("light-theme", myActor, TimePeriod(0, 10));
+~~~
+
+
+
+~~~
+   {                                   //
+   "styles":                           // Style set section
+   {                                   //
+   "light-theme":                      // Style-set name
+   {                                   //
+     "color":[1,1,1,1]                 // }
+     "position":[0,-120,0],            // } properties to set on the given actor
+     "rotation":[0,0,30],              // }
+     "actors":                         //
+     {                                 // Sub Actors are referenced by name
+       "title-text":                   // Actor name to search for under given actor
+       {                               //
+         "color":[1,1,1,1]             // }
+         "position":[0,-120,0],        // } properties to set if 'title-text' is found
+         "rotation":[0,0,30],          // }
+       }
+     },                                //
+     "icon":                           //
+     {                                 //
+       "color":[1,1,1,1]               //
+     }                                 //
+    },                                 //
+    "dark-theme":                      //
+    {                                  //
+    }                                  //
+   }                                   //
+~~~
+
+When applied to an actor tree the actors are referenced by name. Names
+are not unique in DALi.
+
+When a style is applied in code DALi will perform a depth first search
+stopping with the first matching name.
+
+Typically an application developer will apply the style to the template
+root actor and not the stage root actor. Therefore in most uses cases
+name conflicts are not expected.
+
+## Animations {#animations}
+
+The animation section defines a library of animation definitions.
+
+The animations can be created by name from code.
+
+They can also be created automatically from JSON in an actor signal.
+
+~~~
+    {                                    //
+    "animations":                        // Animation library
+    {                                    //
+     "rotate":                           // An Animation named rotate
+     {                                   //
+     "duration": 10,                     // Duration in seconds
+     "loop": false,                      // Whether to loop.
+     "endAction": "Bake",                // Whether to set final value(bake) or
+                                         // reset
+     "disconnectAction": "Discard",      // Whether 'Bake' or 'Discard' when disconnected
+     "properties":
+     [
+                                         // Properties changed in this animation
+     {
+     "actor":"image",                    // Actor found by name from the stage
+     "property":"rotation",              // Property to change
+     "value":[0, 0.1, 0, 0],             // Value to set
+     "alphaFunction": "EASE\_IN\_OUT",   // Interpolation function
+                                         //
+     "timePeriod":                       // Time period for change
+     {"delay": 0,
+      "duration": 3
+      }
+     },
+     ...                                 // 1 or more property changes per animation
+     },                                  //
+     ...                                 //
+    },                                   //
+~~~
+
+### Splines {#splines}
+
+An animation property can be defined with a path and forward direction
+instead of a single final value.
+
+Paths are defined in a top level path section and referenced by the
+animation property.
+
+~~~
+    {                                    //
+    "paths":                             // Path library
+     {                                   //
+     "path0":                            // Path definition by name
+     {                                   //
+     "points":[                          // points
+       [-150, -50, 0],
+       [0.0,70.0,0.0],
+       [190.0,-150.0,0.0]
+      ],
+                                         // curvature automatically creates
+     "curvature":0.35,                   // controlPoints
+                                         //
+     "controlPoints": [...]              // Otherwise controlPoints can be
+                                         // directly specified.
+     }                                   //
+     },                                  //
+    "animations":                        //
+    {                                    //
+     "pathAnimation":
+     {
+     "duration": 3.0,
+     "properties":
+     [
+     {
+     "actor": "greeting2",
+                                         // Path is mandatory for spline
+     "path":"path0",                     // animation.
+     "forward":[1,0,0],                  // Forward vector specifies orientation
+                                         // whilst travelling along the path
+     "alphaFunction": "EASE\_IN\_OUT",   // (optional)
+     "timePeriod":
+     {
+     "delay": 0,
+     "duration": 3
+     }
+     },
+     ...
+                                         // Other properties changes can use
+     ]                                   // paths or values in the same
+                                         // animation.
+    },                                   //
+    }                                    //
+~~~
+
+At least one of the vertex or fragment fields is mandatory. All
+other fields are optional will use internal defaults.
+
+Actors have an "effect" field that refers to the shader effect
+instance to use with that actor.
+
+### Animating shaders {#animatingshaders}
+
+Shader uniforms can be animated as if they are properties of the actor.
+
+When the animation is created from code (or from a signal) the property
+name search begins on the actor, if it isn't found the search continues
+on the attached renderer, and then on the attached shader object.
+
+The actor property names and shader uniform names must not clash for the
+uniform to animate correctly.
+
+The actor needs to register the uniform properties as custom animatable
+properties.
+
+~~~
+{
+  "animations":
+  {
+    "rotate":                          \\ An Animation named rotate
+    {
+      "properties":                    \\ Properties changed in this animation
+      [
+        {
+          "actor": "image",            \\ Actor found by name from the stage
+          "property": "uTranslate",    \\ Uniform name specified as if it is a property of the object
+          "value": [10, 20],           \\ Target value of uniform
+          ...
+        }
+      ]
+    },
+    ...
+  },
+  "stage":
+  [
+    {
+      "type": "ImageView",
+      "name": "image",                 \\ Name of the actor
+      ...
+      "image":
+      {
+        ...
+        "shader":                      \\ ImageView has a shader property where we can set a custom shader
+        {
+          "vertexShader": "..."        \\ Vertex shader with uniform "uTranslate"
+        }
+      },
+      "animatableProperties":          \\ Custom properties that the actor needs to register
+      {
+        "uTranslate": [0, 0]           \\ The name should match the uniform we want to animate
+      },
+      ...
+    },
+    ...
+  ]
+}
+~~~
+
+## Stage {#stage}
+
+The stage section supports the immediate creation of actors at the time
+the JSON is loaded.
+
+The stage is a tree of actors that can be added to DALi's stage object.
+
+~~~
+// C++
+builder = Dali.Builder();
+json_text = load("layout.json");
+builder.Load(json\_text);
+stage = Dali.Stage.GetCurrent();
+builder.AddActors( stage.GetRootLayer()); // Add actors to the stage root layer
+~~~
+
+~~~
+    {                                    \\
+    "stage":                             \\  Stage Section Number
+    [                                    \\  An array of actors
+     {
+     "type": "ImageView",
+     ...
+     "actors":                           \\  Each actor can have children
+                                         \\ creating a tree
+     [
+     {
+     "type": "TextView",
+                                         \\  The Type to create; this can be a
+     ...                                 \\ concrete DALi type (actor/control)
+                                         \\ or a template name.
+     "styles": ["base-style"]
+                                         \\  A list of styles to apply to the
+     }                                   \\ created type.
+     ]
+     }
+    ]
+    }
+~~~
+
+# Actor and Control Properties {#actorprop}
+
+Each control has a set of supported properties documented in the "DALi
+UI Control Specification".
+
+Please refer to the above document for further information about specific
+controls.
+
+*/
diff --git a/docs/content/programming-guide/script-overview.md b/docs/content/programming-guide/script-overview.md
new file mode 100644 (file)
index 0000000..ff2dd06
--- /dev/null
@@ -0,0 +1,208 @@
+<!--
+/**-->
+
+# Scripting Overview  {#scriptoverview}
+
+DALi has JSON to support:
+- layouting
+- theme / styling
+- templated actor/control creation
+- basic actions
+- DALi GUI builder generates JSON files. Allows UI designers to create / modify the application look and feel.
+
+JSON support is built in to DALi.
+
+Files can be loaded inside any DALi application, or from command line using the launcher (part of dali-demo).
+
+~~~{.cpp}
+scripting.example hello-world.json
+~~~
+
+We currently have JSON example files held in dali-demo/resources/scripts
+  
+# JSON
+
+JSON file contains different sections:
+- **Templates** actor & control tree creation
+- **Styles** used to style actor & control trees
+- **Animations**
+- **Instances** of objects for path, renderTasks, frameBuffers
+- **Stage**. A list of actors / controls that can be added to the stage
+- **Constants**  (e.g. positions / colors, that can be references by other parts of the JSON file);
+- **Actions**
+  
+## Examples
+
+### JSON templates section
+  
+~~~{.json}
+
+    “templates”:
+    {
+      "name":"users",
+      "type":"Actor",
+      "parentOrigin":"TOP_CENTER",
+      "anchorPoint":"TOP_CENTER",
+      "size":"{DEFAULT_MENU_USER_SIZE}",
+      "colorMode":"USE_OWN_COLOR",
+      "actors":
+      [
+        {
+          "name":"usersBackground",
+          "type":"ImageView",
+          "parentOrigin":"CENTER",
+          "anchorPoint":"CENTER",
+          "size":"{DEFAULT_MENU_USER_SIZE}",
+          "colorMode":"USE_OWN_COLOR",
+          "image":{ "url":"{IMAGE_PATH}white-pixel.png" },
+          "color":"{DEFAULT_MENU_BACKGROUND_COLOR}"
+        },
+        {
+          "name":"icon",
+          "type":"ImageView",
+          "parentOrigin":"TOP_CENTER",
+          "anchorPoint":"TOP_CENTER",
+          "position":[0,41,1],
+          "image":{ "url":"{IMAGE_PATH}ico_man_nor.png" }
+        },
+      ]
+    },
+
+
+~~~
+
+#### C++ example
+
+~~~{.cpp}
+Builder builder = Builder::New();
+
+std::string jsonData = loadFile("my-app.json");
+
+builder.LoadFromString( jsonData );
+
+Actor userActorTree = builder.Create("users");
+~~~
+
+
+### JSON styles section
+
+~~~{.json}
+“styles”:
+  {
+    “live-tv-focus":
+    {
+      "actors":
+      {
+        "background":
+        {
+          "image":{ "filename":"{IMAGE_PATH}live_tv_background.png" },
+          "color":"{DEFAULT_MENU_ITEM_COLOR_1}"
+        },
+        "icon":
+        {
+          "image":{ "filename":"{IMAGE_PATH}icn_live_tv_foc.png" }
+        },
+        "label":
+        {
+          "colorAlpha":1,
+          "text":"<font size='20' weight='bold'><b>LIVE</b></font>"
+        }
+      }
+    },
+  }
+~~~
+
+#### C++ example
+
+~~~{.cpp}
+builder.ApplyStyle( "live-tv-focus", tvIcon );
+~~~
+
+### JSON animations section
+
+~~~{.json}
+"animations":
+  {
+    "animate-show":
+    {
+      "duration":0.5,
+      "properties":
+      [
+        {
+          "actor":"background",
+          "property":"positionX",
+          "value":30,
+          "alphaFunction":"EASE_IN_OUT"
+        },
+        {
+          "actor":"itemsBackground",
+          "property":"colorAlpha",
+          "value":0.85,
+          "timePeriod": {"delay": 0.25, "duration": 0.25 },
+          "alphaFunction":"EASE_IN_OUT"
+        },
+        {
+          "actor":"usersBackground",
+          "property":"colorAlpha",
+          "value":0.85,
+          "timePeriod": {"delay": 0.25, "duration": 0.25 },
+          "alphaFunction":"EASE_IN_OUT"
+        }
+      ]
+    },
+~~~
+
+#### C++ example
+
+~~~{.cpp}
+// C+++
+
+Animation anim = builder.createAnimation( "animate-show", propertyMap );
+~~~
+
+### JSON stage section
+
+~~~{.json}
+
+“stage": [{
+      "name":"simple-table",
+      "type":"TableView",
+      "backgroundColor": [0.5,0.5,0,1],
+      "parentOrigin": "CENTER",
+      "size":[400,500,1],
+      "rows": 4,
+      "columns":4,
+      "cellPadding": [10, 5],
+      "layoutAnimationDuration": 0.5,
+      "layoutRows": {  // set the height of the rows
+        "0": { "policy": "fixed", "value": 40 },
+        "1": { "policy": "relative", "value": 0.33 },
+        "2": { "policy": "fixed", "value": 120 }
+      },
+      "layoutColumns": { // set the widths of the columns
+        "1": { "policy": "fixed", "value": 150 },
+        "2": { "policy": "relative", "value": 0.35 },
+        "3": { "policy": "relative", "value": 0.15 }
+      },
+      "actors": [{
+          "name":"gallery-1",
+          "type":"ImageView",
+          "image": {
+            "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
+            "rowSpan":4, // property to specify how many rows this child occupies, if not set, default value is 1
+            "columnSpan":1 // property to specify how many columns this child occupies
+            ....
+~~~
+
+#### C++ example
+
+~~~{.cpp}
+// add all actors under stage section to the root layer
+builder.AddActors( Stage::GetCurrent().GetRootLayer() );
+~~~
+
+
+*/
diff --git a/docs/content/programming-guide/scroll-view.h b/docs/content/programming-guide/scroll-view.h
new file mode 100644 (file)
index 0000000..f236440
--- /dev/null
@@ -0,0 +1,83 @@
+/*! \page scroll-view Example and Usage
+
+   We will start by showing the steps to creating a ScrollView, adding to the stage, and adding content to the ScrollView.
+
+   Then we look at some of the options to achieve commonly desired ScrollView effects, from ruler snap points to domains.
+
+   \section intro Simple ScrollView setup, and ruler configuration.
+
+   We declare a ScrollView component called myScrollView
+
+   @code
+   Dali::Toolkit::ScrollView myScrollView;
+   @endcode
+
+   A new ScrollView instance is then created by calling the following
+   @code
+   myScrollView = ScrollView::New();
+   @endcode
+
+   We then add it to the stage.
+   @code
+   Stage::GetCurrent().Add(myScrollView);
+   @endcode
+
+   Then we specify the size. We'll make it cover the entire stage
+   @code
+   Stage stage = Dali::Stage::GetCurrent();
+   Size size = stage.GetSize();
+   myScrollView.SetSize( size );
+   @endcode
+
+   Add Actors to this ScrollView
+   @code
+   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).
+
+   To enforce horizontal-only scrolling, the Y-axis ruler can be disabled
+   @code
+   RulerPtr rulerY = new DefaultRuler();
+   rulerY->Disable();
+   myScrollView.SetRulerY(rulerY);
+   @endcode
+
+   To enable snapping, a FixedRuler can be applied to the X-axis, with snap points spaced to the width of the stage.
+   @code
+   Stage stage = Dali::Stage::GetCurrent();
+   Size size = stage.GetSize();
+   RulerPtr rulerX = new FixedRuler(size.width);
+   myScrollView.SetRulerX(rulerX);
+   @endcode
+
+   A domain can be applied to rulers to prevent scrolling beyond this boundary. In this case to 4 times the width of the stage, allowing for 4 pages to be scrolled.
+   @code
+   Stage stage = Dali::Stage::GetCurrent();
+   Size size = stage.GetSize();
+   RulerPtr rulerX = new FixedRuler(size.width);
+   rulerX->SetDomain(RulerDomain(0.0f, size.width*4.0f));
+   myScrollView.SetRulerX(rulerX);
+   @endcode
+
+   Ruler      Domain      Wrap      Behaviour
+   =====      ======      ====      =========
+
+   Disabled   Disabled    No-Wrap   "No Movement in axis"
+   Disabled   Disabled    Wrap      "No Movement in axis"
+   Disabled   Enabled     No-Wrap   "No Movement in axis"
+   Disabled   Enable      Wrap      "No Movement in axis"
+   Enabled    Disabled    No-Wrap   "Free Movement in axis"
+   Enabled    Disabled    Wrap      "Free Movement in axis, but will wrap based on domain min-max"
+   Enabled    Enabled     No-Wrap   "Movement limited to domain min-max"
+   Enabled    Enabled     Wrap      "Movement limited to domain min-max"
+
+   @note It is important to note that Actors within ScrollView are controlled by constraints,
+   and thus undefined behaviour will occur when applying constraints to these Actors externally.
+   If you wish to apply additional constraints that may conflict with the ScrollView's constraints,
+   then it is recommended that you place the Actors within container Actors. So that the container
+   Actors are affected by the constraints.
+
+ */
+
diff --git a/docs/content/programming-guide/shader-intro.h b/docs/content/programming-guide/shader-intro.h
new file mode 100644 (file)
index 0000000..69e0b11
--- /dev/null
@@ -0,0 +1,86 @@
+/*! \page shader-intro Shader Effects
+ *
+ *
+ * <h2 class="pg">Introduction</h2>
+ *
+ * The shader effects allow the developer to apply visual deformations on Image Views.
+ * They can affect the geometry, the colors and textures of the Image View.
+ *
+ * <br>
+ * <br>
+ * <h2 class="pg">Custom Shader Effects</h2>
+ * The custom shader lets the developers create their own shader effects by specifying the vertex and pixel shaders.
+ *
+ * To set a custom shader to ImageVisual you have to pass it through as a Property::Map
+ * @code
+ * //an example vertex shader
+ * const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+ *   attribute mediump vec2 aPosition;\n
+ *   varying mediump vec2 vTexCoord;\n
+ *   uniform mediump mat4 uMvpMatrix;\n
+ *   uniform mediump vec3 uSize;\n
+ *   \n
+ *   void main()\n
+ *   {\n
+ *     mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+ *     vertexPosition.xyz *= uSize;\n
+ *     vertexPosition = uMvpMatrix * vertexPosition;\n
+ *     \n
+ *     vTexCoord = aPosition + vec2(0.5);\n
+ *     gl_Position = vertexPosition;\n
+ *   }\n
+ * );
+ *
+ * //an example fragment shader
+ * const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+ *   varying mediump vec2 vTexCoord;\n
+ *   uniform sampler2D sTexture;\n
+ *   uniform lowp vec4 uColor;\n
+ *   \n
+ *   void main()\n
+ *   {\n
+ *     gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
+ *   }\n
+ * );
+ *
+ * Property::Map customShader;
+ *
+ * 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);
+ *
+ * ImageView imageView = ImageView::New("image-url.png")
+ * imageView.SetProperty(ImageView::Property::IMAGE, map);
+ * @endcode
+ *
+ * Optionally, you can subdivide the grid horizontally or vertically before you add it to the map but you should not do this if a quad is used.
+ * @code
+ * int X_SUB_DIVISIONS = 20;
+ * int Y_SUB_DIVISIONS = 20;
+ * 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(“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”, “outputIsTransparent”);
+ * @endcode
+ *
+ * The value of a uniform can be set on the imageView
+ * @code
+ * // if the uniform was declared like this in the shader: uniform float myUniform;
+ * imageView.RegisterProperty( "myUniform", 0.5f );
+ * @endcode
+ *
+ *
+ */
diff --git a/docs/content/programming-guide/signals-actions.md b/docs/content/programming-guide/signals-actions.md
new file mode 100644 (file)
index 0000000..89a4130
--- /dev/null
@@ -0,0 +1,21 @@
+<!--
+/**-->
+# Signals & Actions {#signals-actions}
+
+## Signals {#signals}
+
+Classes in DALi provide signals which are emitted whenever a certain action or event occurs.
+The application can connect to these signals using if it wishes to be informed of this occurrence.
+Standard C Style functions can be used to connect to these signals if no local data needs to be accessed, otherwise a class method can also be connected.
+
+Applications can manually disconnect from signals when required but DALi also provides safe signal disconnection.
+This means that when the connecting object is deleted, the signal is automatically disconnected.
+
+## Actions {#actions}
+
+Classes in DALi can perform a certain number of actions.
+For example, an animation provides the ability to "play" or "stop" using an action.
+DALi provides a framework which allows users to set up actions for their classes.
+This is particularly helpful when trying to invoke an action using scripting.
+
+*/
diff --git a/docs/content/programming-guide/size-negotiation-controls.h b/docs/content/programming-guide/size-negotiation-controls.h
new file mode 100644 (file)
index 0000000..2f3ac40
--- /dev/null
@@ -0,0 +1,241 @@
+/*! \page size-negotiation-controls Size Negotiation for Controls
+ *
+<h2 class="pg">Overview</h2>
+
+This document details how to create controls using the size negotiation API and is intended for UI control writters. For an introduction to
+size negotiation please see the <i>Size Negotiation Programming Guide</i>.
+
+The topics covered are:
+- The Relayout Controller
+- Resize Policies
+- Creating a Control: Popups
+- Size Negotiation API
+- Creating a Control: TableView
+
+<h2 class="pg">The Relayout Controller</h2>
+
+<h3>Overview</h3>
+The RelayoutController is an object that is private in DALi Core. It's main job is to take relayout requests from actors.
+It can be enabled or disabled internally. If disabled, then all relayout requests are ignored. By default the relayout controller is disabled until just after the
+initial application initialize. This allows the scene for an application to be created without generating many relayout requests. After the application
+has initialized the scene, then the relayout controller is automatically enabled and a relayout request is called on the root of the scene. This request spreads down the scene
+hierarchy and requests relayout on all actors that have size negotiation enabled.
+
+Relayout requests are put in automatically when a property is changed on an actor or a change to the stage hierarchy is made and manual requests are usually not necessary.
+
+<h2 class="pg">Resize Policies</h2>
+
+In addition to the resize policies detailed in the Size Negotiation Programming Guide there is one additional policy available to control writers:
+
+- ResizePolicy::USE_ASSIGNED_SIZE: Tells the actor to use the size that was passed into the size negotiation algorithm for it. This is used in the OnRelayout
+method derived from Actor when passing back controls to be negotiated using the container argument to the method.
+
+<h2 class="pg">Creating a Control: Popups</h2>
+
+<h3>Initialization</h3>
+Size negotiation is enabled on controls by default. If a control is desired to not have size negotiation enabled then simply pass in the
+DISABLE_SIZE_NEGOTIATION flag into the Control constructor.
+
+The other step to perform is to set default resize policies for width and height.
+
+<h3>A Simple Example: Popup</h3>
+
+This example shows how to set up a popup for use with size negotiation. The popup contains a layer to raise it above all other controls,
+a semi-transparent full-screen backing image to dim the screen, a background image with a shadow border, and buttons that are positioned
+and resized by the popup. The following screen shot shows an example popup.
+
+\image html size-negotiation/PopupExample.png
+
+The first step is to set the default resize policies. This is done in the OnInitialize method. In the following snippet the popup
+is set to have a height resize policy of ResizePolicy::FIT_TO_CHILDREN. This assumes that the width of the popup will be specified by the user of
+the popup and that the desired behaviour is to fit the height of the popup to the size of its content.
+@code
+void Popup::OnInitialize()
+...
+Actor self = Self();
+self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
+@endcode
+The popup will use a layer to place its content in. The layer is created and specified to fill the whole screen by using the following command.
+@code
+mLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+@endcode
+A half transparent backing image is added to the layer and told to fill the layer with the following.
+@code
+mBacking.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
+@endcode
+The popup control is added to the layer and a background image is specified to fill the size of the popup and add a border by the following.
+@code
+mBackgroundImage.SetResizePolicy( ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT, Dimension::ALL_DIMENSIONS );
+Vector3 border( mPopupStyle->backgroundOuterBorder.x, mPopupStyle->backgroundOuterBorder.z, 0.0f );
+mBackgroundImage.SetSizeModeFactor( border );
+@endcode
+A table view is added to the popup to specify layout. It will fill to the width of the popup and expand/contract around its children cell heights.
+@code
+mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+@endcode
+Override the OnRelayout method to position and resize the buttons.
+@code
+void Popup::OnRelayout( const Vector2& size, RelayoutContainer& container )
+...
+@endcode
+Another aspect to the popup is that depending which resize policies are active on it then the inner table view requires different resize policies itself.
+OnSetResizePolicy can be overridden to receive notice that the resize policy has changed on the control and action can be taken.
+@code
+void Popup::OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension )
+...
+if( policy == ResizePolicy::FIT_TO_CHILDREN )
+{
+  // Make content fit to children
+  mPopupLayout.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, dimension );
+  if( dimension & Dimension::HEIGHT )
+  {
+    mPopupLayout.SetFitHeight( 1 );
+  }
+}
+else
+{
+  mPopupLayout.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, dimension );
+  // Make the content cell fill the whole of the available space
+  if( dimension & Dimension::HEIGHT )
+  {
+    mPopupLayout.SetRelativeHeight( 1, 1.0f );
+  }
+}
+@endcode
+Popup also implements the following methods for use with the relevant resize policies:
+- GetNaturalSize
+- GetHeightForWidth
+- GetWidthForHeight
+
+<h2 class="pg">Size Negotiation API</h2>
+
+<h3>Base Class Methods</h3>
+
+The base class methods are used to call functionality held in Actor and are defined in CustomActorImpl.
+
+There is a RelayoutRequest method defined. This method is available for deriving controls to call when they would like themselves to be relaid out.
+@code void RelayoutRequest() @endcode
+
+<h3>Overridable Methods</h3>
+These overridable methods in control provide customization points for the size negotiation algorithm.
+
+<h4>Responding to the Change of Size on a Control</h4>
+
+OnRelayout is called during the relayout process at the end of the frame immediately after the new size has been set on the actor. If the actor has calculated
+the size of child actors then add them to container with their desired size and set the ResizePolicy::USE_ASSIGNED_SIZE resize policy on them.
+At this point the size of the actor has been calculated so it is a good place to calculate positions of child actors etc.
+@code virtual void OnRelayout( const Vector2& size, RelayoutContainer& container ) @endcode
+
+The OnRelayoutSignal signal is raised after SetSize and OnRelayout have been called during the relayout processing at the end of the frame. If the control is deriving
+from Control then the OnRelayout virtual is preferred over this signal. The signal is provided for instance when custom code needs to be run on the
+children of an actor that is not a control.
+@code OnRelayoutSignalType& OnRelayoutSignal() @endcode
+
+The OnCalculateRelayoutSize is called right before the size is calculated for an actor's dimension during the size negotiation phase. At this point all other actors this actor is
+dependent on have been negotiated so calculations depending on these actors can be performed before the size for this actor is calculated. Useful for container size calculations.
+@code virtual void OnCalculateRelayoutSize( Dimension::Type dimension ) @endcode
+
+OnLayoutNegotiated is called right after the size in a given dimension has been negotiated for an actor. This allows calculations to be performed in response to the change
+in a given dimension but before OnRelayout is called.
+@code virtual void OnLayoutNegotiated( float size, Dimension::Type dimension ) @endcode
+
+<h4>Calculating Sizes</h4>
+
+Calculate the natural size for this control. This will be called when a control's resize policy is set to USE_NATURAL_SIZE.
+For example, TableView will calculated the size of the table given its various cell properties.
+@code virtual Vector3 GetNaturalSize() @endcode
+
+Given an input width return the correct height for this control. This will be called when the resize policy is set to ResizePolicy::DIMENSION_DEPENDENCY and
+height has a dependency on width.
+@code virtual float GetHeightForWidth( float width ) @endcode
+
+Given the input height return the correct width for this control. This will be called when the resize policy is set to ResizePolicy::DIMENSION_DEPENDENCY and
+width has a dependency on height.
+@code virtual float GetWidthForHeight( float height ) @endcode
+
+<h4>Relayout Dependencies</h4>
+
+Return true from this method if this control is dependent on any of its children to calculate its own size. All relayout containers that can be dependent on their
+children for their own size need to return true from this.
+@code virtual bool RelayoutDependentOnChildren( Dimension::Type dimension = Dimension::ALL_DIMENSIONS ) @endcode
+
+This will be called by children when they are using the ResizePolicy::FILL_TO_PARENT resize policy. It is the parent's responsibility to calculate the child's correct size.
+@code virtual float CalculateChildSize( const Dali::Actor& child, Dimension::Type dimension ) @endcode
+
+<h4>Events</h4>
+
+OnSetResizePolicy is called when the resize policy is set on an actor. Allows deriving actors to respond to changes in resize policy.
+@code virtual void OnSetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) @endcode
+
+<h2 class="pg">Creating a Control: TableView</h2>
+
+This section demonstrates how size negotiation may be used when creating a table view.
+
+First we define some policies for how table row and columns may resize. These are:
+- Fixed: Use a fixed size
+- Relative: Use a ratio size of empty remaining space
+- Fill: Fill up to all remaining space, distributing evenly between all "fill" row or columns
+
+A data structure is defined to hold information for each row and column regarding their cell size policy and their assigned and calculated sizes.
+
+We need to be able to calculate the fixed sizes of all actors placed into table cells. The place to do this is in OnCalculateRelayoutSize. When
+this is called every actor the table view is dependent on has already had their sizes calculated. Calculations can be made that the main calculation
+for the actor can then use.
+@code
+void TableView::OnCalculateRelayoutSize( Dimension::Type dimension )
+...
+CalculateRowColumnData();
+
+if( dimension & Dimension::WIDTH )
+{
+  CalculateFixedSizes( mColumnData, Dimension::WIDTH );
+  mFixedTotals.width = CalculateTotalFixedSize( mColumnData );
+}
+
+if( dimension & Dimension::HEIGHT )
+{
+  CalculateFixedSizes( mRowData, Dimension::HEIGHT );
+  mFixedTotals.height = CalculateTotalFixedSize( mRowData );
+}
+...
+@endcode
+
+An important override is GetNaturalSize. This will simply return the total sum of the fixed cells for each row and column.
+@code
+Vector3 TableView::GetNaturalSize()
+...
+return Vector3( mFixedTotals.width, mFixedTotals.height, 1.0f );
+...
+@endcode
+
+When the time comes to calculate the size of each child in the table cells the following method will be called.
+@code
+float TableView::CalculateChildSize( const Actor& child, Dimension::Type dimension )
+...
+// Use cell data to calculate child size
+@endcode
+
+The table view is dependent on its children if its size policy is set to USE_NATURAL_SIZE or a row or column is set to "fit" an actor.
+The following code shows calling the base class RelayoutDependentOnChildren to check the resize policy and then searches for fit row or columns.
+@code
+bool TableView::RelayoutDependentOnChildren( Dimension::Type dimension )
+{
+  if ( Control::RelayoutDependentOnChildren( dimension ) )
+  {
+    return true;
+  }
+
+  return FindFit( mRowData ) || FindFit( mColumnData );
+}
+@endcode
+
+With the cell sizes already calculated, the job of OnRelayout is to position all the actors in the table view in their respective positions.
+@code
+void TableView::OnRelayout( const Vector2& size, RelayoutContainer& container )
+...
+// Find each actor and position it, taking padding into account
+@endcode
+
+*
+*/
diff --git a/docs/content/programming-guide/size-negotiation.h b/docs/content/programming-guide/size-negotiation.h
new file mode 100644 (file)
index 0000000..9605573
--- /dev/null
@@ -0,0 +1,257 @@
+/*! \page size-negotiation Size Negotiation
+ *
+<h2 class="pg">Overview</h2>
+
+Size negotiation, also known as layout management, is responsible for allocating sizes to all actors on the stage based on rules of dependency between
+the actors. Requests for relayout on actors are collected during the frame with the actual relayout performed at the end of the frame.
+
+This document details how to use the size negotiation API and is intended for application writters.
+
+The topics covered are:
+- Dimensions
+- Resize policies
+- Actor
+- Debugging
+
+<h2 class="pg">Dimensions</h2>
+
+The notion of width and height is generalised into the concept of a Dimension. Several methods take a Dimension parameter.
+
+The Dimension enum specifies the available dimensions as bitfields:
+- Dimension::WIDTH
+- Dimension::HEIGHT
+
+If a method can process width and height at the same time then the Dimension::ALL_DIMENSIONS mask can be specified.
+
+<h2 class="pg">Resize Policies</h2>
+
+<h3>Policies</h3>
+The ResizePolicy enum specifies a range of options for controlling the way actors resize. These are powerful rules that enable much automatic
+resizing behaviour. They are as following:
+
+- ResizePolicy::FIXED: This is the option to use when you want the specific definite size as set by SetSize (This is the default for all actors)
+- ResizePolicy::USE_NATURAL_SIZE: Use this option for objects such as images or text to get their natural size e.g. The dimensions of the image, or the size of the text without wrapping. Also use this on TableViews when the size of the table is dependent on its children.
+- ResizePolicy::FILL_TO_PARENT: Size will fill up to the size of its parent's size, taking a size factor into account to allow proportionate filling
+- ResizePolicy::SIZE_RELATIVE_TO_PARENT: Fill up the parent with a relative scale. Use SetSizeModeFactor to specify the ratio to fill up to the parent.
+- ResizePolicy::SIZE_FIXED_OFFSET_FROM_PARENT: Fill up the parent and add a fixed offset using SetSizeModeFactor.
+- ResizePolicy::FIT_TO_CHILDREN: Size will scale around the size of the actor's children. E.g. A popup's height may resize itself around it's contents.
+- ResizePolicy::DIMENSION_DEPENDENCY: This covers rules such as width-for-height and height-for-width. You specify that one dimension depends on another.
+
+\image html size-negotiation/ResizePolicies.png
+
+<h2 class="pg">Actor</h2>
+
+This section details how an actor may be used with size negotiation.
+
+<h3>Enabling Size Negotiation</h3>
+
+Text and image actors have relayout enabled by default, while a plain Actor is disabled unless a call to SetResizePolicy is made.
+
+<h3>Specifying Size Policies</h3>
+
+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 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 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.
+
+@code
+Actor rootActor = Actor::New();
+rootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+rootActor.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
+Toolkit::ImageView image = Toolkit::ImageView::New( MY_IMAGE_PATH );
+image.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+rootActor.Add( image );
+@endcode
+
+The following images show the before and after layouts for this code example.
+
+Before:
+\image html size-negotiation/SizeNegotiationExample_Before.png
+After:
+\image html size-negotiation/SizeNegotiationExample_After.png
+
+This example shows an actor rootActor set to expand to its parent's width and contract/expand around its child's height. The child image actor
+is set to natural size which means it will display at the acutal size of the image.
+
+To specify that a dimension has a dependency on another dimension use ResizePolicy::DIMENSION_DEPENDENCY. For example if dimension is Dimension::HEIGHT and dependency is
+Dimension::WIDTH then there is a height-for-width dependency in effect. The classic use case for this
+is a text view that wraps its text. The following example snippet shows a text view that expands its width to the size of its parent, wraps its
+contents and then determines its height based on the width.
+@code
+TextLabel text = TextLabel::New( "Example" );
+text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+@endcode
+
+<h3>Specifying Sizes and Size Limits</h3>
+
+When wanting a specific fixed size for an actor then specify the resize policy to be FIXED and set the desired, or preferred size using SetSize.
+If only one dimension is FIXED then the other value in the size parameter will be ignored, so it is safe to set it to zero.
+
+To constrain the final negotiated size of an actor, set the following for minimum and maximum sizes respectively.
+@code
+void SetMinimumSize( const Vector2& size )
+void SetMaximumSize( const Vector2& size )
+@endcode
+
+<h3>Altering Negotiated Size</h3>
+
+When an actor is required to maintain the aspect ratio of its natural size the following method can be used. This is useful for size negotiating images
+to ensure they maintain their aspect ratio while still fitting within the bounds they have been allocated. This can be one of SizeScalePolicy::USE_SIZE_SET, SizeScalePolicy::FIT_WITH_ASPECT_RATIO
+or SizeScalePolicy::FILL_WITH_ASPECT_RATIO. The first is the default. The second will fit the actor within the bounds it has been allocated while maintaining aspect ratio. The
+third will fill all available space, potentially overflowing its bounds, while maintaining apsect ratio.
+@code void SetSizeScalePolicy( SizeScalePolicy::Type policy ) @endcode
+
+<h3>Using Actors in Containers</h3>
+
+When laying out actors in containers such as TableView it is useful to be able to specify padding that surrounds the actor. E.g. You may
+want some white space around an image actor placed in a table cell. The padding specifies the left, right, bottom and top padding values.
+@code void SetPadding( const Padding& padding ) @endcode
+
+<h2 class="pg">An Example</h2>
+
+This section shows a more complex example of how to configure size negotiation. It creates a popup and adds a table view to it with a text view,
+an image and a sub-table. The sub-table contains a checkbox and another text view.
+@code
+mPopup = CreatePopup();
+mPopup.SetTitle( "Warning" );
+
+// Content
+Toolkit::TableView content = Toolkit::TableView::New( 2, 2 );
+content.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+content.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+content.SetFitHeight( 0 );
+content.SetFitHeight( 1 );
+content.SetPadding( Padding( 20.0f, 20.0f, 20.0f, 0.0f ) );
+
+// Text
+Toolkit::TextLabel text = Toolkit::TextLabel::New( "Do you really want to quit?" );
+text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+
+content.AddChild( text, Toolkit::TableView::CellPosition( 0, 0 ) );
+
+// Image
+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 ) );
+content.AddChild( image, Toolkit::TableView::CellPosition( 0, 1 ) );
+
+// Checkbox and text
+Toolkit::TableView root = Toolkit::TableView::New( 1, 2 );
+root.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+root.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+root.SetFitHeight( 0 );
+root.SetFitWidth( 0 );
+root.SetPadding( Padding( 0.0f, 0.0f, 0.0f, 20.0f ) );
+
+Dali::Image unchecked = Dali::ResourceImage::New( CHECKBOX_UNCHECKED_IMAGE );
+Dali::Image checked = Dali::ResourceImage::New( CHECKBOX_CHECKED_IMAGE );
+Toolkit::CheckBoxButton checkBox = Toolkit::CheckBoxButton::New();
+checkBox.SetBackgroundImage( unchecked );
+checkBox.SetSelectedImage( checked );
+checkBox.SetSize( Vector2( 48, 48 ) );
+
+root.AddChild( checkBox, Toolkit::TableView::CellPosition( 0, 0 ) );
+
+Toolkit::TextLabel text2 = Toolkit::TextLabel::New( "Don't show again" );
+text2.SetPadding( Padding( 20.0f, 0.0f, 0.0f, 10.0f ) );
+
+root.AddChild( text2, Toolkit::TableView::CellPosition( 0, 1 ) );
+
+content.AddChild( root, Toolkit::TableView::CellPosition( 1, 0, 0, 2 ) );  // Column span 2
+
+mPopup.Add( content );
+@endcode
+
+The resulting popup with additional buttons added is shown below.
+\image html size-negotiation/Popup.png
+
+The key things to pick out from this example are the use of the size negotiation API.
+The content table view is set to ResizePolicy::FILL_TO_PARENT for its width and USE_NATURAL_SIZE for its height. This will result
+in the table view expanding its width to fit the available space in the popup while also expanding/contracting its
+height based on the size of the contents in its cells.
+@code
+content.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+content.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+@endcode
+To add a little space around the left, right and bottom of the table view, some padding is added.
+@code
+content.SetPadding( Padding( 20.0f, 20.0f, 20.0f, 0.0f ) );
+@endcode
+The first text view has its width set to ResizePolicy::FILL_TO_PARENT and its height has a dimension dependency on its width. This
+will result in a text view that fills up its width to available space in the table cell and then then calculates its
+height based on its new width. The table view will then fit its height taking the height of the text view into account.
+@code
+text.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+@endcode
+The image view performs a similar relayout. It fits its width to the size of the cell and calculates its height based on the new
+width. Some padding is added to the left of it as well to center it more.
+@code
+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 ) );
+@endcode
+The sub table view is similar as well in that it expands its width to the size of its cell. When it is added to the table view it
+will span two columns. Its height is set to natural size so that it will grow or shrink based on its children cells. Note that for
+a container like table view, USE_NATURAL_SIZE acts in a similar manner to ResizePolicy::FIT_TO_CHILDREN in that the size of the container could
+grow or shrink based on the sizes of the child actors.
+@code
+root.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+root.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+@endcode
+The checkbox is set to have a fixed size.
+@code
+checkBox.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
+@endcode
+The second text view has not specified a resize policy so will use its default of USE_NATURAL_SIZE.
+
+<h2 class="pg">Debugging</h2>
+
+When constructing large scenes using interacting resize policies it is useful to be able to debug the relayout process. The following sections
+describe a pitfall to avoid when creating scenes and a way to print debug output about the actors.
+
+<h3>Infinite Dependency Loops</h3>
+Despite the power of the resize rules there is one pitfall to be aware of: infinite dependency loops. The most simplest form of this is
+shown by a parent actor with resize policy set to ResizePolicy::FIT_TO_CHILDREN with a child that has a resize policy of ResizePolicy::FILL_TO_PARENT. Who should
+determine the size in this case? A more complex loop occurs when ResizePolicy::DIMENSION_DEPENDENCY comes into play. Say a parent has a width policy
+of ResizePolicy::DIMENSION_DEPENDENCY with height and a height policy of ResizePolicy::FIT_TO_CHILDREN. The parent has a single child with a height policy ResizePolicy::DIMENSION_DEPENDENCY
+with width. If the child's width policy is ResizePolicy::FILL_TO_PARENT then a loop will occur. These are two simple examples but the loops could occur
+over larger spreads of parent child relationships. These loops are detected by the relayout algorithm with the result being that actors will
+receive zero sizes. These loops are not common but are still something to watch out for.
+
+<h3 class="pg">Inspecting Actor Relayout Properties</h3>
+To get a print out of the stage hierarchy before and after negotiation, with a list of actors that were negotiated set the LOG_RELAYOUT_CONTROLLER environment variable to 3,true.
+
+E.g. On desktop run:
+
+$  LOG_RELAYOUT_CONTROLLER=3,true dali-demo
+
+Example output from the logging is as follows:
+
+PushButton, OKAY_BUTTON - Pos: [185, 0, 0.1] Size: [165, 76, 76], Dirty: (FALSE,FALSE), Negotiated: (TRUE,TRUE), Enabled: TRUE, (0x1649850)
+
+The format is as follows:
+
+[Actor type], [Actor name] ? Pos:[X, Y, Z] Size[Dimension::WIDTH, Dimension::HEIGHT, DEPTH], Dirty:(Dimension::WIDTH, Dimension::HEIGHT), Negotiated: (Dimension::WIDTH, Dimension::HEIGHT), Enabled: BOOLEAN, (Object address)
+- <i>Actor type</i>: The type name of the actor E.g. PushButton
+- <i>Actor name</i>: The name set on the actor with SetName(). Useful for debugging.
+- <i>Pos</i>: The position of the actor
+- <i>Size</i>: The current size of the actor. Check this to see if the actor has been negotiated correctly.
+- <i>Dirty</i>: Booleans to say if the width or height has been marked as dirty by the relayout dirty flag propagation algorithm
+- <i>Negotiated</i>: Booleans to say if the width or height has been negotiated by the size negotiation algorithm
+- <i>Enabled</i>: Boolean to say if the actor is enabled for size negotitation
+- <i>Object address</i>: The address of the actor object in memory
+*
+*/
diff --git a/docs/content/programming-guide/stage-hand.md b/docs/content/programming-guide/stage-hand.md
new file mode 100644 (file)
index 0000000..8193c58
--- /dev/null
@@ -0,0 +1,167 @@
+<!--
+/**-->
+
+# Stagehand Visual Debugger for DALi {#stagehand}
+
+![ ](blocks.png)
+
+## Introduction
+
+Stagehand  is an open source tool that allows a developer to:
+
+- Connect to a DALi application running on:
+ - Tizen
+ - Ubuntu
+- View a wireframe of the current scene on top of a screen shot
+- Modify properties in the scene
+- Monitor performance of the application
+
+  
+Full source code is available from http://github.com/gamoeba/stagehand.git
+
+Stagehand is released under the Apache 2 licence.
+
+## Installing StageHand on Ubuntu
+
+http://www.gamoeba.com/stagehand/
+
+Install both files on the website. Start with the QT dependencies first.
+
+
+## How it works
+
+Stagehand connects to DALi via the network using a TCP/IP connection.
+  
+![ ](inner-workings.png)
+
+## Connecting Stagehand to your DALi application
+
+### Preparing DALi
+
+Stagehand connects to DALi via network using a TCP/IP connection, to enable this, your dali-adaptor RPM must be built with a configure option: `--enable-networklogging`
+
+Here is an example dali-adaptor configure line:
+~~~
+$ CXXFLAGS="-g -O0 -Wno-unused-local-typedefs" CXX="ccache g++" ./configure --prefix=$DESKTOP_PREFIX --enable-debug=yes --enable-profile=UBUNTU --enable-networklogging
+~~~
+
+Once this RPM is installed, you can run your DALi application and connect Stagehand to it.
+  
+
+### Network setup
+
+To enable network control on DALi, an environment variable must be set:
+
+~~~
+$ export DALI_NETWORK_CONTROL=1 to enable
+~~~
+Or run the application with the variable set.
+~~~
+$ DALI_NETWORK_CONTROL=1 /usr/apps/com.samsung.dali-demo/bin/dali-demo
+~~~
+
+Check what network port the application is using. It will be from port 3031 onwards.
+  
+If running DALi on desktop, just type netstat -tlnp. On Tizen log into the device and run netstat. E.g.
+~~~
+$ su
+
+$ netstat -tlpn
+~~~
+
+![ ](netstat.png)
+
+
+### Connecting with Stagehand
+
+Click the settings icons below
+  
+![ ](stagehand-settings.png)
+
+
+### Connecting to DALi running on Tizen
+
+Here we are connecting to a device running SDB
+  
+![ ](stagehand-tizen-connection.png)
+
+### Connect to DALi running on Desktop ( Ubuntu )
+  
+![ ](stagehand-ubuntu-connection.png)
+
+## Using Stagehand
+
+Click Refresh to load the current scene from the device.
+  
+![ ](stagehand-refesh.png)
+
+Click screen shot to get overlay current screen
+  
+![ ](stagehand-screenshot.png)
+
+To cycle through the actor hierarchy, keep clicking the same spot. Alternatively, select using the actor tree.
+
+  
+![ ](stagehand-mainscreen.png)
+
+
+Click the save icon to save the scene
+  
+![ ](stagehand-save.png)
+
+Zooming in and out
+  
+![ ](stagehand-zoom.png)
+
+Modifying the scene
+  
+![ ](stagehand-modify.png)
+
+## Performance monitoring
+
+To enable performance option. Edit
+  
+~/.stagehand/stagehand.ini
+  
+Set perfmode=on
+
+Restart application. Click performance
+  
+![ ](stagehand-performance.png)
+
+## Trouble shooting
+
+You can manually check the network is enabled on the DALi application using netcat.
+
+In the example below we are connecting to a Tizen device using SDB port forwarding.
+  
+After running nc localhost 3031 we type help
+  
+![ ](stagehand-netcat.png)
+
+
+## Tizen smack
+
+
+If you can't connect to a DALi application, but using netstat you can see a port is open.
+  
+Check the smack log for errors:
+~~~
+tail -f -n 10 /var/log/audit/audit.log | grep 'internet'
+~~~
+
+If it is being blocked, you temporarily enable it by editing:
+  
+~~~
+ /etc/smack/accesses2.d/ your-app-name
+
+then add: system::user_internet …..app-name rw
+~~~
+## Tizen Emulator connection problem
+
+
+Make sure  DALi application is run using launch_app:
+~~~
+launch_app [APP_ID] __AUL_SDK__ DEBUG __DLP_DEBUG_ARG__ :10003
+~~~
+
diff --git a/docs/content/programming-guide/styling.h b/docs/content/programming-guide/styling.h
new file mode 100644 (file)
index 0000000..f28eb47
--- /dev/null
@@ -0,0 +1,72 @@
+/*! \page styling Styling
+ *
+@section styling-controls Styling Controls
+
+DALi Controls can be styled to look and behaviour differently.
+
+There are 2 ways to style a control, 1 is recommended.
+
+1) json markup in one of the style files.
+
+~~~
+      ...
+      "control":
+      {
+        "filename":"{IMAGES}file_name.png"
+      },
+      ...
+~~~
+
+or 2) via code using SetProperty
+
+@code
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+control.SetProperty( Control::BACKGROUND, "file_name.png" );
+@endcode
+
+By setting the properties in the json file and not in code it prevents the need to edit code and recompile if changes required.
+
+In the example above, if the png file needs to be changed, method 1 only requires the json file to be changed and no actual code change.
+
+@section choosing-style-at-build Choosing Style files at build time
+
+When building for a target, a style selector should be specified.
+
+The selectors are resolution biased e.g; 720 and 480.
+
+Below can be added to configure to select a style
+
+@code
+./configure --with-style=480
+@endcode
+
+@code
+./configure --with-style=720
+@endcode
+
+
+or for gbs the below define added to the build command
+
+@code
+--define "dali_style 480x800"
+@endcode
+
+@section resources-for-styling Style specific resources
+
+Each style selector can have resource folders associated with it.
+
+Images for that style should be in their own folder named images.
+
+Common images not specific for a particular style will be in the images-common folder located in the style folder.
+
+All application resources are stored in a defined path (application resource path), from this path sub directories can be specified.
+
+The application resource path  can be retrieved using Application::GetResourcePath()
+
+Alternatively to supply resource paths in json the following constant is available: APPLICATION_RESOURCE_PATH.
+
+It provides the path to the  application resource root folder, from there the filename can an be specified along with any sub folders, e.g Images, Models etc.
+
+
+*
+*/
diff --git a/docs/content/programming-guide/text-auto-scrolling.md b/docs/content/programming-guide/text-auto-scrolling.md
new file mode 100644 (file)
index 0000000..bc37279
--- /dev/null
@@ -0,0 +1,61 @@
+<!--
+/**-->
+
+# Text auto scrolling {#text-auto-scrolling}
+
+## Overview
+
+Auto TextLabel scrolling enables the text to scroll within the control, it can be used if text exceeds the boundary of the control hence showing the full content.
+It will also scroll text that is smaller than the control and ensure the same bit of text is not visible at the same time, this gap can be configured to be larger.
+
+If the number of loops (repetitions) is not set then once triggered to start it will scroll until requested to stop.
+If loop count is set to 3 for example it will scroll the text 3 times.
+
+![ ](AutoScroll.gif)
+
+### Usage
+
+At version 1.1.35 auto scrolling is only supported in single line, multiline text will not scroll and Text should be BEGIN aligned.
+
+The ENABLE_AUTO_SCROLL property should be set to TRUE to enable scrolling.
+
+The scroll speed, gap and loop count can be set in the stylesheet or provided by Dali::Handle::SetProperty. See the description of each below.
+
+Once enabled it will start scrolling until the loop count is completed or the ENABLE_AUTO_SCROLL set to false, setting ENABLE_AUTO_SCROLL to false will let the
+text complete it's current scrolling loop then stop.
+
+## The additional properties below can be set to customize the scrolling behaviour
+
+#### AUTO_SCROLL_SPEED
+
+This controls the speed of the scrolling, the speed should be provided as pixels/second.
+
+#### AUTO_SCROLL_LOOP_COUNT
+
+This specifies how many times the text will complete a full scroll cycle.
+If not set then it will keep scrolling until ENABLE_AUTO_SCROLL is set to false.
+
+Setting ENABLE_AUTO_SCROLL to false will stop scrolling whilst still maintaining the original loop count value for when it is next started.
+
+#### AUTO_SCROLL_GAP
+
+This specifies the amount of whitespace to display before the scrolling text is shown again.
+
+This will be increased if the given value is not large enough to prevent the same bit of text being visible at two locations in the control.
+
+Provide the distance in pixels.
+
+### Scroll Direction
+
+The scroll direction is chosen automatically with the following rules:
+
+If the text is single-lined it will scroll left when the text is Left to Right (LTR) or scroll right if text is Right to Left (RTL).
+
+If the text is multi-lined it will scroll upwards. ( Not supported at 1.1.35 )
+
+### Text Label Scrolling Properties
+
+The properties used by TextLabel for Auto Scrolling are listed [here](@ref TextLabelProperties)
+
+
+*/
diff --git a/docs/content/programming-guide/text-editor.md b/docs/content/programming-guide/text-editor.md
new file mode 100644 (file)
index 0000000..f038054
--- /dev/null
@@ -0,0 +1,117 @@
+<!--
+/**-->
+
+# Text Editor {#text-editor}
+
+## Overview
+
+The Dali::Toolkit::TextEditor is a control which provides a multi-line editable text.
+
+### Basic usage
+
+Add the text-editor to the stage.
+
+~~~{.cpp}
+// C++
+
+TextEditor editor = TextEditor::New();
+
+Stage::GetCurrent().Add( editor );
+~~~
+
+When the TextEditor is tapped, it will automatically gain the keyboard focus. Key events will then result in text being inserted.
+After text has been entered, it can be retrieved from the TEXT property.
+
+~~~{.cpp}
+// C++
+
+Property::Value editorText = editor.GetProperty( TextEditor::Property::TEXT );
+std::cout << "Received text: " << editorText.Get< std::string >() << std::endl;
+~~~
+
+### Font Selection
+
+By default TextEditor will automatically select a suitable font from the platform. However, a different font could be selected. See the [Font Selection](@ref font-selection) section for more details.
+
+### Mark-up Style
+
+Mark-up tags can be used to change the style of the text. See the [Mark-up Style](@ref markup-style) section for more details.
+
+### Input Style
+
+The input style can be changed through the control properties.See the [Input Style](@ref input-style) section for more details.
+
+### Text Alignment
+
+TextEditor displays a multi-line of text, which will scroll if there is not enough room for the text displayed.
+If there is enough room, then the text can be aligned horizontally to the beginning, end, or center of the available area:
+
+~~~{.cpp}
+// C++
+
+editor.SetProperty( TextEditor::Property::HORIZONTAL_ALIGNMENT, "BEGIN" ); // "CENTER" or "END"
+~~~
+
+### Copy and Paste  (Selection)
+
+Text can be selected by a long press or double tapping it. See the [Copy and Paste](@ref copy-n-paste) section for more details.
+
+### TextEditor Decorations
+
+#### Color
+
+To change the color of the text, the recommended way is to use the TEXT_COLOR property.
+
+~~~{.cpp}
+// C++
+editor.SetProperty( TextEditor::Property::TEXT_COLOR, Color::CYAN );
+~~~
+
+### TextEditor Properties
+
+ Name (JSON)                       |  Name (C++)                          |  Type        | Writable     | Animatable
+-----------------------------------|--------------------------------------|--------------|--------------|-----------
+ renderingBackend                  | RENDERING_BACKEND                    |  INTEGER     | O            | X
+ text                              | TEXT                                 |  STRING      | O            | X
+ textColor                         | TEXT_COLOR                           |  VECTOR4     | O            | X
+ fontFamily                        | FONT_FAMILY                          |  STRING      | O            | X
+ fontStyle                         | FONT_STYLE                           |  STRING      | O            | X
+ pointSize                         | POINT_SIZE                           |  FLOAT       | O            | X
+ horizontalAlignment               | HORIZONTAL_ALIGNMENT                 |  STRING      | O            | X
+ verticalAlignment                 | VERTICAL_ALIGNMENT                   |  STRING      | O            | X
+ scrollThreshold                   | SCROLL_THRESHOLD                     |  FLOAT       | O            | X
+ scrollSpeed                       | SCROLL_SPEED                         |  FLOAT       | O            | X
+ primaryCursorColor                | PRIMARY_CURSOR_COLOR                 |  VECTOR4     | O            | X
+ secondaryCursorColor              | SECONDARY_CURSOR_COLOR               |  VECTOR4     | O            | X
+ enableCursorBlink                 | ENABLE_CURSOR_BLINK                  |  BOOLEAN     | O            | X
+ cursorBlinkInterval               | CURSOR_BLINK_INTERVAL                |  FLOAT       | O            | X
+ cursorBlinkDuration               | CURSOR_BLINK_DURATION                |  FLOAT       | O            | X
+ cursorWidth                       | CURSOR_WIDTH                         |  INTEGER     | O            | X
+ grabHandleImage                   | GRAB_HANDLE_IMAGE                    |  STRING      | O            | X
+ grabHandlePressedImage            | GRAB_HANDLE_PRESSED_IMAGE            |  STRING      | O            | X
+ selectionHandleImageLeft          | SELECTION_HANDLE_IMAGE_LEFT          |  STRING      | O            | X
+ selectionHandleImageRight         | SELECTION_HANDLE_IMAGE_RIGHT         |  STRING      | O            | X
+ selectionHandlePressedImageLeft   | SELECTION_HANDLE_PRESSED_IMAGE_LEFT  |  STRING      | O            | X
+ selectionHandlePressedImageRight  | SELECTION_HANDLE_PRESSED_IMAGE_RIGHT |  STRING      | O            | X
+ selectionHandleMarkerImageLeft    | SELECTION_HANDLE_MARKER_IMAGE_LEFT   |  MAP         | O            | X
+ selectionHandleMarkerImageRight   | SELECTION_HANDLE_MARKER_IMAGE_RIGHT  |  MAP         | O            | X
+ selectionHighlightColor           | SELECTION_HIGHLIGHT_COLOR            |  VECTOR4     | O            | X
+ decorationBoundingBox             | DECORATION_BOUNDING_BOX              |  RECTANGLE   | O            | X
+ enableMarkup                      | ENABLE_MARKUP                        |  BOOLEAN     | O            | X
+ inputColor                        | INPUT_COLOR                          |  VECTOR4     | O            | X
+ inputFontFamily                   | INPUT_FONT_FAMILY                    |  STRING      | O            | X
+ inputFontStyle                    | INPUT_FONT_STYLE                     |  STRING      | O            | X
+ inputPointSize                    | INPUT_POINT_SIZE                     |  FLOAT       | O            | X
+ lineSpacing                       | LINE_SPACING                         |  FLOAT       | O            | X
+ inputLineSpacing                  | INPUT_LINE_SPACING                   |  FLOAT       | O            | X
+ underline                         | UNDERLINE                            |  STRING      | O            | X
+ inputUnderline                    | INPUT_UNDERLINE                      |  STRING      | O            | X
+ shadow                            | SHADOW                               |  STRING      | O            | X
+ inputShadow                       | INPUT_SHADOW                         |  STRING      | O            | X
+ emboss                            | EMBOSS                               |  STRING      | O            | X
+ inputEmboss                       | INPUT_EMBOSS                         |  STRING      | O            | X
+ outline                           | OUTLINE                              |  STRING      | O            | X
+ inputOutline                      | INPUT_OUTLINE                        |  STRING      | O            | X
+
+
+*/
diff --git a/docs/content/programming-guide/text-field.md b/docs/content/programming-guide/text-field.md
new file mode 100644 (file)
index 0000000..3a3188f
--- /dev/null
@@ -0,0 +1,129 @@
+<!--
+/**-->
+
+# Text Field {#text-field}
+
+## Overview
+
+The Dali::Toolkit::TextField is a control which provides a single-line editable text field.
+
+### Basic usage
+
+Before any text has been entered, the TextField can display some placeholder text.
+An alternative placeholder can be displayed when the TextField has keyboard focus.
+For example a TextField used to enter a user name could initially show "Unknown Name", and then show "Enter Name." when the cursor is shown.
+
+Note *CR+LF* new line characters are replaced by a *LF* one.
+
+~~~{.cpp}
+// C++
+
+TextField field = TextField::New();
+field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Unnamed Name" );
+field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_FOCUSED, "Enter Name." );
+
+Stage::GetCurrent().Add( field );
+~~~
+
+When the TextField is tapped, it will automatically gain the keyboard focus. Key events will then result in text being inserted, and the placeholder text will be removed.
+After text has been entered, it can be retrieved from the TEXT property.
+
+~~~{.cpp}
+// C++
+
+Property::Value fieldText = field.GetProperty( TextField::Property::TEXT );
+std::cout << "Received text: " << fieldText.Get< std::string >() << std::endl;
+~~~
+
+### Font Selection
+
+By default TextField will automatically select a suitable font from the platform. However, a different font could be selected. See the [Font Selection](@ref font-selection) section for more details.
+
+### Mark-up Style
+
+Mark-up tags can be used to change the style of the text. See the [Mark-up Style](@ref markup-style) section for more details.
+
+### Input Style
+
+The input style can be changed through the control properties. See the [Input Style](@ref input-style) section for more details.
+
+### Text Alignment
+
+TextField displays a single-line of text, which will scroll if there is not enough room for the text displayed.
+If there is enough room, then the text can be aligned horizontally to the beginning, end, or center of the available area:
+
+~~~{.cpp}
+// C++
+
+field.SetProperty( TextField::Property::HORIZONTAL_ALIGNMENT, "BEGIN" ); // "CENTER" or "END"
+~~~
+
+### Copy and Paste  (Selection)
+
+Text can be selected by a long press or double tapping it. See the [Copy and Paste](@ref copy-n-paste) section for more details.
+
+### TextField Decorations
+
+#### Color
+
+To change the color of the text, the recommended way is to use the TEXT_COLOR property.
+An alternative color can be used for placeholder text by setting PLACEHOLDER_TEXT_COLOR.
+Note that unlike the Actor::COLOR property, these properties will not affect child Actors added to the TextField.
+
+~~~{.cpp}
+// C++
+field.SetProperty( TextField::Property::TEXT_COLOR, Color::CYAN );
+field.SetProperty( TextField::Property::PLACEHOLDER_TEXT_COLOR, Color::BLACK );
+~~~
+
+### Text Field Properties
+
+ Name (JSON)                       |  Name (C++)                          |  Type        | Writable     | Animatable
+-----------------------------------|--------------------------------------|--------------|--------------|-----------
+ renderingBackend                  | RENDERING_BACKEND                    |  INTEGER     | O            | X
+ text                              | TEXT                                 |  STRING      | O            | X
+ placeholderText                   | PLACEHOLDER_TEXT                     |  STRING      | O            | X
+ placeholderTextFocused            | PLACEHOLDER_TEXT_FOCUSED             |  STRING      | O            | X
+ fontFamily                        | FONT_FAMILY                          |  STRING      | O            | X
+ fontStyle                         | FONT_STYLE                           |  STRING      | O            | X
+ pointSize                         | POINT_SIZE                           |  FLOAT       | O            | X
+ maxLength                         | MAX_LENGTH                           |  INTEGER     | O            | X
+ exceedPolicy                      | EXCEED_POLICY                        |  INTEGER     | O            | X
+ horizontalAlignment               | HORIZONTAL_ALIGNMENT                 |  STRING      | O            | X
+ verticalAlignment                 | VERTICAL_ALIGNMENT                   |  STRING      | O            | X
+ textColor                         | TEXT_COLOR                           |  VECTOR4     | O            | X
+ placeholderTextColor              | PLACEHOLDER_TEXT_COLOR               |  VECTOR4     | O            | X
+ primaryCursorColor                | PRIMARY_CURSOR_COLOR                 |  VECTOR4     | O            | X
+ secondaryCursorColor              | SECONDARY_CURSOR_COLOR               |  VECTOR4     | O            | X
+ enableCursorBlink                 | ENABLE_CURSOR_BLINK                  |  BOOLEAN     | O            | X
+ cursorBlinkInterval               | CURSOR_BLINK_INTERVAL                |  FLOAT       | O            | X
+ cursorBlinkDuration               | CURSOR_BLINK_DURATION                |  FLOAT       | O            | X
+ cursorWidth                       | CURSOR_WIDTH                         |  INTEGER     | O            | X
+ grabHandleImage                   | GRAB_HANDLE_IMAGE                    |  STRING      | O            | X
+ grabHandlePressedImage            | GRAB_HANDLE_PRESSED_IMAGE            |  STRING      | O            | X
+ scrollThreshold                   | SCROLL_THRESHOLD                     |  FLOAT       | O            | X
+ scrollSpeed                       | SCROLL_SPEED                         |  FLOAT       | O            | X
+ selectionHandleImageLeft          | SELECTION_HANDLE_IMAGE_LEFT          |  STRING      | O            | X
+ selectionHandleImageRight         | SELECTION_HANDLE_IMAGE_RIGHT         |  STRING      | O            | X
+ selectionHandlePressedImageLeft   | SELECTION_HANDLE_PRESSED_IMAGE_LEFT  |  STRING      | O            | X
+ selectionHandlePressedImageRight  | SELECTION_HANDLE_PRESSED_IMAGE_RIGHT |  STRING      | O            | X
+ selectionHandleMarkerImageLeft    | SELECTION_HANDLE_MARKER_IMAGE_LEFT   |  MAP         | O            | X
+ selectionHandleMarkerImageRight   | SELECTION_HANDLE_MARKER_IMAGE_RIGHT  |  MAP         | O            | X
+ selectionHighlightColor           | SELECTION_HIGHLIGHT_COLOR            |  VECTOR4     | O            | X
+ decorationBoundingBox             | DECORATION_BOUNDING_BOX              |  RECTANGLE   | O            | X
+ inputMethodSettings               | INPUT_METHOD_SETTINGS                |  MAP         | O            | X
+ inputColor                        | INPUT_COLOR                          |  VECTOR4     | O            | X
+ enableMarkup                      | ENABLE_MARKUP                        |  BOOLEAN     | O            | X
+ inputFontFamily                   | INPUT_FONT_FAMILY                    |  STRING      | O            | X
+ inputFontStyle                    | INPUT_FONT_STYLE                     |  STRING      | O            | X
+ inputPointSize                    | INPUT_POINT_SIZE                     |  FLOAT       | O            | X
+ underline                         | UNDERLINE                            |  STRING      | O            | X
+ inputUnderline                    | INPUT_UNDERLINE                      |  STRING      | O            | X
+ shadow                            | SHADOW                               |  STRING      | O            | X
+ inputShadow                       | INPUT_SHADOW                         |  STRING      | O            | X
+ emboss                            | EMBOSS                               |  STRING      | O            | X
+ inputEmboss                       | INPUT_EMBOSS                         |  STRING      | O            | X
+ outline                           | OUTLINE                              |  STRING      | O            | X
+ inputOutline                      | INPUT_OUTLINE                        |  STRING      | O            | X
+
+*/
diff --git a/docs/content/programming-guide/text-label.md b/docs/content/programming-guide/text-label.md
new file mode 100644 (file)
index 0000000..4629482
--- /dev/null
@@ -0,0 +1,268 @@
+<!--
+/**-->
+
+# Text Label {#text-label}
+
+## Overview
+
+The Dali::Toolkit::TextLabel is a Dali::Toolkit::Control which renders a short text string.  
+Text labels are lightweight, non-editable and do not respond to user input.
+
+### Basic usage
+
+To display a TextLabel the TEXT property must be set using a UTF-8 string.
+
+Note *CR+LF* new line characters are replaced by a *LF* one.
+
+~~~{.cpp}
+// C++
+
+TextLabel label = TextLabel::New();
+label.SetProperty( TextLabel::Property::TEXT, "Hello World" );
+label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+Stage::GetCurrent().Add( label );
+~~~
+
+The label must also be added to the stage, or to an actor which is on the stage.  
+The position of the label on-screen is dependent on the parentOrigin and anchorPoint properties.  
+
+|  |  |
+|--|--|
+| (ParentOrigin::TOP_LEFT, AnchorPoint::TOP_LEFT) | ![ ](TextLabelTopLeft.png)   |
+
+### Font Selection
+
+By default TextLabel will automatically select a suitable font from the platform. However, a different font could be selected. See the [Font Selection](@ref font-selection) section for more details.
+
+### Mark-up Style
+
+Mark-up tags can be used to change the style of the text. See the [Mark-up Style](@ref markup-style) section for more details.
+
+### Text Alignment
+
+Wrapping can be enabled using the MULTI_LINE property:
+
+~~~{.cpp}
+// C++
+
+label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+~~~
+
+The text can be either aligned horizontally to the beginning, end, or center of the available area:
+
+~~~{.cpp}
+// C++
+
+label.SetProperty( TextLabel::Property::HORIZONTAL_ALIGNMENT, "BEGIN" ); // "CENTER" or "END"
+~~~
+
+|  |  |
+|--|--|
+| Here is the "BEGIN" alignment shown for left-to-right (Latin)   |  right-to-left (Arabic) scripts |
+| ![ ](LatinBegin.png) | ![ ](ArabicBegin.png) |
+| Here is the "CENTER" alignment shown for left-to-right (Latin)  | right-to-left (Arabic) scripts:|
+| ![ ](LatinCenter.png) | ![ ](ArabicCenter.png) |
+| Here is the "END" alignment shown for left-to-right (Latin)  | right-to-left (Arabic) scripts:|
+| ![ ](LatinEnd.png) | ![ ](ArabicEnd.png) |
+
+
+
+The text's alignment and order can be modified to match the direction of the system language.
+
+If the MATCH_SYSTEM_LANGUAGE_DIRECTION property is set to true then the direction of the text is ignored, instead the text is aligned and ordered as the system default language.
+
+~~~{.cpp}
+// C++
+
+label.SetProperty( Toolkit::DevelTextLabel::Property::MATCH_SYSTEM_LANGUAGE_DIRECTION, true );
+~~~
+
+|  |  |
+|--|--|
+| Current system language direction left-to-right | |
+| MATCH_SYSTEM_LANGUAGE_DIRECTION set to TRUE. | MATCH_SYSTEM_LANGUAGE_DIRECTION set to FALSE (default). |
+| BEGIN alignment | BEGIN alignment  |
+| ![ ](HelloWorld-System-BEGIN.png) | ![ ](HelloWorld-Default-BEGIN.png) |
+| CENTER alignment | CENTER alignment  |
+| ![ ](HelloWorld-System-CENTER.png) | ![ ](HelloWorld-Default-CENTER.png) |
+| END alignment | END alignment  |
+| ![ ](HelloWorld-System-END.png) | ![ ](HelloWorld-Default-END.png) |
+
+
+|  |  |
+|--|--|
+| Current system language direction left-to-right | Current system language direction right-to-left |
+| ![ ](LTR_order.png)  | ![ ](RTL_order.png) |
+
+
+The examples above assume that the TextLabel size greater than the minimum required.  
+The next section provides details about the other size related options.
+
+## Negotiating size
+
+\link size-negotiation Size negotiation \endlink is a layouting feature supported by UI controls such as TextLabel.
+  
+There are several resize policies which are commonly used with TextLabels.
+  
+The following examples show TextLabels actual size by setting a colored background, whilst the black area represents the size of the parent control:  
+
+### Using natural size
+
+With a "natural" size TextLabel will be large enough to display the text without wrapping, and will not have extra space to align the text within.  
+Therefore in this example the same result would be displayed, regardless of the alignment or multi-line properties.  
+
+~~~{.cpp}
+// C++
+
+TextLabel label = TextLabel::New( "Hello World" );
+label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+label.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
+label.SetBackgroundColor( Color::BLUE );
+Stage::GetCurrent().Add( label );
+~~~
+
+
+ ![ ](HelloWorld-NaturalSize.png)
+
+
+### Height-for-width negotiation
+
+To layout text labels vertically, a fixed (maximum) width should be provided by the parent control.  
+Each TextLabel will then report a desired height for the given width.  
+Here is an example of this behavior using TableView as the parent:
+
+~~~{.cpp}
+// C++
+TableView parent = TableView::New( 3, 1 );
+parent.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+parent.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::HEIGHT );
+parent.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+Stage::GetCurrent().Add( parent );
+
+TextLabel label = TextLabel::New( "Hello World" );
+label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+label.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+label.SetBackgroundColor( Color::BLUE );
+parent.AddChild( label, TableView::CellPosition( 0, 0 ) );
+parent.SetFitHeight( 0 );
+
+label = TextLabel::New( "A Quick Brown Fox Jumps Over The Lazy Dog" );
+label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+label.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+label.SetBackgroundColor( Color::GREEN );
+label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+parent.AddChild( label, TableView::CellPosition( 1, 0 ) );
+parent.SetFitHeight( 1 );
+
+label = TextLabel::New( "لإعادة ترتيب الشاشات، يجب تغيير نوع العرض إلى شبكة قابلة للتخصيص." );
+label.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
+label.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
+label.SetBackgroundColor( Color::BLUE );
+label.SetProperty( TextLabel::Property::MULTI_LINE, true );
+parent.AddChild( label, TableView::CellPosition( 2, 0 ) );
+parent.SetFitHeight( 2 );
+~~~
+
+ ![ ](HelloWorld-HeightForWidth.png)
+
+
+Note that the "Hello World" text label (above) has been given the full width, not the natural width.
+
+### TextLabel Decorations
+
+#### Color
+
+To change the color of the text, the recommended way is to use the TEXT_COLOR property.  
+Note that unlike the Actor::COLOR property, this will not affect child Actors added to the TextLabel.  
+
+~~~{.cpp}
+// C++
+label.SetProperty( TextLabel::Property::TEXT, "Red Text" );
+label.SetProperty( TextLabel::Property::TEXT_COLOR, Color::RED );
+~~~
+
+ ![ ](RedText.png)
+
+#### Drop Shadow
+
+To add a drop-shadow to the text, simply set the SHADOW property. Shadow parameters can be set through a json string or through a property map, see the examples below.
+
+~~~{.cpp}
+ // C++
+
+stage.SetBackgroundColor( Color::BLUE );
+
+label1.SetProperty( TextLabel::Property::TEXT, "Plain Text" );
+
+label2.SetProperty( TextLabel::Property::TEXT, "Text with Shadow" );
+label2.SetProperty( TextLabel::Property::SHADOW, "{\"offset\":\"1 1\",\"color\":\"black\"}" );
+
+label3.SetProperty( TextLabel::Property::TEXT, "Text with Bigger Shadow" );
+label3.SetProperty( TextLabel::Property::SHADOW, "{\"offset\":\"2 2\",\"color\":\"black\"}" );
+
+label4.SetProperty( TextLabel::Property::TEXT, "Text with Color Soft Shadow" );
+
+Property::Map shadow;
+shadow.Insert( "offset", Vector2(1.0f, 1.0f) );
+shadow.Insert( "color", Color::RED );
+shadow.Insert( "blurRadius", 2.0f ); // A value of 0 indicates no blur. The bigger the radius, the more blurry.
+label4.SetProperty( TextLabel::Property::SHADOW, shadow );
+
+~~~
+
+![ ](PlainText.png)
+
+
+![ ](TextWithShadow.png)
+
+![ ](TextWithBiggerShadow.png)
+
+
+![ ](TextWithColorShadow.png)
+
+
+#### Underline
+
+The text can be underlined by setting UNDERLINE_ENABLED.  
+The color can also be selected using the UNDERLINE_COLOR property.  
+
+~~~{.cpp}
+// C++
+label1.SetProperty( TextLabel::Property::TEXT, "Text with Underline" );
+label1.SetProperty( TextLabel::Property::UNDERLINE_ENABLED, true );
+
+label2.SetProperty( TextLabel::Property::TEXT, "Text with Color Underline" );
+label2.SetProperty( TextLabel::Property::UNDERLINE_ENABLED, true );
+label2.SetProperty( TextLabel::Property::UNDERLINE_COLOR, Color::GREEN );
+~~~
+
+![ ](TextWithUnderline.png)
+
+
+![ ](TextWithColorUnderline.png)
+
+By default the underline height will be taken from the font metrics, however this can be overridden using the UNDERLINE_HEIGHT property:
+
+~~~{.cpp}
+// C++
+
+label1.SetProperty( TextLabel::Property::UNDERLINE_HEIGHT, 1.0f );
+~~~
+
+![ ](TextWith1pxUnderline.png)
+
+### Auto Scrolling
+
+![ ](AutoScroll.gif)
+
+The \link text-auto-scrolling Auto text scrolling \endlink section details how to scroll text automatically.
+
+### Text Label Properties
+
+The properties used by TextLabel are listed [here](@ref TextLabelProperties)
+
+
+*/
diff --git a/docs/content/programming-guide/type-registration.h b/docs/content/programming-guide/type-registration.h
new file mode 100644 (file)
index 0000000..ad7b5a4
--- /dev/null
@@ -0,0 +1,513 @@
+/*! \page type-registration Type Registration
+ *
+@section Overview
+
+DALi has a \link Dali::TypeRegistry type registration \endlink system which can be used to register
+a derived actor/control type along with specifying a method which is used to create this type. This
+type registration normally takes place at library load time.
+
+Once a type is registered, properties, signals and actions can also be registered for all instances
+of this type.
+
+This then allows the application writer to create instances using just the type name; getting and setting properties using a property name or index; connect to
+signals using only the signal name; and activate an action by just using the action name.
+
+This topic covers:
+
+ - @ref register-type
+ - @ref register-property
+ - @ref register-signal
+ - @ref register-action
+ - @ref using-type
+ - @ref using-property
+ - @ref using-signal
+ - @ref using-action
+
+@section register-type Registering a Type
+
+A type can be registered using Dali::TypeRegistration. This is normally done in an unnamed namespace
+within the source file of the deriving control as shown in the code below.
+
+<b>Please note:</b> This snippet assumes knowledge of the \link Dali::Toolkit::Control Control
+\endlink / \link Dali::Toolkit::Internal::Control Internal::Control \endlink creation process where
+<i><b>MyControl</b></i> derives from a Control and <i><b>MyControlImpl</b></i> derives from Internal::Control.
+
+@code
+namespace
+{
+
+Dali::BaseHandle CreateMyControl()
+{
+  // Create an instance of MyControl and return the handle.
+  return MyControlImpl::New();
+}
+
+DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl );
+DALI_TYPE_REGISTRATION_END()
+
+} // unnamed namespace
+@endcode
+
+This registration macro informs DALi of the existence of MyControl type, which class it derives from, and a method for creating an instance of MyControl.
+
+
+@section register-property Registering a Property
+
+DALi has a property system which can be extended by registering more properties through the type
+registry. The property index is <b><i>very important</i></b> when registering these properties and
+all property indices should be between Dali::PROPERTY_REGISTRATION_START_INDEX and
+Dali::PROPERTY_REGISTRATION_MAX_INDEX.
+
+Furthermore, if deriving from a \link Dali::Toolkit::Control Control\endlink, the control
+writer needs to be aware of their parent class's property range to avoid overlapping indices, so should start their property indices after their parent's range.
+Control reserves a property range between
+\link Dali::Toolkit::Control::CONTROL_PROPERTY_START_INDEX Control::CONTROL_PROPERTY_START_INDEX\endlink
+and \link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink.
+
+Any control deriving from \link Dali::Toolkit::Control Control\endlink
+should start at
+\link Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX Control::CONTROL_PROPERTY_END_INDEX\endlink + 1.
+Controls deriving from an existing control such as \link Dali::Toolkit::Button Button\endlink should start at
+\link Dali::Toolkit::Button::PROPERTY_END_INDEX Button::PROPERTY_END_INDEX\endlink + 1.
+
+Please have a look at \ref property-indices for more information.
+
+The following code shows how a property can be added to a type.
+
+@code
+// Define the indices we will use for the properties:
+
+class MyControl : public Control
+{
+  /**
+   * @brief The start and end property ranges for this control.
+   */
+  enum PropertyRange
+  {
+    PROPERTY_START_INDEX = Control::CONTROL_PROPERTY_END_INDEX + 1,
+    PROPERTY_END_INDEX =   PROPERTY_START_INDEX + 1000,
+
+    ANIMATABLE_PROPERTY_START_INDEX = ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX,
+    ANIMATABLE_PROPERTY_END_INDEX =   ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX + 1000
+  };
+
+  struct Property
+  {
+    enum
+    {
+      // Event side properties
+
+      /**
+       * @brief name "propertyOne", type bool
+       * @details Enables the feature.
+       * @SINCE_1_0.0
+       */
+      PROPERTY_ONE = PROPERTY_START_INDEX,
+
+      /**
+       * @brief name "propertyTwo", type float
+       * @details Controls the level of the feature
+       * @SINCE_1_0.0
+       */
+      PROPERTY_TWO,
+
+      /**
+       * @brief name "propertyThree", type Vector4
+       * @details The foreground color
+       * @SINCE_1_0.0
+       */
+      PROPERTY_THREE,
+
+      // Animatable properties
+
+      /**
+       * @brief name "propertyFour", type Vector4
+       * @details Animatable parameters of the feature
+       * @SINCE_1_0.0
+       */
+      PROPERTY_FOUR = ANIMATABLE_PROPERTY_START_INDEX,
+    };
+  };
+
+  /// ...
+};
+@endcode
+
+The control and properties are registered with the TypeRegistry using the following macros:
+
+@code
+DALI_TYPE_REGISTRATION_BEGIN( MyControl, Toolkit::Control, CreateMyControl );
+DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property1", BOOLEAN, PROPERTY_ONE )
+DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property2", FLOAT, PROPERTY_TWO )
+DALI_PROPERTY_REGISTRATION( AppNamespace, MyControl, "property3", VECTOR4, PROPERTY_THREE )
+
+DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( AppNamespace, MyControl, "property4", Vector4(0.f, 0.f, 1.f, 1.f), PROPERTY_FOUR )
+
+DALI_TYPE_REGISTRATION_END()
+@endcode
+
+The DALI_PROPERTY_REGISTRATION macro requires that you define the class methods SetProperty() and GetProperty().
+
+The DALI_ANIMATABLE_PROPERTY_REGISTRATION macros automatically create and handle scene-graph values, and do not need any code in your derived class. Just use the property index in animation or constraint methods.
+
+The SetProperty class method has to be static, and follows the format:
+
+@code
+void MyControl::SetProperty(
+    Dali::BaseObject* object,          // A pointer to an instance of MyControl
+    Dali::Property::Index index,       // The index of the property to set
+    const Dali::Property::Value& value // The value to set the property to
+)
+{
+  // DownCast to MyControl so that we can do the specific behaviour
+  MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
+
+  if ( control )
+  {
+    MyControlImpl& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case PROPERTY_ONE:
+      {
+        // Assume we already have a method in MyControl which sets the appropriate value and takes in a boolean
+        bool property;
+        if( value.Get( property ) )
+        {
+          controlImpl.SetPropertyOne( property );
+        }
+        break;
+      }
+
+      case PROPERTY_TWO
+      {
+        // Assume we already have a method in MyControl which sets the appropriate value and takes in a float
+        float property;
+        if( value.Get( property ) )
+        {
+          controlImpl.SetPropertyTwo( property );
+        }
+        break;
+      }
+
+      case PROPERTY_THREE
+      {
+        // Assume we already have a method in MyControl which sets the appropriate value and takes in a Vector4
+        Vector4 property;
+        if( value.Get( property ) )
+        {
+          controlImpl.SetPropertyThree( property );
+        }
+        break;
+      }
+    }
+  }
+}
+@endcode
+
+And the GetProperty method also has to be static and takes the form:
+
+@code
+Property::Value MyControl::GetProperty(
+    BaseObject* object,     // A pointer to an instance of MyControl
+    Property::Index index ) // The index of the property to retrieve
+{
+  Property::Value value;
+
+  // DownCast to MyControl so that we can do the specific behaviour
+  MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
+
+  if ( control )
+  {
+    MyControlImpl& controlImpl( GetImplementation( control ) );
+
+    switch ( index )
+    {
+      case PROPERTY_ONE:
+      {
+        // Assume we have a member variable that stores the value of this property
+        value = controlImpl.mPropertyOne;
+        break;
+      }
+
+      case PROPERTY_TWO:
+      {
+        // Assume we have a member variable that stores the value of this property
+        value = controlImpl.mPropertyTwo;
+        break;
+      }
+
+      case PROPERTY_THREE:
+      {
+        // Assume we have a member variable that stores the value of this property
+        value = controlImpl.mPropertyThree;
+        break;
+      }
+    }
+  }
+}
+@endcode
+
+@section using-property Setting & Getting Registered Properties
+
+Like other properties, type registered properties can also be set and their values can be retrieved
+in a similar manner. The code below shows how this can be done.
+
+@code
+Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
+
+if ( type )
+{
+  Dali::BaseHandle baseHandle = type.CreateInstance();
+
+  if ( baseHandle )
+  {
+    // Handle deals with properties, so DownCast
+    Dali::Handle handle = Dali::Handle::DownCast( baseHandle );
+
+    if ( handle )
+    {
+      // Setting a property
+      handle.SetProperty( MyControl::Property::PROPERTY_ONE, 11.0f );
+
+      // Get the property name
+      std::cout << "Property1 name is: " << handle.GetPropertyName( MyControl::Property::PROPERTY_ONE ) << std::endl;
+
+      // Get the property
+      bool propertyOne = handle.GetProperty< bool >( MyControl::Property::PROPERTY_ONE );
+
+      // Set the second property
+      handle.SetProperty( MyControl::Property::PROPERTY_TWO, 4.0f );
+    }
+  }
+}
+@endcode
+
+@section register-signal Registering a Signal
+
+Once we've registered a type, we can then inform the type-registry about any signals that our type has:
+
+@code
+// Define the names of the signals
+static const char * const SIGNAL_ONE( "signal1" );
+static const char * const SIGNAL_TWO( "signal2" );
+static const char * const SIGNAL_THREE( "signal3" );
+
+Dali::SignalConnectorType signal1(
+   type,                       // Reference to type registration object (see above)
+   SIGNAL_ONE,                 // Name of our signal
+   &MyControl::DoConnectSignal // Function to call when a call to connect to this signal is received
+);
+
+// Register more signals
+Dali::SignalConnectorType signal2( type, SIGNAL_TWO,   &MyControl::DoConnectSignal );
+Dali::SignalConnectorType signal3( type, SIGNAL_THREE, &MyControl::DoConnectSignal );
+@endcode
+
+It is recommended to use static members (of MyControl class) for the signal names. That way
+applications can also use the static member rather than have to look up the name.
+
+The method that handles the signal connection has to be static and takes the form:
+
+@code
+bool MyControl::DoConnectSignal(
+    Dali::BaseObject* object,                  // A pointer to an instance of MyControl
+    Dali::ConnectionTrackerInterface* tracker, // The object connecting to the signal
+    const std::string& signalName,             // The name of the signal to connect to
+    Dali::FunctorDelegate* functor             // The functor
+)
+{
+  bool connected( false );
+
+  // DownCast to MyControl so that we can call the signal connection methods
+  MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
+
+  if ( control )
+  {
+    if ( signalName == SIGNAL_ONE )
+    {
+      control.SignalOne().Connect( tracker, functor );
+      connected = true;
+    }
+    else if ( signalName == SIGNAL_TWO )
+    {
+      control.SignalTwo().Connect( tracker, functor );
+      connected = true;
+    }
+    else if ( signalName == SIGNAL_THREE )
+    {
+      control.SignalThree().Connect( tracker, functor );
+      connected = true;
+    }
+  }
+
+  return connected; // Return true if connection successfully created
+}
+@endcode
+
+@section register-action Registering an Action
+
+Created controls are able to perform a variety of default actions. Registering an action with the
+type registry allows application writers to perform this action by using the name.
+
+An action can be added to a type as shown below:
+
+@code
+// Define the names of the actions
+static const char * const ACTION_ONE( "action1" );
+static const char * const ACTION_TWO( "action2" );
+static const char * const ACTION_THREE( "action3" );
+
+Dali::TypeAction action1(
+    type,                // Reference to type registration object (see above)
+    ACTION_ONE,          // Name of the action
+    &MyControl::DoAction // Function to call when someone wants to perform this action
+);
+
+// Register mode actions
+Dali::TypeAction action2( type, ACTION_TWO,   &MyControl::DoAction );
+Dali::TypeAction action3( type, ACTION_THREE, &MyControl::DoAction );
+@endcode
+
+It is recommended to use static members (of MyControl class) for the action names. That way
+applications can also use the static member rather than have to look up the name.
+
+The method that handles the action has to be static and takes the form:
+
+@code
+bool MyControl::DoAction(
+    Dali::BaseObject* object,                              // A pointer to an instance of MyControl
+    const std::string& actionName,                         // The name of the action to perform
+    const std::vector< Dali::Property::Value >& attributes // Any passed in attributes
+)
+{
+  bool performed( false );
+
+  Dali::BaseHandle handle(object);
+
+  // DownCast to MyControl so that we can do the specific behaviour
+  MyControl control = MyControl::DownCast( Dali::BaseHandle ( object ) );
+
+  if ( control )
+  {
+    if ( actionName == ACTION_ONE )
+    {
+      // Do action1 e.g. button click etc.
+    }
+    else if ( actionName == ACTION_TWO )
+    {
+      // Do action2, which can have attributes
+      if ( !attributes.empty() )
+      {
+        // Let's assume action2 expects a std::string as an attribute, here's how we'd extract that
+        std::cout << "action2 printing out: " << attributes[0].Get< std::string >() ) << std::endl;
+      }
+    }
+    else if ( actionName == ACTION_THREE )
+    {
+      // Do action3
+    }
+  }
+
+  return performed; // Return true if action successfully performed
+}
+@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 using-type Creating an instance of a Registered Type
+
+When a type is registered with the \link Dali::TypeRegistry type registry\endlink, it allows the
+application writer to get information about the type and even create an instance of it.
+
+@code
+Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
+
+// If type specified is not found, then type will be NULL.
+if ( type )
+{
+  Dali::BaseHandle handle = type.CreateInstance();
+
+  // Can use DownCast to change to MyControl type if required
+  if ( handle )
+  {
+    MyControl control = MyControl::DownCast( handle );
+  }
+}
+@endcode
+
+Normally we would not do the DownCast, just utilise the signals, actions and properties.
+
+@section using-signal Connecting to a Registered Signal
+
+The advantage of registering a signal using the \link Dali::TypeRegistry type registry \endlink is
+that you can connect to a particular signal using just the name of the signal.
+
+The application code would look as follows:
+
+@code
+class MyApp
+{
+public:
+
+  // Assume this is called when creating MyApp
+  void Create()
+  {
+    Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
+
+    if ( type )
+    {
+      mHandle = type.CreateInstance();
+
+      if ( mHandle )
+      {
+        // Connect to signal1 by using its name
+        handle.ConnectSignal( &mConnectionTracker, "signal1", &MyApp::SignalReceived ) )
+      }
+    }
+  }
+
+  // This method will be called when "signal1" is emitted
+  void SignalReceived()
+  {
+    // Do Something when "signal1" is received
+    std::cout << "signal1 received" << std::endl;
+  }
+
+private:
+  Dali::BaseHandle mHandle; // Handle to MyControl created via the type-registry
+  Dali::ConnectionTracker mConnectionTracker; // Used for automatic signal disconnection upon its destruction
+};
+@endcode
+
+@section using-action Performing a Registered Action
+
+Once an action is registered, the application writer can perform that action using the action name:
+
+@code
+Dali::TypeInfo type = Dali::TypeRegistry::Get().GetTypeInfo( "MyControl" );
+
+if ( type )
+{
+  Dali::BaseHandle handle = type.CreateInstance();
+
+  if ( handle )
+  {
+    // Perform action1, no attributes
+    handle.DoAction( "action1", std::vector< Dali::Property::Value >() );
+
+    // Create an attribute vector for action2
+    std::vector< Dali::Property::Value > action2Attributes;
+    action2Attributes.push_back( Dali::Property::Value( "Hello-Action-2" ) );
+
+    // Perform action2, with attributes
+    handle.DoAction( "action2", action2Attributes );
+  }
+}
+@endcode
+
+*
+*/
diff --git a/docs/content/programming-guide/visuals.md b/docs/content/programming-guide/visuals.md
new file mode 100644 (file)
index 0000000..3a58a6d
--- /dev/null
@@ -0,0 +1,672 @@
+<!--
+/**-->
+
+# Visuals {#visuals}
+
+Visuals provide reusable rendering logic which can be used by all controls.
+This means that custom controls do not have to create actors, they can just reuse the existing visuals which increases performance.
+Visuals reuse geometry, shaders etc. across controls and manages the renderer and texture to exist only when the control is on-stage.
+Additionally, they respond to actor size and color change, while also providing clipping at the renderer level.
+DALi provides the following visuals:
+ + [Color](@ref color-visual)
+ + [Gradient](@ref gradient-visual)
+ + [Image](@ref image-visuals)
+ + [Border](@ref border-visual)
+ + [Mesh](@ref mesh-visual)
+ + [Primitive](@ref primitive-visual)
+ + [Text](@ref text-visual)
+ + [Wireframe](@ref wireframe-visual)
+Controls can provide properties that allow users to specify the visual type ( visualType ).
+Setting visual properties are done via a property map.
+The **visualType** field in the property map specifies the visual to use/create.
+This is required to avoid ambiguity as multiple visuals may be capable of rendering the same contents.
+
+Visuals have a **transform** field in the property map to allow layouting within a control. If this field is not set, then the visual defaults to filling the control. The **transform** field has a property map with the following keys:
+
+| Property                                                       | String       | Type              | Required | Description                                                                                 |
+|----------------------------------------------------------------|--------------|:-----------------:|:--------:|---------------------------------------------------------------------------------------------|
+| Dali::Toolkit::Visual::Transform::Property::OFFSET        | offset       | VECTOR2           | No       | The offset of the visual.                                                                   |
+| Dali::Toolkit::Visual::Transform::Property::SIZE          | size         | VECTOR2           | No       | The size of the visual.                                                                     |
+| Dali::Toolkit::Visual::Transform::Property::OFFSET_POLICY | offsetPolicy | VECTOR4           | No       | Whether the offset components are Relative or Absolute [More info](@ref offset-size-policy) |
+| Dali::Toolkit::Visual::Transform::Property::SIZE_POLICY   | sizePolicy   | VECTOR4           | No       | Whether the size components are Relative or Absolute [More info](@ref offset-size-policy)   |
+| Dali::Toolkit::Visual::Transform::Property::ORIGIN        | origin       | INTEGER or STRING | No       | The origin of the visual within the control's area. [More info](@ref align-type)            |
+| Dali::Toolkit::Visual::Transform::Property::ANCHOR_POINT  | anchorPoint  | INTEGER or STRING | No       | The anchor point of the visual. [More info](@ref align-type)                                |
+
+## Offset & Size Policy  {#offset-size-policy}
+
+The offset and size policies can be either Relative or Absolute.
+
+| Enumeration                                             | String   | Description                                                                   |
+|---------------------------------------------------------|----------|-------------------------------------------------------------------------------|
+| Dali::Toolkit::Visual::Transform::Policy::RELATIVE | RELATIVE | *Default*. The size or offset value represents a ratio of the control's size  |
+| Dali::Toolkit::Visual::Transform::Policy::ABSOLUTE | ABSOLUTE | The size or offset value represents world units (pixels)                      |
+
+For example, an offsetPolicy of [ RELATIVE, RELATIVE ], a sizePolicy of [ ABSOLUTE, ABSOLUTE ], an offset of ( 0, 0.25 ) and a size of ( 20, 20 ) means the visual will be 20 pixels by 20 pixels in size, positioned 25% above the center of the control.
+
+## Alignment  {#align-type}
+| Enumeration                                          | String  | Description                                                                                          |
+|------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::Align::TOP_BEGIN | TOP_BEGIN | Aligns to the top of the vertical axis and the beginning of the horizontal axis (The left or right edge in Left-To-Right or Right-to-Left layouts, respectively) |
+| Dali::Toolkit::Align::TOP_CENTER | TOP_CENTER | Aligns to the top of the vertical axis and the center of the horizontal axis |
+| Dali::Toolkit::Align::TOP_END | TOP_END | Aligns to the top of the vertical axis and end of the horizontal axis (The right or left edge in Left-To-Right or Right-to-Left layouts, respectively) |
+| Dali::Toolkit::Align::CENTER_BEGIN | CENTER_BEGIN | Aligns to the center of the vertical axis and the beginning of the horizontal axis|
+| Dali::Toolkit::Align::CENTER | CENTER | Aligns to the center of the control |
+| Dali::Toolkit::Align::CENTER_END | CENTER_END | Aligns to the center of the vertical axis and end of the horizontal axis |
+| Dali::Toolkit::Align::BOTTOM_BEGIN | BOTTOM_BEGIN | Aligns to the bottom of the vertical axis and the beginning of the horizontal axis|
+| Dali::Toolkit::Align::BOTTOM_CENTER | BOTTOM_CENTER | Aligns to the bottom of the vertical axis and the center of the horizontal axis
+| Dali::Toolkit::Align::BOTTOM_END | BOTTOM_END | Aligns to the bottom of the vertical axis and end of the horizontal axis |
+Visuals also have a custom **shader** property. Whilst it's possible to change the shader, please note that some visuals rely on the vertex shader to perform certain functions. For example, the NPatch visual uses the vertex shader to perform the stretching. The **shader** property is a Property::Map with the following keys:
+
+
+| Property                                                  | String         | Type                       | Required | Description                                                                                |
+|-----------------------------------------------------------|----------------|:--------------------------:|:--------:|--------------------------------------------------------------------------------------------|
+| Dali::Toolkit::Visual::Shader::Property::VERTEX_SHADER    | vertexShader   | STRING or ARRAY of STRING  | No       | The vertex shader code. Can use an array of strings to split shader over multiple lines.   |
+| Dali::Toolkit::Visual::Shader::Property::FRAGMENT_SHADER  | fragmentShader | STRING or ARRAY of STRING  | No       | The fragment shader code. Can use an array of strings to split shader over multiple lines. |
+| Dali::Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_X | subdivideGridX | INTEGER                    | No       | How to subdivide the grid along the X-Axis. Defaults to 1.                                 |
+| Dali::Toolkit::Visual::Shader::Property::SUBDIVIDE_GRID_Y | subdivideGridY | INTEGER                    | No       | How to subdivide the grid along the Y-Axis. Defaults to 1.                                 |
+| Dali::Toolkit::Visual::Shader::Property::HINTS            | hints          | INTEGER or ARRAY of STRING | No       | Shader hints bitmask [More info](@ref shader-hints)                                        |
+
+## Shader hints {#shader-hints}
+
+This is a bitmask giving hints to the renderer about what the shader does, in order to help the rendering system optimise it's rendering.
+
+The bitmask can have the following values:
+
+| Value | Description |
+|-------------------------------------------|----------------------------------------|
+| Dali::Shader::Hint::NONE | No hints |
+| Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT | Might generate transparent alpha from opaque inputs |
+| Dali::Shader::Hint::MODIFIES_GEOMETRY | Might change the position of vertices - this disables culling optimizations |
+
+
+See also Dali::Shader::Hint::Value enumeration.
+
+___________________________________________________________________________________________________
+
+## Color Visual {#color-visual}
+
+Renders a color to the visual's quad geometry.
+![ ](visuals/color-visual.png)
+
+### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::COLOR, "COLOR"
+
+| Property                                        | String   | Type    | Required | Description               |
+|-------------------------------------------------|----------|:-------:|:--------:|---------------------------|
+| Dali::Toolkit::ColorVisual::Property::MIX_COLOR | mixColor | VECTOR4 | Yes      | The color required. |
+
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::COLOR;
+map[ ColorVisual::Property::MIX_COLOR ] = Color::RED;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+## Gradient Visual {#gradient-visual}
+
+Renders a smooth transition of colors to the visual's quad geometry.
+Both Linear and Radial gradients are supported.
+
+| Linear | Radial |
+|--------|--------|
+| ![ ](visuals/linear-gradient-visual.png) | ![ ](visuals/radial-gradient-visual.png) |
+
+### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::GRADIENT, "GRADIENT"
+
+| Property                                                | String        | Type              | Required   | Description                                                                                                      |
+|---------------------------------------------------------|---------------|:-----------------:|:----------:|------------------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::GradientVisual::Property::START_POSITION | startPosition | VECTOR2           | For Linear | The start position of the linear gradient.                                                                       |
+| Dali::Toolkit::GradientVisual::Property::END_POSITION   | endPosition   | VECTOR2           | For Linear | The end position of the linear gradient.                                                                         |
+| Dali::Toolkit::GradientVisual::Property::CENTER         | center        | VECTOR2           | For Radial | The center point of the gradient.                                                                                |
+| Dali::Toolkit::GradientVisual::Property::RADIUS         | radius        | FLOAT             | For Radial | The size of the radius.                                                                                          |
+| Dali::Toolkit::GradientVisual::Property::STOP_OFFSET    | stopOffset    | ARRAY of FLOAT    | No         | All the stop offsets. If not supplied default is 0.0 and 1.0.                                                    |
+| Dali::Toolkit::GradientVisual::Property::STOP_COLOR     | stopColor     | ARRAY of VECTOR4  | Yes        | The color at those stop offsets. At least 2 required to show a gradient.                                         |
+| Dali::Toolkit::GradientVisual::Property::UNITS          | units         | INTEGER or STRING | No         | Defines the coordinate system. [More info](@ref gradient-visual-units)                                           |
+| Dali::Toolkit::GradientVisual::Property::SPREAD_METHOD  | spreadMethod  | INTEGER or STRING | No         | Indicates what happens if gradient starts or ends inside bounds. [More info](@ref gradient-visual-spread-method) |
+
+If the *stopOffset* and *stopColor* arrays do not have the same number of elements, then the minimum of the two is used as the stop points.
+
+### Units {#gradient-visual-units}
+
+Defines the coordinate system for the attributes:
+ + Start (x1, y1) and End (x2 and y2) points of a line if using a linear gradient.
+ + Center point (cx, cy) and radius (r) of a circle if using a radial gradient.
+| Enumeration                                               | String              | Description                                                                                                                                    |
+|-----------------------------------------------------------|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::GradientVisual::Units::OBJECT_BOUNDING_BOX | OBJECT_BOUNDING_BOX | *Default*. Uses the normals for the start, end & center points, i.e. top-left is (-0.5, -0.5) and bottom-right is (0.5, 0.5).                  |
+| Dali::Toolkit::GradientVisual::Units::USER_SPACE          | USER_SPACE          | Uses the user coordinates for the start, end & center points, i.e. in a 200 by 200 control, top-left is (0, 0) and bottom-right is (200, 200). |
+
+### Spread Method {#gradient-visual-spread-method}
+
+Indicates what happens if the gradient starts or ends inside the bounds of the target rectangle.
+
+| Enumeration                                          | String  | Description                                                                                          |
+|------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::GradientVisual::SpreadMethod::PAD     | PAD     | *Default*. Uses the terminal colors of the gradient to fill the remainder of the quad geometry.               |
+| Dali::Toolkit::GradientVisual::SpreadMethod::REFLECT | REFLECT | Reflect the gradient pattern start-to-end, end-to-start, start-to-end etc. until the quad geometry is filled. |
+| Dali::Toolkit::GradientVisual::SpreadMethod::REPEAT  | REPEAT  | Repeat the gradient pattern start-to-end, start-to-end, start-to-end etc. until the quad geometry is filled.  |
+
+### Usage
+
+**Linear:**
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::GRADIENT;
+map[ GradientVisual::Property::START_POSITION ] = Vector2( 0.5f, 0.5f );
+map[ GradientVisual::Property::END_POSITION ] = Vector2( -0.5f, -0.5f );
+
+Dali::Property::Array stopOffsets;
+stopOffsets.PushBack( 0.0f );
+stopOffsets.PushBack( 0.3f );
+stopOffsets.PushBack( 0.6f );
+stopOffsets.PushBack( 0.8f );
+stopOffsets.PushBack( 1.f );
+map[ GradientVisual::Property::STOP_OFFSET ] = stopOffsets;
+
+Dali::Property::Array stopColors;
+stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 255.f )/255.f );
+stopColors.PushBack( Vector4( 196.f, 198.f, 71.f, 122.f )/255.f );
+stopColors.PushBack( Vector4( 214.f, 37.f, 139.f, 191.f )/255.f );
+stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 150.f )/255.f );
+stopColors.PushBack( Color::YELLOW );
+map[ GradientVisual::Property::STOP_COLOR ] = stopColors;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+
+**Radial:**
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::GRADIENT;
+map[ GradientVisual::Property::CENTER ] = Vector2( 0.5f, 0.5f );
+map[ GradientVisual::Property::RADIUS ] = 1.414f;
+
+Dali::Property::Array stopOffsets;
+stopOffsets.PushBack( 0.0f );
+stopOffsets.PushBack( 0.3f );
+stopOffsets.PushBack( 0.6f );
+stopOffsets.PushBack( 0.8f );
+stopOffsets.PushBack( 1.f );
+map[ GradientVisual::Property::STOP_OFFSET ] = stopOffsets;
+
+Dali::Property::Array stopColors;
+stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 255.f )/255.f );
+stopColors.PushBack( Vector4( 196.f, 198.f, 71.f, 122.f )/255.f );
+stopColors.PushBack( Vector4( 214.f, 37.f, 139.f, 191.f )/255.f );
+stopColors.PushBack( Vector4( 129.f, 198.f, 193.f, 150.f )/255.f );
+stopColors.PushBack( Color::YELLOW );
+map[ GradientVisual::Property::STOP_COLOR ] = stopColors;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+## Image Visual {#image-visuals}
+
+Renders an image into the visual's geometry.
+Depending on the extension of the image, a different visual is provided to render the image onto the screen.
+ + [Normal (Quad)](@ref image-visual)
+ + [N-Patch](@ref n-patch-visual)
+ + [SVG](@ref svg-visual)
+ + [Animated Image]( @ref animated-image-visual )
+___________________________
+### Normal {#image-visual}
+Renders a raster image ( jpg, png etc.) into the visual's quad geometry.
+![ ](visuals/image-visual.png)
+
+#### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE"
+
+| Property                                             | String        | Type              | Required | Description                                                                                                              |
+|------------------------------------------------------|---------------|:-----------------:|:--------:|--------------------------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::ImageVisual::Property::URL            | url           | STRING            | Yes      | The URL of the image.                                                                                                    |
+| Dali::Toolkit::ImageVisual::Property::FITTING_MODE   | fittingMode   | INTEGER or STRING | No       | Fitting options, used when resizing images to fit desired dimensions. [More info](@ref resourceimagescaling-fittingmode) |
+| Dali::Toolkit::ImageVisual::Property::SAMPLING_MODE  | samplingMode  | INTEGER or STRING | No       | Filtering options, used when resizing images to sample original pixels. [More info](@ref resourceimagescaling-scaling)   |
+| Dali::Toolkit::ImageVisual::Property::DESIRED_WIDTH  | desiredWidth  | INT               | No       | The desired image width. Will use actual image width if not specified.                                                   |
+| Dali::Toolkit::ImageVisual::Property::DESIRED_HEIGHT | desiredHeight | INT               | No       | The desired image height. Will use actual image height if not specified.                                                 |
+| Dali::Toolkit::ImageVisual::Property::PIXEL_AREA     | pixelArea     | VECTOR4           | No       | The image area to be displayed, default value is [0.0, 0.0, 1.0, 1.0]                                                    |
+| Dali::Toolkit::ImageVisual::Property::WRAP_MODE_U    | wrapModeU     | INTEGER or STRING | No       | Wrap mode for u coordinate, valid values are CLAMP_TO_EDGE(default), REPEAT, MIRRORED_REPEAT                               |
+| Dali::Toolkit::ImageVisual::Property::WRAP_MODE_V    | wrapModeV     | INTEGER or STRING | No       | Wrap mode for v coordinate, valid values are CLAMP_TO_EDGE(default), REPEAT, MIRRORED_REPEAT                               |
+
+#### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::IMAGE;
+map[ ImageVisual::Property::URL ] = "path-to-image.jpg";
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+### N-Patch {#n-patch-visual}
+
+Renders an n-patch or a 9-patch image. Uses non-quad geometry. Both geometry and texture are cached to reduce memory consumption if the same n-patch image is used elsewhere.
+![ ](visuals/n-patch-visual.png)
+
+#### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE"
+
+| Property                                          | String        | Type    | Required | Description                      |
+|---------------------------------------------------|---------------|:-------:|:--------:|----------------------------------|
+| Dali::Toolkit::ImageVisual::Property::URL         | url           | STRING  | Yes      | The URL of the n-patch image.    |
+| Dali::Toolkit::ImageVisual::Property::BORDER_ONLY | borderOnly    | BOOLEAN | No       | If true, only draws the borders. |
+
+#### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::IMAGE;
+map[ Dali::Toolkit::ImageVisual::Property::URL ] = "path-to-image.9.png";
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+### SVG {#svg-visual}
+
+Renders a svg image into the visual's quad geometry.
+#### 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">
+</div>
+<div style="width:300px">
+![ ](visuals/svg-visual.svg)
+</div>
+
+#### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE"
+
+| Property                                  | String | Type    | Required | Description                      |
+|-------------------------------------------|--------|:-------:|:--------:|----------------------------------|
+| Dali::Toolkit::ImageVisual::Property::URL | url    | STRING  | Yes      | The URL of the SVG image.    |
+
+#### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::IMAGE;
+map[ Dali::Toolkit::ImageVisual::Property::URL ] = "path-to-image.svg";
+
+control.SetSize( 200.f, 200.f );
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+## Animated Image Visual {#animated-image-visual}
+
+Renders an animated image into the visual's quad geometry. Currently, only the GIF format is supported.
+
+![ ](animated-image-visual.gif)
+
+#### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::IMAGE, "IMAGE"
+
+| Property                                          | String     | Type              | Required | Description                                                                                  |
+|---------------------------------------------------|------------|:-----------------:|:--------:|----------------------------------------------------------------------------------------------|
+| Dali::Toolkit::ImageVisual::Property::URL         | url        | STRING            | Yes      | The URL of the animated image.                                                               |
+| Dali::Toolkit::ImageVisual::Property::PIXEL_AREA  | pixelArea  | VECTOR4           | No       | The image area to be displayed, default value is [0.0, 0.0, 1.0, 1.0]                        |
+| Dali::Toolkit::ImageVisual::Property::WRAP_MODE_U | wrapModeU  | INTEGER or STRING | No       | Wrap mode for u coordinate, valid values are CLAMP_TO_EDGE(default), REPEAT, MIRRORED_REPEAT |
+| Dali::Toolkit::ImageVisual::Property::WRAP_MODE_V | wrapModeV  | INTEGER or STRING | No       | Wrap mode for v coordinate, valid values are CLAMP_TO_EDGE(default), REPEAT, MIRRORED_REPEAT |
+
+#### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+control.SetProperty( Control::Property::BACKGROUND,
+                     Property::Map().Add( Visual::Property::TYPE, Dali::Toolkit::Visual::IMAGE )
+                                    .Add( Dali::Toolkit::ImageVisual::Property::URL, "path-to-image.gif" ) );
+~~~
+___________________________________________________________________________________________________
+
+## Border Visual {#border-visual}
+
+Renders a color as an internal border to the visual's geometry.
+![ ](visuals/border-visual.png)
+
+### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::BORDER, "BORDER"
+
+| Property                                             | String        | Type    | Required | Description                                      |
+|------------------------------------------------------|---------------|:-------:|:--------:|--------------------------------------------------|
+| Dali::Toolkit::BorderVisual::Property::COLOR         | borderColor   | VECTOR4 | Yes      | The color of the border.                         |
+| Dali::Toolkit::BorderVisual::Property::SIZE          | borderSize    | FLOAT   | Yes      | The width of the border (in pixels).             |
+| Dali::Toolkit::BorderVisual::Property::ANTI_ALIASING | antiAliasing  | BOOLEAN | No       | Whether anti-aliasing of the border is required. |
+
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::BORDER;
+map[ BorderVisual::Property::COLOR ] = Color::BLUE;
+map[ BorderVisual::Property::SIZE ] = 5.0f;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+## Mesh Visual {#mesh-visual}
+
+Renders a mesh using a .obj file, optionally with textures provided by a mtl file. Scaled to fit the control.
+![ ](visuals/mesh-visual.png)
+### Properties Supported
+**VisualType:** Dali::Toolkit::Visual::MESH, "MESH"
+
+| Property                                              | String         | Type               | Required          | Description                                                                                      |
+|-------------------------------------------------------|----------------|:------------------:|:-----------------:|--------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::MeshVisual::Property::OBJECT_URL       | objectUrl      | STRING             | Yes               | The location of the ".obj" file.                                                                 |
+| Dali::Toolkit::MeshVisual::Property::MATERIAL_URL     | materialUrl    | STRING             | No                | The location of the ".mtl" file. Leave blank for a textureless object.                           |
+| Dali::Toolkit::MeshVisual::Property::TEXTURES_PATH    | texturesPath   | STRING             | If using material | Path to the directory the textures (including gloss and normal) are stored in.                   |
+| Dali::Toolkit::MeshVisual::Property::SHADING_MODE     | shadingMode    | INTEGER or STRING  | No                | Sets the type of shading mode that the mesh will use. [More info](@ref mesh-visual-shading-mode) |
+| Dali::Toolkit::MeshVisual::Property::USE_MIPMAPPING   | useMipmapping  | BOOLEAN            | No                | Flag for whether to use mipmaps for textures or not. Default true.                               |
+| Dali::Toolkit::MeshVisual::Property::USE_SOFT_NORMALS | useSoftNormals | BOOLEAN            | No                | Flag for whether to average normals at each point to smooth textures or not. Default true.       |
+| Dali::Toolkit::MeshVisual::Property::LIGHT_POSITION   | lightPosition  | VECTOR3            | No                | The position, in stage space, of the point light that applies lighting to the model.             |
+### Shading Mode {#mesh-visual-shading-mode}
+
+When specifying the shading mode, if anything the mode requires is missing, a simpler mode that can be handled with what has been supplied will be used instead.
+**Possible values:**
+| Enumeration                                                                     | String                                   | Description                                                                                                             |
+|---------------------------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
+| Dali::Toolkit::MeshVisual::ShaderType::TEXTURELESS_WITH_DIFFUSE_LIGHTING        | TEXTURELESS_WITH_DIFFUSE_LIGHTING        | *Simplest*. One color that is lit by ambient and diffuse lighting.                                                      |
+| Dali::Toolkit::MeshVisual::ShaderType::TEXTURED_WITH_SPECULAR_LIGHTING          | TEXTURED_WITH_SPECULAR_LIGHTING          | Uses only the visual image textures provided with specular lighting in addition to ambient and diffuse lighting.        |
+| Dali::Toolkit::MeshVisual::ShaderType::TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING | TEXTURED_WITH_DETAILED_SPECULAR_LIGHTING | Uses all textures provided including a gloss, normal and texture map along with specular, ambient and diffuse lighting. |
+
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Stage stage = Dali::Stage::GetCurrent();
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE  ] = Dali::Toolkit::Visual::MESH;
+map[ MeshVisual::Property::OBJECT_URL ] = "home/models/Dino.obj";
+map[ MeshVisual::Property::MATERIAL_URL ] = "home/models/Dino.mtl";
+map[ MeshVisual::Property::TEXTURES_PATH ] = "home/images/";
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+
+___________________________________________________________________________________________________
+
+## Primitive Visual {#primitive-visual}
+
+Renders a simple 3D shape, such as a cube or sphere. Scaled to fit the control.
+
+The shapes are generated with clockwise winding and back-face culling on by default.
+
+![ ](visuals/cube.png)
+### Properties Supported
+
+**VisualType:** Dali::Toolkit::Visual::PRIMITIVE, "PRIMITIVE"
+
+| Property                                                      | String            | Type               | Description                                                                                                     | Default Value                                           | Range                          |
+|---------------------------------------------------------------|-------------------|:------------------:|-----------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------:|:------------------------------:|
+| Dali::Toolkit::PrimitiveVisual::Property::SHAPE               | shape             | INTEGER or STRING  | The specific shape to render. [More info](@ref shape-details)                                                   | Dali::Toolkit::PrimitiveVisual::Shape::SPHERE, "SPHERE" | [See list](@ref shape-details) |
+| Dali::Toolkit::PrimitiveVisual::Property::MIX_COLOR           | mixColor          | VECTOR4            | The color of the shape.                                                                                         | (0.5, 0.5, 0.5, 1.0)                                    | 0.0 - 1.0 for each             |
+| Dali::Toolkit::PrimitiveVisual::Property::SLICES              | slices            | INTEGER            | The number of slices as you go around the shape. [More info](@ref slices-details)                               | 128                                                     | 1 - 255                        |
+| Dali::Toolkit::PrimitiveVisual::Property::STACKS              | stacks            | INTEGER            | The number of stacks as you go down the shape. [More info](@ref stacks-details)                                 | 128                                                     | 1 - 255                        |
+| Dali::Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS    | scaleTopRadius    | FLOAT              | The scale of the radius of the top circle of a conical frustrum.                                                | 1.0                                                     | ≥ 0.0                          |
+| Dali::Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS | scaleBottomRadius | FLOAT              | The scale of the radius of the bottom circle of a conical frustrum.                                             | 1.5                                                     | ≥ 0.0                          |
+| Dali::Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT        | scaleHeight       | FLOAT              | The scale of the height of a conic.                                                                             | 3.0                                                     | > 0.0                          |
+| Dali::Toolkit::PrimitiveVisual::Property::SCALE_RADIUS        | scaleRadius       | FLOAT              | The scale of the radius of a cylinder.                                                                          | 1.0                                                     | > 0.0                          |
+| Dali::Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS    | scaleDimensions   | VECTOR3            | The dimensions of a cuboid. Scales in the same fashion as a 9-patch image.                                      | Vector3::ONE                                            | > 0.0 for each                 |
+| Dali::Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE    | bevelPercentage   | FLOAT              | Determines how bevelled the cuboid should be, based off the smallest dimension. [More info](@ref bevel-details) | 0.0 (no bevel)                                          | 0.0 - 1.0                      |
+| Dali::Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS    | bevelSmoothness   | FLOAT              | Defines how smooth the bevelled edges should be.                                                                | 0.0 (sharp edges)                                       | 0.0 - 1.0                      |
+| Dali::Toolkit::PrimitiveVisual::Property::LIGHT_POSITION      | lightPosition     | VECTOR3            | The position, in stage space, of the point light that applies lighting to the model.                            | (Offset outwards from the center of the screen.)        | Unlimited                      |
+
+### Shapes {#shape-details}
+
+There are six shapes that can be chosen, some of which are simplified specialisations of another.
+
+| Enumeration                                             | String           | Description                                                                       | Parameters                                                    |
+|---------------------------------------------------------|------------------|-----------------------------------------------------------------------------------|---------------------------------------------------------------|
+| Dali::Toolkit::PrimitiveVisual::Shape::SPHERE           | SPHERE           | *Default*.                                                                        | color, slices, stacks                                         |
+| Dali::Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTRUM | CONICAL_FRUSTRUM | The area bound between two circles, i.e. a cone with the tip removed.             | color, scaleTopRadius, scaleBottomRadius, scaleHeight, slices |
+| Dali::Toolkit::PrimitiveVisual::Shape::CONE             | CONE             | Equivalent to a conical frustrum with top radius of zero.                         | color, scaleBottomRadius, scaleHeight, slices                 |
+| Dali::Toolkit::PrimitiveVisual::Shape::CYLINDER         | CYLINDER         | Equivalent to a conical frustrum with equal radii for the top and bottom circles. | color, scaleRadius, scaleHeight, slices                       |
+| Dali::Toolkit::PrimitiveVisual::Shape::CUBE             | CUBE             | Equivalent to a bevelled cube with a bevel percentage of zero.                    | color, scaleDimensions                                        |
+| Dali::Toolkit::PrimitiveVisual::Shape::OCTAHEDRON       | OCTAHEDRON       | Equivalent to a bevelled cube with a bevel percentage of one.                     | color, scaleDimensions                                        |
+| Dali::Toolkit::PrimitiveVisual::Shape::BEVELLED_CUBE    | BEVELLED_CUBE    | A cube/cuboid with all edges flattened to some degree.                            | color, scaleDimensions, bevelPercentage, bevelSmoothness      |
+
+#### Examples below:
+
+**sphere:**
+![ ](visuals/sphere.png)
+**conics:**
+| Frustrum | Cone | Cylinder |
+|----------|------|----------|
+| ![ ](visuals/conical-frustrum.png) | ![ ](visuals/cone.png) | ![ ](visuals/cylinder.png) |
+### Bevel {#bevel-details}
+Bevel percentage ranges from 0.0 to 1.0. It affects the ratio of the outer face widths to the width of the overall cube, as shown:
+| 0.0 ( cube) | 0.3 | 0.7 | 1.0 (octahedron) |
+|-------------|-----|-----|------------------|
+| ![ ](visuals/cube.png) | ![ ](visuals/bevelled-cube-low.png) | ![ ](visuals/bevelled-cube-high.png) | ![ ](visuals/octahedron.png) |
+### Slices {#slices-details}
+For spheres and conical frustrums, 'slices' determines how many divisions there are as you go around the object.
+![ ](visuals/slices.png)
+### Stacks {#stacks-details}
+For spheres, 'stacks' determines how many layers there are as you go down the object.
+![ ](visuals/stacks.png)
+### Usage
+**sphere**
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::PRIMITIVE;
+map[ PrimitiveVisual::Property::SHAPE ] = PrimitiveVisual::Shape::SPHERE;
+map[ PrimitiveVisual::Property::MIX_COLOR ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+
+**conical frustrum**
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::PRIMITIVE;
+map[ PrimitiveVisual::Property::SHAPE ] = PrimitiveVisual::Shape::CONICAL_FRUSTRUM;
+map[ PrimitiveVisual::Property::MIX_COLOR ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+map[ PrimitiveVisual::Property::SCALE_TOP_RADIUS ] = 1.0f;
+map[ PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS ] = 1.5f;
+map[ PrimitiveVisual::Property::SCALE_HEIGHT ] = 3.0f;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+
+**bevelled cube**
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::PRIMITIVE;
+map[ PrimitiveVisual::Property::SHAPE ] = PrimitiveVisual::Shape::BEVELLED_CUBE;
+map[ PrimitiveVisual::Property::MIX_COLOR ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+map[ PrimitiveVisual::Property::BEVEL_PERCENTAGE ] = 0.4f;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+___________________________________________________________________________________________________
+
+## Text Visual {#text-visual}
+
+Renders text within a control.
+
+![ ](visuals/HelloWorld.png)
+
+### Properties
+
+**VisualType:** Dali::Toolkit::Visual::TEXT, "TEXT"
+
+| Property                                                    | String              | Type          | Required | Description                                                                   | Default                |
+|-------------------------------------------------------------|---------------------|:-------------:|:--------:|-------------------------------------------------------------------------------|------------------------|
+| Dali::Toolkit::TextVisual::Property::TEXT                   | text                | STRING        | Yes      | The text to display in UTF-8 format                                           |                        |
+| Dali::Toolkit::TextVisual::Property::FONT_FAMILY            | fontFamily          | STRING        | No       | The requested font family to use                                              |                        |
+| Dali::Toolkit::TextVisual::Property::FONT_STYLE             | fontStyle           | MAP           | No       | The requested font style to use                                               |                        |
+| Dali::Toolkit::TextVisual::Property::POINT_SIZE             | pointSize           | FLOAT         | Yes      | The size of font in points                                                    |                        |
+| Dali::Toolkit::TextVisual::Property::MULTI_LINE             | multiLine           | BOOLEAN       | No       | The single-line or multi-line layout option                                   | false                  |
+| Dali::Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT   | horizontalAlignment | STRING        | No       | The line horizontal alignment: "BEGIN", "CENTER", "END"                       | "BEGIN"                |
+| Dali::Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT     | verticalAlignment   | STRING        | No       | The line vertical alignment: "TOP",   "CENTER", "BOTTOM"                      | "TOP"                  |
+| Dali::Toolkit::TextVisual::Property::TEXT_COLOR             | textColor           | VECTOR4       | No       | The color of the text                                                         | Color::BLACK           |
+| Dali::Toolkit::TextVisual::Property::ENABLE_MARKUP         | enableMarkup           | BOOL       | No       | If mark up should be enabled |                                                        |
+
+### Usage
+
+~~~{.cpp}
+    // C++
+    Dali::Stage stage = Dali::Stage::GetCurrent();
+    stage.SetBackgroundColor( Dali::Color::WHITE );
+
+    Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+    control.SetParentOrigin( ParentOrigin::CENTER );
+
+    Dali::Property::Map map;
+    map[ Dali::Toolkit::Visual::Property::TYPE ] = Dali::Toolkit::Visual::TEXT;
+    map[ Dali::Toolkit::TextVisual::Property::TEXT ] = "Hello world";
+    map[ Dali::Toolkit::TextVisual::Property::TEXT_COLOR ] = Dali::Color::BLACK;
+    map[ Dali::Toolkit::TextVisual::Property::FONT_FAMILY ] = "Sans";
+    map[ Dali::Toolkit::TextVisual::Property::POINT_SIZE ] = 30.f;
+    map[ Dali::Toolkit::TextVisual::Property::HORIZONTAL_ALIGNMENT ] = "CENTER";
+    map[ Dali::Toolkit::TextVisual::Property::VERTICAL_ALIGNMENT ] = "CENTER";
+
+    control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
+
+    stage.Add( control );
+~~~
+
+## Wireframe Visual {#wireframe-visual}
+
+Renders a wireframe around a quad geometry.
+Is mainly used for debugging and is the visual that replaces all other visuals when [Visual Debug Rendering](@ref debugrendering) is turned on.
+![ ](visuals/wireframe-visual.png)
+
+### Properties
+
+**VisualType:** Dali::Toolkit::Visual::WIREFRAME, "WIREFRAME"
+
+### Usage
+
+~~~{.cpp}
+// C++
+Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
+
+Dali::Property::Map map;
+map[ Visual::Property::TYPE ] = Dali::Toolkit::Visual::WIREFRAME;
+
+control.SetProperty( Control::Property::BACKGROUND, map );
+~~~
+
+
+
+*/
diff --git a/docs/dali_doxygen.css b/docs/dali_doxygen.css
new file mode 100644 (file)
index 0000000..3de4bf4
--- /dev/null
@@ -0,0 +1,10 @@
+.image
+{
+   text-align: left;
+   margin-left: 20px;
+   margin-right: 20px;
+}
+
+div.image img {
+  max-width: 70em;
+}
diff --git a/packaging/dali-toolkit.spec b/packaging/dali-toolkit.spec
new file mode 100644 (file)
index 0000000..700f4d2
--- /dev/null
@@ -0,0 +1,401 @@
+Name:       dali-toolkit
+Summary:    Dali 3D engine Toolkit
+Version:    1.5.8
+Release:    1
+Group:      System/Libraries
+License:    Apache-2.0 and BSD-3-Clause and MIT
+URL:        https://review.tizen.org/git/?p=platform/core/uifw/dali-toolkit.git;a=summary
+Source0:    %{name}-%{version}.tar.gz
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires:  cmake
+BuildRequires:  pkgconfig
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali-adaptor)
+BuildRequires:  gettext
+BuildRequires:  pkgconfig(libtzplatform-config)
+Provides: libdali-toolkit-cxx11.so
+Provides: libdali-toolkit-cxx11.so.0
+Provides: libdali-toolkit-cxx11.so.0.0.0
+
+#############################
+# profile setup
+#############################
+
+%description
+Dali 3D engine Toolkit - a set of controls that provide
+user interface functionality.
+
+##############################
+# resource
+##############################
+%package resources_360x360
+Summary:    default resource files for 360x360
+Requires:   %{name} = %{version}-%{release}
+Conflicts:  %{name}-resources_480x800
+Conflicts:  %{name}-resources_720x1280
+Conflicts:  %{name}-resources_1920x1080
+%description resources_360x360
+dali-toolkit default resource files for 360x360
+Contain po / sounds / common images / style / style images
+
+%package resources_480x800
+Summary:    default resource files for 480x800
+Requires:   %{name} = %{version}-%{release}
+Conflicts:  %{name}-resources_360x360
+Conflicts:  %{name}-resources_720x1280
+Conflicts:  %{name}-resources_1920x1080
+%description resources_480x800
+dali-toolkit default resource files for 480x800
+Contain po / sounds / common images / style / style images
+
+%package resources_720x1280
+Summary:    default resource files for 720x1280
+Requires:   %{name} = %{version}-%{release}
+Conflicts:  %{name}-resources_360x360
+Conflicts:  %{name}-resources_480x800
+Conflicts:  %{name}-resources_1920x1080
+%description resources_720x1280
+dali-toolkit default resource files for 720x1280
+Contain po / sounds / common images / style / style images
+
+%package resources_1920x1080
+Summary:    default resource files for 1920x1080
+Requires:   %{name} = %{version}-%{release}
+Conflicts:  %{name}-resources_360x360
+Conflicts:  %{name}-resources_480x800
+Conflicts:  %{name}-resources_720x1280
+%description resources_1920x1080
+dali-toolkit default resource files for 1920x1080
+Contain po / sounds / common images / style / style images
+
+##############################
+# devel
+##############################
+%package devel
+Summary:    Application development package for Dali 3D engine toolkit
+Group:      Development/Building
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+Application development package for Dali 3D engine toolkit - headers and package config
+
+##############################
+# Preparation
+##############################
+%prep
+%setup -q
+
+%define dali_data_rw_dir            %TZ_SYS_SHARE/dali/
+%define dali_data_ro_dir            %TZ_SYS_RO_SHARE/dali/
+
+%define dali_toolkit_image_files    %{dali_data_ro_dir}/toolkit/images/
+%define dali_toolkit_sound_files    %{dali_data_ro_dir}/toolkit/sounds/
+%define dali_toolkit_style_files    %{dali_data_ro_dir}/toolkit/styles/
+%define dev_include_path %{_includedir}
+
+# PO
+{
+cd %{_builddir}/dali-toolkit-%{version}/dali-toolkit/po
+for language in *.po
+do
+  language=${language%.po}
+  msgfmt -o ${language}.mo ${language}.po
+done
+} &> /dev/null
+
+##############################
+# Build
+##############################
+%build
+PREFIX="/usr"
+CXXFLAGS+=" -Wall -g -Os -fPIC -fvisibility-inlines-hidden -fdata-sections -ffunction-sections "
+LDFLAGS+=" -Wl,--rpath=$PREFIX/lib -Wl,--as-needed -Wl,--gc-sections -Wl,-Bsymbolic-functions "
+
+%if 0%{?enable_coverage}
+CXXFLAGS+=" --coverage "
+LDFLAGS+=" --coverage "
+%endif
+
+libtoolize --force
+cd %{_builddir}/dali-toolkit-%{version}/build/tizen
+
+DALI_DATA_RW_DIR="%{dali_data_rw_dir}" ; export DALI_DATA_RW_DIR
+DALI_DATA_RO_DIR="%{dali_data_ro_dir}" ; export DALI_DATA_RO_DIR
+
+cmake \
+%if 0%{?enable_debug}
+      -DCMAKE_BUILD_TYPE=Debug \
+%endif
+%if 0%{?enable_trace}
+      -DENABLE_TRACE=ON \
+%endif
+      -DCMAKE_INSTALL_PREFIX=%{_prefix} \
+      -DCMAKE_INSTALL_LIBDIR=%{_libdir} \
+      -DCMAKE_INSTALL_INCLUDEDIR=%{_includedir} \
+      -DENABLE_I18N=ON
+
+make %{?jobs:-j%jobs}
+
+##############################
+# Installation
+##############################
+%install
+rm -rf %{buildroot}
+cd build/tizen
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+%make_install
+
+# PO
+{
+cd %{_builddir}/dali-toolkit-%{version}/dali-toolkit/po
+for language in *.mo
+do
+  language=${language%.mo}
+  mkdir -p %{buildroot}/%{_datadir}/locale/${language}/LC_MESSAGES/
+  cp ${language}.mo %{buildroot}/%{_datadir}/locale/${language}/LC_MESSAGES/dali-toolkit.mo
+done
+} &> /dev/null
+popd
+
+# Create links to ensure linking with cxx11 library is preserved
+pushd  %{buildroot}%{_libdir}
+ln -sf libdali-toolkit.so libdali-toolkit-cxx11.so
+ln -sf libdali-toolkit.so libdali-toolkit-cxx11.so.0
+ln -sf libdali-toolkit.so libdali-toolkit-cxx11.so.0.0.0
+popd
+
+# Remove default style and style images which are for Linux build
+rm -rf %{buildroot}%{dali_toolkit_style_files}/*
+
+# Make folder to contain style and style images
+# After making folder, copy local style and style images to new folder
+pushd %{_builddir}/%{name}-%{version}
+mkdir -p %{buildroot}%{dali_toolkit_style_files}/360x360
+cp -r dali-toolkit/styles/360x360/* %{buildroot}%{dali_toolkit_style_files}/360x360
+mkdir -p %{buildroot}%{dali_toolkit_style_files}/480x800
+cp -r dali-toolkit/styles/480x800/* %{buildroot}%{dali_toolkit_style_files}/480x800
+mkdir -p %{buildroot}%{dali_toolkit_style_files}/720x1280
+cp -r dali-toolkit/styles/720x1280/* %{buildroot}%{dali_toolkit_style_files}/720x1280
+mkdir -p %{buildroot}%{dali_toolkit_style_files}/1920x1080
+cp -r dali-toolkit/styles/1920x1080/* %{buildroot}%{dali_toolkit_style_files}/1920x1080
+
+# Copy default feedback theme
+cp dali-toolkit/styles/default-feedback-theme.json %{buildroot}%{dali_toolkit_style_files}
+popd
+
+##############################
+# Pre Install
+##############################
+
+%pre resources_360x360
+case "$1" in
+  2)
+    pushd %{dali_toolkit_style_files}
+    rm -rf ./*
+    popd
+  ;;
+esac
+
+%pre resources_480x800
+case "$1" in
+  2)
+    pushd %{dali_toolkit_style_files}
+    rm -rf ./*
+    popd
+  ;;
+esac
+
+%pre resources_720x1280
+case "$1" in
+  2)
+    pushd %{dali_toolkit_style_files}
+    rm -rf ./*
+    popd
+  ;;
+esac
+
+%pre resources_1920x1080
+case "$1" in
+  2)
+    pushd %{dali_toolkit_style_files}
+    rm -rf ./*
+    popd
+  ;;
+esac
+
+##############################
+# Post Install
+##############################
+%post
+/sbin/ldconfig
+exit 0
+
+%post resources_360x360
+pushd %{dali_toolkit_style_files}/360x360
+for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
+popd
+
+%post resources_480x800
+pushd %{dali_toolkit_style_files}/480x800
+for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
+popd
+
+%post resources_720x1280
+pushd %{dali_toolkit_style_files}/720x1280
+for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
+popd
+
+%post resources_1920x1080
+pushd %{dali_toolkit_style_files}/1920x1080
+for FILE in *; do mv ./"${FILE}" ../"${FILE}"; done
+popd
+
+##############################
+# Pre Uninstall
+##############################
+
+%preun resources_360x360
+case "$1" in
+  0)
+    %preun resources_360x360
+    pushd %{dali_toolkit_style_files}
+    mv images ./360x360
+    mv dali-toolkit-default-theme.json ./360x360
+    popd
+  ;;
+esac
+
+%preun resources_480x800
+case "$1" in
+  0)
+    %preun resources_480x800
+    pushd %{dali_toolkit_style_files}
+    mv images ./480x800
+    mv dali-toolkit-default-theme.json ./480x800
+    popd
+  ;;
+esac
+
+%preun resources_720x1280
+case "$1" in
+  0)
+    %preun resources_720x1280
+    pushd %{dali_toolkit_style_files}
+    mv images ./720x1280
+    mv dali-toolkit-default-theme.json ./720x1280
+    popd
+  ;;
+esac
+
+%preun resources_1920x1080
+case "$1" in
+  0)
+    %preun resources_1920x1080
+    pushd %{dali_toolkit_style_files}
+    mv images ./1920x1080
+    mv dali-toolkit-default-theme.json ./1920x1080
+    popd
+  ;;
+esac
+
+##############################
+# Post Uninstall
+##############################
+%postun
+/sbin/ldconfig
+exit 0
+
+%postun resources_360x360
+case "$1" in
+  0)
+    pushd %{dali_toolkit_style_files}
+    rm -rf *
+    popd
+  ;;
+esac
+
+%postun resources_480x800
+case "$1" in
+  0)
+    pushd %{dali_toolkit_style_files}
+    rm -rf *
+    popd
+  ;;
+esac
+
+%postun resources_720x1280
+case "$1" in
+  0)
+    pushd %{dali_toolkit_style_files}
+    rm -rf *
+    popd
+  ;;
+esac
+
+%postun resources_1920x1080
+case "$1" in
+  0)
+    pushd %{dali_toolkit_style_files}
+    rm -rf *
+    popd
+  ;;
+esac
+
+##############################
+# Files in Binary Packages
+##############################
+%files
+%if 0%{?enable_dali_smack_rules}
+%manifest dali-toolkit.manifest-smack
+%else
+%manifest dali-toolkit.manifest
+%endif
+%defattr(-,root,root,-)
+%{_libdir}/libdali-toolkit-cxx11.so*
+%{_libdir}/libdali-toolkit.so*
+%license LICENSE
+
+%files devel
+%defattr(-,root,root,-)
+%{dev_include_path}/dali-toolkit/*
+%{_libdir}/pkgconfig/dali-toolkit.pc
+
+%files resources_360x360
+%manifest dali-toolkit-resources.manifest
+%defattr(-,root,root,-)
+%{dali_toolkit_image_files}/*
+%{dali_toolkit_sound_files}/*
+%{dali_toolkit_style_files}/360x360/*
+%{dali_toolkit_style_files}/default-feedback-theme.json
+%{_datadir}/locale/*/LC_MESSAGES/*
+
+%files resources_480x800
+%manifest dali-toolkit-resources.manifest
+%defattr(-,root,root,-)
+%{dali_toolkit_image_files}/*
+%{dali_toolkit_sound_files}/*
+%{dali_toolkit_style_files}/480x800/*
+%{dali_toolkit_style_files}/default-feedback-theme.json
+%{_datadir}/locale/*/LC_MESSAGES/*
+
+%files resources_720x1280
+%manifest dali-toolkit-resources.manifest
+%defattr(-,root,root,-)
+%{dali_toolkit_image_files}/*
+%{dali_toolkit_sound_files}/*
+%{dali_toolkit_style_files}/720x1280/*
+%{dali_toolkit_style_files}/default-feedback-theme.json
+%{_datadir}/locale/*/LC_MESSAGES/*
+
+%files resources_1920x1080
+%manifest dali-toolkit-resources.manifest
+%defattr(-,root,root,-)
+%{dali_toolkit_image_files}/*
+%{dali_toolkit_sound_files}/*
+%{dali_toolkit_style_files}/1920x1080/*
+%{dali_toolkit_style_files}/default-feedback-theme.json
+%{_datadir}/locale/*/LC_MESSAGES/*